Merge datatype shared selectors/sygus comp 2017 branch. Modify the datatypes decision...
authorajreynol <andrew.j.reynolds@gmail.com>
Mon, 10 Jul 2017 19:06:52 +0000 (14:06 -0500)
committerajreynol <andrew.j.reynolds@gmail.com>
Mon, 10 Jul 2017 19:07:11 +0000 (14:07 -0500)
68 files changed:
src/Makefile.am
src/compat/cvc3_compat.cpp
src/expr/datatype.cpp
src/expr/datatype.h
src/expr/node.cpp
src/main/command_executor_portfolio.cpp
src/options/Makefile.am
src/options/datatypes_modes.h [new file with mode: 0644]
src/options/datatypes_options
src/options/options_handler.cpp
src/options/options_handler.h
src/options/quantifiers_modes.h
src/options/quantifiers_options
src/parser/cvc/Cvc.g
src/parser/smt2/Smt2.g
src/parser/smt2/smt2.cpp
src/parser/smt2/smt2.h
src/printer/cvc/cvc_printer.cpp
src/printer/smt2/smt2_printer.cpp
src/smt/smt_engine.cpp
src/theory/datatypes/datatypes_rewriter.h
src/theory/datatypes/datatypes_sygus.cpp
src/theory/datatypes/datatypes_sygus.h
src/theory/datatypes/kinds
src/theory/datatypes/theory_datatypes.cpp
src/theory/datatypes/theory_datatypes.h
src/theory/datatypes/theory_datatypes_type_rules.h
src/theory/quantifiers/bounded_integers.cpp
src/theory/quantifiers/ce_guided_instantiation.cpp
src/theory/quantifiers/ce_guided_instantiation.h
src/theory/quantifiers/ce_guided_pbe.cpp [new file with mode: 0644]
src/theory/quantifiers/ce_guided_pbe.h [new file with mode: 0644]
src/theory/quantifiers/ce_guided_single_inv.cpp
src/theory/quantifiers/ce_guided_single_inv.h
src/theory/quantifiers/ce_guided_single_inv_sol.cpp
src/theory/quantifiers/ceg_t_instantiator.cpp
src/theory/quantifiers/inst_match_generator.cpp
src/theory/quantifiers/inst_strategy_cbqi.cpp
src/theory/quantifiers/quant_util.cpp
src/theory/quantifiers/quant_util.h
src/theory/quantifiers/quantifiers_attributes.cpp
src/theory/quantifiers/quantifiers_rewriter.cpp
src/theory/quantifiers/quantifiers_rewriter.h
src/theory/quantifiers/term_database.cpp
src/theory/quantifiers/term_database.h
src/theory/quantifiers/theory_quantifiers.cpp
src/theory/sets/rels_utils.h
test/regress/regress0/sygus/General_plus10.sy [new file with mode: 0755]
test/regress/regress0/sygus/Makefile.am
test/regress/regress0/sygus/cggmp.sy [new file with mode: 0644]
test/regress/regress0/sygus/fg_polynomial3.sy [new file with mode: 0644]
test/regress/regress0/sygus/icfp_14.12.sy [new file with mode: 0644]
test/regress/regress0/sygus/icfp_easy-ite.sy [new file with mode: 0644]
test/regress/regress0/sygus/qe.sy [new file with mode: 0644]
test/regress/regress0/sygus/strings-template-infer.sy [new file with mode: 0644]
test/regress/regress0/sygus/strings-trivial-simp.sy [new file with mode: 0644]
test/regress/regress0/sygus/strings-trivial.sy [new file with mode: 0644]
test/regress/regress0/sygus/tl-type-0.sy [new file with mode: 0644]
test/regress/regress0/sygus/tl-type-4x.sy [new file with mode: 0644]
test/regress/regress1/sygus/Makefile.am
test/regress/regress1/sygus/VC22_a.sy [new file with mode: 0644]
test/regress/regress1/sygus/array_sum_dd.sy [new file with mode: 0644]
test/regress/regress1/sygus/icfp_easy_mt_ite.sy [new file with mode: 0644]
test/regress/regress1/sygus/inv_gen_fig8.sy [new file with mode: 0644]
test/regress/regress1/sygus/inv_gen_n_c11.sy [new file with mode: 0644]
test/regress/regress1/sygus/mpg_guard1-dd.sy [new file with mode: 0644]
test/regress/regress1/sygus/three.sy [new file with mode: 0644]
test/regress/regress1/sygus/unbdd_inv_gen_ex7.sy [new file with mode: 0644]

index 157fe33d243800f2947b6c3a8d9ee90abb0629ca..6cbed6fda76918dec52a954f515ffdfb5e9816ed 100644 (file)
@@ -353,6 +353,8 @@ libcvc4_la_SOURCES = \
        theory/quantifiers/ce_guided_single_inv.h \
        theory/quantifiers/ce_guided_single_inv_ei.cpp \
        theory/quantifiers/ce_guided_single_inv_ei.h \
+       theory/quantifiers/ce_guided_pbe.cpp \
+       theory/quantifiers/ce_guided_pbe.h \
        theory/quantifiers/ce_guided_single_inv_sol.cpp \
        theory/quantifiers/ce_guided_single_inv_sol.h \
        theory/quantifiers/ceg_instantiator.cpp \
index 1226d4db52d1707b03445e62548ec97363534a23..be24dacdda8e507113c25b987e63d5c1a1b152e8 100644 (file)
@@ -1833,7 +1833,7 @@ Expr ValidityChecker::recSelectExpr(const Expr& record, const std::string& field
   Type t = record.getType();
   const CVC4::Datatype& dt = ((CVC4::DatatypeType)t).getDatatype();
   unsigned index = CVC4::Datatype::indexOf( dt[0].getSelector(field) );
-  return d_em->mkExpr(CVC4::kind::APPLY_SELECTOR_TOTAL, dt[0][index].getSelector(), record);
+  return d_em->mkExpr(CVC4::kind::APPLY_SELECTOR_TOTAL, dt[0].getSelectorInternal( t, index ), record);
 }
 
 Expr ValidityChecker::recUpdateExpr(const Expr& record, const std::string& field,
@@ -2236,8 +2236,9 @@ Expr ValidityChecker::tupleExpr(const std::vector<Expr>& exprs) {
 Expr ValidityChecker::tupleSelectExpr(const Expr& tuple, int index) {
   CompatCheckArgument(index >= 0 && index < ((CVC4::DatatypeType)tuple.getType()).getTupleLength(),
                       "invalid index in tuple select");
-  const CVC4::Datatype& dt = ((CVC4::DatatypeType)tuple.getType()).getDatatype();
-  return d_em->mkExpr(CVC4::kind::APPLY_SELECTOR_TOTAL, dt[0][index].getSelector(), tuple);
+  Type t = tuple.getType();
+  const CVC4::Datatype& dt = ((CVC4::DatatypeType)t).getDatatype();
+  return d_em->mkExpr(CVC4::kind::APPLY_SELECTOR_TOTAL, dt[0].getSelectorInternal( t, index ), tuple);
 }
 
 Expr ValidityChecker::tupleUpdateExpr(const Expr& tuple, int index,
@@ -2262,7 +2263,8 @@ Expr ValidityChecker::datatypeSelExpr(const std::string& selector, const Expr& a
   const CVC4::Datatype& dt = *(*i).second.first;
   string constructor = (*i).second.second;
   const CVC4::DatatypeConstructor& ctor = dt[constructor];
-  return d_em->mkExpr(CVC4::kind::APPLY_SELECTOR, ctor.getSelector(selector), arg);
+  unsigned sindex = CVC4::Datatype::indexOf( ctor.getSelector(selector) );
+  return d_em->mkExpr(CVC4::kind::APPLY_SELECTOR, ctor.getSelectorInternal( arg.getType(), sindex ), arg);
 }
 
 Expr ValidityChecker::datatypeTestExpr(const std::string& constructor, const Expr& arg) {
index 39bdddbad8cc9f39754fb6eba91a883ebf5c975f..4f1fc82b15c3c0aaaba7127a84e8053a9273bf71 100644 (file)
@@ -28,6 +28,7 @@
 #include "expr/node_manager.h"
 #include "expr/type.h"
 #include "options/set_language.h"
+#include "options/datatypes_options.h"
 
 using namespace std;
 
@@ -161,7 +162,7 @@ void Datatype::resolve(ExprManager* em,
     evalType.push_back(TypeNode::fromType(d_sygus_type));
     TypeNode eval_func_type = nm->mkFunctionType(evalType);
     d_sygus_eval = nm->mkSkolem(name, eval_func_type, "sygus evaluation function").toExpr();    
-  }  
+  }
 }
 
 void Datatype::addConstructor(const DatatypeConstructor& c) {
@@ -180,6 +181,41 @@ void Datatype::setSygus( Type st, Expr bvl, bool allow_const, bool allow_all ){
   d_sygus_allow_all = allow_all;
 }
 
+void Datatype::addSygusConstructor( CVC4::Expr op, std::string& cname, std::vector< CVC4::Type >& cargs,
+                                    CVC4::Expr& let_body, std::vector< CVC4::Expr >& let_args, unsigned let_num_input_args ) {
+  Debug("dt-sygus") << "--> Add constructor " << cname << " to " << getName() << std::endl;
+  if( !let_body.isNull() ){
+    Debug("dt-sygus") << "    let body = " << let_body << ", args = " << let_args.size() << "," << let_num_input_args << std::endl;
+    //TODO : remove arguments not occurring in body
+    //if this is a self identity function, ignore
+    if( let_args.size()==0 && let_args[0]==let_body ){
+      Debug("dt-sygus") << "    identity function " << cargs[0] << " to " << getName() << std::endl;
+      //TODO
+    }
+  }
+  std::string name = getName() + "_" + cname;
+  std::string testerId("is-");
+  testerId.append(name);
+  //checkDeclaration(name, CHECK_UNDECLARED, SYM_VARIABLE);
+  //checkDeclaration(testerId, CHECK_UNDECLARED, SYM_VARIABLE);
+  CVC4::DatatypeConstructor c(name, testerId );
+  c.setSygus( op, let_body, let_args, let_num_input_args );
+  for( unsigned j=0; j<cargs.size(); j++ ){
+    Debug("parser-sygus-debug") << "  arg " << j << " : " << cargs[j] << std::endl;
+    std::stringstream sname;
+    sname << name << "_" << j;
+    c.addArg(sname.str(), cargs[j]);
+  }
+  addConstructor(c);
+}
+
+void Datatype::addSygusConstructor( CVC4::Expr op, std::string& cname, std::vector< CVC4::Type >& cargs ) {
+  CVC4::Expr let_body; 
+  std::vector< CVC4::Expr > let_args; 
+  unsigned let_num_input_args = 0;
+  addSygusConstructor( op, cname, cargs, let_body, let_args, let_num_input_args );
+}
+                                    
 void Datatype::setTuple() {
   PrettyCheckArgument(!d_resolved, this, "cannot set tuple to a finalized Datatype");
   d_isTuple = true;
@@ -584,6 +620,30 @@ const DatatypeConstructor& Datatype::operator[](std::string name) const {
   IllegalArgument(name, "No such constructor `%s' of datatype `%s'", name.c_str(), d_name.c_str());
 }
 
+
+Expr Datatype::getSharedSelector( Type dtt, Type t, unsigned index ) const{
+  PrettyCheckArgument(isResolved(), this, "this datatype is not yet resolved");
+  std::map< Type, std::map< Type, std::map< unsigned, Expr > > >::iterator itd = d_shared_sel.find( dtt );
+  if( itd!=d_shared_sel.end() ){
+    std::map< Type, std::map< unsigned, Expr > >::iterator its = itd->second.find( t );
+    if( its!=itd->second.end() ){
+      std::map< unsigned, Expr >::iterator it = its->second.find( index );
+      if( it!=its->second.end() ){
+        return it->second;
+      }
+    }
+  }
+  //make the shared selector
+  Expr s;
+  NodeManager* nm = NodeManager::fromExprManager( d_self.getExprManager() );
+  std::stringstream ss;
+  ss << "sel_" << index;
+  s = nm->mkSkolem(ss.str(), nm->mkSelectorType(TypeNode::fromType(dtt), TypeNode::fromType(t)), "is a shared selector", NodeManager::SKOLEM_NO_NOTIFY).toExpr();
+  d_shared_sel[dtt][t][index] = s;
+  Trace("dt-shared-sel") << "Made " << s << " of type " << dtt << " -> " << t << std::endl;
+  return s; 
+}
+
 Expr Datatype::getConstructor(std::string name) const {
   return (*this)[name].getConstructor();
 }
@@ -797,6 +857,7 @@ Expr DatatypeConstructor::getConstructor() const {
 
 Type DatatypeConstructor::getSpecializedConstructorType(Type returnType) const {
   PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved");
+  PrettyCheckArgument(returnType.isDatatype(), this, "cannot get specialized constructor type for non-datatype type");
   ExprManagerScope ems(d_constructor);
   const Datatype& dt = Datatype::datatypeOf(d_constructor);
   PrettyCheckArgument(dt.isParametric(), this, "this datatype constructor is not parametric");
@@ -1011,6 +1072,30 @@ Expr DatatypeConstructor::computeGroundTerm( Type t, std::vector< Type >& proces
   return groundTerm;
 }
 
+void DatatypeConstructor::computeSharedSelectors( Type domainType ) const {
+  if( d_shared_selectors[domainType].size()<getNumArgs() ){
+    TypeNode ctype;
+    if( DatatypeType(domainType).isParametric() ){
+      ctype = TypeNode::fromType( getSpecializedConstructorType( domainType ) );
+    }else{
+      ctype = TypeNode::fromType( d_constructor.getType() );
+    }
+    Assert( ctype.isConstructor() );
+    Assert( ctype.getNumChildren()-1==getNumArgs() );
+    //compute the shared selectors
+    const Datatype& dt = Datatype::datatypeOf(d_constructor);
+    std::map< TypeNode, unsigned > counter;
+    for( unsigned j=0; j<ctype.getNumChildren()-1; j++ ){
+      TypeNode t = ctype[j];
+      Expr ss = dt.getSharedSelector( domainType, t.toType(), counter[t] );
+      d_shared_selectors[domainType].push_back( ss );
+      Assert( d_shared_selector_index[domainType].find( ss )==d_shared_selector_index[domainType].end() );
+      d_shared_selector_index[domainType][ss] = j;
+      counter[t]++;
+    }
+  }
+}
+
 
 const DatatypeConstructorArg& DatatypeConstructor::operator[](size_t index) const {
   PrettyCheckArgument(index < getNumArgs(), index, "index out of bounds");
@@ -1069,6 +1154,37 @@ Expr DatatypeConstructorArg::getSelector() const {
   return d_selector;
 }
 
+Expr DatatypeConstructor::getSelectorInternal( Type domainType, size_t index ) const {
+  PrettyCheckArgument(isResolved(), this, "cannot get an internal selector for an unresolved datatype constructor");
+  PrettyCheckArgument(index < getNumArgs(), index, "index out of bounds");
+  if( options::dtSharedSelectors() ){
+    computeSharedSelectors( domainType );
+    Assert( d_shared_selectors[domainType].size()==getNumArgs() );
+    return d_shared_selectors[domainType][index];
+  }else{
+    return d_args[index].getSelector();
+  }
+}
+
+int DatatypeConstructor::getSelectorIndexInternal( Expr sel ) const {
+  PrettyCheckArgument(isResolved(), this, "cannot get an internal selector index for an unresolved datatype constructor");
+  if( options::dtSharedSelectors() ){
+    Assert( sel.getType().isSelector() );
+    Type domainType = ((SelectorType)sel.getType()).getDomain();
+    computeSharedSelectors( domainType );
+    std::map< Expr, unsigned >::iterator its = d_shared_selector_index[domainType].find( sel );
+    if( its!=d_shared_selector_index[domainType].end() ){
+      return (int)its->second;
+    }
+  }else{
+    unsigned sindex = Datatype::indexOf(sel);
+    if( getNumArgs() > sindex && d_args[sindex].getSelector() == sel ){
+      return (int)sindex;
+    }
+  }
+  return -1;
+}
+
 Expr DatatypeConstructorArg::getConstructor() const {
   PrettyCheckArgument(isResolved(), this,
                 "cannot get a associated constructor for argument of an unresolved datatype constructor");
index 456e70fd555e8f7fa34cdbbdff7fe7f8bba332ee..84588fef04fc9e142870b6709476956aa3142f29 100644 (file)
@@ -197,6 +197,10 @@ private:
   Expr d_sygus_let_body;
   std::vector< Expr > d_sygus_let_args;
   unsigned d_sygus_num_let_input_args;
+  
+  /** shared selectors */
+  mutable std::map< Type, std::vector< Expr > > d_shared_selectors;
+  mutable std::map< Type, std::map< Expr, unsigned > > d_shared_selector_index;
 
   void resolve(ExprManager* em, DatatypeType self,
                const std::map<std::string, DatatypeType>& resolutions,
@@ -226,6 +230,8 @@ private:
   bool computeWellFounded( std::vector< Type >& processing ) const throw(IllegalArgumentException);
   /** compute ground term */
   Expr computeGroundTerm( Type t, std::vector< Type >& processing, std::map< Type, Expr >& gt ) const throw(IllegalArgumentException);
+  /** compute shared selectors */
+  void computeSharedSelectors( Type domainType ) const;
 public:
   /**
    * Create a new Datatype constructor with the given name for the
@@ -378,6 +384,17 @@ public:
    */
   Expr getSelector(std::string name) const;
 
+
+  /**
+   * Get the internal selector for a constructor argument.
+   */
+  Expr getSelectorInternal( Type domainType, size_t index ) const;
+  
+  /** 
+   * Get the index for the selector
+   */
+  int getSelectorIndexInternal( Expr sel ) const;
+  
   /**
    * Get whether this datatype involves an external type.  If so,
    * then we will pose additional requirements for sharing.
@@ -506,6 +523,8 @@ private:
   mutable int d_well_founded;
   // ground term for this datatype
   mutable std::map< Type, Expr > d_ground_term;
+  // shared selectors
+  mutable std::map< Type, std::map< Type, std::map< unsigned, Expr > > > d_shared_sel;
 
   /**
    * Datatypes refer to themselves, recursively, and we have a
@@ -549,7 +568,9 @@ private:
   /** compute whether this datatype is well-founded */
   bool computeWellFounded( std::vector< Type >& processing ) const throw(IllegalArgumentException);
   /** compute ground term */
-  Expr computeGroundTerm( Type t, std::vector< Type >& processing ) const throw(IllegalArgumentException);
+  Expr computeGroundTerm( Type t, std::vector< Type >& processing ) const throw(IllegalArgumentException);  
+  /** Get the shared selector */
+  Expr getSharedSelector( Type dtt, Type t, unsigned index ) const;
 public:
 
   /** Create a new Datatype of the given name. */
@@ -575,7 +596,11 @@ public:
    *    allow_const : whether all constants are (implicitly) included in the grammar
    */
   void setSygus( Type st, Expr bvl, bool allow_const, bool allow_all );
-
+  /** add sygus constructor */
+  void addSygusConstructor( CVC4::Expr op, std::string& cname, std::vector< CVC4::Type >& cargs );
+  void addSygusConstructor( CVC4::Expr op, std::string& cname, std::vector< CVC4::Type >& cargs,
+                            CVC4::Expr& let_body, std::vector< CVC4::Expr >& let_args, unsigned let_num_input_args );
+                                    
   /** set tuple */
   void setTuple();
 
@@ -726,7 +751,7 @@ public:
    * similarly-named constructors, the first is returned.
    */
   const DatatypeConstructor& operator[](std::string name) const;
-
   /**
    * Get the constructor operator for the named constructor.
    * This is a linear search through the constructors, so in
index 262085a23d50fad71ce64de64062774ee7c46c12..e45ca49e02af02d42ed9ad35735038367a6a5efb 100644 (file)
@@ -22,6 +22,8 @@
 #include "base/output.h"
 #include "expr/attribute.h"
 
+#include "theory/quantifiers/term_database.h"
+
 
 using namespace std;
 
@@ -111,6 +113,11 @@ bool NodeTemplate<ref_count>::hasBoundVar() {
       for(iterator i = begin(); i != end() && !hasBv; ++i) {
         hasBv = (*i).hasBoundVar();
       }
+      if( !hasBv ){
+        if( getKind()==kind::APPLY_UF && getOperator().hasAttribute(theory::SygusSynthFunVarListAttribute()) ){
+          hasBv = true;
+        }
+      }
     }
     setAttribute(HasBoundVarAttr(), hasBv);
     setAttribute(HasBoundVarComputedAttr(), true);
index 25b160d6ce4e56d84a4904ec4666c8e328d97666..948e05ad314f8dce2c385231c29535c2ccfe9d53 100644 (file)
@@ -197,9 +197,13 @@ bool CommandExecutorPortfolio::doCommandSingleton(Command* cmd)
   // mode = 2 : run _only_ the lastWinner thread, not saving the
   // command
 
+  if( dynamic_cast<CheckSynthCommand*>(cmd) != NULL ){
+    // sygus not supported in portfolio : FIXME: can support once datatypes exportTo is supported
+    return CommandExecutor::doCommandSingleton(cmd);
+  }
+
   if(dynamic_cast<CheckSatCommand*>(cmd) != NULL ||
-     dynamic_cast<QueryCommand*>(cmd) != NULL ||
-     dynamic_cast<CheckSynthCommand*>(cmd) != NULL) {
+     dynamic_cast<QueryCommand*>(cmd) != NULL ) {
     mode = 1;
   } else if(dynamic_cast<GetValueCommand*>(cmd) != NULL ||
             dynamic_cast<GetAssignmentCommand*>(cmd) != NULL ||
index 5a9fa54e6e00c87affa4dc2b4ce0c4f3afbbe3e3..ff889bcb237e5b96e92b589e526662e7ccf5ba4f 100644 (file)
@@ -229,6 +229,7 @@ liboptions_la_SOURCES = \
        base_handlers.h \
        bv_bitblast_mode.cpp \
        bv_bitblast_mode.h \
+       datatypes_modes.h \
        decision_mode.cpp \
        decision_mode.h \
        decision_weight.h \
diff --git a/src/options/datatypes_modes.h b/src/options/datatypes_modes.h
new file mode 100644 (file)
index 0000000..3576ffc
--- /dev/null
@@ -0,0 +1,44 @@
+/*********************                                                        */
+/*! \file datatypes_modes.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds, Tim King, Morgan Deters
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief [[ Add one-line brief description here ]]
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef __CVC4__BASE__DATATYPES_MODES_H
+#define __CVC4__BASE__DATATYPES_MODES_H
+
+#include <iostream>
+
+namespace CVC4 {
+namespace theory {
+
+enum SygusFairMode {
+  /** enforce fairness by direct conflict lemmas */
+  SYGUS_FAIR_DIRECT,
+  /** enforce fairness by datatypes size */
+  SYGUS_FAIR_DT_SIZE,
+  /** enforce fairness by datatypes height bound */
+  SYGUS_FAIR_DT_HEIGHT_PRED,
+  /** enforce fairness by datatypes size bound */
+  SYGUS_FAIR_DT_SIZE_PRED,
+  /** do not use fair strategy for CEGQI */
+  SYGUS_FAIR_NONE,
+};
+
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__BASE__DATATYPES_MODES_H */
index bb92b4e05b9a2438e5347c736a0bff7cf7dc691b..d4d3e941c2dfd2cf826a6884abb4ac8122e630b5 100644 (file)
@@ -29,5 +29,23 @@ option dtInferAsLemmas --dt-infer-as-lemmas bool :default false
 # regression explanations for datatype lemmas
 option dtBlastSplits --dt-blast-splits bool :default false
  when applicable, blast splitting lemmas for all variables at once
+option dtSharedSelectors --dt-share-sel bool :default true
+ internally use shared selectors across multiple constructors
  
+option sygusSymBreak --sygus-sym-break bool :default true
+  simple sygus sym break lemmas
+option sygusSymBreakDynamic --sygus-sym-break-dynamic bool :default true
+  dynamic sygus sym break lemmas
+option sygusOpt1 --sygus-opt1 bool :default false
+  sygus experimental option 
+option sygusSymBreakLazy --sygus-sym-break-lazy bool :default true
+  lazily add symmetry breaking lemmas for terms
+option sygusSymBreakRlv --sygus-sym-break-rlv bool :default true
+  add relevancy conditions to symmetry breaking lemmas
+  
+option sygusFair --sygus-fair=MODE CVC4::theory::SygusFairMode :default CVC4::theory::SYGUS_FAIR_DT_SIZE :include "options/datatypes_modes.h" :handler stringToSygusFairMode
+  if and how to apply fairness for sygus
+option sygusFairMax --sygus-fair-max bool :default true
+  use max instead of sum for multi-function sygus conjectures
+  
 endmodule
index 85fe1453f21cf2be3435483b9f0f6d28677eec33..5658b17b0ebb504de822466f0b2806c999532fa4 100644 (file)
@@ -36,6 +36,7 @@
 #include "options/bv_options.h"
 #include "options/decision_mode.h"
 #include "options/decision_options.h"
+#include "options/datatypes_modes.h"
 #include "options/didyoumean.h"
 #include "options/language.h"
 #include "options/option_exception.h"
@@ -399,11 +400,14 @@ norm \n\
 ";
 
 const std::string OptionsHandler::s_cegqiFairModeHelp = "\
-Modes for enforcing fairness for counterexample guided quantifier instantion, supported by --cegqi-fair:\n\
+Modes for enforcing fairness for counterexample guided quantifier instantion, supported by --sygus-fair:\n\
 \n\
 uf-dt-size \n\
 + Enforce fairness using an uninterpreted function for datatypes size.\n\
 \n\
+direct \n\
++ Enforce fairness using direct conflict lemmas.\n\
+\n\
 default | dt-size \n\
 + Default, enforce fairness using size operator.\n\
 \n\
@@ -716,17 +720,17 @@ theory::quantifiers::PrenexQuantMode OptionsHandler::stringToPrenexQuantMode(std
   }
 }
 
-theory::quantifiers::CegqiFairMode OptionsHandler::stringToCegqiFairMode(std::string option, std::string optarg) throw(OptionException) {
-  if(optarg == "uf-dt-size" ) {
-    return theory::quantifiers::CEGQI_FAIR_UF_DT_SIZE;
+theory::SygusFairMode OptionsHandler::stringToSygusFairMode(std::string option, std::string optarg) throw(OptionException) {
+  if(optarg == "direct") {
+    return theory::SYGUS_FAIR_DIRECT;
   } else if(optarg == "default" || optarg == "dt-size") {
-    return theory::quantifiers::CEGQI_FAIR_DT_SIZE;
+    return theory::SYGUS_FAIR_DT_SIZE;
   } else if(optarg == "dt-height-bound" ){
-    return theory::quantifiers::CEGQI_FAIR_DT_HEIGHT_PRED;
-  //} else if(optarg == "dt-size-bound" ){
-  //  return theory::quantifiers::CEGQI_FAIR_DT_SIZE_PRED;
+    return theory::SYGUS_FAIR_DT_HEIGHT_PRED;
+  } else if(optarg == "dt-size-bound" ){
+    return theory::SYGUS_FAIR_DT_SIZE_PRED;
   } else if(optarg == "none") {
-    return theory::quantifiers::CEGQI_FAIR_NONE;
+    return theory::SYGUS_FAIR_NONE;
   } else if(optarg ==  "help") {
     puts(s_cegqiFairModeHelp.c_str());
     exit(1);
index fa87149f823344cd8c334e3a2557342c9d874140..16c77b166b33cfe71b53c0d0f9437b564228c463 100644 (file)
@@ -29,6 +29,7 @@
 #include "options/base_handlers.h"
 #include "options/bv_bitblast_mode.h"
 #include "options/decision_mode.h"
+#include "options/datatypes_modes.h"
 #include "options/language.h"
 #include "options/option_exception.h"
 #include "options/options.h"
@@ -95,7 +96,6 @@ public:
   theory::quantifiers::TriggerSelMode stringToTriggerSelMode(std::string option, std::string optarg) throw(OptionException);
   theory::quantifiers::TriggerActiveSelMode stringToTriggerActiveSelMode(std::string option, std::string optarg) throw(OptionException);
   theory::quantifiers::PrenexQuantMode stringToPrenexQuantMode(std::string option, std::string optarg) throw(OptionException);
-  theory::quantifiers::CegqiFairMode stringToCegqiFairMode(std::string option, std::string optarg) throw(OptionException);
   theory::quantifiers::TermDbMode stringToTermDbMode(std::string option, std::string optarg) throw(OptionException);
   theory::quantifiers::IteLiftQuantMode stringToIteLiftQuantMode(std::string option, std::string optarg) throw(OptionException);
   theory::quantifiers::CegqiSingleInvMode stringToCegqiSingleInvMode(std::string option, std::string optarg) throw(OptionException);
@@ -104,6 +104,7 @@ public:
   theory::quantifiers::QuantDSplitMode stringToQuantDSplitMode(std::string option, std::string optarg) throw(OptionException);
   theory::quantifiers::QuantRepMode stringToQuantRepMode(std::string option, std::string optarg) throw(OptionException);
   theory::quantifiers::FmfBoundMinMode stringToFmfBoundMinMode(std::string option, std::string optarg) throw(OptionException);
+  theory::SygusFairMode stringToSygusFairMode(std::string option, std::string optarg) throw(OptionException);
 
   // theory/bv/options_handlers.h
   void abcEnabledBuild(std::string option, bool value) throw(OptionException);
index 18c3bfedaa50af76e4ebad58ed7362660d0714a5..0b410e3fe1c2f44eabb516b421676a9ba13a13e7 100644 (file)
@@ -133,19 +133,6 @@ enum CVC4_PUBLIC PrenexQuantMode {
   PRENEX_QUANT_NORMAL,
 };
 
-enum CegqiFairMode {
-  /** enforce fairness by UF corresponding to datatypes size */
-  CEGQI_FAIR_UF_DT_SIZE,
-  /** enforce fairness by datatypes size */
-  CEGQI_FAIR_DT_SIZE,
-  /** enforce fairness by datatypes height bound */
-  CEGQI_FAIR_DT_HEIGHT_PRED,
-  /** enforce fairness by datatypes size bound */
-  CEGQI_FAIR_DT_SIZE_PRED,
-  /** do not use fair strategy for CEGQI */
-  CEGQI_FAIR_NONE,
-};
-
 enum TermDbMode {
   /** consider all terms in master equality engine */
   TERM_DB_ALL,
index f15723e085730dbaaa054ce7dc44ac9599b7d084..2cbf158732e813ff5704325c6db97714927a83c9 100644 (file)
@@ -245,8 +245,6 @@ option conjectureGenMaxDepth --conjecture-gen-max-depth=N int :default 3
 
 option ceGuidedInst --cegqi bool :default false :read-write
   counterexample-guided quantifier instantiation
-option ceGuidedInstFair --cegqi-fair=MODE CVC4::theory::quantifiers::CegqiFairMode :default CVC4::theory::quantifiers::CEGQI_FAIR_DT_SIZE :include "options/quantifiers_modes.h" :handler stringToCegqiFairMode
-  if and how to apply fairness for cegqi
 option cegqiSingleInvMode --cegqi-si=MODE CVC4::theory::quantifiers::CegqiSingleInvMode :default CVC4::theory::quantifiers::CEGQI_SI_MODE_NONE :include "options/quantifiers_modes.h" :handler stringToCegqiSingleInvMode :read-write
   mode for processing single invocation synthesis conjectures
 option cegqiSingleInvPartial --cegqi-si-partial bool :default false
@@ -261,29 +259,31 @@ option cegqiSingleInvReconstructConst --cegqi-si-reconstruct-const bool :default
   include constants when reconstruct solutions for single invocation conjectures in original grammar
 option cegqiSingleInvAbort --cegqi-si-abort bool :default false
   abort if synthesis conjecture is not single invocation
+option sygusPbe --sygus-pbe bool :default true
+  sygus advanced pruning based on examples
   
-option sygusNormalForm --sygus-nf bool :default true
-  only search for sygus builtin terms that are in normal form
-option sygusNormalFormArg --sygus-nf-arg bool :default true
-  account for relationship between arguments of operations in sygus normal form
-option sygusNormalFormGlobal --sygus-nf-sym bool :default true
-  narrow sygus search space based on global state of current candidate program
-option sygusNormalFormGlobalGen --sygus-nf-sym-gen bool :default true
-  generalize lemmas for global search space narrowing
-option sygusNormalFormGlobalArg --sygus-nf-sym-arg bool :default true
-  generalize based on arguments in global search space narrowing
-option sygusNormalFormGlobalContent --sygus-nf-sym-content bool :default true
-  generalize based on content in global search space narrowing
+option sygusMinGrammar --sygus-min-grammar bool :default true
+  statically minimize sygus grammars
+option sygusMinGrammarAgg --sygus-min-grammar-agg bool :default false
+  aggressively minimize sygus grammars
+option sygusAddConstGrammar --sygus-add-const-grammar bool :default true
+  statically add constants appearing in conjecture to grammars
   
 option sygusInvTemplMode --sygus-inv-templ=MODE CVC4::theory::quantifiers::SygusInvTemplMode :default CVC4::theory::quantifiers::SYGUS_INV_TEMPL_MODE_NONE :include "options/quantifiers_modes.h" :handler stringToSygusInvTemplMode
   template mode for sygus invariant synthesis
-option sygusUnifCondSol --sygus-unif-csol bool :default false
-  enable approach which unifies conditional solutions
+option sygusInvAutoUnfold --sygus-auto-unfold bool :default true
+  enable approach which automatically unfolds transition systems for directly solving invariant synthesis problems
+option sygusUnifCondSol --sygus-unif-csol bool :default true
+  enable new approach which unifies conditional solutions
 
 option sygusDirectEval --sygus-direct-eval bool :default true
   direct unfolding of evaluation functions
-option sygusCRefEval --sygus-cref-eval bool :default false
+option sygusUnfoldBool --sygus-unfold-bool bool :default true
+  do unfolding of Boolean evaluation functions that appear in refinement lemmas
+option sygusCRefEval --sygus-cref-eval bool :default true
   direct evaluation of refinement lemmas for conflict analysis
+option sygusCRefEvalMinExp --sygus-cref-eval-min-exp bool :default true
+  use min explain for direct evaluation of refinement lemmas for conflict analysis
   
 # approach applied to general quantified formulas
 option cbqi --cbqi bool :read-write :default false
index 622fa9c00239acbe622d80e9e9a4ba5ed908858f..c865332e217d4e1f91a923e5ec5d1f35fd82e37c 100644 (file)
@@ -1616,7 +1616,7 @@ tupleStore[CVC4::Expr& f]
       const Datatype & dt = ((DatatypeType)t).getDatatype();
       args.push_back( dt[0][k].getSelector() );
       args.push_back( f );
-      f2 = MK_EXPR(CVC4::kind::APPLY_SELECTOR_TOTAL,args);
+      f2 = MK_EXPR(CVC4::kind::APPLY_SELECTOR,args);
     }
     ( ( arrayStore[f2]
       | DOT ( tupleStore[f2]
@@ -1651,7 +1651,7 @@ recordStore[CVC4::Expr& f]
       const Datatype & dt = ((DatatypeType)t).getDatatype();
       args.push_back( dt[0][id].getSelector() );
       args.push_back( f );
-      f2 = MK_EXPR(CVC4::kind::APPLY_SELECTOR_TOTAL,args);
+      f2 = MK_EXPR(CVC4::kind::APPLY_SELECTOR,args);
     }
     ( ( arrayStore[f2]
       | DOT ( tupleStore[f2]
@@ -1802,7 +1802,7 @@ postfixTerm[CVC4::Expr& f]
           std::vector<Expr> sargs;
           sargs.push_back( dt[0][id].getSelector() );
           sargs.push_back( f );
-          f = MK_EXPR(CVC4::kind::APPLY_SELECTOR_TOTAL,sargs);
+          f = MK_EXPR(CVC4::kind::APPLY_SELECTOR,sargs);
         }
       | k=numeral
         { Type t = f.getType();
@@ -1819,7 +1819,7 @@ postfixTerm[CVC4::Expr& f]
           std::vector<Expr> sargs;
           sargs.push_back( dt[0][k].getSelector() );
           sargs.push_back( f );
-          f = MK_EXPR(CVC4::kind::APPLY_SELECTOR_TOTAL,sargs);
+          f = MK_EXPR(CVC4::kind::APPLY_SELECTOR,sargs);
         }
       )
     )*
index 8194e1933642f838a373aa43a93d6986cb68d6ad..5d24ec024142aa9a15ff385e2a5f4a6830bf6bf5 100644 (file)
@@ -578,6 +578,7 @@ sygusCommand [CVC4::PtrCloser<CVC4::Command>* cmd]
   std::map< CVC4::Type, CVC4::Type > sygus_to_builtin;
   std::map< CVC4::Type, CVC4::Expr > sygus_to_builtin_expr;
   int startIndex = -1;
+  Expr synth_fun;
 }
   : /* declare-var */
     DECLARE_VAR_TOK { PARSER_STATE->checkThatLogicIsSet(); }
@@ -601,7 +602,25 @@ sygusCommand [CVC4::PtrCloser<CVC4::Command>* cmd]
     { PARSER_STATE->checkThatLogicIsSet(); }
     symbol[fun,CHECK_UNDECLARED,SYM_VARIABLE]
     LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK
-    { seq.reset(new CommandSequence());
+    ( sortSymbol[range,CHECK_DECLARED] )? {
+      if( range.isNull() ){
+        PARSER_STATE->parseError("Must supply return type for synth-fun.");
+      }
+      seq.reset(new CommandSequence());
+      std::vector<Type> var_sorts;
+      for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
+            sortedVarNames.begin(), iend = sortedVarNames.end(); i != iend;
+          ++i) {
+        var_sorts.push_back( (*i).second );
+      }
+      Debug("parser-sygus") << "Define synth fun : " << fun << std::endl;
+      Type synth_fun_type;
+      if( var_sorts.size()>0 ){
+        synth_fun_type = EXPR_MANAGER->mkFunctionType(var_sorts, range);
+      }else{
+        synth_fun_type = range;
+      }
+      synth_fun = PARSER_STATE->mkVar(fun, synth_fun_type);
       PARSER_STATE->pushScope(true);
       for(std::vector<std::pair<std::string, CVC4::Type> >::const_iterator i =
             sortedVarNames.begin(), iend = sortedVarNames.end(); i != iend;
@@ -616,11 +635,12 @@ sygusCommand [CVC4::PtrCloser<CVC4::Command>* cmd]
       }
       terms.clear();
       terms.push_back(bvl);
-    }
-    ( sortSymbol[range,CHECK_DECLARED] )? {
-      if( range.isNull() ){
-        PARSER_STATE->parseError("Must supply return type for synth-fun.");
-      }
+      // associate this variable list with the synth fun
+      std::vector< Expr > attr_val_bvl;
+      attr_val_bvl.push_back( bvl );
+      Command* cattr_bvl = new SetUserAttributeCommand("sygus-synth-fun-var-list", synth_fun, attr_val_bvl);
+      cattr_bvl->setMuted(true);
+      PARSER_STATE->preemptCommand(cattr_bvl);
     }
     ( LPAREN_TOK
     ( LPAREN_TOK
@@ -664,18 +684,11 @@ sygusCommand [CVC4::PtrCloser<CVC4::Command>* cmd]
     )+
     RPAREN_TOK { read_syntax = true; }
     )?
-    { 
+    { // the sygus sym type specifies the required grammar for synth_fun, expressed as a type
+      Type sygus_sym_type;
       if( !read_syntax ){
-        //create the default grammar
-        Debug("parser-sygus") << "Make default grammar..." << std::endl;
-        PARSER_STATE->mkSygusDefaultGrammar(
-            range, terms[0], fun, datatypes, sorts, ops, sygus_vars,
-            startIndex);
-        //set start index
-        Debug("parser-sygus") << "Set start index " << startIndex << "..."
-                              << std::endl;
-        PARSER_STATE->setSygusStartIndex(fun, startIndex, datatypes, sorts,
-                                         ops);        
+        sygus_sym_type = range;
+        PARSER_STATE->popScope();
       }else{
         Debug("parser-sygus") << "--- Process " << sgts.size()
                               << " sygus gterms..." << std::endl;
@@ -708,57 +721,32 @@ sygusCommand [CVC4::PtrCloser<CVC4::Command>* cmd]
               datatypes[i], ops[i], cnames[i], cargs[i],
               unresolved_gterm_sym[i], sygus_to_builtin );
         }
-        PARSER_STATE->setSygusStartIndex(fun, startIndex, datatypes, sorts,
-                                         ops);
-      }
-      //only care about datatypes/sorts/ops past here
-      PARSER_STATE->popScope();
-      Debug("parser-sygus") << "--- Make " << datatypes.size()
-                            << " mutual datatypes..." << std::endl;
-      for( unsigned i=0; i<datatypes.size(); i++ ){
-        Debug("parser-sygus") << "  " << i << " : " << datatypes[i].getName()
-                              << std::endl;
-      }
-      std::vector<DatatypeType> datatypeTypes =
-          PARSER_STATE->mkMutualDatatypeTypes(datatypes);
-      seq->addCommand(new DatatypeDeclarationCommand(datatypeTypes));
-      std::map<DatatypeType, Expr> evals;
-      if( sorts[0]!=range ){
-        PARSER_STATE->parseError(std::string("Bad return type in grammar for "
-                                             "SyGuS function ") + fun);
-      }
-      // make all the evals first, since they are mutually referential
-      for(size_t i = 0; i < datatypeTypes.size(); ++i) {
-        DatatypeType dtt = datatypeTypes[i];
-        const Datatype& dt = dtt.getDatatype();
-        Expr eval = dt.getSygusEvaluationFunc();
-        Debug("parser-sygus") << "Make eval " << eval << " for " << dt.getName()
-                              << std::endl;
-        evals.insert(std::make_pair(dtt, eval));
-        if(i == 0) {
-          PARSER_STATE->addSygusFun(fun, eval);
+        PARSER_STATE->setSygusStartIndex(fun, startIndex, datatypes, sorts, ops);
+        //only care about datatypes/sorts/ops past here
+        PARSER_STATE->popScope();
+        Debug("parser-sygus") << "--- Make " << datatypes.size()
+                              << " mutual datatypes..." << std::endl;
+        for( unsigned i=0; i<datatypes.size(); i++ ){
+          Debug("parser-sygus") << "  " << i << " : " << datatypes[i].getName() << std::endl;
         }
-      }
-      // now go through and settle everything
-      for(size_t i = 0; i < datatypeTypes.size(); ++i) {
-        DatatypeType dtt = datatypeTypes[i];
-        const Datatype& dt = dtt.getDatatype();
-        Expr eval = evals[dtt];
-        Debug("parser-sygus") << "Sygus : process grammar : " << dt
-                              << std::endl;
-        for(size_t j = 0; j < dt.getNumConstructors(); ++j) {
-          Expr assertion = PARSER_STATE->getSygusAssertion(
-              datatypeTypes, ops, evals, terms, eval, dt, i, j );
-          seq->addCommand(new AssertCommand(assertion));
+        std::vector<DatatypeType> datatypeTypes =
+            PARSER_STATE->mkMutualDatatypeTypes(datatypes);
+        seq->addCommand(new DatatypeDeclarationCommand(datatypeTypes));
+        if( sorts[0]!=range ){
+          PARSER_STATE->parseError(std::string("Bad return type in grammar for "
+                                               "SyGuS function ") + fun);
         }
+        sygus_sym_type = datatypeTypes[0];
       }
+      
+      // store a dummy variable which stands for second-order quantification, linked to synth fun by an attribute
+      PARSER_STATE->addSygusFunSymbol( sygus_sym_type, synth_fun );
       cmd->reset(seq.release());
     }
   | /* constraint */
     CONSTRAINT_TOK { 
       PARSER_STATE->checkThatLogicIsSet();
       Debug("parser-sygus") << "Sygus : define sygus funs..." << std::endl;
-      PARSER_STATE->defineSygusFuns(); 
       Debug("parser-sygus") << "Sygus : read constraint..." << std::endl;
     }
     term[expr, expr2]
@@ -769,7 +757,6 @@ sygusCommand [CVC4::PtrCloser<CVC4::Command>* cmd]
   | INV_CONSTRAINT_TOK {  
       PARSER_STATE->checkThatLogicIsSet();
       Debug("parser-sygus") << "Sygus : define sygus funs..." << std::endl;
-      PARSER_STATE->defineSygusFuns(); 
       Debug("parser-sygus") << "Sygus : read inv-constraint..." << std::endl;
     }
     ( symbol[name,CHECK_NONE,SYM_VARIABLE] { 
@@ -796,9 +783,8 @@ sygusCommand [CVC4::PtrCloser<CVC4::Command>* cmd]
       }
       //make relevant terms
       for( unsigned i=0; i<4; i++ ){
-        Debug("parser-sygus") << "Make inv-constraint term #" << i << "..."
-                              << std::endl;
         Expr op = terms[i];
+        Debug("parser-sygus") << "Make inv-constraint term #" << i << " : " << op  << "..." << std::endl;
         std::vector< Expr > children;
         children.push_back( op );
         if( i==2 ){
@@ -806,13 +792,13 @@ sygusCommand [CVC4::PtrCloser<CVC4::Command>* cmd]
         }else{
           children.insert( children.end(), primed[0].begin(), primed[0].end() );
         }
-        terms[i] = EXPR_MANAGER->mkExpr(kind::APPLY,children);
+        terms[i] = EXPR_MANAGER->mkExpr( i==0 ? kind::APPLY_UF : kind::APPLY,children);
         if( i==0 ){
           std::vector< Expr > children2;
           children2.push_back( op );
           children2.insert(children2.end(), primed[1].begin(),
                            primed[1].end());
-          terms.push_back( EXPR_MANAGER->mkExpr(kind::APPLY,children2) );
+          terms.push_back( EXPR_MANAGER->mkExpr(kind::APPLY_UF,children2) );
         }
       }
       //make constraints
@@ -832,7 +818,7 @@ sygusCommand [CVC4::PtrCloser<CVC4::Command>* cmd]
     }
   | /* check-synth */
     CHECK_SYNTH_TOK
-    { PARSER_STATE->checkThatLogicIsSet(); PARSER_STATE->defineSygusFuns(); }
+    { PARSER_STATE->checkThatLogicIsSet(); }
     { Expr sygusVar = EXPR_MANAGER->mkVar("sygus", EXPR_MANAGER->booleanType());
       Expr inst_attr =EXPR_MANAGER->mkExpr(kind::INST_ATTRIBUTE, sygusVar);
       Expr sygusAttr = EXPR_MANAGER->mkExpr(kind::INST_PATTERN_LIST, inst_attr);
@@ -900,6 +886,12 @@ sygusGTerm[CVC4::SygusGTerm& sgt, std::string& fun]
           k = CVC4::kind::BITVECTOR_UDIV_TOTAL;
         }else if( k==CVC4::kind::BITVECTOR_UREM ){
           k = CVC4::kind::BITVECTOR_UREM_TOTAL;
+        }else if( k==CVC4::kind::DIVISION ){
+          k = CVC4::kind::DIVISION_TOTAL;
+        }else if( k==CVC4::kind::INTS_DIVISION ){
+          k = CVC4::kind::INTS_DIVISION_TOTAL;
+        }else if( k==CVC4::kind::INTS_MODULUS ){
+          k = CVC4::kind::INTS_MODULUS_TOTAL;
         }
         sgt.d_name = kind::kindToString(k);
         sgt.d_gterm_type = SygusGTerm::gterm_op;
@@ -952,6 +944,12 @@ sygusGTerm[CVC4::SygusGTerm& sgt, std::string& fun]
             k = CVC4::kind::BITVECTOR_UDIV_TOTAL;
           }else if( k==CVC4::kind::BITVECTOR_UREM ){
             k = CVC4::kind::BITVECTOR_UREM_TOTAL;
+          }else if( k==CVC4::kind::DIVISION ){
+            k = CVC4::kind::DIVISION_TOTAL;
+          }else if( k==CVC4::kind::INTS_DIVISION ){
+            k = CVC4::kind::INTS_DIVISION_TOTAL;
+          }else if( k==CVC4::kind::INTS_MODULUS ){
+            k = CVC4::kind::INTS_MODULUS_TOTAL;
           }
           sgt.d_name = kind::kindToString(k);
           sgt.d_gterm_type = SygusGTerm::gterm_op;
@@ -2084,6 +2082,7 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
            if( args.size()!=dtc.getNumArgs() ){
              PARSER_STATE->parseError("Bad number of arguments for application of constructor in pattern.");
            }
+           //FIXME: make MATCH a kind and make this a rewrite
            // build a lambda
            std::vector<Expr> largs;
            largs.push_back( MK_EXPR( CVC4::kind::BOUND_VAR_LIST, args ) );
@@ -2092,7 +2091,8 @@ term[CVC4::Expr& expr, CVC4::Expr& expr2]
            aargs.push_back( MK_EXPR( CVC4::kind::LAMBDA, largs ) );
            for( unsigned i=0; i<dtc.getNumArgs(); i++ ){
              //can apply total version since we will be guarded by ITE condition
-             aargs.push_back( MK_EXPR( CVC4::kind::APPLY_SELECTOR_TOTAL, dtc[i].getSelector(), expr ) );
+             // however, we need to apply partial version since we don't have the internal selector available
+             aargs.push_back( MK_EXPR( CVC4::kind::APPLY_SELECTOR, dtc[i].getSelector(), expr ) );
            }
            patexprs.push_back( MK_EXPR( CVC4::kind::APPLY, aargs ) );
            patconds.push_back( MK_EXPR( CVC4::kind::APPLY_TESTER, dtc.getTester(), expr ) );
index 7fa71890e734f66dae549d1cdac30a60916eb70d..fe5eb3ac8af4f046321ddcc6c0d7724acc37db63 100644 (file)
@@ -33,8 +33,7 @@ namespace parser {
 
 Smt2::Smt2(ExprManager* exprManager, Input* input, bool strictMode, bool parseOnly) :
   Parser(exprManager,input,strictMode,parseOnly),
-  d_logicSet(false),
-  d_nextSygusFun(0) {
+  d_logicSet(false) {
   d_unsatCoreNames.push(std::map<Expr, std::string>());
   if( !strictModeEnabled() ) {
     addTheory(Smt2::THEORY_CORE);
@@ -541,246 +540,6 @@ Expr Smt2::mkSygusVar(const std::string& name, const Type& type, bool isPrimed)
   return e;
 }
 
-void collectSygusGrammarTypesFor( Type range, std::vector< Type >& types, std::map< Type, std::vector< DatatypeConstructorArg > >& sels ){
-  if( !range.isBoolean() ){
-    if( std::find( types.begin(), types.end(), range )==types.end() ){
-      Debug("parser-sygus") << "...will make grammar for " << range << std::endl;
-      types.push_back( range );
-      if( range.isDatatype() ){
-        const Datatype& dt = ((DatatypeType)range).getDatatype();
-        for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-          for( unsigned j=0; j<dt[i].getNumArgs(); j++ ){
-            Type crange = ((SelectorType)dt[i][j].getType()).getRangeType();
-            sels[crange].push_back( dt[i][j] );
-            collectSygusGrammarTypesFor( crange, types, sels );
-          }
-        }
-      }
-    }
-  }
-}
-
-void Smt2::mkSygusDefaultGrammar( const Type& range, Expr& bvl, const std::string& fun, std::vector<CVC4::Datatype>& datatypes,
-                                  std::vector<Type>& sorts, std::vector< std::vector<Expr> >& ops, std::vector<Expr> sygus_vars, int& startIndex ) {
-
-  //if( !range.isBoolean() && !range.isInteger() && !range.isBitVector() && !range.isDatatype() ){
-  //  parseError("No default grammar for type.");
-  //}
-  startIndex = -1;
-  Debug("parser-sygus") << "Construct default grammar for " << fun << " " << range << std::endl;
-  std::map< CVC4::Type, CVC4::Type > sygus_to_builtin;
-
-  std::vector< Type > types;
-  std::map< Type, std::vector< DatatypeConstructorArg > > sels;
-  //types for each of the variables
-  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());
-
-  std::vector< Type > unres_types;
-  std::map< Type, 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_types.push_back(unres_t);
-    type_to_unres[types[i]] = unres_t;
-    sygus_to_builtin[unres_t] = types[i];
-  }
-  for( unsigned i=0; i<types.size(); i++ ){
-    Debug("parser-sygus") << "Make grammar for " << types[i] << " " << unres_types[i] << std::endl;
-    std::vector<std::string> cnames;
-    std::vector<std::vector<CVC4::Type> > cargs;
-    std::vector<std::string> unresolved_gterm_sym;
-    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];
-        Debug("parser-sygus") << "...add for variable " << ss.str() << std::endl;
-        ops[i].push_back( sygus_vars[j] );
-        cnames.push_back( ss.str() );
-        cargs.push_back( std::vector< CVC4::Type >() );
-      }
-    }
-    //add constants
-    std::vector< Expr > consts;
-    mkSygusConstantsForType( types[i], consts );
-    for( unsigned j=0; j<consts.size(); j++ ){
-      std::stringstream ss;
-      ss << consts[j];
-      Debug("parser-sygus") << "...add for constant " << ss.str() << std::endl;
-      ops[i].push_back( consts[j] );
-      cnames.push_back( ss.str() );
-      cargs.push_back( std::vector< CVC4::Type >() );
-    }
-    //ITE
-    CVC4::Kind k = kind::ITE;
-    Debug("parser-sygus") << "...add for " << k << std::endl;
-    ops[i].push_back(getExprManager()->operatorOf(k));
-    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;
-        Debug("parser-sygus") << "...add for " << k << std::endl;
-        ops[i].push_back(getExprManager()->operatorOf(k));
-        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() ){
-      Debug("parser-sygus") << "...add for constructors" << std::endl;
-      const Datatype& dt = ((DatatypeType)types[i]).getDatatype();
-      for( unsigned k=0; k<dt.getNumConstructors(); k++ ){
-        Debug("parser-sygus") << "...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++ ){
-          Type crange = ((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;
-      warning(sserr.str());
-    }
-    //add for all selectors to this type
-    if( !sels[types[i]].empty() ){
-      Debug("parser-sygus") << "...add for selectors" << std::endl;
-      for( unsigned j=0; j<sels[types[i]].size(); j++ ){
-        Debug("parser-sygus") << "...for " << sels[types[i]][j].getName() << std::endl;
-        Type arg_type = ((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] );
-      }
-    }
-    Debug("parser-sygus") << "...make datatype " << datatypes.back() << std::endl;
-    datatypes[i].setSygus( types[i], bvl, true, true );
-    mkSygusDatatype( datatypes[i], ops[i], cnames, cargs, unresolved_gterm_sym, sygus_to_builtin );
-    sorts.push_back( types[i] );
-    //set start index if applicable
-    if( types[i]==range ){
-      startIndex = i;
-    }
-  }
-
-  //make Boolean type
-  Type btype = getExprManager()->booleanType();
-  datatypes.push_back(Datatype(dbname));
-  ops.push_back(std::vector<Expr>());
-  std::vector<std::string> cnames;
-  std::vector<std::vector<CVC4::Type> > cargs;
-  std::vector<std::string> unresolved_gterm_sym;
-  Debug("parser-sygus") << "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];
-      Debug("parser-sygus") << "...add for variable " << ss.str() << std::endl;
-      ops.back().push_back( sygus_vars[i] );
-      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< Expr > consts;
-    mkSygusConstantsForType( btype, consts );
-    for( unsigned j=0; j<consts.size(); j++ ){
-      std::stringstream ss;
-      ss << consts[j];
-      Debug("parser-sygus") << "...add for constant " << ss.str() << std::endl;
-      ops.back().push_back( consts[j] );
-      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 );
-    Debug("parser-sygus") << "...add for " << k << std::endl;
-    ops.back().push_back(getExprManager()->operatorOf(k));
-    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++ ){
-    Debug("parser-sygus") << "...add predicates for " << types[i] << std::endl;
-    //add equality per type
-    CVC4::Kind k = kind::EQUAL;
-    Debug("parser-sygus") << "...add for " << k << std::endl;
-    ops.back().push_back(getExprManager()->operatorOf(k));
-    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;
-      Debug("parser-sygus") << "...add for " << k << std::endl;
-      ops.back().push_back(getExprManager()->operatorOf(k));
-      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
-      Debug("parser-sygus") << "...add for testers" << std::endl;
-      const Datatype& dt = ((DatatypeType)types[i]).getDatatype();
-      for( unsigned k=0; k<dt.getNumConstructors(); k++ ){
-        Debug("parser-sygus") << "...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 = sorts.size();
-  }
-  Debug("parser-sygus") << "...make datatype " << datatypes.back() << std::endl;
-  datatypes.back().setSygus( btype, bvl, true, true );
-  mkSygusDatatype( datatypes.back(), ops.back(), cnames, cargs, unresolved_gterm_sym, sygus_to_builtin );
-  sorts.push_back( btype );
-
-  Debug("parser-sygus") << "...finished make default grammar for " << fun << " " << range << std::endl;
-}
-
 void Smt2::mkSygusConstantsForType( const Type& type, std::vector<CVC4::Expr>& ops ) {
   if( type.isInteger() ){
     ops.push_back(getExprManager()->mkConst(Rational(0)));
@@ -1152,77 +911,22 @@ void Smt2::setSygusStartIndex( std::string& fun, int startIndex,
   }
 }
 
-void Smt2::defineSygusFuns() {
-  // only define each one once
-  while(d_nextSygusFun < d_sygusFuns.size()) {
-    std::pair<std::string, Expr> p = d_sygusFuns[d_nextSygusFun];
-    std::string fun = p.first;
-    Debug("parser-sygus") << "Sygus : define fun " << fun << std::endl;
-    Expr eval = p.second;
-    FunctionType evalType = eval.getType();
-    std::vector<Type> argTypes = evalType.getArgTypes();
-    Type rangeType = evalType.getRangeType();
-    Debug("parser-sygus") << "...eval type : " << evalType << ", #args=" << argTypes.size() << std::endl;
-
-    // first make the function type
-    std::vector<Expr> sygusVars;
-    std::vector<Type> funType;
-    for(size_t j = 1; j < argTypes.size(); ++j) {
-      funType.push_back(argTypes[j]);
-      std::stringstream ss;
-      ss << fun << "_v_" << j;
-      sygusVars.push_back(getExprManager()->mkBoundVar(ss.str(), argTypes[j]));
-    }
-    Type funt;
-    if( !funType.empty() ){
-      funt = getExprManager()->mkFunctionType(funType, rangeType);
-      Debug("parser-sygus") << "...eval function type : " << funt << std::endl;
-
-      // copy the bound vars
-      /*
-      std::vector<Expr> sygusVars;
-      //std::vector<Type> types;
-      for(size_t i = 0; i < d_sygusVars.size(); ++i) {
-        std::stringstream ss;
-        ss << d_sygusVars[i];
-        Type type = d_sygusVars[i].getType();
-        sygusVars.push_back(getExprManager()->mkBoundVar(ss.str(), type));
-        //types.push_back(type);
-      }
-      Debug("parser-sygus") << "...made vars, #vars=" << sygusVars.size() << std::endl;
-      */
-
-      //Type t = getExprManager()->mkFunctionType(types, rangeType);
-      //Debug("parser-sygus") << "...function type : " << t << std::endl;
-    }else{
-      funt = rangeType;
-    }
-    Expr lambda = mkFunction(fun, funt, ExprManager::VAR_FLAG_DEFINED);
-    Debug("parser-sygus") << "...made function : " << lambda << std::endl;
-    std::vector<Expr> applyv;
-    Expr funbv = getExprManager()->mkBoundVar(std::string("f") + fun, argTypes[0]);
-    d_sygusFunSymbols.push_back(funbv);
-    applyv.push_back(eval);
-    applyv.push_back(funbv);
-    for(size_t i = 0; i < sygusVars.size(); ++i) {
-      applyv.push_back(sygusVars[i]);
-    }
-    Expr apply = getExprManager()->mkExpr(kind::APPLY_UF, applyv);
-    Debug("parser-sygus") << "...made apply " << apply << std::endl;
-    Debug("parser-sygus") << "--> Define " << fun << " as " << lambda << " " << apply << std::endl;
-    Command* cmd = new DefineFunctionCommand(fun, lambda, sygusVars, apply);
-    preemptCommand(cmd);
-
-    ++d_nextSygusFun;
-  }
-}
-
 void Smt2::mkSygusDatatype( CVC4::Datatype& dt, std::vector<CVC4::Expr>& ops,
                             std::vector<std::string>& cnames, std::vector< std::vector< CVC4::Type > >& cargs,
                             std::vector<std::string>& unresolved_gterm_sym,
                             std::map< CVC4::Type, CVC4::Type >& sygus_to_builtin ) {
   Debug("parser-sygus") << "Making sygus datatype " << dt.getName() << std::endl;
   Debug("parser-sygus") << "  add constructors..." << std::endl;
+  std::vector<std::string> df_name; 
+  std::vector<CVC4::Expr> df_op;
+  std::vector< std::vector<Expr> > df_let_args;
+  std::vector< Expr > df_let_body;
+  //dt.mkSygusConstructors( ops, cnames, cargs, sygus_to_builtin, 
+  //                        d_sygus_let_func_to_vars, d_sygus_let_func_to_body, d_sygus_let_func_to_num_input_vars, 
+  //                        df_name, df_op, df_let_args, df_let_body );
+  
+  Debug("parser-sygus") << "SMT2 sygus parser : Making constructors for sygus datatype " << dt.getName() << std::endl;
+  Debug("parser-sygus") << "  add constructors..." << std::endl;
   for( int i=0; i<(int)cnames.size(); i++ ){
     bool is_dup = false;
     bool is_dup_op = false;
@@ -1283,9 +987,15 @@ void Smt2::mkSygusDatatype( CVC4::Datatype& dt, std::vector<CVC4::Expr>& ops,
       //replace operator and name
       ops[i] = mkFunction(ss.str(), ft, ExprManager::VAR_FLAG_DEFINED);
       cnames[i] = ss.str();
-      d_sygus_defined_funs.push_back( ops[i] );
-      preemptCommand( new DefineFunctionCommand(ss.str(), ops[i], let_args, let_body) );
-      addSygusDatatypeConstructor( dt, ops[i], cnames[i], cargs[i], let_body, let_args, 0 );
+      // indicate we need a define function
+      df_name.push_back( ss.str() );
+      df_op.push_back( ops[i] );
+      df_let_args.push_back( let_args );
+      df_let_body.push_back( let_body );
+      
+      //d_sygus_defined_funs.push_back( ops[i] );
+      //preemptCommand( new DefineFunctionCommand(ss.str(), ops[i], let_args, let_body) );
+      dt.addSygusConstructor( ops[i], cnames[i], cargs[i], let_body, let_args, 0 );
     }else{
       std::map< CVC4::Expr, CVC4::Expr >::iterator it = d_sygus_let_func_to_body.find( ops[i] );
       if( it!=d_sygus_let_func_to_body.end() ){
@@ -1293,9 +1003,10 @@ void Smt2::mkSygusDatatype( CVC4::Datatype& dt, std::vector<CVC4::Expr>& ops,
         let_args.insert( let_args.end(), d_sygus_let_func_to_vars[ops[i]].begin(), d_sygus_let_func_to_vars[ops[i]].end() );
         let_num_input_args = d_sygus_let_func_to_num_input_vars[ops[i]];
       }
-      addSygusDatatypeConstructor( dt, ops[i], cnames[i], cargs[i], let_body, let_args, let_num_input_args );
+      dt.addSygusConstructor( ops[i], cnames[i], cargs[i], let_body, let_args, let_num_input_args );
     }
   }
+
   Debug("parser-sygus") << "  add constructors for unresolved symbols..." << std::endl;
   if( !unresolved_gterm_sym.empty() ){
     std::vector< Type > types;
@@ -1320,12 +1031,18 @@ void Smt2::mkSygusDatatype( CVC4::Datatype& dt, std::vector<CVC4::Expr>& ops,
           std::stringstream ssid;
           ssid << unresolved_gterm_sym[i] << "_id";
           Expr id_op = mkFunction(ss.str(), ft, ExprManager::VAR_FLAG_DEFINED);
-          d_sygus_defined_funs.push_back( id_op );
-          preemptCommand( new DefineFunctionCommand(ssid.str(), id_op, let_args, let_body) );
+          // indicate we need a define function
+          df_name.push_back( ssid.str() );
+          df_op.push_back( id_op );
+          df_let_args.push_back( let_args );
+          df_let_body.push_back( let_body );
+          
+          //d_sygus_defined_funs.push_back( id_op );
+          //preemptCommand( new DefineFunctionCommand(ssid.str(), id_op, let_args, let_body) );
           //make the sygus argument list
           std::vector< Type > id_carg;
           id_carg.push_back( t );
-          addSygusDatatypeConstructor( dt, id_op, unresolved_gterm_sym[i], id_carg, let_body, let_args, 0 );
+          dt.addSygusConstructor( id_op, unresolved_gterm_sym[i], id_carg, let_body, let_args, 0 );
           //add to operators
           ops.push_back( id_op );
         }
@@ -1334,187 +1051,12 @@ void Smt2::mkSygusDatatype( CVC4::Datatype& dt, std::vector<CVC4::Expr>& ops,
       }
     }
   }
-
-}
-
-void Smt2::addSygusDatatypeConstructor( CVC4::Datatype& dt, CVC4::Expr op, std::string& cname, std::vector< CVC4::Type >& cargs,
-                                        CVC4::Expr& let_body, std::vector< CVC4::Expr >& let_args, unsigned let_num_input_args ) {
-  Debug("parser-sygus") << "--> Add constructor " << cname << " to " << dt.getName() << std::endl;
-  if( !let_body.isNull() ){
-    Debug("parser-sygus") << "    let body = " << let_body << ", args = " << let_args.size() << "," << let_num_input_args << std::endl;
-    //TODO : remove arguments not occurring in body
-    //if this is a self identity function, ignore
-    if( let_args.size()==0 && let_args[0]==let_body ){
-      Debug("parser-sygus") << "    identity function " << cargs[0] << " to " << dt.getName() << std::endl;
-      //TODO
-    }
-  }
-  std::string name = dt.getName() + "_" + cname;
-  std::string testerId("is-");
-  testerId.append(name);
-  checkDeclaration(name, CHECK_UNDECLARED, SYM_VARIABLE);
-  checkDeclaration(testerId, CHECK_UNDECLARED, SYM_VARIABLE);
-  CVC4::DatatypeConstructor c(name, testerId );
-  c.setSygus( op, let_body, let_args, let_num_input_args );
-  for( unsigned j=0; j<cargs.size(); j++ ){
-    Debug("parser-sygus-debug") << "  arg " << j << " : " << cargs[j] << std::endl;
-    std::stringstream sname;
-    sname << name << "_" << j;
-    c.addArg(sname.str(), cargs[j]);
-  }
-  dt.addConstructor(c);
-}
-
-
-// i is index in datatypes/ops
-// j is index is datatype
-Expr Smt2::getSygusAssertion( std::vector<DatatypeType>& datatypeTypes, std::vector< std::vector<Expr> >& ops,
-                              std::map<DatatypeType, Expr>& evals, std::vector<Expr>& terms,
-                              Expr eval, const Datatype& dt, size_t i, size_t j ) {
-  const DatatypeConstructor& ctor = dt[j];
-  Debug("parser-sygus") << "Sygus : process constructor " << j << " : " << dt[j] << std::endl;
-  std::vector<Expr> bvs, extraArgs;
-  for(size_t k = 0; k < ctor.getNumArgs(); ++k) {
-    std::string vname = "v_" + ctor[k].getName();
-    Expr bv = getExprManager()->mkBoundVar(vname, SelectorType(ctor[k].getType()).getRangeType());
-    bvs.push_back(bv);
-    extraArgs.push_back(bv);
-  }
-  if( !terms[0].isNull() ){
-    bvs.insert(bvs.end(), terms[0].begin(), terms[0].end());
-  }
-  Expr bvl;
-  if( !bvs.empty() ){
-    bvl = getExprManager()->mkExpr(kind::BOUND_VAR_LIST, bvs);
-  }
-  Debug("parser-sygus") << "...made bv list " << bvl << std::endl;
-  std::vector<Expr> patv;
-  patv.push_back(eval);
-  std::vector<Expr> applyv;
-  applyv.push_back(ctor.getConstructor());
-  applyv.insert(applyv.end(), extraArgs.begin(), extraArgs.end());
-  for(size_t k = 0; k < applyv.size(); ++k) {
-  }
-  Expr cpatv = getExprManager()->mkExpr(kind::APPLY_CONSTRUCTOR, applyv);
-  Debug("parser-sygus") << "...made eval ctor apply " << cpatv << std::endl;
-  patv.push_back(cpatv);
-  if( !terms[0].isNull() ){
-    patv.insert(patv.end(), terms[0].begin(), terms[0].end());
-  }
-  Expr evalApply = getExprManager()->mkExpr(kind::APPLY_UF, patv);
-  Debug("parser-sygus") << "...made eval apply " << evalApply << std::endl;
-  std::vector<Expr> builtApply;
-  for(size_t k = 0; k < extraArgs.size(); ++k) {
-    std::vector<Expr> patvb;
-    patvb.push_back(evals[DatatypeType(extraArgs[k].getType())]);
-    patvb.push_back(extraArgs[k]);
-    if( !terms[0].isNull() ){
-      patvb.insert(patvb.end(), terms[0].begin(), terms[0].end());
-    }
-    Debug("parser-sygus-debug") << "...add to built apply " << evals[DatatypeType(extraArgs[k].getType())] << " " << extraArgs[k] << " " << extraArgs[k].getType() << std::endl;
-    builtApply.push_back(getExprManager()->mkExpr(kind::APPLY_UF, patvb));
-    Debug("parser-sygus-debug") << "...added " << builtApply.back() << std::endl;
-  }
-  for(size_t k = 0; k < builtApply.size(); ++k) {
-  }
-  Expr builtTerm;
-  Debug("parser-sygus") << "...operator is : " << ops[i][j] << ", type = " << ops[i][j].getType() << ", kind = " << ops[i][j].getKind() << ", is defined = " << isDefinedFunction( ops[i][j] ) << std::endl;
-  if( ops[i][j].getKind() != kind::BUILTIN ){
-    Kind ok = kind::UNDEFINED_KIND;
-    if( isDefinedFunction( ops[i][j] ) || std::find( d_sygus_defined_funs.begin(), d_sygus_defined_funs.end(), ops[i][j] )!=d_sygus_defined_funs.end() ){
-      ok = kind::APPLY;
-    }else{
-      Type t = ops[i][j].getType();
-      if( t.isConstructor() ){
-        ok = kind::APPLY_CONSTRUCTOR;
-      }else if( t.isSelector() ){
-        ok = kind::APPLY_SELECTOR;
-      }else if( t.isTester() ){
-        ok = kind::APPLY_TESTER;
-      }else{
-        ok = getExprManager()->operatorToKind( ops[i][j] );
-      }
-    }
-    Debug("parser-sygus") << "...processed operator kind : " << ok << std::endl;
-    if( ok!=kind::UNDEFINED_KIND ){
-      builtTerm = getExprManager()->mkExpr(ok, ops[i][j], builtApply);
-    }else{
-      builtTerm = ops[i][j];
-    }
-  }else{
-    if( !builtApply.empty() ){
-      builtTerm = getExprManager()->mkExpr(ops[i][j], builtApply);
-    }else{
-      builtTerm = ops[i][j];
-    }
-  }
-  Debug("parser-sygus") << "...made built term " << builtTerm << std::endl;
-  Expr assertion = getExprManager()->mkExpr(kind::EQUAL, evalApply, builtTerm);
-  if( !bvl.isNull() ){
-    Expr pattern = getExprManager()->mkExpr(kind::INST_PATTERN, evalApply);
-    pattern = getExprManager()->mkExpr(kind::INST_PATTERN_LIST, pattern);
-    assertion = getExprManager()->mkExpr(kind::FORALL, bvl, assertion, pattern);
-  }
-  Debug("parser-sygus") << "...made assertion " << assertion << std::endl;
-
-  //linearize multiplication if possible
-  if( builtTerm.getKind()==kind::MULT ){
-    for(size_t k = 0; k < ctor.getNumArgs(); ++k) {
-      Type at = SelectorType(ctor[k].getType()).getRangeType();
-      if( at.isDatatype() ){
-        DatatypeType atd = (DatatypeType)SelectorType(ctor[k].getType()).getRangeType();
-        Debug("parser-sygus") << "Argument " << k << " " << atd << std::endl;
-        std::vector<DatatypeType>::iterator itd = std::find( datatypeTypes.begin(), datatypeTypes.end(), atd );
-        if( itd!=datatypeTypes.end() ){
-          Debug("parser-sygus2") << "Exists in datatypeTypes." << std::endl;
-          unsigned index = itd-datatypeTypes.begin();
-          Debug("parser-sygus2") << "index = " << index << std::endl;
-          bool isConst = true;
-          for( unsigned cc = 0; cc < ops[index].size(); cc++ ){
-            Debug("parser-sygus2") << "ops[" << cc << "]=" << ops[index][cc] << std::endl;
-            if( ops[index][cc].getKind() != kind::CONST_RATIONAL ){
-              isConst = false;
-              break;
-            }
-          }
-          if( isConst ){
-            Debug("parser-sygus") << "Linearize multiplication " << ctor << " based on argument " << k << std::endl;
-            const Datatype & atdd = atd.getDatatype();
-            std::vector<Expr> assertions;
-            std::vector<Expr> nbvs;
-            for( unsigned a=0; a<bvl.getNumChildren(); a++ ){
-              if( a!=k ){
-                nbvs.push_back( bvl[a] );
-              }
-            }
-            Expr nbvl = getExprManager()->mkExpr( kind::BOUND_VAR_LIST, nbvs );
-            for( unsigned cc = 0; cc < ops[index].size(); cc++ ){
-              //Make new assertion based on partially instantiating existing
-              applyv[k+1] = getExprManager()->mkExpr(kind::APPLY_CONSTRUCTOR, atdd[cc].getConstructor());
-              Debug("parser-sygus") << "applyv " << applyv[k+1] << std::endl;
-              cpatv = getExprManager()->mkExpr(kind::APPLY_CONSTRUCTOR, applyv);
-              Debug("parser-sygus") << "cpatv " << cpatv << std::endl;
-              patv[1] = cpatv;
-              evalApply = getExprManager()->mkExpr(kind::APPLY_UF, patv);
-              Debug("parser-sygus") << "evalApply " << evalApply << std::endl;
-              builtApply[k] = ops[index][cc];
-              Debug("parser-sygus") << "builtApply " << builtApply[k] << std::endl;
-              builtTerm = getExprManager()->mkExpr(ops[i][j], builtApply);
-              Debug("parser-sygus") << "builtTerm " << builtTerm << std::endl;
-              Expr eassertion = getExprManager()->mkExpr(kind::EQUAL, evalApply, builtTerm);
-              Expr epattern = getExprManager()->mkExpr(kind::INST_PATTERN, evalApply);
-              epattern = getExprManager()->mkExpr(kind::INST_PATTERN_LIST, epattern);
-              eassertion = getExprManager()->mkExpr(kind::FORALL, nbvl, eassertion, epattern);
-              assertions.push_back( eassertion );
-            }
-            assertion = assertions.size()==1 ? assertions[0] : getExprManager()->mkExpr( kind::AND, assertions );
-            Debug("parser-sygus") << "...(linearized) assertion is: " << assertion << std::endl;
-          }
-        }
-      }
-    }
+  
+  
+  for( unsigned i=0; i<df_name.size(); i++ ){
+    d_sygus_defined_funs.push_back( df_op[i] );
+    preemptCommand( new DefineFunctionCommand(df_name[i], df_op[i], df_let_args[i], df_let_body[i]) );
   }
-  return assertion;
 }
 
 const void Smt2::getSygusPrimedVars( std::vector<Expr>& vars, bool isPrimed ) {
@@ -1531,5 +1073,16 @@ const void Smt2::getSygusPrimedVars( std::vector<Expr>& vars, bool isPrimed ) {
   }
 }
 
+const void Smt2::addSygusFunSymbol( Type t, Expr synth_fun ){
+  Expr sym = mkBoundVar("sfproxy", t);
+  d_sygusFunSymbols.push_back(sym);
+  
+  std::vector< Expr > attr_value;
+  attr_value.push_back( synth_fun );
+  Command* cattr = new SetUserAttributeCommand("sygus-synth-fun", sym, attr_value);
+  cattr->setMuted(true);
+  preemptCommand(cattr);
+}
+
 }/* CVC4::parser namespace */
 }/* CVC4 namespace */
index 8222ac3a35dcf7204dadbf775cca720895cb77f5..3eed0e871927a863909fec9311b3805e780d120a 100644 (file)
@@ -62,10 +62,9 @@ private:
   std::pair<Expr, std::string> d_lastNamedTerm;
   // this is a user-context stack
   std::stack< std::map<Expr, std::string> > d_unsatCoreNames;
+  // for sygus
   std::vector<Expr> d_sygusVars, d_sygusConstraints, d_sygusFunSymbols;
-  std::vector< std::pair<std::string, Expr> > d_sygusFuns;
   std::map< Expr, bool > d_sygusVarPrimed;
-  size_t d_nextSygusFun;
 
 protected:
   Smt2(ExprManager* exprManager, Input* input, bool strictMode = false, bool parseOnly = false);
@@ -179,9 +178,6 @@ public:
 
   Expr mkSygusVar(const std::string& name, const Type& type, bool isPrimed = false);
 
-  void mkSygusDefaultGrammar( const Type& range, Expr& bvl, const std::string& fun, std::vector<CVC4::Datatype>& datatypes,
-                              std::vector<Type>& sorts, std::vector< std::vector<Expr> >& ops, std::vector<Expr> sygus_vars, int& startIndex );
-
   void mkSygusConstantsForType( const Type& type, std::vector<CVC4::Expr>& ops );
 
   void processSygusGTerm( CVC4::SygusGTerm& sgt, int index,
@@ -218,24 +214,11 @@ public:
                            std::vector< CVC4::Type>& sorts,
                            std::vector< std::vector<CVC4::Expr> >& ops );
 
-  void addSygusFun(const std::string& fun, Expr eval) {
-    d_sygusFuns.push_back(std::make_pair(fun, eval));
-  }
-
-  void defineSygusFuns();
-
   void mkSygusDatatype( CVC4::Datatype& dt, std::vector<CVC4::Expr>& ops,
                         std::vector<std::string>& cnames, std::vector< std::vector< CVC4::Type > >& cargs,
                         std::vector<std::string>& unresolved_gterm_sym,
                         std::map< CVC4::Type, CVC4::Type >& sygus_to_builtin );
 
-  // i is index in datatypes/ops
-  // j is index is datatype
-  Expr getSygusAssertion( std::vector<DatatypeType>& datatypeTypes, std::vector< std::vector<Expr> >& ops,
-                          std::map<DatatypeType, Expr>& evals, std::vector<Expr>& terms,
-                          Expr eval, const Datatype& dt, size_t i, size_t j );
-
-
 
   void addSygusConstraint(Expr constraint) {
     d_sygusConstraints.push_back(constraint);
@@ -254,6 +237,7 @@ public:
   }
   const void getSygusPrimedVars( std::vector<Expr>& vars, bool isPrimed );
 
+  const void addSygusFunSymbol( Type t, Expr synth_fun );
   const std::vector<Expr>& getSygusFunSymbols() {
     return d_sygusFunSymbols;
   }
@@ -327,9 +311,6 @@ private:
 
   void collectSygusLetArgs( CVC4::Expr e, std::vector< CVC4::Type >& sygusArgs, std::vector< CVC4::Expr >& builtinArgs );
 
-  void addSygusDatatypeConstructor( CVC4::Datatype& dt, CVC4::Expr op, std::string& cname, std::vector< CVC4::Type >& cargs,
-                                    CVC4::Expr& let_body, std::vector< CVC4::Expr >& let_args, unsigned let_num_input_args );
-
   Type processSygusNestedGTerm( int sub_dt_index, std::string& sub_dname, std::vector< CVC4::Datatype >& datatypes,
                                 std::vector< CVC4::Type>& sorts,
                                 std::vector< std::vector<CVC4::Expr> >& ops,
index 03029f27e7b9518605abc22322d222fe70ffc9fd..69ba63a475041e5947c9a399e7c96c1100b8f92f 100644 (file)
@@ -392,18 +392,22 @@ void CvcPrinter::toStream(std::ostream& out, TNode n, int depth, bool types, boo
       break;
     case kind::APPLY_SELECTOR:
     case kind::APPLY_SELECTOR_TOTAL: {
-        TypeNode t = n.getType();
+        TypeNode t = n[0].getType();
+        Node opn = n.getOperator();
         if( t.isTuple() ){
           toStream(out, n[0], depth, types, true);
-          out << '.' << Datatype::indexOf( n.getOperator().toExpr() );
+          const Datatype& dt = ((DatatypeType)t.toType()).getDatatype();
+          int sindex = dt[0].getSelectorIndexInternal( opn.toExpr() );
+          out << '.' << sindex;
         }else if( t.isRecord() ){
           toStream(out, n[0], depth, types, true);
           const Record& rec = t.getRecord();
-          unsigned index = Datatype::indexOf( n.getOperator().toExpr() );
-          std::pair<std::string, Type> fld = rec[index];
+          const Datatype& dt = ((DatatypeType)t.toType()).getDatatype();
+          int sindex = dt[0].getSelectorIndexInternal( opn.toExpr() );
+          std::pair<std::string, Type> fld = rec[sindex];
           out << '.' << fld.first;
         }else{
-          toStream(op, n.getOperator(), depth, types, false);
+          toStream(op, opn, depth, types, false);
         }
       }
       break;
index 923574faedafdb5a35a07112dd2cd9f91ba8f6c6..074041262a9047e191be1df8ef43570ef7a01330 100644 (file)
@@ -825,10 +825,10 @@ static string smtKindString(Kind k) throw() {
   case kind::GEQ: return ">=";
   case kind::DIVISION:
   case kind::DIVISION_TOTAL: return "/";
+  case kind::INTS_DIVISION_TOTAL: 
   case kind::INTS_DIVISION: return "div";
-  case kind::INTS_DIVISION_TOTAL: return "INTS_DIVISION_TOTAL";
+  case kind::INTS_MODULUS_TOTAL: 
   case kind::INTS_MODULUS: return "mod";
-  case kind::INTS_MODULUS_TOTAL: return "INTS_MODULUS_TOTAL";
   case kind::ABS: return "abs";
   case kind::IS_INTEGER: return "is_int";
   case kind::TO_INTEGER: return "to_int";
index e9e21fb4821f7007a60809a3df152d02925d03b3..6960c4684ab96468bcb7bdc3382b0a44356eba77 100644 (file)
@@ -89,6 +89,7 @@
 #include "theory/quantifiers/fun_def_process.h"
 #include "theory/quantifiers/macros.h"
 #include "theory/quantifiers/quantifiers_rewriter.h"
+#include "theory/quantifiers/term_database.h"
 #include "theory/sort_inference.h"
 #include "theory/strings/theory_strings.h"
 #include "theory/substitutions.h"
@@ -4605,11 +4606,17 @@ Result SmtEngine::checkSynth(const Expr& e) throw(TypeCheckingException, ModalEx
   if( conj.getKind()==kind::FORALL ){
     //possibly run quantifier elimination to make formula into single invocation
     if( conj[1].getKind()==kind::EXISTS ){
-      Node conj_se = conj[1][1];
+      Node conj_se = Node::fromExpr( expandDefinitions( conj[1][1].toExpr() ) );
 
       Trace("smt-synth") << "Compute single invocation for " << conj_se << "..." << std::endl;
-      quantifiers::SingleInvocationPartition sip( kind::APPLY );
-      sip.init( conj_se );
+      quantifiers::SingleInvocationPartition sip;
+      std::vector< Node > funcs;
+      for( unsigned i=0; i<conj[0].getNumChildren(); i++ ){
+        Node sf = conj[0][i].getAttribute(theory::SygusSynthFunAttribute());
+        Assert( !sf.isNull() );
+        funcs.push_back( sf );
+      }
+      sip.init( funcs, conj_se );
       Trace("smt-synth") << "...finished, got:" << std::endl;
       sip.debugPrint("smt-synth");
 
index e8ec72b37bb1f88b302a48683147247e2e9152b2..025fe0349f528c3e2d62c612514841cc8945c0ff 100644 (file)
@@ -112,18 +112,22 @@ public:
       // Have to be careful not to rewrite well-typed expressions
       // where the selector doesn't match the constructor,
       // e.g. "pred(zero)".
+      TypeNode tn = in.getType();
+      TypeNode argType = in[0].getType();
       TNode selector = in.getOperator();
       TNode constructor = in[0].getOperator();
-      Expr selectorExpr = selector.toExpr();
-      Expr constructorExpr = constructor.toExpr();
-      size_t selectorIndex = Datatype::indexOf(selectorExpr);
-      size_t constructorIndex = Datatype::indexOf(constructorExpr);
-      const Datatype& dt = Datatype::datatypeOf(selectorExpr);
+      size_t constructorIndex = Datatype::indexOf(constructor.toExpr());
+      const Datatype& dt = Datatype::datatypeOf(selector.toExpr());
       const DatatypeConstructor& c = dt[constructorIndex];
-      if(c.getNumArgs() > selectorIndex && c[selectorIndex].getSelector() == selectorExpr) {
+      Trace("datatypes-rewrite-debug") << "Rewriting collapsable selector : " << in;
+      Trace("datatypes-rewrite-debug") << ", cindex = " << constructorIndex << ", selector is " << selector << std::endl;
+      int selectorIndex = c.getSelectorIndexInternal( selector.toExpr() );
+      Trace("datatypes-rewrite-debug") << "Internal selector index is " << selectorIndex << std::endl;
+      if( selectorIndex>=0 ){
+        Assert( selectorIndex<(int)c.getNumArgs() );
         if( dt.isCodatatype() && in[0][selectorIndex].isConst() ){
           //must replace all debruijn indices with self  
-          Node sub = replaceDebruijn( in[0][selectorIndex], in[0], in[0].getType(), 0 );
+          Node sub = replaceDebruijn( in[0][selectorIndex], in[0], argType, 0 );
           Trace("datatypes-rewrite") << "DatatypesRewriter::postRewrite: "
                                      << "Rewrite trivial codatatype selector " << in << " to " << sub << std::endl;
           if( sub!=in ){
@@ -135,8 +139,6 @@ public:
           return RewriteResponse(REWRITE_DONE, in[0][selectorIndex]);
         }
       }else{
-        //typically should not be called
-        TypeNode tn = in.getType();
         Node gt;
         bool useTe = true;
         //if( !tn.isSort() ){
@@ -206,6 +208,11 @@ public:
         Trace("datatypes-rewrite") << "DatatypesRewriter::postRewrite: rewrite height " << in << " to " << res << std::endl;
         return RewriteResponse(REWRITE_AGAIN_FULL, res );
       }
+    }else if( in.getKind()==kind::DT_SIZE_BOUND ){
+      if( in[0].isConst() ){
+        Node res = NodeManager::currentNM()->mkNode( kind::LEQ, NodeManager::currentNM()->mkNode( kind::DT_SIZE, in[0] ), in[1] );
+        return RewriteResponse(REWRITE_AGAIN_FULL, res );
+      }
     }
 
     if(in.getKind() == kind::EQUAL ) {
@@ -271,22 +278,25 @@ public:
     Assert( index>=0 && index<(int)dt.getNumConstructors() );
     std::vector< Node > children;
     children.push_back( Node::fromExpr( dt[index].getConstructor() ) );
-    for( int i=0; i<(int)dt[index].getNumArgs(); i++ ){
-      Node nc = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[index][i].getSelector() ), n );
+    Type t = n.getType().toType();
+    for( unsigned i=0; i<dt[index].getNumArgs(); i++ ){
+      Node nc = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[index].getSelectorInternal( t, i ) ), n );
       children.push_back( nc );
     }
     Node n_ic = NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, children );
-    //add type ascription for ambiguous constructor types
-    if(!n_ic.getType().isComparableTo(n.getType())) {
-      Assert( dt.isParametric() );
-      Debug("datatypes-parametric") << "DtInstantiate: ambiguous type for " << n_ic << ", ascribe to " << n.getType() << std::endl;
-      Debug("datatypes-parametric") << "Constructor is " << dt[index] << std::endl;
-      Type tspec = dt[index].getSpecializedConstructorType(n.getType().toType());
-      Debug("datatypes-parametric") << "Type specification is " << tspec << std::endl;
-      children[0] = NodeManager::currentNM()->mkNode(kind::APPLY_TYPE_ASCRIPTION,
-                                                     NodeManager::currentNM()->mkConst(AscriptionType(tspec)), children[0] );
-      n_ic = NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, children );
-      Assert( n_ic.getType()==n.getType() );
+    if( dt.isParametric() ){
+      TypeNode tn = TypeNode::fromType( t );
+      //add type ascription for ambiguous constructor types
+      if(!n_ic.getType().isComparableTo(tn)) {
+        Debug("datatypes-parametric") << "DtInstantiate: ambiguous type for " << n_ic << ", ascribe to " << n.getType() << std::endl;
+        Debug("datatypes-parametric") << "Constructor is " << dt[index] << std::endl;
+        Type tspec = dt[index].getSpecializedConstructorType(n.getType().toType());
+        Debug("datatypes-parametric") << "Type specification is " << tspec << std::endl;
+        children[0] = NodeManager::currentNM()->mkNode(kind::APPLY_TYPE_ASCRIPTION,
+                                                       NodeManager::currentNM()->mkConst(AscriptionType(tspec)), children[0] );
+        n_ic = NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, children );
+        Assert( n_ic.getType()==tn );
+      }
     }
     Assert( isInstCons( n, n_ic, dt )==index );
     //n_ic = Rewriter::rewrite( n_ic );
@@ -297,9 +307,10 @@ public:
     if( n.getKind()==kind::APPLY_CONSTRUCTOR ){
       int index = Datatype::indexOf( n.getOperator().toExpr() );
       const DatatypeConstructor& c = dt[index];
+      Type nt = n.getType().toType();
       for( unsigned i=0; i<n.getNumChildren(); i++ ){
         if( n[i].getKind()!=kind::APPLY_SELECTOR_TOTAL ||
-            n[i].getOperator()!=Node::fromExpr( c[i].getSelector() ) ||
+            n[i].getOperator()!=Node::fromExpr( c.getSelectorInternal( nt, i ) ) ||
             n[i][0]!=t ){
           return -1;
         }
@@ -610,7 +621,6 @@ public:
       return Node::null();
     }
   }
-  
   static Node normalizeTupleConstructorApp( Node n ){
     Assert( n.getType().isTuple() );
     Assert( n.getKind()==kind::APPLY_CONSTRUCTOR );
@@ -634,7 +644,7 @@ public:
       return NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, ch );
     }
     return n;
-  }
+  }  
   //normalize constant : apply to top-level codatatype constants
   static Node normalizeConstant( Node n ){
     TypeNode tn = n.getType();
index e308ad845bfd6065b0bc22ef34a2aa68dcf682f8..8a8660303a5834437efa5f83551801348504ec57 100644 (file)
@@ -20,6 +20,8 @@
 #include "theory/datatypes/datatypes_rewriter.h"
 #include "theory/datatypes/datatypes_sygus.h"
 #include "theory/quantifiers/term_database.h"
+#include "theory/datatypes/theory_datatypes.h"
+#include "theory/theory_model.h"
 
 using namespace CVC4;
 using namespace CVC4::kind;
@@ -27,370 +29,606 @@ using namespace CVC4::context;
 using namespace CVC4::theory;
 using namespace CVC4::theory::datatypes;
 
-void SygusSplit::getSygusSplits( Node n, const Datatype& dt, std::vector< Node >& splits, std::vector< Node >& lemmas ) {
+Node SygusSplitNew::getSygusSplit( quantifiers::TermDbSygus * tds, Node n, const Datatype& dt ) {
+  TypeNode tnn = n.getType();
+  tds->registerSygusType( tnn );
+  std::vector< Node > curr_splits;
+  for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
+    Trace("sygus-split-debug2") << "Add split " << n << " : constructor " << dt[i].getName() << " : ";
+    if( !tds->isGenericRedundant( tnn, i ) ){
+      std::vector< Node > test_c;
+      test_c.push_back( DatatypesRewriter::mkTester( n, i, dt ) );
+      Node test = test_c.size()==1 ? test_c[0] : NodeManager::currentNM()->mkNode( AND, test_c );
+      curr_splits.push_back( test );
+      Trace("sygus-split-debug2") << "SUCCESS" << std::endl;
+      Trace("sygus-split-debug") << "Disjunct #" << curr_splits.size() << " : " << test << std::endl;
+    }else{
+      Trace("sygus-split-debug2") << "redundant operator" << std::endl;
+    }
+  }
+  Assert( !curr_splits.empty() );
+  return curr_splits.size()==1 ? curr_splits[0] : NodeManager::currentNM()->mkNode( OR, curr_splits );
+
+}
+void SygusSplitNew::getSygusSplits( Node n, const Datatype& dt, std::vector< Node >& splits, std::vector< Node >& lemmas ) {
   Assert( dt.isSygus() );
   if( d_splits.find( n )==d_splits.end() ){
     Trace("sygus-split") << "Get sygus splits " << n << std::endl;
-    //get the kinds for child datatype
-    TypeNode tnn = n.getType();
-    registerSygusType( tnn );
+    Node split = getSygusSplit( d_tds, n, dt );
+    Assert( !split.isNull() );
+    d_splits[n].push_back( split );
+  }
+  //copy to splits
+  splits.insert( splits.end(), d_splits[n].begin(), d_splits[n].end() );
+}
+
 
-    //get parent information, if possible
-    int csIndex = -1;
-    int sIndex = -1;
-    Node arg1;
-    TypeNode tn1;
-    TypeNode tnnp;
-    Node ptest;
-    if( n.getKind()==APPLY_SELECTOR_TOTAL ){
-      Node op = n.getOperator();
-      Expr selectorExpr = op.toExpr();
-      const Datatype& pdt = Datatype::datatypeOf(selectorExpr);
-      Assert( pdt.isSygus() );
-      csIndex = Datatype::cindexOf(selectorExpr);
-      sIndex = Datatype::indexOf(selectorExpr);
-      tnnp = n[0].getType();
-      //register the constructors that are redundant children of argument sIndex of constructor index csIndex of dt
-      registerSygusTypeConstructorArg( tnn, dt, tnnp, pdt, csIndex, sIndex );
+SygusSymBreakNew::SygusSymBreakNew( TheoryDatatypes * td, quantifiers::TermDbSygus * tds, context::Context* c ) : 
+d_td( td ), d_tds( tds ), d_context( c ), 
+d_testers( c ), d_is_const( c ), d_testers_exp( c ), d_active_terms( c ), d_currTermSize( c ) {
+  d_zero = NodeManager::currentNM()->mkConst( Rational(0) );
+}
 
-      if( options::sygusNormalFormArg() ){
-        if( sIndex==1 && pdt[csIndex].getNumArgs()==2 ){
-          arg1 = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( pdt[csIndex][0].getSelector() ), n[0] );
-          tn1 = arg1.getType();
-          if( !tn1.isDatatype() ){
-            arg1 = Node::null();
+SygusSymBreakNew::~SygusSymBreakNew() {
+  for( std::map< Node, SearchSizeInfo * >::iterator it = d_szinfo.begin(); it != d_szinfo.end(); ++it ){
+    delete it->second;
+  }
+}
+
+/** add tester */
+void SygusSymBreakNew::assertTester( int tindex, TNode n, Node exp, std::vector< Node >& lemmas ) {
+  registerTerm( n, lemmas );
+  // check if this is a relevant (sygus) term
+  if( d_term_to_anchor.find( n )!=d_term_to_anchor.end() ){
+    Trace("sygus-sb-debug2") << "Sygus : process tester : " << exp << std::endl;
+    // if not already active (may have duplicate calls for the same tester)
+    if( d_active_terms.find( n )==d_active_terms.end() ) {
+      d_testers[n] = tindex;
+      d_testers_exp[n] = exp;
+      
+      // check if parent is active
+      bool do_add = true;
+      if( options::sygusSymBreakLazy() ){
+        if( n.getKind()==kind::APPLY_SELECTOR_TOTAL ){
+          NodeSet::const_iterator it = d_active_terms.find( n[0] );
+          if( it==d_active_terms.end() ){
+            do_add = false;
+          }else{
+            //this must be a proper selector
+            IntMap::const_iterator itt = d_testers.find( n[0] );
+            Assert( itt!=d_testers.end() );
+            int ptindex = (*itt).second;
+            TypeNode ptn = n[0].getType();
+            const Datatype& pdt = ((DatatypeType)ptn.toType()).getDatatype();
+            int sindex_in_parent = pdt[ptindex].getSelectorIndexInternal( n.getOperator().toExpr() );
+            // the tester is irrelevant in this branch
+            if( sindex_in_parent==-1 ){
+              do_add = false;
+            }
           }
         }
       }
-      // we are splitting on a term that may later have no semantics : guard this case
-      ptest = DatatypesRewriter::mkTester( n[0], csIndex, pdt );
-      Trace("sygus-split-debug") << "Parent guard : " << ptest << std::endl;
+      if( do_add ){
+        assertTesterInternal( tindex, n, exp, lemmas );
+      }else{
+        Trace("sygus-sb-debug2") << "...ignore inactive tester : " << exp << std::endl;
+      }
+    }else{
+      Trace("sygus-sb-debug2") << "...ignore repeated tester : " << exp << std::endl;
     }
+  }else{
+    Trace("sygus-sb-debug2") << "...ignore non-sygus tester : " << exp << std::endl;
+  }
+}
 
-    std::vector< Node > ptest_c;
-    bool narrow = false;
-    for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-      Trace("sygus-split-debug2") << "Add split " << n << " : constructor " << dt[i].getName() << " : ";
-      Assert( d_sygus_nred.find( tnn )!=d_sygus_nred.end() );
-      bool addSplit = d_sygus_nred[tnn][i];
-      if( addSplit ){
-        if( csIndex!=-1 ){
-          Assert( d_sygus_pc_nred[tnn][csIndex].find( sIndex )!=d_sygus_pc_nred[tnn][csIndex].end() );
-          addSplit = d_sygus_pc_nred[tnn][csIndex][sIndex][i];
+void SygusSymBreakNew::assertFact( Node n, bool polarity, std::vector< Node >& lemmas ) {
+  if( n.getKind()==kind::DT_SYGUS_TERM_ORDER ){
+    if( polarity ){
+      Trace("sygus-sb-torder") << "Sygus term order : " << n[0] << " < " << n[1] << std::endl;
+      Node comm_sb = getTermOrderPredicate( n[0], n[1] );
+      Node comm_lem = NodeManager::currentNM()->mkNode( kind::OR, n.negate(), comm_sb );
+      lemmas.push_back( comm_lem );
+    }
+  }else if( n.getKind()==kind::DT_SYGUS_BOUND ){
+    Node m = n[0];
+    Trace("sygus-fair") << "Have sygus bound : " << n << ", polarity=" << polarity << " on measure " << m << std::endl;
+    registerMeasureTerm( m );
+    if( options::sygusFair()==SYGUS_FAIR_DT_SIZE ){
+      std::map< Node, SearchSizeInfo * >::iterator its = d_szinfo.find( m );
+      Assert( its!=d_szinfo.end() );
+      Node mt = its->second->getOrMkSygusMeasureTerm( lemmas );
+      //it relates the measure term to arithmetic
+      Node blem = n.eqNode( NodeManager::currentNM()->mkNode( kind::LEQ, mt, n[1] ) );
+      lemmas.push_back( blem );
+    }
+    if( polarity ){
+      unsigned s = n[1].getConst<Rational>().getNumerator().toUnsignedInt();
+      notifySearchSize( m, s, n, lemmas );
+    }
+  }else if( n.getKind() == kind::DT_SYGUS_IS_CONST ){
+    assertIsConst( n[0], polarity, lemmas );
+  }else if( n.getKind() == kind::DT_HEIGHT_BOUND || n.getKind()==DT_SIZE_BOUND ){
+    //reduce to arithmetic TODO ?
+
+  }
+}
+
+void SygusSymBreakNew::assertIsConst( Node n, bool polarity, std::vector< Node >& lemmas ) {
+  if( d_active_terms.find( n )!=d_active_terms.end() ) {
+    // what kind of constructor is n?
+    IntMap::const_iterator itt = d_testers.find( n );
+    Assert( itt!=d_testers.end() );
+    int tindex = (*itt).second;
+    TypeNode tn = n.getType();
+    const Datatype& dt = ((DatatypeType)tn.toType()).getDatatype();
+    Node lem;
+    if( dt[tindex].getNumArgs()==0 ){
+      // is this a constant?
+      Node sygus_op = Node::fromExpr( dt[tindex].getSygusOp() );
+      if( sygus_op.isConst()!=polarity ){
+        lem = NodeManager::currentNM()->mkNode( kind::DT_SYGUS_IS_CONST, n );
+        if( polarity ){
+          lem.negate();
         }
-        if( addSplit ){
-          std::vector< Node > test_c;
-          Node test = DatatypesRewriter::mkTester( n, i, dt );
-          test_c.push_back( test );
-          //check if we can strengthen the first argument
-          if( !arg1.isNull() ){
-            const Datatype& dt1 = ((DatatypeType)(tn1).toType()).getDatatype();
-            Kind k = d_tds->getArgKind( tnnp, csIndex );
-            //size comparison for arguments (if necessary)
-            Node sz_leq;
-            if( tn1==tnn && quantifiers::TermDb::isComm( k ) ){
-              sz_leq = NodeManager::currentNM()->mkNode( LEQ, NodeManager::currentNM()->mkNode( DT_SIZE, n ), NodeManager::currentNM()->mkNode( DT_SIZE, arg1 ) );
-            }
-            std::map< int, std::vector< int > >::iterator it = d_sygus_pc_arg_pos[tnn][csIndex].find( i );
-            if( it!=d_sygus_pc_arg_pos[tnn][csIndex].end() ){
-              Assert( !it->second.empty() );
-              std::vector< Node > lem_c;
-              for( unsigned j=0; j<it->second.size(); j++ ){
-                Node tt = DatatypesRewriter::mkTester( arg1, it->second[j], dt1 );
-                //if commutative operator, and children have same constructor type, then first arg is larger than second arg
-                if( it->second[j]==(int)i && !sz_leq.isNull() ){
-                  tt = NodeManager::currentNM()->mkNode( AND, tt, sz_leq );
-                }
-                lem_c.push_back( tt );
-              }
-              Node argStr = lem_c.size()==1 ? lem_c[0] : NodeManager::currentNM()->mkNode( OR, lem_c );
-              Trace("sygus-str") << "...strengthen corresponding first argument of " << test << " : " << argStr << std::endl;
-              test_c.push_back( argStr );
-              narrow = true;
-            }else{
-              if( !sz_leq.isNull() ){
-                test_c.push_back( NodeManager::currentNM()->mkNode( OR, DatatypesRewriter::mkTester( arg1, i, dt1 ).negate(), sz_leq ) );
-                narrow = true;
-              }
-            }
-          }
-          //other constraints on arguments
-          Kind curr = d_tds->getArgKind( tnn, i );
-          if( curr!=UNDEFINED_KIND ){
-            //ITE children must be distinct when properly typed
-            if( curr==ITE ){
-              if( d_tds->getArgType( dt[i], 1 )==tnn && d_tds->getArgType( dt[i], 2 )==tnn ){
-                Node arg_ite1 = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[i][1].getSelector() ), n );
-                Node arg_ite2 = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[i][2].getSelector() ), n );
-                Node deq = arg_ite1.eqNode( arg_ite2 ).negate();
-                Trace("sygus-str") << "...ite strengthen arguments " << deq << std::endl;
-                test_c.push_back( deq );
-                narrow = true;
-              }
-              //condition must be distinct from all parent ITE's
-              Node curr = n;
-              Node arg_itec = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[i][0].getSelector() ), n );
-              while( curr.getKind()==APPLY_SELECTOR_TOTAL ){
-                if( curr[0].getType()==tnn ){
-                  int sIndexCurr = Datatype::indexOf( curr.getOperator().toExpr() );
-                  int csIndexCurr = Datatype::cindexOf( curr.getOperator().toExpr() );
-                  if( sIndexCurr!=0 && csIndexCurr==(int)i ){
-                    Trace("sygus-ite") << "Parent ITE " << curr << " of " << n << std::endl;
-                    Node arg_itecp = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[i][0].getSelector() ), curr[0] );
-                    Node deq = arg_itec.eqNode( arg_itecp ).negate();
-                    Trace("sygus-str") << "...ite strengthen condition " << deq << std::endl;
-                    test_c.push_back( deq );
-                    narrow = true;
-                  }
-                }
-                curr = curr[0];
-              }
-            }
-          }
-          //add fairness constraint
-          if( options::ceGuidedInstFair()==quantifiers::CEGQI_FAIR_DT_SIZE ){
-            Node szl = NodeManager::currentNM()->mkNode( DT_SIZE, n );
-            Node szr = NodeManager::currentNM()->mkNode( DT_SIZE, DatatypesRewriter::getInstCons( n, dt, i ) );
-            szr = Rewriter::rewrite( szr );
-            test_c.push_back( szl.eqNode( szr ) );
+      }
+    }else{
+      // reduce
+      std::vector< Node > child_conj;
+      for( unsigned j=0; j<dt[tindex].getNumArgs(); j++ ){
+        Node sel = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[tindex].getSelectorInternal( tn.toType(), j ) ), n );
+        child_conj.push_back( NodeManager::currentNM()->mkNode( kind::DT_SYGUS_IS_CONST, sel ) );
+      }
+      lem = child_conj.size()==1 ? child_conj[0] : NodeManager::currentNM()->mkNode( kind::AND, child_conj );
+      // only an implication (TODO : strengthen?)
+      lem = NodeManager::currentNM()->mkNode( kind::OR, lem.negate(), NodeManager::currentNM()->mkNode( kind::DT_SYGUS_IS_CONST, n ) );
+    }
+    if( !lem.isNull() ){
+      Trace("sygus-isc") << "Sygus is-const lemma : " << lem << std::endl;
+      Node rlv = getRelevancyCondition( n );
+      if( !rlv.isNull() ){
+        lem = NodeManager::currentNM()->mkNode( kind::OR, rlv.negate(), lem );
+      }
+      lemmas.push_back( lem );
+    }
+  }else{
+    // lazy
+    d_is_const[n] = polarity ? 1 : -1;
+  }
+}
+
+Node SygusSymBreakNew::getTermOrderPredicate( Node n1, Node n2 ) {
+  std::vector< Node > comm_disj;
+  // (1) size of left is greater than size of right
+  Node sz_less = NodeManager::currentNM()->mkNode( GT, NodeManager::currentNM()->mkNode( DT_SIZE, n1 ), 
+                                                       NodeManager::currentNM()->mkNode( DT_SIZE, n2 ) );
+  comm_disj.push_back( sz_less );
+  // (2) ...or sizes are equal and first child is less by term order
+  std::vector< Node > sz_eq_cases; 
+  Node sz_eq = NodeManager::currentNM()->mkNode( EQUAL, NodeManager::currentNM()->mkNode( DT_SIZE, n1 ), 
+                                                        NodeManager::currentNM()->mkNode( DT_SIZE, n2 ) );
+  sz_eq_cases.push_back( sz_eq );
+  if( options::sygusOpt1() ){
+    TypeNode tnc = n1.getType();
+    const Datatype& cdt = ((DatatypeType)(tnc).toType()).getDatatype();
+    for( unsigned j=0; j<cdt.getNumConstructors(); j++ ){
+      if( !d_tds->isGenericRedundant( tnc, j ) ){
+        std::vector< Node > case_conj;
+        for( unsigned k=0; k<j; k++ ){
+          if( !d_tds->isGenericRedundant( tnc, k ) ){
+            case_conj.push_back( DatatypesRewriter::mkTester( n2, k, cdt ).negate() );
           }
-          test = test_c.size()==1 ? test_c[0] : NodeManager::currentNM()->mkNode( AND, test_c );
-          d_splits[n].push_back( test );
-          Trace("sygus-split-debug2") << "SUCCESS" << std::endl;
-          Trace("sygus-split-debug") << "Disjunct #" << d_splits[n].size() << " : " << test << std::endl;
-        }else{
-          Trace("sygus-split-debug2") << "redundant argument" << std::endl;
-          narrow = true;
         }
-      }else{
-        Trace("sygus-split-debug2") << "redundant operator" << std::endl;
-        narrow = true;
-      }
-      if( !ptest.isNull() ){
-        ptest_c.push_back( DatatypesRewriter::mkTester( n, i, dt ) );
+        if( !case_conj.empty() ){
+          Node corder = NodeManager::currentNM()->mkNode( kind::OR, DatatypesRewriter::mkTester( n1, j, cdt ).negate(),
+                                                          case_conj.size()==1 ? case_conj[0] : NodeManager::currentNM()->mkNode( kind::AND, case_conj ) );
+          sz_eq_cases.push_back( corder );
+        }
       }
     }
-    if( narrow && !ptest.isNull() ){
-      Node split = d_splits[n].empty() ? NodeManager::currentNM()->mkConst( false ) :
-                                        ( d_splits[n].size()==1 ? d_splits[n][0] : NodeManager::currentNM()->mkNode( OR, d_splits[n] ) );
-      if( !d_splits[n].empty() ){
-        d_splits[n].clear();
-        split = NodeManager::currentNM()->mkNode( AND, ptest, split );
+  }
+  Node sz_eqc = sz_eq_cases.size()==1 ? sz_eq_cases[0] : NodeManager::currentNM()->mkNode( kind::AND, sz_eq_cases );
+  comm_disj.push_back( sz_eqc );
+  
+  return NodeManager::currentNM()->mkNode( kind::OR, comm_disj );
+}
+  
+void SygusSymBreakNew::registerTerm( Node n, std::vector< Node >& lemmas ) {
+  if( d_is_top_level.find( n )==d_is_top_level.end() ){
+    d_is_top_level[n] = false;
+    TypeNode tn = n.getType();
+    unsigned d = 0;
+    bool is_top_level = false;
+    bool success = false;
+    if( n.getKind()==kind::APPLY_SELECTOR_TOTAL ){
+      registerTerm( n[0], lemmas );
+      std::map< Node, Node >::iterator it = d_term_to_anchor.find( n[0] );
+      if( it!=d_term_to_anchor.end() ) {
+        d_term_to_anchor[n] = it->second;
+        d_term_to_anchor_root[n] = d_term_to_anchor_root[n[0]];
+        d = d_term_to_depth[n[0]] + 1;
+        is_top_level = computeTopLevel( tn, n[0] );
+        success = true;
       }
-      d_splits[n].push_back( split );
-      if( !ptest_c.empty() ){
-        ptest = NodeManager::currentNM()->mkNode( AND, ptest.negate(), NodeManager::currentNM()->mkNode( OR, ptest_c ) );
+    }else if( n.isVar() ){
+      registerSizeTerm( n, lemmas );
+      if( d_register_st[n] ){
+        d_term_to_anchor[n] = n;
+        d_term_to_anchor_root[n] = d_tds->isMeasuredTerm( n );
+        // this assertion fails if we have a sygus term in the search that is unmeasured
+        Assert( !d_term_to_anchor_root[n].isNull() );
+        d = 0;
+        is_top_level = true;
+        success = true;
       }
-      d_splits[n].push_back( ptest );
+    }
+    if( success ){
+      Trace("sygus-sb-debug") << "Register : " << n << ", depth : " << d << ", top level = " << is_top_level << ", type = " << ((DatatypeType)tn.toType()).getDatatype().getName() << std::endl;
+      d_term_to_depth[n] = d;
+      d_is_top_level[n] = is_top_level;
+      registerSearchTerm( tn, d, n, is_top_level, lemmas );
     }else{
-      Assert( !d_splits[n].empty() );
+      Trace("sygus-sb-debug2") << "Term " << n << " is not part of sygus search." << std::endl;
     }
+  }
+}
 
+bool SygusSymBreakNew::computeTopLevel( TypeNode tn, Node n ){
+  if( n.getType()==tn ){
+    return false;
+  }else if( n.getKind()==kind::APPLY_SELECTOR_TOTAL ){
+    return computeTopLevel( tn, n[0] );
+  }else{
+    return true;
   }
-  //copy to splits
-  splits.insert( splits.end(), d_splits[n].begin(), d_splits[n].end() );
 }
 
-void SygusSplit::registerSygusType( TypeNode tn ) {
-  if( d_register.find( tn )==d_register.end() ){
-    if( !tn.isDatatype() ){
-      d_register[tn] = TypeNode::null();
-    }else{
-      const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-      Trace("sygus-split") << "Register type " << dt.getName() << "..." << std::endl;
-      d_register[tn] = TypeNode::fromType( dt.getSygusType() );
-      if( d_register[tn].isNull() ){
-        Trace("sygus-split") << "...not sygus." << std::endl;
-      }else{
-        d_tds->registerSygusType( tn );
+void SygusSymBreakNew::assertTesterInternal( int tindex, TNode n, Node exp, std::vector< Node >& lemmas ) {
+  d_active_terms.insert( n );
+  Trace("sygus-sb-debug2") << "Sygus : activate term : " << n << " : " << exp << std::endl;  
+  
+  /* TODO
+  IntMap::const_iterator itisc = d_is_const.find( n );
+  if( itisc != d_is_const.end() ){
+    assertIsConst( n, (*itisc).second==1, lemmas );
+  }
+  */
+  
+  TypeNode ntn = n.getType();
+  const Datatype& dt = ((DatatypeType)ntn.toType()).getDatatype();
+  
+  // get the search size for this
+  Assert( d_term_to_anchor.find( n )!=d_term_to_anchor.end() );
+  Node a = d_term_to_anchor[n];
+  Assert( d_anchor_to_measure_term.find( a )!=d_anchor_to_measure_term.end() );
+  Node m = d_anchor_to_measure_term[a];
+  std::map< Node, SearchSizeInfo * >::iterator itsz = d_szinfo.find( m );
+  Assert( itsz!=d_szinfo.end() );
+  unsigned ssz = itsz->second->d_curr_search_size;
+  
+  if( options::sygusFair()==SYGUS_FAIR_DIRECT ){
+    if( dt[tindex].getNumArgs()>0 ){
+      // consider lower bounds for size of types
+      unsigned lb_add = d_tds->getMinConsTermSize( ntn, tindex );
+      unsigned lb_rem = n==a ? 0 : d_tds->getMinTermSize( ntn );
+      Assert( lb_add>=lb_rem );
+      d_currTermSize[a].set( d_currTermSize[a].get() + ( lb_add - lb_rem ) );
+    }
+    if( (unsigned)d_currTermSize[a].get()>ssz ){
+      if( Trace.isOn("sygus-sb-fair") ){
+        std::map< TypeNode, int > var_count;
+        Node templ = getCurrentTemplate( a, var_count );
+        Trace("sygus-sb-fair") << "FAIRNESS : we have " <<  d_currTermSize[a].get() << " at search size " << ssz << ", template is " << templ << std::endl;
+      }
+      // conflict
+      std::vector< Node > conflict;
+      for( NodeSet::const_iterator its = d_active_terms.begin(); its != d_active_terms.end(); ++its ){
+        Node x = *its;
+        Node xa = d_term_to_anchor[x];
+        if( xa==a ){
+          IntMap::const_iterator ittv = d_testers.find( x );
+          Assert( ittv != d_testers.end() );
+          int tindex = (*ittv).second;
+          const Datatype& dti = ((DatatypeType)x.getType().toType()).getDatatype();
+          if( dti[tindex].getNumArgs()>0 ){
+            NodeMap::const_iterator itt = d_testers_exp.find( x );
+            Assert( itt != d_testers_exp.end() );
+            conflict.push_back( (*itt).second );
+          }
+        }
+      }
+      Assert( conflict.size()==(unsigned)d_currTermSize[a].get() );
+      Assert( itsz->second->d_search_size_exp.find( ssz )!=itsz->second->d_search_size_exp.end() );
+      conflict.push_back( itsz->second->d_search_size_exp[ssz] );
+      Node conf = NodeManager::currentNM()->mkNode( kind::AND, conflict );
+      Trace("sygus-sb-fair") << "Conflict is : " << conf << std::endl;
+      lemmas.push_back( conf.negate() );
+      return;
+    }
+  }
+
+  // now, add all applicable symmetry breaking lemmas for this term
+  Assert( d_term_to_depth.find( n )!=d_term_to_depth.end() );
+  unsigned d = d_term_to_depth[n];
+  Trace("sygus-sb-fair-debug") << "Tester " << exp << " is for depth " << d << " term in search size " << ssz << std::endl;
+  //Assert( d<=ssz );
+  if( options::sygusSymBreakLazy() ){
+    addSymBreakLemmasFor( ntn, n, d, lemmas );
+  }
+     
+  // process simple symmetry breaking
+  unsigned max_depth = ssz>=d ? ssz-d : 0;
+  unsigned min_depth = d_simple_proc[exp];
+  if( min_depth<=max_depth ){
+    TNode x = getFreeVar( ntn );
+    Node rlv = getRelevancyCondition( n );
+    for( unsigned d=0; d<=max_depth; d++ ){
+      Node simple_sb_pred = getSimpleSymBreakPred( ntn, tindex, d );
+      if( !simple_sb_pred.isNull() ){
+        simple_sb_pred = simple_sb_pred.substitute( x, n );
+        if( !rlv.isNull() ){
+          simple_sb_pred = NodeManager::currentNM()->mkNode( kind::OR, rlv.negate(), simple_sb_pred ); 
+        }
+        lemmas.push_back( simple_sb_pred ); 
+      }
+    }
+  }
+  d_simple_proc[exp] = max_depth + 1;
+  
+  // add back testers for the children if they exist
+  if( options::sygusSymBreakLazy() ){
+    for( unsigned j=0; j<dt[tindex].getNumArgs(); j++ ){
+      Node sel = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[tindex].getSelectorInternal( ntn.toType(), j ) ), n );
+      Trace("sygus-sb-debug2") << "  activate child sel : " << sel << std::endl;
+      Assert( d_active_terms.find( sel )==d_active_terms.end() );
+      IntMap::const_iterator itt = d_testers.find( sel );
+      if( itt != d_testers.end() ){
+        Assert( d_testers_exp.find( sel ) != d_testers_exp.end() );
+        assertTesterInternal( (*itt).second, sel, d_testers_exp[sel], lemmas );
+      }
+    }
+  }
+}
 
-        //compute the redundant operators
+Node SygusSymBreakNew::getRelevancyCondition( Node n ) {
+  std::map< Node, Node >::iterator itr = d_rlv_cond.find( n );
+  if( itr==d_rlv_cond.end() ){
+    Node cond;
+    if( n.getKind()==APPLY_SELECTOR_TOTAL && options::sygusSymBreakRlv() ){
+      TypeNode ntn = n[0].getType();
+      Type nt = ntn.toType();
+      const Datatype& dt = ((DatatypeType)nt).getDatatype();
+      Expr selExpr = n.getOperator().toExpr();
+      if( options::dtSharedSelectors() ){
+        std::vector< Node > disj;
+        bool excl = false;
         for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-          bool nred = true;
-          if( options::sygusNormalForm() ){
-            Trace("sygus-split-debug") << "Is " << dt[i].getName() << " a redundant operator?" << std::endl;
-            Kind ck = d_tds->getArgKind( tn, i );
-            if( ck!=UNDEFINED_KIND ){
-              Kind dk;
-              if( d_tds->isAntisymmetric( ck, dk ) ){
-                int j = d_tds->getKindArg( 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 = d_tds->mkGeneric( dt, i, var_count, pre );
-              nred = !isGenericRedundant( tn, g );
-              Trace("sygus-split-debug") << "...done check " << dt[i].getName() << " based on generic rewriting" << std::endl;
+          if( !d_tds->isGenericRedundant( ntn, i ) ){
+            int sindexi = dt[i].getSelectorIndexInternal( selExpr );
+            if( sindexi!=-1 ){
+              disj.push_back( DatatypesRewriter::mkTester( n[0], i, dt ) );
+            }else{
+              excl = true;
             }
           }
-          d_sygus_nred[tn].push_back( nred );
         }
+        Assert( !disj.empty() );
+        if( excl ){
+          cond = disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( kind::OR, disj );
+        }
+      }else{
+        int sindex = Datatype::cindexOf( selExpr );
+        Assert( sindex!=-1 );
+        cond = DatatypesRewriter::mkTester( n[0], sindex, dt );
+      }
+      Node c1 = getRelevancyCondition( n[0] );
+      if( cond.isNull() ){
+        cond = c1;
+      }else if( !c1.isNull() ){
+        cond = NodeManager::currentNM()->mkNode( kind::AND, cond, c1 );
       }
-      Trace("sygus-split-debug") << "...done register type " << dt.getName() << std::endl;
     }
+    Trace("sygus-sb-debug2") << "Relevancy condition for " << n << " is " << cond << std::endl;
+    d_rlv_cond[n] = cond;
+    return cond;
+  }else{
+    return itr->second;
   }
 }
 
-void SygusSplit::registerSygusTypeConstructorArg( TypeNode tnn, const Datatype& dt, TypeNode tnnp, const Datatype& pdt, int csIndex, int sIndex ) {
-  std::map< int, std::vector< bool > >::iterator it = d_sygus_pc_nred[tnn][csIndex].find( sIndex );
-  if( it==d_sygus_pc_nred[tnn][csIndex].end() ){
-    d_sygus_pc_nred[tnn][csIndex][sIndex].clear();
-    registerSygusType( tnn );
-    registerSygusType( tnnp );
-    Trace("sygus-split") << "Register type constructor arg " << dt.getName() << " " << csIndex << " " << sIndex << std::endl;
-    if( !options::sygusNormalForm() ){
-      for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-        d_sygus_pc_nred[tnn][csIndex][sIndex].push_back( true );
+Node SygusSymBreakNew::getSimpleSymBreakPred( TypeNode tn, int tindex, unsigned depth ) {
+  std::map< unsigned, Node >::iterator it = d_simple_sb_pred[tn][tindex].find( depth );
+  if( it==d_simple_sb_pred[tn][tindex].end() ){
+    Node n = getFreeVar( tn );
+    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+    Assert( tindex>=0 && tindex<(int)dt.getNumConstructors() ); 
+    //conjunctive conclusion of lemma
+    std::vector< Node > sbp_conj;
+    
+    if( depth==0 ){
+      //fairness
+      if( options::sygusFair()==SYGUS_FAIR_DT_SIZE ){
+        Node szl = NodeManager::currentNM()->mkNode( DT_SIZE, n );
+        Node szr = NodeManager::currentNM()->mkNode( DT_SIZE, DatatypesRewriter::getInstCons( n, dt, tindex ) );
+        szr = Rewriter::rewrite( szr );
+        sbp_conj.push_back( szl.eqNode( szr ) );
+        //sbp_conj.push_back( NodeManager::currentNM()->mkNode( kind::GEQ, szl, NodeManager::currentNM()->mkConst( Rational(0) ) ) );
       }
-    }else{
-      // calculate which constructors we should consider based on normal form for terms
-      //get parent kind
-      Kind parentKind = d_tds->getArgKind( tnnp, csIndex );
-      for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-        Assert( d_sygus_nred.find( tnn )!=d_sygus_nred.end() );
-        bool addSplit = d_sygus_nred[tnn][i];
-        if( addSplit && parentKind!=UNDEFINED_KIND ){
-          Kind ak = d_tds->getArgKind( tnn, i );
-          if( ak!=UNDEFINED_KIND ){
-            addSplit = considerSygusSplitKind( dt, pdt, tnn, tnnp, ak, parentKind, sIndex );
-            if( !addSplit ){
-              Trace("sygus-nf") << "* Sygus norm " << pdt.getName() << " : do not consider " << dt.getName() << "::" << ak;
-              Trace("sygus-nf") << " as argument " << sIndex << " of " << parentKind << "." << std::endl;
+    }
+    
+    //symmetry breaking
+    Kind nk = d_tds->getConsNumKind( tn, tindex );
+    if( options::sygusSymBreak() ){
+      // if less than the maximum depth we consider
+      if( depth<2 ){
+        //get children
+        std::vector< Node > children;
+        for( unsigned j=0; j<dt[tindex].getNumArgs(); j++ ){
+          Node sel = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[tindex].getSelectorInternal( tn.toType(), j ) ), n );
+          Assert( sel.getType().isDatatype() );
+          Assert( ((DatatypeType)sel.getType().toType()).getDatatype().isSygus() );
+          children.push_back( sel );
+          d_tds->registerSygusType( sel.getType() );
+        }
+        //builtin type
+        TypeNode tnb = TypeNode::fromType( dt.getSygusType() );
+        
+        // direct solving for children
+        //   for instance, we may want to insist that the LHS of MINUS is 0
+        std::map< unsigned, unsigned > children_solved;
+        for( unsigned j=0; j<dt[tindex].getNumArgs(); j++ ){
+          int i = d_tds->solveForArgument( tn, tindex, j );
+          if( i>=0 ){
+            children_solved[j] = i;
+            TypeNode ctn = children[j].getType();
+            const Datatype& cdt = ((DatatypeType)(ctn).toType()).getDatatype();
+            Assert( i<(int)cdt.getNumConstructors() );
+            sbp_conj.push_back( DatatypesRewriter::mkTester( children[j], i, cdt ) );
+          }
+        }
+        
+        // depth 1 symmetry breaking : talks about direct children
+        if( depth==1 ){
+          if( nk!=UNDEFINED_KIND ){
+            // commutative operators 
+            if( quantifiers::TermDb::isComm( nk ) ){
+              if( children.size()==2 ){
+                if( children[0].getType()==children[1].getType() ){
+  #if 0
+                  Node order_pred = NodeManager::currentNM()->mkNode( DT_SYGUS_TERM_ORDER, children[0], children[1] );
+                  sbp_conj.push_back( order_pred );
+                  Node child11 = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[tindex].getSelectorInternal( tn.toType(), 1 ) ), children[0] );
+                  Assert( child11.getType()==children[1].getType() );
+                  //chainable
+                  if( children[0].getType()==tn ){
+                    Node order_pred_trans = NodeManager::currentNM()->mkNode( OR, DatatypesRewriter::mkTester( children[0], tindex, dt ).negate(),
+                                                                              NodeManager::currentNM()->mkNode( DT_SYGUS_TERM_ORDER, child11, children[1] ) );
+                    sbp_conj.push_back( order_pred_trans );
+                  }
+  #else   
+                  Node order_pred = getTermOrderPredicate( children[0], children[1] );
+                  sbp_conj.push_back( order_pred );
+  #endif
+                }
+              }
             }
-          }else{
-            Node ac = d_tds->getArgConst( tnn, i );
-            if( !ac.isNull() ){
-              addSplit = considerSygusSplitConst( dt, pdt, tnn, tnnp, ac, parentKind, sIndex );
-              if( !addSplit ){
-                Trace("sygus-nf") << "* Sygus norm " << pdt.getName() << " : do not consider constant " << dt.getName() << "::" << ac;
-                Trace("sygus-nf") << " as argument " << sIndex << " of " << parentKind << "." << std::endl;
+            // operators whose arguments are non-additive (e.g. should be different)
+            std::vector< unsigned > deq_child[2];
+            if( children.size()==2 && children[0].getType()==tn ){
+              bool argDeq = false;
+              if( quantifiers::TermDb::isNonAdditive( nk ) ){
+                argDeq = true;
+              }else{
+                //other cases of rewriting x k x -> x'
+                Node req_const;
+                if( nk==GT || nk==LT || nk==XOR || nk==MINUS || nk==BITVECTOR_SUB || nk==BITVECTOR_XOR || nk==BITVECTOR_UREM_TOTAL ){
+                  //must have the zero element
+                  req_const = d_tds->getTypeValue( tnb, 0 );
+                }else if( nk==EQUAL || nk==LEQ || nk==GEQ || nk==BITVECTOR_XNOR ){
+                  req_const = d_tds->getTypeMaxValue( tnb );
+                }
+                // cannot do division since we have to consider when both are zero
+                if( !req_const.isNull() ){
+                  if( d_tds->hasConst( tn, req_const ) ){
+                    argDeq = true;
+                  }
+                }
+              }
+              if( argDeq ){
+                deq_child[0].push_back( 0 );deq_child[1].push_back( 1 );
               }
             }
-          }
-          if( addSplit ){
-            if( pdt[csIndex].getNumArgs()==1 ){
-              //generic rewriting
-              std::map< int, Node > prec;
-              std::map< TypeNode, int > var_count;
-              Node gc = d_tds->mkGeneric( dt, i, var_count, prec );
-              std::map< int, Node > pre;
-              pre[sIndex] = gc;
-              Node g = d_tds->mkGeneric( pdt, csIndex, var_count, pre );
-              addSplit = !isGenericRedundant( tnnp, g );
+            if( nk==ITE || nk==STRING_STRREPL ){
+              deq_child[0].push_back( 1 );deq_child[1].push_back( 2 );
             }
+            if( nk==STRING_STRREPL ){
+              deq_child[0].push_back( 0 );deq_child[1].push_back( 1 );
+            }
+            for( unsigned i=0; i<deq_child[0].size(); i++ ){
+              unsigned c1 = deq_child[0][i];
+              unsigned c2 = deq_child[1][i];
+              if( children[c1].getType()==children[c2].getType() ){
+                if( !children[c1].getType().getCardinality().isOne() ){
+                  sbp_conj.push_back( children[c1].eqNode( children[c2] ).negate() );
+                }
+              }
+            }
+            
             /*
-            else{
-              Trace("sygus-nf-temp") << "Check " << dt[i].getName() << " as argument " << sIndex << " under " << parentKind << std::endl;
-              std::map< int, Node > prec;
-              std::map< TypeNode, int > var_count;
-              Node gc = d_tds->mkGeneric( dt, i, var_count, prec );
-              std::map< int, Node > pre;
-              pre[sIndex] = gc;
-              Node g = d_tds->mkGeneric( pdt, csIndex, var_count, pre );
-              bool tmp = !isGenericRedundant( tnnp, g, false );
+            // division by zero  TODO ?
+            if( nk==DIVISION || nk==DIVISION_TOTAL || nk==INTS_DIVISION || nk==INTS_DIVISION_TOTAL || 
+                nk==INTS_MODULUS || nk==INTS_MODULUS_TOTAL ){
+              Assert( children.size()==2 );
+              // do not consider non-constant denominators ?
+              sbp_conj.push_back( NodeManager::currentNM()->mkNode( kind::DT_SYGUS_IS_CONST, children[1] ) );
+              // do not consider zero denominator
+              Node tzero = d_tds->getTypeValue( tnb, 0 );
+              int zero_arg = d_tds->getConstConsNum( children[1].getType(), tzero );
+              if( zero_arg!=-1 ){
+                
+              }else{
+                // semantic skolem for zero?
+              }
+            }else if( nk==BITVECTOR_UDIV_TOTAL || nk==BITVECTOR_UDIV || nk==BITVECTOR_SDIV || nk==BITVECTOR_UREM || nk==BITVECTOR_UREM_TOTAL ){
+
             }
             */
-          }
-        }
-        d_sygus_pc_nred[tnn][csIndex][sIndex].push_back( addSplit );
-      }
-      //compute argument relationships for 2-arg constructors
-      if( parentKind!=UNDEFINED_KIND && pdt[csIndex].getNumArgs()==2 ){
-        int osIndex = sIndex==0 ? 1 : 0;
-        TypeNode tnno = d_tds->getArgType( pdt[csIndex], osIndex );
-        if( tnno.isDatatype() ){
-          const Datatype& dto = ((DatatypeType)(tnno).toType()).getDatatype();
-          registerSygusTypeConstructorArg( tnno, dto, tnnp, pdt, csIndex, osIndex );
-          //compute relationships when doing 0-arg
-          if( sIndex==0 ){
-            Assert( d_sygus_pc_nred[tnn][csIndex].find( sIndex )!=d_sygus_pc_nred[tnn][csIndex].end() );
-            Assert( d_sygus_pc_nred[tnno][csIndex].find( osIndex )!=d_sygus_pc_nred[tnno][csIndex].end() );
-
-            bool isPComm = quantifiers::TermDb::isComm( parentKind );
-            std::map< int, bool > larg_consider;
-            for( unsigned i=0; i<dto.getNumConstructors(); i++ ){
-              if( d_sygus_pc_nred[tnno][csIndex][osIndex][i] ){
-                //arguments that can be removed
-                std::map< int, bool > rem_arg;
-                //collect information about this index
-                Node oac = d_tds->getArgConst( tnno, i );
-                bool isSingularConst = !oac.isNull() && d_tds->isSingularArg( oac, parentKind, 1 );
-                bool argConsider = false;
-                for( unsigned j=0; j<dt.getNumConstructors(); j++ ){
-                  if( d_sygus_pc_nred[tnn][csIndex][sIndex][j] ){
-                    Trace("sygus-split-debug") << "Check redundancy of " << dt[j].getSygusOp() << " and " << dto[i].getSygusOp() << " under " << parentKind << std::endl;
-                    bool rem = false;
-                    if( isPComm && j>i && tnn==tnno && d_sygus_pc_nred[tnno][csIndex][osIndex][j] ){
-                      //based on commutativity
-                      // use term ordering : constructor index of first argument is not greater than constructor index of second argument
-                      rem = true;
-                      Trace("sygus-nf") << "* Sygus norm : commutativity of " << parentKind << " : consider " << dt[j].getSygusOp() << " before " << dto[i].getSygusOp() << std::endl;
-                    }else if( isSingularConst && argConsider ){
-                      rem = true;
-                      Trace("sygus-nf") << "* Sygus norm : RHS singularity arg " << dto[i].getSygusOp() << " of " << parentKind;
-                      Trace("sygus-nf") << " : do not consider " << dt[j].getSygusOp() << " as first arg." << std::endl;
+            
+            Trace("sygus-sb-simple-debug") << "Process arguments for " << tn << " : " << nk << " : " << std::endl;
+            // singular arguments (e.g. 0 for mult) 
+            // redundant arguments (e.g. 0 for plus, 1 for mult)
+            // right-associativity
+            // simple rewrites
+            for( unsigned j=0; j<dt[tindex].getNumArgs(); j++ ){
+              Node nc = children[j];
+              // if not already solved
+              if( children_solved.find( j )==children_solved.end() ){
+                TypeNode tnc = nc.getType();
+                const Datatype& cdt = ((DatatypeType)(tnc).toType()).getDatatype();
+                for( unsigned k=0; k<cdt.getNumConstructors(); k++ ){
+                  // if not already generic redundant
+                  if( !d_tds->isGenericRedundant( tnc, k ) ){
+                    Kind nck = d_tds->getConsNumKind( tnc, k );
+                    bool red = false;
+                    //check if the argument is redundant
+                    if( nck!=UNDEFINED_KIND ){
+                      Trace("sygus-sb-simple-debug") << "  argument " << j << " " << k << " is : " << nck << std::endl;
+                      red = !d_tds->considerArgKind( tnc, tn, nck, nk, j );
                     }else{
-                      Node cac = d_tds->getArgConst( tnn, j );
-                      if( !cac.isNull() && d_tds->isSingularArg( cac, parentKind, 0 ) && larg_consider.find( j )!=larg_consider.end() ){
-                        rem = true;
-                        Trace("sygus-nf") << "* Sygus norm : LHS singularity arg " << dt[j].getSygusOp() << " of " << parentKind;
-                        Trace("sygus-nf") << " : do not consider " << dto[i].getSygusOp() << " as second arg." << std::endl;
+                      Node cc = d_tds->getConsNumConst( tnc, k  );
+                      if( !cc.isNull() ){
+                        Trace("sygus-sb-simple-debug") << "  argument " << j << " " << k << " is constant : " << cc << std::endl;
+                        red = !d_tds->considerConst( tnc, tn, cc, nk, j );
                       }else{
-                        if( parentKind!=UNDEFINED_KIND ){
-                          std::map< TypeNode, int > var_count;
-                          std::map< int, Node > pre;
-                          Node g1 = d_tds->mkGeneric( dt, j, var_count, pre );
-                          Node g2 = d_tds->mkGeneric( dto, i, var_count, pre );
-                          Node g = NodeManager::currentNM()->mkNode( parentKind, g1, g2 );
-                          if( isGenericRedundant( tnnp, g ) ){
-                            rem = true;
-                          }
-                        }
+                        //defined function?
                       }
                     }
-                    if( rem ){
-                      rem_arg[j] = true;
-                    }else{
-                      argConsider = true;
-                      larg_consider[j] = true;
+                    if( red ){
+                      Trace("sygus-sb-simple-debug") << "  ...redundant." << std::endl;
+                      sbp_conj.push_back( DatatypesRewriter::mkTester( nc, k, cdt ).negate() );
                     }
                   }
                 }
-                if( !rem_arg.empty() ){
-                  d_sygus_pc_arg_pos[tnno][csIndex][i].clear();
-                  Trace("sygus-split-debug") << "Possibilities for first argument of " << parentKind << ", when second argument is " << dto[i].getName() << " : " << std::endl;
-                  for( unsigned j=0; j<dt.getNumConstructors(); j++ ){
-                    if( d_sygus_pc_nred[tnn][csIndex][sIndex][j] && rem_arg.find( j )==rem_arg.end() ){
-                      d_sygus_pc_arg_pos[tnno][csIndex][i].push_back( j );
-                      Trace("sygus-split-debug") << "  " << dt[j].getName() << std::endl;
-                    }
-                  }
-                  //if there are no possibilities for first argument, then this child is redundant
-                  if( d_sygus_pc_arg_pos[tnno][csIndex][i].empty() ){
-                    Trace("sygus-nf") << "* Sygus norm " << pdt.getName() << " : do not consider constant " << dt.getName() << "::" << dto[i].getName();
-                    Trace("sygus-nf") << " as argument " << osIndex << " of " << parentKind << " (based on arguments)." << std::endl;
-                    d_sygus_pc_nred[tnno][csIndex][osIndex][i] = false;
+              }
+            }
+          }else{
+            // defined function?
+          }
+        }else if( depth==2 ){
+          if( nk!=UNDEFINED_KIND ){
+            // commutative operators 
+            if( quantifiers::TermDb::isComm( nk ) ){
+              if( children.size()==2 ){
+                if( children[0].getType()==children[1].getType() ){
+                  //chainable
+                  // TODO : this is depth 2
+                  if( children[0].getType()==tn ){
+                    Node child11 = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[tindex].getSelectorInternal( tn.toType(), 1 ) ), children[0] );
+                    Assert( child11.getType()==children[1].getType() );
+                    Node order_pred_trans = NodeManager::currentNM()->mkNode( OR, DatatypesRewriter::mkTester( children[0], tindex, dt ).negate(),
+                                                                              getTermOrderPredicate( child11, children[1] ) );
+
+                    sbp_conj.push_back( order_pred_trans );
                   }
                 }
               }
@@ -399,975 +637,703 @@ void SygusSplit::registerSygusTypeConstructorArg( TypeNode tnn, const Datatype&
         }
       }
     }
+    
+    Node sb_pred;
+    if( !sbp_conj.empty() ){
+      sb_pred = sbp_conj.size()==1 ? sbp_conj[0] : NodeManager::currentNM()->mkNode( kind::AND, sbp_conj );
+      Trace("sygus-sb-simple") << "Simple predicate for " << tn << " index " << tindex << " (" << nk << ") at depth " << depth << " : " << std::endl;
+      Trace("sygus-sb-simple") << "   " << sb_pred << std::endl;
+      sb_pred = NodeManager::currentNM()->mkNode( kind::OR, DatatypesRewriter::mkTester( n, tindex, dt ).negate(), sb_pred );
+    }
+    d_simple_sb_pred[tn][tindex][depth] = sb_pred;
+    return sb_pred;
+  }else{
+    return it->second;
   }
 }
 
-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 );
-    }
+TNode SygusSymBreakNew::getFreeVar( TypeNode tn ) {
+  std::map< TypeNode, Node >::iterator it = d_free_var.find( tn );
+  if( it==d_free_var.end() ){
+    Node x = NodeManager::currentNM()->mkSkolem( "x", tn );
+    d_free_var[tn] = x;
+    return x;
+  }else{
+    return it->second;
   }
-  bool satisfiedBy( quantifiers::TermDbSygus * tdb, TypeNode tn ){
-    if( d_req_kind!=UNDEFINED_KIND ){
-      int c = tdb->getKindArg( tn, d_req_kind );
-      if( c!=-1 ){
-        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 ) ){
-              return false;
-            }
-          }else{
-            return false;
-          }
-        }
-        return true;
-      }else{
-        return false;
-      }
-    }else if( !d_req_const.isNull() ){
-      return tdb->hasConst( tn, d_req_const );
-    }else if( !d_req_type.isNull() ){
-      return tn==d_req_type;
-    }else{
-      return true;
-    }
+}
+
+unsigned SygusSymBreakNew::processSelectorChain( Node n, std::map< TypeNode, Node >& top_level, std::map< Node, unsigned >& tdepth, std::vector< Node >& lemmas ) {
+  unsigned ret = 0;
+  if( n.getKind()==APPLY_SELECTOR_TOTAL ){
+    ret = processSelectorChain( n[0], top_level, tdepth, lemmas );
   }
-};
+  TypeNode tn = n.getType();
+  if( top_level.find( tn )==top_level.end() ){
+    top_level[tn] = n;
+    //tdepth[n] = ret;
+    registerSearchTerm( tn, ret, n, true, lemmas );
+  }else{
+    registerSearchTerm( tn, ret, n, false, lemmas );
+  }
+  tdepth[n] = ret;
+  return ret+1;
+}
 
+void SygusSymBreakNew::registerSearchTerm( TypeNode tn, unsigned d, Node n, bool topLevel, std::vector< Node >& lemmas ) {
+  //register this term
+  std::map< Node, Node >::iterator ita = d_term_to_anchor.find( n );
+  Assert( ita != d_term_to_anchor.end() );
+  Node a = ita->second;
+  Assert( !a.isNull() );
+  if( std::find( d_cache[a].d_search_terms[tn][d].begin(), d_cache[a].d_search_terms[tn][d].end(), n )==d_cache[a].d_search_terms[tn][d].end() ){
+    Trace("sygus-sb-debug") << "  register search term : " << n << " at depth " << d << ", type=" << tn << ", tl=" << topLevel << std::endl;
+    d_cache[a].d_search_terms[tn][d].push_back( n );
+    if( !options::sygusSymBreakLazy() ){
+      addSymBreakLemmasFor( tn, n, d, lemmas );
+    }
+  }
+}
 
-//this function gets all easy redundant cases, before consulting rewriters
-bool SygusSplit::considerSygusSplitKind( const Datatype& dt, const Datatype& pdt, TypeNode tn, TypeNode tnp, Kind k, Kind parent, int arg ) {
-  Assert( d_tds->hasKind( tn, k ) );
-  Assert( d_tds->hasKind( tnp, parent ) );
-  Trace("sygus-split") << "Consider sygus split kind " << k << ", parent = " << parent << ", arg = " << arg << "?" << std::endl;
-  int c = d_tds->getKindArg( tn, k );
-  int pc = d_tds->getKindArg( tnp, parent );
-  if( k==parent ){
-    //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], dt );
-      Assert( firstArg!=-1 );
-      Trace("sygus-split-debug") << "Associative, with first arg = " << firstArg << std::endl;
-      return arg==firstArg;
+class EquivSygusInvarianceTest : public quantifiers::SygusInvarianceTest {
+public:
+  EquivSygusInvarianceTest(){}
+  ~EquivSygusInvarianceTest(){}
+  Node d_ex_ar;
+  Node d_bvr;
+  std::vector< Node > d_exo;
+  void init( quantifiers::TermDbSygus * tds, TypeNode tn, Node ar, Node bvr ) {
+    //compute the current examples
+    d_bvr = bvr;
+    if( tds->hasPbeExamples( ar ) ){
+      d_ex_ar = ar;
+      unsigned nex = tds->getNumPbeExamples( ar );
+      for( unsigned i=0; i<nex; i++ ){
+        d_exo.push_back( tds->evaluateBuiltin( tn, bvr, ar, i ) );
+      }
     }
   }
-  //describes the shape of an alternate term to construct
-  //  we check whether this term is in the sygus grammar below
-  ReqTrie rt;
-  bool rt_valid = false;
-  
-  //construct rt by cases
-  if( parent==NOT || parent==BITVECTOR_NOT || parent==UMINUS || parent==BITVECTOR_NEG ){
-    rt_valid = true;
-    //negation normal form
-    if( parent==k ){
-      rt.d_req_type = d_tds->getArgType( dt[c], 0 );
+protected:
+  bool invariant( quantifiers::TermDbSygus * tds, Node nvn, Node x ){
+    TypeNode tn = nvn.getType();
+    Node nbv = tds->sygusToBuiltin( nvn, tn );
+    Node nbvr = tds->extendedRewrite( nbv );
+    Trace("sygus-sb-mexp-debug") << "  min-exp check : " << nbv << " -> " << nbvr << std::endl;
+    bool exc_arg = false;
+    // equivalent / singular up to normalization
+    if( nbvr==d_bvr ){
+      // gives the same result : then the explanation for the child is irrelevant 
+      exc_arg = true;
+      Trace("sygus-sb-mexp") << "sb-min-exp : " << tds->sygusToBuiltin( nvn ) << " is rewritten to " << nbvr;
+      Trace("sygus-sb-mexp") << " regardless of the content of " << tds->sygusToBuiltin( x ) << std::endl;
     }else{
-      Kind reqk = UNDEFINED_KIND;       //required kind for all children
-      std::map< unsigned, Kind > reqkc; //required kind for some children
-      if( parent==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 = d_tds->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 = d_tds->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 = d_tds->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 = d_tds->getArgType( dt[c], 1 );
-          rt.d_children[1].d_req_kind = PLUS;
-          rt.d_children[1].d_children[0].d_req_type = d_tds->getArgType( dt[c], 0 );
-          rt.d_children[1].d_children[1].d_req_const = NodeManager::currentNM()->mkConst( Rational( 1 ) );
-        }else{
-          rt_valid = false;
-        }
-      }else if( parent==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{
-          rt_valid = false;
-        }
-      }else if( parent==UMINUS ){
-        if( k==PLUS ){
-          rt.d_req_kind = PLUS;reqk = UMINUS;
-        }else{
-          rt_valid = false;
-        }
-      }else if( parent==BITVECTOR_NEG ){
-        if( k==PLUS ){
-          rt.d_req_kind = PLUS;reqk = BITVECTOR_NEG;
-        }else{
-          rt_valid = false;
-        }
-      }
-      if( rt_valid && ( reqk!=UNDEFINED_KIND || !reqkc.empty() ) ){
-        int pcr = d_tds->getKindArg( 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 = d_tds->getArgType( dt[c], i );
-              }
-            }
-          }else{
-            rt_valid = false;
+      if( nbvr.isVar() ){
+        TypeNode xtn = x.getType();
+        if( xtn==tn ){
+          Node bx = tds->sygusToBuiltin( x, xtn );
+          Assert( bx.getType()==nbvr.getType() );
+          if( nbvr==bx ){
+            Trace("sygus-sb-mexp") << "sb-min-exp : " << tds->sygusToBuiltin( nvn ) << " always rewrites to argument " << nbvr << std::endl;
+            // rewrites to the variable : then the explanation of this is irrelevant as well
+            exc_arg = true;
+            d_bvr = nbvr;
           }
-        }else{
-          rt_valid = false;
         }
       }
     }
-  }else if( k==MINUS || k==BITVECTOR_SUB ){
-    if( parent==EQUAL || 
-        parent==MINUS || parent==BITVECTOR_SUB || 
-        parent==LEQ || parent==LT || parent==GEQ || parent==GT ){
-      int oarg = arg==0 ? 1 : 0;
-      //  (~ x (- y z))  ---->  (~ (+ x z) y)
-      //  (~ (- y z) x)  ---->  (~ y (+ x z))
-      rt.d_req_kind = parent;
-      rt.d_children[arg].d_req_type = d_tds->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 = d_tds->getArgType( pdt[pc], oarg );
-      rt.d_children[oarg].d_children[1].d_req_type = d_tds->getArgType( dt[c], 1 );
-      rt_valid = true;
-    }else if( parent==PLUS || parent==BITVECTOR_PLUS ){
-      //  (+ x (- y z))  -----> (- (+ x y) z)
-      //  (+ (- y z) x)  -----> (- (+ x y) z)
-      rt.d_req_kind = parent==PLUS ? MINUS : BITVECTOR_SUB;
-      int oarg = arg==0 ? 1 : 0;
-      rt.d_children[0].d_req_kind = parent;
-      rt.d_children[0].d_children[0].d_req_type = d_tds->getArgType( pdt[pc], oarg );
-      rt.d_children[0].d_children[1].d_req_type = d_tds->getArgType( dt[c], 0 );
-      rt.d_children[1].d_req_type = d_tds->getArgType( dt[c], 1 );
-      rt_valid = true;
-    }
-  }else if( k==ITE ){
-    if( parent!=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 = d_tds->getArgType( dt[c], 0 );
-      unsigned n_args = pdt[pc].getNumArgs();
-      for( unsigned r=1; r<=2; r++ ){
-        rt.d_children[r].d_req_kind = parent;
-        for( unsigned q=0; q<n_args; q++ ){
-          if( (int)q==arg ){
-            rt.d_children[r].d_children[q].d_req_type = d_tds->getArgType( dt[c], r );
-          }else{
-            rt.d_children[r].d_children[q].d_req_type = d_tds->getArgType( pdt[pc], q );
+    // equivalent under examples
+    if( !exc_arg ){
+      if( !d_ex_ar.isNull() ){
+        bool ex_equiv = true;
+        for( unsigned j=0; j<d_exo.size(); j++ ){
+          Node nbvr_ex = tds->evaluateBuiltin( tn, nbvr, d_ex_ar, j );
+          if( nbvr_ex!=d_exo[j] ){
+            ex_equiv = false;
+            break;
           }
         }
+        if( ex_equiv ){
+          Trace("sygus-sb-mexp") << "sb-min-exp : " << tds->sygusToBuiltin( nvn );
+          Trace("sygus-sb-mexp") << " is the same w.r.t. examples regardless of the content of " << tds->sygusToBuiltin( x ) << std::endl;
+          exc_arg = true;
+        }
       }
-      rt_valid = true;
-      //TODO: this increases term size but is probably a good idea
-    }
-  }else if( k==NOT ){
-    if( parent==ITE ){
-      //  (ite (not y) z w)  -----> (ite y w z)
-      rt.d_req_kind = ITE;
-      rt.d_children[0].d_req_type = d_tds->getArgType( dt[c], 0 );
-      rt.d_children[1].d_req_type = d_tds->getArgType( pdt[pc], 2 );
-      rt.d_children[2].d_req_type = d_tds->getArgType( pdt[pc], 1 );
     }
+    return exc_arg;
   }
-  Trace("sygus-consider-split") << "Consider sygus split kind " << k << ", parent = " << parent << ", arg = " << arg << "?" << std::endl;
-  if( rt_valid ){
-    rt.print("sygus-consider-split");
-    //check if it meets the requirements
-    if( rt.satisfiedBy( d_tds, tnp ) ){
-      Trace("sygus-consider-split") << "...success!" << std::endl;
-      //do not need to consider the kind in the search since there are ways to construct equivalent terms
-      return false;
+};
+
+
+class DivByZeroSygusInvarianceTest : public quantifiers::SygusInvarianceTest {
+public:
+  DivByZeroSygusInvarianceTest(){}
+  ~DivByZeroSygusInvarianceTest(){}
+
+protected:
+  bool invariant( quantifiers::TermDbSygus * tds, Node nvn, Node x ){
+    TypeNode tn = nvn.getType();
+    Node nbv = tds->sygusToBuiltin( nvn, tn );
+    Node nbvr = tds->extendedRewrite( nbv );
+    if( tds->involvesDivByZero( nbvr ) ){
+      Trace("sygus-sb-mexp") << "sb-min-exp : " << tds->sygusToBuiltin( nvn ) << " involves div-by-zero regardless of " << tds->sygusToBuiltin( x ) << std::endl;
+      return true;
     }else{
-      Trace("sygus-consider-split") << "...failed." << std::endl;
+      return false;
     }
-    Trace("sygus-consider-split") << std::endl;
   }
-  //must consider this kind in the search  
-  return true;
-}
+};
 
-//this function gets all easy redundant cases, before consulting rewriters
-bool SygusSplit::considerSygusSplitConst( const Datatype& dt, const Datatype& pdt, TypeNode tn, TypeNode tnp, Node c, Kind parent, int arg ) {
-  Assert( d_tds->hasConst( tn, c ) );
-  Assert( d_tds->hasKind( tnp, parent ) );
-  int pc = d_tds->getKindArg( tnp, parent );
-  Trace("sygus-split") << "Consider sygus split const " << c << ", parent = " << parent << ", arg = " << arg << "?" << std::endl;
-  if( d_tds->isIdempotentArg( c, parent, arg ) ){
-    Trace("sygus-split-debug") << "  " << c << " is idempotent arg " << arg << " of " << parent << "..." << std::endl;
-    if( pdt[pc].getNumArgs()==2 ){
-      int oarg = arg==0 ? 1 : 0;
-      TypeNode otn = TypeNode::fromType( ((SelectorType)pdt[pc][oarg].getType()).getRangeType() );
-      if( otn==tnp ){
+bool SygusSymBreakNew::registerSearchValue( Node a, Node n, Node nv, unsigned d, std::vector< Node >& lemmas ) {
+  Assert( n.getType()==nv.getType() );
+  Assert( nv.getKind()==APPLY_CONSTRUCTOR );
+  TypeNode tn = n.getType(); 
+  // currently bottom-up, could be top-down?
+  if( nv.getNumChildren()>0 ){
+    const Datatype& dt = ((DatatypeType)tn.toType()).getDatatype();
+    unsigned cindex = Datatype::indexOf( nv.getOperator().toExpr() );
+    for( unsigned i=0; i<nv.getNumChildren(); i++ ){
+      Node sel = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex].getSelectorInternal( tn.toType(), i ) ), n );
+      if( !registerSearchValue( a, sel, nv[i], d+1, lemmas ) ){
         return false;
       }
     }
-  }else if( d_tds->isSingularArg( c, parent, arg ) ){
-    Trace("sygus-split-debug") << "  " << c << " is singular arg " << arg << " of " << parent << "..." << std::endl;
-    if( d_tds->hasConst( tnp, c ) ){
-      return false;
-    }
   }
-  if( pdt[pc].getNumArgs()==2 ){
-    Kind ok;
-    int offset;
-    if( d_tds->hasOffsetArg( parent, arg, offset, ok ) ){
-      Trace("sygus-split-debug") << parent << " has offset arg " << ok << " " << offset << std::endl;
-      int ok_arg = d_tds->getKindArg( tnp, ok );
-      if( ok_arg!=-1 ){
-        Trace("sygus-split-debug") << "...at argument " << ok_arg << std::endl;
-        //other operator be the same type
-        if( isTypeMatch( pdt[ok_arg], pdt[arg] ) ){
-          int status;
-          Node co = d_tds->getTypeValueOffset( c.getType(), c, offset, status );
-          Trace("sygus-split-debug") << c << " with offset " << offset << " is " << co << ", status=" << status << std::endl;
-          if( status==0 && !co.isNull() ){
-            if( d_tds->hasConst( tn, co ) ){
-              Trace("sygus-split-debug") << "arg " << arg << " " << c << " in " << parent << " can be treated as " << co << " in " << ok << "..." << std::endl;
-              return false;
-            }else{
-              Trace("sygus-split-debug") << "Type does not have constant." << std::endl;
+  Trace("sygus-sb-debug2") << "Registering search value " << n << " -> " << nv << std::endl;
+  // must do this for all nodes, regardless of top-level
+  if( d_cache[a].d_search_val_proc.find( nv )==d_cache[a].d_search_val_proc.end() ){
+    d_cache[a].d_search_val_proc[nv] = true;
+    // get the root (for PBE symmetry breaking)
+    Assert( d_term_to_anchor_root.find( a )!=d_term_to_anchor_root.end() );
+    Node ar = d_term_to_anchor_root[a];
+    Assert( !ar.isNull() );
+    Trace("sygus-sb-debug") << "  ...register search value " << nv << ", type=" << tn << std::endl;
+    Node bv = d_tds->sygusToBuiltin( nv, tn );
+    Trace("sygus-sb-debug") << "  ......builtin is " << bv << std::endl;
+    Node bvr = d_tds->extendedRewrite( bv );
+    Trace("sygus-sb-debug") << "  ......rewrites to " << bvr << std::endl;
+    unsigned sz = d_tds->getSygusTermSize( nv );      
+    std::vector< Node > exp;
+    bool do_exclude = false;
+    if( d_tds->involvesDivByZero( bvr ) ){
+      Node x = getFreeVar( tn );
+      DivByZeroSygusInvarianceTest dbzet;
+      Trace("sygus-sb-mexp-debug") << "Minimize explanation for div-by-zero in " << d_tds->sygusToBuiltin( nv ) << std::endl;
+      d_tds->getExplanationFor( x, nv, exp, dbzet, Node::null(), sz );
+      do_exclude = true;
+    }else{
+      std::map< Node, Node >::iterator itsv = d_cache[a].d_search_val[tn].find( bvr );
+      Node bad_val_bvr;
+      bool by_examples = false;
+      if( itsv==d_cache[a].d_search_val[tn].end() ){
+        // is it equivalent under examples?
+        Node bvr_equiv = d_tds->addPbeSearchVal( tn, ar, bvr );
+        if( !bvr_equiv.isNull() ){
+          if( bvr_equiv!=bvr ){
+            Trace("sygus-sb-debug") << "......adding search val for " << bvr << " returned " << bvr_equiv << std::endl;
+            Assert( d_cache[a].d_search_val[tn].find( bvr_equiv )!=d_cache[a].d_search_val[tn].end() );
+            Trace("sygus-sb-debug") << "......search value was " << d_cache[a].d_search_val[tn][bvr_equiv] << std::endl;
+            if( Trace.isOn("sygus-sb-exc") ){
+              Node prev = d_tds->sygusToBuiltin( d_cache[a].d_search_val[tn][bvr_equiv], tn );
+              Trace("sygus-sb-exc") << "  ......programs " << prev << " and " << bv << " are equivalent up to examples." << std::endl;
             }
+            bad_val_bvr = bvr_equiv;
+            by_examples = true;
           }
-        }else{
-          Trace("sygus-split-debug") << "Type mismatch." << std::endl;
         }
+        //store rewritten values, regardless of whether it will be considered
+        d_cache[a].d_search_val[tn][bvr] = nv;
+        d_cache[a].d_search_val_sz[tn][bvr] = sz;
+      }else{
+        bad_val_bvr = bvr;
+        if( Trace.isOn("sygus-sb-exc") ){
+          Node prev_bv = d_tds->sygusToBuiltin( itsv->second, tn );
+          Trace("sygus-sb-exc") << "  ......programs " << prev_bv << " and " << bv << " rewrite to " << bvr << "." << std::endl;
+        } 
       }
+      
+      if( !bad_val_bvr.isNull() ){
+        Node bad_val = nv;
+        Node bad_val_o = d_cache[a].d_search_val[tn][bad_val_bvr];
+        Assert( d_cache[a].d_search_val_sz[tn].find( bad_val_bvr )!=d_cache[a].d_search_val_sz[tn].end() );
+        unsigned prev_sz = d_cache[a].d_search_val_sz[tn][bad_val_bvr];
+        if( prev_sz>sz ){
+          //swap : the excluded value is the previous
+          d_cache[a].d_search_val_sz[tn][bad_val_bvr] = sz;
+          bad_val = d_cache[a].d_search_val[tn][bad_val_bvr];
+          bad_val_o = nv;
+          sz = prev_sz;
+        }
+        if( Trace.isOn("sygus-sb-exc") ){
+          Node bad_val_bv = d_tds->sygusToBuiltin( bad_val, tn );
+          Trace("sygus-sb-exc") << "  ........exclude : " << bad_val_bv;
+          if( by_examples ){
+            Trace("sygus-sb-exc") << " (by examples)";
+          }
+          Trace("sygus-sb-exc") << std::endl;
+        } 
+        Assert( d_tds->getSygusTermSize( bad_val )==sz );
+
+        Node x = getFreeVar( tn );
+        
+        // do analysis of the evaluation  FIXME: does not work (evaluation is non-constant)
+        EquivSygusInvarianceTest eset;
+        eset.init( d_tds, tn, ar, bvr );
+        Trace("sygus-sb-mexp-debug") << "Minimize explanation for eval[" << d_tds->sygusToBuiltin( bad_val ) << "] = " << bvr << std::endl;
+        d_tds->getExplanationFor( x, bad_val, exp, eset, bad_val_o, sz );
+        do_exclude = true;
+      }
+    }
+    if( do_exclude ){
+      Node lem = exp.size()==1 ? exp[0] : NodeManager::currentNM()->mkNode( kind::AND, exp );
+      lem = lem.negate();
+      /*  add min type depth to size : TODO?
+      Assert( d_term_to_anchor.find( n )!=d_term_to_anchor.end() );
+      TypeNode atype = d_term_to_anchor[n].getType();
+      if( atype!=tn ){
+        unsigned min_type_depth = d_tds->getMinTypeDepth( atype, tn );
+        if( min_type_depth>0 ){
+          Trace("sygus-sb-exc") << "  ........min type depth for " << ((DatatypeType)tn.toType()).getDatatype().getName() << " in ";
+          Trace("sygus-sb-exc") << ((DatatypeType)atype.toType()).getDatatype().getName() << " is " << min_type_depth << std::endl;
+          sz = sz + min_type_depth;
+        }
+      }
+      */
+      Trace("sygus-sb-exc") << "  ........exc lemma is " << lem << ", size = " << sz << std::endl;
+      registerSymBreakLemma( tn, lem, sz, a, lemmas );
+      return false;
     }
   }
   return true;
 }
 
-int SygusSplit::getFirstArgOccurrence( const DatatypeConstructor& c, const Datatype& dt ) {
-  for( unsigned i=0; i<c.getNumArgs(); i++ ){
-    if( isArgDatatype( c, i, dt ) ){
-      return i;
-    }
-  }
-  return -1;
-}
 
-bool SygusSplit::isArgDatatype( const DatatypeConstructor& c, int i, const Datatype& dt ) {
-  TypeNode tni = d_tds->getArgType( c, i );
-  if( tni.isDatatype() ){
-    const Datatype& adt = ((DatatypeType)(tni).toType()).getDatatype();
-    if( adt==dt ){
-      return true;
-    }
-  }
-  return false;
-}
 
-bool SygusSplit::isTypeMatch( const DatatypeConstructor& c1, const DatatypeConstructor& c2 ){
-  if( c1.getNumArgs()!=c2.getNumArgs() ){
-    return false;
-  }else{
-    for( unsigned i=0; i<c1.getNumArgs(); i++ ){
-      if( d_tds->getArgType( c1, i )!=d_tds->getArgType( c2, i ) ){
-        return false;
+void SygusSymBreakNew::registerSymBreakLemma( TypeNode tn, Node lem, unsigned sz, Node a, std::vector< Node >& lemmas ) {
+  // lem holds for all terms of type tn, and is applicable to terms of size sz
+  Trace("sygus-sb-debug") << "  register sym break lemma : " << lem << ", size " << sz << std::endl;
+  Assert( !a.isNull() );
+  d_cache[a].d_sb_lemmas[tn][sz].push_back( lem );
+  TNode x = getFreeVar( tn );
+  unsigned csz = getSearchSizeForAnchor( a );
+  int max_depth = ((int)csz)-((int)sz);
+  for( int d=0; d<=max_depth; d++ ){
+    std::map< unsigned, std::vector< Node > >::iterator itt = d_cache[a].d_search_terms[tn].find( d );
+    if( itt!=d_cache[a].d_search_terms[tn].end() ){
+      for( unsigned k=0; k<itt->second.size(); k++ ){
+        TNode t = itt->second[k];  
+        if( !options::sygusSymBreakLazy() || d_active_terms.find( t )!=d_active_terms.end() ){
+          addSymBreakLemma( tn, lem, x, t, sz, d, lemmas );
+        }
       }
     }
-    return true;
   }
 }
+void SygusSymBreakNew::addSymBreakLemmasFor( TypeNode tn, Node t, unsigned d, std::vector< Node >& lemmas ) {
+  Assert( d_term_to_anchor.find( t )!=d_term_to_anchor.end() );
+  Node a = d_term_to_anchor[t];
+  addSymBreakLemmasFor( tn, t, d, a, lemmas );
+}
 
-bool SygusSplit::isGenericRedundant( TypeNode tn, Node g, bool active ) {
-  //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 = d_tds->getNormalized( tn, g, false );
-    Trace("sygus-gnf-debug") << "Generic " << g << " rewrites to " << gr << std::endl;
-    if( active ){
-      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;
-        d_gen_terms_inactive[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{
-      std::map< Node, Node >::iterator itg = d_gen_terms_inactive[tn].find( gr );
-      if( itg==d_gen_terms_inactive[tn].end() ){
-        Trace("sygus-nf-temp") << "..." << g << " rewrites to " << gr << std::endl;
-        d_gen_terms_inactive[tn][gr] = g;
-      }else{
-        Trace("sygus-nf-temp") << "* Note " << g << " and " << itg->second << " both rewrite to " << gr << std::endl;
+void SygusSymBreakNew::addSymBreakLemmasFor( TypeNode tn, Node t, unsigned d, Node a, std::vector< Node >& lemmas ) {
+  Assert( t.getType()==tn );
+  Assert( !a.isNull() );
+  std::map< TypeNode, std::map< unsigned, std::vector< Node > > >::iterator its = d_cache[a].d_sb_lemmas.find( tn );
+  if( its != d_cache[a].d_sb_lemmas.end() ){
+    TNode x = getFreeVar( tn );
+    //get symmetry breaking lemmas for this term 
+    unsigned csz = getSearchSizeForAnchor( a );
+    int max_sz = ((int)csz) - ((int)d);
+    for( std::map< unsigned, std::vector< Node > >::iterator it = its->second.begin(); it != its->second.end(); ++it ){
+      if( (int)it->first<=max_sz ){
+        for( unsigned k=0; k<it->second.size(); k++ ){
+          Node lem = it->second[k];
+          addSymBreakLemma( tn, lem, x, t, it->first, d, lemmas );
+        }
       }
-      return false;
     }
-  }else{
-    return it->second;
   }
 }
 
-
-
-SygusSymBreak::SygusSymBreak( quantifiers::TermDbSygus * tds, context::Context* c ) : d_tds( tds ), d_context( c ) {
-
+void SygusSymBreakNew::addSymBreakLemma( TypeNode tn, Node lem, TNode x, TNode n, unsigned lem_sz, unsigned n_depth, std::vector< Node >& lemmas ) {
+  Assert( !options::sygusSymBreakLazy() || d_active_terms.find( n )!=d_active_terms.end() );
+  // apply lemma
+  Node slem = lem.substitute( x, n );
+  Trace("sygus-sb-exc-debug") << "SymBreak lemma : " << slem << std::endl;
+  Node rlv = getRelevancyCondition( n );
+  if( !rlv.isNull() ){
+    slem = NodeManager::currentNM()->mkNode( kind::OR, rlv.negate(), slem );
+  }
+  lemmas.push_back( slem );
 }
-
-SygusSymBreak::~SygusSymBreak() {
-  for(std::map< Node, ProgSearch* >::iterator i = d_prog_search.begin(), iend = d_prog_search.end();
-      i != iend; ++i){
-    ProgSearch* current = (*i).second;
-    if(current != NULL){
-      delete current;
-    }
+  
+void SygusSymBreakNew::preRegisterTerm( TNode n, std::vector< Node >& lemmas  ) {
+  if( n.isVar() ){
+    Trace("sygus-sb-debug") << "Pre-register variable : " << n << std::endl;
+    registerSizeTerm( n, lemmas );
   }
 }
 
-void SygusSymBreak::addTester( int tindex, Node n, Node exp ) {
-  if( options::sygusNormalFormGlobal() ){
-    Node a = getAnchor( n );
-    Trace("sygus-sym-break-debug") << "Add tester " << tindex << " " << n << " for " << a << std::endl;
-    std::map< Node, ProgSearch * >::iterator it = d_prog_search.find( a );
-    ProgSearch * ps;
-    if( it==d_prog_search.end() ){
-      //check if sygus type
-      TypeNode tn = a.getType();
-      Assert( tn.isDatatype() );
-      const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+void SygusSymBreakNew::registerSizeTerm( Node e, std::vector< Node >& lemmas ) {
+  if( d_register_st.find( e )==d_register_st.end() ){
+    if( e.getType().isDatatype() ){
+      const Datatype& dt = ((DatatypeType)(e.getType()).toType()).getDatatype();
       if( dt.isSygus() ){
-        ps = new ProgSearch( this, a, d_context );
+        if( !d_tds->isMeasuredTerm( e ).isNull() ){
+          d_register_st[e] = true;
+          Node ag = d_tds->getActiveGuardForMeasureTerm( e );
+          if( !ag.isNull() ){
+            d_anchor_to_active_guard[e] = ag;
+          }
+          Node m;
+          if( !ag.isNull() ){
+            // if it has an active guard (it is an enumerator), use itself as measure term. This will enforce fairness on it independently.
+            m = e;
+          }else{
+            // otherwise we enforce fairness in a unified way for all
+            if( d_generic_measure_term.isNull() ){
+              // choose e as master for all future terms
+              d_generic_measure_term = e;
+            }
+            m = d_generic_measure_term;
+          }
+          Trace("sygus-sb") << "Sygus : register size term : " << e << " with measure " << m << std::endl;
+          registerMeasureTerm( m );
+          d_szinfo[m]->d_anchors.push_back( e );
+          d_anchor_to_measure_term[e] = m;
+          if( options::sygusFair()==SYGUS_FAIR_DT_SIZE ){
+            // update constraints on the measure term
+            if( options::sygusFairMax() ){
+              if( options::sygusFair()==SYGUS_FAIR_DT_SIZE ){
+                Node ds = NodeManager::currentNM()->mkNode( kind::DT_SIZE, e );
+                Node slem = NodeManager::currentNM()->mkNode( kind::LEQ, ds, d_szinfo[m]->getOrMkSygusMeasureTerm( lemmas ) );
+                lemmas.push_back( slem );
+              }
+            }else{
+              Node mt = d_szinfo[m]->getOrMkSygusActiveMeasureTerm( lemmas );
+              Node new_mt = NodeManager::currentNM()->mkSkolem( "mt", NodeManager::currentNM()->integerType() );
+              lemmas.push_back( NodeManager::currentNM()->mkNode( kind::GEQ, new_mt, d_zero ) );
+              if( options::sygusFair()==SYGUS_FAIR_DT_SIZE ){
+                Node ds = NodeManager::currentNM()->mkNode( kind::DT_SIZE, e );
+                lemmas.push_back( mt.eqNode( NodeManager::currentNM()->mkNode( kind::PLUS, new_mt, ds ) ) );
+                //lemmas.push_back( NodeManager::currentNM()->mkNode( kind::GEQ, ds, d_zero ) );
+              }
+              d_szinfo[m]->d_sygus_measure_term_active = new_mt;
+            }
+          }
+        }else{
+          // not sure if it is a size term or not (may be registered later?)
+        }
       }else{
-        ps = NULL;
+        d_register_st[e] = false;
       }
-      d_prog_search[a] = ps;
     }else{
-      ps = it->second;
-    }
-    if( ps ){
-      ps->addTester( tindex, n, exp );
+      d_register_st[e] = false;
     }
   }
 }
 
-Node SygusSymBreak::getAnchor( Node n ) {
-  if( n.getKind()==APPLY_SELECTOR_TOTAL ){
-    return getAnchor( n[0] );
-  }else{
-    return n;
+void SygusSymBreakNew::registerMeasureTerm( Node m ) {
+  std::map< Node, SearchSizeInfo * >::iterator it = d_szinfo.find( m );
+  if( it==d_szinfo.end() ){
+    Trace("sygus-sb") << "Sygus : register measure term : " << m << std::endl;
+    d_szinfo[m] = new SearchSizeInfo( m, d_td->getSatContext() );
   }
 }
 
-void SygusSymBreak::ProgSearch::addTester( int tindex, Node n, Node exp ) {
-#ifdef CVC4_ASSERTIONS
-  Node a;
-  int teindex = DatatypesRewriter::isTester( exp, a );
-  Assert( teindex==tindex );
-  Assert( a==n );
-#endif
-  NodeMap::const_iterator it = d_testers.find( n );
-  if( it==d_testers.end() ){
-    d_testers[n] = exp;
-    if( n==d_anchor ){
-      assignTester( tindex, n, 0 );
-    }else{
-      IntMap::const_iterator it = d_watched_terms.find( n );
-      if( it!=d_watched_terms.end() ){
-        assignTester( tindex, n, (*it).second );
+void SygusSymBreakNew::notifySearchSize( Node m, unsigned s, Node exp, std::vector< Node >& lemmas ) {
+  std::map< Node, SearchSizeInfo * >::iterator its = d_szinfo.find( m );
+  Assert( its!=d_szinfo.end() );
+  if( its->second->d_search_size.find( s )==its->second->d_search_size.end() ){
+    its->second->d_search_size[s] = true;
+    its->second->d_search_size_exp[s] = exp;
+    Assert( s==0 || its->second->d_search_size.find( s-1 )!=its->second->d_search_size.end() );
+    Trace("sygus-fair") << "SygusSymBreakNew:: now considering term measure : " << s << " for " << m << std::endl;
+    Assert( s>=its->second->d_curr_search_size );
+    while( s>its->second->d_curr_search_size ){
+      incrementCurrentSearchSize( m, lemmas );
+    }
+    Trace("sygus-fair") << "...finish increment for term measure : " << s << std::endl;
+    /*
+    //re-add all testers (some may now be relevant) TODO
+    for( IntMap::const_iterator it = d_testers.begin(); it != d_testers.end(); ++it ){
+      Node n = (*it).first;
+      NodeMap::const_iterator itx = d_testers_exp.find( n );
+      if( itx!=d_testers_exp.end() ){
+        int tindex = (*it).second;
+        Node exp = (*itx).second;
+        assertTester( tindex, n, exp, lemmas );
       }else{
-        Trace("sygus-sym-break-debug2") << "...add to wait list " << tindex << " " << n << " for " << d_anchor << std::endl;
+        Assert( false );
       }
     }
-  }else{
-    Trace("sygus-sym-break-debug2") << "...already seen " << tindex << " " << n << " for " << d_anchor << std::endl;
+    */
   }
 }
 
-bool SygusSymBreak::ProgSearch::assignTester( int tindex, Node n, int depth ) {
-  Trace("sygus-sym-break-debug") << "SymBreak : Assign tester : " << tindex << " " << n << ", depth = " << depth << " of " << d_anchor << std::endl;
-  TypeNode tn = n.getType();
-  Assert( tn.isDatatype() );
-  const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-  std::vector< Node > tst_waiting;
-  for( unsigned i=0; i<dt[tindex].getNumArgs(); i++ ){
-    Node sel = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[tindex][i].getSelector() ), n );
-    NodeMap::const_iterator it = d_testers.find( sel );
-    if( it!=d_testers.end() ){
-      tst_waiting.push_back( (*it).second );
-    }else{
-      Trace("sygus-sym-break-debug") << "...add " << sel << " as watch term for " << (depth+1) << std::endl;
-      d_watched_terms[sel] = depth+1;
-    }
-  }
-  //update watched count
-  IntIntMap::const_iterator it = d_watched_count.find( depth+1 );
-  if( it==d_watched_count.end() ){
-    d_watched_count[depth+1] = dt[tindex].getNumArgs();
-  }else{
-    d_watched_count[depth+1] = d_watched_count[depth+1] + dt[tindex].getNumArgs();
-  }
-  Trace("sygus-sym-break-debug") << "...watched count now " << d_watched_count[depth+1].get() << " for " << (depth+1) << " of " << d_anchor << std::endl;
-  //now decrement watch count and process
-  if( depth>0 ){
-    Assert( d_watched_count[depth]>0 );
-    d_watched_count[depth] = d_watched_count[depth] - 1;
-  }
-  //determine if any subprograms on the current path are redundant
-  if( processSubprograms( n, depth, depth ) ){
-    if( processProgramDepth( depth ) ){
-      //assign preexisting testers
-      for( unsigned i=0; i<tst_waiting.size(); i++ ){
-        Node nw;
-        int tindexw = DatatypesRewriter::isTester( tst_waiting[i], nw );
-        Assert( tindexw!=-1 );
-        if( !assignTester( tindexw, nw, depth+1 ) ){
-          return false;
+unsigned SygusSymBreakNew::getSearchSizeFor( Node n ) {
+  Trace("sygus-sb-debug2") << "get search size for term : " << n << std::endl;
+  std::map< Node, Node >::iterator ita = d_term_to_anchor.find( n );
+  Assert( ita != d_term_to_anchor.end() );
+  return getSearchSizeForAnchor( ita->second );
+}
+
+unsigned SygusSymBreakNew::getSearchSizeForAnchor( Node a ) {
+  Trace("sygus-sb-debug2") << "get search size for anchor : " << a << std::endl;
+  std::map< Node, Node >::iterator it = d_anchor_to_measure_term.find( a );
+  Assert( it!=d_anchor_to_measure_term.end() );
+  return getSearchSizeForMeasureTerm( it->second );
+}
+
+unsigned SygusSymBreakNew::getSearchSizeForMeasureTerm( Node m ) {
+  Trace("sygus-sb-debug2") << "get search size for measure : " << m << std::endl;
+  std::map< Node, SearchSizeInfo * >::iterator its = d_szinfo.find( m );
+  Assert( its!=d_szinfo.end() );
+  return its->second->d_curr_search_size;
+}
+  
+void SygusSymBreakNew::incrementCurrentSearchSize( Node m, std::vector< Node >& lemmas ) {
+  std::map< Node, SearchSizeInfo * >::iterator itsz = d_szinfo.find( m );
+  Assert( itsz!=d_szinfo.end() );
+  itsz->second->d_curr_search_size++;
+  Trace("sygus-fair") << "  register search size " << itsz->second->d_curr_search_size << " for " << m << std::endl;
+  for( std::map< Node, SearchCache >::iterator itc = d_cache.begin(); itc != d_cache.end(); ++itc ){
+    Node a = itc->first;
+    Trace("sygus-fair-debug") << "  look at anchor " << a << "..." << std::endl;
+    // check whether a is bounded by m
+    Assert( d_anchor_to_measure_term.find( a )!=d_anchor_to_measure_term.end() );
+    if( d_anchor_to_measure_term[a]==m ){
+      for( std::map< TypeNode, std::map< unsigned, std::vector< Node > > >::iterator its = itc->second.d_sb_lemmas.begin();
+           its != itc->second.d_sb_lemmas.end(); ++its ){
+        TypeNode tn = its->first;
+        TNode x = getFreeVar( tn );
+        for( std::map< unsigned, std::vector< Node > >::iterator it = its->second.begin(); it != its->second.end(); ++it ){
+          unsigned sz = it->first;
+          int new_depth = ((int)itsz->second->d_curr_search_size) - ((int)sz);
+          std::map< unsigned, std::vector< Node > >::iterator itt = itc->second.d_search_terms[tn].find( new_depth );
+          if( itt!=itc->second.d_search_terms[tn].end() ){
+            for( unsigned k=0; k<itt->second.size(); k++ ){
+              TNode t = itt->second[k];
+              if( !options::sygusSymBreakLazy() || d_active_terms.find( t )!=d_active_terms.end() ){
+                for( unsigned j=0; j<it->second.size(); j++ ){
+                  Node lem = it->second[j];
+                  addSymBreakLemma( tn, lem, x, t, sz, new_depth, lemmas );
+                }
+              }
+            }
+          }
         }
       }
-      return true;
     }
   }
-  return false;
 }
 
-bool SygusSymBreak::ProgSearch::processProgramDepth( int depth ){
-  if( depth==d_prog_depth.get() && ( depth==0 || ( d_watched_count.find( depth )!=d_watched_count.end() && d_watched_count[depth]==0 ) ) ){
-    d_prog_depth = d_prog_depth + 1;
-    if( depth>0 ){
-      Trace("sygus-sym-break-debug") << "Program is set for depth " << depth << std::endl;
-      std::map< TypeNode, int > var_count;
-      std::vector< Node > testers;
-      std::map< Node, std::vector< Node > > testers_u;
-      //now have entire information about candidate program at given depth
-      Node prog = getCandidateProgramAtDepth( depth, d_anchor, 0, Node::null(), var_count, testers, testers_u );
-      if( !prog.isNull() ){
-        if( !d_parent->processCurrentProgram( d_anchor, d_anchor_type, depth, prog, testers, testers_u, var_count ) ){
-          return false;
-        }
+void SygusSymBreakNew::check( std::vector< Node >& lemmas ) {
+  Trace("sygus-sb") << "SygusSymBreakNew::check" << std::endl;
+  for( std::map< Node, bool >::iterator it = d_register_st.begin(); it != d_register_st.end(); ++it ){
+    if( it->second ){
+      Node prog = it->first;
+      Node progv = d_td->getValuation().getModel()->getValue( prog );
+      // TODO : remove this step (ensure there is no way a sygus term cannot be assigned a tester before this point)
+      if( !debugTesters( prog, progv, 0, lemmas ) ){
+        Trace("sygus-sb") << "  SygusSymBreakNew::check: ...WARNING: considered missing split for " << prog << "." << std::endl;
+        // this should not happen generally, it is caused by a sygus term not being assigned a tester
+        //Assert( false );
       }else{
-        Assert( false );
+        //debugging : ensure fairness was properly handled
+        if( options::sygusFair()==SYGUS_FAIR_DT_SIZE ){  
+          Node prog_sz = NodeManager::currentNM()->mkNode( kind::DT_SIZE, prog );
+          Node prog_szv = d_td->getValuation().getModel()->getValue( prog_sz );
+          Node progv_sz = NodeManager::currentNM()->mkNode( kind::DT_SIZE, progv );
+            
+          Trace("sygus-sb") << "  Mv[" << prog << "] = " << progv << ", size = " << prog_szv << std::endl;
+          if( prog_szv.getConst<Rational>().getNumerator().toUnsignedInt() > getSearchSizeForAnchor( prog ) ){
+            AlwaysAssert( false );
+            Node szlem = NodeManager::currentNM()->mkNode( kind::OR, prog.eqNode( progv ).negate(),
+                                                                     prog_sz.eqNode( progv_sz ) );
+            Trace("sygus-sb-warn") << "SygusSymBreak : WARNING : adding size correction : " << szlem << std::endl;
+            lemmas.push_back( szlem );                                                     
+            return;
+          }
+        }
+        
+        // register the search value ( prog -> progv ), this may invoke symmetry breaking 
+        if( options::sygusSymBreakDynamic() ){
+          if( !registerSearchValue( prog, prog, progv, 0, lemmas ) ){
+            Trace("sygus-sb") << "  SygusSymBreakNew::check: ...added new symmetry breaking lemma for " << prog << "." << std::endl;
+          }
+        }
       }
     }
-    return processProgramDepth( depth+1 );
-  }else{
-    return true;
   }
-}
-
-bool SygusSymBreak::ProgSearch::processSubprograms( Node n, int depth, int odepth ) {
-  Trace("sygus-sym-break-debug") << "Processing subprograms on path " << n << ", which has depth " << depth << std::endl;
-  depth--;
-  if( depth>0 ){
-    Assert( n.getKind()==APPLY_SELECTOR_TOTAL );
-    std::map< TypeNode, int > var_count;
-    std::vector< Node > testers;
-    std::map< Node, std::vector< Node > > testers_u;
-    //now have entire information about candidate program at given depth
-    Node prog = getCandidateProgramAtDepth( odepth-depth, n[0], 0, Node::null(), var_count, testers, testers_u );
-    if( !prog.isNull() ){
-      if( !d_parent->processCurrentProgram( n[0], n[0].getType(), odepth-depth, prog, testers, testers_u, var_count ) ){
-        return false;
+  //register any measured terms that we haven't encountered yet (should only be invoked on first call to check
+  std::vector< Node > mts;
+  d_tds->getMeasuredTerms( mts );
+  for( unsigned i=0; i<mts.size(); i++ ){
+    registerSizeTerm( mts[i], lemmas );
+  }
+  Trace("sygus-sb") << " SygusSymBreakNew::check: finished." << std::endl;
+  
+  if( Trace.isOn("cegqi-engine") ){
+    if( lemmas.empty() ){
+      Trace("cegqi-engine") << "*** Sygus : passed datatypes check. term size(s) : ";
+      for( std::map< Node, SearchSizeInfo * >::iterator it = d_szinfo.begin(); it != d_szinfo.end(); ++it ){
+        SearchSizeInfo * s = it->second;
+        Trace("cegqi-engine") << s->d_curr_search_size << " ";
       }
-      //also try higher levels
-      return processSubprograms( n[0], depth, odepth );
-    }else{
-      Trace("sygus-sym-break-debug") << "...program incomplete." << std::endl;
+      Trace("cegqi-engine") << std::endl;
     }
   }
-  return true;
 }
 
-Node SygusSymBreak::ProgSearch::getCandidateProgramAtDepth( int depth, Node prog, int curr_depth, Node parent, std::map< TypeNode, int >& var_count,
-                                                            std::vector< Node >& testers, std::map< Node, std::vector< Node > >& testers_u ) {
-  Assert( depth>=curr_depth );
-  Trace("sygus-sym-break-debug") << "Reconstructing program for " << prog << " at depth " << curr_depth << "/" << depth << " " << prog.getType() << std::endl;
-  NodeMap::const_iterator it = d_testers.find( prog );
-  if( it!=d_testers.end() ){
-    Node tst = (*it).second;
-    testers.push_back( tst );
-    testers_u[parent].push_back( tst );
-    //Assert( tst[0]==prog );
-    int tindex = DatatypesRewriter::isTester( tst );//Datatype::indexOf( tst.getOperator().toExpr() );
-    Assert( tindex!=-1 );
-    TypeNode tn = prog.getType();
-    Assert( tn.isDatatype() );
-    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-    std::map< int, Node > pre;
-    if( curr_depth<depth ){
-      for( unsigned i=0; i<dt[tindex].getNumArgs(); i++ ){
-        Node sel = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[tindex][i].getSelector() ), prog );
-        pre[i] = getCandidateProgramAtDepth( depth, sel, curr_depth+1, prog, var_count, testers, testers_u );
-        if( pre[i].isNull() ){
-          return Node::null();
-        }
-      }
+void SygusSymBreakNew::getPossibleCons( const Datatype& dt, TypeNode tn, std::vector< bool >& pcons ) {
+  Assert( pcons.size()==dt.getNumConstructors() );
+  d_tds->registerSygusType( tn );
+  for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
+    if( d_tds->isGenericRedundant( tn, i ) ){
+      pcons[i] = false;
     }
-    return d_parent->d_tds->mkGeneric( dt, tindex, var_count, pre );
-  }else{
-    Trace("sygus-sym-break-debug") << "...failure." << std::endl;
-    return Node::null();
   }
 }
 
-bool SygusSymBreak::processCurrentProgram( Node a, TypeNode at, int depth, Node prog,
-                                           std::vector< Node >& testers, std::map< Node, std::vector< Node > >& testers_u,
-                                           std::map< TypeNode, int >& var_count ) {
-  Assert( a.getType()==at );
-  std::map< Node, bool >::iterator it = d_redundant[at].find( prog );
-  bool red;
-  if( it==d_redundant[at].end() ){
-    Trace("sygus-sym-break") << "Currently considering program : " << prog << " at depth " << depth << " for " << a << std::endl;
-    Node progr = d_tds->getNormalized( at, prog );
-    Node rep_prog;
-    std::map< Node, Node >::iterator itnp = d_normalized_to_orig[at].find( progr );
-    int tsize = d_tds->getSygusTermSize( prog );
-    if( itnp==d_normalized_to_orig[at].end() ){
-      d_normalized_to_orig[at][progr] = prog;
-      if( progr.getKind()==SKOLEM && d_tds->getSygusTypeForVar( progr )==at ){
-        Trace("sygus-nf") << "* Sygus sym break : " << prog << " rewrites to variable " << progr << " of same type as self" << std::endl;
-        d_redundant[at][prog] = true;
-        red = true;
-      }else{
-        d_redundant[at][prog] = false;
-        red = false;
-        Trace("sygus-nf-reg") << "*** Sygus normal form : normal form of " << prog << " is " << progr << std::endl;
-      }
-    }else{
-      rep_prog = itnp->second;
-      if( tsize<d_normalized_to_term_size[at][progr] ){
-        d_normalized_to_orig[at][progr] = prog;
-        Trace("sygus-nf-debug") << "Program is redundant, but has smaller size than " << rep_prog << std::endl;
-        d_redundant[at].erase( rep_prog );
-        d_redundant[at][prog] = false;
-        red = false;
-        Trace("sygus-nf-reg") << "*** Sygus normal form : normal form of " << prog << " is " << progr << " (redundant but smaller than " << rep_prog << ") " << std::endl;
-      }else{
-        Assert( prog!=itnp->second );
-        d_redundant[at][prog] = true;
-        red = true;
-        Trace("sygus-nf") << "* Sygus sym break : " << prog << " and " << rep_prog << " both rewrite to " << progr << std::endl;
-        Trace("sygus-nf-debug") << "  sizes : " << tsize << " " << d_normalized_to_term_size[at][progr] << std::endl;
-      }
+bool SygusSymBreakNew::debugTesters( Node n, Node vn, int ind, std::vector< Node >& lemmas ) {
+  Assert( vn.getKind()==kind::APPLY_CONSTRUCTOR );
+  if( Trace.isOn("sygus-sb-warn") ){
+    Node prog_sz = NodeManager::currentNM()->mkNode( kind::DT_SIZE, n );
+    Node prog_szv = d_td->getValuation().getModel()->getValue( prog_sz );
+    for( int i=0; i<ind; i++ ){
+      Trace("sygus-sb-warn") << "  ";
     }
-    if( !red ){
-      d_normalized_to_term_size[at][progr] = tsize;
-    }else{
-      Assert( !testers.empty() );
-      bool conflict_gen_set = false;
-      if( options::sygusNormalFormGlobalGen() ){
-        bool narrow = false;
-        Trace("sygus-nf-gen-debug") << "Tester tree is : " << std::endl;
-        for( std::map< Node, std::vector< Node > >::iterator it = testers_u.begin(); it != testers_u.end(); ++it ){
-          Trace("sygus-nf-gen-debug") << "  " << it->first << " -> " << std::endl;
-          for( unsigned i=0; i<it->second.size(); i++ ){
-            Trace("sygus-nf-gen-debug") << "    " << it->second[i] << std::endl;
-          }
-        }
-        Trace("sygus-nf-gen-debug") << std::endl;
-
-        //generalize conflict
-        if( prog.getNumChildren()>0 ){
-          Assert( !testers.empty() );
-          d_tds->registerSygusType( at );
-          //Trace("sygus-nf-gen-debug") << "Testers are : " << std::endl;
-          //for( unsigned i=0; i<testers.size(); i++ ){
-          //  Trace("sygus-nf-gen-debug") << "* " << testers[i] << std::endl;
-          //}
-          Assert( testers[0][0]==a );
-          Assert( prog.getNumChildren()==testers_u[a].size() );
-          //get the normal form for each child
-          Kind parentKind = prog.getKind();
-          Kind parentOpKind = prog.getOperator().getKind();
-          Trace("sygus-nf-gen-debug") << "Parent kind is " << parentKind << " " << parentOpKind << std::endl;
-          //std::map< int, Node > norm_children;
-
-          //arguments that are relevant
-          std::map< unsigned, bool > rlv;
-          //testers that are irrelevant
-          std::map< Node, bool > irrlv_tst;
-
-          std::vector< Node > children;
-          std::vector< TypeNode > children_stype;
-          std::vector< Node > nchildren;
-          for( unsigned i=0; i<testers_u[a].size(); i++ ){
-            TypeNode tn = testers_u[a][i][0].getType();
-            children.push_back( prog[i] );
-            children_stype.push_back( tn );
-            Node nc = d_tds->getNormalized( tn, prog[i], true );
-            //norm_children[i] = nc;
-            rlv[i] = true;
-            nchildren.push_back( nc );
-            Trace("sygus-nf-gen") << "- child " << i << " normalizes to " << nc << std::endl;
-          }
-          if( testers_u[a].size()>1 ){
-            bool finished = false;
-            const Datatype & pdt = ((DatatypeType)(at).toType()).getDatatype();
-            int pc = DatatypesRewriter::isTester( testers[0] );//Datatype::indexOf( testers[0].getOperator().toExpr() );
-            Assert( pc!=-1 );
-            // [1] determine a minimal subset of the arguments that the rewriting depended on
-            //quick checks based on constants
-            for( unsigned i=0; i<nchildren.size(); i++ ){
-              Node arg = nchildren[i];
-              if( arg.isConst() ){
-                if( parentOpKind==kind::BUILTIN ){
-                  Trace("sygus-nf-gen") << "-- constant arg " <<i << " under builtin operator." << std::endl;
-                  if( !processConstantArg( at, pdt, pc, parentKind, i, arg, rlv ) ){
-                    Trace("sygus-nf") << "  - argument " << i << " is singularly redundant." << std::endl;
-                    for( std::map< unsigned, bool >::iterator itr = rlv.begin(); itr != rlv.end(); ++itr ){
-                      if( itr->first!=i ){
-                        rlv[itr->first] = false;
-                      }
-                    }
-                    narrow = true;
-                    finished = true;
-                    break;
-                  }
-                }
-              }
-            }
-
-            if( !finished ){
-              // [2] check replacing each argument with a fresh variable gives the same result
-              Node progc = prog;
-              if( options::sygusNormalFormGlobalArg() ){
-                bool argChanged = false;
-                Trace("sygus-nf-gen-debug") << "Check replacements on " << prog << " " << prog.getKind() << std::endl;
-                for( unsigned i=0; i<prog.getNumChildren(); i++ ){
-                  Node prev = children[i];
-                  children[i] = d_tds->getVarInc( children_stype[i], var_count );
-                  if( parentOpKind!=kind::BUILTIN ){
-                    children.insert( children.begin(), prog.getOperator() );
-                  }
-                  Node progcn = NodeManager::currentNM()->mkNode( prog.getKind(), children );
-                  if( parentOpKind!=kind::BUILTIN ){
-                    children.erase( children.begin(), children.begin() + 1 );
-                  }
-                  Node progcr = Rewriter::rewrite( progcn );
-                  Trace("sygus-nf-gen-debug") << "Var replace argument " << i << " : " << progcn << " -> " << progcr << std::endl;
-                  if( progcr==progr ){
-                    //this argument is not relevant, continue with it remaining as variable
-                    rlv[i] = false;
-                    argChanged = true;
-                    narrow = true;
-                    Trace("sygus-nf") << "  - argument " << i << " is not relevant." << std::endl;
-                  }else{
-                    //go back to original
-                    children[i] = prev;
-                    var_count[children_stype[i]]--;
-                  }
-                }
-                if( argChanged ){
-                  progc = NodeManager::currentNM()->mkNode( prog.getKind(), children );
-                }
-              }
-              Trace("sygus-nf-gen-debug") << "Relevant template (post argument analysis) is : " << progc << std::endl;
-
-              // [3] generalize content
-              if( options::sygusNormalFormGlobalContent() ){
-                std::map< Node, std::vector< Node > > nodes;
-                std::vector< Node > curr_vars;
-                std::vector< Node > curr_subs;
-                collectSubterms( progc, testers[0], testers_u, nodes );
-                for( std::map< Node, std::vector< Node > >::iterator it = nodes.begin(); it != nodes.end(); ++it ){
-                  if( it->second.size()>1 ){
-                    Trace("sygus-nf-gen-debug") << it->first << " occurs " << it->second.size() << " times, at : " << std::endl;
-                    bool success = true;
-                    TypeNode tn;
-                    for( unsigned j=0; j<it->second.size(); j++ ){
-                      Trace("sygus-nf-gen-debug") << "  " << it->second[j] << " ";
-                      TypeNode tnc = it->second[j][0].getType();
-                      if( !tn.isNull() && tn!=tnc ){
-                        success = false;
-                      }
-                      tn = tnc;
-                    }
-                    Trace("sygus-nf-gen-debug") << std::endl;
-                    if( success ){
-                      Node prev = progc;
-                      //try a substitution on all terms of this form simultaneously to see if the content of this subterm is irrelevant
-                      TypeNode tn = it->second[0][0].getType();
-                      TNode st = it->first;
-                      //we may already have substituted within this subterm
-                      if( !curr_subs.empty() ){
-                        st = st.substitute( curr_vars.begin(), curr_vars.end(), curr_subs.begin(), curr_subs.end() );
-                        Trace("sygus-nf-gen-debug") << "...substituted : " << st << std::endl;
-                      }
-                      TNode nv = d_tds->getVarInc( tn, var_count );
-                      progc = progc.substitute( st, nv );
-                      Node progcr = Rewriter::rewrite( progc );
-                      Trace("sygus-nf-gen-debug") << "Var replace content " << st << " : " << progc << " -> " << progcr << std::endl;
-                      if( progcr==progr ){
-                        narrow = true;
-                        Trace("sygus-nf") << "  - content " << st << " is not relevant." << std::endl;
-                        int t_prev = -1;
-                        for( unsigned i=0; i<it->second.size(); i++ ){
-                          irrlv_tst[it->second[i]] = true;
-                          Trace("sygus-nf-gen-debug") << "By content, " << it->second[i] << " is irrelevant." << std::endl;
-                          int t_curr = std::find( testers.begin(), testers.end(), it->second[i] )-testers.begin();
-                          Assert( testers[t_curr]==it->second[i] );
-                          if( t_prev!=-1 ){
-                            d_lemma_inc_eq[at][prog].push_back( std::pair< int, int >( t_prev, t_curr ) );
-                            Trace("sygus-nf-gen-debug") << "Which requires " << testers[t_prev][0] << " = " << testers[t_curr][0] << std::endl;
-                          }
-                          t_prev = t_curr;
-                        }
-                        curr_vars.push_back( st );
-                        curr_subs.push_back( nv );
-                      }else{
-                        var_count[tn]--;
-                        progc = prev;
-                      }
-                    }else{
-                      Trace("sygus-nf-gen-debug") << "...content is from multiple grammars, abort." << std::endl;
-                    }
-                  }
-                }
-              }
-              Trace("sygus-nf-gen-debug") << "Relevant template (post content analysis) is : " << progc << std::endl;
-            }
-            if( narrow ){
-              //relevant testers : root + recursive collection of relevant children
-              Trace("sygus-nf-gen-debug") << "Collect relevant testers..." << std::endl;
-              std::vector< Node > rlv_testers;
-              rlv_testers.push_back( testers[0] );
-              for( unsigned i=0; i<testers_u[a].size(); i++ ){
-                if( rlv[i] ){
-                  collectTesters( testers_u[a][i], testers_u, rlv_testers, irrlv_tst );
-                }
-              }
-              //must guard case : generalized lemma cannot exclude original representation
-              if( !isSeparation( rep_prog, testers[0], testers_u, rlv_testers ) ){
-                //must construct template
-                Node anc_var;
-                std::map< TypeNode, Node >::iterator itav = d_anchor_var.find( at );
-                if( itav==d_anchor_var.end() ){
-                  anc_var = NodeManager::currentNM()->mkSkolem( "a", at, "Sygus nf global gen anchor var" );
-                  d_anchor_var[at] = anc_var;
-                }else{
-                  anc_var = itav->second;
-                }
-                int status = 0;
-                Node anc_temp = getSeparationTemplate( at, rep_prog, anc_var, status );
-                Trace("sygus-nf") << "  -- separation template is " << anc_temp << ", status = " << status << std::endl;
-                d_lemma_inc_eq_gr[status][at][prog].push_back( anc_temp );
-              }else{
-                Trace("sygus-nf") << "  -- no separation necessary" << std::endl;
-              }
-              Trace("sygus-nf-gen-debug") << "Relevant testers : " << std::endl;
-              for( unsigned i=0; i<testers.size(); i++ ){
-                bool rl = std::find( rlv_testers.begin(), rlv_testers.end(), testers[i] )!=rlv_testers.end();
-                Trace("sygus-nf-gen-debug") << "* " << testers[i] << " -> " << rl << std::endl;
-                d_lemma_inc_tst[at][prog].push_back( rl );
-              }
-
-              conflict_gen_set = true;
-            }
-          }
-        }
-      }
-      if( !conflict_gen_set ){
-        for( unsigned i=0; i<testers.size(); i++ ){
-          d_lemma_inc_tst[at][prog].push_back( true );
-        }
-      }
+    Trace("sygus-sb-warn") << n << " : " << vn << " : " << prog_szv << std::endl;
+  }
+  TypeNode tn = n.getType();
+  const Datatype& dt = ((DatatypeType)tn.toType()).getDatatype();
+  int cindex = Datatype::indexOf( vn.getOperator().toExpr() );
+  Node tst = DatatypesRewriter::mkTester( n, cindex, dt );
+  bool hastst = d_td->getValuation().getModel()->hasTerm( tst );
+  Node tstrep = d_td->getValuation().getModel()->getRepresentative( tst );
+  if( !hastst || tstrep!=NodeManager::currentNM()->mkConst( true ) ){
+    Trace("sygus-sb-warn") << "- has tester : " << tst << " : " << ( hastst ? "true" : "false" );
+    Trace("sygus-sb-warn") << ", value=" << tstrep << std::endl;
+    if( !hastst ){
+      Node split = SygusSplitNew::getSygusSplit( d_tds, n, dt );
+      Assert( !split.isNull() );
+      lemmas.push_back( split );
+      return false;
     }
-  }else{
-    red = it->second;
-    Trace("sygus-nf-debug") << "Already processed, redundant : " << red << std::endl;
   }
-  if( red ){
-    if( std::find( d_lemmas_reported[at][prog].begin(), d_lemmas_reported[at][prog].end(), a )==d_lemmas_reported[at][prog].end() ){
-      d_lemmas_reported[at][prog].push_back( a );
-      Assert( d_lemma_inc_tst[at][prog].size()==testers.size() );
-      std::vector< Node > disj;
-      //get the guard equalities
-      for( unsigned r=0; r<2; r++ ){
-        for( unsigned i=0; i<d_lemma_inc_eq_gr[r][at][prog].size(); i++ ){
-          TNode n2 = d_lemma_inc_eq_gr[r][at][prog][i];
-          if( r==1 ){
-            TNode anc_var = d_anchor_var[at];
-            TNode anc = a;
-            Assert( !anc_var.isNull() );
-            n2 = n2.substitute( anc_var, anc );
-          }
-          disj.push_back( a.eqNode( n2 ) );
-        }
-      }
-      //get the equalities that should be included
-      for( unsigned i=0; i<d_lemma_inc_eq[at][prog].size(); i++ ){
-        TNode n1 = testers[ d_lemma_inc_eq[at][prog][i].first ][0];
-        TNode n2 = testers[ d_lemma_inc_eq[at][prog][i].second ][0];
-        disj.push_back( n1.eqNode( n2 ).negate() );
-      }
-      //get the testers that should be included
-      for( unsigned i=0; i<testers.size(); i++ ){
-        if( d_lemma_inc_tst[at][prog][i] ){
-          disj.push_back( testers[i].negate() );
-        }
-      }
-      Node lem = disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( OR, disj );
-      d_lemmas.push_back( lem );
-      Trace("sygus-sym-break-lemma") << "Sym break lemma : " << lem << std::endl;
-    }else{
-      Trace("sygus-sym-break2") << "repeated lemma for " << prog << " from " << a << std::endl;
+  for( unsigned i=0; i<vn.getNumChildren(); i++ ){
+    Node sel = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex].getSelectorInternal( tn.toType(), i ) ), n );
+    if( !debugTesters( sel, vn[i], ind+1, lemmas ) ){
+      return false;
     }
-    //for now, continue adding lemmas (since we are not forcing conflicts)
-    //return false;
   }
   return true;
 }
 
-bool SygusSymBreak::isSeparation( Node rep_prog, Node tst_curr, std::map< Node, std::vector< Node > >& testers_u, std::vector< Node >& rlv_testers ) {
-  TypeNode tn = tst_curr[0].getType();
-  Trace("sygus-nf-gen-debug") << "is separation " << rep_prog << " " << tst_curr << " " << tn << std::endl;
-  Node rop = rep_prog.getNumChildren()==0 ? rep_prog : rep_prog.getOperator();
-  //we can continue if the tester in question is relevant
-  if( std::find( rlv_testers.begin(), rlv_testers.end(), tst_curr )!=rlv_testers.end() ){
-    int tindex = DatatypesRewriter::isTester( tst_curr );
-    Assert( tindex!=-1 );
-    //unsigned tindex = Datatype::indexOf( tst_curr.getOperator().toExpr() );
-    d_tds->registerSygusType( tn );
-    Node op = d_tds->getArgOp( tn, tindex );
-    if( op!=rop ){
-      Trace("sygus-nf-gen-debug") << "mismatch, success." << std::endl;
-      return true;
-    }else if( !testers_u[tst_curr[0]].empty() ){
-      Assert( testers_u[tst_curr[0]].size()==rep_prog.getNumChildren() );
-      for( unsigned i=0; i<rep_prog.getNumChildren(); i++ ){
-        if( isSeparation( rep_prog[i], testers_u[tst_curr[0]][i], testers_u, rlv_testers ) ){
-          return true;
-        }
-      }
+Node SygusSymBreakNew::getCurrentTemplate( Node n, std::map< TypeNode, int >& var_count ) {
+  if( d_active_terms.find( n )!=d_active_terms.end() ){
+    TypeNode tn = n.getType();
+    IntMap::const_iterator it = d_testers.find( n );
+    Assert( it != d_testers.end() );
+    const Datatype& dt = ((DatatypeType)tn.toType()).getDatatype();
+    int tindex = (*it).second;
+    Assert( tindex>=0 );
+    Assert( tindex<(int)dt.getNumConstructors() );
+    std::vector< Node > children;
+    children.push_back( Node::fromExpr( dt[tindex].getConstructor() ) );
+    for( unsigned i=0; i<dt[tindex].getNumArgs(); i++ ){
+      Node sel = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[tindex].getSelectorInternal( tn.toType(), i ) ), n );
+      Node cc = getCurrentTemplate( sel, var_count );
+      children.push_back( cc );
     }
-    return false;
+    return NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, children );
   }else{
-    Trace("sygus-nf-gen-debug") << "not relevant, fail." << std::endl;
-    return false;
+    return d_tds->getFreeVarInc( n.getType(), var_count );
   }
 }
 
-Node SygusSymBreak::getSeparationTemplate( TypeNode tn,  Node rep_prog, Node anc_var, int& status ) {
-  Trace("sygus-nf-gen-debug") << "get separation template " << rep_prog << std::endl;
-  const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-  if( d_tds->isVar( rep_prog ) ){
-    status = 1;
-    return anc_var;
-  }else{
-    Node rop = rep_prog.getNumChildren()==0 ? rep_prog : rep_prog.getOperator();
-    int rop_arg = d_tds->getOpArg( tn, rop );
-    Assert( rop_arg>=0 && rop_arg<(int)dt.getNumConstructors() );
-    Assert( rep_prog.getNumChildren()==dt[rop_arg].getNumArgs() );
-
-    std::vector< Node > children;
-    children.push_back( Node::fromExpr( dt[rop_arg].getConstructor() ) );
-    for( unsigned i=0; i<rep_prog.getNumChildren(); i++ ){
-      TypeNode tna = TypeNode::fromType( ((SelectorType)dt[rop_arg][i].getType()).getRangeType() );
+Node SygusSymBreakNew::SearchSizeInfo::getOrMkSygusMeasureTerm( std::vector< Node >& lemmas ) {
+  if( d_sygus_measure_term.isNull() ){
+    d_sygus_measure_term = NodeManager::currentNM()->mkSkolem( "mt", NodeManager::currentNM()->integerType() );
+    lemmas.push_back( NodeManager::currentNM()->mkNode( kind::GEQ, d_sygus_measure_term, NodeManager::currentNM()->mkConst( Rational(0) ) ) );
+  }
+  return d_sygus_measure_term;
+}
 
-      int new_status = 0;
-      Node arg = getSeparationTemplate( tna, rep_prog[i], anc_var, new_status );
-      if( new_status==1 ){
-        TNode tanc_var = anc_var;
-        TNode tanc_var_subs = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[rop_arg][i].getSelector() ), anc_var );
-        arg = arg.substitute( tanc_var, tanc_var_subs );
-        status = 1;
-      }
-      children.push_back( arg );
-    }
-    return NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
+Node SygusSymBreakNew::SearchSizeInfo::getOrMkSygusActiveMeasureTerm( std::vector< Node >& lemmas ) {
+  if( d_sygus_measure_term_active.isNull() ){
+    d_sygus_measure_term_active = getOrMkSygusMeasureTerm( lemmas );
   }
+  return d_sygus_measure_term_active;
 }
 
-bool SygusSymBreak::processConstantArg( TypeNode tnp, const Datatype & pdt, int pc,
-                                        Kind k, int i, Node arg, std::map< unsigned, bool >& rlv ) {
-  Assert( d_tds->hasKind( tnp, k ) );
-  if( k==AND || k==OR || ( k==EQUAL && arg.getType().isBoolean() ) || k==XOR || k==IMPLIES || ( k==ITE && i==0 ) ){
-    return false;
-  }else if( d_tds->isIdempotentArg( arg, k, i ) ){
-    if( pdt[pc].getNumArgs()==2 ){
-      int oi = i==0 ? 1 : 0;
-      TypeNode otn = TypeNode::fromType( ((SelectorType)pdt[pc][oi].getType()).getRangeType() );
-      if( otn==tnp ){
-        return false;
-      }
-    }
-  }else if( d_tds->isSingularArg( arg, k, i ) ){
-    if( d_tds->hasConst( tnp, arg ) ){
-      return false;
+Node SygusSymBreakNew::SearchSizeInfo::getFairnessLiteral( unsigned s, TheoryDatatypes * d, std::vector< Node >& lemmas ) {
+  if( options::sygusFair()!=SYGUS_FAIR_NONE ){
+    std::map< unsigned, Node >::iterator it = d_lits.find( s );
+    if( it==d_lits.end() ){
+      Assert( !d_this.isNull() );
+      Node c = NodeManager::currentNM()->mkConst( Rational( s ) );
+      Node lit = NodeManager::currentNM()->mkNode( DT_SYGUS_BOUND, d_this, c );
+      lit = d->getValuation().ensureLiteral( lit );
+      
+      Trace("sygus-fair") << "******* Sygus : allocate size literal " << s << " for " << d_this << " : " << lit << std::endl;
+      Trace("cegqi-engine") << "******* Sygus : allocate size literal " << s << " for " << d_this << std::endl;
+      Node lem = NodeManager::currentNM()->mkNode( kind::OR, lit, lit.negate() );
+      Trace("sygus-dec") << "Sygus : Fairness split : " << lem << std::endl;
+      lemmas.push_back( lem );
+      d->getOutputChannel().requirePhase( lit, true );
+    
+      d_lits[s] = lit;
+      return lit;
+    }else{
+      return it->second;
     }
+  }else{
+    return Node::null();
   }
-  TypeNode tn = arg.getType();
-  return true;
 }
 
-void SygusSymBreak::collectTesters( Node tst, std::map< Node, std::vector< Node > >& testers_u, std::vector< Node >& testers, std::map< Node, bool >& irrlv_tst ) {
-  if( irrlv_tst.find( tst )==irrlv_tst.end() ){
-    testers.push_back( tst );
-    std::map< Node, std::vector< Node > >::iterator it = testers_u.find( tst[0] );
-    if( it!=testers_u.end() ){
-      for( unsigned i=0; i<it->second.size(); i++ ){
-        collectTesters( it->second[i], testers_u, testers, irrlv_tst );
-      }
+Node SygusSymBreakNew::getNextDecisionRequest( unsigned& priority, std::vector< Node >& lemmas ) {
+  Trace("sygus-dec-debug") << "SygusSymBreakNew: Get next decision " << std::endl;
+  for( std::map< Node, Node >::iterator it = d_anchor_to_active_guard.begin(); it != d_anchor_to_active_guard.end(); ++it ){
+    if( getGuardStatus( it->second )==0 ){
+      Trace("sygus-dec") << "Sygus : Decide next on active guard : " << it->second << "..." << std::endl;
+      priority = 1;
+      return it->second;
+    }
+  }
+  for( std::map< Node, SearchSizeInfo * >::iterator it = d_szinfo.begin(); it != d_szinfo.end(); ++it ){
+    SearchSizeInfo * s = it->second;
+    std::vector< Node > new_lit;
+    Node c_lit = s->getCurrentFairnessLiteral( d_td, lemmas );
+    Assert( !c_lit.isNull() );
+    int gstatus = getGuardStatus( c_lit );
+    if( gstatus==-1 ){
+      s->incrementCurrentLiteral();
+      c_lit = s->getCurrentFairnessLiteral( d_td, lemmas );
+      Assert( !c_lit.isNull() );
+      Trace("sygus-dec") << "Sygus : Decide on next lit : " << c_lit << "..." << std::endl;
+      priority = 1;
+      return c_lit;
+    }else if( gstatus==0 ){
+      Trace("sygus-dec") << "Sygus : Decide on current lit : " << c_lit << "..." << std::endl;
+      priority = 1;
+      return c_lit;
     }
   }
+  return Node::null();
 }
 
-void SygusSymBreak::collectSubterms( Node n, Node tst_curr, std::map< Node, std::vector< Node > >& testers_u, std::map< Node, std::vector< Node > >& nodes ) {
-  if( !d_tds->isVar( n ) ){
-    nodes[n].push_back( tst_curr );
-    for( unsigned i=0; i<testers_u[tst_curr[0]].size(); i++ ){
-      collectSubterms( n[i], testers_u[tst_curr[0]][i], testers_u, nodes );
+int SygusSymBreakNew::getGuardStatus( Node g ) {
+  bool value;
+  if( d_td->getValuation().hasSatValue( g, value ) ) {
+    if( value ){
+      return 1;
+    }else{
+      return -1;
     }
+  }else{
+    return 0;
   }
 }
+
index 739cbb5e0597cc95c7bbc5136d997b700da3fc23..7d88447eae21e3a10e634c2b46745ac651cedc25 100644 (file)
@@ -16,8 +16,8 @@
 
 #include "cvc4_private.h"
 
-#ifndef __CVC4__THEORY__DATATYPES__DATATYPES_SYGUS_H
-#define __CVC4__THEORY__DATATYPES__DATATYPES_SYGUS_H
+#ifndef __CVC4__THEORY__DATATYPES__DATATYPES_SYGUS_NEW_H
+#define __CVC4__THEORY__DATATYPES__DATATYPES_SYGUS_NEW_H
 
 #include <iostream>
 #include <map>
 #include "context/context.h"
 #include "context/cdchunk_list.h"
 #include "context/cdhashmap.h"
+#include "context/cdhashset.h"
 #include "context/cdo.h"
+#include "theory/quantifiers/term_database.h"
 
 namespace CVC4 {
 namespace theory {
-namespace quantifiers {
-  class TermDbSygus;
-} /* namespace quantifiers */
-
 namespace datatypes {
 
-class SygusSplit
+class TheoryDatatypes;
+
+class SygusSplitNew
 {
 private:
   quantifiers::TermDbSygus * d_tds;
   std::map< Node, std::vector< Node > > d_splits;
-  std::map< TypeNode, std::vector< bool > > d_sygus_nred;
-  std::map< TypeNode, std::map< int, std::map< int, std::vector< bool > > > > d_sygus_pc_nred;
-  std::map< TypeNode, std::map< int, std::map< int, std::vector< int > > > > d_sygus_pc_arg_pos;
-  std::map< TypeNode, TypeNode > d_register;  //stores sygus type
-  // type to (rewritten) to original
-  std::map< TypeNode, std::map< Node, Node > > d_gen_terms;
-  std::map< TypeNode, std::map< Node, Node > > d_gen_terms_inactive;
-  std::map< TypeNode, std::map< Node, bool > > d_gen_redundant;
-private:
-  /** register sygus type */
-  void registerSygusType( TypeNode tn );
-  /** register sygus operator */
-  void registerSygusTypeConstructorArg( TypeNode tnn, const Datatype& dt, TypeNode tnnp, const Datatype& pdt, int csIndex, int sIndex );
-  /** consider sygus split */
-  bool considerSygusSplitKind( const Datatype& dt, const Datatype& pdt, TypeNode tn, TypeNode tnp, Kind k, Kind parent, int arg );
-  bool considerSygusSplitConst( const Datatype& dt, const Datatype& pdt, TypeNode tn, TypeNode tnp, Node c, Kind parent, int arg );
-  /** get first occurrence */
-  int getFirstArgOccurrence( const DatatypeConstructor& c, const Datatype& dt );
-  /** is arg datatype */
-  bool isArgDatatype( const DatatypeConstructor& c, int i, const Datatype& dt );
-  /** is type match */
-  bool isTypeMatch( const DatatypeConstructor& c1, const DatatypeConstructor& c2 );
-private:
-  // generic cache
-  bool isGenericRedundant( TypeNode tn, Node g, bool active = true );
 public:
-  SygusSplit( quantifiers::TermDbSygus * tds ) : d_tds( tds ){}
-  ~SygusSplit(){}
+  SygusSplitNew( quantifiers::TermDbSygus * tds ) : d_tds( tds ){}
+  virtual ~SygusSplitNew(){}
   /** get sygus splits */
   void getSygusSplits( Node n, const Datatype& dt, std::vector< Node >& splits, std::vector< Node >& lemmas );
+  static Node getSygusSplit( quantifiers::TermDbSygus * tds, Node n, const Datatype& dt );
 };
 
-
-
-
-class SygusSymBreak
+class SygusSymBreakNew
 {
 private:
+  TheoryDatatypes * d_td;
   quantifiers::TermDbSygus * d_tds;
   context::Context* d_context;
-  class ProgSearch {
-    typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap;
-    typedef context::CDHashMap< Node, int, NodeHashFunction > IntMap;
-    typedef context::CDHashMap< int, int > IntIntMap;
-  private:
-    SygusSymBreak * d_parent;
-    Node getCandidateProgramAtDepth( int depth, Node prog, int curr_depth, Node parent, std::map< TypeNode, int >& var_count,
-                                     std::vector< Node >& testers, std::map< Node, std::vector< Node > >& testers_u );
-    bool processProgramDepth( int depth );
-    bool processSubprograms( Node n, int depth, int odepth );
-    bool assignTester( int tindex, Node n, int depth );
+  typedef context::CDHashMap< Node, int, NodeHashFunction > IntMap;
+  typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap;
+  typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
+  typedef context::CDChunkList<Node> NodeList;
+  typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
+  IntMap d_testers;
+  IntMap d_is_const;
+  NodeMap d_testers_exp;
+  NodeSet d_active_terms;
+  IntMap d_currTermSize;
+  Node d_zero;
+private:
+  std::map< Node, Node > d_term_to_anchor;
+  std::map< Node, Node > d_term_to_anchor_root;
+  std::map< Node, unsigned > d_term_to_depth;
+  std::map< Node, bool > d_is_top_level;
+  void registerTerm( Node n, std::vector< Node >& lemmas );
+  bool computeTopLevel( TypeNode tn, Node n );
+private:
+  //list of all terms encountered in search at depth
+  class SearchCache {
   public:
-    ProgSearch( SygusSymBreak * p, Node a, context::Context* c ) :
-      d_parent( p ), d_anchor( a ), d_testers( c ), d_watched_terms( c ), d_watched_count( c ), d_prog_depth( c, 0 ) {
-      d_anchor_type = d_anchor.getType();
+    SearchCache(){}
+    std::map< TypeNode, std::map< unsigned, std::vector< Node > > > d_search_terms;
+    std::map< TypeNode, std::map< unsigned, std::vector< Node > > > d_sb_lemmas;
+    // search values
+    std::map< TypeNode, std::map< Node, Node > > d_search_val;
+    std::map< TypeNode, std::map< Node, unsigned > > d_search_val_sz;
+    std::map< TypeNode, std::map< Node, Node > > d_search_val_b;
+    std::map< Node, bool > d_search_val_proc;
+  };
+  // anchor -> cache
+  std::map< Node, SearchCache > d_cache;
+  Node d_null;
+  void assertTesterInternal( int tindex, TNode n, Node exp, std::vector< Node >& lemmas );
+  // register search term
+  void registerSearchTerm( TypeNode tn, unsigned d, Node n, bool topLevel, std::vector< Node >& lemmas );
+  bool registerSearchValue( Node a, Node n, Node nv, unsigned d, std::vector< Node >& lemmas );
+  void registerSymBreakLemma( TypeNode tn, Node lem, unsigned sz, Node e, std::vector< Node >& lemmas );
+  void addSymBreakLemmasFor( TypeNode tn, Node t, unsigned d, Node e, std::vector< Node >& lemmas );
+  void addSymBreakLemmasFor( TypeNode tn, Node t, unsigned d, std::vector< Node >& lemmas );
+  void addSymBreakLemma( TypeNode tn, Node lem, TNode x, TNode n, unsigned lem_sz, unsigned n_depth, std::vector< Node >& lemmas );
+private:
+  std::map< Node, Node > d_rlv_cond;
+  Node getRelevancyCondition( Node n );
+private:
+  std::map< TypeNode, std::map< int, std::map< unsigned, Node > > > d_simple_sb_pred;
+  std::map< TypeNode, Node > d_free_var;
+  // user-context dependent if sygus-incremental
+  std::map< Node, unsigned > d_simple_proc;
+  //get simple symmetry breaking predicate
+  Node getSimpleSymBreakPred( TypeNode tn, int tindex, unsigned depth );
+  TNode getFreeVar( TypeNode tn );
+  Node getTermOrderPredicate( Node n1, Node n2 );
+private:
+  //should be user-context dependent if sygus in incremental mode
+  std::map< Node, bool > d_register_st;
+  void registerSizeTerm( Node e, std::vector< Node >& lemmas );
+  class SearchSizeInfo {
+  public:
+    SearchSizeInfo( Node t, context::Context* c ) : d_this( t ), d_curr_search_size(0), d_curr_lit( c, 0 ) {}
+    Node d_this;
+    std::map< unsigned, Node > d_search_size_exp;
+    std::map< unsigned, bool > d_search_size;
+    unsigned d_curr_search_size;
+    Node d_sygus_measure_term;
+    Node d_sygus_measure_term_active;
+    std::vector< Node > d_anchors;
+    Node getOrMkSygusMeasureTerm( std::vector< Node >& lemmas );
+    Node getOrMkSygusActiveMeasureTerm( std::vector< Node >& lemmas );
+  public:
+    /** current cardinality */
+    context::CDO< unsigned > d_curr_lit;
+    std::map< unsigned, Node > d_lits;
+    Node getFairnessLiteral( unsigned s, TheoryDatatypes * d, std::vector< Node >& lemmas );
+    Node getCurrentFairnessLiteral( TheoryDatatypes * d, std::vector< Node >& lemmas ) { 
+      return getFairnessLiteral( d_curr_lit.get(), d, lemmas ); 
     }
-    ~ProgSearch(){}
-    Node d_anchor;
-    NodeMap d_testers;
-    IntMap d_watched_terms;
-    IntIntMap d_watched_count;
-    TypeNode d_anchor_type;
-    context::CDO<int> d_prog_depth;
-    void addTester( int tindex, Node n, Node exp );
+    /** increment current term size */
+    void incrementCurrentLiteral() { d_curr_lit.set( d_curr_lit.get() + 1 ); }
   };
-  std::map< Node, ProgSearch * > d_prog_search;
-  std::map< TypeNode, std::map< Node, Node > > d_normalized_to_orig;
-  std::map< TypeNode, std::map< Node, bool > > d_redundant;
-  std::map< TypeNode, std::map< Node, int > > d_normalized_to_term_size;
-  std::map< TypeNode, std::map< Node, std::vector< Node > > > d_lemmas_reported;
-  //which testers to include in the lemma
-  std::map< TypeNode, std::map< Node, std::vector< bool > > > d_lemma_inc_tst;
-  //additional equalities to include in the lemma
-  std::map< TypeNode, std::map< Node, std::vector< std::pair< int, int > > > > d_lemma_inc_eq;
-  //other equalities
-  std::map< TypeNode, Node > d_anchor_var;
-  std::map< TypeNode, std::map< Node, std::vector< Node > > > d_lemma_inc_eq_gr[2];
+  std::map< Node, SearchSizeInfo * > d_szinfo;
+  std::map< Node, Node > d_anchor_to_measure_term;
+  std::map< Node, Node > d_anchor_to_active_guard;
+  Node d_generic_measure_term;
+  void incrementCurrentSearchSize( Node m, std::vector< Node >& lemmas );
+  void notifySearchSize( Node m, unsigned s, Node exp, std::vector< Node >& lemmas );
+  void registerMeasureTerm( Node m );
+  unsigned getSearchSizeFor( Node n );
+  unsigned getSearchSizeForAnchor( Node n );
+  unsigned getSearchSizeForMeasureTerm( Node m );
+private:
+  unsigned processSelectorChain( Node n, std::map< TypeNode, Node >& top_level, 
+                                 std::map< Node, unsigned >& tdepth, std::vector< Node >& lemmas );
+  bool debugTesters( Node n, Node vn, int ind, std::vector< Node >& lemmas );
+  Node getCurrentTemplate( Node n, std::map< TypeNode, int >& var_count );
+  int getGuardStatus( Node g );
 private:
-  Node getAnchor( Node n );
-  bool processCurrentProgram( Node a, TypeNode at, int depth, Node prog,
-                              std::vector< Node >& testers, std::map< Node, std::vector< Node > >& testers_u,
-                              std::map< TypeNode, int >& var_count );
-  bool processConstantArg( TypeNode tnp, const Datatype & pdt, int pc, Kind k, int i, Node arg, std::map< unsigned, bool >& rlv );
-  void collectTesters( Node tst, std::map< Node, std::vector< Node > >& testers_u, std::vector< Node >& testers, std::map< Node, bool >& irrlv_tst );
-  void collectSubterms( Node n, Node tst_curr, std::map< Node, std::vector< Node > >& testers_u, std::map< Node, std::vector< Node > >& nodes );
-  bool isSeparation( Node rep_prog, Node tst_curr, std::map< Node, std::vector< Node > >& testers_u, std::vector< Node >& rlv_testers );
-  Node getSeparationTemplate( TypeNode tn, Node rep_prog, Node anc_var, int& status );
+  void assertIsConst( Node n, bool polarity, std::vector< Node >& lemmas );
 public:
-  SygusSymBreak( quantifiers::TermDbSygus * tds, context::Context* c );
-  ~SygusSymBreak();
+  SygusSymBreakNew( TheoryDatatypes * td, quantifiers::TermDbSygus * tds, context::Context* c );
+  ~SygusSymBreakNew();
   /** add tester */
-  void addTester( int tindex, Node n, Node exp );
-  /** lemmas we have generated */
-  std::vector< Node > d_lemmas;
+  void assertTester( int tindex, TNode n, Node exp, std::vector< Node >& lemmas );
+  void assertFact( Node n, bool polarity, std::vector< Node >& lemmas );
+  void preRegisterTerm( TNode n, std::vector< Node >& lemmas  );
+  void check( std::vector< Node >& lemmas );
+  void getPossibleCons( const Datatype& dt, TypeNode tn, std::vector< bool >& pcons );
+public:
+  Node getNextDecisionRequest( unsigned& priority, std::vector< Node >& lemmas );
 };
 
 }
@@ -143,3 +173,4 @@ public:
 }
 
 #endif
+
index efee5e8764b3db4ff6e391e3034231784474cc29..3ce416b403dee002e8f3b9363a5f87e6a5d8898c 100644 (file)
@@ -7,7 +7,7 @@
 theory THEORY_DATATYPES ::CVC4::theory::datatypes::TheoryDatatypes "theory/datatypes/theory_datatypes.h"
 typechecker "theory/datatypes/theory_datatypes_type_rules.h"
 
-properties check presolve parametric propagate
+properties check presolve parametric propagate getNextDecisionRequest
 
 rewriter ::CVC4::theory::datatypes::DatatypesRewriter "theory/datatypes/datatypes_rewriter.h"
 
@@ -106,6 +106,18 @@ operator DT_SIZE 1 "datatypes size"
 typerule DT_SIZE ::CVC4::theory::datatypes::DtSizeTypeRule
 
 operator DT_HEIGHT_BOUND 2 "datatypes height bound"
-typerule DT_HEIGHT_BOUND ::CVC4::theory::datatypes::DtHeightBoundTypeRule
+typerule DT_HEIGHT_BOUND ::CVC4::theory::datatypes::DtBoundTypeRule
+
+operator DT_SIZE_BOUND 2 "datatypes height bound"
+typerule DT_SIZE_BOUND ::CVC4::theory::datatypes::DtBoundTypeRule
+
+operator DT_SYGUS_BOUND 2 "datatypes sygus bound"
+typerule DT_SYGUS_BOUND ::CVC4::theory::datatypes::DtSygusBoundTypeRule
+
+operator DT_SYGUS_TERM_ORDER 2 "datatypes sygus term order"
+typerule DT_SYGUS_TERM_ORDER ::CVC4::theory::datatypes::DtSygusPredTypeRule
+
+operator DT_SYGUS_IS_CONST 1 "datatypes sygus is constant"
+typerule DT_SYGUS_IS_CONST ::CVC4::theory::datatypes::DtSygusPredTypeRule
 
 endtheory
index 22065e082a50d7cf445241e235bfd62d590fe49b..874f49f1e5381463d116b83cd9f99f441e29de46 100644 (file)
@@ -31,6 +31,7 @@
 #include "theory/type_enumerator.h"
 #include "theory/valuation.h"
 #include "options/theory_options.h"
+#include "options/quantifiers_options.h"
 
 using namespace std;
 using namespace CVC4::kind;
@@ -62,12 +63,15 @@ TheoryDatatypes::TheoryDatatypes(Context* c, UserContext* u, OutputChannel& out,
   // The kinds we are treating as function application in congruence
   d_equalityEngine.addFunctionKind(kind::APPLY_CONSTRUCTOR);
   d_equalityEngine.addFunctionKind(kind::APPLY_SELECTOR_TOTAL);
-  d_equalityEngine.addFunctionKind(kind::DT_SIZE);
-  d_equalityEngine.addFunctionKind(kind::DT_HEIGHT_BOUND);
+  //d_equalityEngine.addFunctionKind(kind::DT_SIZE);
+  //d_equalityEngine.addFunctionKind(kind::DT_HEIGHT_BOUND);
+  //d_equalityEngine.addFunctionKind(kind::DT_SYGUS_TERM_ORDER);
+  //d_equalityEngine.addFunctionKind(kind::DT_SYGUS_IS_CONST);
   d_equalityEngine.addFunctionKind(kind::APPLY_TESTER);
   //d_equalityEngine.addFunctionKind(kind::APPLY_UF);
 
   d_true = NodeManager::currentNM()->mkConst( true );
+  d_zero = NodeManager::currentNM()->mkConst( Rational(0) );
   d_dtfCounter = 0;
 
   d_sygus_split = NULL;
@@ -134,11 +138,19 @@ TNode TheoryDatatypes::getEqcConstructor( TNode r ) {
 }
 
 void TheoryDatatypes::check(Effort e) {
-  if (done() && !fullEffort(e)) {
+  if (done() && e<EFFORT_FULL) {
     return;
   }
   Assert( d_pending.empty() && d_pending_merge.empty() );
   d_addedLemma = false;
+  
+  if( e == EFFORT_LAST_CALL ){
+    Assert( d_sygus_sym_break );
+    std::vector< Node > lemmas;
+    d_sygus_sym_break->check( lemmas );
+    doSendLemmas( lemmas );
+    return;
+  }
 
   TimerStat::CodeTimer checkTimer(d_checkTime);
 
@@ -273,7 +285,7 @@ void TheoryDatatypes::check(Effort e) {
                 consIndex = fconsIndex!=-1 ? fconsIndex : consIndex;
               }
 
-              if( needSplit && consIndex!=-1 ) {
+              if( needSplit ) {
                 if( dt.getNumConstructors()==1 ){
                   //this may not be necessary?
                   //if only one constructor, then this term must be this constructor
@@ -283,7 +295,8 @@ void TheoryDatatypes::check(Effort e) {
                   Trace("datatypes-infer") << "DtInfer : 1-cons (full) : " << t << std::endl;
                   d_infer.push_back( t );
                 }else{
-                  if( options::dtBinarySplit() ){
+                  Assert( consIndex!=-1 || dt.isSygus() );
+                  if( options::dtBinarySplit() && consIndex!=-1 ){
                     Node test = DatatypesRewriter::mkTester( n, consIndex, dt );
                     Trace("dt-split") << "*************Split for possible constructor " << dt[consIndex] << " for " << n << endl;
                     test = Rewriter::rewrite( test );
@@ -296,8 +309,10 @@ void TheoryDatatypes::check(Effort e) {
                     Trace("dt-split") << "*************Split for constructors on " << n <<  endl;
                     std::vector< Node > children;
                     if( dt.isSygus() && d_sygus_split ){
+                      Trace("dt-sygus") << "DtSygus : split on " << n << std::endl;
                       std::vector< Node > lemmas;
                       d_sygus_split->getSygusSplits( n, dt, children, lemmas );
+                      Trace("dt-sygus") << "Finished compute split, returned " << lemmas.size() << " lemmas." << std::endl;
                       for( unsigned i=0; i<lemmas.size(); i++ ){
                         Trace("dt-lemma-sygus") << "Dt sygus lemma : " << lemmas[i] << std::endl;
                         doSendLemma( lemmas[i] );
@@ -360,6 +375,10 @@ void TheoryDatatypes::check(Effort e) {
   }
 }
 
+bool TheoryDatatypes::needsCheckLastEffort() {
+  return d_sygus_sym_break!=NULL;
+}
+
 void TheoryDatatypes::flushPendingFacts(){
   doPendingMerges();
   //pending lemmas: used infrequently, only for definitional lemmas
@@ -403,9 +422,7 @@ void TheoryDatatypes::flushPendingFacts(){
         }
       }
       Trace("dt-lemma") << "Datatypes lemma : " << lem << std::endl;
-      if( doSendLemma( lem ) ){
-        d_addedLemma = true;
-      }
+      doSendLemma( lem );
     }else{
       assertFact( fact, exp );
       d_addedFact = true;
@@ -435,12 +452,22 @@ bool TheoryDatatypes::doSendLemma( Node lem ) {
     Trace("dt-lemma-send") << "TheoryDatatypes::doSendLemma : " << lem << std::endl;
     d_lemmas_produced_c[lem] = true;
     d_out->lemma( lem );
+    d_addedLemma = true;
     return true;
   }else{
     return false;
   }
 }
-
+bool TheoryDatatypes::doSendLemmas( std::vector< Node >& lemmas ){
+  bool ret = false;
+  for( unsigned i=0; i<lemmas.size(); i++ ){
+    bool cret = doSendLemma( lemmas[i] );
+    ret = ret || cret;
+  }
+  lemmas.clear();
+  return ret;
+}
+        
 void TheoryDatatypes::assertFact( Node fact, Node exp ){
   Assert( d_pending_merge.empty() );
   Trace("datatypes-debug") << "TheoryDatatypes::assertFact : " << fact << std::endl;
@@ -452,6 +479,12 @@ void TheoryDatatypes::assertFact( Node fact, Node exp ){
     d_equalityEngine.assertPredicate( atom, polarity, exp );
   }
   doPendingMerges();
+  // could be sygus-specific
+  if( d_sygus_sym_break ){
+    std::vector< Node > lemmas;
+    d_sygus_sym_break->assertFact( atom, polarity, lemmas );
+    doSendLemmas( lemmas );
+  }
   //add to tester if applicable
   Node t_arg;
   int tindex = DatatypesRewriter::isTester( atom, t_arg );
@@ -461,36 +494,22 @@ void TheoryDatatypes::assertFact( Node fact, Node exp ){
     EqcInfo* eqc = getOrMakeEqcInfo( rep, true );
     addTester( tindex, fact, eqc, rep, t_arg );
     Trace("dt-tester") << "Done assert tester." << std::endl;
+    //do pending merges
+    doPendingMerges();
+    Trace("dt-tester") << "Done pending merges." << std::endl;
     if( !d_conflict && polarity ){
       if( d_sygus_sym_break ){
+        Trace("dt-sygus") << "Assert tester to sygus : " << atom << std::endl;
         //Assert( !d_sygus_util->d_conflict );
-        Trace("dt-tester") << "Assert tester to sygus : " << atom << std::endl;
-        d_sygus_sym_break->addTester( tindex, t_arg, atom );
-        Trace("dt-tester") << "Done assert tester to sygus." << std::endl;
-        for( unsigned i=0; i<d_sygus_sym_break->d_lemmas.size(); i++ ){
-          Trace("dt-lemma-sygus") << "Sygus symmetry breaking lemma : " << d_sygus_sym_break->d_lemmas[i] << std::endl;
-          doSendLemma( d_sygus_sym_break->d_lemmas[i] );
-        }
-        d_sygus_sym_break->d_lemmas.clear();
-        /*
-        if( d_sygus_util->d_conflict ){
-          //d_conflict = true;
-          if( !d_sygus_util->d_conflictNode.isNull() ){
-            std::vector< TNode > assumptions;
-            explain( d_sygus_util->d_conflictNode, assumptions );
-            d_conflictNode = mkAnd( assumptions );
-            Trace("dt-conflict") << "CONFLICT: sygus symmetry breaking conflict : " << d_conflictNode << std::endl;
-            d_out->conflict( d_conflictNode );
-          }
-          return;
-        }
-        */
+        std::vector< Node > lemmas;
+        d_sygus_sym_break->assertTester( tindex, t_arg, atom, lemmas );
+        Trace("dt-sygus") << "Done assert tester to sygus." << std::endl;
+        doSendLemmas( lemmas );
       }
     }
   }else{
     Trace("dt-tester-debug") << "Assert (non-tester) : " << atom << std::endl;
   }
-  doPendingMerges();
   Trace("datatypes-debug") << "TheoryDatatypes::assertFact : finished " << fact << std::endl;
 }
 
@@ -507,8 +526,16 @@ void TheoryDatatypes::preRegisterTerm(TNode n) {
     d_equalityEngine.addTriggerPredicate(n);
     break;
   default:
+    if( n.getKind()==kind::DT_SIZE ){
+      d_out->lemma( NodeManager::currentNM()->mkNode( LEQ, d_zero, n ) );
+    }
     // Function applications/predicates
     d_equalityEngine.addTerm(n);
+    if( d_sygus_sym_break ){
+      std::vector< Node > lemmas;
+      d_sygus_sym_break->preRegisterTerm(n, lemmas);
+      doSendLemmas( lemmas );
+    }
     //d_equalityEngine.addTriggerTerm(n, THEORY_DATATYPES);
     break;
   }
@@ -519,23 +546,35 @@ void TheoryDatatypes::finishInit() {
   if( getQuantifiersEngine() && options::ceGuidedInst() ){
     quantifiers::TermDbSygus * tds = getQuantifiersEngine()->getTermDatabaseSygus();
     Assert( tds!=NULL );
-    d_sygus_split = new SygusSplit( tds );
-    d_sygus_sym_break = new SygusSymBreak( tds, getSatContext() );
+    d_sygus_split = new SygusSplitNew( tds );
+    d_sygus_sym_break = new SygusSymBreakNew( this, tds, getSatContext() );
   }
 }
 
 Node TheoryDatatypes::expandDefinition(LogicRequest &logicRequest, Node n) {
   switch( n.getKind() ){
   case kind::APPLY_SELECTOR: {
+    Trace("dt-expand") << "Dt Expand definition : " << n << std::endl;
     Node selector = n.getOperator();
     Expr selectorExpr = selector.toExpr();
-    Node sel = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, Node::fromExpr( selectorExpr ), n[0] );
+    // APPLY_SELECTOR always applies to an external selector, cindexOf is legal here
+    size_t cindex = Datatype::cindexOf(selectorExpr);
+    const Datatype& dt = Datatype::datatypeOf(selectorExpr);
+    const DatatypeConstructor& c = dt[cindex];
+    Node selector_use;
+    TypeNode ndt = n[0].getType();
+    if( options::dtSharedSelectors() ){
+      size_t selectorIndex = Datatype::indexOf(selectorExpr);
+      Trace("dt-expand") << "...selector index = " << selectorIndex << std::endl;
+      Assert( selectorIndex<c.getNumArgs() );
+      selector_use = Node::fromExpr( c.getSelectorInternal( ndt.toType(), selectorIndex ) );
+    }else{
+      selector_use = selector;
+    }
+    Node sel = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, selector_use, n[0] );
     if( options::dtRewriteErrorSel() ){
       return sel;
     }else{
-      size_t selectorIndex = Datatype::cindexOf(selectorExpr);
-      const Datatype& dt = Datatype::datatypeOf(selectorExpr);
-      const DatatypeConstructor& c = dt[selectorIndex];
       Expr tester = c.getTester();
       Node tst = NodeManager::currentNM()->mkNode( kind::APPLY_TESTER, Node::fromExpr( tester ), n[0] );
       tst = Rewriter::rewrite( tst );
@@ -543,7 +582,6 @@ Node TheoryDatatypes::expandDefinition(LogicRequest &logicRequest, Node n) {
       if( tst==d_true ){
         n_ret = sel;
       }else{
-        TypeNode ndt = n[0].getType();
         mkExpDefSkolem( selector, ndt, n.getType() );
         Node sk = NodeManager::currentNM()->mkNode( kind::APPLY_UF, d_exp_def_skolem[ndt][ selector ], n[0]  );
         if( tst==NodeManager::currentNM()->mkConst( false ) ){
@@ -599,7 +637,7 @@ Node TheoryDatatypes::ppRewrite(TNode in) {
         b << in[1];
         Debug("tuprec") << "arg " << i << " gets updated to " << in[1] << std::endl;
       } else {
-        b << NodeManager::currentNM()->mkNode(kind::APPLY_SELECTOR_TOTAL, Node::fromExpr(dt[0][i].getSelector()), in[0]);
+        b << NodeManager::currentNM()->mkNode(kind::APPLY_SELECTOR_TOTAL, Node::fromExpr(dt[0].getSelectorInternal( t.toType(), i )), in[0]);
         Debug("tuprec") << "arg " << i << " copies " << b[b.getNumChildren() - 1] << std::endl;
       }
     }
@@ -965,7 +1003,8 @@ bool TheoryDatatypes::hasTester( Node n ) {
 }
 
 void TheoryDatatypes::getPossibleCons( EqcInfo* eqc, Node n, std::vector< bool >& pcons ){
-  const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype();
+  TypeNode tn = n.getType();
+  const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
   int lindex = getLabelIndex( eqc, n );
   pcons.resize( dt.getNumConstructors(), lindex==-1 );
   if( lindex!=-1 ){
@@ -982,17 +1021,10 @@ void TheoryDatatypes::getPossibleCons( EqcInfo* eqc, Node n, std::vector< bool >
         Assert( tindex!=-1 );
         pcons[ tindex ] = false;
       }
-    }
-  }
-}
-
-void TheoryDatatypes::getSelectorsForCons( Node r, std::map< int, bool >& sels ) {
-  NodeIntMap::iterator sel_i = d_selector_apps.find( r );
-  if( sel_i != d_selector_apps.end() ){
-    int n_sel = (*sel_i).second;
-    for( int j=0; j<n_sel; j++ ){
-      int sindex = Datatype::indexOf( d_selector_apps_data[r][j].getOperator().toExpr() );
-      sels[sindex] = true;
+      //further limit the possibilities based on grammar minimization
+      if( d_sygus_sym_break && dt.isSygus() ){
+        d_sygus_sym_break->getPossibleCons( dt, tn, pcons );
+      }
     }
   }
 }
@@ -1061,6 +1093,7 @@ void TheoryDatatypes::addTester( int ttindex, Node t, EqcInfo* eqc, Node n, Node
     NodeIntMap::iterator lbl_i = d_labels.find( n );
     Assert( lbl_i != d_labels.end() );
     int n_lbl = (*lbl_i).second;
+    std::map< int, bool > neg_testers;
     for( int i=0; i<n_lbl; i++ ){
       Node ti = d_labels_data[n][i];
       Assert( ti.getKind()==NOT );
@@ -1076,6 +1109,8 @@ void TheoryDatatypes::addTester( int ttindex, Node t, EqcInfo* eqc, Node n, Node
         }else{            //it is redundant
           return;
         }
+      }else{
+        neg_testers[jtindex] = true;
       }
     }
     if( !makeConflict ){
@@ -1093,11 +1128,21 @@ void TheoryDatatypes::addTester( int ttindex, Node t, EqcInfo* eqc, Node n, Node
       Debug("datatypes-labels") << "Labels at " << n_lbl << " / " << dt.getNumConstructors() << std::endl;
       if( tpolarity ){
         instantiate( eqc, n );
+        //TODO : and it is not the other testers FIXME
+        for( int i=0; i<(int)dt.getNumConstructors(); i++ ){
+          if( i!=ttindex && neg_testers.find( i )==neg_testers.end() ){
+            Assert( n.getKind()!=APPLY_CONSTRUCTOR );
+            Node infer = DatatypesRewriter::mkTester( n, i, dt ).negate();
+            Trace("datatypes-infer") << "DtInfer : neg label : " << infer << " by " << t << std::endl;
+            d_infer.push_back( infer );
+            d_infer_exp.push_back( t );
+          }
+        }
       }else{
         //check if we have reached the maximum number of testers
         // in this case, add the positive tester
         //this should not be done for sygus, since cases may be limited
-        if( n_lbl==(int)dt.getNumConstructors()-1 && !dt.isSygus() ){
+        if( n_lbl==(int)dt.getNumConstructors()-1 ){
           std::vector< bool > pcons;
           getPossibleCons( eqc, n, pcons );
           int testerIndex = -1;
@@ -1107,7 +1152,7 @@ void TheoryDatatypes::addTester( int ttindex, Node t, EqcInfo* eqc, Node n, Node
               break;
             }
           }
-          Assert( testerIndex!=-1 );
+          Assert( dt.isSygus() || testerIndex!=-1 );
           //we must explain why each term in the set of testers for this equivalence class is equal
           std::vector< Node > eq_terms;
           NodeBuilder<> nb(kind::AND);
@@ -1127,7 +1172,7 @@ void TheoryDatatypes::addTester( int ttindex, Node t, EqcInfo* eqc, Node n, Node
               }
             }
           }
-          Node t_concl = DatatypesRewriter::mkTester( t_arg, testerIndex, dt );
+          Node t_concl = testerIndex==-1 ? NodeManager::currentNM()->mkConst( false ) : DatatypesRewriter::mkTester( t_arg, testerIndex, dt );
           Node t_concl_exp = ( nb.getNumChildren() == 1 ) ? nb.getChild( 0 ) : nb;
           d_pending.push_back( t_concl );
           d_pending_exp[ t_concl ] = t_concl_exp;
@@ -1257,7 +1302,6 @@ Node TheoryDatatypes::removeUninterpretedConstants( Node n, std::map< Node, Node
   }
 } 
 
-
 void TheoryDatatypes::collapseSelector( Node s, Node c ) {
   Assert( c.getKind()==APPLY_CONSTRUCTOR );
   Trace("dt-collapse-sel") << "collapse selector : " << s << " " << c << std::endl;
@@ -1273,8 +1317,13 @@ void TheoryDatatypes::collapseSelector( Node s, Node c ) {
     use_s = s;
   }
   if( s.getKind()==kind::APPLY_SELECTOR_TOTAL ){
-    //Trace("dt-collapse-sel") << "Indices : " << Datatype::indexOf(c.getOperator().toExpr()) << " " << Datatype::cindexOf(s.getOperator().toExpr()) << std::endl;
-    wrong = Datatype::indexOf(c.getOperator().toExpr())!=Datatype::cindexOf(s.getOperator().toExpr());
+    Expr selectorExpr = s.getOperator().toExpr();
+    size_t constructorIndex = Datatype::indexOf(c.getOperator().toExpr());
+    const Datatype& dt = Datatype::datatypeOf(selectorExpr);
+    const DatatypeConstructor& dtc = dt[constructorIndex];
+    int selectorIndex = dtc.getSelectorIndexInternal( selectorExpr );
+    wrong = selectorIndex<0;
+    
     //if( wrong ){
     //  return;
     //}
@@ -1286,21 +1335,6 @@ void TheoryDatatypes::collapseSelector( Node s, Node c ) {
     if( options::dtRefIntro() ){
       use_s = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, s.getOperator(), use_s );
     }
-  }else{
-    if( s.getKind()==DT_SIZE ){
-      r = NodeManager::currentNM()->mkNode( DT_SIZE, c );
-      if( options::dtRefIntro() ){
-        use_s = NodeManager::currentNM()->mkNode( DT_SIZE, use_s );
-      }
-    }else if( s.getKind()==DT_HEIGHT_BOUND ){
-      r = NodeManager::currentNM()->mkNode( DT_HEIGHT_BOUND, c, s[1] );
-      if( options::dtRefIntro() ){
-        use_s = NodeManager::currentNM()->mkNode( DT_HEIGHT_BOUND, use_s, s[1] );
-      }
-      if( r==d_true ){
-        return;
-      }
-    }
   }
   if( !r.isNull() ){
     Node rr = Rewriter::rewrite( r );
@@ -1321,7 +1355,7 @@ void TheoryDatatypes::collapseSelector( Node s, Node c ) {
         eq_exp = c.eqNode( s[0] );
       }
       Trace("datatypes-infer") << "DtInfer : collapse sel";
-      Trace("datatypes-infer") << ( wrong ? " wrong" : "");
+      //Trace("datatypes-infer") << ( wrong ? " wrong" : "");
       Trace("datatypes-infer") << " : " << eq << " by " << eq_exp << std::endl;
       d_pending.push_back( eq );
       d_pending_exp[ eq ] = eq_exp;
@@ -1643,13 +1677,6 @@ void TheoryDatatypes::collectTerms( Node n ) {
         addSelector( n, eqc, rep );
 
         if( n.getKind() == DT_SIZE ){
-          Node conc = NodeManager::currentNM()->mkNode( LEQ, NodeManager::currentNM()->mkConst( Rational(0) ), n );
-          //must be non-negative
-          Trace("datatypes-infer") << "DtInfer : non-negative size : " << conc << std::endl;
-          //d_pending.push_back( conc );
-          //d_pending_exp[ conc ] = d_true;
-          //d_infer.push_back( conc );
-          d_pending_lem.push_back( conc );
   /*
           //add size = 0 lemma
           Node nn = n.eqNode( NodeManager::currentNM()->mkConst( Rational(0) ) );
@@ -1703,14 +1730,19 @@ Node TheoryDatatypes::getInstantiateCons( Node n, const Datatype& dt, int index
   if( it!=d_inst_map[n].end() ){
     return it->second;
   }else{
-    //add constructor to equivalence class
-    Node k = getTermSkolemFor( n );
-    Node n_ic = DatatypesRewriter::getInstCons( k, dt, index );
-    //Assert( n_ic==Rewriter::rewrite( n_ic ) );
-    n_ic = Rewriter::rewrite( n_ic );
-    collectTerms( n_ic );
-    d_equalityEngine.addTerm(n_ic);
-    Debug("dt-enum") << "Made instantiate cons " << n_ic << std::endl;
+    Node n_ic;
+    if( n.getKind()==APPLY_CONSTRUCTOR && n.getNumChildren()==0 ){
+      n_ic = n;
+    }else{
+      //add constructor to equivalence class
+      Node k = getTermSkolemFor( n );
+      n_ic = DatatypesRewriter::getInstCons( k, dt, index );
+      //Assert( n_ic==Rewriter::rewrite( n_ic ) );
+      n_ic = Rewriter::rewrite( n_ic );
+      collectTerms( n_ic );
+      d_equalityEngine.addTerm(n_ic);
+      Debug("dt-enum") << "Made instantiate cons " << n_ic << std::endl;
+    }
     d_inst_map[n][index] = n_ic;
     return n_ic;
   }
@@ -2258,6 +2290,17 @@ std::pair<bool, Node> TheoryDatatypes::entailmentCheck(TNode lit, const Entailme
   return make_pair(false, Node::null());
 }
 
+Node TheoryDatatypes::getNextDecisionRequest( unsigned& priority ) {
+  if( d_sygus_sym_break ){
+    std::vector< Node > lemmas;
+    Node ret = d_sygus_sym_break->getNextDecisionRequest( priority, lemmas );
+    doSendLemmas( lemmas );
+    return ret;
+  }else{
+    return Node::null();
+  }
+}
+
 } /* namepsace CVC4::theory::datatypes */
 } /* namepsace CVC4::theory */
 } /* namepsace CVC4 */
index ae299029a597163083dedb845896617c116cc048..fd79e3fdcfd2272cc397b6aa93e09d8ae73b6abe 100644 (file)
@@ -29,6 +29,7 @@
 #include "theory/theory.h"
 #include "theory/uf/equality_engine.h"
 #include "util/hash.h"
+#include "expr/attribute.h"
 
 namespace CVC4 {
 namespace theory {
@@ -54,6 +55,7 @@ private:
   NodeList d_infer;
   NodeList d_infer_exp;
   Node d_true;
+  Node d_zero;
   /** mkAnd */
   Node mkAnd( std::vector< TNode >& assumptions );
 private:
@@ -136,7 +138,6 @@ private:
   bool hasTester( Node n );
   /** get the possible constructors for n */
   void getPossibleCons( EqcInfo* eqc, Node n, std::vector< bool >& cons );
-  void getSelectorsForCons( Node r, std::map< int, bool >& sels );
   /** mkExpDefSkolem */
   void mkExpDefSkolem( Node sel, TypeNode dt, TypeNode rt );
   /** skolems for terms */
@@ -189,9 +190,6 @@ private:
   unsigned d_dtfCounter;
   /** expand definition skolem functions */
   std::map< TypeNode, std::map< Node, Node > > d_exp_def_skolem;
-  /** sygus utilities */
-  SygusSplit * d_sygus_split;
-  SygusSymBreak * d_sygus_sym_break;
   /** uninterpreted constant to variable map */
   std::map< Node, Node > d_uc_to_fresh_var;
 private:
@@ -212,6 +210,7 @@ private:
   void doPendingMerges();
   /** do send lemma */
   bool doSendLemma( Node lem );
+  bool doSendLemmas( std::vector< Node >& lem );
   /** get or make eqc info */
   EqcInfo* getOrMakeEqcInfo( TNode n, bool doMake = false );
 
@@ -257,6 +256,7 @@ public:
   void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
 
   void check(Effort e);
+  bool needsCheckLastEffort();
   void preRegisterTerm(TNode n);
   void finishInit();
   Node expandDefinition(LogicRequest &logicRequest, Node n);
@@ -320,6 +320,12 @@ private:
   bool areDisequal( TNode a, TNode b );
   bool areCareDisequal( TNode x, TNode y );
   TNode getRepresentative( TNode a );
+private:
+  /** sygus utilities */
+  SygusSplitNew * d_sygus_split;
+  SygusSymBreakNew * d_sygus_sym_break;
+public:
+  Node getNextDecisionRequest( unsigned& priority );
 };/* class TheoryDatatypes */
 
 }/* CVC4::theory::datatypes namespace */
index 2d7866b7bde8fe43a8f04a2b65f5d2085b93b12a..82d7274faed95b1a27d21d63f26028692b66ddcd 100644 (file)
@@ -311,7 +311,7 @@ class DtSizeTypeRule {
   }
 }; /* class DtSizeTypeRule */
 
-class DtHeightBoundTypeRule {
+class DtBoundTypeRule {
  public:
   inline static TypeNode computeType(NodeManager* nodeManager, TNode n,
                                      bool check) {
@@ -320,20 +320,64 @@ class DtHeightBoundTypeRule {
       if (!t.isDatatype()) {
         throw TypeCheckingExceptionPrivate(
             n,
-            "expecting datatype height bound term to have datatype argument.");
+            "expecting datatype bound term to have datatype argument.");
       }
       if (n[1].getKind() != kind::CONST_RATIONAL) {
         throw TypeCheckingExceptionPrivate(
-            n, "datatype height bound must be a constant");
+            n, "datatype bound must be a constant");
       }
       if (n[1].getConst<Rational>().getNumerator().sgn() == -1) {
         throw TypeCheckingExceptionPrivate(
-            n, "datatype height bound must be non-negative");
+            n, "datatype bound must be non-negative");
       }
     }
     return nodeManager->booleanType();
   }
-}; /* class DtHeightBoundTypeRule */
+}; /* class DtBoundTypeRule */
+
+class DtSygusBoundTypeRule {
+ public:
+  inline static TypeNode computeType(NodeManager* nodeManager, TNode n,
+                                     bool check) {
+    if (check) {
+      if (!n[0].getType().isDatatype()) {
+        throw TypeCheckingExceptionPrivate(
+            n, "datatype sygus bound takes a datatype");
+      }
+      if (n[1].getKind() != kind::CONST_RATIONAL) {
+        throw TypeCheckingExceptionPrivate(
+            n, "datatype sygus bound must be a constant");
+      }
+      if (n[1].getConst<Rational>().getNumerator().sgn() == -1) {
+        throw TypeCheckingExceptionPrivate(
+            n, "datatype sygus bound must be non-negative");
+      }
+    }
+    return nodeManager->booleanType();
+  }
+}; /* class DtSygusBoundTypeRule */
+
+
+class DtSygusPredTypeRule {
+ public:
+  inline static TypeNode computeType(NodeManager* nodeManager, TNode n,
+                                     bool check) {
+    if (check) {
+      TypeNode tn = n[0].getType();
+      if (!tn.isDatatype() || !((DatatypeType)tn.toType()).getDatatype().isSygus()) {
+        throw TypeCheckingExceptionPrivate(
+            n, "datatype sygus predicate expecting terms of sygus type");
+      }
+      for( unsigned i=0; i<n.getNumChildren(); i++ ){
+        if (tn!=n[i].getType()) {
+          throw TypeCheckingExceptionPrivate(
+              n, "datatype sygus predicate expecting two terms of the same type");
+        }
+      }
+    }
+    return nodeManager->booleanType();
+  }
+}; /* class DtSygusPredTypeRule */
 
 } /* CVC4::theory::datatypes namespace */
 } /* CVC4::theory namespace */
index 6920fc539b7b1750da1a89f4e0bea2d88ef073fe..903a729f531cd458592a5e316deb5f2de761c011 100644 (file)
@@ -778,7 +778,7 @@ Node BoundedIntegers::matchBoundVar( Node v, Node t, Node e ){
       if( e.getKind()==kind::APPLY_CONSTRUCTOR ){
         u = matchBoundVar( v, t[i], e[i] );
       }else{
-        Node se = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[index][i].getSelector() ), e );
+        Node se = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[index].getSelectorInternal( e.getType().toType(), i ) ), e );
         u = matchBoundVar( v, t[i], se );
       }
       if( !u.isNull() ){
index e82af63e49aa5fbcc74b1e737436e1f4730567ee..63e8aa365b930c682e5719cc905b481f646aed87 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "expr/datatype.h"
 #include "options/quantifiers_options.h"
+#include "options/datatypes_options.h"
 #include "smt/smt_statistics_registry.h"
 #include "theory/quantifiers/first_order_model.h"
 #include "theory/quantifiers/term_database.h"
@@ -32,19 +33,142 @@ namespace quantifiers {
 
 
 CegConjecture::CegConjecture( QuantifiersEngine * qe, context::Context* c )
-    : d_qe( qe ), d_curr_lit( c, 0 ) {
+    : d_qe( qe ) {
   d_refine_count = 0;
   d_ceg_si = new CegConjectureSingleInv( qe, this );
+  d_ceg_pbe = new CegConjecturePbe( qe, this );
 }
 
 CegConjecture::~CegConjecture() {
   delete d_ceg_si;
+  delete d_ceg_pbe;
+}
+
+Node CegConjecture::convertToEmbedding( Node n, std::map< Node, Node >& synth_fun_vars, std::map< Node, Node >& visited ){
+  std::map< Node, Node >::iterator it = visited.find( n );
+  if( it==visited.end() ){
+    Node ret = n;
+    
+    std::vector< Node > children;
+    bool childChanged = false;
+    bool madeOp = false;
+    Kind ret_k = n.getKind();
+    Node op;
+    if( n.getNumChildren()>0 ){
+      if( n.getKind()==kind::APPLY_UF ){
+        op = n.getOperator();
+      }
+    }else{
+      op = n;
+    }
+    // is it a synth function?
+    std::map< Node, Node >::iterator its = synth_fun_vars.find( op );
+    if( its!=synth_fun_vars.end() ){
+      Assert( its->second.getType().isDatatype() );
+      // make into evaluation function
+      const Datatype& dt = ((DatatypeType)its->second.getType().toType()).getDatatype();
+      Assert( dt.isSygus() );
+      children.push_back( Node::fromExpr( dt.getSygusEvaluationFunc() ) );
+      children.push_back( its->second );
+      madeOp = true;
+      childChanged = true;
+      ret_k = kind::APPLY_UF;
+    }
+    if( n.getNumChildren()>0 || childChanged ){
+      if( !madeOp ){
+        if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
+          children.push_back( n.getOperator() );
+        }
+      }
+      for( unsigned i=0; i<n.getNumChildren(); i++ ){
+        Node nc = convertToEmbedding( n[i], synth_fun_vars, visited ); 
+        childChanged = childChanged || nc!=n[i];
+        children.push_back( nc );
+      }
+      if( childChanged ){
+        ret = NodeManager::currentNM()->mkNode( ret_k, children );
+      }
+    }
+    visited[n] = ret;
+    return ret;
+  }else{
+    return it->second;
+  }
+}
+
+void CegConjecture::collectConstants( Node n, std::map< TypeNode, std::vector< Node > >& consts, std::map< Node, bool >& visited ) {
+  if( visited.find( n )==visited.end() ){
+    visited[n] = true;
+    if( n.isConst() ){
+      TypeNode tn = n.getType();
+      Node nc = n;
+      if( tn.isReal() ){
+        nc = NodeManager::currentNM()->mkConst( n.getConst<Rational>().abs() );
+      }
+      if( std::find( consts[tn].begin(), consts[tn].end(), nc )==consts[tn].end() ){
+        Trace("cegqi-debug") << "...consider const : " << nc << std::endl;
+        consts[tn].push_back( nc );
+      }
+    }
+    
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      collectConstants( n[i], consts, visited );
+    }
+  }
 }
 
 void CegConjecture::assign( Node q ) {
   Assert( d_quant.isNull() );
   Assert( q.getKind()==FORALL );
+  Trace("cegqi") << "CegConjecture : assign : " << q << std::endl;
   d_assert_quant = q;
+  std::map< TypeNode, std::vector< Node > > extra_cons;
+  
+  Trace("cegqi") << "CegConjecture : collect constants..." << std::endl;
+  if( options::sygusAddConstGrammar() ){
+    std::map< Node, bool > cvisited;
+    collectConstants( q[1], extra_cons, cvisited );
+  } 
+  
+  Trace("cegqi") << "CegConjecture : convert to deep embedding..." << std::endl;
+  //convert to deep embedding
+  std::vector< Node > qchildren;
+  std::map< Node, Node > visited;
+  std::map< Node, Node > synth_fun_vars;
+  std::vector< Node > ebvl;
+  for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+    Node v = q[0][i];
+    Node sf = v.getAttribute(SygusSynthFunAttribute());
+    Assert( !sf.isNull() );
+    Node sfvl = sf.getAttribute(SygusSynthFunVarListAttribute());
+    // sfvl may be null for constant synthesis functions
+    Trace("cegqi-debug") << "...sygus var list associated with " << sf << " is " << sfvl << std::endl;
+    TypeNode tn;
+    if( v.getType().isDatatype() && ((DatatypeType)v.getType().toType()).getDatatype().isSygus() ){
+      tn = v.getType();
+    }else{
+      // make the default grammar
+      std::stringstream ss;
+      ss << sf;
+      tn = d_qe->getTermDatabaseSygus()->mkSygusDefaultType( v.getType(), sfvl, ss.str(), extra_cons );
+    }
+    d_qe->getTermDatabaseSygus()->registerSygusType( tn );
+    // ev is the first-order variable corresponding to this synth fun
+    std::stringstream ss;
+    ss << "f" << sf;
+    Node ev = NodeManager::currentNM()->mkBoundVar( ss.str(), tn ); 
+    ebvl.push_back( ev );
+    synth_fun_vars[sf] = ev;
+    Trace("cegqi") << "...embedding synth fun : " << sf << " -> " << ev << std::endl;
+  }
+  qchildren.push_back( NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, ebvl ) );
+  qchildren.push_back( convertToEmbedding( q[1], synth_fun_vars, visited ) );
+  if( q.getNumChildren()==3 ){
+    qchildren.push_back( q[2] );
+  }
+  q = NodeManager::currentNM()->mkNode( kind::FORALL, qchildren );
+  Trace("cegqi") << "CegConjecture : converted to embedding : " << q << std::endl;
+
   //register with single invocation if applicable
   if( d_qe->getTermDatabase()->isQAttrSygus( d_assert_quant ) && options::cegqiSingleInvMode()!=CEGQI_SI_MODE_NONE ){
     d_ceg_si->initialize( q );
@@ -52,18 +176,44 @@ void CegConjecture::assign( Node q ) {
       //Node red_lem = NodeManager::currentNM()->mkNode( OR, q.negate(), d_cegqi_si->d_quant );
       //may have rewritten quantified formula (for invariant synthesis)
       q = d_ceg_si->d_quant;
+      Assert( q.getKind()==kind::FORALL );
     }
   }
+
   d_quant = q;
   Assert( d_candidates.empty() );
   std::vector< Node > vars;
   for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
     vars.push_back( q[0][i] );
-    d_candidates.push_back( NodeManager::currentNM()->mkSkolem( "e", q[0][i].getType() ) );
+    Node e = NodeManager::currentNM()->mkSkolem( "e", q[0][i].getType() );
+    d_candidates.push_back( e );
   }
   Trace("cegqi") << "Base quantified formula is : " << q << std::endl;
   //construct base instantiation
   d_base_inst = Rewriter::rewrite( d_qe->getInstantiation( q, vars, d_candidates ) );
+  
+  // register this term with sygus database
+  std::vector< Node > guarded_lemmas;
+  if( !isSingleInvocation() ){
+    if( options::sygusPbe() ){
+      d_ceg_pbe->initialize( d_base_inst, d_candidates, guarded_lemmas );
+    }
+    for( unsigned i=0; i<d_candidates.size(); i++ ){
+      Node e = d_candidates[i];
+      if( options::sygusPbe() ){
+        std::vector< std::vector< Node > > exs;
+        std::vector< Node > exos;
+        std::vector< Node > exts;
+        // use the PBE examples, regardless of the search algorith, since these help search space pruning
+        if( d_ceg_pbe->getPbeExamples( e, exs, exos, exts ) ){
+          d_qe->getTermDatabaseSygus()->registerPbeExamples( e, exs, exos, exts );
+        }
+      }else{
+        d_qe->getTermDatabaseSygus()->registerMeasuredTerm( e, e );
+      }
+    }
+  }
+  
   Trace("cegqi") << "Base instantiation is :      " << d_base_inst << std::endl;
   if( d_qe->getTermDatabase()->isQAttrSygus( d_assert_quant ) ){
     CegInstantiation::collectDisjuncts( d_base_inst, d_base_disj );
@@ -80,269 +230,50 @@ void CegConjecture::assign( Node q ) {
         }
       }
     }
-    if( options::sygusUnifCondSol() ){
-      // for each variable, determine whether we can do conditional counterexamples
-      for( unsigned i=0; i<d_candidates.size(); i++ ){
-        registerCandidateConditional( d_candidates[i] );
-      }
-    }
     d_syntax_guided = true;
   }else if( d_qe->getTermDatabase()->isQAttrSynthesis( d_assert_quant ) ){
     d_syntax_guided = false;
   }else{
     Assert( false );
   }
-}
-
-void CegConjecture::registerCandidateConditional( Node v ) {
-  TypeNode tn = v.getType();
-  bool type_valid = false;
-  bool success = false;
-  std::vector< TypeNode > unif_types;
-  if( tn.isDatatype() ){
-    const Datatype& dt = ((DatatypeType)tn.toType()).getDatatype();
-    if( dt.isSygus() ){
-      type_valid = true;
-      if( d_candidates.size()==1 ){  // conditional solutions for multiple function conjectures TODO?
-        for( unsigned r=0; r<2; r++ ){
-          for( unsigned j=0; j<dt.getNumConstructors(); j++ ){
-            Node op = Node::fromExpr( dt[j].getSygusOp() );
-            if( r==0 ){
-              if( op.getKind() == kind::BUILTIN ){
-                Kind sk = NodeManager::operatorToKind( op );
-                if( sk==kind::ITE ){
-                  // we can do unification
-                  success = true;
-                  d_cinfo[v].d_csol_op = Node::fromExpr( dt[j].getConstructor() );
-                  Assert( dt[j].getNumArgs()==3 );
-                  for( unsigned k=0; k<3; k++ ){
-                    unif_types.push_back( TypeNode::fromType( dt[j][k].getRangeType() ) );
-                  }
-                  break;
-                }
-              }
-            }else{
-              if( dt[j].getNumArgs()>=3 ){
-                // could be a defined ITE (this is a hack for ICFP benchmarks)
-                std::vector< Node > utchildren;
-                utchildren.push_back( Node::fromExpr( dt[j].getConstructor() ) );
-                std::vector< Node > sks;
-                for( unsigned k=0; k<dt[j].getNumArgs(); k++ ){
-                  Type t = dt[j][k].getRangeType();
-                  Node kv = NodeManager::currentNM()->mkSkolem( "ut", TypeNode::fromType( t ) );
-                  sks.push_back( kv );
-                  utchildren.push_back( kv );
-                }
-                Node ut = NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, utchildren );
-                std::vector< Node > echildren;
-                echildren.push_back( Node::fromExpr( dt.getSygusEvaluationFunc() ) );
-                echildren.push_back( ut );
-                Node sbvl = Node::fromExpr( dt.getSygusVarList() );
-                for( unsigned k=0; k<sbvl.getNumChildren(); k++ ){
-                  echildren.push_back( sbvl[k] );
-                }
-                Node eut = NodeManager::currentNM()->mkNode( kind::APPLY_UF, echildren );
-                Trace("sygus-unif-debug") << "Test evaluation of " << eut << "..." << std::endl;
-                eut = d_qe->getTermDatabaseSygus()->unfold( eut );
-                Trace("sygus-unif-debug") << "...got " << eut << std::endl;
-                if( eut.getKind()==kind::ITE ){
-                  success = true;
-                  std::vector< Node > vs;
-                  std::vector< Node > ss;
-                  std::map< Node, unsigned > templ_var_index;
-                  for( unsigned k=0; k<sks.size(); k++ ){
-                    echildren[1] = sks[k];
-                    Node esk = NodeManager::currentNM()->mkNode( kind::APPLY_UF, echildren );
-                    vs.push_back( esk );
-                    Node tvar = NodeManager::currentNM()->mkSkolem( "templ", esk.getType() );
-                    templ_var_index[tvar] = k;
-                    ss.push_back( tvar );
-                  }
-                  eut = eut.substitute( vs.begin(), vs.end(), ss.begin(), ss.end() );
-                  Trace("sygus-unif") << "Defined constructor " << j << ", base term is " << eut << std::endl;
-                  //success if we can find a injection from ITE args to sygus args
-                  std::map< unsigned, unsigned > templ_injection;
-                  for( unsigned k=0; k<3; k++ ){
-                    if( !inferIteTemplate( k, eut[k], templ_var_index, templ_injection ) ){
-                      Trace("sygus-unif") << "...failed to find injection (range)." << std::endl;
-                      success = false;
-                      break;
-                    }
-                    if( templ_injection.find( k )==templ_injection.end() ){
-                      Trace("sygus-unif") << "...failed to find injection (domain)." << std::endl;
-                      success = false;
-                      break;
-                    }
-                  }
-                  if( success ){
-                    d_cinfo[v].d_csol_op = Node::fromExpr( dt[j].getConstructor() );
-                    for( unsigned k=0; k<3; k++ ){
-                      Assert( templ_injection.find( k )!=templ_injection.end() );
-                      unsigned sk_index = templ_injection[k];
-                      unif_types.push_back( sks[sk_index].getType() );
-                      //also store the template information, if necessary
-                      Node teut = eut[k];
-                      if( !teut.isVar() ){
-                        d_cinfo[v].d_template[k] = teut;
-                        d_cinfo[v].d_template_arg[k] = ss[sk_index];
-                        Trace("sygus-unif") << "  Arg " << k << " : template : " << teut << ", arg " << ss[sk_index] << std::endl;
-                      }else{
-                        Assert( teut==ss[sk_index] );
-                      }
-                    }
-                  }
-                }
-              }
-            }
-          }
-          if( success ){
-            break;
-          }
-        }
-      }
-    }
-  }
-  //mark active
-  if( !success ){
-    d_cinfo[v].d_csol_status = -1;
-  }else{     
-    //make progress guard
-    Node pg = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "P", NodeManager::currentNM()->booleanType(), "Progress guard for conditional solution." ) );
-    Node pglem = NodeManager::currentNM()->mkNode( kind::OR, pg.negate(), pg );
-    Trace("cegqi-lemma") << "Cegqi::Lemma : progress split : " << pglem << std::endl;
-    d_qe->getOutputChannel().lemma( pglem );
-    d_qe->getOutputChannel().requirePhase( pg, true );
-              
-    Assert( unif_types.size()==3 ); 
-    d_cinfo[v].d_csol_cond = NodeManager::currentNM()->mkSkolem( "c", unif_types[0] );
-    for( unsigned k=0; k<2; k++ ){
-      d_cinfo[v].d_csol_var[k] = NodeManager::currentNM()->mkSkolem( "e", unif_types[k+1] );
-      // optimization : need not be an ITE if types are equivalent  TODO
-    }
-    d_cinfo[v].d_csol_progress_guard = pg;
-    Trace("sygus-unif") << "Can do synthesis unification for variable " << v << ", based on operator " << d_cinfo[v].d_csol_op << std::endl;
-  }
-  if( !type_valid ){
-    Assert( false );
-  }
-}
-
-bool CegConjecture::inferIteTemplate( unsigned k, Node n, std::map< Node, unsigned >& templ_var_index, std::map< unsigned, unsigned >& templ_injection ){
-  if( n.getNumChildren()==0 ){
-    std::map< Node, unsigned >::iterator itt = templ_var_index.find( n );
-    if( itt!=templ_var_index.end() ){
-      unsigned kk = itt->second;
-      std::map< unsigned, unsigned >::iterator itti = templ_injection.find( k );
-      if( itti==templ_injection.end() ){
-        templ_injection[k] = kk;
-      }else if( itti->second!=kk ){
-        return false;
-      }
-    }
-    return true;
-  }else{
-    for( unsigned i=0; i<n.getNumChildren(); i++ ){
-      if( !inferIteTemplate( k, n[i], templ_var_index, templ_injection ) ){
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-void CegConjecture::initializeGuard(){
-  if( isAssigned() ){
-    if( !d_syntax_guided ){
-      if( d_nsg_guard.isNull() ){
-        d_nsg_guard = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "G", NodeManager::currentNM()->booleanType() ) );
-        d_nsg_guard = d_qe->getValuation().ensureLiteral( d_nsg_guard );
-        AlwaysAssert( !d_nsg_guard.isNull() );
-        d_qe->getOutputChannel().requirePhase( d_nsg_guard, true );
-        //add immediate lemma
-        Node lem = NodeManager::currentNM()->mkNode( OR, d_nsg_guard.negate(), d_base_inst.negate() );
-        Trace("cegqi-lemma") << "Cegqi::Lemma : non-syntax-guided : " << lem << std::endl;
-        d_qe->getOutputChannel().lemma( lem );
-      }
-    }else if( d_ceg_si->d_si_guard.isNull() ){
-      std::vector< Node > lems;
-      d_ceg_si->getInitialSingleInvLemma( lems );
-      for( unsigned i=0; i<lems.size(); i++ ){
-        Trace("cegqi-lemma") << "Cegqi::Lemma : single invocation " << i << " : " << lems[i] << std::endl;
-        d_qe->getOutputChannel().lemma( lems[i] );
-        if( Trace.isOn("cegqi-debug") ){
-          Node rlem = Rewriter::rewrite( lems[i] );
-          Trace("cegqi-debug") << "...rewritten : " << rlem << std::endl;
-        }
+  
+  // initialize the guard
+  if( !d_syntax_guided ){
+    if( d_nsg_guard.isNull() ){
+      d_nsg_guard = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "G", NodeManager::currentNM()->booleanType() ) );
+      d_nsg_guard = d_qe->getValuation().ensureLiteral( d_nsg_guard );
+      AlwaysAssert( !d_nsg_guard.isNull() );
+      d_qe->getOutputChannel().requirePhase( d_nsg_guard, true );
+      // negated base as a guarded lemma
+      guarded_lemmas.push_back( d_base_inst.negate() );
+    }
+  }else if( d_ceg_si->d_si_guard.isNull() ){
+    std::vector< Node > lems;
+    d_ceg_si->getInitialSingleInvLemma( lems );
+    for( unsigned i=0; i<lems.size(); i++ ){
+      Trace("cegqi-lemma") << "Cegqi::Lemma : single invocation " << i << " : " << lems[i] << std::endl;
+      d_qe->getOutputChannel().lemma( lems[i] );
+      if( Trace.isOn("cegqi-debug") ){
+        Node rlem = Rewriter::rewrite( lems[i] );
+        Trace("cegqi-debug") << "...rewritten : " << rlem << std::endl;
       }
     }
-    Assert( !getGuard().isNull() );
   }
-}
-
-void CegConjecture::setMeasureTerm( Node mt ){ 
-  d_measure_term = mt;
-  d_active_measure_term = mt;
-}
-
-Node CegConjecture::getMeasureTermFactor( Node v ) {
-  Node ret;
-  if( getCegqiFairMode()==CEGQI_FAIR_DT_SIZE ){
-    if( v.getType().isDatatype() ){
-      ret = NodeManager::currentNM()->mkNode( DT_SIZE, v );
-    }
+  Assert( !getGuard().isNull() );
+  Node gneg = getGuard().negate();
+  for( unsigned i=0; i<guarded_lemmas.size(); i++ ){
+    Node lem = NodeManager::currentNM()->mkNode( OR, gneg, guarded_lemmas[i] );
+    Trace("cegqi-lemma") << "Cegqi::Lemma : initial (guarded) lemma : " << lem << std::endl;
+    d_qe->getOutputChannel().lemma( lem );
   }
-  //TODO
-  Assert( ret.isNull() || ret.getType().isInteger() );
-  return ret;
-}
-  
   
-Node CegConjecture::getFairnessLiteral( int i ) {
-  if( d_measure_term.isNull() ){
-    return Node::null();
-  }else{
-    std::map< int, Node >::iterator it = d_lits.find( i );
-    if( it==d_lits.end() ){
-      Trace("cegqi-engine") << "******* CEGQI : allocate size literal " << i << std::endl;
-      Node c = NodeManager::currentNM()->mkConst( Rational( i ) );
-      Node lit = NodeManager::currentNM()->mkNode( LEQ, d_measure_term, c );
-      lit = Rewriter::rewrite( lit );
-      d_lits[i] = lit;
-
-      Node lem = NodeManager::currentNM()->mkNode( kind::OR, lit, lit.negate() );
-      Trace("cegqi-lemma") << "Cegqi::Lemma : Fairness split : " << lem << std::endl;
-      d_qe->getOutputChannel().lemma( lem );
-      d_qe->getOutputChannel().requirePhase( lit, true );
-
-      if( getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED || getCegqiFairMode()==CEGQI_FAIR_DT_SIZE_PRED ){
-        //implies height bounds on each candidate variable
-        std::vector< Node > lem_c;
-        for( unsigned j=0; j<d_candidates.size(); j++ ){
-          if( getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED ){
-            lem_c.push_back( NodeManager::currentNM()->mkNode( DT_HEIGHT_BOUND, d_candidates[j], c ) );
-          }else{
-            //lem_c.push_back( NodeManager::currentNM()->mkNode( DT_SIZE_BOUND, d_candidates[j], c ) );
-          }
-        }
-        Node hlem = NodeManager::currentNM()->mkNode( OR, lit.negate(), lem_c.size()==1 ? lem_c[0] : NodeManager::currentNM()->mkNode( AND, lem_c ) );
-        Trace("cegqi-lemma") << "Cegqi::Lemma : Fairness expansion (pred) : " << hlem << std::endl;
-        d_qe->getOutputChannel().lemma( hlem );
-      }
-      return lit;
-    }else{
-      return it->second;
-    }
-  }
+  Trace("cegqi") << "...finished, single invocation = " << isSingleInvocation() << std::endl;
 }
 
 Node CegConjecture::getGuard() {
   return !d_syntax_guided ? d_nsg_guard : d_ceg_si->d_si_guard;
 }
 
-CegqiFairMode CegConjecture::getCegqiFairMode() {
-  return isSingleInvocation() ? CEGQI_FAIR_NONE : options::ceGuidedInstFair();
-}
-
 bool CegConjecture::isSingleInvocation() const {
   return d_ceg_si->isSingleInvocation();
 }
@@ -410,99 +341,21 @@ bool CegConjecture::needsRefinement() {
   return !d_ce_sk.empty();
 }
 
-void CegConjecture::getConditionalCandidateList( std::vector< Node >& clist, Node curr, bool reqAdd ){
-  Assert( options::sygusUnifCondSol() );
-  std::map< Node, CandidateInfo >::iterator it = d_cinfo.find( curr );
-  if( it!=d_cinfo.end() ){
-    if( !it->second.d_csol_cond.isNull() ){
-      if( it->second.d_csol_status!=-1 ){
-        int pstatus = getProgressStatus( curr );
-        if( pstatus!=-1 ){
-          Assert( it->second.d_csol_status==0 || it->second.d_csol_status==1 );
-          //interested in model value for condition and branched variables
-          clist.push_back( it->second.d_csol_cond );
-          //assume_flat_ITEs
-          clist.push_back( it->second.d_csol_var[it->second.d_csol_status] );
-          //conditionally get the other branch
-          getConditionalCandidateList( clist, it->second.d_csol_var[1-it->second.d_csol_status], false );
-          return;
-        }else{
-          // it is progress-inactive, will not be included
-        }
-      }
-      //otherwise, yet to expand branch
-      if( !reqAdd ){
-        // if we are not top-level, we can ignore this (it won't be part of solution)
-        return;
-      }
-    }else{
-      // a standard variable not handlable by unification
-    }
-    clist.push_back( curr );
-  }
-}
-
 void CegConjecture::getCandidateList( std::vector< Node >& clist, bool forceOrig ) {
-  if( options::sygusUnifCondSol() && !forceOrig ){
-    for( unsigned i=0; i<d_candidates.size(); i++ ){
-      getConditionalCandidateList( clist, d_candidates[i], true );
-    }
+  if( d_ceg_pbe->isPbe() && !forceOrig ){
+    //Assert( isGround() );
+    d_ceg_pbe->getCandidateList( d_candidates, clist );
   }else{
     clist.insert( clist.end(), d_candidates.begin(), d_candidates.end() );
   }
 }
 
-Node CegConjecture::constructConditionalCandidate( std::map< Node, Node >& cmv, Node curr ) {
-  Assert( options::sygusUnifCondSol() );
-  std::map< Node, Node >::iterator itc = cmv.find( curr );
-  if( itc!=cmv.end() ){
-    return itc->second;
-  }else{
-    std::map< Node, CandidateInfo >::iterator it = d_cinfo.find( curr );
-    if( it!=d_cinfo.end() ){
-      if( !it->second.d_csol_cond.isNull() ){
-        if( it->second.d_csol_status!=-1 ){
-          int pstatus = getProgressStatus( curr );
-          if( pstatus!=-1 ){
-            Assert( it->second.d_csol_status==0 || it->second.d_csol_status==1 );
-            Node v_curr = constructConditionalCandidate( cmv, it->second.d_csol_var[it->second.d_csol_status] );
-            Node v_next = constructConditionalCandidate( cmv, it->second.d_csol_var[1-it->second.d_csol_status] );
-            if( v_next.isNull() ){
-              // try taking current branch as a leaf
-              return v_curr;
-            }else{
-              Node v_cond = constructConditionalCandidate( cmv, it->second.d_csol_cond );
-              std::vector< Node > args;
-              args.push_back( it->second.d_csol_op );
-              args.push_back( v_cond );
-              args.push_back( it->second.d_csol_status==0 ? v_curr : v_next );
-              args.push_back( it->second.d_csol_status==0 ? v_next : v_curr );
-              return NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, args );
-            }
-          }
-        }
-      }
-    }
-  }
-  return Node::null();
-}
-
-bool CegConjecture::constructCandidates( std::vector< Node >& clist, std::vector< Node >& model_values, std::vector< Node >& candidate_values ) {
+bool CegConjecture::constructCandidates( std::vector< Node >& clist, std::vector< Node >& model_values, std::vector< Node >& candidate_values, 
+                                         std::vector< Node >& lems ) {
   Assert( clist.size()==model_values.size() );
-  if( options::sygusUnifCondSol() ){
-    std::map< Node, Node > cmv;
-    for( unsigned i=0; i<clist.size(); i++ ){
-      cmv[ clist[i] ] = model_values[i];
-    }
-    for( unsigned i=0; i<d_candidates.size(); i++ ){
-      Node n = constructConditionalCandidate( cmv, d_candidates[i] );
-      Trace("cegqi-candidate") << "...constructed conditional candidate " << n << " for " << d_candidates[i] << std::endl;
-      candidate_values.push_back( n );
-      if( n.isNull() ){
-        Assert( false ); //currently should never happen
-        return false;
-      }
-    }
+  if( d_ceg_pbe->isPbe() ){
+    //Assert( isGround() );
+    return d_ceg_pbe->constructCandidates( clist, model_values, d_candidates, candidate_values, lems );
   }else{
     Assert( model_values.size()==d_candidates.size() );
     candidate_values.insert( candidate_values.end(), model_values.begin(), model_values.end() );
@@ -515,175 +368,73 @@ void CegConjecture::doCegConjectureCheck(std::vector< Node >& lems, std::vector<
   getCandidateList( clist );
   std::vector< Node > c_model_values;
   Trace("cegqi-check") << "CegConjuncture : check, build candidates..." << std::endl;
-  if( constructCandidates( clist, model_values, c_model_values ) ){
-    Assert( c_model_values.size()==d_candidates.size() );
+  bool constructed_cand = constructCandidates( clist, model_values, c_model_values, lems );
+
+  //must get a counterexample to the value of the current candidate
+  Node inst;
+  if( constructed_cand ){
     if( Trace.isOn("cegqi-check")  ){
       Trace("cegqi-check") << "CegConjuncture : check candidate : " << std::endl;
       for( unsigned i=0; i<c_model_values.size(); i++ ){
         Trace("cegqi-check") << "  " << i << " : " << d_candidates[i] << " -> " << c_model_values[i] << std::endl;
       }
     }
-    //must get a counterexample to the value of the current candidate
-    Node inst = d_base_inst.substitute( d_candidates.begin(), d_candidates.end(), c_model_values.begin(), c_model_values.end() );
-    bool hasActiveConditionalNode = false;
-    if( options::sygusUnifCondSol() ){
-      //TODO
-      hasActiveConditionalNode = true;
-    }
-    //check whether we will run CEGIS on inner skolem variables
-    bool sk_refine = ( !isGround() || d_refine_count==0 || hasActiveConditionalNode );
-    if( sk_refine ){
-      Assert( d_ce_sk.empty() );
-      d_ce_sk.push_back( std::vector< Node >() );
+    Assert( c_model_values.size()==d_candidates.size() );
+    inst = d_base_inst.substitute( d_candidates.begin(), d_candidates.end(), c_model_values.begin(), c_model_values.end() );
+  }else{
+    inst = d_base_inst;
+  }
+  
+  //check whether we will run CEGIS on inner skolem variables
+  bool sk_refine = ( !isGround() || d_refine_count==0 ) && ( !d_ceg_pbe->isPbe() || constructed_cand );
+  if( sk_refine ){
+    Assert( d_ce_sk.empty() );
+    d_ce_sk.push_back( std::vector< Node >() );
+  }else{
+    if( !constructed_cand ){
+      return;
     }
-    std::vector< Node > ic;
-    ic.push_back( d_assert_quant.negate() );
-    std::vector< Node > d;
-    CegInstantiation::collectDisjuncts( inst, d );
-    Assert( d.size()==d_base_disj.size() );
-    //immediately skolemize inner existentials
-    for( unsigned i=0; i<d.size(); i++ ){
-      Node dr = Rewriter::rewrite( d[i] );
-      if( dr.getKind()==NOT && dr[0].getKind()==FORALL ){
+  }
+  
+  std::vector< Node > ic;
+  ic.push_back( d_assert_quant.negate() );
+  std::vector< Node > d;
+  CegInstantiation::collectDisjuncts( inst, d );
+  Assert( d.size()==d_base_disj.size() );
+  //immediately skolemize inner existentials
+  for( unsigned i=0; i<d.size(); i++ ){
+    Node dr = Rewriter::rewrite( d[i] );
+    if( dr.getKind()==NOT && dr[0].getKind()==FORALL ){
+      if( constructed_cand ){
         ic.push_back( d_qe->getTermDatabase()->getSkolemizedBody( dr[0] ).negate() );
-        if( sk_refine ){
-          d_ce_sk.back().push_back( dr[0] );
-        }
-      }else{
+      }
+      if( sk_refine ){
+        Assert( !isGround() );
+        d_ce_sk.back().push_back( dr[0] );
+      }
+    }else{
+      if( constructed_cand ){
         ic.push_back( dr );
-        if( sk_refine ){
-          d_ce_sk.back().push_back( Node::null() );
-        }
         if( !d_inner_vars_disj[i].empty() ){
           Trace("cegqi-debug") << "*** quantified disjunct : " << d[i] << " simplifies to " << dr << std::endl;
         }
       }
+      if( sk_refine ){
+        d_ce_sk.back().push_back( Node::null() );
+      }
     }
+  }
+  if( constructed_cand ){
     Node lem = NodeManager::currentNM()->mkNode( OR, ic );
     lem = Rewriter::rewrite( lem );
+    //eagerly unfold applications of evaluation function
+    if( options::sygusDirectEval() ){
+      Trace("cegqi-debug") << "pre-unfold counterexample : " << lem << std::endl;
+      std::map< Node, Node > visited_n;
+      lem = d_qe->getTermDatabaseSygus()->getEagerUnfold( lem, visited_n );
+    }
     lems.push_back( lem );
     recordInstantiation( c_model_values );
-  }else{
-    Assert( false );
-  }
-}
-
-Node CegConjecture::getActiveConditional( Node curr ) {
-  Assert( options::sygusUnifCondSol() );
-  std::map< Node, CandidateInfo >::iterator it = d_cinfo.find( curr );
-  Assert( it!=d_cinfo.end() );
-  if( !it->second.d_csol_cond.isNull() ){
-    if( it->second.d_csol_status==-1 ){
-      //yet to branch, this is the one
-      return curr;
-    }else{
-      int pstatus = getProgressStatus( curr );
-      if( pstatus==-1 ){
-        // it is progress-inactive
-        return curr;
-      }else{
-        Assert( it->second.d_csol_status==0 || it->second.d_csol_status==1 );
-        return getActiveConditional( it->second.d_csol_var[1-it->second.d_csol_status] );
-      }
-    }
-  }else{
-    //not a conditional
-    return curr;
-  }
-}
-
-void CegConjecture::getContextConditionalNodes( Node curr, Node x, std::vector< Node >& nodes ) {
-  if( curr!=x ){
-    std::map< Node, CandidateInfo >::iterator it = d_cinfo.find( curr );
-    if( !it->second.d_csol_cond.isNull() ){
-      if( it->second.d_csol_status!=-1 ){
-        nodes.push_back( curr );
-        getContextConditionalNodes( it->second.d_csol_var[1-it->second.d_csol_status], x, nodes );
-      }
-    }
-  }
-}
-
-Node CegConjecture::mkConditionalEvalNode( Node c, std::vector< Node >& args ) {
-  Assert( !c.isNull() );
-  std::vector< Node > condc;
-  //get evaluator
-  Assert( c.getType().isDatatype() );
-  const Datatype& cd = ((DatatypeType)c.getType().toType()).getDatatype();
-  Assert( cd.isSygus() );
-  condc.push_back( Node::fromExpr( cd.getSygusEvaluationFunc() ) );
-  condc.push_back( c );
-  for( unsigned a=0; a<args.size(); a++ ){
-    condc.push_back( args[a] );
-  }
-  return NodeManager::currentNM()->mkNode( kind::APPLY_UF, condc );
-}
-
-Node CegConjecture::mkConditionalNode( Node v, std::vector< Node >& args, unsigned eindex ) {
-  std::map< Node, CandidateInfo >::iterator it = d_cinfo.find( v );
-  if( it!=d_cinfo.end() ){
-    Assert( eindex<=2 );
-    Node en = eindex==0 ? it->second.d_csol_cond : it->second.d_csol_var[eindex-1];
-    if( !en.isNull() ){
-      Node ret = mkConditionalEvalNode( en, args );
-      //consider template
-      std::map< unsigned, Node >::iterator itt = it->second.d_template.find( eindex );
-      if( itt!=it->second.d_template.end() ){
-        Assert( it->second.d_template_arg.find( eindex )!=it->second.d_template_arg.end() );
-        TNode var = it->second.d_template_arg[eindex];
-        TNode subs = ret;
-        Node rret = itt->second.substitute( var, subs );
-        ret = rret;
-      }
-      return ret;
-    }
-  }
-  Assert( false );
-  return Node::null();
-}
-
-Node CegConjecture::mkConditional( Node v, std::vector< Node >& args, bool pol ) {
-  Node ret = mkConditionalNode( v, args, 0 );
-  if( !pol ){
-    ret = ret.negate();
-  }
-  return ret;
-}
-  
-Node CegConjecture::purifyConditionalEvaluations( Node n, std::map< Node, Node >& csol_active, std::map< Node, Node >& psubs, std::map< Node, Node >& visited ){
-  std::map< Node, Node >::iterator itv = visited.find( n );
-  if( itv!=visited.end() ){
-    return itv->second;
-  }else{
-    Node ret;
-    if( n.getKind()==APPLY_UF ){
-      std::map< Node, Node >::iterator itc = csol_active.find( n[0] );
-      if( itc!=csol_active.end() ){
-        //purify it with a variable
-        ret = NodeManager::currentNM()->mkSkolem( "y", n.getType(), "purification variable for sygus conditional solution" );
-        psubs[n] = ret;
-      }
-    }
-    if( ret.isNull() ){
-      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 = purifyConditionalEvaluations( n[i], csol_active, psubs, visited );
-          childChanged = childChanged || nc!=n[i];
-          children.push_back( nc );
-        }
-        if( childChanged ){
-          ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
-        }
-      }
-    }
-    visited[n] = ret;
-    return ret;
   }
 }
         
@@ -717,119 +468,9 @@ void CegConjecture::doCegConjectureRefine( std::vector< Node >& lems ){
     }
   }
   
-  
   std::map< Node, Node > csol_active;
   std::map< Node, std::vector< Node > > csol_ccond_nodes;
   std::map< Node, std::map< Node, bool > > csol_cpol;    
-  if( options::sygusUnifCondSol() ){
-    //previous non-ground conditional refinement lemmas must satisfy the current point
-    if( !isGround() ){
-      Trace("cegqi-refine") << "doCegConjectureRefine : check for new refinements of previous lemmas..." << std::endl;
-      for( unsigned i=0; i<d_refinement_lemmas_ngr.size(); i++ ){
-        Node prev_lem = d_refinement_lemmas_ngr[i];
-        prev_lem = prev_lem.substitute( sk_vars.begin(), sk_vars.end(), sk_subs.begin(), sk_subs.end() );
-        if( d_refinement_lemmas_reproc.find( prev_lem )==d_refinement_lemmas_reproc.end() ){
-          d_refinement_lemmas_reproc[prev_lem] = true;
-          //do auxiliary variable substitution
-          std::vector< Node > subs;
-          for( unsigned ii=0; ii<d_refinement_lemmas_aux_vars[i].size(); ii++ ){
-            subs.push_back( NodeManager::currentNM()->mkSkolem( "y", d_refinement_lemmas_aux_vars[i][ii].getType(), 
-                                                                "purification variable for non-ground sygus conditional solution" ) );
-          }
-          prev_lem = prev_lem.substitute( d_refinement_lemmas_aux_vars[i].begin(), d_refinement_lemmas_aux_vars[i].end(), subs.begin(), subs.end() );
-          prev_lem = Rewriter::rewrite( prev_lem );
-          Trace("sygus-unif") << "...previous conditional refinement lemma with new counterexample : " << prev_lem << std::endl;
-          lems.push_back( prev_lem );
-        }
-      }
-      if( !lems.empty() ){  
-        Trace("cegqi-refine") << "...added lemmas, abort further refinement." << std::endl;
-        d_ce_sk.clear();
-        return;
-      }
-    }
-    Trace("cegqi-refine") << "doCegConjectureRefine : conditional solution refinement, expand active conditional nodes" << std::endl;
-    std::vector< Node > new_active_measure_sum;
-    for( unsigned i=0; i<d_candidates.size(); i++ ){
-      Node v = d_candidates[i];
-      Node ac = getActiveConditional( v );
-      Assert( !ac.isNull() );
-      //compute the contextual conditions
-      getContextConditionalNodes( v, ac, csol_ccond_nodes[v] );
-      if( !csol_ccond_nodes[v].empty() ){
-        //it will be conditionally evaluated, this is a placeholder
-        csol_active[v] = Node::null();
-      }
-      Trace("sygus-unif") << "Active conditional for " << v << " is : " << ac << std::endl;
-      //if it is a conditional
-      bool is_active_conditional = false;
-      if( !d_cinfo[ac].d_csol_cond.isNull() ){
-        int pstatus = getProgressStatus( ac );
-        Assert( pstatus!=0 );
-        if( pstatus==-1 ){
-          //inject new progress point TODO?
-          Trace("sygus-unif") << "...progress status is " << pstatus << ", do not expand." << std::endl;
-          Assert( false );
-        }else{
-          is_active_conditional = true;
-          //expand this conditional
-          Trace("sygus-unif") << "****** For " << v << ", expanding an active conditional node : " << ac << std::endl;
-          d_cinfo[ac].d_csol_status = 0;  //TODO: prefer some branches more than others based on the grammar?
-          Trace("sygus-unif") << "...expanded to " << d_cinfo[ac].d_csol_op << "( ";
-          Trace("sygus-unif") << d_cinfo[ac].d_csol_cond << ", " << d_cinfo[ac].d_csol_var[0] << ", ";
-          Trace("sygus-unif") << d_cinfo[ac].d_csol_var[1] << " )" << std::endl;
-          registerCandidateConditional( d_cinfo[ac].d_csol_var[1-d_cinfo[ac].d_csol_status] );
-          //add to measure sum
-          Node acfc = getMeasureTermFactor( d_cinfo[ac].d_csol_cond );
-          if( !acfc.isNull() ){
-            new_active_measure_sum.push_back( acfc );
-          }
-          Node acfv = getMeasureTermFactor( d_cinfo[ac].d_csol_var[d_cinfo[ac].d_csol_status] );
-          if( !acfv.isNull() ){
-            new_active_measure_sum.push_back( acfv );
-          }
-          csol_active[v] = ac;
-        }
-      }
-      if( !is_active_conditional ){
-        Trace("sygus-unif") << "* For " << v << ", its active node " << ac << " is not a conditional node." << std::endl;
-        //if we have not already included this in the measure, do so
-        if( d_cinfo[ac].d_csol_status==-1 ){
-          Node acf = getMeasureTermFactor( ac );
-          if( !acf.isNull() ){
-            new_active_measure_sum.push_back( acf );
-          }
-          d_cinfo[ac].d_csol_status = 2;
-        }
-      }
-      if( !csol_ccond_nodes[v].empty() ){
-        Trace("sygus-unif") << "...it is nested under " << csol_ccond_nodes[v].size() << " other conditionals" << std::endl;
-      }
-    }
-    // must add to active measure
-    if( !new_active_measure_sum.empty() ){
-      Node mcsum = new_active_measure_sum.size()==1 ? new_active_measure_sum[0] : NodeManager::currentNM()->mkNode( kind::PLUS, new_active_measure_sum );
-      Node mclem = NodeManager::currentNM()->mkNode( kind::LEQ, mcsum, d_active_measure_term );
-      Trace("cegqi-lemma") << "Cegqi::Lemma : Measure component lemma : " << mclem << std::endl;
-      d_qe->getOutputChannel().lemma( mclem );
-      /*    
-      for( unsigned i=0; i<new_active_measure_sum.size(); i++ ){
-        Node mclem = NodeManager::currentNM()->mkNode( kind::LEQ, new_active_measure_sum[i], d_active_measure_term );
-        Trace("cegqi-lemma") << "Cegqi::Lemma : Measure component lemma : " << mclem << std::endl;
-        d_qe->getOutputChannel().lemma( mclem );
-      }
-      
-      Node new_active_measure = NodeManager::currentNM()->mkSkolem( "K", NodeManager::currentNM()->integerType() );
-      new_active_measure_sum.push_back( new_active_measure );
-      Node namlem = NodeManager::currentNM()->mkNode( kind::GEQ, new_active_measure, NodeManager::currentNM()->mkConst(Rational(0)));
-      Node ramlem = d_active_measure_term.eqNode( NodeManager::currentNM()->mkNode( kind::PLUS, new_active_measure_sum ) );
-      namlem = NodeManager::currentNM()->mkNode( kind::AND, ramlem, namlem );
-      Trace("cegqi-lemma") << "Cegqi::Lemma : Measure expansion : " << namlem << std::endl;
-      d_qe->getOutputChannel().lemma( namlem );
-      d_active_measure_term = new_active_measure;
-      */
-    }
-  }
   
   //for conditional evaluation
   std::map< Node, Node > psubs_visited;
@@ -855,14 +496,7 @@ void CegConjecture::doCegConjectureRefine( std::vector< Node >& lems ){
     }
     if( !c_disj.isNull() ){
       //compute the body, inst_cond
-      if( options::sygusUnifCondSol() ){
-        Trace("sygus-unif") << "Process " << c_disj << std::endl;
-        c_disj = purifyConditionalEvaluations( c_disj, csol_active, psubs, psubs_visited );
-        Trace("sygus-unif") << "Purified to : " << c_disj << std::endl;
-        Trace("sygus-unif") << "...now with " << psubs.size() << " definitions." << std::endl;
-      }else{
-        //standard CEGIS refinement : plug in values, assert that d_candidates must satisfy entire specification
-      }
+      //standard CEGIS refinement : plug in values, assert that d_candidates must satisfy entire specification
       lem_c.push_back( c_disj );
     }
   }
@@ -872,118 +506,10 @@ void CegConjecture::doCegConjectureRefine( std::vector< Node >& lems ){
   std::vector< Node > psubs_cond_conc;
   std::map< Node, std::vector< Node > > psubs_apply;
   std::vector< Node > paux_vars;
-  if( options::sygusUnifCondSol() ){
-    Trace("cegqi-refine") << "doCegConjectureRefine : add conditional assumptions for " << psubs.size() << " evaluations..." << std::endl;
-    for( std::map< Node, Node >::iterator itp = psubs.begin(); itp != psubs.end(); ++itp ){
-      Assert( csol_active.find( itp->first[0] )!=csol_active.end() );
-      paux_vars.push_back( itp->second );
-      std::vector< Node > args;
-      for( unsigned a=1; a<itp->first.getNumChildren(); a++ ){
-        args.push_back( itp->first[a] );
-      }
-      Node ac = csol_active[itp->first[0]];
-      Assert( d_cinfo.find( ac )!=d_cinfo.end() );
-      Node c = d_cinfo[ac].d_csol_cond;
-      psubs_apply[ c ].push_back( itp->first );
-      Trace("sygus-unif") << "   process assumption " << itp->first << " == " << itp->second << ", with current condition " << c;
-      Trace("sygus-unif") << ", and " << csol_ccond_nodes[itp->first[0]].size() << " context conditionals." << std::endl;
-      std::vector< Node> assm;
-      if( !c.isNull() ){
-        assm.push_back( mkConditional( ac, args, true ) );
-      }
-      for( unsigned j=0; j<csol_ccond_nodes[itp->first[0]].size(); j++ ){
-        Node acc = csol_ccond_nodes[itp->first[0]][j];
-        bool pol = ( d_cinfo[acc].d_csol_status==1 );
-        assm.push_back( mkConditional( acc, args, pol ) );
-      }
-      Assert( !assm.empty() );
-      Node c_ant = assm.size()==1 ? assm[0] : NodeManager::currentNM()->mkNode( kind::AND, assm );
-      psubs_cond_ant.push_back( c_ant );
-      // make the evaluation node
-      Node eret = mkConditionalNode( ac, args, d_cinfo[ac].d_csol_status+1 );
-      Node c_conc = eret.eqNode( itp->second );
-      psubs_cond_conc.push_back( c_conc );
-      Trace("sygus-unif") << "   ...made conditional correctness assumption : " << c_ant << " => " << c_conc << std::endl;
-    }
-  }else{
-    Assert( psubs.empty() );
-  }
+  Assert( psubs.empty() );
   
   Node base_lem = lem_c.size()==1 ? lem_c[0] : NodeManager::currentNM()->mkNode( AND, lem_c );
   
-  if( options::sygusUnifCondSol() ){
-    Trace("sygus-unif-debug") << "We have base lemma : " << base_lem << std::endl;
-    //progress lemmas
-    Trace("cegqi-refine") << "doCegConjectureRefine : add progress lemmas..." << std::endl;
-    std::map< Node, bool > cprocessed;
-    for( std::map< Node, Node >::iterator itc = csol_active.begin(); itc !=csol_active.end(); ++itc ){
-      Node x = itc->first;
-      Node ac = itc->second;
-      Assert( d_cinfo.find( ac )!=d_cinfo.end() );
-      Node c = d_cinfo[ac].d_csol_cond;    
-      if( !c.isNull() ){
-        Trace("sygus-unif") << "  process conditional " << c << " for " << x << ", which was applied " << psubs_apply[c].size() << " times." << std::endl;
-        //make the progress point
-        Assert( x.getType().isDatatype() );
-        const Datatype& dx = ((DatatypeType)x.getType().toType()).getDatatype();
-        Node sbvl = Node::fromExpr( dx.getSygusVarList() );
-        std::vector< Node > prgr_pt;
-        for( unsigned a=0; a<sbvl.getNumChildren(); a++ ){
-          prgr_pt.push_back( NodeManager::currentNM()->mkSkolem( "kp", sbvl[a].getType(), "progress point for sygus conditional" ) );
-        }
-        Node pdlem;    
-        if( !psubs_apply[c].empty() ){
-          std::vector< Node > prgr_domain_d;
-          for( unsigned j=0; j<psubs_apply[c].size(); j++ ){
-            std::vector< Node > prgr_domain;
-            for( unsigned a=1; a<psubs_apply[c][j].getNumChildren(); a++ ){
-              Assert( a<=prgr_pt.size() );
-              prgr_domain.push_back( prgr_pt[a-1].eqNode( psubs_apply[c][j][a] ) );
-            }
-            if( !prgr_domain.empty() ){
-              //the point is in the domain of this function application
-              Node pdc = prgr_domain.size()==1 ? prgr_domain[0] : NodeManager::currentNM()->mkNode( AND, prgr_domain );
-              prgr_domain_d.push_back( pdc );
-            }
-          }
-          if( !prgr_domain_d.empty() ){
-            //the progress point is in the domain of some function application
-            pdlem = prgr_domain_d.size()==1 ? prgr_domain_d[0] : NodeManager::currentNM()->mkNode( OR, prgr_domain_d );
-            pdlem = pdlem.substitute( sk_vars.begin(), sk_vars.end(), sk_subs.begin(), sk_subs.end() );
-            Trace("sygus-unif") << "Progress domain point lemma is " << pdlem << std::endl;
-            lems.push_back( pdlem );
-          }
-        }
-        //the condition holds for the point, if this is an active condition
-        Node cplem = mkConditional( ac, prgr_pt );
-        if( !csol_ccond_nodes[x].empty() ){
-          std::vector< Node > prgr_conj;
-          prgr_conj.push_back( cplem );
-          // ...and not for its context
-          for( unsigned j=0; j<csol_ccond_nodes[x].size(); j++ ){
-            Node acc = csol_ccond_nodes[x][j];
-            bool pol = ( d_cinfo[acc].d_csol_status==1 );
-            prgr_conj.push_back( mkConditional( acc, prgr_pt, pol ) );
-          }
-          cplem = NodeManager::currentNM()->mkNode( kind::AND, prgr_conj );
-        }
-        Assert( !d_cinfo[x].d_csol_progress_guard.isNull() );
-        cplem = NodeManager::currentNM()->mkNode( kind::OR, d_cinfo[x].d_csol_progress_guard.negate(), cplem );
-        Trace("sygus-unif") << "Progress lemma is " << cplem << std::endl;
-        lems.push_back( cplem );
-      }
-    }
-    /*
-    if( !prgr_conj.empty() ){
-      Node prgr_lem = prgr_conj.size()==1 ? prgr_conj[0] : NodeManager::currentNM()->mkNode( kind::AND, prgr_conj );
-      prgr_lem = prgr_lem.substitute( sk_vars.begin(), sk_vars.end(), sk_subs.begin(), sk_subs.end() );
-      prgr_lem = NodeManager::currentNM()->mkNode( OR, getGuard().negate(), prgr_lem );
-      Trace("sygus-unif") << "Progress lemma is " << prgr_lem << std::endl;
-      lems.push_back( prgr_lem );
-    }
-    */
-  }
-  
   Trace("cegqi-refine") << "doCegConjectureRefine : construct and finalize lemmas..." << std::endl;
   
   Node lem = base_lem;
@@ -992,37 +518,8 @@ void CegConjecture::doCegConjectureRefine( std::vector< Node >& lems ){
   base_lem = Rewriter::rewrite( base_lem );
   d_refinement_lemmas_base.push_back( base_lem );
   
-  if( options::sygusUnifCondSol() ){
-    //add the conditional evaluation
-    if( !psubs_cond_ant.empty() ){
-      std::vector< Node > children;
-      children.push_back( base_lem );
-      std::vector< Node > pav;
-      std::vector< Node > pcv;
-      for( unsigned i=0; i<psubs_cond_ant.size(); i++ ){
-        children.push_back( NodeManager::currentNM()->mkNode( kind::OR, psubs_cond_ant[i].negate(), psubs_cond_conc[i] ) );
-        Node pa = psubs_cond_ant[i].substitute( sk_vars.begin(), sk_vars.end(), sk_subs.begin(), sk_subs.end() );
-        pav.push_back( pa );
-        Node pc = psubs_cond_conc[i].substitute( sk_vars.begin(), sk_vars.end(), sk_subs.begin(), sk_subs.end() );
-        pcv.push_back( pc );
-      }
-      d_refinement_lemmas_ceval_ant.push_back( pav );
-      d_refinement_lemmas_ceval_conc.push_back( pcv );
-      lem = NodeManager::currentNM()->mkNode( AND, children );
-    }
-  }
-
   lem = NodeManager::currentNM()->mkNode( OR, getGuard().negate(), lem );
   
-  if( options::sygusUnifCondSol() ){
-    if( !isGround() ){
-      //store the non-ground version of the lemma
-      lem = Rewriter::rewrite( lem );
-      d_refinement_lemmas_ngr.push_back( lem );
-      d_refinement_lemmas_aux_vars.push_back( paux_vars );
-    }
-  }
-  
   lem = lem.substitute( sk_vars.begin(), sk_vars.end(), sk_subs.begin(), sk_subs.end() );
   lem = Rewriter::rewrite( lem );
   d_refinement_lemmas.push_back( lem );
@@ -1071,62 +568,6 @@ void CegConjecture::debugPrint( const char * c ) {
   }
 }
 
-int CegConjecture::getProgressStatus( Node v ) {
-  Assert( options::sygusUnifCondSol() );
-  std::map< Node, CandidateInfo >::iterator it = d_cinfo.find( v );
-  if( it!=d_cinfo.end() ){
-    if( !it->second.d_csol_cond.isNull() ){
-      if( it->second.d_csol_status!=-1 ){
-        Node plit = it->second.d_csol_progress_guard;
-        Assert( !plit.isNull() );
-        //check SAT value of plit
-        bool value;
-        if( d_qe->getValuation().hasSatValue( plit, value ) ) {
-          if( !value ){
-            return -1;
-          }else{
-            return 1;
-          }
-        }else{
-          return 0;
-        }
-      }
-    }
-  }
-  return -2;
-}
-
-Node CegConjecture::getNextDecisionRequestConditional( Node v, unsigned& priority ) {
-  Assert( options::sygusUnifCondSol() );
-  int pstatus = getProgressStatus( v );
-  if( pstatus>=0 ){
-    std::map< Node, CandidateInfo >::iterator it = d_cinfo.find( v );
-    Assert( it!=d_cinfo.end() );
-    if( pstatus==1 ){
-      //active, recurse
-      Assert( it->second.d_csol_status==0 || it->second.d_csol_status==1 );
-      return getNextDecisionRequestConditional( it->second.d_csol_var[1-it->second.d_csol_status], priority );
-    }else if( pstatus==0 ){
-      //needs decision
-      priority = 1;
-      return it->second.d_csol_progress_guard;
-    }
-  }
-  return Node::null();
-}
-
-Node CegConjecture::getNextDecisionRequest( unsigned& priority ) {
-  if( options::sygusUnifCondSol() ){
-    for( unsigned i=0; i<d_candidates.size(); i++ ){
-      Node lit = getNextDecisionRequestConditional( d_candidates[i], priority );
-      if( !lit.isNull() ){
-        return lit;
-      }
-    }
-  }
-  return Node::null();
-}
-
 CegInstantiation::CegInstantiation( QuantifiersEngine * qe, context::Context* c ) : QuantifiersModule( qe ){
   d_conj = new CegConjecture( qe, qe->getSatContext() );
   d_last_inst_si = false;
@@ -1174,6 +615,7 @@ void CegInstantiation::check( Theory::Effort e, unsigned quant_e ) {
 }
 
 void CegInstantiation::preRegisterQuantifier( Node q ) {
+/*
   if( options::sygusDirectEval() ){
     if( q.getNumChildren()==3 && q[2].getKind()==INST_PATTERN_LIST && q[2][0].getKind()==INST_PATTERN ){  
       //check whether it is an evaluation axiom
@@ -1207,46 +649,15 @@ void CegInstantiation::preRegisterQuantifier( Node q ) {
         }
       }
     }
-  }  
+  } 
+  */ 
 }
 
 void CegInstantiation::registerQuantifier( Node q ) {
-  if( d_quantEngine->getOwner( q )==this && d_eval_axioms.find( q )==d_eval_axioms.end() ){
+  if( d_quantEngine->getOwner( q )==this ){ // && d_eval_axioms.find( q )==d_eval_axioms.end() ){
     if( !d_conj->isAssigned() ){
       Trace("cegqi") << "Register conjecture : " << q << std::endl;
       d_conj->assign( q );
-
-      //fairness
-      if( d_conj->getCegqiFairMode()!=CEGQI_FAIR_NONE ){
-        std::vector< Node > mc;
-        if( options::sygusUnifCondSol() || 
-            d_conj->getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED || d_conj->getCegqiFairMode()==CEGQI_FAIR_DT_SIZE_PRED  ){
-          //measure term is a fresh constant
-          mc.push_back( NodeManager::currentNM()->mkSkolem( "K", NodeManager::currentNM()->integerType() ) );
-        }else{
-          std::vector< Node > clist;
-          d_conj->getCandidateList( clist, true );
-          for( unsigned j=0; j<clist.size(); j++ ){
-            TypeNode tn = clist[j].getType();
-            if( d_conj->getCegqiFairMode()==CEGQI_FAIR_DT_SIZE ){
-              if( tn.isDatatype() ){
-                mc.push_back( NodeManager::currentNM()->mkNode( DT_SIZE, clist[j] ) );
-              }
-            }else if( d_conj->getCegqiFairMode()==CEGQI_FAIR_UF_DT_SIZE ){
-              registerMeasuredType( tn );
-              std::map< TypeNode, Node >::iterator it = d_uf_measure.find( tn );
-              if( it!=d_uf_measure.end() ){
-                mc.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, it->second, clist[j] ) );
-              }
-            }
-          }
-        }
-        if( !mc.empty() ){
-          Node mt = mc.size()==1 ? mc[0] : NodeManager::currentNM()->mkNode( PLUS, mc );
-          Trace("cegqi") << "Measure term is : " << mt << std::endl;
-          d_conj->setMeasureTerm( mt );
-        }
-      }
     }else{
       Assert( d_conj->d_quant==q );
     }
@@ -1259,10 +670,7 @@ void CegInstantiation::assertNode( Node n ) {
 }
 
 Node CegInstantiation::getNextDecisionRequest( unsigned& priority ) {
-  //enforce fairness
   if( d_conj->isAssigned() ){
-    d_conj->initializeGuard();
-    // 
     std::vector< Node > req_dec;
     const CegConjectureSingleInv* ceg_si = d_conj->getCegConjectureSingleInv();
     if( ! ceg_si->d_full_guard.isNull() ){
@@ -1283,32 +691,7 @@ Node CegInstantiation::getNextDecisionRequest( unsigned& priority ) {
         Trace("cegqi-debug2") << "CEGQI : " << req_dec[i] << " already has value " << value << std::endl;
       }
     }
-    
-    //ask the conjecture directly
-    Node lit = d_conj->getNextDecisionRequest( priority );
-    if( !lit.isNull() ){
-      return lit;
-    }
-
-    if( d_conj->getCegqiFairMode()!=CEGQI_FAIR_NONE ){
-      Node lit = d_conj->getFairnessLiteral( d_conj->getCurrentTermSize() );
-      bool value;
-      if( d_quantEngine->getValuation().hasSatValue( lit, value ) ) {
-        if( !value ){
-          d_conj->incrementCurrentTermSize();
-          lit = d_conj->getFairnessLiteral( d_conj->getCurrentTermSize() );
-          Trace("cegqi-debug") << "CEGQI : Decide on next lit : " << lit << "..." << std::endl;
-          priority = 1;
-          return lit;
-        }
-      }else{
-        Trace("cegqi-debug") << "CEGQI : Decide on current lit : " << lit << "..." << std::endl;
-        priority = 1;
-        return lit;
-      }
-    }
   }
-
   return Node::null();
 }
 
@@ -1319,11 +702,9 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
     conj->debugPrint("cegqi-engine-debug");
     Trace("cegqi-engine-debug") << std::endl;
   }
-  if( conj->getCegqiFairMode()!=CEGQI_FAIR_NONE ){
-    Trace("cegqi-engine") << "  * Current term size : " << conj->getCurrentTermSize() << std::endl;
-  }  
 
   if( !conj->needsRefinement() ){
+    Trace("cegqi-engine-debug") << "Do conjecture check..." << std::endl;
     if( conj->d_syntax_guided ){
       std::vector< Node > clems;
       conj->doCegConjectureSingleInvCheck( clems );
@@ -1345,25 +726,24 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
       if( options::sygusDirectEval() ){
         bool addedEvalLemmas = false;
         if( options::sygusCRefEval() ){
-          Trace("cegqi-debug") << "Do cref evaluation..." << std::endl;
+          Trace("cegqi-engine") << "  *** Do conjecture refinement evaluation..." << std::endl;
           // see if any refinement lemma is refuted by evaluation
           std::vector< Node > cre_lems;
           getCRefEvaluationLemmas( conj, clist, model_values, cre_lems );
           if( !cre_lems.empty() ){
-            Trace("cegqi-engine") << "  *** Do conjecture refinement evaluation..." << std::endl;
             for( unsigned j=0; j<cre_lems.size(); j++ ){
               Node lem = cre_lems[j];
-              Trace("cegqi-lemma") << "Cegqi::Lemma : cref evaluation : " << lem << std::endl;
               if( d_quantEngine->addLemma( lem ) ){
+                Trace("cegqi-lemma") << "Cegqi::Lemma : cref evaluation : " << lem << std::endl;
                 addedEvalLemmas = true;
               }
             }
             if( addedEvalLemmas ){
-              return;
+              //return;
             }
           }
         }
-        Trace("cegqi-debug") << "Do direct evaluation..." << std::endl;
+        Trace("cegqi-engine") << "  *** Do direct evaluation..." << std::endl;
         std::vector< Node > eager_terms; 
         std::vector< Node > eager_vals; 
         std::vector< Node > eager_exps;
@@ -1373,15 +753,14 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
         }
         Trace("cegqi-debug") << "...produced " << eager_terms.size()  << " eager evaluation lemmas." << std::endl;
         if( !eager_terms.empty() ){
-          Trace("cegqi-engine") << "  *** Do direct evaluation..." << std::endl;
           for( unsigned j=0; j<eager_terms.size(); j++ ){
             Node lem = NodeManager::currentNM()->mkNode( kind::OR, eager_exps[j].negate(), eager_terms[j].eqNode( eager_vals[j] ) );
             if( d_quantEngine->getTheoryEngine()->isTheoryEnabled(THEORY_BV) ){
               //FIXME: hack to incorporate hacks from BV for division by zero
               lem = bv::TheoryBVRewriter::eliminateBVSDiv( lem );
             }
-            Trace("cegqi-lemma") << "Cegqi::Lemma : evaluation : " << lem << std::endl;
             if( d_quantEngine->addLemma( lem ) ){
+              Trace("cegqi-lemma") << "Cegqi::Lemma : evaluation : " << lem << std::endl;
               addedEvalLemmas = true;
             }
           }
@@ -1390,25 +769,6 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
           return;
         }
       }
-      //check if we must apply fairness lemmas
-      if( conj->getCegqiFairMode()==CEGQI_FAIR_UF_DT_SIZE ){
-        Trace("cegqi-debug") << "Get measure lemmas..." << std::endl;
-        std::vector< Node > lems;
-        for( unsigned j=0; j<clist.size(); j++ ){
-          Trace("cegqi-debug") << "  get measure lemmas for " << clist[j] << " -> " << model_values[j] << std::endl;
-          getMeasureLemmas( clist[j], model_values[j], lems );
-        }
-        Trace("cegqi-debug") << "...produced " << lems.size() << " measure lemmas." << std::endl;
-        if( !lems.empty() ){
-          Trace("cegqi-engine") << "  *** Do measure refinement..." << std::endl;
-          for( unsigned j=0; j<lems.size(); j++ ){
-            Trace("cegqi-lemma") << "Cegqi::Lemma : measure : " << lems[j] << std::endl;
-            d_quantEngine->addLemma( lems[j] );
-          }
-          Trace("cegqi-engine") << "  ...refine size." << std::endl;
-          return;
-        }
-      }
       
       Trace("cegqi-engine") << "  *** Check candidate phase..." << std::endl;
       std::vector< Node > cclems;
@@ -1417,12 +777,6 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
       for( unsigned i=0; i<cclems.size(); i++ ){
         Node lem = cclems[i];
         d_last_inst_si = false;
-        //eagerly unfold applications of evaluation function
-        if( options::sygusDirectEval() ){
-          Trace("cegqi-eager") << "pre-unfold counterexample : " << lem << std::endl;
-          std::map< Node, Node > visited_n;
-          lem = getEagerUnfold( lem, visited_n );
-        }
         Trace("cegqi-lemma") << "Cegqi::Lemma : counterexample : " << lem << std::endl;
         if( d_quantEngine->addLemma( lem ) ){
           ++(d_statistics.d_cegqi_lemmas_ce);
@@ -1482,308 +836,68 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
 }
 
 void CegInstantiation::getCRefEvaluationLemmas( CegConjecture * conj, std::vector< Node >& vs, std::vector< Node >& ms, std::vector< Node >& lems ) {
+  Trace("sygus-cref-eval") << "Cref eval : conjecture has " << conj->getNumRefinementLemmas() << " refinement lemmas." << std::endl;
   if( conj->getNumRefinementLemmas()>0 ){
     Assert( vs.size()==ms.size() );
-    std::map< Node, Node > vtm;
-    for( unsigned i=0; i<vs.size(); i++ ){
-      vtm[vs[i]] = ms[i];
-    }
-    /*
-    if( options::sygusUnifCondSol() ){
-      // first, check progress lemmas  TODO?
-      for( unsigned i=0; i<conj->getNumRefinementLemmas(); i++ ){
-        Node plem = conj->getConditionalProgressLemma( i );
-        std::vector< Node > pp;
-        conj->
-        std::map< Node, Node > visitedp;
-        std::map< Node, std::vector< Node > > expp;
-        conj->getModelValues
-      }
-    }
-    */
+
+    Node neg_guard = conj->getGuard().negate();
     for( unsigned i=0; i<conj->getNumRefinementLemmas(); i++ ){
       Node lem;
       std::map< Node, Node > visited;
       std::map< Node, std::vector< Node > > exp;
-      if( options::sygusUnifCondSol() ){
-        for( unsigned j=0; j<conj->getNumConditionalEvaluations( i ); j++ ){
-          std::map< Node, Node > visitedc;
-          std::map< Node, std::vector< Node > > expc;
-          Node ce = conj->getConditionalEvaluationAntec( i, j );
-          Node cee = crefEvaluate( ce, vtm, visitedc, expc );
-          Trace("sygus-cref-eval") << "Check conditional evaluation condition : " << ce << ", evaluates to " << cee << std::endl;
-          if( !cee.isNull() && cee==d_quantEngine->getTermDatabase()->d_true  ){
-            Node conc = conj->getConditionalEvaluationConc( i, j );
-            // the conditional holds, we will apply this as a substitution
-            for( unsigned r=0; r<2; r++ ){
-              if( conc[r].isVar() ){
-                Node v = conc[r];
-                Node c = conc[1-r];
-                Assert( exp.find( v )==exp.end() );
-                visited[v] = c;
-                //exp[v].insert( exp[v].end(), expc[ce].begin(), expc[ce].end() );
-                exp[v].push_back( ce );
-                Trace("sygus-cref-eval") << "   consider " << v << " -> " << c << " with expanation " << ce << std::endl;
-                break;
-              }
-            }
-          }
-        }
-        //if at least one conditional fires
-        if( !visited.empty() ){
-          lem = conj->getRefinementBaseLemma( i );
-        }
-      }else{
-        lem = conj->getRefinementBaseLemma( i );
-      }
+      lem = conj->getRefinementBaseLemma( i );
       if( !lem.isNull() ){
-        Trace("sygus-cref-eval") << "Check refinement lemma " << lem << " against current model." << std::endl;
-        Node elem = crefEvaluate( lem, vtm, visited, exp );
-        Trace("sygus-cref-eval") << "...evaluated to " << elem << ", exp size = " << exp[lem].size() << std::endl;
-        if( !elem.isNull() && elem==d_quantEngine->getTermDatabase()->d_false ){
-          elem = conj->getGuard().negate();
-          Node cre_lem;
-          if( !exp[lem].empty() ){
-            Node en = exp[lem].size()==1 ? exp[lem][0] : NodeManager::currentNM()->mkNode( kind::AND, exp[lem] );
-            cre_lem = NodeManager::currentNM()->mkNode( kind::OR, en.negate(), elem );
-          }else{
-            cre_lem = elem;
-          }
-          if( std::find( lems.begin(), lems.end(), cre_lem )==lems.end() ){
-            Trace("sygus-cref-eval") << "...produced lemma : " << cre_lem << std::endl;
-            lems.push_back( cre_lem );
+        std::vector< Node > lem_conj;
+        //break into conjunctions
+        if( lem.getKind()==kind::AND ){
+          for( unsigned i=0; i<lem.getNumChildren(); i++ ){
+            lem_conj.push_back( lem[i] );
           }
+        }else{
+          lem_conj.push_back( lem );
         }
-      }
-    }
-  }
-}
-
-Node CegInstantiation::crefEvaluate( Node n, std::map< Node, Node >& vtm, std::map< Node, Node >& visited, std::map< Node, std::vector< Node > >& exp ){
-  std::map< Node, Node >::iterator itv = visited.find( n );
-  Node ret;
-  std::vector< Node > exp_c;
-  if( itv!=visited.end() ){
-    if( !itv->second.isConst() ){
-      //we stored a partially evaluated node, actually evaluate the result now
-      ret = crefEvaluate( itv->second, vtm, visited, exp );
-      exp_c.push_back( itv->second );
-    }else{
-      return itv->second;
-    }
-  }else{
-    if( n.getKind()==kind::APPLY_UF ){
-      //it is an evaluation function
-      Trace("sygus-cref-eval-debug") << "Compute evaluation for : " << n << std::endl;
-      //unfold by one step 
-      Node nn = d_quantEngine->getTermDatabaseSygus()->unfold( n, vtm, exp[n] );
-      Trace("sygus-cref-eval-debug") << "...unfolded once to " << nn << std::endl;
-      Assert( nn!=n );
-      //it is the result of evaluating the unfolding
-      ret = crefEvaluate( nn, vtm, visited, exp );
-      //carry explanation
-      exp_c.push_back( nn );
-    }
-    if( ret.isNull() ){
-      if( n.getNumChildren()>0 ){
-        std::vector< Node > children;
-        bool childChanged = false;
-        if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
-          children.push_back( n.getOperator() );
-        }
-        for( unsigned i=0; i<n.getNumChildren(); i++ ){
-          Node nc = crefEvaluate( n[i], vtm, visited, exp );
-          childChanged = nc!=n[i] || childChanged;
-          children.push_back( nc );
-          //Boolean short circuiting
-          if( n.getKind()==kind::AND ){
-            if( nc==d_quantEngine->getTermDatabase()->d_false ){
-              ret = nc;
-              exp_c.clear();
-            }
-          }else if( n.getKind()==kind::OR ){
-            if( nc==d_quantEngine->getTermDatabase()->d_true ){
-              ret = nc;
-              exp_c.clear();
-            }
-          }else if( n.getKind()==kind::ITE && i==0 ){
-            int index = -1;
-            if( nc==d_quantEngine->getTermDatabase()->d_true ){
-              index = 1;
-            }else if( nc==d_quantEngine->getTermDatabase()->d_false ){
-              index = 2;
+        EvalSygusInvarianceTest vsit;
+        vsit.d_result = d_quantEngine->getTermDatabase()->d_false;
+        for( unsigned j=0; j<lem_conj.size(); j++ ){
+          Node lemc = lem_conj[j];
+          Trace("sygus-cref-eval") << "Check refinement lemma conjunct " << lemc << " against current model." << std::endl;
+          Trace("sygus-cref-eval2") << "Check refinement lemma conjunct " << lemc << " against current model." << std::endl;
+          Node cre_lem;
+          Node lemcs = lemc.substitute( vs.begin(), vs.end(), ms.begin(), ms.end() );
+          Trace("sygus-cref-eval2") << "...under substitution it is : " << lemcs << std::endl;
+          Node lemcsu = d_quantEngine->getTermDatabaseSygus()->evaluateWithUnfolding( lemcs, vsit.d_visited );
+          Trace("sygus-cref-eval2") << "...after unfolding is : " << lemcsu << std::endl;
+          if( lemcsu==d_quantEngine->getTermDatabase()->d_false ){
+            std::vector< Node > msu;
+            std::vector< Node > mexp;
+            msu.insert( msu.end(), ms.begin(), ms.end() );
+            for( unsigned k=0; k<vs.size(); k++ ){
+              vsit.d_var = vs[k];
+              vsit.d_update_nvn = msu[k];
+              msu[k] = vs[k];
+              // substitute for everything except this
+              vsit.d_conj = lemc.substitute( vs.begin(), vs.end(), msu.begin(), msu.end() );
+              // get minimal explanation for this
+              Trace("sygus-cref-eval2-debug") << "  compute min explain of : " << vs[k] << " = " << vsit.d_update_nvn << std::endl;
+              d_quantEngine->getTermDatabaseSygus()->getExplanationFor( vs[k], vsit.d_update_nvn, mexp, vsit );
+              msu[k] = vsit.d_update_nvn;
             }
-            if( index!=-1 ){
-              ret = crefEvaluate( n[index], vtm, visited, exp );
-              exp_c.push_back( n[index] );
+            if( !mexp.empty() ){
+              Node en = mexp.size()==1 ? mexp[0] : NodeManager::currentNM()->mkNode( kind::AND, mexp );
+              cre_lem = NodeManager::currentNM()->mkNode( kind::OR, en.negate(), neg_guard );
+            }else{
+              cre_lem = neg_guard;
             }
           }
-          //carry explanation
-          exp_c.push_back( n[i] );
-          if( !ret.isNull() ){
-            break;
-          }
-        }
-        if( ret.isNull() ){
-          if( childChanged ){
-            ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
-            ret = Rewriter::rewrite( ret );
-          }else{
-            ret = n;
-          }
-        }
-      }else{
-        ret = n;
-      }
-    }
-  }
-  //carry explanation from children
-  for( unsigned i=0; i<exp_c.size(); i++ ){
-    Node nn = exp_c[i];
-    std::map< Node, std::vector< Node > >::iterator itx = exp.find( nn );
-    if( itx!=exp.end() ){
-      for( unsigned j=0; j<itx->second.size(); j++ ){
-        if( std::find( exp[n].begin(), exp[n].end(), itx->second[j] )==exp[n].end() ){
-          exp[n].push_back( itx->second[j] );
-        }
-      }
-    }
-  }
-  Trace("sygus-cref-eval-debug") << "... evaluation of " << n << " is (" << ret.getKind() << ") " << ret << std::endl;
-  Trace("sygus-cref-eval-debug") << "...... exp size = " << exp[n].size() << std::endl;
-  Assert( ret.isNull() || ret.isConst() );
-  visited[n] = ret;
-  return ret;
-}
-
-void CegInstantiation::registerMeasuredType( TypeNode tn ) {
-  std::map< TypeNode, Node >::iterator it = d_uf_measure.find( tn );
-  if( it==d_uf_measure.end() ){
-    if( tn.isDatatype() ){
-      TypeNode op_tn = NodeManager::currentNM()->mkFunctionType( tn, NodeManager::currentNM()->integerType() );
-      Node op = NodeManager::currentNM()->mkSkolem( "tsize", op_tn, "was created by ceg instantiation to enforce fairness." );
-      d_uf_measure[tn] = op;
-    }
-  }
-}
-
-Node CegInstantiation::getSizeTerm( Node n, TypeNode tn, std::vector< Node >& lems ) {
-  std::map< Node, Node >::iterator itt = d_size_term.find( n );
-  if( itt==d_size_term.end() ){
-    registerMeasuredType( tn );
-    Node sn = NodeManager::currentNM()->mkNode( APPLY_UF, d_uf_measure[tn], n );
-    lems.push_back( NodeManager::currentNM()->mkNode( LEQ, NodeManager::currentNM()->mkConst( Rational(0) ), sn ) );
-    d_size_term[n] = sn;
-    return sn;
-  }else{
-    return itt->second;
-  }
-}
-
-void CegInstantiation::getMeasureLemmas( Node n, Node v, std::vector< Node >& lems ) {
-  Trace("cegqi-lemma-debug") << "Get measure lemma " << n << " " << v << std::endl;
-  Assert( n.getType()==v.getType() );
-  TypeNode tn = n.getType();
-  if( tn.isDatatype() ){
-    Assert( v.getKind()==APPLY_CONSTRUCTOR );
-    const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
-    int index = Datatype::indexOf( v.getOperator().toExpr() );
-    std::map< int, Node >::iterator it = d_size_term_lemma[n].find( index );
-    if( it==d_size_term_lemma[n].end() ){
-      Node lhs = getSizeTerm( n, tn, lems );
-      //add measure lemma
-      std::vector< Node > sumc;
-      for( unsigned j=0; j<dt[index].getNumArgs(); j++ ){
-        TypeNode tnc = v[j].getType();
-        if( tnc.isDatatype() ){
-          Node seln = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[index][j].getSelector() ), n );
-          sumc.push_back( getSizeTerm( seln, tnc, lems ) );
-        }
-      }
-      Node rhs;
-      if( !sumc.empty() ){
-        sumc.push_back( NodeManager::currentNM()->mkConst( Rational(1) ) );
-        rhs = NodeManager::currentNM()->mkNode( PLUS, sumc );
-      }else{
-        rhs = NodeManager::currentNM()->mkConst( Rational(0) );
-      }
-      Node lem = lhs.eqNode( rhs );
-      Node cond = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[index].getTester() ), n );
-      lem = NodeManager::currentNM()->mkNode( OR, cond.negate(), lem );
-
-      d_size_term_lemma[n][index] = lem;
-      Trace("cegqi-lemma-debug") << "...constructed lemma " << lem << std::endl;
-      lems.push_back( lem );
-      //return;
-    }
-    //get lemmas for children
-    for( unsigned i=0; i<v.getNumChildren(); i++ ){
-      Node nn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[index][i].getSelector() ), n );
-      getMeasureLemmas( nn, v[i], lems );
-    }
-
-  }
-}
-
-Node CegInstantiation::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 = d_quantEngine->getTermDatabaseSygus()->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() );
+          if( !cre_lem.isNull() ){
+            if( std::find( lems.begin(), lems.end(), cre_lem )==lems.end() ){
+              Trace("sygus-cref-eval") << "...produced lemma : " << cre_lem << std::endl;
+              lems.push_back( cre_lem );
+            }
           }
-          ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
         }
       }
-      if( ret.isNull() ){
-        ret = n;
-      }
     }
-    visited[n] = ret;
-    return ret;
-  }else{
-    return itv->second;
   }
 }
 
@@ -1826,8 +940,10 @@ void CegInstantiation::printSynthSolution( std::ostream& out ) {
             for( unsigned j=0; j<svl.getNumChildren(); j++ ){
               subs.push_back( Node::fromExpr( svl[j] ) );
             }
-            bool templIsPost = false;
-            Node templ;
+            //bool templIsPost = false;
+            const CegConjectureSingleInv* ceg_si = d_conj->getCegConjectureSingleInv();
+            Node templ = ceg_si->getTemplate( prog );
+            /*
             if( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_PRE ){
               const CegConjectureSingleInv* ceg_si = d_conj->getCegConjectureSingleInv();
               if(ceg_si->d_trans_pre.find( prog ) != ceg_si->d_trans_pre.end()){
@@ -1841,8 +957,11 @@ void CegInstantiation::printSynthSolution( std::ostream& out ) {
                 templIsPost = true;
               }
             }
+            */
             Trace("cegqi-inv") << "Template is " << templ << std::endl;
             if( !templ.isNull() ){
+              TNode templa = ceg_si->getTemplateArg( prog );
+              Assert( !templa.isNull() );
               std::vector<Node>& templ_vars = d_conj->getProgTempVars(prog);
               std::vector< Node > vars;
               vars.insert( vars.end(), templ_vars.begin(), templ_vars.end() );
@@ -1860,7 +979,9 @@ void CegInstantiation::printSynthSolution( std::ostream& out ) {
               Trace("cegqi-inv") << "Builtin version of solution is : "
                                  << sol << ", type : " << sol.getType()
                                  << std::endl;
-              sol = NodeManager::currentNM()->mkNode( templIsPost ? AND : OR, sol, templ );
+              //sol = NodeManager::currentNM()->mkNode( templIsPost ? AND : OR, sol, templ );
+              TNode tsol = sol;
+              sol = templ.substitute( templa, tsol );
             }
             if( sol==sygus_sol ){
               sol = sygus_sol;
index 56a71e43eac4415d41a0713a48dab81ae6fda21b..c5c865ff994b25ecc0eba2e417b10016f5bb800f 100644 (file)
@@ -20,7 +20,9 @@
 #include "context/cdchunk_list.h"
 #include "context/cdhashmap.h"
 #include "options/quantifiers_modes.h"
+#include "options/datatypes_modes.h"
 #include "theory/quantifiers/ce_guided_single_inv.h"
+#include "theory/quantifiers/ce_guided_pbe.h"
 #include "theory/quantifiers_engine.h"
 
 namespace CVC4 {
@@ -42,36 +44,13 @@ private:
   std::vector< std::vector< Node > > d_inner_vars_disj;
   /** current extential quantifeirs whose couterexamples we must refine */
   std::vector< std::vector< Node > > d_ce_sk;
-  /** the cardinality literals */
-  std::map< int, Node > d_lits;
-  /** current cardinality */
-  context::CDO< int > d_curr_lit;
-  /** active measure term */
-  Node d_active_measure_term;
   /** refinement lemmas */
   std::vector< Node > d_refinement_lemmas;
   std::vector< Node > d_refinement_lemmas_base;
-  //std::vector< Node > d_refinement_lemmas_cprogress;
-  //std::vector< std::vector< Node > > d_refinement_lemmas_cprogress_pts;
-private: //for condition solutions
-  std::vector< std::vector< Node > > d_refinement_lemmas_aux_vars;
-  std::vector< std::vector< Node > > d_refinement_lemmas_ceval_ant;
-  std::vector< std::vector< Node > > d_refinement_lemmas_ceval_conc;
-  std::vector< Node > d_refinement_lemmas_ngr; //non-ground version
-  std::map< Node, bool > d_refinement_lemmas_reproc;
-  /** get candidate list recursively for conditional solutions */
-  void getConditionalCandidateList( std::vector< Node >& clist, Node curr, bool reqAdd );
-  Node constructConditionalCandidate( std::map< Node, Node >& cmv, Node curr );
-  Node getActiveConditional( Node curr );
-  void getContextConditionalNodes( Node curr, Node x, std::vector< Node >& nodes );
-  Node mkConditionalEvalNode( Node c, std::vector< Node >& args );
-  Node mkConditionalNode( Node v, std::vector< Node >& args, unsigned eindex );
-  Node mkConditional( Node v, std::vector< Node >& args, bool pol = true );
-  Node purifyConditionalEvaluations( Node n, std::map< Node, Node >& csol_cond, std::map< Node, Node >& psubs, 
-                                     std::map< Node, Node >& visited );
-  /** register candidate conditional */
-  void registerCandidateConditional( Node v );
-  bool inferIteTemplate( unsigned k, Node n, std::map< Node, unsigned >& templ_var_index, std::map< unsigned, unsigned >& templ_injection );
+  /** get embedding */
+  Node convertToEmbedding( Node n, std::map< Node, Node >& synth_fun_vars, std::map< Node, Node >& visited );
+  /** collect constants */
+  void collectConstants( Node n, std::map< TypeNode, std::vector< Node > >& consts, std::map< Node, bool >& visited );
 public:
   CegConjecture( QuantifiersEngine * qe, context::Context* c );
   ~CegConjecture();
@@ -83,25 +62,12 @@ public:
 
   class CandidateInfo {
   public:
-    CandidateInfo() : d_csol_status(-1){}
+    CandidateInfo(){}
     /** list of terms we have instantiated candidates with */
     std::vector< Node > d_inst;
-    /** conditional solutions */
-    Node d_csol_op;
-    Node d_csol_cond;
-    Node d_csol_var[2];
-    /** progress guard */
-    Node d_csol_progress_guard;
-    /** solution status */
-    int d_csol_status;
-    /** required for template solutions */
-    std::map< unsigned, Node > d_template;
-    std::map< unsigned, Node > d_template_arg; 
   };
   std::map< Node, CandidateInfo > d_cinfo;
   
-  /** measure term */
-  Node d_measure_term;
   /** measure sum size */
   int d_measure_term_size;
   /** refine count */
@@ -113,7 +79,8 @@ public:
   
   bool needsRefinement();
   void getCandidateList( std::vector< Node >& clist, bool forceOrig = false );
-  bool constructCandidates( std::vector< Node >& clist, std::vector< Node >& model_values, std::vector< Node >& candidate_values );
+  bool constructCandidates( std::vector< Node >& clist, std::vector< Node >& model_values, std::vector< Node >& candidate_values, 
+                            std::vector< Node >& lems );
 
   void doCegConjectureSingleInvCheck(std::vector< Node >& lems);
   void doCegConjectureCheck(std::vector< Node >& lems, std::vector< Node >& model_values);
@@ -146,28 +113,19 @@ public:
 private:
   /** single invocation utility */
   CegConjectureSingleInv * d_ceg_si;
+  /** program by examples utility */
+  CegConjecturePbe * d_ceg_pbe;
 public: //non-syntax guided (deprecated)
   /** guard */
   bool d_syntax_guided;
   Node d_nsg_guard;
 public:
-  /** get current term size */
-  int getCurrentTermSize() { return d_curr_lit.get(); }
-  /** increment current term size */
-  void incrementCurrentTermSize() { d_curr_lit.set( d_curr_lit.get() + 1 ); }
-  /** set measure term */
-  void setMeasureTerm( Node mt );
-  /** get measure term */
-  Node getMeasureTermFactor( Node v );
-  Node getMeasureTerm() { return d_measure_term; }
-  /** allocate literal */
-  Node getFairnessLiteral( int i );
   /** get guard */
   Node getGuard();
   /** is ground */
   bool isGround() { return d_inner_vars.empty(); }
   /** fairness */
-  CegqiFairMode getCegqiFairMode();
+  SygusFairMode getCegqiFairMode();
   /** is single invocation */
   bool isSingleInvocation() const;
   /** is single invocation */
@@ -176,8 +134,6 @@ public:
   bool needsCheck( std::vector< Node >& lem );
   /** preregister conjecture */
   void preregisterConjecture( Node q );
-  /** initialize guard */
-  void initializeGuard();
   /** assign */
   void assign( Node q );
   /** is assigned */
@@ -192,23 +148,6 @@ public:
   Node getRefinementLemma( unsigned i ) { return d_refinement_lemmas[i]; }
   /** get refinement lemma */
   Node getRefinementBaseLemma( unsigned i ) { return d_refinement_lemmas_base[i]; }
-  /** get num conditional evaluations */
-  unsigned getNumConditionalEvaluations( unsigned i ) { return d_refinement_lemmas_ceval_ant[i].size(); }
-  /** get conditional evaluation */
-  Node getConditionalEvaluationAntec( unsigned i, unsigned j ) { return d_refinement_lemmas_ceval_ant[i][j]; }
-  Node getConditionalEvaluationConc( unsigned i, unsigned j ) { return d_refinement_lemmas_ceval_conc[i][j]; }
-  /** get progress lemma */
-  //Node getConditionalProgressLemma( unsigned i ) { return d_refinement_lemmas_cprogress[i]; }
-  /** get progress point */
-  //void getConditionalProgressLemmaPoint( unsigned i, std::vector< Node >& pt ){
-  //  pt.insert( pt.end(), d_refinement_lemmas_cprogress_pts[i].begin(), d_refinement_lemmas_cprogress_pts[i].end() );
-  //}
-private:
-  Node getNextDecisionRequestConditional( Node v, unsigned& priority );
-  // 1 : active, 0 : unknown, -1 : inactive, -2 : not applicable
-  int getProgressStatus( Node v );
-public:
-  Node getNextDecisionRequest( unsigned& priority );
 };
 
 
@@ -221,26 +160,10 @@ private:
   /** last instantiation by single invocation module? */
   bool d_last_inst_si;
   /** evaluation axioms */
-  std::map< Node, bool > d_eval_axioms;
-private: //for enforcing fairness
-  /** measure functions */
-  std::map< TypeNode, Node > d_uf_measure;
-  /** register measured type */
-  void registerMeasuredType( TypeNode tn );
-  /** term -> size term */
-  std::map< Node, Node > d_size_term;
-  /** get size term */
-  Node getSizeTerm( Node n, TypeNode tn, std::vector< Node >& lems );
-  /** term x constructor -> lemma */
-  std::map< Node, std::map< int, Node > > d_size_term_lemma;
-  /** get measure lemmas */
-  void getMeasureLemmas( Node n, Node v, std::vector< Node >& lems );
+  //std::map< Node, bool > d_eval_axioms;
 private: //for direct evaluation
   /** get refinement evaluation */
   void getCRefEvaluationLemmas( CegConjecture * conj, std::vector< Node >& vs, std::vector< Node >& ms, std::vector< Node >& lems );
-  Node crefEvaluate( Node lem, std::map< Node, Node >& vtm, std::map< Node, Node >& visited, std::map< Node, std::vector< Node > >& exp );
-  /** get eager unfolding */
-  Node getEagerUnfold( Node n, std::map< Node, Node >& visited );
 private:
   /** check conjecture */
   void checkCegConjecture( CegConjecture * conj );
diff --git a/src/theory/quantifiers/ce_guided_pbe.cpp b/src/theory/quantifiers/ce_guided_pbe.cpp
new file mode 100644 (file)
index 0000000..38b5af8
--- /dev/null
@@ -0,0 +1,1859 @@
+/*********************                                                        */
+/*! \file ce_guided_pbe.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief utility for processing programming by examples synthesis conjectures
+ **
+ **/
+#include "theory/quantifiers/ce_guided_pbe.h"
+
+#include "expr/datatype.h"
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/datatypes/datatypes_rewriter.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace std;
+
+namespace CVC4 {
+
+void indent( const char * c, int ind ) {
+  if( Trace.isOn(c) ){
+    for( int i=0; i<ind; i++ ){ 
+      Trace(c) << "  "; 
+    }
+  } 
+}
+void print_val( const char * c, std::vector< Node >& vals, bool pol = true ){
+  if( Trace.isOn(c) ){
+    for( unsigned i=0; i<vals.size(); i++ ){
+      //Trace(c) << ( pol ? vals[i] : !vals[i] );
+      Trace(c) << ( ( pol ? vals[i].getConst<bool>() : !vals[i].getConst<bool>() ) ? "1" : "0" );
+    }
+  }
+}
+void print_strat( const char * c, unsigned s ){
+  switch(s){
+  case CegConjecturePbe::strat_ITE:Trace(c) << "ITE";break;
+  case CegConjecturePbe::strat_CONCAT:Trace(c) << "CONCAT";break;
+  case CegConjecturePbe::strat_ID:Trace(c) << "ID";break;
+  default:Trace(c) << "strat_" << s;break;
+  }
+}
+void print_role( const char * c, unsigned r ){
+  switch(r){
+  case CegConjecturePbe::enum_io:Trace(c) << "IO";break;
+  case CegConjecturePbe::enum_ite_condition:Trace(c) << "CONDITION";break;
+  case CegConjecturePbe::enum_concat_term:Trace(c) << "CTERM";break;
+  case CegConjecturePbe::enum_any:Trace(c) << "ANY";break;
+  default:Trace(c) << "role_" << r;break;
+  }
+}
+
+CegConjecturePbe::CegConjecturePbe(QuantifiersEngine* qe, CegConjecture* p)
+    : d_qe(qe),
+      d_parent(p){
+  d_tds = d_qe->getTermDatabaseSygus();
+  d_true = NodeManager::currentNM()->mkConst(true);
+  d_false = NodeManager::currentNM()->mkConst(false);
+  d_is_pbe = false;
+}
+
+CegConjecturePbe::~CegConjecturePbe() {
+
+}
+
+//--------------------------------- collecting finite input/output domain information
+
+void CegConjecturePbe::collectExamples( Node n, std::map< Node, bool >& visited, bool hasPol, bool pol ) {
+  if( visited.find( n )==visited.end() ){
+    visited[n] = true;
+    Node neval;
+    Node n_output;
+    if( n.getKind()==APPLY_UF && n.getNumChildren()>0 ){
+      neval = n;
+      if( hasPol ){
+        n_output = !pol ? d_true : d_false;
+      }
+    }else if( n.getKind()==EQUAL && hasPol && !pol ){
+      for( unsigned r=0; r<2; r++ ){
+        if( n[r].getKind()==APPLY_UF && n[r].getNumChildren()>0 ){
+          neval = n[r];
+          if( n[1-r].isConst() ){
+            n_output = n[1-r];
+          }
+        }
+      }
+    }
+    if( !neval.isNull() ){
+      if( neval.getKind()==APPLY_UF && neval.getNumChildren()>0 ){
+        // is it an evaluation function?
+        if( d_examples.find( neval[0] )!=d_examples.end() ){
+          std::map< Node, bool >::iterator itx = d_examples_invalid.find( neval[0] );
+          if( itx==d_examples_invalid.end() ){
+            //collect example
+            bool success = true;
+            std::vector< Node > ex;
+            for( unsigned j=1; j<neval.getNumChildren(); j++ ){
+              if( !neval[j].isConst() ){
+                success = false;
+                break;
+              }else{
+                ex.push_back( neval[j] );
+              }
+            }
+            if( success ){
+              d_examples[neval[0]].push_back( ex );
+              d_examples_out[neval[0]].push_back( n_output );
+              d_examples_term[neval[0]].push_back( neval );
+              if( n_output.isNull() ){
+                d_examples_out_invalid[neval[0]] = true;
+              }else{
+                Assert( n_output.isConst() );
+              }
+              //finished processing this node
+              return;
+            }else{
+              d_examples_invalid[neval[0]] = true;
+              d_examples_out_invalid[neval[0]] = true;
+            }
+          }
+        }
+      }
+    }
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      bool newHasPol;
+      bool newPol;
+      QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol );
+      collectExamples( n[i], visited, newHasPol, newPol );
+    }
+  }
+}
+
+void CegConjecturePbe::initialize( Node n, std::vector< Node >& candidates, std::vector< Node >& lemmas ) {
+  Trace("sygus-pbe") << "Initialize PBE : " << n << std::endl;
+  
+  for( unsigned i=0; i<candidates.size(); i++ ){
+    Node v = candidates[i];
+    d_examples[v].clear();
+    d_examples_out[v].clear();
+    d_examples_term[v].clear();
+  }
+  
+  std::map< Node, bool > visited;
+  collectExamples( n, visited, true, true );
+  
+  for( unsigned i=0; i<candidates.size(); i++ ){
+    Node v = candidates[i];
+    Trace("sygus-pbe") << "  examples for " << v << " : ";
+    if( d_examples_invalid.find( v )!=d_examples_invalid.end() ){
+      Trace("sygus-pbe") << "INVALID" << std::endl;
+    }else{
+      Trace("sygus-pbe") << std::endl;
+      for( unsigned j=0; j<d_examples[v].size(); j++ ){
+        Trace("sygus-pbe") << "    ";
+        for( unsigned k=0; k<d_examples[v][j].size(); k++ ){
+          Trace("sygus-pbe") << d_examples[v][j][k] << " ";
+        }
+        if( !d_examples_out[v][j].isNull() ){
+          Trace("sygus-pbe") << " -> " << d_examples_out[v][j];
+        }
+        Trace("sygus-pbe") << std::endl;
+      }
+    }
+  }
+  
+  //register candidates
+  if( options::sygusUnifCondSol() ){
+    if( candidates.size()==1 ){// conditional solutions for multiple function conjectures TODO?
+      // collect a pool of types over which we will enumerate terms 
+      Node c = candidates[0];
+      //the candidate must be input/output examples
+      if( d_examples_out_invalid.find( c )==d_examples_out_invalid.end() ){
+        Assert( d_examples.find( c )!=d_examples.end() );
+        Trace("sygus-unif") << "It is input/output examples..." << std::endl;
+        TypeNode ctn = c.getType();
+        d_cinfo[c].initialize( c );
+        // collect the enumerator types / form the strategy
+        collectEnumeratorTypes( c, ctn, enum_io );
+        // if we have non-trivial strategies, then use pbe
+        if( d_cinfo[c].isNonTrivial() ){
+          // static learning of redundant constructors
+          staticLearnRedundantOps( c, lemmas );
+          d_is_pbe = true;
+        }
+      }
+    }
+  }
+  if( !d_is_pbe ){
+    Trace("sygus-unif") << "Do not do PBE optimizations, register..." << std::endl;
+    for( unsigned i=0; i<candidates.size(); i++ ){
+      d_qe->getTermDatabaseSygus()->registerMeasuredTerm( candidates[i], candidates[i] );
+    }
+  }
+}
+
+bool CegConjecturePbe::getPbeExamples( Node v, std::vector< std::vector< Node > >& exs, 
+                                       std::vector< Node >& exos, std::vector< Node >& exts ) {
+  std::map< Node, bool >::iterator itx = d_examples_invalid.find( v );
+  if( itx==d_examples_invalid.end() ){
+    Assert( d_examples.find( v )!=d_examples.end() );
+    exs = d_examples[v];
+    Assert( d_examples_out.find( v )!=d_examples_out.end() );
+    exos = d_examples_out[v];
+    Assert( d_examples_term.find( v )!=d_examples_term.end() );
+    exts = d_examples_term[v];
+    return true;
+  }
+  return false;
+}
+
+
+// ----------------------------- establishing enumeration types
+
+
+void CegConjecturePbe::registerEnumerator( Node et, Node c, TypeNode tn, unsigned enum_role, bool inSearch ) {
+  Trace("sygus-unif-debug") << "...register " << et << " for " << ((DatatypeType)tn.toType()).getDatatype().getName();
+  Trace("sygus-unif-debug") << ", role = ";
+  print_role( "sygus-unif-debug", enum_role );
+  Trace("sygus-unif-debug") << ", in search = " << inSearch << std::endl;
+  d_einfo[et].d_parent_candidate = c;
+  d_einfo[et].d_role = enum_role;
+  // if we are actually enumerating this (could be a compound node in the strategy)
+  if( inSearch ){
+    std::map< TypeNode, Node >::iterator itn = d_cinfo[c].d_search_enum.find( tn );
+    if( itn==d_cinfo[c].d_search_enum.end() ){
+      // use this for the search
+      d_cinfo[c].d_search_enum[tn] = et;
+      d_cinfo[c].d_esym_list.push_back( et );
+      d_einfo[et].d_enum_slave.push_back( et );
+      //register measured term with database
+      d_qe->getTermDatabaseSygus()->registerMeasuredTerm( et, c, true );
+      d_einfo[et].d_active_guard = d_qe->getTermDatabaseSygus()->getActiveGuardForMeasureTerm( et );
+    }else{
+      Trace("sygus-unif-debug") << "Make " << et << " a slave of " << itn->second << std::endl;
+      d_einfo[itn->second].d_enum_slave.push_back( et );
+    }
+  }
+}
+
+void CegConjecturePbe::collectEnumeratorTypes( Node e, TypeNode tn, unsigned enum_role ) {
+  if( d_cinfo[e].d_tinfo.find( tn )==d_cinfo[e].d_tinfo.end() ){
+    // register type
+    Trace("sygus-unif") << "Register enumerating type : " << tn << std::endl;
+    d_cinfo[e].initializeType( tn );
+  }
+  if( d_cinfo[e].d_tinfo[tn].d_enum.find( enum_role )==d_cinfo[e].d_tinfo[tn].d_enum.end() ){
+  
+    Node ee = NodeManager::currentNM()->mkSkolem( "ee", tn );
+    d_cinfo[e].d_tinfo[tn].d_enum[enum_role] = ee;
+    Trace("sygus-unif-debug") << "...enumerator " << ee << " for " << ((DatatypeType)tn.toType()).getDatatype().getName() << ", role = ";
+    print_role( "sygus-unif-debug", enum_role );
+    Trace("sygus-unif-debug") << std::endl;
+    // wait to register : may or may not actually be enumerating it
+
+    if( enum_role==enum_io ){
+      // look at information on how we will construct solutions for this type
+      Assert( tn.isDatatype() );
+      const Datatype& dt = ((DatatypeType)tn.toType()).getDatatype();
+      Assert( dt.isSygus() );
+      std::map< Node, std::vector< TypeNode > > cop_to_child_types;
+      std::map< Node, std::map< unsigned, Node > > cop_to_child_templ;
+      std::map< Node, std::map< unsigned, Node > > cop_to_child_templ_arg;
+      std::map< Node, unsigned > cop_to_strat;
+      std::map< Node, unsigned > cop_to_cindex;
+      
+      for( unsigned r=0; r<2; r++ ){
+        for( unsigned j=0; j<dt.getNumConstructors(); j++ ){
+          bool success = false;
+          Node cop = Node::fromExpr( dt[j].getConstructor() );
+          Node op = Node::fromExpr( dt[j].getSygusOp() );
+          if( r==0 ){
+            cop_to_cindex[cop] = j;
+            if( op.getKind() == kind::BUILTIN ){
+              Kind sk = NodeManager::operatorToKind( op );
+              if( sk==kind::ITE ){
+                Trace("sygus-unif") << "...type " << dt.getName() << " has ITE, enumerate child types..." << std::endl;
+                // we can do unification
+                Assert( dt[j].getNumArgs()==3 );
+                cop_to_strat[cop] = strat_ITE;
+              }else if( sk==kind::STRING_CONCAT ){
+                if( dt[j].getNumArgs()==2 ) {
+                  cop_to_strat[cop] = strat_CONCAT;
+                }
+                Trace("sygus-unif") << "...type " << dt.getName() << " has CONCAT, child types successful = " << success << std::endl;
+              }
+              if( cop_to_strat.find( cop )!=cop_to_strat.end() ){
+                // add child types
+                for( unsigned k=0; k<dt[j].getNumArgs(); k++ ){
+                  TypeNode ct = TypeNode::fromType( dt[j][k].getRangeType() );
+                  Trace("sygus-unif") << "   Child type " << k << " : " << ((DatatypeType)ct.toType()).getDatatype().getName() << std::endl;
+                  cop_to_child_types[cop].push_back( ct );
+                }
+              }
+            }
+          }else if( cop_to_strat.find( cop )==cop_to_strat.end() ){
+            // could be a defined function (this is a hack for ICFP benchmarks)
+            std::vector< Node > utchildren;
+            utchildren.push_back( cop );
+            std::vector< Node > sks;
+            std::vector< TypeNode > sktns;
+            for( unsigned k=0; k<dt[j].getNumArgs(); k++ ){
+              Type t = dt[j][k].getRangeType();
+              TypeNode ttn = TypeNode::fromType( t );
+              Node kv = NodeManager::currentNM()->mkSkolem( "ut", ttn );
+              sks.push_back( kv );
+              sktns.push_back( ttn );
+              utchildren.push_back( kv );
+            }
+            Node ut = NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, utchildren );
+            std::vector< Node > echildren;
+            echildren.push_back( Node::fromExpr( dt.getSygusEvaluationFunc() ) );
+            echildren.push_back( ut );
+            Node sbvl = Node::fromExpr( dt.getSygusVarList() );
+            for( unsigned k=0; k<sbvl.getNumChildren(); k++ ){
+              echildren.push_back( sbvl[k] );
+            }
+            Node eut = NodeManager::currentNM()->mkNode( kind::APPLY_UF, echildren );
+            Trace("sygus-unif-debug2") << "Test evaluation of " << eut << "..." << std::endl;
+            eut = d_qe->getTermDatabaseSygus()->unfold( eut );
+            Trace("sygus-unif-debug2") << "...got " << eut << std::endl;       
+            Trace("sygus-unif-debug2") << "Type : " << eut.getType() << std::endl;     
+
+            if( eut.getKind()==kind::ITE ){
+              if( dt[j].getNumArgs()>=eut.getNumChildren() ){
+                cop_to_strat[cop] = strat_ITE;
+              }
+            }else if( eut.getKind()==kind::STRING_CONCAT ){
+              if( dt[j].getNumArgs()>=eut.getNumChildren() ){
+                cop_to_strat[cop] = strat_CONCAT;
+              }
+            }else if( eut.getKind()==kind::APPLY_UF ){
+              // identity operator?
+              if( dt[j].getNumArgs()==1 ){
+                cop_to_strat[cop] = strat_ID;
+              }
+            }
+            
+            if( cop_to_strat.find( cop )!=cop_to_strat.end() ){
+              std::map< unsigned, unsigned > templ_injection;
+              std::vector< Node > vs;
+              std::vector< Node > ss;
+              std::map< Node, unsigned > templ_var_index;
+              for( unsigned k=0; k<sks.size(); k++ ){
+                Assert( sks[k].getType().isDatatype() );
+                const Datatype& cdt = ((DatatypeType)sks[k].getType().toType()).getDatatype();
+                echildren[0] = Node::fromExpr( cdt.getSygusEvaluationFunc() );
+                echildren[1] = sks[k];
+                Trace("sygus-unif-debug2") << "...set eval dt to " << sks[k] << std::endl;
+                Node esk = NodeManager::currentNM()->mkNode( kind::APPLY_UF, echildren );
+                vs.push_back( esk );
+                Node tvar = NodeManager::currentNM()->mkSkolem( "templ", esk.getType() );
+                templ_var_index[tvar] = k;
+                Trace("sygus-unif-debug2") << "* template inference : looking for " << tvar << " for arg " << k << std::endl;
+                ss.push_back( tvar );
+                Trace("sygus-unif-debug2") << "* substitute : " << esk << " -> " << tvar << std::endl;
+              }
+              eut = eut.substitute( vs.begin(), vs.end(), ss.begin(), ss.end() );
+              Trace("sygus-unif-debug2") << "Defined constructor " << j << ", base term is " << eut << std::endl;
+              std::map< unsigned, Node > test_args;
+              if( cop_to_strat[cop] == strat_ID ){
+                test_args[0] = eut;
+              }else{
+                for( unsigned k=0; k<eut.getNumChildren(); k++ ){
+                  test_args[k] = eut[k];
+                }
+              }
+              for( std::map< unsigned, Node >::iterator it = test_args.begin(); it != test_args.end(); ++it ){
+                unsigned k = it->first;
+                Node eut_c = it->second;
+                //success if we can find a injection from args to sygus args
+                if( !inferTemplate( k, eut_c, templ_var_index, templ_injection ) ){
+                  Trace("sygus-unif-debug2") << "...failed to find injection (range)." << std::endl;
+                  cop_to_strat.erase( cop );
+                  break;
+                }
+                if( templ_injection.find( k )==templ_injection.end() ){
+                  Trace("sygus-unif-debug2") << "...failed to find injection (domain)." << std::endl;
+                  cop_to_strat.erase( cop );
+                  break;
+                }
+              }
+              if( cop_to_strat.find( cop )!=cop_to_strat.end() ){
+                Trace("sygus-unif") << "...type " << dt.getName() << " has defined constructor matching strategy ";
+                Trace("sygus-unif") << cop_to_strat[cop] << ", enumerate child types..." << std::endl;
+                for( unsigned k=0; k<eut.getNumChildren(); k++ ){
+                  Assert( templ_injection.find( k )!=templ_injection.end() );
+                  unsigned sk_index = templ_injection[k];
+                  //also store the template information, if necessary
+                  Node teut = eut[k];
+                  if( !teut.isVar() ){
+                    if( cop_to_strat[cop] == strat_ID ){
+                      Trace("sygus-unif-debug") << "...cannot use template with ID strategy." << std::endl;
+                      cop_to_strat.erase( cop );
+                    }else{
+                      cop_to_child_templ[cop][k] = teut;
+                      cop_to_child_templ_arg[cop][k] = ss[sk_index];
+                      Trace("sygus-unif") << "  Arg " << k << " : template : " << teut << ", arg " << ss[sk_index] << std::endl;
+                    }
+                  }else{
+                    Assert( teut==ss[sk_index] );
+                  }
+                }
+                // collect children types
+                for( unsigned k=0; k<dt[j].getNumArgs(); k++ ){
+                  Trace("sygus-unif") << "   Child type " << k << " : " << ((DatatypeType)sktns[k].toType()).getDatatype().getName() << std::endl;
+                  cop_to_child_types[cop].push_back( sktns[k] );
+                }
+              }
+            }
+          }
+        }
+      }
+      bool search_this = true;
+      for( std::map< Node, unsigned >::iterator itc = cop_to_strat.begin(); itc != cop_to_strat.end(); ++itc ){
+        if( itc->second==strat_CONCAT || ( itc->second==strat_ID && dt.getNumConstructors()==1 ) ){
+          search_this = false;
+          break;
+        }
+      }
+      Trace("sygus-unif-debug2") << "...this register..." << std::endl;
+      registerEnumerator( ee, e, tn, enum_role, search_this );
+      
+      if( cop_to_child_types.empty() ){
+        Trace("sygus-unif") << "...consider " << dt.getName() << " a basic type" << std::endl;
+      }else{
+        for( std::map< Node, std::vector< TypeNode > >::iterator itct = cop_to_child_types.begin(); itct != cop_to_child_types.end(); ++itct ){
+          Node cop = itct->first;
+          Assert( cop_to_strat.find( cop )!=cop_to_strat.end() );
+          unsigned strat = cop_to_strat[cop];
+          d_cinfo[e].d_tinfo[tn].d_strat[cop].d_this = strat;
+          Trace("sygus-unif-debug") << "Process strategy for operator : " << cop << " : ";
+          print_strat("sygus-unif-debug", strat );
+          Trace("sygus-unif-debug") << std::endl;
+
+          for( unsigned j=0; j<itct->second.size(); j++ ){
+            //calculate if we should allocate a new enumerator : should be true if we have a new role
+            unsigned enum_role_c = enum_role;
+            if( strat==strat_ITE ){
+              if( j==0 ){
+                enum_role_c = enum_ite_condition;
+              }else{
+                // role is the same as parent
+              }
+            }else if( strat==strat_CONCAT ){
+              enum_role_c = enum_concat_term;
+            }else if( strat==strat_ID ){
+              // role is the same as parent
+            }
+            
+            // register the child type
+            TypeNode ct = itct->second[j];
+            d_cinfo[e].d_tinfo[tn].d_strat[cop].d_csol_cts.push_back( ct );
+            
+            // make the enumerator
+            Node et;
+            if( cop_to_child_templ[cop].find( j )!=cop_to_child_templ[cop].end() ){
+              // it is templated, allocate a fresh variable
+              et = NodeManager::currentNM()->mkSkolem( "et", ct );
+              Trace("sygus-unif-debug") << "...enumerate " << et << " of type " << ((DatatypeType)ct.toType()).getDatatype().getName();
+              Trace("sygus-unif-debug") << " for arg " << j << " of " << ((DatatypeType)tn.toType()).getDatatype().getName() << std::endl;
+              registerEnumerator( et, e, ct, enum_role_c, true );
+              d_einfo[et].d_template = cop_to_child_templ[cop][j];
+              d_einfo[et].d_template_arg = cop_to_child_templ_arg[cop][j];
+              Assert( !d_einfo[et].d_template.isNull() );
+              Assert( !d_einfo[et].d_template_arg.isNull() );
+            }else{
+              Trace("sygus-unif-debug") << "...child type enumerate " << ((DatatypeType)ct.toType()).getDatatype().getName() << ", role = ";
+              print_role( "sygus-unif-debug", enum_role_c );
+              Trace("sygus-unif-debug") << std::endl;
+              collectEnumeratorTypes( e, ct, enum_role_c );
+              // otherwise use the previous
+              Assert( d_cinfo[e].d_tinfo[ct].d_enum.find( enum_role_c )!=d_cinfo[e].d_tinfo[ct].d_enum.end() );
+              et = d_cinfo[e].d_tinfo[ct].d_enum[enum_role_c];
+            }
+            Trace("sygus-unif-debug") << "Register child enumerator " << et << ", arg " << j << " of " << cop << ", role = ";
+            print_role( "sygus-unif-debug", enum_role_c );
+            Trace("sygus-unif-debug") << std::endl;
+            Assert( !et.isNull() );
+            d_cinfo[e].d_tinfo[tn].d_strat[cop].d_cenum.push_back( et );
+            // need to make this take into account template
+            //Assert( et.getType()==e.getType() || d_einfo[et].d_role!=enum_io );
+          }
+          Trace("sygus-unif") << "Initialized strategy ";
+          print_strat( "sygus-unif", strat );
+          Trace("sygus-unif") << " for " << ((DatatypeType)tn.toType()).getDatatype().getName() << ", operator " << cop;
+          Trace("sygus-unif") << ", #children = " << d_cinfo[e].d_tinfo[tn].d_strat[cop].d_cenum.size() << std::endl;
+          Assert( d_cinfo[e].d_tinfo[tn].d_strat[cop].d_cenum.size()==d_cinfo[e].d_tinfo[tn].d_strat[cop].d_csol_cts.size() );
+        }
+      }
+    }else{
+      Trace("sygus-unif-debug") << "...this register (non-io)" << std::endl;
+      registerEnumerator( ee, e, tn, enum_role, true );
+    }
+  }
+}
+
+bool CegConjecturePbe::inferTemplate( unsigned k, Node n, std::map< Node, unsigned >& templ_var_index, std::map< unsigned, unsigned >& templ_injection ){
+  if( n.getNumChildren()==0 ){
+    std::map< Node, unsigned >::iterator itt = templ_var_index.find( n );
+    if( itt!=templ_var_index.end() ){
+      unsigned kk = itt->second;
+      std::map< unsigned, unsigned >::iterator itti = templ_injection.find( k );
+      if( itti==templ_injection.end() ){
+        Trace("sygus-unif-debug") << "...set template injection " << k <<  " -> " << kk << std::endl;
+        templ_injection[k] = kk;
+      }else if( itti->second!=kk ){
+        return false;
+      }
+    }
+    return true;
+  }else{
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      if( !inferTemplate( k, n[i], templ_var_index, templ_injection ) ){
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+void CegConjecturePbe::staticLearnRedundantOps( Node c, std::vector< Node >& lemmas ) {
+  for( unsigned i=0; i<d_cinfo[c].d_esym_list.size(); i++ ){
+    Node e = d_cinfo[c].d_esym_list[i];
+    std::map< Node, EnumInfo >::iterator itn = d_einfo.find( e );
+    Assert( itn!=d_einfo.end() );
+    // see if there is anything we can eliminate
+    Trace("sygus-unif") << "* Search enumerator #" << i << " : type " << ((DatatypeType)e.getType().toType()).getDatatype().getName() << " : ";
+    Trace("sygus-unif") << e << " has " << itn->second.d_enum_slave.size() << " slaves:" << std::endl;
+    for( unsigned j=0; j<itn->second.d_enum_slave.size(); j++ ){
+      Node es = itn->second.d_enum_slave[j];
+      std::map< Node, EnumInfo >::iterator itns = d_einfo.find( es );
+      Assert( itns!=d_einfo.end() );
+      Trace("sygus-unif") << "  " << es << ", role = ";
+      print_role( "sygus-unif", itns->second.d_role );
+      Trace("sygus-unif") << std::endl;
+    }
+  }
+  Trace("sygus-unif") << std::endl;
+  Trace("sygus-unif") << "Strategy for candidate " << c << " is : " << std::endl;
+  std::map< Node, bool > visited;
+  std::vector< Node > redundant;
+  staticLearnRedundantOps( c, d_cinfo[c].getRootEnumerator(), visited, redundant, lemmas, 0 );
+  for( unsigned i=0; i<lemmas.size(); i++ ){  
+    Trace("sygus-unif") << "...can exclude based on  : " << lemmas[i] << std::endl;
+  }
+}
+
+void CegConjecturePbe::staticLearnRedundantOps( Node c, Node e, std::map< Node, bool >& visited, std::vector< Node >& redundant,
+                                                std::vector< Node >& lemmas, int ind ) {
+
+  std::map< Node, EnumInfo >::iterator itn = d_einfo.find( e );
+  Assert( itn!=d_einfo.end() );                                    
+  if( visited.find( e )==visited.end() ){
+    visited[e] = true;
+
+    indent("sygus-unif", ind);
+    Trace("sygus-unif") << e << " : role : ";
+    print_role("sygus-unif", itn->second.d_role);
+    Trace("sygus-unif") << " : ";
+
+    if( itn->second.isTemplated() ){
+      Trace("sygus-unif") << "basic, templated : \\ " << itn->second.d_template_arg << ". " << itn->second.d_template << std::endl;
+    }else{
+      TypeNode etn = e.getType();
+      std::map< TypeNode, EnumTypeInfo >::iterator itt = d_cinfo[c].d_tinfo.find( etn );
+      Assert( itt!=d_cinfo[c].d_tinfo.end() );
+      if( itt->second.d_strat.empty() ){
+        Trace("sygus-unif") << "basic" << std::endl;
+      }else{
+        Trace("sygus-unif") << "compound" << std::endl;
+        // various strategies 
+        for( std::map< Node, EnumTypeInfoStrat >::iterator itts = itt->second.d_strat.begin(); itts!=itt->second.d_strat.end(); ++itts ){
+          indent("sygus-unif", ind+1);
+          Trace("sygus-unif") << "Strategy : ";
+          unsigned strat = itts->second.d_this;
+          print_strat("sygus-unif", strat);
+          Trace("sygus-unif") << std::endl;
+          for( unsigned i=0; i<itts->second.d_cenum.size(); i++ ){
+            std::vector< Node > redundant_c;
+            bool no_repeat_op = false;
+            // do not repeat operators that the strategy uses
+            if( itts->second.d_csol_cts[i]==etn ){
+              if( strat==strat_ITE && i!=0 ){
+                no_repeat_op = true;
+              }else if( strat==strat_CONCAT || strat==strat_ID ){
+                no_repeat_op = true;
+              }
+            }
+            if( no_repeat_op ){
+              redundant_c.push_back( itts->first );
+            }
+            //do not use standard Boolean connectives in ITE conditions
+            if( strat==strat_ITE && i==0 && itts->second.d_csol_cts[1]==itts->second.d_csol_cts[2] ){
+              TypeNode ctn = itts->second.d_csol_cts[0];
+              const Datatype& cdt = ((DatatypeType)ctn.toType()).getDatatype();
+              for( unsigned j=0; j<cdt.getNumConstructors(); j++ ){
+                Kind ck = d_tds->getConsNumKind( ctn, j );
+                if( ck!=UNDEFINED_KIND && TermDb::isBoolConnective( ck ) ){
+                  bool typeCorrect = true;
+                  for( unsigned k=0; k<cdt[j].getNumArgs(); k++ ){
+                    if( d_tds->getArgType( cdt[j], k )!=ctn ){
+                      typeCorrect = false;
+                      break;
+                    }
+                  }
+                  if( typeCorrect ){
+                    Trace("sygus-unif-debug") << "Exclude Boolean connective in ITE conditional : " << ck << " in conditional type " << cdt.getName() << std::endl;
+                    Node exc_cons = Node::fromExpr( cdt[j].getConstructor() );
+                    if( std::find( redundant_c.begin(), redundant_c.end(), exc_cons )==redundant_c.end() ){
+                      redundant_c.push_back( exc_cons );
+                    }
+                  }
+                }
+              }
+            }
+            // recurse
+            staticLearnRedundantOps( c, itts->second.d_cenum[i], visited, redundant_c, lemmas, ind+2 );
+          }
+        }
+      }
+    }
+  }else{
+    indent("sygus-unif", ind);
+    Trace("sygus-unif") << e << std::endl;
+  }
+  if( !redundant.empty() ){
+    // TODO : if this becomes more general, must get master enumerator here
+    if( itn->second.d_enum_slave.size()==1 ){
+      for( unsigned i=0; i<redundant.size(); i++ ){
+        int cindex = Datatype::indexOf( redundant[i].toExpr() );
+        Assert( cindex!=-1 );
+        const Datatype& dt = Datatype::datatypeOf( redundant[i].toExpr() );
+        Node tst = datatypes::DatatypesRewriter::mkTester( e, cindex, dt ).negate();
+        if( std::find( lemmas.begin(), lemmas.end(), tst )==lemmas.end() ){
+          lemmas.push_back( tst );
+        }
+      }
+    }
+  }
+}
+
+
+// ------------------------------------------- solution construction from enumeration
+
+void CegConjecturePbe::getCandidateList( std::vector< Node >& candidates, std::vector< Node >& clist ) {
+  for( unsigned i=0; i<candidates.size(); i++ ){
+    Node v = candidates[i];
+    std::map< Node, CandidateInfo >::iterator it = d_cinfo.find( v );
+    if( it!=d_cinfo.end() ){
+      for( unsigned j=0; j<it->second.d_esym_list.size(); j++ ){
+        Node e = it->second.d_esym_list[j];
+        std::map< Node, EnumInfo >::iterator it = d_einfo.find( e );
+        Assert( it != d_einfo.end() );
+        if( getGuardStatus( it->second.d_active_guard )==1 ){
+          clist.push_back( e );
+        }
+      }
+    }
+  }
+}
+
+bool CegConjecturePbe::constructCandidates( std::vector< Node >& enums, std::vector< Node >& enum_values, 
+                                            std::vector< Node >& candidates, std::vector< Node >& candidate_values, 
+                                            std::vector< Node >& lems ) {
+  Assert( enums.size()==enum_values.size() );
+  if( !enums.empty() ){
+    unsigned min_term_size = 0;
+    std::vector< unsigned > enum_consider;
+    Trace("sygus-pbe-enum") << "Register new enumerated values : " << std::endl;
+    for( unsigned i=0; i<enums.size(); i++ ){
+      Trace("sygus-pbe-enum") << "  " << enums[i] << " -> " << enum_values[i] << std::endl;
+      unsigned sz = d_tds->getSygusTermSize( enum_values[i] );
+      if( i==0 || sz<min_term_size ){
+        enum_consider.clear();
+        min_term_size = sz;
+        enum_consider.push_back( i );
+      }else if( sz==min_term_size ){
+        enum_consider.push_back( i );
+      }
+    }
+    // only consider the enumerators that are at minimum size (for fairness)
+    Trace("sygus-pbe-enum") << "...register " << enum_consider.size() << " / " << enums.size() << std::endl;
+    for( unsigned i=0; i<enum_consider.size(); i++ ){
+      unsigned j = enum_consider[i];
+      addEnumeratedValue( enums[j], enum_values[j], lems );
+    }
+  }
+  for( unsigned i=0; i<candidates.size(); i++ ){
+    Node c = candidates[i];
+    //build decision tree for candidate
+    Node vc = constructSolution( c );
+    if( vc.isNull() ){     
+      return false;
+    }else{
+      candidate_values.push_back( vc );
+    }
+  }
+  return true;
+}
+
+void CegConjecturePbe::addEnumeratedValue( Node x, Node v, std::vector< Node >& lems ) {
+  std::map< Node, EnumInfo >::iterator it = d_einfo.find( x );
+  Assert( it != d_einfo.end() );
+  if( getGuardStatus( it->second.d_active_guard )==1 ){
+    Assert( std::find( it->second.d_enum_vals.begin(), it->second.d_enum_vals.end(), v )==it->second.d_enum_vals.end() );
+    Node c = it->second.d_parent_candidate;
+    Node exp_exc;
+    if( d_examples_out_invalid.find( c )==d_examples_out_invalid.end() ){
+      std::map< Node, CandidateInfo >::iterator itc = d_cinfo.find( c );
+      Assert( itc != d_cinfo.end() );      
+      TypeNode xtn = x.getType();
+      Node bv = d_tds->sygusToBuiltin( v, xtn );
+      std::map< Node, std::vector< std::vector< Node > > >::iterator itx = d_examples.find( c );
+      std::map< Node, std::vector< Node > >::iterator itxo = d_examples_out.find( c );
+      Assert( itx!=d_examples.end() );
+      Assert( itxo!=d_examples_out.end() );
+      Assert( itx->second.size()==itxo->second.size() );
+      // notify all slaves
+      Assert( !it->second.d_enum_slave.empty() );
+      //explanation for why this value should be excluded
+      for( unsigned s=0; s<it->second.d_enum_slave.size(); s++ ){
+        Node xs = it->second.d_enum_slave[s];
+        std::map< Node, EnumInfo >::iterator itv = d_einfo.find( xs );
+        Assert( itv!=d_einfo.end() );
+        Trace("sygus-pbe-enum") << "Process " << xs << " from " << s << std::endl;
+        //bool prevIsCover = false;
+        if( itv->second.d_role==enum_io ){
+          Trace("sygus-pbe-enum") << "   IO-Eval of ";
+          //prevIsCover = itv->second.isFeasible();
+        }else{
+          Trace("sygus-pbe-enum") << "Evaluation of ";
+        }
+        Trace("sygus-pbe-enum")  << xs <<  " : ";
+        //evaluate all input/output examples
+        std::vector< Node > results;
+        Node templ = itv->second.d_template;
+        TNode templ_var = itv->second.d_template_arg;
+        std::map< Node, bool > cond_vals;
+        for( unsigned j=0; j<itx->second.size(); j++ ){
+          Node res = d_tds->evaluateBuiltin( xtn, bv, itx->second[j] );
+          Trace("sygus-pbe-enum-debug") << "...got res = " << res << " from " << bv << std::endl;
+          Assert( res.isConst() );
+          if( !templ.isNull() ){
+            TNode tres = res;
+            res = templ.substitute( templ_var, res );
+            res = Rewriter::rewrite( res );
+            Assert( res.isConst() );
+          }
+          Node resb;
+          if( itv->second.d_role==enum_io ){
+            Node out = itxo->second[j];
+            Assert( out.isConst() );
+            resb = res==out ? d_true : d_false;
+          }else{
+            resb = res;
+          }
+          cond_vals[resb] = true;
+          results.push_back( resb );
+          if( Trace.isOn("sygus-pbe-enum") ){
+            if( resb.getType().isBoolean() ){
+              Trace("sygus-pbe-enum") << ( resb==d_true ? "1" : "0" );
+            }else{
+              Trace("sygus-pbe-enum") << "?";
+            }
+          }
+        }
+        bool keep = false;
+        if( itv->second.d_role==enum_io ){
+          if( cond_vals.find( d_true )!=cond_vals.end() || cond_vals.empty() ){  // latter is the degenerate case of no examples
+            //check subsumbed/subsuming
+            std::vector< Node > subsume;
+            if( cond_vals.find( d_false )==cond_vals.end() ){
+              // it is the entire solution, we are done
+              Trace("sygus-pbe-enum") << "  ...success, full solution added to PBE pool : " << d_tds->sygusToBuiltin( v ) << std::endl;
+              if( !itv->second.isSolved() ){
+                itv->second.setSolved( v );
+                // it subsumes everything
+                itv->second.d_term_trie.clear();
+                itv->second.d_term_trie.addTerm( this, v, results, true, subsume );
+              }
+              keep = true;
+            }else{
+              Node val = itv->second.d_term_trie.addTerm( this, v, results, true, subsume );
+              if( val==v ){
+                Trace("sygus-pbe-enum") << "  ...success"; 
+                if( !subsume.empty() ){
+                  itv->second.d_enum_subsume.insert( itv->second.d_enum_subsume.end(), subsume.begin(), subsume.end() );
+                  Trace("sygus-pbe-enum") << " and subsumed " << subsume.size() << " terms";
+                }
+                Trace("sygus-pbe-enum") << "!   add to PBE pool : " << d_tds->sygusToBuiltin( v ) << std::endl;
+                keep = true;
+              }else{
+                Assert( subsume.empty() );
+                Trace("sygus-pbe-enum") << "  ...fail : subsumed" << std::endl;
+              }
+            }
+          }else{
+            Trace("sygus-pbe-enum") << "  ...fail : it does not satisfy examples." << std::endl;
+          }
+        }else{
+          // is it excluded for domain-specific reason?
+          std::vector< Node > exp_exc_vec;
+          if( getExplanationForEnumeratorExclude( c, x, v, results, it->second, exp_exc_vec ) ){
+            Assert( !exp_exc_vec.empty() );
+            exp_exc = exp_exc_vec.size()==1 ? exp_exc_vec[0] : NodeManager::currentNM()->mkNode( kind::AND, exp_exc_vec );
+            Trace("sygus-pbe-enum") << "  ...fail : term is excluded (domain-specific)" << std::endl;
+          }else{
+            //if( cond_vals.size()!=2 ){
+            //  // must discriminate
+            //  Trace("sygus-pbe-enum") << "  ...fail : conditional is constant." << std::endl;
+            //  keep = false;
+            //}
+            // must be unique up to examples
+            Node val = itv->second.d_term_trie.addCond( this, v, results, true );
+            if( val==v ){
+              Trace("sygus-pbe-enum") << "  ...success!   add to PBE pool : " << d_tds->sygusToBuiltin( v ) << std::endl;
+              keep = true;
+            }else{
+              Trace("sygus-pbe-enum") << "  ...fail : term is not unique" << std::endl;
+            }
+            itc->second.d_cond_count++;
+          }
+        }
+        if( keep ){
+          // notify the parent to retry the build of PBE
+          itc->second.d_check_sol = true;
+          itv->second.addEnumValue( this, v, results );
+          /*
+          if( Trace.isOn("sygus-pbe-enum") ){
+            if( itv->second.d_role==enum_io ){
+              if( !prevIsCover && itv->second.isFeasible() ){
+                Trace("sygus-pbe-enum") << "...PBE : success : Evaluation of " << xs << " now covers all examples." << std::endl;
+              }
+            }
+          }
+          */
+        }
+      }
+    }else{
+      Trace("sygus-pbe-enum-debug") << "  ...examples do not have output." << std::endl;
+    }
+    //exclude this value on subsequent iterations
+    Node g = it->second.d_active_guard;
+    if( exp_exc.isNull() ){
+      // if we did not already explain why this should be excluded, use default
+      exp_exc = d_tds->getExplanationForConstantEquality( x, v );
+    }
+    Node exlem = NodeManager::currentNM()->mkNode( kind::OR, g.negate(), exp_exc.negate() );
+    Trace("sygus-pbe-enum-lemma") << "CegConjecturePbe : enumeration exclude lemma : " << exlem << std::endl;
+    lems.push_back( exlem );
+  }else{
+    Trace("sygus-pbe-enum-debug") << "  ...guard is inactive." << std::endl;
+  }
+}
+
+
+
+class NegContainsSygusInvarianceTest : public quantifiers::SygusInvarianceTest {
+public:
+  NegContainsSygusInvarianceTest(){}
+  ~NegContainsSygusInvarianceTest(){}
+  Node d_ar;
+  std::vector< Node > d_exo;
+  std::vector< unsigned > d_neg_con_indices;
+  
+  void init( quantifiers::TermDbSygus * tds, Node ar, std::vector< Node >& exo, std::vector< unsigned >& ncind ) {
+    if( tds->hasPbeExamples( ar ) ){
+      Assert( tds->getNumPbeExamples( ar )==exo.size() );
+      d_ar = ar;
+      d_exo.insert( d_exo.end(), exo.begin(), exo.end() );
+      d_neg_con_indices.insert( d_neg_con_indices.end(), ncind.begin(), ncind.end() );
+    }
+  }
+protected:  
+  bool invariant( quantifiers::TermDbSygus * tds, Node nvn, Node x ){
+    if( !d_ar.isNull() ){
+      TypeNode tn = nvn.getType();
+      Node nbv = tds->sygusToBuiltin( nvn, tn );
+      Node nbvr = tds->extendedRewrite( nbv );
+      // if for any of the examples, it is not contained, then we can exclude
+      for( unsigned i=0; i<d_neg_con_indices.size(); i++ ){
+        unsigned ii = d_neg_con_indices[i];
+        Assert( ii<d_exo.size() );
+        Node nbvre = tds->evaluateBuiltin( tn, nbvr, d_ar, ii );
+        Node out = d_exo[ii];
+        Node cont = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, out, nbvre );
+        Node contr = Rewriter::rewrite( cont );
+        if( contr==tds->d_false ){
+          if( Trace.isOn("sygus-pbe-cterm") ){
+            Trace("sygus-pbe-cterm") << "PBE-cterm : enumerator : do not consider ";
+            Trace("sygus-pbe-cterm") << nbv << " for any " << tds->sygusToBuiltin( x ) << " since " << std::endl;
+            Trace("sygus-pbe-cterm") << "   PBE-cterm :    for input example : ";
+            std::vector< Node > ex;
+            tds->getPbeExample( d_ar, ii, ex );
+            for( unsigned j=0; j<ex.size(); j++ ){
+              Trace("sygus-pbe-cterm") << ex[j] << " ";
+            }
+            Trace("sygus-pbe-cterm") << std::endl;
+            Trace("sygus-pbe-cterm") << "   PBE-cterm :     this rewrites to : " << nbvre << std::endl;
+            Trace("sygus-pbe-cterm") << "   PBE-cterm : and is not in output : " << out << std::endl;
+          }
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+};
+
+
+bool CegConjecturePbe::getExplanationForEnumeratorExclude( Node c, Node x, Node v, std::vector< Node >& results, EnumInfo& ei, std::vector< Node >& exp ) {
+  if( ei.d_enum_slave.size()==1 ){
+    // this check whether the example evaluates to something that is larger than the output
+    //  if so, then this term is never useful when using a concatenation strategy
+    if( ei.d_role==enum_concat_term ){
+      if( Trace.isOn("sygus-pbe-cterm-debug") ){
+        Trace("sygus-pbe-enum") << std::endl;
+      }
+
+      // check if all examples had longer length that the output
+      std::map< Node, std::vector< Node > >::iterator itxo = d_examples_out.find( c );
+      Assert( itxo!=d_examples_out.end() );
+      Assert( itxo->second.size()==results.size() );
+      Trace("sygus-pbe-cterm-debug") << "Check enumerator exclusion for " << x << " -> " << d_tds->sygusToBuiltin( v ) << " based on containment." << std::endl;
+      std::vector< unsigned > cmp_indices;
+      for( unsigned i=0; i<results.size(); i++ ){
+        Assert( results[i].isConst() );
+        Assert( itxo->second[i].isConst() );
+        /*
+        unsigned vlen = results[i].getConst<String>().size();
+        unsigned xlen = itxo->second[i].getConst<String>().size();
+        Trace("sygus-pbe-cterm-debug") << "  " << results[i] << " <> " << itxo->second[i];
+        int index = vlen>xlen ? 1 : ( vlen<xlen ? -1 : 0 );
+        Trace("sygus-pbe-cterm-debug") << "..." << index << std::endl;
+        cmp_indices[index].push_back( i );
+        */
+        Trace("sygus-pbe-cterm-debug") << "  " << results[i] << " <> " << itxo->second[i];
+        Node cont = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, itxo->second[i], results[i] );
+        Node contr = Rewriter::rewrite( cont );
+        if( contr==d_false ){
+          cmp_indices.push_back( i );
+          Trace("sygus-pbe-cterm-debug") << "...not contained." << std::endl;
+        }else{
+          Trace("sygus-pbe-cterm-debug") << "...contained." << std::endl;
+        }
+      }
+      // TODO : stronger requirement if we incorporate ITE + CONCAT mixed strategy : must be longer than *all* examples
+      if( !cmp_indices.empty() ){
+        //set up the inclusion set
+        NegContainsSygusInvarianceTest ncset;
+        ncset.init( d_tds, c, itxo->second, cmp_indices );
+        d_tds->getExplanationFor( x, v, exp, ncset );
+        Trace("sygus-pbe-cterm") << "PBE-cterm : enumerator exclude " << d_tds->sygusToBuiltin( v ) << " due to negative containment." << std::endl;
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+
+
+void CegConjecturePbe::EnumInfo::addEnumValue( CegConjecturePbe * pbe, Node v, std::vector< Node >& results ) {
+  d_enum_val_to_index[v] = d_enum_vals.size();
+  d_enum_vals.push_back( v );
+  d_enum_vals_res.push_back( results );
+  /*
+  if( d_role==enum_io ){
+    // compute 
+    if( d_enum_total.empty() ){
+      d_enum_total = results;
+    }else if( !d_enum_total_true ){
+      d_enum_total_true = true;
+      Assert( d_enum_total.size()==results.size() );
+      for( unsigned i=0; i<results.size(); i++ ){
+        if( d_enum_total[i]==pbe->d_true || results[i]==pbe->d_true ){
+          d_enum_total[i] = pbe->d_true;
+        }else{
+          d_enum_total[i] = pbe->d_false;
+          d_enum_total_true = false;
+        }
+      }
+    }
+  }
+  */
+}
+
+void CegConjecturePbe::EnumInfo::setSolved( Node slv ) {
+  d_enum_solved = slv;
+  //d_enum_total_true = true;
+}
+    
+void CegConjecturePbe::CandidateInfo::initialize( Node c ) {
+  d_this_candidate = c;
+  d_root = c.getType();
+}
+
+void CegConjecturePbe::CandidateInfo::initializeType( TypeNode tn ) {
+  d_tinfo[tn].d_this_type = tn;
+  d_tinfo[tn].d_parent = this;
+}
+
+Node CegConjecturePbe::CandidateInfo::getRootEnumerator() {
+  std::map< unsigned, Node >::iterator it = d_tinfo[d_root].d_enum.find( enum_io );
+  Assert( it!=d_tinfo[d_root].d_enum.end() );
+  return it->second;
+}
+
+bool CegConjecturePbe::CandidateInfo::isNonTrivial() {
+  //TODO
+  return true;
+}
+
+// status : 0 : exact, -1 : vals is subset, 1 : vals is superset
+Node CegConjecturePbe::SubsumeTrie::addTermInternal( CegConjecturePbe * pbe, Node t, std::vector< Node >& vals, bool pol, 
+                                                     std::vector< Node >& subsumed, bool spol, IndexFilter * f, 
+                                                     unsigned index, int status, bool checkExistsOnly, bool checkSubsume ) {
+  if( index==vals.size() ){
+    if( status==0 ){
+      // set the term if checkExistsOnly = false
+      if( d_term.isNull() && !checkExistsOnly ){
+        d_term = t;
+      }
+    }else if( status==1 ){
+      Assert( checkSubsume );
+      // found a subsumed term
+      if( !d_term.isNull() ){
+        subsumed.push_back( d_term );
+        if( !checkExistsOnly ){
+          // remove it if checkExistsOnly = false
+          d_term = Node::null();
+        }
+      }
+    }else{
+      Assert( !checkExistsOnly && checkSubsume );
+    }
+    return d_term;
+  }else{
+    // the current value 
+    Assert( pol || ( vals[index].isConst() && vals[index].getType().isBoolean() ) );
+    Node cv = pol ? vals[index] : ( vals[index]==pbe->d_true ? pbe->d_false : pbe->d_true );
+    // if checkExistsOnly = false, check if the current value is subsumed if checkSubsume = true, if so, don't add
+    if( !checkExistsOnly && checkSubsume ){
+      std::vector< bool > check_subsumed_by;
+      if( status==0 ){
+        if( cv==pbe->d_false ){
+          check_subsumed_by.push_back( spol );
+        }
+      }else if( status==-1 ){
+        check_subsumed_by.push_back( spol );
+        if( cv==pbe->d_false ){
+          check_subsumed_by.push_back( !spol );
+        }
+      }
+      // check for subsumed nodes
+      for( unsigned i=0; i<check_subsumed_by.size(); i++ ){
+        Node csval = check_subsumed_by[i] ? pbe->d_true : pbe->d_false;
+        // check if subsumed
+        std::map< Node, SubsumeTrie >::iterator itc = d_children.find( csval );
+        if( itc!=d_children.end() ){
+          unsigned next_index = f ? f->next( index ) : index+1;
+          Node ret = itc->second.addTermInternal( pbe, t, vals, pol, subsumed, spol, f, next_index, -1, checkExistsOnly, checkSubsume );
+          // ret subsumes t
+          if( !ret.isNull() ){
+            return ret;
+          }
+        }
+      }
+    }
+    Node ret;
+    std::vector< bool > check_subsume;
+    if( status==0 ){
+      unsigned next_index = f ? f->next( index ) : index+1;
+      if( checkExistsOnly ){
+        std::map< Node, SubsumeTrie >::iterator itc = d_children.find( cv );
+        if( itc!=d_children.end() ){
+          ret = itc->second.addTermInternal( pbe, t, vals, pol, subsumed, spol, f, next_index, 0, checkExistsOnly, checkSubsume );
+        }
+      }else{
+        Assert( spol );
+        ret = d_children[cv].addTermInternal( pbe, t, vals, pol, subsumed, spol, f, next_index, 0, checkExistsOnly, checkSubsume );
+        if( ret!=t ){
+          // we were subsumed by ret, return
+          return ret;
+        }
+      }
+      if( checkSubsume ){
+        // check for subsuming
+        if( cv==pbe->d_true ){
+          check_subsume.push_back( !spol );
+        }
+      }
+    }else if( status==1 ){
+      Assert( checkSubsume );
+      check_subsume.push_back( !spol );
+      if( cv==pbe->d_true ){
+        check_subsume.push_back( spol );
+      }
+    }
+    if( checkSubsume ){
+      // check for subsumed terms
+      for( unsigned i=0; i<check_subsume.size(); i++ ){
+        Node csval = check_subsume[i] ? pbe->d_true : pbe->d_false;
+        std::map< Node, SubsumeTrie >::iterator itc = d_children.find( csval );
+        if( itc!=d_children.end() ){
+          unsigned next_index = f ? f->next( index ) : index+1;
+          itc->second.addTermInternal( pbe, t, vals, pol, subsumed, spol, f, next_index, 1, checkExistsOnly, checkSubsume );
+          // clean up
+          if( itc->second.isEmpty() ){
+            Assert( !checkExistsOnly );
+            d_children.erase( csval );
+          }
+        }
+      }
+    }
+    return ret;
+  }
+}
+
+Node CegConjecturePbe::SubsumeTrie::addTerm( CegConjecturePbe * pbe, Node t, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed, IndexFilter * f ) {
+  unsigned start_index = f ? f->start() : 0;
+  return addTermInternal( pbe, t, vals, pol, subsumed, true, f, start_index, 0, false, true );
+}
+
+Node CegConjecturePbe::SubsumeTrie::addCond( CegConjecturePbe * pbe, Node c, std::vector< Node >& vals, bool pol, IndexFilter * f ) {
+  unsigned start_index = f ? f->start() : 0;
+  std::vector< Node > subsumed;
+  return addTermInternal( pbe, c, vals, pol, subsumed, true, f, start_index, 0, false, false );
+}
+
+void CegConjecturePbe::SubsumeTrie::getSubsumed( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed, IndexFilter * f ){
+  unsigned start_index = f ? f->start() : 0;
+  addTermInternal( pbe, Node::null(), vals, pol, subsumed, true, f, start_index, 1, true, true );
+}
+
+void CegConjecturePbe::SubsumeTrie::getSubsumedBy( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed_by, IndexFilter * f ){
+  // flip polarities
+  unsigned start_index = f ? f->start() : 0;
+  addTermInternal( pbe, Node::null(), vals, !pol, subsumed_by, false, f, start_index, 1, true, true );
+}
+
+void CegConjecturePbe::SubsumeTrie::getLeavesInternal( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::map< int, std::vector< Node > >& v, 
+                                                       IndexFilter * f, unsigned index, int status ) {
+  if( index==vals.size() ){
+    Assert( !d_term.isNull() );
+    Assert( std::find( v[status].begin(), v[status].end(), d_term )==v[status].end() );
+    v[status].push_back( d_term );
+  }else{
+    Assert( vals[index].isConst() && vals[index].getType().isBoolean() );
+    // filter should be for cv
+    Assert( f==NULL || vals[index]==( pol ? pbe->d_true : pbe->d_false ) );
+    for( std::map< Node, SubsumeTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+      int new_status = status;
+      // if the current value is true
+      if( vals[index]==( pol ? pbe->d_true : pbe->d_false ) ){
+        if( status!=0 ){
+          new_status = ( it->first == pbe->d_true ? 1 : -1 );
+          if( status!=-2 && new_status!=status ){
+            new_status = 0;
+          }
+        }
+      }
+      unsigned next_index = f ? f->next( index ) : index+1;
+      it->second.getLeavesInternal( pbe, vals, pol, v, f, next_index, new_status );
+    }
+  }
+}
+
+void CegConjecturePbe::SubsumeTrie::getLeaves( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::map< int, std::vector< Node > >& v, IndexFilter * f ) {
+  unsigned start_index = f ? f->start() : 0;
+  getLeavesInternal( pbe, vals, pol, v, f, start_index, -2 );
+}
+
+void CegConjecturePbe::IndexFilter::mk( std::vector< Node >& vals, bool pol ) {
+  Trace("sygus-pbe-debug") << "Make for : ";
+  print_val( "sygus-pbe-debug", vals, pol );
+  Trace("sygus-pbe-debug") << std::endl;
+  Node poln = NodeManager::currentNM()->mkConst( pol );
+  
+  unsigned curr_index = 0;
+  while( curr_index<vals.size() && vals[curr_index]!=poln ){
+    curr_index++;
+  }
+  d_next[0] = curr_index;
+  Trace("sygus-pbe-debug") << "0 -> " << curr_index << std::endl;
+  unsigned i = curr_index;
+  while( i<vals.size() ){
+    while( i<vals.size() && vals[i]!=poln ){
+      i++;
+    }
+    i++;
+    d_next[curr_index+1] = i;
+    Trace("sygus-pbe-debug") << curr_index+1 << " -> " << i << std::endl;
+    curr_index = i;
+  }
+  
+  // verify it is correct
+  unsigned j = start();
+  for( unsigned k=0; k<j; k++ ){
+    AlwaysAssert( vals[k]!=poln );
+  }
+  Trace("sygus-pbe-debug") << "...start : " << j << std::endl;
+  unsigned counter = 0;
+  while( j<vals.size() ){
+    Trace("sygus-pbe-debug") << "...at : " << j << std::endl;
+    AlwaysAssert( vals[j]==poln );
+    unsigned jj = next( j );
+    AlwaysAssert( jj>j );
+    for( unsigned k=(j+1); k<jj; k++ ){
+      AlwaysAssert( vals[k]!=poln );
+    }
+    AlwaysAssert( counter<=vals.size() );
+    counter++;
+    j = jj;
+  }
+  
+  
+}
+
+unsigned CegConjecturePbe::IndexFilter::start() {
+  std::map< unsigned, unsigned >::iterator it = d_next.find( 0 );
+  if( it==d_next.end() ){
+    return 0;
+  }else{
+    return it->second;
+  }
+}
+
+unsigned CegConjecturePbe::IndexFilter::next( unsigned i ) {
+  std::map< unsigned, unsigned >::iterator it = d_next.find( i+1 );
+  if( it==d_next.end() ){
+    return i+1;
+  }else{
+    return it->second;
+  }      
+}
+
+bool CegConjecturePbe::IndexFilter::isEq( std::vector< Node >& vals, Node v ) {
+  unsigned index = start();
+  while( index<vals.size() ){
+    if( vals[index]!=v ){
+      return false;
+    }
+    index = next( index );
+  }
+  return true;
+}
+
+Node CegConjecturePbe::constructSolution( Node c ){
+  std::map< Node, CandidateInfo >::iterator itc = d_cinfo.find( c );
+  Assert( itc!=d_cinfo.end() );
+  if( !itc->second.d_solution.isNull() ){
+    // already has a solution
+    return itc->second.d_solution;
+  }else{
+    // only check if an enumerator updated
+    if( itc->second.d_check_sol ){
+      Trace("sygus-pbe") << "Construct solution, #iterations = " << itc->second.d_cond_count << std::endl;
+      itc->second.d_check_sol = false;
+      // try multiple times if we have done multiple conditions, due to non-determinism
+      Node vc;
+      for( unsigned i=0; i<=itc->second.d_cond_count; i++ ){
+        Trace("sygus-pbe-dt") << "ConstructPBE for candidate: " << c << std::endl;
+        Node e = itc->second.getRootEnumerator();
+        UnifContext x;
+        x.initialize( this, c );
+        Node vcc = constructSolution( c, e, x, 1 );
+        if( !vcc.isNull() ){
+          if( vc.isNull() || ( !vc.isNull() && d_tds->getSygusTermSize( vcc )<d_tds->getSygusTermSize( vc ) ) ){
+            Trace("sygus-pbe") << "**** PBE SOLVED : " << c << " = " << vcc << std::endl;
+            Trace("sygus-pbe") << "...solved at iteration " << i << std::endl;
+            vc = vcc;
+          }
+        }
+      }
+      if( !vc.isNull() ){
+        itc->second.d_solution = vc;
+        return vc;
+      }
+      Trace("sygus-pbe") << "...failed to solve." << std::endl;
+    }
+    return Node::null();
+  }
+}
+
+Node CegConjecturePbe::constructBestSolvedTerm( std::vector< Node >& solved, UnifContext& x ){
+  Assert( !solved.empty() );
+  // TODO
+  return solved[0];
+}
+
+Node CegConjecturePbe::constructBestStringSolvedTerm( std::vector< Node >& solved, UnifContext& x ) {
+  Assert( !solved.empty() );
+  // TODO
+  return solved[0];
+}
+
+Node CegConjecturePbe::constructBestSolvedConditional( std::vector< Node >& solved, UnifContext& x ){
+  Assert( !solved.empty() );
+  // TODO
+  return solved[0];
+}
+
+Node CegConjecturePbe::constructBestConditional( std::vector< Node >& conds, UnifContext& x ) {
+  Assert( !conds.empty() );
+  // TODO
+  double r = (double)(rand())/((double)(RAND_MAX));
+  unsigned cindex = r*conds.size();
+  if( cindex>conds.size() ){
+    cindex = conds.size() - 1;
+  }
+  return conds[cindex];
+}
+
+Node CegConjecturePbe::constructBestStringToConcat( std::vector< Node > strs,
+                                                    std::map< Node, unsigned > total_inc, 
+                                                    std::map< Node, std::vector< unsigned > > incr,
+                                                    UnifContext& x ) {
+  Assert( !strs.empty() );
+  // TODO
+  double r = (double)(rand())/((double)(RAND_MAX));
+  unsigned cindex = r*strs.size();
+  if( cindex>strs.size() ){
+    cindex = strs.size() - 1;
+  }
+  return strs[cindex];
+}                         
+                                    
+Node CegConjecturePbe::constructSolution( Node c, Node e, UnifContext& x, int ind ) {
+  indent("sygus-pbe-dt-debug", ind);
+  Trace("sygus-pbe-dt-debug") << "ConstructPBE: enum: " << e << " in context ";
+  print_val("sygus-pbe-dt-debug", x.d_vals);
+  Trace("sygus-pbe-dt-debug") << std::endl;
+  std::map< Node, EnumInfo >::iterator itn = d_einfo.find( e );
+  Assert( itn!=d_einfo.end() );
+  Node ret_dt;
+  if( itn->second.d_role==enum_any ){
+    indent("sygus-pbe-dt", ind);
+    ret_dt = constructBestSolvedTerm( itn->second.d_enum_vals, x );
+    Trace("sygus-pbe-dt") << "return PBE: success : use any " << d_tds->sygusToBuiltin( ret_dt ) << std::endl;
+    Assert( !ret_dt.isNull() );
+  }else if( itn->second.d_role==enum_io && !x.isReturnValueModified() && itn->second.isSolved() ){
+    // this type has a complete solution
+    ret_dt = itn->second.getSolved();
+    indent("sygus-pbe-dt", ind);
+    Trace("sygus-pbe-dt") << "return PBE: success : solved " << d_tds->sygusToBuiltin( ret_dt ) << std::endl;
+    Assert( !ret_dt.isNull() );
+  }else{
+    TypeNode etn = e.getType();
+    std::map< TypeNode, EnumTypeInfo >::iterator itt = d_cinfo[c].d_tinfo.find( etn );
+    Assert( itt!=d_cinfo[c].d_tinfo.end() );
+    if( d_tds->sygusToBuiltinType( e.getType() ).isString() ){
+      // check if a current value that closes all examples
+      
+      // get the term enumerator for this type
+      bool success = true;
+      std::map< Node, EnumInfo >::iterator itet;
+      if( itn->second.d_role==enum_concat_term ){
+        itet = itn;
+      }else{
+        std::map< unsigned, Node >::iterator itnt = itt->second.d_enum.find( enum_concat_term );
+        if( itnt != itt->second.d_enum.end() ){
+          Node et = itnt->second;
+          itet = d_einfo.find( et );
+        }else{
+          success = false;
+        }
+      }
+      if( success ){
+        Assert( itet!=d_einfo.end() );
+
+        // get the current examples
+        std::map< Node, std::vector< Node > >::iterator itx = d_examples_out.find( c );
+        Assert( itx!=d_examples_out.end() );
+        std::vector< CVC4::String > ex_vals;
+        x.getCurrentStrings( this, itx->second, ex_vals );
+        Assert( itn->second.d_enum_vals.size()==itn->second.d_enum_vals_res.size() );
+        
+        // test each example in the term enumerator for the type
+        std::vector< Node > str_solved;
+        for( unsigned i=0; i<itet->second.d_enum_vals.size(); i++ ){
+          if( x.isStringSolved( this, ex_vals, itet->second.d_enum_vals_res[i] ) ){
+            str_solved.push_back( itet->second.d_enum_vals[i] );
+          }
+        }
+        if( !str_solved.empty() ){
+          ret_dt = constructBestStringSolvedTerm( str_solved, x );
+          indent("sygus-pbe-dt", ind);
+          Trace("sygus-pbe-dt") << "return PBE: success : string solved " << d_tds->sygusToBuiltin( ret_dt ) << std::endl;
+        }else{
+          indent("sygus-pbe-dt-debug", ind);
+          Trace("sygus-pbe-dt-debug") << "  ...not currently string solved." << std::endl;
+        }
+      }
+    }else if( itn->second.d_role==enum_io && !x.isReturnValueModified() ){
+      // it has an enumerated value that is conditionally correct under the current assumptions
+      std::vector< Node > subsumed_by;
+      itn->second.d_term_trie.getSubsumedBy( this, x.d_vals, true, subsumed_by );
+      if( !subsumed_by.empty() ){
+        ret_dt = constructBestSolvedTerm( subsumed_by, x );
+        indent("sygus-pbe-dt", ind);
+        Trace("sygus-pbe-dt") << "return PBE: success : conditionally solved" << d_tds->sygusToBuiltin( ret_dt ) << std::endl;
+      }else{
+        indent("sygus-pbe-dt-debug", ind);
+        Trace("sygus-pbe-dt-debug") << "  ...not currently conditionally solved." << std::endl;
+      }
+    }
+    if( ret_dt.isNull() ){
+      if( !itn->second.isTemplated() ){
+        // try to construct a compound solution, if strategies are available
+        
+        // do various strategies 
+        for( std::map< Node, EnumTypeInfoStrat >::iterator itts = itt->second.d_strat.begin(); itts!=itt->second.d_strat.end(); ++itts ){
+          std::map< unsigned, Node > dt_children_cons;
+          unsigned strat = itts->second.d_this;
+          
+          bool success = true;
+          
+          // for ITE
+          std::map< unsigned, Node > look_ahead_solved_children;
+          Node split_cond_enum;
+          int split_cond_res_index = -1;
+          
+          //for CONCAT
+          Node incr_val;
+          int incr_type = 0;
+          std::map< Node, std::vector< unsigned > > incr;
+            
+          // construct the child order
+          std::vector< unsigned > corder;
+          if( strat==strat_CONCAT ){
+            for( unsigned r=0; r<2; r++ ){
+              unsigned sc = r==0 ? 0 : itts->second.d_cenum.size()-1;
+              Node ce = itts->second.d_cenum[sc];
+              if( ce.getType()==etn ){
+                // prefer simple recursion (self type)
+                Assert( d_einfo.find( ce )!=d_einfo.end() );
+                Assert( d_einfo[ce].d_role==enum_concat_term );
+                corder.push_back( sc );
+                unsigned inc = r==0 ? 1 : -1;
+                unsigned scc = sc + inc;
+                while( scc>=0 && scc<itts->second.d_cenum.size() ){
+                  corder.push_back( scc );
+                  scc = scc + inc;
+                }
+                break;
+              }
+            }
+          }else{
+            for( unsigned sc=0; sc<itts->second.d_cenum.size(); sc++ ){
+              corder.push_back( sc );
+            }
+          }    
+          Assert( corder.size()==itts->second.d_cenum.size() );
+            
+            
+          for( unsigned scc=0; scc<corder.size(); scc++ ){
+            unsigned sc = corder[scc];
+            Node rec_c;
+            indent("sygus-pbe-dt", ind);
+            Trace("sygus-pbe-dt") << "construct PBE child #" << sc << "..." << std::endl;
+            std::map< unsigned, Node >::iterator itla = look_ahead_solved_children.find( sc );
+            if( itla!=look_ahead_solved_children.end() ){
+              rec_c = itla->second;
+              indent("sygus-pbe-dt-debug", ind+1);
+              Trace("sygus-pbe-dt-debug") << "ConstructPBE: look ahead solved : " << d_tds->sygusToBuiltin( rec_c ) << std::endl;
+            }else{
+              // get the child enumerator
+              Node ce = itts->second.d_cenum[sc];
+              if( strat==strat_ITE && scc==0 ){
+                Assert( itts->second.d_cenum.size()==3 ); // for now, fix to 3 child ITEs
+                // choose a condition
+                
+                // register the condition enumerator
+                std::map< Node, EnumInfo >::iterator itnc = d_einfo.find( ce );
+                Assert( itnc!=d_einfo.end() );
+                // only used if the return value is not modified
+                if( !x.isReturnValueModified() ){
+                  if( x.d_uinfo.find( ce )==x.d_uinfo.end() ){
+                    Trace("sygus-pbe-dt-debug2") << "  reg : PBE: Look for direct solutions for conditional enumerator " << ce << " ... " << std::endl;
+                    x.d_uinfo[ce].d_status = 0;
+                    Assert( itnc->second.d_enum_vals.size()==itnc->second.d_enum_vals_res.size() );
+                    for( unsigned i=1; i<=2; i++ ){
+                      Node te = itts->second.d_cenum[i];
+                      std::map< Node, EnumInfo >::iterator itnt = d_einfo.find( te );
+                      Assert( itnt!=d_einfo.end() );
+                      bool branch_pol = ( i==1 );
+                      // for each condition, get terms that satisfy it in this branch
+                      for( unsigned k=0; k<itnc->second.d_enum_vals.size(); k++ ){
+                        Node cond = itnc->second.d_enum_vals[k];
+                        std::vector< Node > solved;
+                        itnt->second.d_term_trie.getSubsumedBy( this, itnc->second.d_enum_vals_res[k], branch_pol, solved );
+                        Trace("sygus-pbe-dt-debug2") << "  reg : PBE: " << d_tds->sygusToBuiltin( cond ) << " has " << solved.size() << " solutions in branch " << i << std::endl;
+                        if( !solved.empty() ){
+                          Node slv = constructBestSolvedTerm( solved, x );
+                          Trace("sygus-pbe-dt-debug") << "  reg : PBE: ..." << d_tds->sygusToBuiltin( slv ) << " is a solution under branch " << i;
+                          Trace("sygus-pbe-dt-debug") << " of condition " << d_tds->sygusToBuiltin( cond ) << std::endl;
+                          x.d_uinfo[ce].d_look_ahead_sols[cond][i] = slv;
+                        }
+                      }
+                    }
+                  }
+                }
+                
+                // get the conditionals in the current context : they must be distinguishable
+                std::map< int, std::vector< Node > > possible_cond;
+                std::map< Node, int > solved_cond;  //stores branch
+                itnc->second.d_term_trie.getLeaves( this, x.d_vals, true, possible_cond );
+                
+                std::map< int, std::vector< Node > >::iterator itpc = possible_cond.find( 0 );
+                if( itpc!=possible_cond.end() ){
+                  indent("sygus-pbe-dt-debug", ind);
+                  Trace("sygus-pbe-dt-debug") << "PBE : We have " << itpc->second.size() << " distinguishable conditionals:" << std::endl;       
+                  for( unsigned k=0; k<itpc->second.size(); k++ ){                  
+                    indent("sygus-pbe-dt-debug", ind+1);
+                    Trace("sygus-pbe-dt-debug") << d_tds->sygusToBuiltin( itpc->second[k] ) << std::endl;
+                  }   
+                  
+                
+                  // static look ahead conditional : choose conditionals that have solved terms in at least one branch
+                  //    only applicable if we have not modified the return value
+                  std::map< int, std::vector< Node > > solved_cond;
+                  if( !x.isReturnValueModified() ){
+                    Assert( x.d_uinfo.find( ce )!=x.d_uinfo.end() );
+                    int solve_max = 0;
+                    for( unsigned k=0; k<itpc->second.size(); k++ ){
+                      Node cond = itpc->second[k];
+                      std::map< Node, std::map< unsigned, Node > >::iterator itla = x.d_uinfo[ce].d_look_ahead_sols.find( cond );
+                      if( itla!=x.d_uinfo[ce].d_look_ahead_sols.end() ){
+                        int nsolved = itla->second.size();
+                        solve_max = nsolved > solve_max ? nsolved : solve_max;
+                        solved_cond[nsolved].push_back( cond );
+                      }
+                    }
+                    int n = solve_max;
+                    while( n>0 ){
+                      if( !solved_cond[n].empty() ){
+                        rec_c = constructBestSolvedConditional( solved_cond[n], x );
+                        indent("sygus-pbe-dt", ind);
+                        Trace("sygus-pbe-dt") << "PBE: ITE strategy : choose solved conditional " << d_tds->sygusToBuiltin( rec_c ) << " with " << n << " solved children..." << std::endl;
+                        std::map< Node, std::map< unsigned, Node > >::iterator itla = x.d_uinfo[ce].d_look_ahead_sols.find( rec_c );
+                        Assert( itla!=x.d_uinfo[ce].d_look_ahead_sols.end() );
+                        for( std::map< unsigned, Node >::iterator itla2 = itla->second.begin(); itla2 != itla->second.end(); ++itla2 ){
+                          look_ahead_solved_children[ itla2->first ] = itla2->second;
+                        }
+                        break;
+                      }
+                      n--;
+                    }
+                  }
+                  
+                  // dynamic look ahead conditional : compute if there are any solved terms in this branch  TODO
+                  if( ind>0 ){
+                    
+                  }
+                  
+                  // otherwise, guess a conditional
+                  if( rec_c.isNull() ){
+                    rec_c = constructBestConditional( itpc->second, x );
+                    Assert( !rec_c.isNull() );
+                    indent("sygus-pbe-dt", ind);
+                    Trace("sygus-pbe-dt") << "PBE: ITE strategy : choose random conditional " << d_tds->sygusToBuiltin( rec_c ) << std::endl;
+                  }
+                }else{
+                  // TODO : degenerate case where children have different types
+                  indent("sygus-pbe-dt", ind);
+                  Trace("sygus-pbe-dt") << "return PBE: failed ITE strategy, cannot find a distinguishable condition" << std::endl;
+                }
+                if( !rec_c.isNull() ){
+                  Assert( itnc->second.d_enum_val_to_index.find( rec_c )!=itnc->second.d_enum_val_to_index.end() );
+                  split_cond_res_index = itnc->second.d_enum_val_to_index[rec_c];
+                  split_cond_enum = ce;
+                  Assert( split_cond_res_index>=0 );
+                  Assert( split_cond_res_index<(int)itnc->second.d_enum_vals_res.size() );
+                }
+              }else if( strat==strat_CONCAT && scc==0 ){
+                std::map< Node, EnumInfo >::iterator itsc = d_einfo.find( ce );
+                Assert( itsc!=d_einfo.end() );
+                // ensured by the child order we set above
+                Assert( itsc->second.d_role==enum_concat_term );
+                // check if each return value is a prefix/suffix of all open examples
+                incr_type = sc==0 ? -1 : 1;
+                if( x.d_has_string_pos==0 || x.d_has_string_pos==incr_type ){
+                  bool isPrefix = incr_type==-1;
+                  std::map< Node, unsigned > total_inc;
+                  std::vector< Node > inc_strs;
+                  std::map< Node, std::vector< Node > >::iterator itx = d_examples_out.find( c );
+                  Assert( itx!=d_examples_out.end() );
+                  // make the value of the examples
+                  std::vector< CVC4::String > ex_vals;
+                  x.getCurrentStrings( this, itx->second, ex_vals );
+
+                  // check if there is a value for which is a prefix/suffix of all active examples
+                  Assert( itsc->second.d_enum_vals.size()==itsc->second.d_enum_vals_res.size() );
+                  
+                  for( unsigned i=0; i<itsc->second.d_enum_vals.size(); i++ ){
+                    Node val_t = itsc->second.d_enum_vals[i];
+                    indent("sygus-pbe-dt-debug", ind);
+                    Trace("sygus-pbe-dt-debug") << "increment string values : " << val_t << " : ";
+                    Assert( itsc->second.d_enum_vals_res[i].size()==itx->second.size() );
+                    unsigned tot = 0;
+                    bool exsuccess = x.getStringIncrement( this, isPrefix, ex_vals, itsc->second.d_enum_vals_res[i], incr[val_t], tot );
+                    if( tot==0 ){
+                      exsuccess = false;
+                    }
+                    if( !exsuccess ){
+                      incr.erase( val_t );
+                      Trace("sygus-pbe-dt-debug") << "...fail" << std::endl;
+                    }else{
+                      total_inc[ val_t ] = tot;
+                      inc_strs.push_back( val_t );
+                      Trace("sygus-pbe-dt-debug") << "...success, total increment = " << tot << std::endl;
+                    }
+                  }
+
+                  if( !incr.empty() ){
+                    rec_c = constructBestStringToConcat( inc_strs, total_inc, incr, x );
+                    incr_val = rec_c;
+                    Assert( !rec_c.isNull() );
+                    indent("sygus-pbe-dt", ind);
+                    Trace("sygus-pbe-dt") << "PBE: CONCAT strategy : choose " << ( isPrefix ? "pre" : "suf" ) << "fix value " << d_tds->sygusToBuiltin( rec_c ) << std::endl;
+                  }else{
+                    indent("sygus-pbe-dt", ind);
+                    Trace("sygus-pbe-dt") << "PBE: failed CONCAT strategy, no values are " << ( isPrefix ? "pre" : "suf" ) << "fix of all examples." << std::endl;
+                  }
+                }else{
+                  indent("sygus-pbe-dt", ind);
+                  Trace("sygus-pbe-dt") << "PBE: failed CONCAT strategy, prefix/suffix mismatch." << std::endl;
+                }
+              }else{
+                // a standard term
+                
+                // store previous values
+                std::vector< Node > prev;
+                std::vector< unsigned > prev_str_pos;
+                int prev_has_str_pos = false;
+                // update the context
+                bool ret = false;
+                if( strat==strat_ITE ){
+                  std::map< Node, EnumInfo >::iterator itnc = d_einfo.find( split_cond_enum );
+                  Assert( itnc!=d_einfo.end() );
+                  Assert( split_cond_res_index>=0 );
+                  Assert( split_cond_res_index<(int)itnc->second.d_enum_vals_res.size() );
+                  prev = x.d_vals;
+                  ret = x.updateContext( this, itnc->second.d_enum_vals_res[split_cond_res_index], sc==1 );
+                }else if( strat==strat_CONCAT ){
+                  prev_str_pos = x.d_str_pos;
+                  prev_has_str_pos = x.d_has_string_pos;
+                  Assert( incr.find( incr_val )!=incr.end() );
+                  ret = x.updateStringPosition( this, incr[incr_val] );
+                  x.d_has_string_pos = incr_type;
+                }else if( strat==strat_ID ){
+                  ret = true;
+                }
+                // must have updated the context
+                AlwaysAssert( ret );
+                // recurse
+                rec_c = constructSolution( c, ce, x, ind+1 );
+                if( !rec_c.isNull() ){
+                  //revert context
+                  if( strat==strat_ITE ){
+                    x.d_vals = prev;
+                  }else if( strat==strat_CONCAT ){
+                    x.d_str_pos = prev_str_pos;
+                    x.d_has_string_pos = prev_has_str_pos;
+                  }
+                }
+              }
+            }
+            if( !rec_c.isNull() ){
+              dt_children_cons[sc] = rec_c;
+            }else{
+              success = false;
+              break;
+            }
+          }
+          if( success ){
+            std::vector< Node > dt_children;
+            Assert( !itts->first.isNull() );
+            dt_children.push_back( itts->first );
+            for( unsigned sc=0; sc<itts->second.d_cenum.size(); sc++ ){
+              std::map< unsigned, Node >::iterator itdc = dt_children_cons.find( sc );
+              Assert( itdc!=dt_children_cons.end() );
+              dt_children.push_back( itdc->second );
+            }         
+            ret_dt = NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, dt_children );
+            indent("sygus-pbe-dt-debug", ind);
+            Trace("sygus-pbe-dt-debug") << "PBE: success : constructed for strategy ";
+            print_strat( "sygus-pbe-dt-debug", strat );
+            Trace("sygus-pbe-dt-debug") << std::endl;
+            break;
+          }else{
+            indent("sygus-pbe-dt-debug", ind);
+            Trace("sygus-pbe-dt-debug") << "PBE: failed for strategy ";
+            print_strat( "sygus-pbe-dt-debug", strat );
+            Trace("sygus-pbe-dt-debug") << std::endl;
+          }
+        }
+        if( ret_dt.isNull() ){
+          indent("sygus-pbe-dt", ind);
+          Trace("sygus-pbe-dt") << "return PBE: fail : all strategies failed " << std::endl;
+        }
+      }else{
+        indent("sygus-pbe-dt", ind);
+        Trace("sygus-pbe-dt") << "return PBE: fail : non-basic" << std::endl;
+      }
+    }
+  }
+  if( !ret_dt.isNull() ){
+    Assert( ret_dt.getType()==e.getType() );
+  }
+  indent("sygus-pbe-dt", ind);
+  Trace("sygus-pbe-dt") << "ConstructPBE: returned " << ret_dt << std::endl;
+  return ret_dt;
+}
+
+bool CegConjecturePbe::UnifContext::updateContext( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol ) {
+  Assert( d_vals.size()==vals.size() );
+  bool changed = false;
+  Node poln = pol ? pbe->d_true : pbe->d_false;
+  for( unsigned i=0; i<vals.size(); i++ ){
+    if( vals[i]!=poln ){
+      if( d_vals[i]==pbe->d_true ){
+        d_vals[i] = pbe->d_false;
+        changed = true;
+      }
+    }
+  }
+  return changed;
+}
+
+bool CegConjecturePbe::UnifContext::updateStringPosition( CegConjecturePbe * pbe, std::vector< unsigned >& pos ) {
+  Assert( pos.size()==d_str_pos.size() );
+  bool changed = false;
+  for( unsigned i=0; i<pos.size(); i++ ){
+    if( pos[i]>0 ){
+      d_str_pos[i] += pos[i];
+      changed = true;
+    }
+  }
+  return changed;
+}
+
+bool CegConjecturePbe::UnifContext::isReturnValueModified() {
+  if( d_has_string_pos!=0 ){
+    return true;
+  }
+  return false;
+}
+
+void CegConjecturePbe::UnifContext::initialize( CegConjecturePbe * pbe, Node c ) {
+  Assert( d_vals.empty() );
+  Assert( d_str_pos.empty() );
+  
+  // initialize with #examples
+  Assert( pbe->d_examples.find( c )!=pbe->d_examples.end() );
+  unsigned sz = pbe->d_examples[c].size();
+  for( unsigned i=0; i<sz; i++ ){
+    d_vals.push_back( pbe->d_true );
+  }
+  
+  if( !pbe->d_examples_out[c].empty() ){
+    // output type of the examples
+    TypeNode exotn = pbe->d_examples_out[c][0].getType();
+    
+    if( exotn.isString() ){
+      for( unsigned i=0; i<sz; i++ ){
+        d_str_pos.push_back( 0 );
+      }
+    }
+  }
+}
+
+
+void CegConjecturePbe::UnifContext::getCurrentStrings( CegConjecturePbe * pbe, std::vector< Node >& vals, std::vector< CVC4::String >& ex_vals ) {
+  bool isPrefix = d_has_string_pos==-1;
+  CVC4::String dummy;
+  for( unsigned i=0; i<vals.size(); i++ ){
+    if( d_vals[i]==pbe->d_true ){
+      Assert( vals[i].isConst() );
+      unsigned pos_value = d_str_pos[i];
+      if( pos_value>0 ){
+        Assert( d_has_string_pos!=0 );
+        CVC4::String s = vals[i].getConst<String>();
+        Assert( pos_value<=s.size() );
+        ex_vals.push_back( isPrefix ? s.suffix( s.size()-pos_value ) : 
+                                      s.prefix( s.size()-pos_value ) );
+      }else{
+        ex_vals.push_back( vals[i].getConst<String>() );
+      }
+    }else{
+      // irrelevant, add dummy
+      ex_vals.push_back( dummy );
+    }
+  }
+}
+
+bool CegConjecturePbe::UnifContext::getStringIncrement( CegConjecturePbe * pbe, bool isPrefix, std::vector< CVC4::String >& ex_vals, std::vector< Node >& vals, std::vector< unsigned >& inc, unsigned& tot ) {
+  for( unsigned j=0; j<vals.size(); j++ ){
+    unsigned ival = 0;
+    if( d_vals[j]==pbe->d_true ){
+      // example is active in this context
+      Assert( vals[j].isConst() );
+      CVC4::String mystr = vals[j].getConst<String>();
+      ival = mystr.size();
+      if( mystr.size()<=ex_vals[j].size() ){
+        if( !( isPrefix ? ex_vals[j].strncmp(mystr, ival) : ex_vals[j].rstrncmp(mystr, ival) ) ){
+          Trace("sygus-pbe-dt-debug") << "X";
+          return false;
+        }
+      }else{
+        Trace("sygus-pbe-dt-debug") << "X";
+        return false;
+      }
+    }
+    Trace("sygus-pbe-dt-debug") << ival;
+    tot += ival;
+    inc.push_back( ival );
+  }
+  return true;
+}
+bool CegConjecturePbe::UnifContext::isStringSolved( CegConjecturePbe * pbe, std::vector< CVC4::String >& ex_vals, std::vector< Node >& vals ) {
+  for( unsigned j=0; j<vals.size(); j++ ){
+    if( d_vals[j]==pbe->d_true ){
+      // example is active in this context
+      Assert( vals[j].isConst() );
+      CVC4::String mystr = vals[j].getConst<String>();
+      if( ex_vals[j]!=mystr ){
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+int CegConjecturePbe::getGuardStatus( Node g ) {
+  bool value;
+  if( d_qe->getValuation().hasSatValue( g, value ) ) {
+    if( value ){
+      return 1;
+    }else{
+      return -1;
+    }
+  }else{
+    return 0;
+  }
+}
+
+}
diff --git a/src/theory/quantifiers/ce_guided_pbe.h b/src/theory/quantifiers/ce_guided_pbe.h
new file mode 100644 (file)
index 0000000..f40f29b
--- /dev/null
@@ -0,0 +1,273 @@
+/*********************                                                        */
+/*! \file ce_guided_pbe.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved.  See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief utility for processing programming by examples synthesis conjectures
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_PBE_H
+#define __CVC4__THEORY__QUANTIFIERS__CE_GUIDED_PBE_H
+
+#include "context/cdhashmap.h"
+#include "context/cdchunk_list.h"
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class CegConjecture;
+class CegConjecturePbe;
+class CegEntailmentInfer;
+
+class CegConjecturePbe {
+private:
+  QuantifiersEngine* d_qe;
+  quantifiers::TermDbSygus * d_tds;
+  CegConjecture* d_parent;
+
+  std::map< Node, bool > d_examples_invalid;
+  std::map< Node, bool > d_examples_out_invalid;
+  std::map< Node, std::vector< std::vector< Node > > > d_examples;
+  std::map< Node, std::vector< Node > > d_examples_out;
+  std::map< Node, std::vector< Node > > d_examples_term;
+  
+  void collectExamples( Node n, std::map< Node, bool >& visited, bool hasPol, bool pol );
+  bool d_is_pbe;
+public:  
+  Node d_true;
+  Node d_false;
+  enum {
+    enum_io,
+    enum_ite_condition,
+    enum_concat_term,
+    enum_any,
+  };
+  enum {
+    strat_ITE,
+    strat_CONCAT,
+    strat_ID,
+  };
+public:
+  CegConjecturePbe( QuantifiersEngine * qe, CegConjecture * p );
+  ~CegConjecturePbe();
+
+  void initialize( Node n, std::vector< Node >& candidates, std::vector< Node >& lemmas );
+  bool getPbeExamples( Node v, std::vector< std::vector< Node > >& exs, 
+                       std::vector< Node >& exos, std::vector< Node >& exts);
+  bool isPbe() { return d_is_pbe; }
+private:  // for registration
+  void collectEnumeratorTypes( Node c, TypeNode tn, unsigned enum_role );
+  void registerEnumerator( Node et, Node c, TypeNode tn, unsigned enum_role, bool inSearch );
+  void staticLearnRedundantOps( Node c, std::vector< Node >& lemmas );
+  void staticLearnRedundantOps( Node c, Node e, std::map< Node, bool >& visited, std::vector< Node >& redundant, 
+                                std::vector< Node >& lemmas, int ind );
+
+  /** register candidate conditional */
+  bool inferTemplate( unsigned k, Node n, std::map< Node, unsigned >& templ_var_index, std::map< unsigned, unsigned >& templ_injection );  
+  /** get guard status */
+  int getGuardStatus( Node g );
+public:
+  class IndexFilter {
+  public:
+    IndexFilter(){}
+    void mk( std::vector< Node >& vals, bool pol = true );
+    std::map< unsigned, unsigned > d_next;
+    unsigned start();
+    unsigned next( unsigned i );
+    void clear() { d_next.clear(); }
+    bool isEq( std::vector< Node >& vs, Node v );
+  };
+private:
+  // subsumption trie
+  class SubsumeTrie {
+  private:
+    Node addTermInternal( CegConjecturePbe * pbe, Node t, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed, bool spol, IndexFilter * f, 
+                          unsigned index, int status, bool checkExistsOnly, bool checkSubsume );
+  public:
+    SubsumeTrie(){}
+    Node d_term;
+    std::map< Node, SubsumeTrie > d_children;
+    // adds term to the trie, removes based on subsumption
+    Node addTerm( CegConjecturePbe * pbe, Node t, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed, IndexFilter * f = NULL );
+    // adds condition to the trie (does not do subsumption)
+    Node addCond( CegConjecturePbe * pbe, Node c, std::vector< Node >& vals, bool pol, IndexFilter * f = NULL );
+    // returns the set of terms that are subsets of vals
+    void getSubsumed( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed, IndexFilter * f = NULL );
+    // returns the set of terms that are supersets of vals
+    void getSubsumedBy( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::vector< Node >& subsumed_by, IndexFilter * f = NULL );
+  private:
+    void getLeavesInternal( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::map< int, std::vector< Node > >& v, IndexFilter * f, 
+                            unsigned index, int status );
+  public:
+    // v[-1,1,0] -> children always false, always true, both
+    void getLeaves( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol, std::map< int, std::vector< Node > >& v, IndexFilter * f = NULL );
+  public:
+    bool isEmpty() { return d_term.isNull() && d_children.empty(); }
+    void clear() {
+      d_term = Node::null();
+      d_children.clear(); 
+    }
+  };
+
+  class EnumInfo {
+  private:
+    /** an OR of all in d_enum_res */
+    //std::vector< Node > d_enum_total;
+    //bool d_enum_total_true;
+    Node d_enum_solved;
+  public:
+    EnumInfo() : d_role( enum_io ){}
+    Node d_parent_candidate;
+    
+    // for template
+    Node d_template;
+    Node d_template_arg;
+    
+    // TODO : make private
+    unsigned d_role;
+    
+    Node d_active_guard;
+    std::vector< Node > d_enum_slave;
+    /** values we have enumerated */
+    std::vector< Node > d_enum_vals;
+    /** this either stores the values of f( I ) for inputs 
+        or the value of f( I ) = O if d_role==enum_io
+    */
+    std::vector< std::vector< Node > > d_enum_vals_res;
+    std::vector< Node > d_enum_subsume;
+    std::map< Node, unsigned > d_enum_val_to_index;
+    SubsumeTrie d_term_trie;
+  public:
+    bool isTemplated() { return !d_template.isNull(); }
+    void addEnumValue( CegConjecturePbe * pbe, Node v, std::vector< Node >& results );
+    void setSolved( Node slv );
+    bool isSolved() { return !d_enum_solved.isNull(); }
+    Node getSolved() { return d_enum_solved; }
+  };
+  std::map< Node, EnumInfo > d_einfo;
+private:
+  class CandidateInfo;
+  class EnumTypeInfoStrat {
+  public:
+    unsigned d_this;
+    /** conditional solutions */
+    std::vector< TypeNode > d_csol_cts;
+    std::vector< Node > d_cenum;
+  };
+  class EnumTypeInfo {
+  public:
+    EnumTypeInfo() : d_parent( NULL ){}
+    CandidateInfo * d_parent;
+    // role -> _
+    std::map< unsigned, Node > d_enum;
+    TypeNode d_this_type;
+    // strategies for enum_io role
+    std::map< Node, EnumTypeInfoStrat > d_strat;
+    bool isSolved( CegConjecturePbe * pbe );
+  };
+  class CandidateInfo {
+  public:
+    CandidateInfo() : d_check_sol( false ), d_cond_count( 0 ){}
+    Node d_this_candidate;
+    TypeNode d_root;
+    std::map< TypeNode, EnumTypeInfo > d_tinfo;
+    std::vector< Node > d_esym_list;
+    // role -> sygus type -> enumerator
+    std::map< TypeNode, Node > d_search_enum;
+    bool d_check_sol;
+    unsigned d_cond_count;
+    Node d_solution;
+    void initialize( Node c );
+    void initializeType( TypeNode tn );
+    Node getRootEnumerator();
+    bool isNonTrivial();
+  };
+  //  candidate -> sygus type -> info
+  std::map< Node, CandidateInfo > d_cinfo;
+
+  /** add enumerated value */
+  void addEnumeratedValue( Node x, Node v, std::vector< Node >& lems );
+  bool getExplanationForEnumeratorExclude( Node c, Node x, Node v, std::vector< Node >& results, EnumInfo& ei, std::vector< Node >& exp );
+  
+private:  
+  // filtering verion
+  /*
+  class FilterSubsumeTrie {
+  public:
+    SubsumeTrie d_trie;
+    IndexFilter d_filter;
+    Node addTerm( Node t, std::vector< bool >& vals, std::vector< Node >& subsumed, bool checkExistsOnly = false ){
+      return d_trie.addTerm( t, vals, subsumed, &d_filter, d_filter.start(), checkExistsOnly );
+    }
+  };
+  */
+  class UnifContext {
+  public:
+    UnifContext() : d_has_string_pos(0) {}
+    //IndexFilter d_filter;
+    // the value of the context conditional
+    std::vector< Node > d_vals;
+    // update the examples
+    bool updateContext( CegConjecturePbe * pbe, std::vector< Node >& vals, bool pol );
+    // the position in the strings
+    std::vector< unsigned > d_str_pos;
+    // 0 : pos not modified, 1 : pos indicates suffix incremented, -1 : pos indicates prefix incremented
+    int d_has_string_pos;
+    // update the string examples
+    bool updateStringPosition( CegConjecturePbe * pbe, std::vector< unsigned >& pos );
+    // is return value modified 
+    bool isReturnValueModified();
+    class UEnumInfo {
+    public:
+      UEnumInfo() : d_status(-1){}
+      int d_status;
+      // enum val -> polarity -> solved
+      std::map< Node, std::map< unsigned, Node > > d_look_ahead_sols;
+    };
+    // enumerator -> info
+    std::map< Node, UEnumInfo > d_uinfo;
+    void initialize( CegConjecturePbe * pbe, Node c );
+    void getCurrentStrings( CegConjecturePbe * pbe, std::vector< Node >& vals, std::vector< CVC4::String >& ex_vals );
+    bool getStringIncrement( CegConjecturePbe * pbe, bool isPrefix, std::vector< CVC4::String >& ex_vals, 
+                             std::vector< Node >& vals, std::vector< unsigned >& inc, unsigned& tot );
+    bool isStringSolved( CegConjecturePbe * pbe, std::vector< CVC4::String >& ex_vals, std::vector< Node >& vals );
+  };
+  /** construct solution */
+  Node constructSolution( Node c );
+  Node constructSolution( Node c, Node e, UnifContext& x, int ind );
+  Node constructBestSolvedTerm( std::vector< Node >& solved, UnifContext& x );
+  Node constructBestStringSolvedTerm( std::vector< Node >& solved, UnifContext& x );
+  Node constructBestSolvedConditional( std::vector< Node >& solved, UnifContext& x );
+  Node constructBestConditional( std::vector< Node >& conds, UnifContext& x );
+  Node constructBestStringToConcat( std::vector< Node > strs,
+                                    std::map< Node, unsigned > total_inc, 
+                                    std::map< Node, std::vector< unsigned > > incr,
+                                    UnifContext& x );
+  void getStringIncrement( bool isPrefix, Node c, Node v,                                     
+                           std::map< Node, unsigned > total_inc, 
+                           std::map< Node, std::vector< unsigned > > incr );
+public:
+  void registerCandidates( std::vector< Node >& candidates ); 
+  void getCandidateList( std::vector< Node >& candidates, std::vector< Node >& clist );
+  // lems and candidate values are outputs  
+  bool constructCandidates( std::vector< Node >& enums, std::vector< Node >& enum_values, 
+                            std::vector< Node >& candidates, std::vector< Node >& candidate_values, 
+                            std::vector< Node >& lems );
+};
+
+
+}/* namespace CVC4::theory::quantifiers */
+}/* namespace CVC4::theory */
+}/* namespace CVC4 */
+
+#endif
index 41b262ddf250ec613d956ac89734d488f70f6aed..4db6df1552d7f388ae88ddc59dae64dc3127d8e6 100644 (file)
@@ -174,8 +174,16 @@ void CegConjectureSingleInv::initialize( Node q ) {
     qq = removeDeepEmbedding( qq, progs, types, type_valid, visited );
     Trace("cegqi-si-debug") << "- Remove deep embedding, got : " << qq << ", type valid = " << type_valid << std::endl;
     if( type_valid==0 ){
+      std::vector< Node > prog_funcs;
+      for( unsigned j=0; j<progs.size(); j++ ){
+        std::map< Node, Node >::iterator itns = d_nsi_op_map.find( progs[j] );
+        if( itns != d_nsi_op_map.end() ){
+          prog_funcs.push_back( itns->second );
+        }
+      }
+    
       //process the single invocation-ness of the property
-      d_sip->init( types, qq );
+      d_sip->init( prog_funcs, qq );
       Trace("cegqi-si") << "- Partitioned to single invocation parts : " << std::endl;
       d_sip->debugPrint( "cegqi-si" );
       //map from program to bound variables
@@ -193,9 +201,12 @@ void CegConjectureSingleInv::initialize( Node q ) {
             Trace("cegqi-si") << "  " << pv << ", " << inv << " is associated with program " << prog << std::endl;
             d_prog_to_sol_index[prog] = order_vars.size();
             order_vars.push_back( pv );
+          }else{
+            Trace("cegqi-si") << "  " << prog << " has no fo var." << std::endl;
           }
         }else{
           //does not mention the function
+          Trace("cegqi-si") << "  " << prog << " is not mentioned." << std::endl;
         }
       }
       //reorder the variables
@@ -215,64 +226,71 @@ void CegConjectureSingleInv::initialize( Node q ) {
           singleInvocation = true;
         }else if( options::sygusInvTemplMode() != SYGUS_INV_TEMPL_MODE_NONE ){
           //if we are doing invariant templates, then construct the template
-          std::map< Node, bool > has_inv;
-          std::map< Node, std::vector< Node > > inv_pre_post[2];
-          for( unsigned i=0; i<d_sip->d_conjuncts[2].size(); i++ ){
-            std::vector< Node > disjuncts;
-            Node func;
-            int pol = -1;
-            Trace("cegqi-inv") << "INV process " << d_sip->d_conjuncts[2][i] << std::endl;
-            d_sip->extractInvariant( d_sip->d_conjuncts[2][i], func, pol, disjuncts );
-            if( pol>=0 ){
-              Assert( d_nsi_op_map_to_prog.find( func )!=d_nsi_op_map_to_prog.end() );
-              Node prog = d_nsi_op_map_to_prog[func];
-              Trace("cegqi-inv") << "..." << ( pol==0 ? "pre" : "post" ) << "-condition for " << prog << "." << std::endl;
-              Node c = disjuncts.empty() ? d_qe->getTermDatabase()->d_false : ( disjuncts.size()==1 ? disjuncts[0] : NodeManager::currentNM()->mkNode( OR, disjuncts ) );
-              c = pol==0 ? TermDb::simpleNegate( c ) : c;
-              Trace("cegqi-inv-debug") << "...extracted : " << c << std::endl;
-              inv_pre_post[pol][prog].push_back( c );
-              has_inv[prog] = true;
-            }else{
-              Trace("cegqi-inv") << "...no status." << std::endl;
-            }
-          }
-
-          Trace("cegqi-inv") << "Constructing invariant templates..." << std::endl;
-          //now, contruct the template for the invariant(s)
+          Trace("cegqi-si") << "- Do transition inference..." << std::endl;
+          d_ti[q].process( qq );
+          Trace("cegqi-inv") << std::endl;
           std::map< Node, Node > prog_templ;
-          for( std::map< Node, bool >::iterator iti = has_inv.begin(); iti != has_inv.end(); ++iti ){
-            Node prog = iti->first;
-            Trace("cegqi-inv") << "...for " << prog << "..." << std::endl;
-            Trace("cegqi-inv") << "   args : ";
-            for( unsigned j=0; j<d_sip->d_si_vars.size(); j++ ){
-              std::stringstream ss;
-              ss << "i_" << j;
-              Node v = NodeManager::currentNM()->mkBoundVar( ss.str(), d_sip->d_si_vars[j].getType() );
-              d_prog_templ_vars[prog].push_back( v );
-              Trace("cegqi-inv") << v << " ";
-            }
-            Trace("cegqi-inv") << std::endl;
-            Node pre = inv_pre_post[0][prog].empty() ? NodeManager::currentNM()->mkConst( false ) :
-                        ( inv_pre_post[0][prog].size()==1 ? inv_pre_post[0][prog][0] : NodeManager::currentNM()->mkNode( OR, inv_pre_post[0][prog] ) );
-            d_trans_pre[prog] = pre.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
-            Node post = inv_pre_post[1][prog].empty() ? NodeManager::currentNM()->mkConst( true ) :
-                        ( inv_pre_post[1][prog].size()==1 ? inv_pre_post[1][prog][0] : NodeManager::currentNM()->mkNode( AND, inv_pre_post[1][prog] ) );
-            d_trans_post[prog] = post.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
+          if( !d_ti[q].d_func.isNull() ){
+            // map the program back via non-single invocation map
+            Assert( d_nsi_op_map_to_prog.find( d_ti[q].d_func )!=d_nsi_op_map_to_prog.end() );
+            Node prog = d_nsi_op_map_to_prog[d_ti[q].d_func];
+            Assert( d_prog_templ_vars[prog].empty() );
+            d_prog_templ_vars[prog].insert( d_prog_templ_vars[prog].end(), d_ti[q].d_vars.begin(), d_ti[q].d_vars.end() );
+            d_trans_pre[prog] = d_ti[q].getComponent( 1 );
+            d_trans_post[prog] = d_ti[q].getComponent( -1 );
             Trace("cegqi-inv") << "   precondition : " << d_trans_pre[prog] << std::endl;
             Trace("cegqi-inv") << "  postcondition : " << d_trans_post[prog] << std::endl;
             Node invariant = single_inv_app_map[prog];
             invariant = invariant.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() );
             Trace("cegqi-inv") << "      invariant : " << invariant << std::endl;
+            
             //construct template
-            Node templ;
-            if( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_PRE ){
-              //templ = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant ), d_trans_post[prog] );
-              templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant );
-            }else{
-              Assert( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_POST );
-              //templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant ) );
-              templ = NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant );
+            d_templ_arg[prog] = NodeManager::currentNM()->mkSkolem( "I", invariant.getType() );
+            if( options::sygusInvAutoUnfold() ){
+              if( d_ti[q].isComplete() ){
+                Trace("cegqi-inv-auto-unfold") << "Automatic deterministic unfolding... " << std::endl;
+                // auto-unfold
+                DetTrace dt;
+                int init_dt = d_ti[q].initializeTrace( dt );
+                if( init_dt==0 ){
+                  Trace("cegqi-inv-auto-unfold") << "  Init : ";
+                  dt.print("cegqi-inv-auto-unfold");
+                  Trace("cegqi-inv-auto-unfold") << std::endl;
+                  unsigned counter = 0;
+                  unsigned status = 0;
+                  while( counter<100 && status==0 ){
+                    status = d_ti[q].incrementTrace( dt );
+                    counter++;
+                    Trace("cegqi-inv-auto-unfold") << "  #" << counter << " : ";
+                    dt.print("cegqi-inv-auto-unfold");
+                    Trace("cegqi-inv-auto-unfold") << "...status = " << status << std::endl;
+                  }
+                  if( status==1 ){
+                    // we have a trivial invariant
+                    d_templ[prog] = d_ti[q].constructFormulaTrace( dt );
+                    Trace("cegqi-inv") << "By finite deterministic terminating trace, a solution invariant is : " << std::endl;
+                    Trace("cegqi-inv") << "   " << d_templ[prog] << std::endl;
+                    // FIXME : this should be uncessary
+                    d_templ[prog] = NodeManager::currentNM()->mkNode( AND, d_templ[prog], d_templ_arg[prog] );
+                  }
+                }else{
+                  Trace("cegqi-inv-auto-unfold") << "...failed initialize." << std::endl;
+                }
+              }
             }
+            if( d_templ[prog].isNull() ){
+              if( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_PRE ){
+                //d_templ[prog] = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant ), d_trans_post[prog] );
+                d_templ[prog] = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], d_templ_arg[prog] );
+              }else{
+                Assert( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_POST );
+                //d_templ[prog] = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant ) );
+                d_templ[prog] = NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], d_templ_arg[prog] );
+              }
+            }
+            TNode iv = d_templ_arg[prog];
+            TNode is = invariant;
+            Node templ = d_templ[prog].substitute( iv, is );
             visited.clear();
             templ = addDeepEmbedding( templ, visited );
             Trace("cegqi-inv") << "       template : " << templ << std::endl;
@@ -447,7 +465,7 @@ Node CegConjectureSingleInv::removeDeepEmbedding( Node n, std::vector< Node >& p
           op = it->second;
         }
         children[0] = d_nsi_op_map[n[0]];
-        ret = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+        ret = children.size()>1 ? NodeManager::currentNM()->mkNode( APPLY_UF, children ) : children[0];
       }
     }
     if( ret.isNull() ){
@@ -591,6 +609,7 @@ bool CegConjectureSingleInv::addLemma( Node n ) {
 
 bool CegConjectureSingleInv::check( std::vector< Node >& lems ) {
   if( !d_single_inv.isNull() ) {
+    Trace("cegqi-si-debug") << "CegConjectureSingleInv::check..." << std::endl;
     if( !d_ns_guard.isNull() ){
       //if partially single invocation, check if we have constructed a candidate by refutation
       bool value;
@@ -636,6 +655,7 @@ bool CegConjectureSingleInv::check( std::vector< Node >& lems ) {
           Trace("cegqi-lemma") << "Cegqi::Lemma : verification, refinement lemma : " << inst << std::endl;
           d_qe->addLemma( finst_lem );
           */
+          Trace("cegqi-si-debug") << "CegConjectureSingleInv::check returned verification lemma (nsi)..." << std::endl;
           return true;
         }else{
           //currently trying to construct candidate by refutation (by d_cinst->check below)
@@ -650,9 +670,12 @@ bool CegConjectureSingleInv::check( std::vector< Node >& lems ) {
       //construct d_single_inv
       d_single_inv = Node::null();
       initializeNextSiConjecture();
+      Trace("cegqi-si-debug") << "CegConjectureSingleInv::check initialized next si conjecture..." << std::endl;
       return true;
     }
+    Trace("cegqi-si-debug") << "CegConjectureSingleInv::check consulting ceg instantiation..." << std::endl;
     d_curr_lemmas.clear();
+    Assert( d_cinst!=NULL );
     //call check for instantiator
     d_cinst->check();
     //add lemmas
@@ -667,6 +690,7 @@ bool CegConjectureSingleInv::check( std::vector< Node >& lems ) {
     }
     return !lems.empty();
   }else{
+    // not single invocation
     return false;
   }
 }
@@ -706,7 +730,6 @@ 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] );
@@ -714,29 +737,29 @@ Node CegConjectureSingleInv::postProcessSolution( Node n ){
     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() );
+    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;
     }
-    return NodeManager::currentNM()->mkNode( k, children );
-  }else{
-    return n;
   }
 }
 
@@ -817,7 +840,6 @@ Node CegConjectureSingleInv::getSolution( unsigned sol_index, TypeNode stn, int&
 Node CegConjectureSingleInv::reconstructToSyntax( Node s, TypeNode stn, int& reconstructed, bool rconsSygus ) {
   d_solution = s;
   const Datatype& dt = ((DatatypeType)(stn).toType()).getDatatype();
-  Trace("csi-sol") << "Reconstruct to syntax " << s << ", allow all = " << dt.getSygusAllowAll() << " " << stn << ", reconstruct = " << rconsSygus << std::endl;
 
   //reconstruct the solution into sygus if necessary
   reconstructed = 0;
@@ -895,20 +917,21 @@ bool SingleInvocationPartition::init( Node n ) {
   //first, get types of arguments for functions
   std::vector< TypeNode > typs;
   std::map< Node, bool > visited;
+  std::vector< Node > funcs;
   if( inferArgTypes( n, typs, visited ) ){
-    return init( typs, n );
+    return init( funcs, typs, n, false );
   }else{
     Trace("si-prt") << "Could not infer argument types." << std::endl;
     return false;
   }
 }
 
+// gets the argument type list for the first APPLY_UF we see
 bool SingleInvocationPartition::inferArgTypes( Node n, std::vector< TypeNode >& typs, std::map< Node, bool >& visited ) {
   if( visited.find( n )==visited.end() ){
     visited[n] = true;
     if( n.getKind()!=FORALL ){
-    //if( TermDb::hasBoundVarAttr( n ) ){
-      if( n.getKind()==d_checkKind ){
+      if( n.getKind()==APPLY_UF ){
         for( unsigned i=0; i<n.getNumChildren(); i++ ){
           typs.push_back( n[i].getType() );
         }
@@ -920,16 +943,41 @@ bool SingleInvocationPartition::inferArgTypes( Node n, std::vector< TypeNode >&
           }
         }
       }
-    //}
     }
   }
   return false;
 }
 
-bool SingleInvocationPartition::init( std::vector< TypeNode >& typs, Node n ){
+bool SingleInvocationPartition::init( std::vector< Node >& funcs, Node n ) {
+  Trace("si-prt") << "Initialize with " << funcs.size() << " input functions..." << std::endl;
+  std::vector< TypeNode > typs;
+  if( !funcs.empty() ){
+    TypeNode tn0 = funcs[0].getType();
+    for( unsigned i=1; i<funcs.size(); i++ ){
+      if( funcs[i].getType()!=tn0 ){
+        // can't anti-skolemize functions of different sort
+        Trace("si-prt") << "...type mismatch" << std::endl;
+        return false;
+      }
+    }
+    if( tn0.getNumChildren()>1 ){
+      for( unsigned j=0; j<tn0.getNumChildren()-1; j++ ){
+        typs.push_back( tn0[j] );
+      }
+    }
+  }
+  Trace("si-prt") << "#types = " << typs.size() << std::endl;
+  return init( funcs, typs, n, true );  
+}
+
+bool SingleInvocationPartition::init( std::vector< Node >& funcs, std::vector< TypeNode >& typs, Node n, bool has_funcs ){
   Assert( d_arg_types.empty() );
+  Assert( d_input_funcs.empty() );
   Assert( d_si_vars.empty() );
+  d_has_input_funcs = has_funcs;
   d_arg_types.insert( d_arg_types.end(), typs.begin(), typs.end() );
+  d_input_funcs.insert( d_input_funcs.end(), funcs.begin(), funcs.end() );
+  Trace("si-prt") << "Initialize..." << std::endl;
   for( unsigned j=0; j<d_arg_types.size(); j++ ){
     std::stringstream ss;
     ss << "s_" << j;
@@ -968,7 +1016,9 @@ void SingleInvocationPartition::process( Node n ) {
       if( processConjunct( cr, visited, args, terms, subs ) ){
         for( unsigned j=0; j<terms.size(); j++ ){
           si_terms.push_back( subs[j] );
-          si_subs.push_back( d_func_fo_var[subs[j].getOperator()] );
+          Node op = subs[j].hasOperator() ? subs[j].getOperator() : subs[j];
+          Assert( d_func_fo_var.find( op )!=d_func_fo_var.end() );
+          si_subs.push_back( d_func_fo_var[op] );
         }
         std::map< Node, Node > subs_map;
         std::map< Node, Node > subs_map_rev;
@@ -1090,9 +1140,21 @@ bool SingleInvocationPartition::processConjunct( Node n, std::map< Node, bool >&
         }
       }
       if( ret ){
-        if( n.getKind()==d_checkKind ){
+        Node f;
+        bool success = false;
+        if( d_has_input_funcs ){
+          f = n.hasOperator() ? n.getOperator() : n;
+          if( std::find( d_input_funcs.begin(), d_input_funcs.end(), f )!=d_input_funcs.end() ){
+            success = true;
+          }
+        }else{
+          if( n.getKind()==kind::APPLY_UF ){
+            f = n.getOperator();
+            success = true;
+          }
+        }
+        if( success ){
           if( std::find( terms.begin(), terms.end(), n )==terms.end() ){
-            Node f = n.getOperator();
             //check if it matches the type requirement
             if( isAntiSkolemizableType( f ) ){
               if( args.empty() ){
@@ -1134,7 +1196,7 @@ bool SingleInvocationPartition::isAntiSkolemizableType( Node f ) {
   }else{
     TypeNode tn = f.getType();
     bool ret = false;
-    if( tn.getNumChildren()==d_arg_types.size()+1 ){
+    if( tn.getNumChildren()==d_arg_types.size()+1 || ( d_arg_types.empty() && tn.getNumChildren()==0 ) ){
       ret = true;
       std::vector< Node > children;
       children.push_back( f );
@@ -1147,12 +1209,23 @@ bool SingleInvocationPartition::isAntiSkolemizableType( Node f ) {
         }
       }
       if( ret ){
-        Node t = NodeManager::currentNM()->mkNode( d_checkKind, children );
+        Node t;
+        if( children.size()>1 ){
+          t = NodeManager::currentNM()->mkNode( kind::APPLY_UF, children );
+        }else{
+          t = children[0];
+        }
         d_func_inv[f] = t;
         d_inv_to_func[t] = f;
         std::stringstream ss;
         ss << "F_" << f;
-        Node v = NodeManager::currentNM()->mkBoundVar( ss.str(), tn.getRangeType() );
+        TypeNode rt;
+        if( d_arg_types.empty() ){
+          rt = tn;
+        }else{
+          rt = tn.getRangeType();
+        }
+        Node v = NodeManager::currentNM()->mkBoundVar( ss.str(), rt );
         d_func_fo_var[f] = v;
         d_fo_var_to_func[v] = f;
         d_func_vars.push_back( v );
@@ -1181,8 +1254,21 @@ Node SingleInvocationPartition::getSpecificationInst( Node n, std::map< Node, No
       childChanged = childChanged || ( nn!=n[i] );
     }
     Node ret;
-    if( n.getKind()==d_checkKind ){
-      std::map< Node, Node >::iterator itl = lam.find( n.getOperator() );
+    Node f;
+    bool success = false;
+    if( d_has_input_funcs ){
+      f = n.hasOperator() ? n.getOperator() : n;
+      if( std::find( d_input_funcs.begin(), d_input_funcs.end(), f )!=d_input_funcs.end() ){
+        success = true;
+      }
+    }else{
+      if( n.getKind()==APPLY_UF ){
+        f = n.getOperator();
+        success = true;
+      }
+    }
+    if( success ){
+      std::map< Node, Node >::iterator itl = lam.find( f );
       if( itl!=lam.end() ){
         Assert( itl->second[0].getNumChildren()==children.size() );
         std::vector< Node > terms;
@@ -1214,55 +1300,6 @@ Node SingleInvocationPartition::getSpecificationInst( int index, std::map< Node,
   return getSpecificationInst( conj, lam, visited );
 }
 
-void SingleInvocationPartition::extractInvariant( Node n, Node& func, int& pol, std::vector< Node >& disjuncts ) {
-  std::map< Node, bool > visited;
-  extractInvariant2( n, func, pol, disjuncts, true, visited );
-}
-
-void SingleInvocationPartition::extractInvariant2( Node n, Node& func, int& pol, std::vector< Node >& disjuncts, bool hasPol, std::map< Node, bool >& visited ) {
-  if( visited.find( n )==visited.end() && pol!=-2 ){
-    Trace("cegqi-inv-debug2") << "Extract : " << n << " " << hasPol << ", pol = " << pol << std::endl;
-    visited[n] = true;
-    if( n.getKind()==OR && hasPol ){
-      for( unsigned i=0; i<n.getNumChildren(); i++ ){
-        extractInvariant2( n[i], func, pol, disjuncts, true, visited );
-      }
-    }else{
-      if( hasPol ){
-        bool lit_pol = n.getKind()!=NOT;
-        Node lit = n.getKind()==NOT ? n[0] : n;
-        std::map< Node, Node >::iterator it = d_inv_to_func.find( lit );
-        if( it!=d_inv_to_func.end() ){
-          if( pol==-1 ){
-            pol = lit_pol ? 0 : 1;
-            func = it->second;
-          }else{
-            //mixing multiple invariants
-            pol = -2;
-          }
-          return;
-        }else{
-          disjuncts.push_back( n );
-        }
-      }
-      //if another part mentions UF or a free variable, then fail
-      if( n.getKind()==APPLY_UF ){
-        Node op = n.getOperator();
-        if( d_funcs.find( op )!=d_funcs.end() ){
-          pol = -2;
-          return;
-        }
-      }else if( n.getKind()==BOUND_VARIABLE && std::find( d_si_vars.begin(), d_si_vars.end(), n )==d_si_vars.end() ){
-        pol = -2;
-        return;
-      }
-      for( unsigned i=0; i<n.getNumChildren(); i++ ){
-        extractInvariant2( n[i], func, pol, disjuncts, false, visited );
-      }
-    }
-  }
-}
-
 void SingleInvocationPartition::debugPrint( const char * c ) {
   Trace(c) << "Single invocation variables : ";
   for( unsigned i=0; i<d_si_vars.size(); i++ ){
@@ -1288,4 +1325,391 @@ void SingleInvocationPartition::debugPrint( const char * c ) {
   Trace(c) << std::endl;
 }
 
+
+bool DetTrace::DetTraceTrie::add( Node loc, std::vector< Node >& val, unsigned index ){
+  if( index==val.size() ){
+    if( d_children.empty() ){
+      d_children[loc].clear();
+      return true;
+    }else{
+      return false;
+    }
+  }else{
+    return d_children[val[index]].add( loc, val, index+1 );
+  }
+}
+
+Node DetTrace::DetTraceTrie::constructFormula( std::vector< Node >& vars, unsigned index ){
+  if( index==vars.size() ){
+    return NodeManager::currentNM()->mkConst( true );    
+  }else{
+    std::vector< Node > disj;
+    for( std::map< Node, DetTraceTrie >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+      Node eq = vars[index].eqNode( it->first );
+      if( index<vars.size()-1 ){
+        Node conc = it->second.constructFormula( vars, index+1 );
+        disj.push_back( NodeManager::currentNM()->mkNode( kind::AND, eq, conc ) );
+      }else{
+        disj.push_back( eq );
+      }
+    }
+    Assert( !disj.empty() );
+    return disj.size()==1 ? disj[0] : NodeManager::currentNM()->mkNode( kind::OR, disj );
+  }
+}
+
+bool DetTrace::increment( Node loc, std::vector< Node >& vals ){
+  if( d_trie.add( loc, vals ) ){
+    for( unsigned i=0; i<vals.size(); i++ ){
+      d_curr[i] = vals[i];
+    }
+    return true;
+  }else{
+    return false;
+  }
+}
+
+Node DetTrace::constructFormula( std::vector< Node >& vars ) {
+  return d_trie.constructFormula( vars );
+}
+
+
+void DetTrace::print( const char* c ) {
+  for( unsigned i=0; i<d_curr.size(); i++ ){
+    Trace(c) << d_curr[i] << " ";
+  }
+}
+
+void TransitionInference::initialize( Node f, std::vector< Node >& vars ) {
+  Assert( d_vars.empty() );
+  d_func = f;
+  d_vars.insert( d_vars.end(), vars.begin(), vars.end() );
 }
+
+
+void TransitionInference::getConstantSubstitution( std::vector< Node >& vars, std::vector< Node >& disjuncts, std::vector< Node >& const_var, std::vector< Node >& const_subs, bool reqPol ) {
+  for( unsigned j=0; j<disjuncts.size(); j++ ){
+    Node sn;
+    if( !const_var.empty() ){
+      sn = disjuncts[j].substitute( const_var.begin(), const_var.end(), const_subs.begin(), const_subs.end() );
+      sn = Rewriter::rewrite( sn );
+    }else{
+      sn = disjuncts[j];
+    }
+    bool slit_pol = sn.getKind()!=NOT;
+    Node slit = sn.getKind()==NOT ? sn[0] : sn;
+    if( slit.getKind()==EQUAL && slit_pol==reqPol ){
+      // check if it is a variable equality
+      TNode v;
+      Node s;
+      for( unsigned r=0; r<2; r++ ){
+        if( std::find( vars.begin(), vars.end(), slit[r] )!=vars.end() ){
+          if( !TermDb::containsTerm( slit[1-r], slit[r] ) ){
+            v = slit[r];
+            s = slit[1-r];
+            break;
+          }
+        }
+      }
+      if( v.isNull() ){
+        //solve for var
+        std::map< Node, Node > msum;
+        if( QuantArith::getMonomialSumLit( slit, msum ) ){
+          for( std::map< Node, Node >::iterator itm = msum.begin(); itm != msum.end(); ++itm ){
+            if( std::find( vars.begin(), vars.end(), itm->first )!=vars.end() ){  
+              Node veq_c;
+              Node val;
+              int ires = QuantArith::isolate( itm->first, msum, veq_c, val, EQUAL );
+              if( ires!=0 && veq_c.isNull() && !TermDb::containsTerm( val, itm->first ) ){
+                v = itm->first;
+                s = val;
+              }
+            }
+          }
+        }
+      }
+      if( !v.isNull() ){
+        TNode ts = s;
+        for( unsigned k=0; k<const_subs.size(); k++ ){
+          const_subs[k] = Rewriter::rewrite( const_subs[k].substitute( v, ts ) );
+        }
+        Trace("cegqi-inv-debug2") << "...substitution : " << v << " -> " << s << std::endl;
+        const_var.push_back( v );
+        const_subs.push_back( s );
+      }
+    }
+  }
+}
+
+void TransitionInference::process( Node n ) {
+  d_complete = true;
+  std::vector< Node > n_check;
+  if( n.getKind()==AND ){
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      n_check.push_back( n[i] );
+    }
+  }else{
+    n_check.push_back( n );
+  }
+  for( unsigned i=0; i<n_check.size(); i++ ){
+    Node nn = n_check[i];
+    std::map< Node, bool > visited;
+    std::map< bool, Node > terms;
+    std::vector< Node > disjuncts;
+    Trace("cegqi-inv") << "TransitionInference : Process disjunct : " << nn << std::endl;
+    if( processDisjunct( nn, terms, disjuncts, visited, true ) ){
+      if( !terms.empty() ){
+        Node norm_args;
+        int comp_num;
+        std::map< bool, Node >::iterator itt = terms.find( false );
+        if( itt!=terms.end() ){
+          norm_args = itt->second;
+          if( terms.find( true )!=terms.end() ){
+            comp_num = 0;
+          }else{
+            comp_num = -1;
+          }
+        }else{
+          norm_args = terms[true];
+          comp_num = 1;
+        }
+        std::vector< Node > subs;
+        for( unsigned j=0; j<norm_args.getNumChildren(); j++ ){
+          subs.push_back( norm_args[j] );
+        }        
+        Trace("cegqi-inv-debug2") << "  normalize based on " << norm_args << std::endl;
+        Assert( d_vars.size()==subs.size() );
+        for( unsigned j=0; j<disjuncts.size(); j++ ){
+          disjuncts[j] = Rewriter::rewrite( disjuncts[j].substitute( subs.begin(), subs.end(), d_vars.begin(), d_vars.end() ) );
+          Trace("cegqi-inv-debug2") << "  ..." << disjuncts[j] << std::endl;
+        }
+        std::vector< Node > const_var;
+        std::vector< Node > const_subs;
+        if( comp_num==0 ){
+          //transition
+          Assert( terms.find( true )!=terms.end() );
+          Node next = terms[true];
+          next = Rewriter::rewrite( next.substitute( subs.begin(), subs.end(), d_vars.begin(), d_vars.end() ) );
+          Trace("cegqi-inv-debug") << "transition next predicate : " << next << std::endl;
+          // normalize the other direction
+          std::vector< Node > rvars;
+          for( unsigned i=0; i<next.getNumChildren(); i++ ){
+            rvars.push_back( next[i] );
+          }
+          if( d_prime_vars.size()<next.getNumChildren() ){
+            for( unsigned i=0; i<next.getNumChildren(); i++ ){
+              Node v = NodeManager::currentNM()->mkSkolem( "ir", next[i].getType(), "template inference rev argument" );
+              d_prime_vars.push_back( v );
+            }
+          }
+          Trace("cegqi-inv-debug2") << "  normalize based on " << next << std::endl;
+          Assert( d_vars.size()==subs.size() );
+          for( unsigned j=0; j<disjuncts.size(); j++ ){
+            disjuncts[j] = Rewriter::rewrite( disjuncts[j].substitute( rvars.begin(), rvars.end(), d_prime_vars.begin(), d_prime_vars.end() ) );
+            Trace("cegqi-inv-debug2") << "  ..." << disjuncts[j] << std::endl;
+          }
+          getConstantSubstitution( d_prime_vars, disjuncts, const_var, const_subs, false );
+        }else{
+          getConstantSubstitution( d_vars, disjuncts, const_var, const_subs, false );
+        }
+        Node res;
+        if( disjuncts.empty() ){
+          res = NodeManager::currentNM()->mkConst( false );
+        }else if( disjuncts.size()==1 ){
+          res = disjuncts[0];
+        }else{
+          res = NodeManager::currentNM()->mkNode( kind::OR, disjuncts );
+        }
+        if( !res.hasBoundVar() ){
+          Trace("cegqi-inv") << "*** inferred " << ( comp_num==1 ? "pre" : ( comp_num==-1 ? "post" : "trans" ) ) << "-condition : " << res << std::endl;
+          d_com[comp_num].d_conjuncts.push_back( res );
+          if( !const_var.empty() ){
+            bool has_const_eq = const_var.size()==d_vars.size();
+            Trace("cegqi-inv") << "    with constant substitution, complete = " << has_const_eq << " : " << std::endl;
+            for( unsigned i=0; i<const_var.size(); i++ ){
+              Trace("cegqi-inv") << "      " << const_var[i] << " -> " << const_subs[i] << std::endl;
+              if( has_const_eq ){
+                d_com[comp_num].d_const_eq[res][const_var[i]] = const_subs[i];
+              }
+            }
+            Trace("cegqi-inv") << "...size = " << const_var.size() << ", #vars = " << d_vars.size() << std::endl;
+          }
+        }else{
+          Trace("cegqi-inv-debug2") << "...failed, free variable." << std::endl;
+          d_complete = false;
+        }
+      }
+    }else{
+      d_complete = false;
+    }
+  }
+  
+  // finalize the components
+  for( int i=-1; i<=1; i++ ){
+    Node ret;
+    if( d_com[i].d_conjuncts.empty() ){
+      ret = NodeManager::currentNM()->mkConst( true );
+    }else if( d_com[i].d_conjuncts.size()==1 ){
+      ret = d_com[i].d_conjuncts[0];
+    }else{
+      ret = NodeManager::currentNM()->mkNode( kind::AND, d_com[i].d_conjuncts );
+    }
+    if( i==0 || i==1 ){
+      // pre-condition and transition are negated
+      ret = TermDb::simpleNegate( ret );
+    }
+    d_com[i].d_this = ret;
+  }
+}
+
+bool TransitionInference::processDisjunct( Node n, std::map< bool, Node >& terms, std::vector< Node >& disjuncts, 
+                                           std::map< Node, bool >& visited, bool topLevel ) {
+  if( visited.find( n )==visited.end() ){
+    visited[n] = true;
+    bool childTopLevel = n.getKind()==OR && topLevel;
+    //if another part mentions UF or a free variable, then fail
+    bool lit_pol = n.getKind()!=NOT;
+    Node lit = n.getKind()==NOT ? n[0] : n;
+    if( lit.getKind()==APPLY_UF ){
+      Node op = lit.getOperator();
+      if( d_func.isNull() ){
+        d_func = op;
+        Trace("cegqi-inv-debug") << "Use " << op << " with args ";
+        for( unsigned i=0; i<lit.getNumChildren(); i++ ){
+          Node v = NodeManager::currentNM()->mkSkolem( "i", lit[i].getType(), "template inference argument" );
+          d_vars.push_back( v );
+          Trace("cegqi-inv-debug") << v << " ";
+        }
+        Trace("cegqi-inv-debug") << std::endl;
+      }
+      if( op!=d_func ){
+        Trace("cegqi-inv-debug") << "...failed, free function : " << n << std::endl;
+        return false;
+      }else if( topLevel ){
+        if( terms.find( lit_pol )==terms.end() ){
+          terms[lit_pol] = lit;
+          return true;
+        }else{
+          Trace("cegqi-inv-debug") << "...failed, repeated inv-app : " << lit << std::endl;
+          return false;
+        }
+      }else{
+        Trace("cegqi-inv-debug") << "...failed, non-entailed inv-app : " << lit << std::endl;
+        return false;
+      }
+    }else if( topLevel && !childTopLevel ){
+      disjuncts.push_back( n );
+    }
+    for( unsigned i=0; i<n.getNumChildren(); i++ ){
+      if( !processDisjunct( n[i], terms, disjuncts, visited, childTopLevel ) ){
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+Node TransitionInference::getComponent( int i ) {
+  return d_com[i].d_this;
+}
+
+int TransitionInference::initializeTrace( DetTrace& dt, Node loc, bool fwd ) {
+  int index = fwd ? 1 : -1;
+  Assert( d_com[index].has( loc ) );
+  std::map< Node, std::map< Node, Node > >::iterator it = d_com[index].d_const_eq.find( loc );
+  if( it!=d_com[index].d_const_eq.end() ){
+    std::vector< Node > next;
+    for( unsigned i=0; i<d_vars.size(); i++ ){
+      Node v = d_vars[i];
+      Assert( it->second.find( v )!=it->second.end() );
+      next.push_back( it->second[v] );
+      dt.d_curr.push_back( it->second[v] );
+    }
+    Trace("cegqi-inv-debug2") << "dtrace : initial increment" << std::endl;
+    bool ret = dt.increment( loc, next );
+    AlwaysAssert( ret );
+    return 0;
+  }
+  return -1;
+}
+  
+int TransitionInference::incrementTrace( DetTrace& dt, Node loc, bool fwd ) {
+  Assert( d_com[0].has( loc ) );
+  // check if it satisfies the pre/post condition
+  int check_index = fwd ? -1 : 1;
+  Node cc = getComponent( check_index );
+  Assert( !cc.isNull() );
+  Node ccr = Rewriter::rewrite( cc.substitute( d_vars.begin(), d_vars.end(), dt.d_curr.begin(), dt.d_curr.end() ) );
+  if( ccr.isConst() ){
+    if( ccr.getConst<bool>()==( fwd ? false : true ) ){
+      Trace("cegqi-inv-debug2") << "dtrace : counterexample" << std::endl;
+      return 2;
+    }
+  }
+
+
+  // terminates?
+  Node c = getComponent( 0 );
+  Assert( !c.isNull() );
+
+  Assert( d_vars.size()==dt.d_curr.size() );
+  Node cr = Rewriter::rewrite( c.substitute( d_vars.begin(), d_vars.end(), dt.d_curr.begin(), dt.d_curr.end() ) );
+  if( cr.isConst() ){
+    if( !cr.getConst<bool>() ){
+      Trace("cegqi-inv-debug2") << "dtrace : terminated" << std::endl;
+      return 1;
+    }else{
+      return -1;
+    }
+  }
+  if( fwd ){
+    std::map< Node, std::map< Node, Node > >::iterator it = d_com[0].d_const_eq.find( loc );
+    if( it!=d_com[0].d_const_eq.end() ){
+      std::vector< Node > next;
+      for( unsigned i=0; i<d_prime_vars.size(); i++ ){
+        Node pv = d_prime_vars[i];
+        Assert( it->second.find( pv )!=it->second.end() );
+        Node pvs = it->second[pv];
+        Assert( d_vars.size()==dt.d_curr.size() );
+        Node pvsr = Rewriter::rewrite( pvs.substitute( d_vars.begin(), d_vars.end(), dt.d_curr.begin(), dt.d_curr.end() ) );
+        next.push_back( pvsr );
+      }
+      if( dt.increment( loc, next ) ){
+        Trace("cegqi-inv-debug2") << "dtrace : success increment" << std::endl;
+        return 0;
+      }else{
+        // looped
+        Trace("cegqi-inv-debug2") << "dtrace : looped" << std::endl;
+        return 1;
+      }
+    }
+  }else{
+    //TODO
+  }
+  return -1;
+}
+
+int TransitionInference::initializeTrace( DetTrace& dt, bool fwd ) {
+  Trace("cegqi-inv-debug2") << "Initialize trace" << std::endl;
+  int index = fwd ? 1 : -1;
+  if( d_com[index].d_conjuncts.size()==1 ){
+    return initializeTrace( dt, d_com[index].d_conjuncts[0], fwd );
+  }else{
+    return -1;
+  }
+}
+
+int TransitionInference::incrementTrace( DetTrace& dt, bool fwd ) {
+  if( d_com[0].d_conjuncts.size()==1 ){
+    return incrementTrace( dt, d_com[0].d_conjuncts[0], fwd );
+  }else{
+    return -1;
+  }
+}
+
+Node TransitionInference::constructFormulaTrace( DetTrace& dt ) {
+  return dt.constructFormula( d_vars );
+}
+  
+} //namespace CVC4
+
index daa298610b29a61a2a8e0f42dc57eb4e3a8f8e46..e22d5fb536c0513440bb314ee1bcd6f68702b1bf 100644 (file)
@@ -44,6 +44,58 @@ public:
 
 class SingleInvocationPartition;
 
+class DetTrace {
+private:
+  class DetTraceTrie {
+  public:
+    std::map< Node, DetTraceTrie > d_children;
+    bool add( Node loc, std::vector< Node >& val, unsigned index = 0 );
+    void clear() { d_children.clear(); }
+    Node constructFormula( std::vector< Node >& vars, unsigned index = 0 );
+  };
+  DetTraceTrie d_trie;
+public:
+  std::vector< Node > d_curr;
+  bool increment( Node loc, std::vector< Node >& vals );
+  Node constructFormula( std::vector< Node >& vars );
+  void print( const char* c );
+};
+
+class TransitionInference {
+private:
+  bool processDisjunct( Node n, std::map< bool, Node >& terms, std::vector< Node >& disjuncts, std::map< Node, bool >& visited, bool topLevel );
+  void getConstantSubstitution( std::vector< Node >& vars, std::vector< Node >& disjuncts, std::vector< Node >& const_var, std::vector< Node >& const_subs, bool reqPol );
+  bool d_complete;
+public:
+  TransitionInference() : d_complete( false ) {}
+  std::vector< Node > d_vars;
+  std::vector< Node > d_prime_vars;
+  Node d_func;
+  
+  class Component {
+  public:
+    Component(){}
+    Node d_this;
+    std::vector< Node > d_conjuncts;
+    std::map< Node, std::map< Node, Node > > d_const_eq;
+    bool has( Node c ) { return std::find( d_conjuncts.begin(), d_conjuncts.end(), c )!=d_conjuncts.end(); }
+  };
+  std::map< int, Component > d_com;
+  
+  void initialize( Node f, std::vector< Node >& vars );
+  void process( Node n );
+  Node getComponent( int i );
+  bool isComplete() { return d_complete; }
+  
+  // 0 : success, 1 : terminated, 2 : counterexample, -1 : invalid
+  int initializeTrace( DetTrace& dt, Node loc, bool fwd = true );
+  int incrementTrace( DetTrace& dt, Node loc, bool fwd = true );
+  int initializeTrace( DetTrace& dt, bool fwd = true );
+  int incrementTrace( DetTrace& dt, bool fwd = true );
+  Node constructFormulaTrace( DetTrace& dt );
+};
+
+
 class CegConjectureSingleInv {
  private:
   friend class CegqiOutputSingleInv;
@@ -72,6 +124,7 @@ class CegConjectureSingleInv {
   QuantifiersEngine* d_qe;
   CegConjecture* d_parent;
   SingleInvocationPartition* d_sip;
+  std::map< Node, TransitionInference > d_ti;
   CegConjectureSingleInvSol* d_sol;
   CegEntailmentInfer* d_ei;
   // the instantiator
@@ -130,6 +183,8 @@ class CegConjectureSingleInv {
   std::map< Node, Node > d_trans_pre;
   std::map< Node, Node > d_trans_post;
   std::map< Node, std::vector< Node > > d_prog_templ_vars;
+  std::map< Node, Node > d_templ;
+  std::map< Node, Node > d_templ_arg;
   //the non-single invocation portion of the quantified formula
   std::map< Node, Node > d_nsi_op_map;
   std::map< Node, Node > d_nsi_op_map_to_prog;
@@ -170,6 +225,22 @@ class CegConjectureSingleInv {
     std::map<Node, Node>::const_iterator location = d_trans_post.find(prog);
     return location->second;
   }
+  Node getTemplate(Node prog) const {
+    std::map<Node, Node>::const_iterator tmpl = d_templ.find(prog);
+    if( tmpl!=d_templ.end() ){
+      return tmpl->second;
+    }else{
+      return Node::null();
+    }
+  }
+  Node getTemplateArg(Node prog) const {
+    std::map<Node, Node>::const_iterator tmpla = d_templ_arg.find(prog);
+    if( tmpla != d_templ_arg.end() ){
+      return tmpla->second;
+    }else{
+      return Node::null();
+    }
+  }
 
 };
 
@@ -178,21 +249,22 @@ class CegConjectureSingleInv {
 // "d_arg_types",  and all invocations are in the same order across all
 // functions
 class SingleInvocationPartition {
- private:
+private:
+  bool d_has_input_funcs;
+  std::vector< Node > d_input_funcs;
   //options
-  Kind d_checkKind;
   bool inferArgTypes( Node n, std::vector< TypeNode >& typs, std::map< Node, bool >& visited );
   void process( Node n );
   bool collectConjuncts( Node n, bool pol, std::vector< Node >& conj );
   bool processConjunct( Node n, std::map< Node, bool >& visited, std::vector< Node >& args,
                         std::vector< Node >& terms, std::vector< Node >& subs );
   Node getSpecificationInst( Node n, std::map< Node, Node >& lam, std::map< Node, Node >& visited );
-  void extractInvariant2( Node n, Node& func, int& pol, std::vector< Node >& disjuncts, bool hasPol, std::map< Node, bool >& visited );
+  bool init( std::vector< Node >& funcs, std::vector< TypeNode >& typs, Node n, bool has_funcs );
 public:
-  SingleInvocationPartition( Kind checkKind = kind::APPLY_UF ) : d_checkKind( checkKind ){}
+  SingleInvocationPartition() : d_has_input_funcs( false ){}
   ~SingleInvocationPartition(){}
   bool init( Node n );
-  bool init( std::vector< TypeNode >& typs, Node n );
+  bool init( std::vector< Node >& funcs, Node n );
 
   //outputs (everything is with bound var)
   std::vector< TypeNode > d_arg_types;
@@ -216,14 +288,13 @@ public:
 
   Node getSpecificationInst( int index, std::map< Node, Node >& lam );
 
-  void extractInvariant( Node n, Node& func, int& pol, std::vector< Node >& disjuncts );
-
   bool isPurelySingleInvocation() { return d_conjuncts[1].empty(); }
   bool isNonGroundSingleInvocation() { return d_conjuncts[3].size()==d_conjuncts[1].size(); }
 
   void debugPrint( const char * c );
 };
 
+
 }/* namespace CVC4::theory::quantifiers */
 }/* namespace CVC4::theory */
 }/* namespace CVC4 */
index 79b4f2c0e588b99a2ff162f2f48d08075c7582b9..aea1e4efc5d0e04f7ff94a0a3bb24326508f2ee0 100644 (file)
@@ -383,7 +383,7 @@ Node CegConjectureSingleInvSol::simplifySolutionNode( Node sol, TypeNode stn, st
     d_qe->getTermDatabaseSygus()->registerSygusType( stn );
     std::map< int, TypeNode > stnc;
     if( !stn.isNull() ){
-      int karg = d_qe->getTermDatabaseSygus()->getKindArg( stn, sol.getKind() );
+      int karg = d_qe->getTermDatabaseSygus()->getKindConsNum( stn, sol.getKind() );
       if( karg!=-1 ){
         const Datatype& dt = ((DatatypeType)(stn).toType()).getDatatype();
         if( dt[karg].getNumArgs()==sol.getNumChildren() ){
@@ -741,14 +741,14 @@ int CegConjectureSingleInvSol::collectReconstructNodes( Node t, TypeNode stn, in
     Node min_t = d_qe->getTermDatabaseSygus()->minimizeBuiltinTerm( t );
     Trace("csi-rcons-debug") << "Minimized term is : " << min_t << std::endl;
     //check if op is in syntax sort
-    carg = d_qe->getTermDatabaseSygus()->getOpArg( stn, min_t );
+    carg = d_qe->getTermDatabaseSygus()->getOpConsNum( stn, min_t );
     if( carg!=-1 ){
       Trace("csi-rcons-debug") << "  Type has operator." << std::endl;
       d_reconstruct[id] = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, Node::fromExpr( dt[carg].getConstructor() ) );
       status = 0;
     }else{
       //check if kind is in syntax sort
-      karg = d_qe->getTermDatabaseSygus()->getKindArg( stn, min_t.getKind() );
+      karg = d_qe->getTermDatabaseSygus()->getKindConsNum( stn, min_t.getKind() );
       if( karg!=-1 ){
         //collect the children of min_t
         std::vector< Node > tchildren;
@@ -880,7 +880,7 @@ int CegConjectureSingleInvSol::collectReconstructNodes( Node t, TypeNode stn, in
                 }
                 //get decompositions
                 for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
-                  Kind k = d_qe->getTermDatabaseSygus()->getArgKind( stn, i );
+                  Kind k = d_qe->getTermDatabaseSygus()->getConsNumKind( stn, i );
                   getEquivalentTerms( k, min_t, equiv );
                 }
                 //assign ids to terms
index 23b0b85fe50a00214225710afa4c132ece4bace7..cd541a2a60a224af80771f064c7351e233b58b94 100644 (file)
@@ -688,7 +688,7 @@ Node DtInstantiator::solve_dt( Node v, Node a, Node b, Node sa, Node sb ) {
       TypeNode tn = a.getType();
       const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
       for( unsigned i=0; i<a.getNumChildren(); i++ ){
-        Node nn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex][i].getSelector() ), sb );
+        Node nn = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex].getSelectorInternal( tn.toType(), i ) ), sb );
         Node s = solve_dt( v, a[i], Node::null(), sa[i], nn );
         if( !s.isNull() ){
           return s;
@@ -720,7 +720,7 @@ bool DtInstantiator::processEqualTerms( CegInstantiator * ci, SolvedForm& sf, No
       unsigned cindex = Datatype::indexOf( n.getOperator().toExpr() );
       //now must solve for selectors applied to pv
       for( unsigned j=0; j<dt[cindex].getNumArgs(); j++ ){
-        Node c = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex][j].getSelector() ), pv );
+        Node c = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[cindex].getSelectorInternal( d_type.toType(), j ) ), pv );
         ci->pushStackVariable( c );
         children.push_back( c );
       }
index 9202062a479d02a6613c042eaf0b639cb6e61a34..79a412b3ca60ae76aee1c94a8cf99ddbe1b5c920 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "expr/datatype.h"
 #include "options/quantifiers_options.h"
+#include "options/datatypes_options.h"
 #include "theory/quantifiers/candidate_generator.h"
 #include "theory/quantifiers/term_database.h"
 #include "theory/quantifiers/trigger.h"
@@ -116,7 +117,8 @@ void InstMatchGenerator::initialize( Node q, QuantifiersEngine* qe, std::vector<
           break;
         }
       }
-    }else if( d_match_pattern.getKind()==APPLY_SELECTOR_TOTAL && d_match_pattern[0].getKind()==INST_CONSTANT && options::purifyDtTriggers() ){
+    }else if( d_match_pattern.getKind()==APPLY_SELECTOR_TOTAL && d_match_pattern[0].getKind()==INST_CONSTANT && 
+              options::purifyDtTriggers() && !options::dtSharedSelectors() ){
       d_match_pattern = d_match_pattern[0];
     }
     d_match_pattern_type = d_match_pattern.getType();
index 0c2822cd9a18f06d360b9dc98aa176da6c9cb7e9..8e53c97dc753e46c03c78e1ed28783bdaaddc0b7 100644 (file)
@@ -561,6 +561,9 @@ bool InstStrategyCbqi::doCbqi( Node q ){
           }
         }
       }
+      if( d_quantEngine->getTermDatabase()->isQAttrSygus( q ) ){
+        ret = 0;
+      }
       if( ret!=0 ){
         //if quantifier has a non-handled variable, then do not use cbqi
         //if quantifier has an APPLY_UF term, then do not use cbqi unless EPR
index 21ad032f32bb47d5b926efed1b1b0128cd407e1c..b34abba1317a5c6cb69cf9793bbc547446a71866 100644 (file)
@@ -531,3 +531,75 @@ Node QuantEPR::mkEPRAxiom( TypeNode tn ) {
   }
 }
 
+
+void TermRecBuild::addTerm( Node n ) {
+  d_term.push_back( n );
+  std::vector< Node > currc;
+  d_kind.push_back( n.getKind() );
+  if( n.getMetaKind()==kind::metakind::PARAMETERIZED ){
+    currc.push_back( n.getOperator() );
+    d_has_op.push_back( true );
+  }else{
+    d_has_op.push_back( false );
+  }
+  for( unsigned i=0; i<n.getNumChildren(); i++ ){
+    currc.push_back( n[i] );
+  }
+  d_children.push_back( currc );  
+}
+
+void TermRecBuild::init( Node n ) {
+  Assert( d_term.empty() );
+  addTerm( n );
+}
+
+void TermRecBuild::push( unsigned p ) {
+  Assert( !d_term.empty() );
+  unsigned curr = d_term.size()-1;
+  Assert( d_pos.size()==curr );
+  Assert( d_pos.size()+1==d_children.size() );
+  Assert( p<d_term[curr].getNumChildren() );
+  addTerm( d_term[curr][p] );
+  d_pos.push_back( p );
+}
+
+void TermRecBuild::pop() {
+  Assert( !d_pos.empty() );
+  d_pos.pop_back();
+  d_kind.pop_back();
+  d_has_op.pop_back();
+  d_children.pop_back();
+  d_term.pop_back(); 
+}
+
+void TermRecBuild::replaceChild( unsigned i, Node n ) {
+  Assert( !d_term.empty() );
+  unsigned curr = d_term.size()-1;
+  unsigned o = d_has_op[curr] ? 1 : 0;
+  d_children[curr][i+o] = n;
+}
+
+Node TermRecBuild::getChild( unsigned i ) {
+  unsigned curr = d_term.size()-1;
+  unsigned o = d_has_op[curr] ? 1 : 0;
+  return d_children[curr][i+o];
+}
+
+Node TermRecBuild::build( unsigned d ) {
+  Assert( d_pos.size()+1==d_term.size() );
+  Assert( d<d_term.size() );
+  int p = d<d_pos.size() ? d_pos[d] : -2;
+  std::vector< Node > children;
+  unsigned o = d_has_op[d] ? 1 : 0;
+  for( unsigned i=0; i<d_children[d].size(); i++ ){
+    Node nc;
+    if( p+o==i ){
+      nc = build( d+1 );
+    }else{
+      nc = d_children[d][i];
+    }
+    children.push_back( nc );
+  }
+  return NodeManager::currentNM()->mkNode( d_kind[d], children );
+}
+
index 42fb7381c1f9f9c719e097ff4d6521276b220bee..40a5b584930654a2473c7ee1716af19007203f0e 100644 (file)
@@ -207,6 +207,24 @@ public:
   bool hasEPRAxiom( TypeNode tn ) const { return d_epr_axiom.find( tn )!=d_epr_axiom.end(); }
 };
 
+class TermRecBuild {
+private:
+  std::vector< Node > d_term;
+  std::vector< std::vector< Node > > d_children;
+  std::vector< Kind > d_kind;
+  std::vector< bool > d_has_op;
+  std::vector< unsigned > d_pos;
+  void addTerm( Node n );
+public:
+  TermRecBuild(){}
+  void init( Node n );
+  void push( unsigned p );
+  void pop();
+  void replaceChild( unsigned i, Node n );
+  Node getChild( unsigned i );
+  Node build( unsigned p=0 );
+};
+
 }
 }
 
index 2261fd036c937b27364f7a7575daf3e112c64ca8..a9b1470fd17eeeb679638bd29da0de8f48a1cd63 100644 (file)
@@ -42,6 +42,16 @@ void QuantifiersAttributes::setUserAttribute( const std::string& attr, Node n, s
     Trace("quant-attr-debug") << "Set sygus " << n << std::endl;
     SygusAttribute ca;
     n.setAttribute( ca, true );
+  }else if( attr=="sygus-synth-fun" ){
+    Assert( node_values.size()==1 );
+    Trace("quant-attr-debug") << "Set sygus synth fun " << n << " to "  << node_values[0] << std::endl;
+    SygusSynthFunAttribute ssfa;
+    n.setAttribute( ssfa, node_values[0] );
+  }else if( attr=="sygus-synth-fun-var-list" ){
+    Assert( node_values.size()==1 );
+    Trace("quant-attr-debug") << "Set sygus synth fun var list to " << n << " to "  << node_values[0] << std::endl;
+    SygusSynthFunVarListAttribute ssfvla;
+    n.setAttribute( ssfvla, node_values[0] );
   }else if( attr=="synthesis" ){
     Trace("quant-attr-debug") << "Set synthesis " << n << std::endl;
     SynthesisAttribute ca;
index 2d4a6e99c035402d79d9cc9afaf3216a55440f50..4cb41e19e77ca1a0f38255a7f6414e85344401eb 100644 (file)
@@ -1188,9 +1188,15 @@ Node QuantifiersRewriter::computePrenexAgg( Node n, bool topLevel, std::map< uns
           children[i] = children[i][1];
         }
       }
-      // TODO : keep the pattern
+      // keep the pattern
+      std::vector< Node > iplc;
+      if( n.getNumChildren()==3 ){
+        for( unsigned i=0; i<n[2].getNumChildren(); i++ ){
+          iplc.push_back( n[2][i] );
+        }
+      } 
       Node nb = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( OR, children );
-      ret = mkForall( args, nb, true );
+      ret = mkForall( args, nb, iplc, true );
     }else{
       std::vector< Node > args;
       std::vector< Node > nargs;
@@ -1347,14 +1353,19 @@ Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, QAttri
     return NodeManager::currentNM()->mkNode( kind::FORALL, children );
   }
 }
+
 Node QuantifiersRewriter::mkForall( std::vector< Node >& args, Node body, bool marked ) {
+  std::vector< Node > iplc;
+  return mkForall( args, body, iplc, marked );
+}
+
+Node QuantifiersRewriter::mkForall( std::vector< Node >& args, Node body, std::vector< Node >& iplc, bool marked ) {
   if( args.empty() ){
     return body;
   }else{
     std::vector< Node > children;
     children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args ) );
     children.push_back( body );
-    std::vector< Node > iplc;
     if( marked ){
       Node avar = NodeManager::currentNM()->mkSkolem( "id", NodeManager::currentNM()->booleanType() );
       QuantIdNumAttribute ida;
index 0edea5faeccaff9b16c8f2b31d073b77e8dd8926..d1f81972610fd0bc65ba739cd4d7b74c191193c1 100644 (file)
@@ -94,6 +94,7 @@ public:
   static Node preprocess( Node n, bool isInst = false );
   static Node mkForAll( std::vector< Node >& args, Node body, QAttributes& qa );
   static Node mkForall( std::vector< Node >& args, Node body, bool marked = false );
+  static Node mkForall( std::vector< Node >& args, Node body, std::vector< Node >& iplc, bool marked = false );
 };/* class QuantifiersRewriter */
 
 }/* CVC4::theory::quantifiers namespace */
index 7d4f5b43361e8cd12b9d0543f8522f5d6c77b0b2..9e7f174c1f8534463b67db0e02014c16ecfc51f9 100644 (file)
@@ -17,6 +17,7 @@
 #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"
@@ -30,6 +31,8 @@
 #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;
@@ -1102,7 +1105,10 @@ void getSelfSel( const Datatype& dt, const DatatypeConstructor& dc, Node n, Type
     }
     */
     for( unsigned k=0; k<ssc.size(); k++ ){
-      selfSel.push_back( NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, dc[j].getSelector(), n ) );
+      Node ss = NodeManager::currentNM()->mkNode( APPLY_SELECTOR_TOTAL, dc.getSelectorInternal( n.getType().toType(), j ), n );
+      if( std::find( selfSel.begin(), selfSel.end(), ss )==selfSel.end() ){
+        selfSel.push_back( ss );
+      }
     }
   }
 }
@@ -1843,13 +1849,16 @@ Node TermDb::ensureType( Node n, TypeNode tn ) {
 
 void TermDb::getRelevancyCondition( Node n, std::vector< Node >& cond ) {
   if( n.getKind()==APPLY_SELECTOR_TOTAL ){
-    unsigned scindex = Datatype::cindexOf(n.getOperator().toExpr());
-    const Datatype& dt = ((DatatypeType)(n[0].getType()).toType()).getDatatype();
-    Node rc = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[scindex].getTester() ), n[0] ).negate();
-    if( std::find( cond.begin(), cond.end(), rc )==cond.end() ){
-      cond.push_back( rc );
+    // don't worry about relevancy conditions if using shared selectors
+    if( !options::dtSharedSelectors() ){
+      unsigned scindex = Datatype::cindexOf(n.getOperator().toExpr());
+      const Datatype& dt = ((DatatypeType)(n[0].getType()).toType()).getDatatype();
+      Node rc = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[scindex].getTester() ), n[0] ).negate();
+      if( std::find( cond.begin(), cond.end(), rc )==cond.end() ){
+        cond.push_back( rc );
+      }
+      getRelevancyCondition( n[0], cond );
     }
-    getRelevancyCondition( n[0], cond );
   }
 }
 
@@ -1956,6 +1965,10 @@ bool TermDb::isComm( Kind k ) {
          k==BITVECTOR_PLUS || k==BITVECTOR_MULT || k==BITVECTOR_AND || k==BITVECTOR_OR || k==BITVECTOR_XOR || k==BITVECTOR_XNOR;
 }
 
+bool TermDb::isNonAdditive( Kind k ) {
+  return k==AND || k==OR || k==BITVECTOR_AND || k==BITVECTOR_OR;
+}
+
 bool TermDb::isBoolConnective( Kind k ) {
   return k==OR || k==AND || k==EQUAL || k==ITE || k==FORALL || k==NOT || k==SEP_STAR;
 }
@@ -2278,6 +2291,22 @@ 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 );
@@ -2287,16 +2316,23 @@ bool TermDbSygus::reset( Theory::Effort e ) {
   return true;  
 }
 
-TNode TermDbSygus::getVar( TypeNode tn, int i ) {
-  while( i>=(int)d_fv[tn].size() ){
-    std::stringstream ss;
-    TypeNode vtn = tn;
+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();
-      ss << "fv_" << dt.getName() << "_" << i;
       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;
     }
@@ -2304,23 +2340,43 @@ TNode TermDbSygus::getVar( TypeNode tn, int i ) {
     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[tn].push_back( v );
+    d_fv[sindex][tn].push_back( v );
   }
-  return d_fv[tn][i];
+  return d_fv[sindex][tn][i];
 }
 
-TNode TermDbSygus::getVarInc( TypeNode tn, std::map< TypeNode, int >& var_count ) {
+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 getVar( tn, 0 );
+    return getFreeVar( tn, 0, useSygusType );
   }else{
     int index = it->second;
     var_count[tn]++;
-    return getVar( tn, index );
+    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];
@@ -2433,7 +2489,7 @@ bool TermDbSygus::getMatch( Node t, TypeNode st, int& index_found, std::vector<
 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() ){
-    registerSygusType( tn );
+    Assert( isRegistered( tn ) );
     std::map< TypeNode, int > var_count;
     std::map< int, Node > pre;
     Node g = mkGeneric( dt, c, var_count, pre );
@@ -2441,7 +2497,7 @@ Node TermDbSygus::getGenericBase( TypeNode tn, const Datatype& dt, int c ) {
     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") << "Sygus DB : Generic base " << dt[c].getName() << " : " << gr << std::endl;
+    Trace("sygus-db-debug") << "Sygus DB : Generic base " << dt[c].getName() << " : " << gr << std::endl;
     d_generic_base[tn][c] = gr;
     return gr;
   }else{
@@ -2458,7 +2514,7 @@ Node TermDbSygus::mkGeneric( const Datatype& dt, int c, std::map< TypeNode, int
   if( op.getKind()!=BUILTIN ){
     children.push_back( op );
   }
-  Trace("sygus-db") << "mkGeneric " << dt.getName() << " " << op << " " << op.getKind() << "..." << std::endl;
+  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;
@@ -2466,7 +2522,7 @@ Node TermDbSygus::mkGeneric( const Datatype& dt, int c, std::map< TypeNode, int
     if( it!=pre.end() ){
       a = it->second;
     }else{
-      a = getVarInc( tna, var_count );
+      a = getFreeVarInc( tna, var_count, true );
     }
     Assert( !a.isNull() );
     children.push_back( a );
@@ -2476,7 +2532,7 @@ Node TermDbSygus::mkGeneric( const Datatype& dt, int c, std::map< TypeNode, int
     ret = NodeManager::currentNM()->mkNode( op, children );
   }else{
     Kind ok = getOperatorKind( op );
-    Trace("sygus-db") << "Operator kind is " << ok << std::endl;
+    Trace("sygus-db-debug") << "Operator kind is " << ok << std::endl;
     if( children.size()==1 && ok==kind::UNDEFINED_KIND ){
       ret = children[0];
     }else{
@@ -2490,34 +2546,50 @@ Node TermDbSygus::mkGeneric( const Datatype& dt, int c, std::map< TypeNode, int
       */
     }
   }
-  Trace("sygus-db") << "...returning " << ret << std::endl;
+  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();
-    Assert( 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 ) );
+    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 );
     }
-    Node 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;
     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 ) {
@@ -2537,7 +2609,7 @@ Node TermDbSygus::builtinToSygusConst( Node c, TypeNode tn, int rcons_depth ) {
       k.setAttribute(spa,c);
       sc = k;
     }else{
-      int carg = getOpArg( tn, c );
+      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() ) );
@@ -2560,7 +2632,7 @@ Node TermDbSygus::builtinToSygusConst( Node c, TypeNode tn, int rcons_depth ) {
             //accelerated, recursive reconstruction of constants
             Kind pk = getPlusKind( TypeNode::fromType( dt.getSygusType() ) );
             if( pk!=UNDEFINED_KIND ){
-              int arg = getKindArg( tn, pk );
+              int arg = getKindConsNum( tn, pk );
               if( arg!=-1 ){
                 Kind ck = getComparisonKind( TypeNode::fromType( dt.getSygusType() ) );
                 Kind pkm = getPlusKind( TypeNode::fromType( dt.getSygusType() ), true );
@@ -2663,11 +2735,11 @@ Node TermDbSygus::getNormalized( TypeNode t, Node prog, bool do_pre_norm, bool d
   }
 }
 
-int TermDbSygus::getSygusTermSize( Node n ){
-  if( isVar( n ) ){
+unsigned TermDbSygus::getSygusTermSize( Node n ){
+  if( n.getNumChildren()==0 ){
     return 0;
   }else{
-    int sum = 0;
+    unsigned sum = 0;
     for( unsigned i=0; i<n.getNumChildren(); i++ ){
       sum += getSygusTermSize( n[i] );
     }
@@ -2675,6 +2747,23 @@ int TermDbSygus::getSygusTermSize( Node n ){
   }
 }
 
+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;
@@ -2700,17 +2789,22 @@ bool TermDbSygus::isAntisymmetric( Kind k, Kind& dk ) {
 }
 
 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 ){
+    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_SUB ){
+    }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==BITVECTOR_UDIV || ik==BITVECTOR_SDIV ){
+    }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 ) ){
@@ -2722,20 +2816,60 @@ bool TermDbSygus::isIdempotentArg( Node n, Kind ik, int arg ) {
 }
 
 
-bool TermDbSygus::isSingularArg( Node n, Kind ik, int arg ) {
+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 true;
-    }else if( ik==DIVISION || ik==BITVECTOR_UDIV || ik==BITVECTOR_SDIV ){
-      return arg==0;
+      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 true;
+      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 false;
+  return Node::null();
 }
 
 bool TermDbSygus::hasOffsetArg( Kind ik, int arg, int& offset, Kind& ok ) {
@@ -2759,6 +2893,392 @@ bool TermDbSygus::hasOffsetArg( Kind ik, int arg, int& offset, Kind& ok ) {
 }
 
 
+
+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() ){
@@ -2774,6 +3294,10 @@ Node TermDbSygus::getTypeValue( TypeNode tn, int val ) {
       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;
@@ -2810,6 +3334,7 @@ Node TermDbSygus::getTypeValueOffset( TypeNode tn, Node val, int offset, int& st
         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;
@@ -2833,17 +3358,71 @@ struct sortConstants {
   }
 };
 
-void TermDbSygus::registerSygusType( TypeNode tn ){
-  if( d_register.find( tn )==d_register.end() ){
-    if( !tn.isDatatype() ){
-      d_register[tn] = TypeNode::null();
+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;
-      d_register[tn] = TypeNode::fromType( dt.getSygusType() );
-      if( d_register[tn].isNull() ){
-        Trace("sygus-db") << "...not sygus." << std::endl;
-      }else{
+      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 );
@@ -2896,65 +3475,373 @@ void TermDbSygus::registerSygusType( TypeNode tn ){
             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 );
+          }
+        }
       }
     }
   }
 }
 
-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::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;
+  }
 }
 
-int TermDbSygus::getKindArg( 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;
-    }
+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;
   }
-  return -1;
 }
 
-int TermDbSygus::getConstArg( 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;
-    }
+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();
   }
-  return -1;
 }
 
-int TermDbSygus::getOpArg( TypeNode tn, Node n ) {
-  std::map< Node, int >::iterator it = d_ops[tn].find( n );
-  if( it!=d_ops[tn].end() ){
-    return it->second;
+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 -1;
+    return Node::null();
   }
 }
 
-bool TermDbSygus::hasKind( TypeNode tn, Kind k ) {
-  return getKindArg( tn, k )!=-1;
-}
-bool TermDbSygus::hasConst( TypeNode tn, Node n ) {
-  return getConstArg( tn, n )!=-1;
+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::hasOp( TypeNode tn, Node n ) {
-  return getOpArg( tn, n )!=-1;
+
+bool TermDbSygus::hasPbeExamples( Node e ) {
+  return d_pbe_exs.find( e )!=d_pbe_exs.end();
 }
 
-Node TermDbSygus::getArgOp( TypeNode tn, int i ) {
-  Assert( isRegistered( tn ) );
+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 );
@@ -2965,7 +3852,7 @@ Node TermDbSygus::getArgOp( TypeNode tn, int i ) {
   return Node::null();
 }
 
-Node TermDbSygus::getArgConst( TypeNode tn, int i ) {
+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() ){
@@ -2977,7 +3864,7 @@ Node TermDbSygus::getArgConst( TypeNode tn, int i ) {
   return Node::null();
 }
 
-Kind TermDbSygus::getArgKind( TypeNode tn, int i ) {
+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() ){
@@ -2990,7 +3877,7 @@ Kind TermDbSygus::getArgKind( TypeNode tn, int i ) {
 }
 
 bool TermDbSygus::isKindArg( TypeNode tn, int i ) {
-  return getArgKind( tn, i )!=UNDEFINED_KIND;
+  return getConsNumKind( tn, i )!=UNDEFINED_KIND;
 }
 
 bool TermDbSygus::isConstArg( TypeNode tn, int i ) {
@@ -3016,6 +3903,30 @@ TypeNode TermDbSygus::getArgType( const DatatypeConstructor& c, int i ) {
   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() ) ){
@@ -3101,6 +4012,49 @@ bool TermDbSygus::doCompare( Node a, Node b, Kind k ) {
   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;
@@ -3227,6 +4181,15 @@ Node TermDbSygus::getAnchor( Node 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() ){
@@ -3238,6 +4201,15 @@ void TermDbSygus::registerEvalTerm( Node n ) {
           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() );
@@ -3245,15 +4217,14 @@ void TermDbSygus::registerEvalTerm( Node n ) {
             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++ ){
-              //if( var_list[j-1].getType().isBoolean() ){
-              //  //TODO: remove this case when boolean term conversion is eliminated
-              //  Node c = NodeManager::currentNM()->mkConst(BitVector(1u, 1u));
-              //  d_eval_args[n[0]].back().push_back( n[j].eqNode( c ) );
-              //}else{
-                d_eval_args[n[0]].back().push_back( n[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;
           }
@@ -3277,7 +4248,11 @@ void TermDbSygus::registerModelValue( Node a, Node v, std::vector< Node >& terms
         Node vn = n.substitute( at, vt );
         vn = Rewriter::rewrite( vn );
         unsigned start = d_node_mv_args_proc[n][vn];
-        Node antec = n.eqNode( 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();
@@ -3291,20 +4266,78 @@ void TermDbSygus::registerModelValue( Node a, Node v, std::vector< Node >& terms
         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++ ){
-          Assert( vars.size()==it->second[i].size() );
-          Node sBTerm = bTerm.substitute( vars.begin(), vars.end(), it->second[i].begin(), it->second[i].end() );
-          sBTerm = Rewriter::rewrite( sBTerm );
-          //Node lem = NodeManager::currentNM()->mkNode(EQUAL, d_evals[n][i], sBTerm ); 
-          //lem = NodeManager::currentNM()->mkNode( OR, antec.negate(), lem );
+          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( sBTerm );
-          exps.push_back( antec );
-          Trace("sygus-eager") << "Conclude : " << d_evals[n][i] << " == " << sBTerm << std::endl;
-          Trace("sygus-eager") << "   from " << antec << std::endl;
-          //Trace("sygus-eager") << "Lemma : " << lem << std::endl;
-          //lems.push_back( lem );
+          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();
       }
@@ -3312,9 +4345,139 @@ void TermDbSygus::registerModelValue( Node a, Node v, std::vector< Node >& terms
   }
 }
 
+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] );
@@ -3340,13 +4503,20 @@ Node TermDbSygus::unfold( Node en, std::map< Node, Node >& vtm, std::vector< Nod
         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 = en[0].getKind()==kind::APPLY_CONSTRUCTOR ? en[0][j] : NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, Node::fromExpr( dt[i][j].getSelector() ), en[0] );
+      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
@@ -3359,16 +4529,10 @@ Node TermDbSygus::unfold( Node en, std::map< Node, Node >& vtm, std::vector< Nod
     Node ret = mkGeneric( dt, i, var_count, pre );
     // if it is a variable, apply the substitution
     if( ret.getKind()==kind::BOUND_VARIABLE ){
-      //replace by argument
-      Node var_list = Node::fromExpr( dt.getSygusVarList() );
-      //TODO : set argument # on sygus variables
-      for( unsigned j=0; j<var_list.getNumChildren(); j++ ){
-        if( var_list[j]==ret ){
-          ret = args[j];
-          break;
-        }
-      }
-      Assert( ret.isConst() );
+      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() ) );
@@ -3380,6 +4544,714 @@ Node TermDbSygus::unfold( Node en, std::map< Node, Node >& vtm, std::vector< Nod
   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 912961e19a7f7f765c8fc032dc3a0c566fa68721..b1d4f7f2b336826f47ff8b1fb68ffb6a5e343091 100644 (file)
@@ -93,6 +93,14 @@ typedef expr::Attribute< LtePartialInstAttributeId, bool > LtePartialInstAttribu
 struct SygusProxyAttributeId {};
 typedef expr::Attribute<SygusProxyAttributeId, Node> SygusProxyAttribute;
 
+// attribute for associating a synthesis function with a first order variable
+struct SygusSynthFunAttributeId {};
+typedef expr::Attribute<SygusSynthFunAttributeId, Node> SygusSynthFunAttribute;
+
+// attribute for associating a variable list with a synth fun
+struct SygusSynthFunVarListAttributeId {};
+typedef expr::Attribute<SygusSynthFunVarListAttributeId, Node> SygusSynthFunVarListAttribute;
+
 //attribute for fun-def abstraction type
 struct AbsTypeFunDefAttributeId {};
 typedef expr::Attribute<AbsTypeFunDefAttributeId, bool> AbsTypeFunDefAttribute;
@@ -109,6 +117,11 @@ typedef expr::Attribute< QuantElimPartialAttributeId, bool > QuantElimPartialAtt
 struct QuantIdNumAttributeId {};
 typedef expr::Attribute< QuantIdNumAttributeId, uint64_t > QuantIdNumAttribute;
 
+/** sygus var num */
+struct SygusVarNumAttributeId {};
+typedef expr::Attribute<SygusVarNumAttributeId, uint64_t> SygusVarNumAttribute;
+
+
 
 class QuantifiersEngine;
 
@@ -495,6 +508,8 @@ public:
   static bool isAssoc( Kind k );
   /** is comm */
   static bool isComm( Kind k );
+  /** ( x k ... ) k x = ( x k ... ) */
+  static bool isNonAdditive( Kind k );
   /** is bool connective */
   static bool isBoolConnective( Kind k );
   /** is bool connective term */
@@ -559,20 +574,50 @@ 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;
+  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 getVar( TypeNode tn, int i );
-  TNode getVarInc( TypeNode tn, std::map< TypeNode, int >& var_count );
-  bool isVar( Node n ) { return d_fv_stype.find( n )!=d_fv_stype.end(); }
+  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;
@@ -581,8 +626,15 @@ private:
 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;
@@ -592,6 +644,7 @@ private:
   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;
@@ -601,36 +654,63 @@ private:
   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 getKindArg( TypeNode tn, Kind k );
-  int getConstArg( TypeNode tn, Node n );
-  int getOpArg( TypeNode tn, Node n );
+  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 getArgConst( TypeNode tn, int i );
-  Node getArgOp( TypeNode tn, int i );
-  Kind getArgKind( TypeNode tn, int i );
+  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 );
-  void registerSygusType( TypeNode tn );
   /** 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 */
-  bool isSingularArg( Node n, Kind ik, int arg );
+  Node isSingularArg( Node n, Kind ik, int arg );
   /** get offset arg */
   bool hasOffsetArg( Kind ik, int arg, int& offset, Kind& ok );
   /** get value */
@@ -643,10 +723,14 @@ public:
   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 );
-  int getSygusTermSize( Node n );
+  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 */
@@ -655,19 +739,36 @@ public:
   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 );
@@ -677,6 +778,87 @@ public:
     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 */
index 64160dc713379e7087e1ceb9d68f8110c51f9f3c..00a358e5ff9a154f88d77991bcf80d792871805b 100644 (file)
@@ -43,6 +43,8 @@ TheoryQuantifiers::TheoryQuantifiers(Context* c, context::UserContext* u, Output
   out.handleUserAttribute( "conjecture", this );
   out.handleUserAttribute( "fun-def", this );
   out.handleUserAttribute( "sygus", this );
+  out.handleUserAttribute( "sygus-synth-fun", this );
+  out.handleUserAttribute( "sygus-synth-fun-var-list", this );
   out.handleUserAttribute( "synthesis", this );
   out.handleUserAttribute( "quant-inst-max-level", this );
   out.handleUserAttribute( "rr-priority", this );
index 5f4c7d79db439b664b066fd19fe183c4ca145cdd..d179c447ec00a45023b33046b3c1390ab367dee7 100644 (file)
@@ -66,8 +66,9 @@ public:
     if( tuple.getKind() == kind::APPLY_CONSTRUCTOR ) {
       return tuple[n_th];
     }
-    Datatype dt = tuple.getType().getDatatype();
-    return NodeManager::currentNM()->mkNode(kind::APPLY_SELECTOR_TOTAL, dt[0][n_th].getSelector(), tuple);
+    TypeNode tn = tuple.getType();
+    Datatype dt = tn.getDatatype();
+    return NodeManager::currentNM()->mkNode(kind::APPLY_SELECTOR_TOTAL, dt[0].getSelectorInternal( tn.toType(), n_th ), tuple);
   } 
   
   static Node reverseTuple( Node tuple ) {
diff --git a/test/regress/regress0/sygus/General_plus10.sy b/test/regress/regress0/sygus/General_plus10.sy
new file mode 100755 (executable)
index 0000000..ee26fac
--- /dev/null
@@ -0,0 +1,11 @@
+; EXPECT: unsat
+; COMMAND-LINE: --cegqi-si=all --no-dump-synth
+(set-logic LIA)
+
+(synth-fun fb () Int ((Start Int ((Constant Int)))))
+(synth-fun fc () Int ((Start Int ((Constant Int)))))
+
+(constraint (= fc (+ fb 10))) 
+
+(check-synth)
+
index 0764b5d77a9b3b971d39b0c99178ff6b08bddb2f..0786c3f31f41b24d4ae263c1b9f00b68ceb43a4d 100644 (file)
@@ -50,7 +50,19 @@ TESTS = commutative.sy \
         no-mention.sy \
         max2-univ.sy \
         strings-small.sy \
-        strings-unconstrained.sy
+        strings-unconstrained.sy \
+        tl-type-4x.sy \
+        tl-type-0.sy \
+        fg_polynomial3.sy \
+        icfp_14.12.sy \
+        strings-trivial-simp.sy \
+        icfp_easy-ite.sy \
+        strings-template-infer.sy \
+        strings-trivial.sy \
+        General_plus10.sy \
+        qe.sy \
+        cggmp.sy
+
 
 # sygus tests currently taking too long for make regress
 EXTRA_DIST = $(TESTS) \
diff --git a/test/regress/regress0/sygus/cggmp.sy b/test/regress/regress0/sygus/cggmp.sy
new file mode 100644 (file)
index 0000000..1ae1f53
--- /dev/null
@@ -0,0 +1,23 @@
+; EXPECT: unsat
+; COMMAND-LINE: --sygus-inv-templ=pre --no-dump-synth
+
+(set-logic LIA)
+
+(synth-inv inv-f ((i Int) (j Int)))
+
+(declare-primed-var i Int)
+(declare-primed-var j Int)
+
+(define-fun pre-f ((i Int) (j Int)) Bool
+(and (= i 1)  
+(= j 10)))
+
+(define-fun trans-f ((i Int) (j Int) (i! Int) (j! Int)) Bool
+(and (and (>= j i) (= i! (+ i 2))) (= j! (- j 1))))
+
+(define-fun post-f ((i Int) (j Int)) Bool
+(not (and (< j i) (not (= j 6)))))
+
+(inv-constraint inv-f pre-f trans-f post-f)
+
+(check-synth)
diff --git a/test/regress/regress0/sygus/fg_polynomial3.sy b/test/regress/regress0/sygus/fg_polynomial3.sy
new file mode 100644 (file)
index 0000000..dab92bb
--- /dev/null
@@ -0,0 +1,18 @@
+; EXPECT: unsat
+; COMMAND-LINE: --no-dump-synth
+
+(set-logic LIA)
+
+(synth-fun addExpr1 ((x Int) (y Int)) Int
+)
+
+(synth-fun addExpr2 ((x Int) (y Int)) Int
+)
+
+(declare-var x Int)
+(declare-var y Int)
+
+(constraint (= (+ (addExpr1 x y) (addExpr2 y x)) (- x (+ x y))))
+
+(check-synth)
+
diff --git a/test/regress/regress0/sygus/icfp_14.12.sy b/test/regress/regress0/sygus/icfp_14.12.sy
new file mode 100644 (file)
index 0000000..d9c19f8
--- /dev/null
@@ -0,0 +1,63 @@
+; EXPECT: unsat
+; COMMAND-LINE: --no-dump-synth
+(set-logic BV)
+
+(define-fun shr1 ((x (BitVec 64))) (BitVec 64) (bvlshr x #x0000000000000001))
+(define-fun shr4 ((x (BitVec 64))) (BitVec 64) (bvlshr x #x0000000000000004))
+(define-fun shr16 ((x (BitVec 64))) (BitVec 64) (bvlshr x #x0000000000000010))
+(define-fun shl1 ((x (BitVec 64))) (BitVec 64) (bvshl x #x0000000000000001))
+(define-fun if0 ((x (BitVec 64)) (y (BitVec 64)) (z (BitVec 64))) (BitVec 64) (ite (= x #x0000000000000001) y z))
+
+(synth-fun f ( (x (BitVec 64))) (BitVec 64)
+(
+
+(Start (BitVec 64) (#x0000000000000000 #x0000000000000001 x (bvnot Start)
+                    (shl1 Start)
+                   (shr1 Start)
+                   (shr4 Start)
+                   (shr16 Start)
+                   (bvand Start Start)
+                   (bvor Start Start)
+                   (bvxor Start Start)
+                   (bvadd Start Start)
+                   (if0 Start Start Start)
+ ))
+)
+)
+(constraint (= (f #x6E393354DFFAAB51) #xC8E366559002AA57))
+(constraint (= (f #xFDA75AD598A27135) #x812C529533AEC765))
+(constraint (= (f #x58682C0FA4F8DB6D) #xD3CBE9F82D839249))
+(constraint (= (f #x58FDC0941A7E079F) #xD3811FB5F2C0FC30))
+(constraint (= (f #xBDC9B88103ECB0C9) #xA11B23BF7E09A79B))
+(constraint (= (f #x000000000001502F) #xFFFFFFFFFFFF57E8))
+(constraint (= (f #x0000000000010999) #xFFFFFFFFFFFF7B33))
+(constraint (= (f #x0000000000013169) #xFFFFFFFFFFFF674B))
+(constraint (= (f #x000000000001B1A9) #xFFFFFFFFFFFF272B))
+(constraint (= (f #x0000000000016D77) #xFFFFFFFFFFFF4944))
+(constraint (= (f #x0000000000000001) #xFFFFFFFFFFFFFFFF))
+(constraint (= (f #x1ED2E25068744C80) #x0000000000000000))
+(constraint (= (f #x2D2144F9D8CDCBD6) #x0000000000000000))
+(constraint (= (f #xE5D371D100002E8A) #x0000000000000000))
+(constraint (= (f #xADFF6BA34EBDAD72) #x0000000000000000))
+(constraint (= (f #xDA9299B546AAB59A) #x0000000000000000))
+(constraint (= (f #x0000000000015C8A) #x0000000000000000))
+(constraint (= (f #x0000000000017066) #x0000000000000000))
+(constraint (= (f #x000000000001D9D8) #x0000000000000000))
+(constraint (= (f #x00000000000151AE) #x0000000000000000))
+(constraint (= (f #x0000000000017A14) #x0000000000000000))
+(constraint (= (f #xF0F0F0F0F0F0F0F2) #x0000000000000000))
+(constraint (= (f #x83163CFD5DDCCCFB) #xBE74E18151119982))
+(constraint (= (f #xEA31B6A50EF4E399) #x8AE724AD78858E33))
+(constraint (= (f #xE0B1EF549BB6D4B9) #x8FA70855B22495A3))
+(constraint (= (f #x086F9E13A16C363D) #xFBC830F62F49E4E1))
+(constraint (= (f #x2426824D3E67E342) #x0000000000000000))
+(constraint (= (f #xDD518DEFFF18308A) #x0000000000000000))
+(constraint (= (f #x21ECDADB06B3CB03) #xEF0992927CA61A7E))
+(constraint (= (f #x72B1976FBB63A82B) #xC6A73448224E2BEA))
+(constraint (= (f #x16CB47AE0281B27F) #xF49A5C28FEBF26C0))
+(constraint (= (f #x82DE7A1FCA0C0B8F) #xBE90C2F01AF9FA38))
+(constraint (= (f #x0000000000000001) #xFFFFFFFFFFFFFFFF))
+(constraint (= (f #xF0F0F0F0F0F0F0F2) #x0000000000000000))
+(constraint (= (f #x000000000001F0D4) #x0000000000000000))
+(constraint (= (f #x0000000000010067) #xFFFFFFFFFFFF7FCC))
+(check-synth)
diff --git a/test/regress/regress0/sygus/icfp_easy-ite.sy b/test/regress/regress0/sygus/icfp_easy-ite.sy
new file mode 100644 (file)
index 0000000..2482646
--- /dev/null
@@ -0,0 +1,34 @@
+; EXPECT: unsat
+; COMMAND-LINE: --no-dump-synth
+(set-logic BV)
+
+(define-fun shr1 ((x (BitVec 64))) (BitVec 64) (bvlshr x #x0000000000000001))
+(define-fun shr4 ((x (BitVec 64))) (BitVec 64) (bvlshr x #x0000000000000004))
+(define-fun shr16 ((x (BitVec 64))) (BitVec 64) (bvlshr x #x0000000000000010))
+(define-fun shl1 ((x (BitVec 64))) (BitVec 64) (bvshl x #x0000000000000001))
+(define-fun if0 ((x (BitVec 64)) (y (BitVec 64)) (z (BitVec 64))) (BitVec 64) (ite (= x #x0000000000000001) y z))
+
+(synth-fun f ( (x (BitVec 64))) (BitVec 64)
+(
+
+(Start (BitVec 64) (#x0000000000000000 #x0000000000000001 x (bvnot Start)
+                    (shl1 Start)
+                   (shr1 Start)
+                   (shr4 Start)
+                   (shr16 Start)
+                   (bvand Start Start)
+                   (bvor Start Start)
+                   (bvxor Start Start)
+                   (bvadd Start Start)
+                   (ite StartBool Start Start)
+ ))
+(StartBool Bool ((= Start #x0000000000000001)))
+)
+)
+(constraint (= (f #x0000000000000001) #x0000000000000001))
+
+(constraint (= (f #x0000000000100001) #x0000000000100001))
+
+(constraint (= (f #xE5D371D100002E8A) #x0000000000000000))
+
+(check-synth)
diff --git a/test/regress/regress0/sygus/qe.sy b/test/regress/regress0/sygus/qe.sy
new file mode 100644 (file)
index 0000000..eaff0fd
--- /dev/null
@@ -0,0 +1,12 @@
+; EXPECT: unsat
+; COMMAND-LINE: --cegqi-si=all --no-dump-synth
+(set-logic LIA)
+
+(synth-fun f ((x Int)) Int)
+
+(declare-var x Int)
+(declare-var y Int)
+
+(constraint (=> (or (= y 2) (= y 3)) (> (f x) y)))
+
+(check-synth)
diff --git a/test/regress/regress0/sygus/strings-template-infer.sy b/test/regress/regress0/sygus/strings-template-infer.sy
new file mode 100644 (file)
index 0000000..498e713
--- /dev/null
@@ -0,0 +1,16 @@
+; EXPECT: unsat
+; COMMAND-LINE: --no-dump-synth
+(set-logic SLIA)
+(define-fun cA ((x String) (y String)) String (str.++ (str.++ x "A") y))
+(synth-fun f ((name String)) String
+    ((Start String (name "A" "B" ""
+                       (cA Start Start)))))
+
+
+(declare-var name String)
+(constraint (= (f "BB") "AAAAAAAAAAAA"))
+(check-synth)
diff --git a/test/regress/regress0/sygus/strings-trivial-simp.sy b/test/regress/regress0/sygus/strings-trivial-simp.sy
new file mode 100644 (file)
index 0000000..d37ac8b
--- /dev/null
@@ -0,0 +1,14 @@
+; EXPECT: unsat
+; COMMAND-LINE: --no-dump-synth
+(set-logic SLIA)
+(synth-fun f ((name String)) String
+    ((Start String (name "A" "B"
+                       (str.++ Start Start)))))
+
+
+(declare-var name String)
+(constraint (= (f "BB") "AAAAAAAAAAAABAAAAAAAABAAA"))
+(check-synth)
diff --git a/test/regress/regress0/sygus/strings-trivial.sy b/test/regress/regress0/sygus/strings-trivial.sy
new file mode 100644 (file)
index 0000000..f484792
--- /dev/null
@@ -0,0 +1,15 @@
+; EXPECT: unsat
+; COMMAND-LINE: --no-dump-synth
+(set-logic SLIA)
+(synth-fun f ((name String)) String
+    ((Start String (ntString))
+     (ntString String (name "A" "B"
+                       (str.++ ntString ntString)))))
+
+
+(declare-var name String)
+(constraint (= (f "B") "AAAAAAAAAAAAAAAAAAAAAAAAA"))
+(check-synth)
diff --git a/test/regress/regress0/sygus/tl-type-0.sy b/test/regress/regress0/sygus/tl-type-0.sy
new file mode 100644 (file)
index 0000000..ef046c8
--- /dev/null
@@ -0,0 +1,11 @@
+; EXPECT: unsat
+; COMMAND-LINE: --cegqi-si=none --no-dump-synth
+(set-logic LIA)
+(synth-fun f ((x Int)) Int
+    ((Start Int ((+ Term Term)))
+     (Term Int (x 0))))
+
+(declare-var x Int)
+(constraint (= (f x) 0))
+(check-synth)
+
diff --git a/test/regress/regress0/sygus/tl-type-4x.sy b/test/regress/regress0/sygus/tl-type-4x.sy
new file mode 100644 (file)
index 0000000..a18d130
--- /dev/null
@@ -0,0 +1,11 @@
+; EXPECT: unsat
+; COMMAND-LINE: --cegqi-si=none --no-dump-synth
+(set-logic LIA)
+(synth-fun f ((x Int)) Int
+    ((Start Int (Term (+ Start Start)))
+     (Term Int (x 0))))
+
+(declare-var x Int)
+(constraint (= (f x) (* 4 x)))
+(check-synth)
+
index 2dff1f1daa003660530cca6ea20f9e8ee34a64f9..f1f1c134281c8dd64e4423c264759839e1887394 100644 (file)
@@ -18,7 +18,14 @@ endif
 # put it below in "TESTS +="
 TESTS =        \
        hd-sdiv.sy \
-       stopwatch-bt.sy
+       stopwatch-bt.sy \
+       array_sum_dd.sy \
+       mpg_guard1-dd.sy \
+       VC22_a.sy \
+       inv_gen_n_c11.sy \
+       unbdd_inv_gen_ex7.sy \
+       icfp_easy_mt_ite.sy \
+  three.sy
 
 EXTRA_DIST = $(TESTS)
 
diff --git a/test/regress/regress1/sygus/VC22_a.sy b/test/regress/regress1/sygus/VC22_a.sy
new file mode 100644 (file)
index 0000000..75bed6a
--- /dev/null
@@ -0,0 +1,60 @@
+; EXPECT: unsat
+; COMMAND-LINE: --no-dump-synth
+(set-logic LIA)
+
+(synth-fun f ((x1 Int) (x2 Int)) Int
+       ((Start Int (0 1 x1 x2
+                               (ite StartBool Start Start)))
+               (StartBool Bool ((= Start Start)))))
+
+(define-fun vmin () Int 1)
+(define-fun vmax () Int 2)
+
+(define-fun Zero ((v Int)) Bool
+       (= v 0))
+
+(define-fun InV1 ((v Int)) Bool
+       (and (>= v vmin) (<= v vmax)))
+
+(define-fun InV2 ((v1 Int) (v2 Int)) Bool
+       (and (and (and (>= v1 vmin) (<= v1 vmax))
+                       (>= v2 vmin)) (<= v2 vmax)))
+
+(define-fun InVorZero ((v Int)) Bool
+       (or (InV1 v) (Zero v)))
+
+
+(define-fun UnsafeSame ((x1 Int) (x2 Int) (v1 Int) (v2 Int)) Bool
+       (or (and (>= x1 x2) (>= (+ x2 v2) (+ x1 v1)))
+               (and (>= x2 x1) (>= (+ x1 v1) (+ x2 v2)))))
+
+(define-fun Unsafe ((x1 Int) (x2 Int) (v1 Int) (v2 Int)) Bool
+       (UnsafeSame x1 x2 v1 v2))
+
+(define-fun BadSame ((x1 Int) (x2 Int)) Bool
+       (= x1 x2))
+
+(define-fun Bad ((x1 Int) (x2 Int)) Bool
+       (BadSame x1 x2))
+
+(declare-var x1 Int)
+(declare-var x2 Int)
+(declare-var v1 Int)
+(declare-var v2 Int)
+
+(constraint (InVorZero (f x1 x2)))
+
+(constraint (or (or (not (InV2 v1 v2))
+                       (Zero (f x1 x2)))
+               (and (not (Unsafe x1 x2 (f x1 x2) (f x1 x2)))
+                       (not (Zero (f (+ x1 (f x1 x2)) (+ x2 (f x1 x2))))))))
+
+(constraint (or (or (not (InV2 v1 v2))
+                       (or (Unsafe x1 x2 v1 v2)
+                               (Zero (f (+ x1 v1) (+ x2 v2)))))
+               (not (Zero (f x1 x2)))))
+
+(constraint (or (Bad x1 x2) (not (Zero (f x1 x2)))))
+
+(check-synth)
+
diff --git a/test/regress/regress1/sygus/array_sum_dd.sy b/test/regress/regress1/sygus/array_sum_dd.sy
new file mode 100644 (file)
index 0000000..dacd734
--- /dev/null
@@ -0,0 +1,11 @@
+; EXPECT: unsat
+; COMMAND-LINE: --no-dump-synth
+(set-logic LIA)
+(synth-fun findSum ( (y1 Int) (y2 Int) )Int (
+(Start Int ( 0 1 y1 y2 (+ Start Start) (ite BoolExpr Start Start))) 
+(BoolExpr Bool ((< Start Start) (<= Start Start)))))
+(declare-var x1 Int)
+(declare-var x2 Int)
+(constraint (=> (> (+ x1 x2) 0) (= (findSum x1 x2 ) x1)))
+(constraint (=> (<= (+ x1 x2) 0) (= (findSum x1 x2 ) x2)))
+(check-synth)
diff --git a/test/regress/regress1/sygus/icfp_easy_mt_ite.sy b/test/regress/regress1/sygus/icfp_easy_mt_ite.sy
new file mode 100644 (file)
index 0000000..b7428fd
--- /dev/null
@@ -0,0 +1,32 @@
+; EXPECT: unsat
+; COMMAND-LINE: --no-dump-synth
+(set-logic BV)
+
+(define-fun shr1 ((x (BitVec 64))) (BitVec 64) (bvlshr x #x0000000000000001))
+(define-fun shr4 ((x (BitVec 64))) (BitVec 64) (bvlshr x #x0000000000000004))
+(define-fun shr16 ((x (BitVec 64))) (BitVec 64) (bvlshr x #x0000000000000010))
+(define-fun shl1 ((x (BitVec 64))) (BitVec 64) (bvshl x #x0000000000000001))
+(define-fun if0 ((x (BitVec 64)) (y (BitVec 64)) (z (BitVec 64))) (BitVec 64) (ite (= x #x0000000000000001) y z))
+
+(synth-fun f ( (x (BitVec 64))) (BitVec 64)
+(
+
+(Start (BitVec 64) (#x0000000000000000 #x0000000000000001 x (bvnot Start)
+                    (shl1 Start)
+                   (shr1 Start)
+                   (shr4 Start)
+                   (shr16 Start)
+                   (bvand Start Start)
+                   (bvor Start Start)
+                   (bvxor Start Start)
+                   (bvadd Start Start)
+                   (ite StartBool Start Start)
+ ))
+(StartBool Bool ((= Start #x0000000000000001)))
+)
+)
+(constraint (= (f #x6E393354DFFAAB51) #xC8E366559002AA57))
+
+(constraint (= (f #xE5D371D100002E8A) #x0000000000000000))
+
+(check-synth)
diff --git a/test/regress/regress1/sygus/inv_gen_fig8.sy b/test/regress/regress1/sygus/inv_gen_fig8.sy
new file mode 100644 (file)
index 0000000..5496f3c
--- /dev/null
@@ -0,0 +1,46 @@
+; EXPECT: unsat
+; COMMAND-LINE: --no-dump-synth
+(set-logic LIA)
+(synth-fun inv ((l Int)) Bool
+    (
+        (Start Bool ((and AtomicFormula AtomicFormula)
+                     (or AtomicFormula AtomicFormula)))
+        (AtomicFormula Bool ((<= Sum Const) (= Sum Const)))
+        (Sum Int ((+ Term Term)))
+        (Term Int ((* Sign Var)))
+        (Sign Int (0 1 -1))
+        (Var Int (l))
+        (Const Int (-3 -2 -1 0 1 2 3))
+    )
+)
+
+(define-fun implies ((b1 Bool) (b2 Bool)) Bool (or (not b1) b2))
+(define-fun and3 ((b1 Bool) (b2 Bool) (b3 Bool)) Bool (and (and b1 b2) b3))
+(define-fun and4 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool)) Bool (and (and3 b1 b2 b3) b4))
+(define-fun and5 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool) (b5 Bool)) Bool (and (and4 b1 b2 b3 b4) b5))
+(define-fun and6 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool) (b5 Bool) (b6 Bool)) Bool (and (and5 b1 b2 b3 b4 b5) b6))
+(define-fun or3 ((b1 Bool) (b2 Bool) (b3 Bool)) Bool (or (or b1 b2) b3))
+(define-fun or4 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool)) Bool (or (or3 b1 b2 b3) b4))
+(define-fun or5 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool) (b5 Bool)) Bool (or (or4 b1 b2 b3 b4) b5))
+
+(declare-var x0 Int)
+(declare-var x1 Int)
+(declare-var x2 Int)
+(declare-var x3 Int)
+(declare-var x4 Int)
+(declare-var l Int)
+(declare-var x0p Int)
+(declare-var x1p Int)
+(declare-var x2p Int)
+(declare-var x3p Int)
+(declare-var x4p Int)
+
+(constraint (implies (and6 (= l 0) (or (= x0p (+ x0 1)) (= x0p (- x0 1))) 
+                                 (or (= x1p (+ x1 1)) (= x1p (- x1 1)))
+                                 (or (= x2p (+ x2 1)) (= x2p (- x2 1)))
+                                 (or (= x3p (+ x3 1)) (= x3p (- x3 1)))
+                                 (or (= x4p (+ x4 1)) (= x4p (- x4 1)))) 
+                    (inv l)))
+(constraint (implies (and (inv l) (not (= l 0))) false))
+
+(check-synth)
diff --git a/test/regress/regress1/sygus/inv_gen_n_c11.sy b/test/regress/regress1/sygus/inv_gen_n_c11.sy
new file mode 100644 (file)
index 0000000..946f284
--- /dev/null
@@ -0,0 +1,36 @@
+; EXPECT: unsat
+; COMMAND-LINE: --no-dump-synth
+(set-logic LIA)
+(synth-fun inv ((i Int) (l Int)) Bool
+    (
+        (Start Bool ((and AtomicFormula AtomicFormula)
+                     (or AtomicFormula AtomicFormula)))
+        (AtomicFormula Bool ((<= Sum Const) (= Sum Const)))
+        (Sum Int ((+ Term Term)))
+        (Term Int ((* Sign Var)))
+        (Sign Int (0 1 -1))
+        (Var Int (i l))
+        (Const Int (-7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7))
+    )
+)
+
+(define-fun implies ((b1 Bool) (b2 Bool)) Bool (or (not b1) b2))
+(define-fun and3 ((b1 Bool) (b2 Bool) (b3 Bool)) Bool (and (and b1 b2) b3))
+(define-fun and4 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool)) Bool (and (and3 b1 b2 b3) b4))
+(define-fun and5 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool) (b5 Bool)) Bool (and (and4 b1 b2 b3 b4) b5))
+(define-fun and6 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool) (b5 Bool) (b6 Bool)) Bool (and (and5 b1 b2 b3 b4 b5) b6))
+(define-fun or3 ((b1 Bool) (b2 Bool) (b3 Bool)) Bool (or (or b1 b2) b3))
+(define-fun or4 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool)) Bool (or (or3 b1 b2 b3) b4))
+(define-fun or5 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool) (b5 Bool)) Bool (or (or4 b1 b2 b3 b4) b5))
+
+(declare-var i Int)
+(declare-var l Int)
+(declare-var i1 Int)
+(declare-var l1 Int)
+(declare-var l2 Int)
+
+(constraint (implies (= l 0) (inv i l)))
+(constraint (implies (and5 (inv i l) (implies (= l 4) (= l1 0)) (implies (not (= l 4)) (= l1 l)) (not (or (< l1 0) (>= l1 5))) (= l2 (+ l1 1))) (inv i l2)))
+(constraint (implies (and4 (inv i l) (implies (= l 4) (= l1 0)) (implies (not (= l 4)) (= l1 l)) (or (< l1 0) (>= l1 5))) false))
+
+(check-synth)
diff --git a/test/regress/regress1/sygus/mpg_guard1-dd.sy b/test/regress/regress1/sygus/mpg_guard1-dd.sy
new file mode 100644 (file)
index 0000000..e574f7e
--- /dev/null
@@ -0,0 +1,27 @@
+; EXPECT: unsat
+; COMMAND-LINE: --no-dump-synth
+(set-logic LIA)
+
+(synth-fun eq1 ( (x Int) (y Int) ) Int
+    ((Start Int (x
+                 y
+                 0
+                 (+ Start Start)
+                 (- Start Start)
+                 (ite StartBool Start Start)))
+     (StartBool Bool ((and StartBool StartBool)
+                      (<=  Start Start)
+                      (=   Start Start)))))
+
+(define-fun iteB (( b1 Bool ) (b2 Bool ) (b3 Bool )) Bool (or (and b1 b2) (and (not b1) b3)))
+
+(declare-var x Int) 
+(declare-var y Int) 
+
+(constraint (iteB (>= x 0) 
+                  (= (eq1 x y) (+ x x))
+                             (= (eq1 x y) x)
+))
+
+(check-synth)
+
diff --git a/test/regress/regress1/sygus/three.sy b/test/regress/regress1/sygus/three.sy
new file mode 100644 (file)
index 0000000..6e2ce3a
--- /dev/null
@@ -0,0 +1,30 @@
+; EXPECT: unsat
+; COMMAND-LINE: --no-dump-synth 
+
+(set-logic LIA)
+
+(synth-fun f ((x Int)) Int
+    ((Start Int (
+                 x
+                 3
+                 7
+                 10
+                 (* Start Start)
+                 (mod Start Start)))))
+
+(declare-var x Int)
+
+(constraint (= (f x) (f (+ x 10))))
+(constraint (= (f 1) 3))
+(constraint (= (f 2) 6))
+(constraint (= (f 3) 9))
+(constraint (= (f 4) 2))
+(constraint (= (f 5) 5))
+(constraint (= (f 6) 8))
+(constraint (= (f 7) 1))
+(constraint (= (f 8) 4))
+(constraint (= (f 9) 7))
+(constraint (= (f 0) 0))
+
+(check-synth)
+
diff --git a/test/regress/regress1/sygus/unbdd_inv_gen_ex7.sy b/test/regress/regress1/sygus/unbdd_inv_gen_ex7.sy
new file mode 100644 (file)
index 0000000..f840fa5
--- /dev/null
@@ -0,0 +1,40 @@
+; EXPECT: unsat
+; COMMAND-LINE: --no-dump-synth
+(set-logic LIA)
+(synth-fun inv ((i Int) (y Int) (l Int)) Bool
+    (
+        (Start Bool ((and AtomicFormula AtomicFormula)
+                     (or AtomicFormula AtomicFormula)))
+        (AtomicFormula Bool ((<= Sum Const) (= Sum Const)))
+        (Sum Int ((+ Term Term)))
+        (Term Int ((* Sign Var)))
+        (Sign Int (0 1 -1))
+        (Var Int (i y l))
+        (Const Int ((+ Const Const) (- Const Const) 0 1))
+    )
+)
+
+(define-fun implies ((b1 Bool) (b2 Bool)) Bool (or (not b1) b2))
+(define-fun and3 ((b1 Bool) (b2 Bool) (b3 Bool)) Bool (and (and b1 b2) b3))
+(define-fun and4 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool)) Bool (and (and3 b1 b2 b3) b4))
+(define-fun and5 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool) (b5 Bool)) Bool (and (and4 b1 b2 b3 b4) b5))
+(define-fun and6 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool) (b5 Bool) (b6 Bool)) Bool (and (and5 b1 b2 b3 b4 b5) b6))
+(define-fun or3 ((b1 Bool) (b2 Bool) (b3 Bool)) Bool (or (or b1 b2) b3))
+(define-fun or4 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool)) Bool (or (or3 b1 b2 b3) b4))
+(define-fun or5 ((b1 Bool) (b2 Bool) (b3 Bool) (b4 Bool) (b5 Bool)) Bool (or (or4 b1 b2 b3 b4) b5))
+
+(declare-var i Int)
+(declare-var x Int)
+(declare-var y Int)
+(declare-var l Int)
+(declare-var i1 Int)
+(declare-var x1 Int)
+(declare-var y1 Int)
+(declare-var l1 Int)
+
+(constraint (implies (or3 (< x 0) (< y 0) (> y x)) true))
+(constraint (implies (and3 (not (or3 (< x 0) (< y 0) (> y x))) (= l x) (= i 0)) (inv i y l)))
+(constraint (implies (and4 (inv i y l) (< i y) (not (or (< i 0) (>= i l))) (= i1 (+ i 1))) (inv i1 y l)))
+(constraint (implies (and3 (inv i y l) (< i y) (or (< i 0) (>= i  l))) false))
+
+(check-synth)