summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am2
-rw-r--r--src/compat/cvc3_compat.cpp10
-rw-r--r--src/expr/datatype.cpp118
-rw-r--r--src/expr/datatype.h31
-rw-r--r--src/expr/node.cpp7
-rw-r--r--src/main/command_executor_portfolio.cpp8
-rw-r--r--src/options/Makefile.am1
-rw-r--r--src/options/datatypes_modes.h44
-rw-r--r--src/options/datatypes_options18
-rw-r--r--src/options/options_handler.cpp22
-rw-r--r--src/options/options_handler.h3
-rw-r--r--src/options/quantifiers_modes.h13
-rw-r--r--src/options/quantifiers_options34
-rw-r--r--src/parser/cvc/Cvc.g8
-rw-r--r--src/parser/smt2/Smt2.g132
-rw-r--r--src/parser/smt2/smt2.cpp541
-rw-r--r--src/parser/smt2/smt2.h23
-rw-r--r--src/printer/cvc/cvc_printer.cpp14
-rw-r--r--src/printer/smt2/smt2_printer.cpp4
-rw-r--r--src/smt/smt_engine.cpp13
-rw-r--r--src/theory/datatypes/datatypes_rewriter.h60
-rw-r--r--src/theory/datatypes/datatypes_sygus.cpp2310
-rw-r--r--src/theory/datatypes/datatypes_sygus.h203
-rw-r--r--src/theory/datatypes/kinds16
-rw-r--r--src/theory/datatypes/theory_datatypes.cpp219
-rw-r--r--src/theory/datatypes/theory_datatypes.h14
-rw-r--r--src/theory/datatypes/theory_datatypes_type_rules.h54
-rw-r--r--src/theory/quantifiers/bounded_integers.cpp2
-rw-r--r--src/theory/quantifiers/ce_guided_instantiation.cpp1487
-rw-r--r--src/theory/quantifiers/ce_guided_instantiation.h103
-rw-r--r--src/theory/quantifiers/ce_guided_pbe.cpp1859
-rw-r--r--src/theory/quantifiers/ce_guided_pbe.h273
-rw-r--r--src/theory/quantifiers/ce_guided_single_inv.cpp700
-rw-r--r--src/theory/quantifiers/ce_guided_single_inv.h85
-rw-r--r--src/theory/quantifiers/ce_guided_single_inv_sol.cpp8
-rw-r--r--src/theory/quantifiers/ceg_t_instantiator.cpp4
-rw-r--r--src/theory/quantifiers/inst_match_generator.cpp4
-rw-r--r--src/theory/quantifiers/inst_strategy_cbqi.cpp3
-rw-r--r--src/theory/quantifiers/quant_util.cpp72
-rw-r--r--src/theory/quantifiers/quant_util.h18
-rw-r--r--src/theory/quantifiers/quantifiers_attributes.cpp10
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.cpp17
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.h1
-rw-r--r--src/theory/quantifiers/term_database.cpp2068
-rw-r--r--src/theory/quantifiers/term_database.h212
-rw-r--r--src/theory/quantifiers/theory_quantifiers.cpp2
-rw-r--r--src/theory/sets/rels_utils.h5
-rwxr-xr-xtest/regress/regress0/sygus/General_plus10.sy11
-rw-r--r--test/regress/regress0/sygus/Makefile.am14
-rw-r--r--test/regress/regress0/sygus/cggmp.sy23
-rw-r--r--test/regress/regress0/sygus/fg_polynomial3.sy18
-rw-r--r--test/regress/regress0/sygus/icfp_14.12.sy63
-rw-r--r--test/regress/regress0/sygus/icfp_easy-ite.sy34
-rw-r--r--test/regress/regress0/sygus/qe.sy12
-rw-r--r--test/regress/regress0/sygus/strings-template-infer.sy16
-rw-r--r--test/regress/regress0/sygus/strings-trivial-simp.sy14
-rw-r--r--test/regress/regress0/sygus/strings-trivial.sy15
-rw-r--r--test/regress/regress0/sygus/tl-type-0.sy11
-rw-r--r--test/regress/regress0/sygus/tl-type-4x.sy11
-rw-r--r--test/regress/regress1/sygus/Makefile.am9
-rw-r--r--test/regress/regress1/sygus/VC22_a.sy60
-rw-r--r--test/regress/regress1/sygus/array_sum_dd.sy11
-rw-r--r--test/regress/regress1/sygus/icfp_easy_mt_ite.sy32
-rw-r--r--test/regress/regress1/sygus/inv_gen_fig8.sy46
-rw-r--r--test/regress/regress1/sygus/inv_gen_n_c11.sy36
-rw-r--r--test/regress/regress1/sygus/mpg_guard1-dd.sy27
-rw-r--r--test/regress/regress1/sygus/three.sy30
-rw-r--r--test/regress/regress1/sygus/unbdd_inv_gen_ex7.sy40
68 files changed, 7815 insertions, 3573 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 157fe33d2..6cbed6fda 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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 \
diff --git a/src/compat/cvc3_compat.cpp b/src/compat/cvc3_compat.cpp
index 1226d4db5..be24dacdd 100644
--- a/src/compat/cvc3_compat.cpp
+++ b/src/compat/cvc3_compat.cpp
@@ -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) {
diff --git a/src/expr/datatype.cpp b/src/expr/datatype.cpp
index 39bdddbad..4f1fc82b1 100644
--- a/src/expr/datatype.cpp
+++ b/src/expr/datatype.cpp
@@ -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");
diff --git a/src/expr/datatype.h b/src/expr/datatype.h
index 456e70fd5..84588fef0 100644
--- a/src/expr/datatype.h
+++ b/src/expr/datatype.h
@@ -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
diff --git a/src/expr/node.cpp b/src/expr/node.cpp
index 262085a23..e45ca49e0 100644
--- a/src/expr/node.cpp
+++ b/src/expr/node.cpp
@@ -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);
diff --git a/src/main/command_executor_portfolio.cpp b/src/main/command_executor_portfolio.cpp
index 25b160d6c..948e05ad3 100644
--- a/src/main/command_executor_portfolio.cpp
+++ b/src/main/command_executor_portfolio.cpp
@@ -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 ||
diff --git a/src/options/Makefile.am b/src/options/Makefile.am
index 5a9fa54e6..ff889bcb2 100644
--- a/src/options/Makefile.am
+++ b/src/options/Makefile.am
@@ -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
index 000000000..3576ffc72
--- /dev/null
+++ b/src/options/datatypes_modes.h
@@ -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 */
diff --git a/src/options/datatypes_options b/src/options/datatypes_options
index bb92b4e05..d4d3e941c 100644
--- a/src/options/datatypes_options
+++ b/src/options/datatypes_options
@@ -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
diff --git a/src/options/options_handler.cpp b/src/options/options_handler.cpp
index 85fe1453f..5658b17b0 100644
--- a/src/options/options_handler.cpp
+++ b/src/options/options_handler.cpp
@@ -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);
diff --git a/src/options/options_handler.h b/src/options/options_handler.h
index fa87149f8..16c77b166 100644
--- a/src/options/options_handler.h
+++ b/src/options/options_handler.h
@@ -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);
diff --git a/src/options/quantifiers_modes.h b/src/options/quantifiers_modes.h
index 18c3bfeda..0b410e3fe 100644
--- a/src/options/quantifiers_modes.h
+++ b/src/options/quantifiers_modes.h
@@ -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,
diff --git a/src/options/quantifiers_options b/src/options/quantifiers_options
index f15723e08..2cbf15873 100644
--- a/src/options/quantifiers_options
+++ b/src/options/quantifiers_options
@@ -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
diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g
index 622fa9c00..c865332e2 100644
--- a/src/parser/cvc/Cvc.g
+++ b/src/parser/cvc/Cvc.g
@@ -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);
}
)
)*
diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g
index 8194e1933..5d24ec024 100644
--- a/src/parser/smt2/Smt2.g
+++ b/src/parser/smt2/Smt2.g
@@ -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 ) );
diff --git a/src/parser/smt2/smt2.cpp b/src/parser/smt2/smt2.cpp
index 7fa71890e..fe5eb3ac8 100644
--- a/src/parser/smt2/smt2.cpp
+++ b/src/parser/smt2/smt2.cpp
@@ -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 */
diff --git a/src/parser/smt2/smt2.h b/src/parser/smt2/smt2.h
index 8222ac3a3..3eed0e871 100644
--- a/src/parser/smt2/smt2.h
+++ b/src/parser/smt2/smt2.h
@@ -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,
diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp
index 03029f27e..69ba63a47 100644
--- a/src/printer/cvc/cvc_printer.cpp
+++ b/src/printer/cvc/cvc_printer.cpp
@@ -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;
diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp
index 923574fae..074041262 100644
--- a/src/printer/smt2/smt2_printer.cpp
+++ b/src/printer/smt2/smt2_printer.cpp
@@ -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";
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index e9e21fb48..6960c4684 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -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");
diff --git a/src/theory/datatypes/datatypes_rewriter.h b/src/theory/datatypes/datatypes_rewriter.h
index e8ec72b37..025fe0349 100644
--- a/src/theory/datatypes/datatypes_rewriter.h
+++ b/src/theory/datatypes/datatypes_rewriter.h
@@ -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();
diff --git a/src/theory/datatypes/datatypes_sygus.cpp b/src/theory/datatypes/datatypes_sygus.cpp
index e308ad845..8a8660303 100644
--- a/src/theory/datatypes/datatypes_sygus.cpp
+++ b/src/theory/datatypes/datatypes_sygus.cpp
@@ -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;
}
}
+
diff --git a/src/theory/datatypes/datatypes_sygus.h b/src/theory/datatypes/datatypes_sygus.h
index 739cbb5e0..7d88447ea 100644
--- a/src/theory/datatypes/datatypes_sygus.h
+++ b/src/theory/datatypes/datatypes_sygus.h
@@ -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>
@@ -27,115 +27,145 @@
#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
+
diff --git a/src/theory/datatypes/kinds b/src/theory/datatypes/kinds
index efee5e876..3ce416b40 100644
--- a/src/theory/datatypes/kinds
+++ b/src/theory/datatypes/kinds
@@ -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
diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp
index 22065e082..874f49f1e 100644
--- a/src/theory/datatypes/theory_datatypes.cpp
+++ b/src/theory/datatypes/theory_datatypes.cpp
@@ -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 */
diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h
index ae299029a..fd79e3fdc 100644
--- a/src/theory/datatypes/theory_datatypes.h
+++ b/src/theory/datatypes/theory_datatypes.h
@@ -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 */
diff --git a/src/theory/datatypes/theory_datatypes_type_rules.h b/src/theory/datatypes/theory_datatypes_type_rules.h
index 2d7866b7b..82d7274fa 100644
--- a/src/theory/datatypes/theory_datatypes_type_rules.h
+++ b/src/theory/datatypes/theory_datatypes_type_rules.h
@@ -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 */
diff --git a/src/theory/quantifiers/bounded_integers.cpp b/src/theory/quantifiers/bounded_integers.cpp
index 6920fc539..903a729f5 100644
--- a/src/theory/quantifiers/bounded_integers.cpp
+++ b/src/theory/quantifiers/bounded_integers.cpp
@@ -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() ){
diff --git a/src/theory/quantifiers/ce_guided_instantiation.cpp b/src/theory/quantifiers/ce_guided_instantiation.cpp
index e82af63e4..63e8aa365 100644
--- a/src/theory/quantifiers/ce_guided_instantiation.cpp
+++ b/src/theory/quantifiers/ce_guided_instantiation.cpp
@@ -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;
diff --git a/src/theory/quantifiers/ce_guided_instantiation.h b/src/theory/quantifiers/ce_guided_instantiation.h
index 56a71e43e..c5c865ff9 100644
--- a/src/theory/quantifiers/ce_guided_instantiation.h
+++ b/src/theory/quantifiers/ce_guided_instantiation.h
@@ -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
index 000000000..38b5af85f
--- /dev/null
+++ b/src/theory/quantifiers/ce_guided_pbe.cpp
@@ -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
index 000000000..f40f29b2a
--- /dev/null
+++ b/src/theory/quantifiers/ce_guided_pbe.h
@@ -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
diff --git a/src/theory/quantifiers/ce_guided_single_inv.cpp b/src/theory/quantifiers/ce_guided_single_inv.cpp
index 41b262ddf..4db6df155 100644
--- a/src/theory/quantifiers/ce_guided_single_inv.cpp
+++ b/src/theory/quantifiers/ce_guided_single_inv.cpp
@@ -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
+
diff --git a/src/theory/quantifiers/ce_guided_single_inv.h b/src/theory/quantifiers/ce_guided_single_inv.h
index daa298610..e22d5fb53 100644
--- a/src/theory/quantifiers/ce_guided_single_inv.h
+++ b/src/theory/quantifiers/ce_guided_single_inv.h
@@ -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 */
diff --git a/src/theory/quantifiers/ce_guided_single_inv_sol.cpp b/src/theory/quantifiers/ce_guided_single_inv_sol.cpp
index 79b4f2c0e..aea1e4efc 100644
--- a/src/theory/quantifiers/ce_guided_single_inv_sol.cpp
+++ b/src/theory/quantifiers/ce_guided_single_inv_sol.cpp
@@ -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
diff --git a/src/theory/quantifiers/ceg_t_instantiator.cpp b/src/theory/quantifiers/ceg_t_instantiator.cpp
index 23b0b85fe..cd541a2a6 100644
--- a/src/theory/quantifiers/ceg_t_instantiator.cpp
+++ b/src/theory/quantifiers/ceg_t_instantiator.cpp
@@ -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 );
}
diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp
index 9202062a4..79a412b3c 100644
--- a/src/theory/quantifiers/inst_match_generator.cpp
+++ b/src/theory/quantifiers/inst_match_generator.cpp
@@ -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();
diff --git a/src/theory/quantifiers/inst_strategy_cbqi.cpp b/src/theory/quantifiers/inst_strategy_cbqi.cpp
index 0c2822cd9..8e53c97dc 100644
--- a/src/theory/quantifiers/inst_strategy_cbqi.cpp
+++ b/src/theory/quantifiers/inst_strategy_cbqi.cpp
@@ -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
diff --git a/src/theory/quantifiers/quant_util.cpp b/src/theory/quantifiers/quant_util.cpp
index 21ad032f3..b34abba13 100644
--- a/src/theory/quantifiers/quant_util.cpp
+++ b/src/theory/quantifiers/quant_util.cpp
@@ -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 );
+}
+
diff --git a/src/theory/quantifiers/quant_util.h b/src/theory/quantifiers/quant_util.h
index 42fb7381c..40a5b5849 100644
--- a/src/theory/quantifiers/quant_util.h
+++ b/src/theory/quantifiers/quant_util.h
@@ -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 );
+};
+
}
}
diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp
index 2261fd036..a9b1470fd 100644
--- a/src/theory/quantifiers/quantifiers_attributes.cpp
+++ b/src/theory/quantifiers/quantifiers_attributes.cpp
@@ -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;
diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp
index 2d4a6e99c..4cb41e19e 100644
--- a/src/theory/quantifiers/quantifiers_rewriter.cpp
+++ b/src/theory/quantifiers/quantifiers_rewriter.cpp
@@ -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;
diff --git a/src/theory/quantifiers/quantifiers_rewriter.h b/src/theory/quantifiers/quantifiers_rewriter.h
index 0edea5fae..d1f819726 100644
--- a/src/theory/quantifiers/quantifiers_rewriter.h
+++ b/src/theory/quantifiers/quantifiers_rewriter.h
@@ -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 */
diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp
index 7d4f5b433..9e7f174c1 100644
--- a/src/theory/quantifiers/term_database.cpp
+++ b/src/theory/quantifiers/term_database.cpp
@@ -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,11 +3475,250 @@ 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 );
+ }
+ }
}
}
}
}
+void TermDbSygus::registerMeasuredTerm( Node e, Node root, bool mkActiveGuard ) {
+ Assert( d_measured_term.find( e )==d_measured_term.end() );
+ Trace("sygus-db") << "Register measured term : " << e << " with root " << root << std::endl;
+ d_measured_term[e] = root;
+ if( mkActiveGuard ){
+ // make the guard
+ Node eg = Rewriter::rewrite( NodeManager::currentNM()->mkSkolem( "eG", NodeManager::currentNM()->booleanType() ) );
+ eg = d_quantEngine->getValuation().ensureLiteral( eg );
+ AlwaysAssert( !eg.isNull() );
+ d_quantEngine->getOutputChannel().requirePhase( eg, true );
+ //add immediate lemma
+ Node lem = NodeManager::currentNM()->mkNode( OR, eg, eg.negate() );
+ Trace("cegqi-lemma") << "Cegqi::Lemma : enumerator : " << lem << std::endl;
+ d_quantEngine->getOutputChannel().lemma( lem );
+ d_measured_term_active_guard[e] = eg;
+ }
+}
+
+void TermDbSygus::registerPbeExamples( Node e, std::vector< std::vector< Node > >& exs,
+ std::vector< Node >& exos, std::vector< Node >& exts ) {
+ Trace("sygus-db") << "Register " << exs.size() << " PBE examples with " << e << std::endl;
+ Assert( d_measured_term.find( e )==d_measured_term.end() || isMeasuredTerm( e )==e );
+ Assert( d_pbe_exs.find( e )==d_pbe_exs.end() );
+ Assert( exs.size()==exos.size() );
+ d_pbe_exs[e] = exs;
+ d_pbe_exos[e] = exos;
+ for( unsigned i=0; i<exts.size(); i++ ){
+ Trace("sygus-db-debug") << " # " << i << " : " << exts[i] << std::endl;
+ Assert( exts[i].getKind()==APPLY_UF );
+ Assert( exts[i][0]==e );
+ d_pbe_term_id[exts[i]] = i;
+ }
+}
+
+Node TermDbSygus::isMeasuredTerm( Node e ) {
+ std::map< Node, Node >::iterator itm = d_measured_term.find( e );
+ if( itm!=d_measured_term.end() ){
+ return itm->second;
+ }else{
+ return Node::null();
+ }
+}
+
+Node TermDbSygus::getActiveGuardForMeasureTerm( Node e ) {
+ std::map< Node, Node >::iterator itag = d_measured_term_active_guard.find( e );
+ if( itag!=d_measured_term_active_guard.end() ){
+ return itag->second;
+ }else{
+ return Node::null();
+ }
+}
+
+void TermDbSygus::getMeasuredTerms( std::vector< Node >& mts ) {
+ for( std::map< Node, Node >::iterator itm = d_measured_term.begin(); itm != d_measured_term.end(); ++itm ){
+ mts.push_back( itm->first );
+ }
+}
+
+bool TermDbSygus::hasPbeExamples( Node e ) {
+ return d_pbe_exs.find( e )!=d_pbe_exs.end();
+}
+
+unsigned TermDbSygus::getNumPbeExamples( Node e ) {
+ std::map< Node, std::vector< std::vector< Node > > >::iterator it = d_pbe_exs.find( e );
+ if( it!=d_pbe_exs.end() ){
+ return it->second.size();
+ }else{
+ return 0;
+ }
+}
+
+void TermDbSygus::getPbeExample( Node e, unsigned i, std::vector< Node >& ex ) {
+ std::map< Node, std::vector< std::vector< Node > > >::iterator it = d_pbe_exs.find( e );
+ if( it!=d_pbe_exs.end() ){
+ Assert( i<it->second.size() );
+ Assert( i<d_pbe_exos[e].size() );
+ ex.insert( ex.end(), it->second[i].begin(), it->second[i].end() );
+ }else{
+ Assert( false );
+ }
+}
+Node TermDbSygus::getPbeExampleOut( Node e, unsigned i ) {
+ std::map< Node, std::vector< Node > >::iterator it = d_pbe_exos.find( e );
+ if( it!=d_pbe_exos.end() ){
+ Assert( i<it->second.size() );
+ return it->second[i];
+ }else{
+ Assert( false );
+ return Node::null();
+ }
+}
+
+int TermDbSygus::getPbeExampleId( Node n ) {
+ std::map< Node, unsigned >::iterator it = d_pbe_term_id.find( n );
+ if( it!=d_pbe_term_id.end() ){
+ return it->second;
+ }else{
+ return -1;
+ }
+}
+
bool TermDbSygus::isRegistered( TypeNode tn ) {
return d_register.find( tn )!=d_register.end();
}
@@ -2910,7 +3728,76 @@ TypeNode TermDbSygus::sygusToBuiltinType( TypeNode tn ) {
return d_register[tn];
}
-int TermDbSygus::getKindArg( TypeNode tn, Kind k ) {
+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() ){
@@ -2922,7 +3809,7 @@ int TermDbSygus::getKindArg( TypeNode tn, Kind k ) {
return -1;
}
-int TermDbSygus::getConstArg( TypeNode tn, Node n ){
+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() ){
@@ -2934,7 +3821,7 @@ int TermDbSygus::getConstArg( TypeNode tn, Node n ){
return -1;
}
-int TermDbSygus::getOpArg( TypeNode tn, Node n ) {
+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;
@@ -2944,16 +3831,16 @@ int TermDbSygus::getOpArg( TypeNode tn, Node n ) {
}
bool TermDbSygus::hasKind( TypeNode tn, Kind k ) {
- return getKindArg( tn, k )!=-1;
+ return getKindConsNum( tn, k )!=-1;
}
bool TermDbSygus::hasConst( TypeNode tn, Node n ) {
- return getConstArg( tn, n )!=-1;
+ return getConstConsNum( tn, n )!=-1;
}
bool TermDbSygus::hasOp( TypeNode tn, Node n ) {
- return getOpArg( tn, n )!=-1;
+ return getOpConsNum( tn, n )!=-1;
}
-Node TermDbSygus::getArgOp( TypeNode tn, int i ) {
+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() ){
@@ -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 */
+
diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h
index 912961e19..b1d4f7f2b 100644
--- a/src/theory/quantifiers/term_database.h
+++ b/src/theory/quantifiers/term_database.h
@@ -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 */
diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp
index 64160dc71..00a358e5f 100644
--- a/src/theory/quantifiers/theory_quantifiers.cpp
+++ b/src/theory/quantifiers/theory_quantifiers.cpp
@@ -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 );
diff --git a/src/theory/sets/rels_utils.h b/src/theory/sets/rels_utils.h
index 5f4c7d79d..d179c447e 100644
--- a/src/theory/sets/rels_utils.h
+++ b/src/theory/sets/rels_utils.h
@@ -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
index 000000000..ee26fac79
--- /dev/null
+++ b/test/regress/regress0/sygus/General_plus10.sy
@@ -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)
+
diff --git a/test/regress/regress0/sygus/Makefile.am b/test/regress/regress0/sygus/Makefile.am
index 0764b5d77..0786c3f31 100644
--- a/test/regress/regress0/sygus/Makefile.am
+++ b/test/regress/regress0/sygus/Makefile.am
@@ -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
index 000000000..1ae1f53c0
--- /dev/null
+++ b/test/regress/regress0/sygus/cggmp.sy
@@ -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
index 000000000..dab92bb88
--- /dev/null
+++ b/test/regress/regress0/sygus/fg_polynomial3.sy
@@ -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
index 000000000..d9c19f8c1
--- /dev/null
+++ b/test/regress/regress0/sygus/icfp_14.12.sy
@@ -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
index 000000000..248264698
--- /dev/null
+++ b/test/regress/regress0/sygus/icfp_easy-ite.sy
@@ -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
index 000000000..eaff0fd9a
--- /dev/null
+++ b/test/regress/regress0/sygus/qe.sy
@@ -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
index 000000000..498e713e8
--- /dev/null
+++ b/test/regress/regress0/sygus/strings-template-infer.sy
@@ -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
index 000000000..d37ac8bf4
--- /dev/null
+++ b/test/regress/regress0/sygus/strings-trivial-simp.sy
@@ -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
index 000000000..f4847922d
--- /dev/null
+++ b/test/regress/regress0/sygus/strings-trivial.sy
@@ -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
index 000000000..ef046c8e0
--- /dev/null
+++ b/test/regress/regress0/sygus/tl-type-0.sy
@@ -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
index 000000000..a18d13052
--- /dev/null
+++ b/test/regress/regress0/sygus/tl-type-4x.sy
@@ -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)
+
diff --git a/test/regress/regress1/sygus/Makefile.am b/test/regress/regress1/sygus/Makefile.am
index 2dff1f1da..f1f1c1342 100644
--- a/test/regress/regress1/sygus/Makefile.am
+++ b/test/regress/regress1/sygus/Makefile.am
@@ -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
index 000000000..75bed6a28
--- /dev/null
+++ b/test/regress/regress1/sygus/VC22_a.sy
@@ -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
index 000000000..dacd7347d
--- /dev/null
+++ b/test/regress/regress1/sygus/array_sum_dd.sy
@@ -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
index 000000000..b7428fd51
--- /dev/null
+++ b/test/regress/regress1/sygus/icfp_easy_mt_ite.sy
@@ -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
index 000000000..5496f3c0a
--- /dev/null
+++ b/test/regress/regress1/sygus/inv_gen_fig8.sy
@@ -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
index 000000000..946f284cb
--- /dev/null
+++ b/test/regress/regress1/sygus/inv_gen_n_c11.sy
@@ -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
index 000000000..e574f7eb6
--- /dev/null
+++ b/test/regress/regress1/sygus/mpg_guard1-dd.sy
@@ -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
index 000000000..6e2ce3a2c
--- /dev/null
+++ b/test/regress/regress1/sygus/three.sy
@@ -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
index 000000000..f840fa519
--- /dev/null
+++ b/test/regress/regress1/sygus/unbdd_inv_gen_ex7.sy
@@ -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)
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback