summaryrefslogtreecommitdiff
path: root/src/theory/quantifiers/term_database.cpp
diff options
context:
space:
mode:
authorajreynol <andrew.j.reynolds@gmail.com>2017-07-10 14:06:52 -0500
committerajreynol <andrew.j.reynolds@gmail.com>2017-07-10 14:07:11 -0500
commitf3590092818d9eab9d961ea602093029ff472a85 (patch)
tree1401f00df0d9659ba2321ea2088fe0c3f4de9f52 /src/theory/quantifiers/term_database.cpp
parentd598a9644862d176632071bca8448765d9cc3cc1 (diff)
Merge datatype shared selectors/sygus comp 2017 branch. Modify the datatypes decision procedure to share selectors of the same type across multiple constructors. Major rewrite of the SyGuS solver. Adds several new strategies for I/O example problems (PBE) and invariant synthesis. Major simplifications to sygus parsing and synthesis conjecture representation. Do not support check-synth in portfolio. Add sygus regressions.
Diffstat (limited to 'src/theory/quantifiers/term_database.cpp')
-rw-r--r--src/theory/quantifiers/term_database.cpp2068
1 files changed, 1970 insertions, 98 deletions
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 */
+
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback