}
}
}
- if(in.getKind() == kind::DT_SIZE && in[0].getKind()==kind::APPLY_CONSTRUCTOR ){
- std::vector< Node > children;
- for( unsigned i=0; i<in[0].getNumChildren(); i++ ){
- if( in[0][i].getType().isDatatype() ){
- children.push_back( NodeManager::currentNM()->mkNode( kind::DT_SIZE, in[0][i] ) );
+ if(in.getKind() == kind::DT_SIZE ){
+ if( in[0].getKind()==kind::APPLY_CONSTRUCTOR ){
+ std::vector< Node > children;
+ for( unsigned i=0; i<in[0].getNumChildren(); i++ ){
+ if( in[0][i].getType().isDatatype() ){
+ children.push_back( NodeManager::currentNM()->mkNode( kind::DT_SIZE, in[0][i] ) );
+ }
+ }
+ Node res;
+ if( !children.empty() ){
+ children.push_back( NodeManager::currentNM()->mkConst( Rational(1) ) );
+ res = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( kind::PLUS, children );
+ }else{
+ res = NodeManager::currentNM()->mkConst( Rational(0) );
}
+ Trace("datatypes-rewrite") << "DatatypesRewriter::postRewrite: rewrite size " << in << " to " << res << std::endl;
+ return RewriteResponse(REWRITE_AGAIN_FULL, res );
}
- Node res;
- if( !children.empty() ){
- children.push_back( NodeManager::currentNM()->mkConst( Rational(1) ) );
- res = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( kind::PLUS, children );
- }else{
- res = NodeManager::currentNM()->mkConst( Rational(0) );
+ }else if(in.getKind() == kind::DT_HEIGHT_BOUND ){
+ if( in[0].getKind()==kind::APPLY_CONSTRUCTOR ){
+ std::vector< Node > children;
+ Node res;
+ Rational r = in[1].getConst<Rational>();
+ Rational rmo = Rational( r-Rational(1) );
+ for( unsigned i=0; i<in[0].getNumChildren(); i++ ){
+ if( in[0][i].getType().isDatatype() ){
+ if( r.isZero() ){
+ res = NodeManager::currentNM()->mkConst(false);
+ break;
+ }else{
+ children.push_back( NodeManager::currentNM()->mkNode( kind::DT_HEIGHT_BOUND, in[0][i], NodeManager::currentNM()->mkConst(rmo) ) );
+ }
+ }
+ }
+ if( res.isNull() ){
+ res = children.size()==0 ? NodeManager::currentNM()->mkConst(true) : ( children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( kind::AND, children ) );
+ }
+ Trace("datatypes-rewrite") << "DatatypesRewriter::postRewrite: rewrite height " << in << " to " << res << std::endl;
+ return RewriteResponse(REWRITE_AGAIN_FULL, res );
}
- Trace("datatypes-rewrite") << "DatatypesRewriter::postRewrite: rewrite " << in << " to " << res << std::endl;
- return RewriteResponse(REWRITE_AGAIN_FULL, res );
}
if(in.getKind() == kind::TUPLE_SELECT &&
in[0].getKind() == kind::TUPLE) {
}
}
}
-
+
+ // we are splitting on a term that may later have no semantics : guard this case
+ Node ptest = DatatypesRewriter::mkTester( n[0], csIndex, pdt ).negate();
+ Trace("sygus-split-debug") << "Parent guard : " << ptest << std::endl;
+ d_splits[n].push_back( ptest );
}
for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
}
}
}
+ //NAND,NOR
}
d_sygus_nred[tn].push_back( nred );
}
Kind nk = UNDEFINED_KIND;
Kind reqk = UNDEFINED_KIND;
std::map< int, Kind > reqk_arg; //TODO
- if( k==AND ) {
- nk = OR;reqk = NOT;
- }else if( k==OR ){
- nk = AND;reqk = NOT;
- }else if( k==IFF ) {
- nk = XOR;
- }else if( k==XOR ) {
- nk = IFF;
- }else if( k==BITVECTOR_AND ) {
- nk = BITVECTOR_OR;reqk = BITVECTOR_NOT;
- }else if( k==BITVECTOR_OR ){
- nk = BITVECTOR_AND;reqk = BITVECTOR_NOT;
- }else if( k==BITVECTOR_XNOR ) {
- nk = BITVECTOR_XOR;
- }else if( k==BITVECTOR_XOR ) {
- nk = BITVECTOR_XNOR;
+ if( parent==NOT ){
+ if( k==AND ) {
+ nk = OR;reqk = NOT;
+ }else if( k==OR ){
+ nk = AND;reqk = NOT;
+ }else if( k==IFF ) {
+ nk = XOR;
+ }else if( k==XOR ) {
+ nk = IFF;
+ }
+ }
+ if( parent==BITVECTOR_NOT ){
+ if( k==BITVECTOR_AND ) {
+ nk = BITVECTOR_OR;reqk = BITVECTOR_NOT;
+ }else if( k==BITVECTOR_OR ){
+ nk = BITVECTOR_AND;reqk = BITVECTOR_NOT;
+ }else if( k==BITVECTOR_XNOR ) {
+ nk = BITVECTOR_XOR;
+ }else if( k==BITVECTOR_XOR ) {
+ nk = BITVECTOR_XNOR;
+ }
}
- //NAND,NOR
if( nk!=UNDEFINED_KIND ){
Trace("sygus-split-debug") << "Push " << parent << " over " << k << " to " << nk;
if( reqk!=UNDEFINED_KIND ){
operator DT_SIZE 1 "datatypes size"
typerule DT_SIZE ::CVC4::theory::datatypes::DtSizeTypeRule
+operator DT_HEIGHT_BOUND 1 "datatypes height bound"
+typerule DT_HEIGHT_BOUND ::CVC4::theory::datatypes::DtHeightBoundTypeRule
+
endtheory
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::APPLY_TESTER);
//d_equalityEngine.addFunctionKind(kind::APPLY_UF);
TimerStat::CodeTimer checkTimer(d_checkTime);
- Trace("datatypes-debug") << "Check effort " << e << std::endl;
+ Trace("datatypes-check") << "Check effort " << e << std::endl;
while(!done() && !d_conflict) {
// Get all the assertions
Assertion assertion = get();
}
void TheoryDatatypes::addSelector( Node s, EqcInfo* eqc, Node n, bool assertFacts ) {
- Debug("datatypes-debug") << "Add selector : " << s << " to eqc(" << n << ")" << std::endl;
+ Trace("dt-collapse-sel") << "Add selector : " << s << " to eqc(" << n << ")" << std::endl;
//check to see if it is redundant
NodeListMap::iterator sel_i = d_selector_apps.find( n );
Assert( sel_i != d_selector_apps.end() );
NodeList* sel = (*sel_i).second;
for( NodeList::const_iterator j = sel->begin(); j != sel->end(); ++j ){
Node ss = *j;
- if( s.getOperator()==ss.getOperator() ){
+ if( s.getOperator()==ss.getOperator() && ( s.getKind()!=DT_HEIGHT_BOUND || s[1]==ss[1] ) ){
+ Trace("dt-collapse-sel") << "...redundant." << std::endl;
return;
}
}
Assert( c.getKind()==APPLY_CONSTRUCTOR );
Trace("dt-collapse-sel") << "collapse selector : " << s << " " << c << std::endl;
Node r;
+ bool wrong = false;
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());
+ //if( wrong ){
+ // return;
+ //}
//if( Datatype::indexOf(c.getOperator().toExpr())!=Datatype::cindexOf(s.getOperator().toExpr()) ){
// mkExpDefSkolem( s.getOperator(), s[0].getType(), s.getType() );
// r = NodeManager::currentNM()->mkNode( kind::APPLY_UF, d_exp_def_skolem[s.getOperator().toExpr()], s[0] );
//}else{
r = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, s.getOperator(), c );
- }else if( s.getKind()==kind::DT_SIZE ){
- r = NodeManager::currentNM()->mkNode( kind::DT_SIZE, c );
+ }else if( s.getKind()==DT_SIZE ){
+ r = NodeManager::currentNM()->mkNode( DT_SIZE, c );
+ }else if( s.getKind()==DT_HEIGHT_BOUND ){
+ r = NodeManager::currentNM()->mkNode( DT_HEIGHT_BOUND, c, s[1] );
+ if( r==d_true ){
+ return;
+ }
}
Node rr = Rewriter::rewrite( r );
if( s!=rr ){
Node eq_exp = c.eqNode( s[0] );
Node eq = rr.getType().isBoolean() ? s.iffNode( rr ) : s.eqNode( rr );
- Trace("datatypes-infer") << "DtInfer : collapse sel : " << eq << " by " << eq_exp << std::endl;
+ Trace("datatypes-infer") << "DtInfer : collapse sel";
+ 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;
for( unsigned j=i+1; j<functionTerms; j++ ){
TNode f2 = r==0 ? d_consTerms[j] : d_selTerms[j];
Trace("dt-cg-debug") << "dt-cg: " << f1 << " and " << f2 << " " << (f1.getOperator()==f2.getOperator()) << " " << areEqual( f1, f2 ) << std::endl;
- if( f1.getOperator()==f2.getOperator() && ( f1.getKind()!=DT_SIZE || f1[0].getType()==f2[0].getType() ) && !areEqual( f1, f2 ) ){
+ if( f1.getOperator()==f2.getOperator() &&
+ ( ( f1.getKind()!=DT_SIZE && f1.getKind()!=DT_HEIGHT_BOUND ) || f1[0].getType()==f2[0].getType() ) &&
+ !areEqual( f1, f2 ) ){
Trace("dt-cg") << "Check " << f1 << " and " << f2 << std::endl;
bool somePairIsDisequal = false;
currentPairs.clear();
if( n.getKind() == APPLY_CONSTRUCTOR ){
Debug("datatypes") << " Found constructor " << n << endl;
d_consTerms.push_back( n );
- }else if( n.getKind() == APPLY_SELECTOR_TOTAL || n.getKind() == DT_SIZE ){
+ }else if( n.getKind() == APPLY_SELECTOR_TOTAL || n.getKind() == DT_SIZE || n.getKind() == DT_HEIGHT_BOUND ){
d_selTerms.push_back( n );
//we must also record which selectors exist
- Debug("datatypes") << " Found selector " << n << endl;
+ Trace("dt-collapse-sel") << " Found selector " << n << endl;
//if (n.getType().isBoolean()) {
// d_equalityEngine.addTriggerPredicate( n );
//}else{
d_pending.push_back( conc );
d_pending_exp[ conc ] = d_true;
d_infer.push_back( conc );
+ }else if( n.getKind() == DT_HEIGHT_BOUND ){
+ if( n[1].getConst<Rational>().isZero() ){
+ std::vector< Node > children;
+ const Datatype& dt = ((DatatypeType)(n[0].getType()).toType()).getDatatype();
+ for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
+ if( DatatypesRewriter::isNullaryConstructor( dt[i] ) ){
+ Node test = DatatypesRewriter::mkTester( n[0], i, dt );
+ children.push_back( test );
+ }
+ }
+ Node lem;
+ if( children.empty() ){
+ lem = n.negate();
+ }else{
+ lem = NodeManager::currentNM()->mkNode( IFF, n, children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( OR, children ) );
+ }
+ Trace("datatypes-infer") << "DtInfer : zero height : " << lem << std::endl;
+ d_pending.push_back( lem );
+ d_pending_exp[ lem ] = d_true;
+ d_infer.push_back( lem );
+ }
}
}
}
}
};/* class DtSizeTypeRule */
+class DtHeightBoundTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ) {
+ TypeNode t = n[0].getType(check);
+ if (!t.isDatatype()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting datatype height bound term to have datatype argument.");
+ }
+ if( n[1].getKind()!=kind::CONST_RATIONAL ){
+ throw TypeCheckingExceptionPrivate(n, "datatype height bound must be a constant");
+ }
+ if( n[1].getConst<Rational>().getNumerator().sgn()==-1 ){
+ throw TypeCheckingExceptionPrivate(n, "datatype height bound must be non-negative");
+ }
+ }
+ return nodeManager->integerType();
+ }
+};/* class DtHeightBoundTypeRule */
+
}/* CVC4::theory::datatypes namespace */
}/* CVC4::theory namespace */
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 lit = NodeManager::currentNM()->mkNode( LEQ, d_measure_term, NodeManager::currentNM()->mkConst( Rational( i ) ) );
+ 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;
Trace("cegqi-lemma") << "Fairness split : " << lem << std::endl;
qe->getOutputChannel().lemma( lem );
qe->getOutputChannel().requirePhase( lit, true );
+
+ if( options::ceGuidedInstFair()==CEGQI_FAIR_DT_HEIGHT_PRED ){
+ //implies height bounds on each candidate variable
+ std::vector< Node > lem_c;
+ for( unsigned j=0; j<d_candidates.size(); j++ ){
+ lem_c.push_back( NodeManager::currentNM()->mkNode( DT_HEIGHT_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") << "Fairness expansion (dt-height-pred) : " << hlem << std::endl;
+ qe->getOutputChannel().lemma( hlem );
+ }
return lit;
}else{
return it->second;
if( it!=d_uf_measure.end() ){
mc.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, it->second, d_conj->d_candidates[j] ) );
}
+ }else if( options::ceGuidedInstFair()==CEGQI_FAIR_DT_HEIGHT_PRED ){
+ //measure term is a fresh constant
+ mc.push_back( NodeManager::currentNM()->mkSkolem( "K", NodeManager::currentNM()->integerType() ) );
}
}
if( !mc.empty() ){
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,
/** do not use fair strategy for CEGQI */
CEGQI_FAIR_NONE,
} CegqiFairMode;
if and how to apply fairness for cegqi
option sygusDecompose --sygus-decompose bool :default false
decompose single invocation synthesis conjectures
-option sygusNormalForm --sygus-normal-form bool :default true
+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
default | dt-size \n\
+ Default, enforce fairness using size theory operator.\n\
\n\
+dt-height-bound \n\
++ Enforce fairness by height bound predicate.\n\
+\n\
none \n\
+ Do not enforce fairness. \n\
\n\
return CEGQI_FAIR_UF_DT_SIZE;
} else if(optarg == "default" || optarg == "dt-size") {
return CEGQI_FAIR_DT_SIZE;
+ } else if(optarg == "dt-height-bound" ){
+ return CEGQI_FAIR_DT_HEIGHT_PRED;
} else if(optarg == "none") {
return CEGQI_FAIR_NONE;
} else if(optarg == "help") {