diff options
author | PaulMeng <pmtruth@hotmail.com> | 2016-07-05 13:56:53 -0400 |
---|---|---|
committer | PaulMeng <pmtruth@hotmail.com> | 2016-07-05 13:56:53 -0400 |
commit | 36a0d1d948f201471596e092136c5a00103f78af (patch) | |
tree | 7a9b0d79074da1cb0c1cbed986584d50792a30e9 /src/theory/quantifiers | |
parent | 66525e81928d0d025dbcc197ab3ef772eac31103 (diff) | |
parent | a58abbe71fb1fc07129ff9c7568ac544145fb57c (diff) |
Merge branch 'master' of https://github.com/CVC4/CVC4.git
Conflicts:
proofs/signatures/Makefile.am
src/Makefile.am
src/expr/datatype.cpp
src/options/datatypes_options
src/options/options_template.cpp
src/options/quantifiers_options
src/proof/arith_proof.cpp
src/proof/arith_proof.h
src/proof/array_proof.cpp
src/proof/array_proof.h
src/proof/bitvector_proof.cpp
src/proof/bitvector_proof.h
src/proof/cnf_proof.cpp
src/proof/cnf_proof.h
src/proof/proof_manager.cpp
src/proof/proof_manager.h
src/proof/sat_proof.h
src/proof/sat_proof_implementation.h
src/proof/skolemization_manager.h
src/proof/theory_proof.cpp
src/proof/theory_proof.h
src/proof/uf_proof.cpp
src/proof/uf_proof.h
src/prop/cnf_stream.cpp
src/prop/cnf_stream.h
src/prop/minisat/core/Solver.cc
src/prop/prop_engine.cpp
src/prop/prop_engine.h
src/prop/theory_proxy.cpp
src/smt/smt_engine.cpp
src/smt/smt_engine_check_proof.cpp
src/theory/arrays/array_proof_reconstruction.cpp
src/theory/arrays/theory_arrays.cpp
src/theory/bv/eager_bitblaster.cpp
src/theory/bv/lazy_bitblaster.cpp
src/theory/datatypes/theory_datatypes.cpp
src/theory/quantifiers/alpha_equivalence.cpp
src/theory/quantifiers/candidate_generator.cpp
src/theory/quantifiers/candidate_generator.h
src/theory/quantifiers/ce_guided_single_inv.cpp
src/theory/quantifiers/ceg_instantiator.cpp
src/theory/quantifiers/conjecture_generator.cpp
src/theory/quantifiers/equality_infer.cpp
src/theory/quantifiers/equality_infer.h
src/theory/quantifiers/inst_match_generator.cpp
src/theory/quantifiers/inst_propagator.cpp
src/theory/quantifiers/inst_propagator.h
src/theory/quantifiers/inst_strategy_e_matching.cpp
src/theory/quantifiers/inst_strategy_e_matching.h
src/theory/quantifiers/instantiation_engine.cpp
src/theory/quantifiers/model_builder.cpp
src/theory/quantifiers/model_engine.cpp
src/theory/quantifiers/quant_conflict_find.cpp
src/theory/quantifiers/quant_conflict_find.h
src/theory/quantifiers/quant_split.cpp
src/theory/quantifiers/quant_util.cpp
src/theory/quantifiers/quantifiers_rewriter.cpp
src/theory/quantifiers/quantifiers_rewriter.h
src/theory/quantifiers/term_database.cpp
src/theory/quantifiers/term_database.h
src/theory/quantifiers/trigger.cpp
src/theory/quantifiers/trigger.h
src/theory/quantifiers_engine.cpp
src/theory/quantifiers_engine.h
src/theory/sets/kinds
src/theory/sets/theory_sets_private.cpp
src/theory/sets/theory_sets_private.h
src/theory/sets/theory_sets_rewriter.cpp
src/theory/sets/theory_sets_type_rules.h
src/theory/strings/theory_strings.cpp
src/theory/strings/theory_strings.h
src/theory/theory_engine.cpp
src/theory/theory_engine.h
src/theory/uf/equality_engine.cpp
test/regress/regress0/fmf/Makefile.am
test/regress/regress0/quantifiers/Makefile.am
test/regress/regress0/strings/Makefile.am
test/regress/regress0/sygus/Makefile.am
test/regress/regress0/sygus/max2-univ.sy
Diffstat (limited to 'src/theory/quantifiers')
78 files changed, 2235 insertions, 1587 deletions
diff --git a/src/theory/quantifiers/alpha_equivalence.cpp b/src/theory/quantifiers/alpha_equivalence.cpp index 80066d690..a00d6d8a1 100644..100755 --- a/src/theory/quantifiers/alpha_equivalence.cpp +++ b/src/theory/quantifiers/alpha_equivalence.cpp @@ -30,17 +30,30 @@ struct sortTypeOrder { }; Node AlphaEquivalenceNode::registerNode( AlphaEquivalenceNode* aen, QuantifiersEngine* qe, Node q, std::vector< Node >& tt, std::vector< int >& arg_index ) { + std::map< Node, bool > visited; while( !tt.empty() ){ if( tt.size()==arg_index.size()+1 ){ Node t = tt.back(); - Node op = t.hasOperator() ? t.getOperator() : t; - arg_index.push_back( 0 ); + Node op; + if( t.hasOperator() ){ + if( visited.find( t )==visited.end() ){ + visited[t] = true; + op = t.getOperator(); + arg_index.push_back( 0 ); + }else{ + op = t; + arg_index.push_back( -1 ); + } + }else{ + op = t; + arg_index.push_back( 0 ); + } Trace("aeq-debug") << op << " "; aen = &(aen->d_children[op][t.getNumChildren()]); }else{ Node t = tt.back(); int i = arg_index.back(); - if( i==(int)t.getNumChildren() ){ + if( i==-1 || i==(int)t.getNumChildren() ){ tt.pop_back(); arg_index.pop_back(); }else{ @@ -56,9 +69,9 @@ Node AlphaEquivalenceNode::registerNode( AlphaEquivalenceNode* aen, QuantifiersE }else{ if( q.getNumChildren()==2 ){ //lemma ( q <=> d_quant ) - Trace("quant-ae") << "Alpha equivalent : " << std::endl; - Trace("quant-ae") << " " << q << std::endl; - Trace("quant-ae") << " " << aen->d_quant << std::endl; + Trace("alpha-eq") << "Alpha equivalent : " << std::endl; + Trace("alpha-eq") << " " << q << std::endl; + Trace("alpha-eq") << " " << aen->d_quant << std::endl; lem = q.iffNode( aen->d_quant ); }else{ //do not reduce annotated quantified formulas based on alpha equivalence diff --git a/src/theory/quantifiers/alpha_equivalence.h b/src/theory/quantifiers/alpha_equivalence.h index 8e7556eb6..8e7556eb6 100644..100755 --- a/src/theory/quantifiers/alpha_equivalence.h +++ b/src/theory/quantifiers/alpha_equivalence.h diff --git a/src/theory/quantifiers/ambqi_builder.cpp b/src/theory/quantifiers/ambqi_builder.cpp index 5192da7de..97116dee4 100644..100755 --- a/src/theory/quantifiers/ambqi_builder.cpp +++ b/src/theory/quantifiers/ambqi_builder.cpp @@ -787,7 +787,7 @@ void AbsMbqiBuilder::processBuildModel(TheoryModel* m, bool fullModel) { Trace("ambqi-model-debug") << "Initial terms: " << std::endl; for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){ Node n = fm->d_uf_terms[f][i]; - if( !n.getAttribute(NoMatchAttribute()) ){ + if( d_qe->getTermDatabase()->isTermActive( n ) ){ Trace("ambqi-model-debug") << " " << n << " -> " << fm->getRepresentativeId( n ) << std::endl; fapps.push_back( n ); } diff --git a/src/theory/quantifiers/ambqi_builder.h b/src/theory/quantifiers/ambqi_builder.h index 3669d38b7..3669d38b7 100644..100755 --- a/src/theory/quantifiers/ambqi_builder.h +++ b/src/theory/quantifiers/ambqi_builder.h diff --git a/src/theory/quantifiers/anti_skolem.cpp b/src/theory/quantifiers/anti_skolem.cpp index c8d18aced..c8d18aced 100644..100755 --- a/src/theory/quantifiers/anti_skolem.cpp +++ b/src/theory/quantifiers/anti_skolem.cpp diff --git a/src/theory/quantifiers/anti_skolem.h b/src/theory/quantifiers/anti_skolem.h index 721371159..721371159 100644..100755 --- a/src/theory/quantifiers/anti_skolem.h +++ b/src/theory/quantifiers/anti_skolem.h diff --git a/src/theory/quantifiers/bounded_integers.cpp b/src/theory/quantifiers/bounded_integers.cpp index d32ef59a1..7184624da 100644..100755 --- a/src/theory/quantifiers/bounded_integers.cpp +++ b/src/theory/quantifiers/bounded_integers.cpp @@ -28,7 +28,7 @@ using namespace CVC4::theory::quantifiers; using namespace CVC4::kind; -BoundedIntegers::RangeModel::RangeModel(BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy) : d_bi(bi), +BoundedIntegers::IntRangeModel::IntRangeModel(BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy) : d_bi(bi), d_range(r), d_curr_max(-1), d_lit_to_range(u), d_range_assertions(c), d_has_range(c,false), d_curr_range(c,-1), d_ranges_proxied(u) { if( options::fmfBoundIntLazy() ){ d_proxy_range = isProxy ? r : NodeManager::currentNM()->mkSkolem( "pbir", r.getType() ); @@ -40,7 +40,7 @@ BoundedIntegers::RangeModel::RangeModel(BoundedIntegers * bi, Node r, context::C } } -void BoundedIntegers::RangeModel::initialize() { +void BoundedIntegers::IntRangeModel::initialize() { //add initial split lemma Node ltr = NodeManager::currentNM()->mkNode( LT, d_proxy_range, NodeManager::currentNM()->mkConst( Rational(0) ) ); ltr = Rewriter::rewrite( ltr ); @@ -55,7 +55,7 @@ void BoundedIntegers::RangeModel::initialize() { d_bi->addLiteralFromRange(ltr_lit, d_range); } -void BoundedIntegers::RangeModel::assertNode(Node n) { +void BoundedIntegers::IntRangeModel::assertNode(Node n) { bool pol = n.getKind()!=NOT; Node nlit = n.getKind()==NOT ? n[0] : n; if( d_lit_to_range.find( nlit )!=d_lit_to_range.end() ){ @@ -93,7 +93,7 @@ void BoundedIntegers::RangeModel::assertNode(Node n) { } } -void BoundedIntegers::RangeModel::allocateRange() { +void BoundedIntegers::IntRangeModel::allocateRange() { d_curr_max++; int newBound = d_curr_max; Trace("bound-int-proc") << "Allocate range bound " << newBound << " for " << d_range << std::endl; @@ -110,7 +110,7 @@ void BoundedIntegers::RangeModel::allocateRange() { d_bi->addLiteralFromRange(ltr_lit, d_range); } -Node BoundedIntegers::RangeModel::getNextDecisionRequest() { +Node BoundedIntegers::IntRangeModel::getNextDecisionRequest() { //request the current cardinality as a decision literal, if not already asserted for( NodeIntMap::iterator it = d_lit_to_range.begin(); it != d_lit_to_range.end(); ++it ){ int i = (*it).second; @@ -129,7 +129,7 @@ Node BoundedIntegers::RangeModel::getNextDecisionRequest() { return Node::null(); } -bool BoundedIntegers::RangeModel::proxyCurrentRange() { +bool BoundedIntegers::IntRangeModel::proxyCurrentRange() { //Trace("model-engine") << "Range(" << d_range << ") currently is " << d_curr_max.get() << std::endl; if( d_range!=d_proxy_range ){ //int curr = d_curr_range.get(); @@ -148,11 +148,24 @@ bool BoundedIntegers::RangeModel::proxyCurrentRange() { } + + + BoundedIntegers::BoundedIntegers(context::Context* c, QuantifiersEngine* qe) : QuantifiersModule(qe), d_assertions(c){ } +BoundedIntegers::~BoundedIntegers() { + for( std::map< Node, RangeModel * >::iterator it = d_rms.begin(); it != d_rms.end(); ++it ){ + delete it->second; + } +} + +void BoundedIntegers::presolve() { + d_bnd_it.clear(); +} + bool BoundedIntegers::isBound( Node f, Node v ) { return std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end(); } @@ -172,62 +185,79 @@ bool BoundedIntegers::hasNonBoundVar( Node f, Node b ) { return false; } -void BoundedIntegers::processLiteral( Node f, Node lit, bool pol, +void BoundedIntegers::processLiteral( Node q, Node lit, bool pol, + std::map< Node, unsigned >& bound_lit_type_map, std::map< int, std::map< Node, Node > >& bound_lit_map, - std::map< int, std::map< Node, bool > >& bound_lit_pol_map ) { - if( lit.getKind()==GEQ && lit[0].getType().isInteger() ){ - std::map< Node, Node > msum; - if (QuantArith::getMonomialSumLit( lit, msum )){ - Trace("bound-int-debug") << "Literal (polarity = " << pol << ") " << lit << " is monomial sum : " << std::endl; - QuantArith::debugPrintMonomialSum( msum, "bound-int-debug" ); - for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ - if ( !it->first.isNull() && it->first.getKind()==BOUND_VARIABLE && !isBound( f, it->first ) ){ - Node veq; - if( QuantArith::isolate( it->first, msum, veq, GEQ )!=0 ){ - Node n1 = veq[0]; - Node n2 = veq[1]; - if(pol){ - //flip - n1 = veq[1]; - n2 = veq[0]; - if( n1.getKind()==BOUND_VARIABLE ){ - n2 = QuantArith::offset( n2, 1 ); + std::map< int, std::map< Node, bool > >& bound_lit_pol_map, + std::map< int, std::map< Node, Node > >& bound_int_range_term ) { + if( lit.getKind()==GEQ ){ + if( lit[0].getType().isInteger() ){ + std::map< Node, Node > msum; + if( QuantArith::getMonomialSumLit( lit, msum ) ){ + Trace("bound-int-debug") << "Literal (polarity = " << pol << ") " << lit << " is monomial sum : " << std::endl; + QuantArith::debugPrintMonomialSum( msum, "bound-int-debug" ); + for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ + if ( !it->first.isNull() && it->first.getKind()==BOUND_VARIABLE && !isBound( q, it->first ) ){ + Node veq; + if( QuantArith::isolate( it->first, msum, veq, GEQ )!=0 ){ + Node n1 = veq[0]; + Node n2 = veq[1]; + if(pol){ + //flip + n1 = veq[1]; + n2 = veq[0]; + if( n1.getKind()==BOUND_VARIABLE ){ + n2 = QuantArith::offset( n2, 1 ); + }else{ + n1 = QuantArith::offset( n1, -1 ); + } + veq = NodeManager::currentNM()->mkNode( GEQ, n1, n2 ); + } + Trace("bound-int-debug") << "Isolated for " << it->first << " : (" << n1 << " >= " << n2 << ")" << std::endl; + Node t = n1==it->first ? n2 : n1; + if( !hasNonBoundVar( q, t ) ) { + Trace("bound-int-debug") << "The bound is relevant." << std::endl; + int loru = n1==it->first ? 0 : 1; + bound_lit_type_map[it->first] = BOUND_INT_RANGE; + bound_int_range_term[loru][it->first] = t; + bound_lit_map[loru][it->first] = lit; + bound_lit_pol_map[loru][it->first] = pol; }else{ - n1 = QuantArith::offset( n1, -1 ); + Trace("bound-int-debug") << "The term " << t << " has non-bound variable." << std::endl; } - veq = NodeManager::currentNM()->mkNode( GEQ, n1, n2 ); - } - Trace("bound-int-debug") << "Isolated for " << it->first << " : (" << n1 << " >= " << n2 << ")" << std::endl; - Node t = n1==it->first ? n2 : n1; - if( !hasNonBoundVar( f, t ) ) { - Trace("bound-int-debug") << "The bound is relevant." << std::endl; - int loru = n1==it->first ? 0 : 1; - d_bounds[loru][f][it->first] = t; - bound_lit_map[loru][it->first] = lit; - bound_lit_pol_map[loru][it->first] = pol; - }else{ - Trace("bound-int-debug") << "The term " << t << " has non-bound variable." << std::endl; } } } } } + }else if( lit.getKind()==MEMBER ){ + //TODO: enable this when sets models are fixed + /* + if( !pol && lit[0].getKind()==BOUND_VARIABLE && !isBound( q, lit[0] ) && !lit[1].hasBoundVar() ){ + Trace("bound-int-debug") << "Literal (polarity = " << pol << ") " << lit << " is membership." << std::endl; + bound_lit_type_map[lit[0]] = BOUND_SET_MEMBER; + bound_lit_map[0][lit[0]] = lit; + bound_lit_pol_map[0][lit[0]] = pol; + } + */ }else if( lit.getKind()==LEQ || lit.getKind()==LT || lit.getKind()==GT ) { Message() << "BoundedIntegers : Bad kind for literal : " << lit << std::endl; } } -void BoundedIntegers::process( Node f, Node n, bool pol, +void BoundedIntegers::process( Node q, Node n, bool pol, + std::map< Node, unsigned >& bound_lit_type_map, std::map< int, std::map< Node, Node > >& bound_lit_map, - std::map< int, std::map< Node, bool > >& bound_lit_pol_map ){ + std::map< int, std::map< Node, bool > >& bound_lit_pol_map, + std::map< int, std::map< Node, Node > >& bound_int_range_term ){ if( (n.getKind()==OR && pol) || (n.getKind()==AND && !pol) ){ for( unsigned i=0; i<n.getNumChildren(); i++) { - process( f, n[i], pol, bound_lit_map, bound_lit_pol_map ); + process( q, n[i], pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term ); } }else if( n.getKind()==NOT ){ - process( f, n[0], !pol, bound_lit_map, bound_lit_pol_map ); + process( q, n[0], !pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term ); }else { - processLiteral( f, n, pol, bound_lit_map, bound_lit_pol_map ); + processLiteral( q, n, pol, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term ); } } @@ -258,58 +288,99 @@ void BoundedIntegers::addLiteralFromRange( Node lit, Node r ) { } } +void BoundedIntegers::setBoundedVar( Node q, Node v, unsigned bound_type ) { + d_bound_type[q][v] = bound_type; + d_set_nums[q][v] = d_set[q].size(); + d_set[q].push_back( v ); + Trace("bound-int-var") << "Bound variable #" << d_set_nums[q][v] << " : " << v << std::endl; +} + void BoundedIntegers::registerQuantifier( Node f ) { Trace("bound-int") << "Register quantifier " << f << std::endl; - bool hasIntType = false; - int finiteTypes = 0; - std::map< Node, int > numMap; - for( unsigned i=0; i<f[0].getNumChildren(); i++) { - numMap[f[0][i]] = i; - if( f[0][i].getType().isInteger() ){ - hasIntType = true; - } - else if( f[0][i].getType().isSort() || f[0][i].getType().getCardinality().isFinite() ){ - finiteTypes++; - } - } - if( hasIntType ){ - bool success; - do{ - std::map< int, std::map< Node, Node > > bound_lit_map; - std::map< int, std::map< Node, bool > > bound_lit_pol_map; - success = false; - process( f, f[1], true, bound_lit_map, bound_lit_pol_map ); - for( std::map< Node, Node >::iterator it = d_bounds[0][f].begin(); it != d_bounds[0][f].end(); ++it ){ - Node v = it->first; - if( !isBound(f,v) ){ - if( d_bounds[1][f].find(v)!=d_bounds[1][f].end() ){ - d_set[f].push_back(v); - d_set_nums[f].push_back(numMap[v]); + + bool success; + do{ + std::map< Node, unsigned > bound_lit_type_map; + std::map< int, std::map< Node, Node > > bound_lit_map; + std::map< int, std::map< Node, bool > > bound_lit_pol_map; + std::map< int, std::map< Node, Node > > bound_int_range_term; + success = false; + process( f, f[1], true, bound_lit_type_map, bound_lit_map, bound_lit_pol_map, bound_int_range_term ); + //for( std::map< Node, Node >::iterator it = d_bounds[0][f].begin(); it != d_bounds[0][f].end(); ++it ){ + for( std::map< Node, unsigned >::iterator it = bound_lit_type_map.begin(); it != bound_lit_type_map.end(); ++it ){ + Node v = it->first; + if( !isBound( f, v ) ){ + bool setBoundVar = false; + if( it->second==BOUND_INT_RANGE ){ + //must have both + if( bound_lit_map[0].find( v )!=bound_lit_map[0].end() && bound_lit_map[1].find( v )!=bound_lit_map[1].end() ){ + setBoundedVar( f, v, BOUND_INT_RANGE ); + setBoundVar = true; success = true; - //set Attributes on literals for( unsigned b=0; b<2; b++ ){ - Assert( bound_lit_map[b].find( v )!=bound_lit_map[b].end() ); + //set the bounds + Assert( bound_int_range_term[b].find( v )!=bound_int_range_term[b].end() ); + d_bounds[b][f][v] = bound_int_range_term[b][v]; + } + Node r = NodeManager::currentNM()->mkNode( MINUS, d_bounds[1][f][v], d_bounds[0][f][v] ); + d_range[f][v] = Rewriter::rewrite( r ); + Trace("bound-int") << "Variable " << v << " is bound because of int range literals " << bound_lit_map[0][v] << " and " << bound_lit_map[1][v] << std::endl; + } + }else if( it->second==BOUND_SET_MEMBER ){ + setBoundedVar( f, v, BOUND_SET_MEMBER ); + setBoundVar = true; + d_setm_range[f][v] = bound_lit_map[0][v][1]; + Trace("bound-int") << "Variable " << v << " is bound because of set membership literal " << bound_lit_map[0][v] << std::endl; + } + if( setBoundVar ){ + //set Attributes on literals + for( unsigned b=0; b<2; b++ ){ + if( bound_lit_map[b].find( v )!=bound_lit_map[b].end() ){ Assert( bound_lit_pol_map[b].find( v )!=bound_lit_pol_map[b].end() ); BoundIntLitAttribute bila; bound_lit_map[b][v].setAttribute( bila, bound_lit_pol_map[b][v] ? 1 : 0 ); + }else{ + Assert( it->second!=BOUND_INT_RANGE ); } - Trace("bound-int") << "Variable " << v << " is bound because of literals " << bound_lit_map[0][v] << " and " << bound_lit_map[1][v] << std::endl; } } } - }while( success ); - Trace("bound-int") << "Bounds are : " << std::endl; - for( unsigned i=0; i<d_set[f].size(); i++) { - Node v = d_set[f][i]; - Node r = NodeManager::currentNM()->mkNode( MINUS, d_bounds[1][f][v], d_bounds[0][f][v] ); - d_range[f][v] = Rewriter::rewrite( r ); + } + }while( success ); + + Trace("bound-int") << "Bounds are : " << std::endl; + for( unsigned i=0; i<d_set[f].size(); i++) { + Node v = d_set[f][i]; + if( d_bound_type[f][v]==BOUND_INT_RANGE ){ Trace("bound-int") << " " << d_bounds[0][f][v] << " <= " << v << " <= " << d_bounds[1][f][v] << " (range is " << d_range[f][v] << ")" << std::endl; + }else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){ + Trace("bound-int") << " " << v << " in " << d_setm_range[f][v] << std::endl; + } + } + + bool bound_success = true; + for( unsigned i=0; i<f[0].getNumChildren(); i++) { + if( d_bound_type[f].find( f[0][i] )==d_bound_type[f].end() ){ + TypeNode tn = f[0][i].getType(); + if( !tn.isSort() && !getTermDatabase()->mayComplete( tn ) ){ + Trace("bound-int-warn") << "Warning : Bounded Integers : Due to quantification on " << f[0][i] << ", could not find bounds for " << f << std::endl; + bound_success = false; + break; + } } - if( d_set[f].size()==(f[0].getNumChildren()-finiteTypes) ){ - d_bound_quants.push_back( f ); - for( unsigned i=0; i<d_set[f].size(); i++) { - Node v = d_set[f][i]; - Node r = d_range[f][v]; + } + + if( bound_success ){ + d_bound_quants.push_back( f ); + for( unsigned i=0; i<d_set[f].size(); i++) { + Node v = d_set[f][i]; + if( d_bound_type[f][v]==BOUND_INT_RANGE || d_bound_type[f][v]==BOUND_SET_MEMBER ){ + Node r; + if( d_bound_type[f][v]==BOUND_INT_RANGE ){ + r = d_range[f][v]; + }else if( d_bound_type[f][v]==BOUND_SET_MEMBER ){ + r = NodeManager::currentNM()->mkNode( CARD, d_setm_range[f][v] ); + } bool isProxy = false; if( r.hasBoundVar() ){ //introduce a new bound @@ -319,18 +390,15 @@ void BoundedIntegers::registerQuantifier( Node f ) { r = new_range; isProxy = true; } - if( r.getKind()!=CONST_RATIONAL ){ + if( !r.isConst() ){ if( std::find(d_ranges.begin(), d_ranges.end(), r)==d_ranges.end() ){ - Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << " " << r.getKind() << std::endl; + Trace("bound-int") << "For " << v << ", bounded Integer Module will try to minimize : " << r << std::endl; d_ranges.push_back( r ); - d_rms[r] = new RangeModel(this, r, d_quantEngine->getSatContext(), d_quantEngine->getUserContext(), isProxy ); + d_rms[r] = new IntRangeModel( this, r, d_quantEngine->getSatContext(), d_quantEngine->getUserContext(), isProxy ); d_rms[r]->initialize(); } } } - }else{ - Trace("bound-int-warn") << "Warning : Bounded Integers : Could not find bounds for " << f << std::endl; - //Message() << "Bound integers : Cannot infer bounds of " << f << std::endl; } } } @@ -376,39 +444,28 @@ Node BoundedIntegers::getNextDecisionRequest() { return Node::null(); } +unsigned BoundedIntegers::getBoundVarType( Node q, Node v ) { + std::map< Node, unsigned >::iterator it = d_bound_type[q].find( v ); + if( it==d_bound_type[q].end() ){ + return BOUND_NONE; + }else{ + return it->second; + } +} + void BoundedIntegers::getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) { l = d_bounds[0][f][v]; u = d_bounds[1][f][v]; if( d_nground_range[f].find(v)!=d_nground_range[f].end() ){ - //must create substitution + //get the substitution std::vector< Node > vars; std::vector< Node > subs; - Trace("bound-int-rsi") << "Get bound value in model of variable " << v << std::endl; - for( unsigned i=0; i<d_set[f].size(); i++) { - if( d_set[f][i]!=v ){ - Trace("bound-int-rsi") << "Look up the value for " << d_set[f][i] << " " << rsi->d_var_order[d_set_nums[f][i]] << std::endl; - Trace("bound-int-rsi") << "term : " << rsi->getTerm(rsi->d_var_order[d_set_nums[f][i]]) << std::endl; - vars.push_back(d_set[f][i]); - subs.push_back(rsi->getTerm(rsi->d_var_order[d_set_nums[f][i]])); - }else{ - break; - } - } - Trace("bound-int-rsi") << "Do substitution..." << std::endl; - //check if it has been instantiated - if (!vars.empty() && !d_bnd_it[f][v].hasInstantiated(subs)){ - //must add the lemma - Node nn = d_nground_range[f][v]; - nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); - Node lem = NodeManager::currentNM()->mkNode( LEQ, nn, d_range[f][v] ); - Trace("bound-int-lemma") << "*** Add lemma to minimize instantiated non-ground term " << lem << std::endl; - d_quantEngine->getOutputChannel().lemma(lem, false, true); - l = Node::null(); - u = Node::null(); - return; - }else{ + if( getRsiSubsitution( f, v, vars, subs, rsi ) ){ u = u.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); l = l.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); + }else{ + u = Node::null(); + l = Node::null(); } } } @@ -416,12 +473,86 @@ void BoundedIntegers::getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, void BoundedIntegers::getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ) { getBounds( f, v, rsi, l, u ); Trace("bound-int-rsi") << "Get value in model for..." << l << " and " << u << std::endl; - l = d_quantEngine->getModel()->getCurrentModelValue( l ); - u = d_quantEngine->getModel()->getCurrentModelValue( u ); + if( !l.isNull() ){ + l = d_quantEngine->getModel()->getCurrentModelValue( l ); + } + if( !u.isNull() ){ + u = d_quantEngine->getModel()->getCurrentModelValue( u ); + } Trace("bound-int-rsi") << "Value is " << l << " ... " << u << std::endl; return; } -bool BoundedIntegers::isGroundRange(Node f, Node v) { - return isBoundVar(f,v) && !getLowerBound(f,v).hasBoundVar() && !getUpperBound(f,v).hasBoundVar(); +bool BoundedIntegers::isGroundRange( Node q, Node v ) { + if( isBoundVar(q,v) ){ + if( d_bound_type[q][v]==BOUND_INT_RANGE ){ + return !getLowerBound(q,v).hasBoundVar() && !getUpperBound(q,v).hasBoundVar(); + }else if( d_bound_type[q][v]==BOUND_SET_MEMBER ){ + return !d_setm_range[q][v].hasBoundVar(); + } + } + return false; } + +Node BoundedIntegers::getSetRange( Node q, Node v, RepSetIterator * rsi ) { + Node sr = d_setm_range[q][v]; + if( d_nground_range[q].find(v)!=d_nground_range[q].end() ){ + //get the substitution + std::vector< Node > vars; + std::vector< Node > subs; + if( getRsiSubsitution( q, v, vars, subs, rsi ) ){ + sr = sr.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); + }else{ + sr = Node::null(); + } + } + return sr; +} + +Node BoundedIntegers::getSetRangeValue( Node q, Node v, RepSetIterator * rsi ) { + Node sr = getSetRange( q, v, rsi ); + if( !sr.isNull() ){ + Trace("bound-int-rsi") << "Get value in model for..." << sr << std::endl; + sr = d_quantEngine->getModel()->getCurrentModelValue( sr ); + Trace("bound-int-rsi") << "Value is " << sr << std::endl; + } + return sr; +} + +bool BoundedIntegers::getRsiSubsitution( Node q, Node v, std::vector< Node >& vars, std::vector< Node >& subs, RepSetIterator * rsi ) { + + Trace("bound-int-rsi") << "Get bound value in model of variable " << v << std::endl; + Assert( d_set_nums[q].find( v )!=d_set_nums[q].end() ); + int vindex = d_set_nums[q][v]; + Assert( d_set_nums[q][v]==vindex ); + Trace("bound-int-rsi-debug") << " index order is " << vindex << std::endl; + //must take substitution for all variables that are iterating at higher level + for( int i=0; i<vindex; i++) { + Assert( d_set_nums[q][d_set[q][i]]==i ); + Trace("bound-int-rsi") << "Look up the value for " << d_set[q][i] << " " << i << std::endl; + int v = rsi->getVariableOrder( i ); + Assert( q[0][v]==d_set[q][i] ); + Node t = rsi->getCurrentTerm( v ); + Trace("bound-int-rsi") << "term : " << t << std::endl; + vars.push_back( d_set[q][i] ); + subs.push_back( t ); + } + + //check if it has been instantiated + if( !vars.empty() && !d_bnd_it[q][v].hasInstantiated(subs) ){ + if( d_bound_type[q][v]==BOUND_INT_RANGE ){ + //must add the lemma + Node nn = d_nground_range[q][v]; + nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); + Node lem = NodeManager::currentNM()->mkNode( LEQ, nn, d_range[q][v] ); + Trace("bound-int-lemma") << "*** Add lemma to minimize instantiated non-ground term " << lem << std::endl; + d_quantEngine->getOutputChannel().lemma(lem, false, true); + }else{ + //TODO : sets + } + return false; + }else{ + return true; + } +} + diff --git a/src/theory/quantifiers/bounded_integers.h b/src/theory/quantifiers/bounded_integers.h index 7d15097bd..ab4bcba96 100644..100755 --- a/src/theory/quantifiers/bounded_integers.h +++ b/src/theory/quantifiers/bounded_integers.h @@ -39,31 +39,57 @@ class BoundedIntegers : public QuantifiersModule typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap; typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap; typedef context::CDHashMap<int, bool> IntBoolMap; +public: + enum { + BOUND_FINITE, + BOUND_INT_RANGE, + BOUND_SET_MEMBER, + BOUND_NONE + }; private: //for determining bounds bool isBound( Node f, Node v ); bool hasNonBoundVar( Node f, Node b ); - std::map< Node, std::map< Node, Node > > d_bounds[2]; + //bound type + std::map< Node, std::map< Node, unsigned > > d_bound_type; std::map< Node, std::vector< Node > > d_set; - std::map< Node, std::vector< int > > d_set_nums; + std::map< Node, std::map< Node, int > > d_set_nums; + //integer lower/upper bounds + std::map< Node, std::map< Node, Node > > d_bounds[2]; std::map< Node, std::map< Node, Node > > d_range; std::map< Node, std::map< Node, Node > > d_nground_range; + //set membership range + std::map< Node, std::map< Node, Node > > d_setm_range; void hasFreeVar( Node f, Node n ); void process( Node f, Node n, bool pol, + std::map< Node, unsigned >& bound_lit_type_map, std::map< int, std::map< Node, Node > >& bound_lit_map, - std::map< int, std::map< Node, bool > >& bound_lit_pol_map ); + std::map< int, std::map< Node, bool > >& bound_lit_pol_map, + std::map< int, std::map< Node, Node > >& bound_int_range_term ); void processLiteral( Node f, Node lit, bool pol, + std::map< Node, unsigned >& bound_lit_type_map, std::map< int, std::map< Node, Node > >& bound_lit_map, - std::map< int, std::map< Node, bool > >& bound_lit_pol_map ); + std::map< int, std::map< Node, bool > >& bound_lit_pol_map, + std::map< int, std::map< Node, Node > >& bound_int_range_term ); std::vector< Node > d_bound_quants; private: class RangeModel { + public: + RangeModel(){} + virtual ~RangeModel(){} + virtual void initialize() = 0; + virtual void assertNode(Node n) = 0; + virtual Node getNextDecisionRequest() = 0; + virtual bool proxyCurrentRange() = 0; + }; + class IntRangeModel : public RangeModel { private: BoundedIntegers * d_bi; void allocateRange(); Node d_proxy_range; public: - RangeModel(BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy); + IntRangeModel( BoundedIntegers * bi, Node r, context::Context* c, context::Context* u, bool isProxy); + virtual ~IntRangeModel(){} Node d_range; int d_curr_max; std::map< int, Node > d_range_literal; @@ -108,27 +134,36 @@ private: std::map< Node, std::map< Node, BoundInstTrie > > d_bnd_it; private: void addLiteralFromRange( Node lit, Node r ); + + void setBoundedVar( Node f, Node v, unsigned bound_type ); public: BoundedIntegers( context::Context* c, QuantifiersEngine* qe ); - ~BoundedIntegers() throw() {} - + virtual ~BoundedIntegers(); + + void presolve(); bool needsCheck( Theory::Effort e ); void check( Theory::Effort e, unsigned quant_e ); void registerQuantifier( Node f ); void assertNode( Node n ); Node getNextDecisionRequest(); - bool isBoundVar( Node f, Node v ) { return std::find( d_set[f].begin(), d_set[f].end(), v )!=d_set[f].end(); } - unsigned getNumBoundVars( Node f ) { return d_set[f].size(); } - Node getBoundVar( Node f, int i ) { return d_set[f][i]; } - int getBoundVarNum( Node f, int i ) { return d_set_nums[f][i]; } - Node getLowerBound( Node f, Node v ){ return d_bounds[0][f][v]; } - Node getUpperBound( Node f, Node v ){ return d_bounds[1][f][v]; } + bool isBoundVar( Node q, Node v ) { return std::find( d_set[q].begin(), d_set[q].end(), v )!=d_set[q].end(); } + unsigned getBoundVarType( Node q, Node v ); + unsigned getNumBoundVars( Node q ) { return d_set[q].size(); } + Node getBoundVar( Node q, int i ) { return d_set[q][i]; } + //for integer range + Node getLowerBound( Node q, Node v ){ return d_bounds[0][q][v]; } + Node getUpperBound( Node q, Node v ){ return d_bounds[1][q][v]; } void getBounds( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ); void getBoundValues( Node f, Node v, RepSetIterator * rsi, Node & l, Node & u ); bool isGroundRange(Node f, Node v); + //for set range + Node getSetRange( Node q, Node v, RepSetIterator * rsi ); + Node getSetRangeValue( Node q, Node v, RepSetIterator * rsi ); /** Identify this module */ std::string identify() const { return "BoundedIntegers"; } +private: + bool getRsiSubsitution( Node q, Node v, std::vector< Node >& vars, std::vector< Node >& subs, RepSetIterator * rsi ); }; } diff --git a/src/theory/quantifiers/candidate_generator.cpp b/src/theory/quantifiers/candidate_generator.cpp index 43f5ee2fd..a0d9bda0f 100644..100755 --- a/src/theory/quantifiers/candidate_generator.cpp +++ b/src/theory/quantifiers/candidate_generator.cpp @@ -28,7 +28,7 @@ using namespace CVC4::theory; using namespace CVC4::theory::inst; bool CandidateGenerator::isLegalCandidate( Node n ){ - return ( !n.getAttribute(NoMatchAttribute()) && ( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(n) ) ); + return d_qe->getTermDatabase()->isTermActive( n ) && ( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(n) ); } void CandidateGeneratorQueue::addCandidate( Node n ) { @@ -59,7 +59,7 @@ Node CandidateGeneratorQueue::getNextCandidate(){ } CandidateGeneratorQE::CandidateGeneratorQE( QuantifiersEngine* qe, Node pat ) : - d_qe( qe ), d_term_iter( -1 ){ +CandidateGenerator( qe ), d_term_iter( -1 ){ d_op = qe->getTermDatabase()->getMatchOperator( pat ); Assert( !d_op.isNull() ); d_op_arity = pat.getNumChildren(); @@ -186,7 +186,7 @@ Node CandidateGeneratorQE::getNextCandidate(){ } CandidateGeneratorQELitEq::CandidateGeneratorQELitEq( QuantifiersEngine* qe, Node mpat ) : - d_match_pattern( mpat ), d_qe( qe ){ + CandidateGenerator( qe ), d_match_pattern( mpat ){ Assert( mpat.getKind()==EQUAL ); for( unsigned i=0; i<2; i++ ){ if( !quantifiers::TermDb::hasInstConstAttr(mpat[i]) ){ @@ -225,7 +225,7 @@ Node CandidateGeneratorQELitEq::getNextCandidate(){ CandidateGeneratorQELitDeq::CandidateGeneratorQELitDeq( QuantifiersEngine* qe, Node mpat ) : - d_match_pattern( mpat ), d_qe( qe ){ +CandidateGenerator( qe ), d_match_pattern( mpat ){ Assert( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ); d_match_pattern_type = d_match_pattern[0].getType(); @@ -259,7 +259,7 @@ Node CandidateGeneratorQELitDeq::getNextCandidate(){ CandidateGeneratorQEAll::CandidateGeneratorQEAll( QuantifiersEngine* qe, Node mpat ) : - d_match_pattern( mpat ), d_qe( qe ){ + CandidateGenerator( qe ), d_match_pattern( mpat ){ d_match_pattern_type = mpat.getType(); Assert( mpat.getKind()==INST_CONSTANT ); d_f = quantifiers::TermDb::getInstConstAttr( mpat ); diff --git a/src/theory/quantifiers/candidate_generator.h b/src/theory/quantifiers/candidate_generator.h index 18ef6a086..4fc6969fc 100644..100755 --- a/src/theory/quantifiers/candidate_generator.h +++ b/src/theory/quantifiers/candidate_generator.h @@ -33,8 +33,10 @@ namespace inst { /** base class for generating candidates for matching */ class CandidateGenerator { +protected: + QuantifiersEngine* d_qe; public: - CandidateGenerator(){} + CandidateGenerator( QuantifiersEngine* qe ) : d_qe( qe ){} virtual ~CandidateGenerator(){} /** Get candidates functions. These set up a context to get all match candidates. @@ -54,7 +56,7 @@ public: virtual void resetInstantiationRound() = 0; public: /** legal candidate */ - static bool isLegalCandidate( Node n ); + bool isLegalCandidate( Node n ); };/* class CandidateGenerator */ /** candidate generator queue (for manual candidate generation) */ @@ -63,7 +65,7 @@ private: std::vector< Node > d_candidates; int d_candidate_index; public: - CandidateGeneratorQueue() : d_candidate_index( 0 ){} + CandidateGeneratorQueue( QuantifiersEngine* qe ) : CandidateGenerator( qe ), d_candidate_index( 0 ){} ~CandidateGeneratorQueue() throw() {} void addCandidate( Node n ); @@ -80,8 +82,6 @@ class CandidateGeneratorQE : public CandidateGenerator private: //operator you are looking for Node d_op; - //instantiator pointer - QuantifiersEngine* d_qe; //the equality class iterator unsigned d_op_arity; std::vector< quantifiers::TermArgTrie* > d_tindex; @@ -122,8 +122,6 @@ private: Node d_match_pattern; Node d_match_gterm; bool d_do_mgt; - //einstantiator pointer - QuantifiersEngine* d_qe; public: CandidateGeneratorQELitEq( QuantifiersEngine* qe, Node mpat ); ~CandidateGeneratorQELitEq() throw() {} @@ -142,8 +140,6 @@ private: Node d_match_pattern; //type of disequality TypeNode d_match_pattern_type; - //einstantiator pointer - QuantifiersEngine* d_qe; public: CandidateGeneratorQELitDeq( QuantifiersEngine* qe, Node mpat ); ~CandidateGeneratorQELitDeq() throw() {} @@ -161,8 +157,6 @@ private: //equality you are trying to match equalities for Node d_match_pattern; TypeNode d_match_pattern_type; - //einstantiator pointer - QuantifiersEngine* d_qe; // quantifier/index for the variable we are matching Node d_f; unsigned d_index; diff --git a/src/theory/quantifiers/ce_guided_instantiation.cpp b/src/theory/quantifiers/ce_guided_instantiation.cpp index d9059a3e6..71bf7c426 100644..100755 --- a/src/theory/quantifiers/ce_guided_instantiation.cpp +++ b/src/theory/quantifiers/ce_guided_instantiation.cpp @@ -21,6 +21,8 @@ #include "theory/quantifiers/first_order_model.h" #include "theory/quantifiers/term_database.h" #include "theory/theory_engine.h" +#include "prop/prop_engine.h" +#include "theory/bv/theory_bv_rewriter.h" using namespace CVC4::kind; using namespace std; @@ -46,7 +48,7 @@ void CegConjecture::assign( Node q ) { Assert( q.getKind()==FORALL ); d_assert_quant = q; //register with single invocation if applicable - if( d_qe->getTermDatabase()->isQAttrSygus( d_assert_quant ) && options::cegqiSingleInv() ){ + if( d_qe->getTermDatabase()->isQAttrSygus( d_assert_quant ) && options::cegqiSingleInvMode()!=CEGQI_SI_MODE_NONE ){ d_ceg_si->initialize( q ); if( q!=d_ceg_si->d_quant ){ //Node red_lem = NodeManager::currentNM()->mkNode( OR, q.negate(), d_cegqi_si->d_quant ); @@ -55,12 +57,15 @@ void CegConjecture::assign( Node q ) { } } d_quant = q; + Assert( d_candidates.empty() ); + std::vector< Node > vars; for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ + vars.push_back( q[0][i] ); d_candidates.push_back( NodeManager::currentNM()->mkSkolem( "e", q[0][i].getType() ) ); } Trace("cegqi") << "Base quantified formula is : " << q << std::endl; //construct base instantiation - d_base_inst = Rewriter::rewrite( d_qe->getInstantiation( q, d_candidates ) ); + d_base_inst = Rewriter::rewrite( d_qe->getInstantiation( q, vars, d_candidates ) ); Trace("cegqi") << "Base instantiation is : " << d_base_inst << std::endl; if( d_qe->getTermDatabase()->isQAttrSygus( d_assert_quant ) ){ CegInstantiation::collectDisjuncts( d_base_inst, d_base_disj ); @@ -130,14 +135,18 @@ Node CegConjecture::getLiteral( QuantifiersEngine * qe, int i ) { qe->getOutputChannel().lemma( lem ); qe->getOutputChannel().requirePhase( lit, true ); - if( getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED ){ + if( getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED || getCegqiFairMode()==CEGQI_FAIR_DT_SIZE_PRED ){ //implies height bounds on each candidate variable std::vector< Node > lem_c; for( unsigned j=0; j<d_candidates.size(); j++ ){ - lem_c.push_back( NodeManager::currentNM()->mkNode( DT_HEIGHT_BOUND, d_candidates[j], c ) ); + if( getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED ){ + lem_c.push_back( NodeManager::currentNM()->mkNode( DT_HEIGHT_BOUND, d_candidates[j], c ) ); + }else{ + //lem_c.push_back( NodeManager::currentNM()->mkNode( DT_SIZE_BOUND, d_candidates[j], c ) ); + } } Node hlem = NodeManager::currentNM()->mkNode( OR, lit.negate(), lem_c.size()==1 ? lem_c[0] : NodeManager::currentNM()->mkNode( AND, lem_c ) ); - Trace("cegqi-lemma") << "Cegqi::Lemma : Fairness expansion (dt-height-pred) : " << hlem << std::endl; + Trace("cegqi-lemma") << "Cegqi::Lemma : Fairness expansion (pred) : " << hlem << std::endl; qe->getOutputChannel().lemma( hlem ); } return lit; @@ -257,8 +266,45 @@ void CegInstantiation::check( Theory::Effort e, unsigned quant_e ) { } } +void CegInstantiation::preRegisterQuantifier( Node q ) { + if( options::sygusDirectEval() ){ + if( q.getNumChildren()==3 && q[2].getKind()==INST_PATTERN_LIST && q[2][0].getKind()==INST_PATTERN ){ + //check whether it is an evaluation axiom + Node pat = q[2][0][0]; + if( pat.getKind()==APPLY_UF ){ + TypeNode tn = pat[0].getType(); + if( datatypes::DatatypesRewriter::isTypeDatatype(tn) ){ + const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); + if( dt.isSygus() ){ + //do unfolding if it induces Boolean structure, + //do direct evaluation if it does not induce Boolean structure, + // the reasoning is unfolding over these terms does not lead to helpful conflict analysis, and introduces many shared terms + bool directEval = true; + TypeNode ptn = pat.getType(); + if( ptn.isBoolean() || ptn.isBitVector() ){ + directEval = false; + }else{ + unsigned cindex = Datatype::indexOf(pat[0].getOperator().toExpr() ); + Node base = d_quantEngine->getTermDatabaseSygus()->getGenericBase( tn, dt, cindex ); + Trace("cegqi-debug") << "Generic base term for " << pat[0] << " is " << base << std::endl; + if( base.getKind()==ITE ){ + directEval = false; + } + } + if( directEval ){ + //take ownership of this quantified formula (will use direct evaluation instead of unfolding instantiation) + d_quantEngine->setOwner( q, this ); + d_eval_axioms[q] = true; + } + } + } + } + } + } +} + void CegInstantiation::registerQuantifier( Node q ) { - if( d_quantEngine->getOwner( q )==this ){ + if( d_quantEngine->getOwner( q )==this && d_eval_axioms.find( q )==d_eval_axioms.end() ){ if( !d_conj->isAssigned() ){ Trace("cegqi") << "Register conjecture : " << q << std::endl; d_conj->assign( q ); @@ -278,7 +324,7 @@ void CegInstantiation::registerQuantifier( Node q ) { if( it!=d_uf_measure.end() ){ mc.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, it->second, d_conj->d_candidates[j] ) ); } - }else if( d_conj->getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED ){ + }else if( d_conj->getCegqiFairMode()==CEGQI_FAIR_DT_HEIGHT_PRED || d_conj->getCegqiFairMode()==CEGQI_FAIR_DT_SIZE_PRED ){ //measure term is a fresh constant mc.push_back( NodeManager::currentNM()->mkSkolem( "K", NodeManager::currentNM()->integerType() ) ); } @@ -291,6 +337,8 @@ void CegInstantiation::registerQuantifier( Node q ) { }else{ Assert( d_conj->d_quant==q ); } + }else{ + Trace("cegqi-debug") << "Register quantifier : " << q << std::endl; } } @@ -317,7 +365,7 @@ Node CegInstantiation::getNextDecisionRequest() { Trace("cegqi-debug") << "CEGQI : Decide next on : " << req_dec[i] << "..." << std::endl; return req_dec[i]; }else{ - Trace("cegqi-debug") << "CEGQI : " << req_dec[i] << " already has value " << value << std::endl; + Trace("cegqi-debug2") << "CEGQI : " << req_dec[i] << " already has value " << value << std::endl; } } @@ -350,6 +398,11 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) { Trace("cegqi-engine-debug") << conj->d_candidates[i] << " "; } Trace("cegqi-engine-debug") << std::endl; + Trace("cegqi-engine-debug") << " * Candidate ce skolems : "; + for( unsigned i=0; i<conj->d_ce_sk.size(); i++ ){ + Trace("cegqi-engine-debug") << conj->d_ce_sk[i] << " "; + } + Trace("cegqi-engine-debug") << std::endl; if( conj->getCegqiFairMode()!=CEGQI_FAIR_NONE ){ Trace("cegqi-engine") << " * Current term size : " << conj->d_curr_lit.get() << std::endl; } @@ -374,6 +427,24 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) { } std::vector< Node > model_values; if( getModelValues( conj, conj->d_candidates, model_values ) ){ + if( options::sygusDirectEval() ){ + std::vector< Node > eager_eval_lem; + for( unsigned j=0; j<conj->d_candidates.size(); j++ ){ + d_quantEngine->getTermDatabaseSygus()->registerModelValue( conj->d_candidates[j], model_values[j], eager_eval_lem ); + } + if( !eager_eval_lem.empty() ){ + for( unsigned j=0; j<eager_eval_lem.size(); j++ ){ + Node lem = eager_eval_lem[j]; + if( d_quantEngine->getTheoryEngine()->isTheoryEnabled(THEORY_BV) ){ + //FIXME: hack to incorporate hacks from BV for division by zero + lem = bv::TheoryBVRewriter::eliminateBVSDiv( lem ); + } + Trace("cegqi-lemma") << "Cegqi::Lemma : evaluation : " << lem << std::endl; + d_quantEngine->addLemma( lem ); + } + return; + } + } //check if we must apply fairness lemmas if( conj->getCegqiFairMode()==CEGQI_FAIR_UF_DT_SIZE ){ std::vector< Node > lems; @@ -390,6 +461,7 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) { } } //must get a counterexample to the value of the current candidate + Assert( conj->d_candidates.size()==model_values.size() ); Node inst = conj->d_base_inst.substitute( conj->d_candidates.begin(), conj->d_candidates.end(), model_values.begin(), model_values.end() ); //check whether we will run CEGIS on inner skolem variables bool sk_refine = ( !conj->isGround() || conj->d_refine_count==0 ); @@ -422,10 +494,30 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) { Node lem = NodeManager::currentNM()->mkNode( OR, ic ); lem = Rewriter::rewrite( lem ); d_last_inst_si = false; + //eagerly unfold applications of evaluation function + if( options::sygusDirectEval() ){ + Trace("cegqi-eager") << "pre-unfold counterexample : " << lem << std::endl; + std::map< Node, Node > visited_n; + lem = getEagerUnfold( lem, visited_n ); + } + Trace("cegqi-lemma") << "Cegqi::Lemma : counterexample : " << lem << std::endl; - d_quantEngine->addLemma( lem ); - ++(d_statistics.d_cegqi_lemmas_ce); - Trace("cegqi-engine") << " ...find counterexample." << std::endl; + if( d_quantEngine->addLemma( lem ) ){ + ++(d_statistics.d_cegqi_lemmas_ce); + Trace("cegqi-engine") << " ...find counterexample." << std::endl; + }else{ + //this may happen if we eagerly unfold, simplify to true + if( !options::sygusDirectEval() ){ + Trace("cegqi-engine") << " ...FAILED to add candidate!" << std::endl; + }else{ + Trace("cegqi-engine-debug") << " ...FAILED to add candidate!" << std::endl; + } + if( conj->d_refine_count==0 ){ + //immediately go to refine candidate + checkCegConjecture( conj ); + return; + } + } } }else{ @@ -589,6 +681,74 @@ void CegInstantiation::getMeasureLemmas( Node n, Node v, std::vector< Node >& le } } +Node CegInstantiation::getEagerUnfold( Node n, std::map< Node, Node >& visited ) { + std::map< Node, Node >::iterator itv = visited.find( n ); + if( itv==visited.end() ){ + Trace("cegqi-eager-debug") << "getEagerUnfold " << n << std::endl; + Node ret; + if( n.getKind()==APPLY_UF ){ + TypeNode tn = n[0].getType(); + Trace("cegqi-eager-debug") << "check " << n[0].getType() << std::endl; + if( datatypes::DatatypesRewriter::isTypeDatatype(tn) ){ + const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); + if( dt.isSygus() ){ + Trace("cegqi-eager") << "Unfold eager : " << n << std::endl; + Node bTerm = d_quantEngine->getTermDatabaseSygus()->sygusToBuiltin( n[0], tn ); + Trace("cegqi-eager") << "Built-in term : " << bTerm << std::endl; + std::vector< Node > vars; + std::vector< Node > subs; + Node var_list = Node::fromExpr( dt.getSygusVarList() ); + Assert( var_list.getNumChildren()+1==n.getNumChildren() ); + for( unsigned j=0; j<var_list.getNumChildren(); j++ ){ + vars.push_back( var_list[j] ); + } + for( unsigned j=1; j<n.getNumChildren(); j++ ){ + Node nc = getEagerUnfold( n[j], visited ); + 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)); + subs.push_back( nc.eqNode( c ) ); + }else{ + 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; + } +} + void CegInstantiation::printSynthSolution( std::ostream& out ) { if( d_conj->isAssigned() ){ Trace("cegqi-debug") << "Printing synth solution..." << std::endl; diff --git a/src/theory/quantifiers/ce_guided_instantiation.h b/src/theory/quantifiers/ce_guided_instantiation.h index 57dc31850..c8b41c035 100644..100755 --- a/src/theory/quantifiers/ce_guided_instantiation.h +++ b/src/theory/quantifiers/ce_guided_instantiation.h @@ -126,6 +126,8 @@ private: CegConjecture * d_conj; /** last instantiation by single invocation module? */ bool d_last_inst_si; + /** evaluation axioms */ + std::map< Node, bool > d_eval_axioms; private: //for enforcing fairness /** measure functions */ std::map< TypeNode, Node > d_uf_measure; @@ -139,6 +141,8 @@ private: //for enforcing fairness std::map< Node, std::map< int, Node > > d_size_term_lemma; /** get measure lemmas */ void getMeasureLemmas( Node n, Node v, std::vector< Node >& lems ); + /** get eager unfolding */ + Node getEagerUnfold( Node n, std::map< Node, Node >& visited ); private: /** check conjecture */ void checkCegConjecture( CegConjecture * conj ); @@ -156,6 +160,7 @@ public: /* Call during quantifier engine's check */ void check( Theory::Effort e, unsigned quant_e ); /* Called for new quantifiers */ + void preRegisterQuantifier( Node q ); void registerQuantifier( Node q ); void assertNode( Node n ); Node getNextDecisionRequest(); diff --git a/src/theory/quantifiers/ce_guided_single_inv.cpp b/src/theory/quantifiers/ce_guided_single_inv.cpp index 33856d226..3177739ac 100644..100755 --- a/src/theory/quantifiers/ce_guided_single_inv.cpp +++ b/src/theory/quantifiers/ce_guided_single_inv.cpp @@ -111,6 +111,7 @@ void CegConjectureSingleInv::getInitialSingleInvLemma( std::vector< Node >& lems void CegConjectureSingleInv::initialize( Node q ) { Assert( d_quant.isNull() ); + Assert( options::cegqiSingleInvMode()!=CEGQI_SI_MODE_NONE ); //initialize data d_quant = q; //process @@ -121,6 +122,7 @@ void CegConjectureSingleInv::initialize( Node q ) { std::map< Node, std::map< Node, std::vector< Node > > > prog_invoke; std::vector< Node > progs; std::map< Node, std::map< Node, bool > > contains; + bool is_syntax_restricted = false; for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ progs.push_back( q[0][i] ); //check whether all types have ITE @@ -131,161 +133,173 @@ void CegConjectureSingleInv::initialize( Node q ) { d_has_ites = false; } } + Assert( datatypes::DatatypesRewriter::isTypeDatatype(tn) ); + const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); + Assert( dt.isSygus() ); + if( !dt.getSygusAllowAll() ){ + is_syntax_restricted = true; + } } - Node qq = q[1]; - if( q[1].getKind()==NOT && q[1][0].getKind()==FORALL ){ - qq = q[1][0][1]; - }else{ - qq = TermDb::simpleNegate( qq ); - } - //remove the deep embedding - std::map< Node, Node > visited; - std::vector< TypeNode > types; - std::vector< Node > order_vars; - std::map< Node, Node > single_inv_app_map; - int type_valid = 0; - qq = removeDeepEmbedding( qq, progs, types, type_valid, visited ); - Trace("cegqi-si-debug") << "- Remove deep embedding, got : " << qq << ", type valid = " << type_valid << std::endl; + //abort if not aggressive bool singleInvocation = true; - if( type_valid==0 ){ - //process the single invocation-ness of the property - d_sip->init( types, qq ); - Trace("cegqi-si") << "- Partitioned to single invocation parts : " << std::endl; - d_sip->debugPrint( "cegqi-si" ); - //map from program to bound variables - for( unsigned j=0; j<progs.size(); j++ ){ - Node prog = progs[j]; - std::map< Node, Node >::iterator it_nsi = d_nsi_op_map.find( prog ); - if( it_nsi!=d_nsi_op_map.end() ){ - Node op = it_nsi->second; - std::map< Node, Node >::iterator it_fov = d_sip->d_func_fo_var.find( op ); - if( it_fov!=d_sip->d_func_fo_var.end() ){ - Node pv = it_fov->second; - Assert( d_sip->d_func_inv.find( op )!=d_sip->d_func_inv.end() ); - Node inv = d_sip->d_func_inv[op]; - single_inv_app_map[prog] = inv; - Trace("cegqi-si") << " " << pv << ", " << inv << " is associated with program " << prog << std::endl; - d_prog_to_sol_index[prog] = order_vars.size(); - order_vars.push_back( pv ); + if( options::cegqiSingleInvMode()==CEGQI_SI_MODE_USE && is_syntax_restricted ){ + singleInvocation = false; + Trace("cegqi-si") << "...grammar is restricted, do not use single invocation techniques." << std::endl; + }else{ + Node qq = q[1]; + if( q[1].getKind()==NOT && q[1][0].getKind()==FORALL ){ + qq = q[1][0][1]; + }else{ + qq = TermDb::simpleNegate( qq ); + } + //remove the deep embedding + std::map< Node, Node > visited; + std::vector< TypeNode > types; + std::vector< Node > order_vars; + std::map< Node, Node > single_inv_app_map; + int type_valid = 0; + qq = removeDeepEmbedding( qq, progs, types, type_valid, visited ); + Trace("cegqi-si-debug") << "- Remove deep embedding, got : " << qq << ", type valid = " << type_valid << std::endl; + if( type_valid==0 ){ + //process the single invocation-ness of the property + d_sip->init( types, qq ); + Trace("cegqi-si") << "- Partitioned to single invocation parts : " << std::endl; + d_sip->debugPrint( "cegqi-si" ); + //map from program to bound variables + for( unsigned j=0; j<progs.size(); j++ ){ + Node prog = progs[j]; + std::map< Node, Node >::iterator it_nsi = d_nsi_op_map.find( prog ); + if( it_nsi!=d_nsi_op_map.end() ){ + Node op = it_nsi->second; + std::map< Node, Node >::iterator it_fov = d_sip->d_func_fo_var.find( op ); + if( it_fov!=d_sip->d_func_fo_var.end() ){ + Node pv = it_fov->second; + Assert( d_sip->d_func_inv.find( op )!=d_sip->d_func_inv.end() ); + Node inv = d_sip->d_func_inv[op]; + single_inv_app_map[prog] = inv; + Trace("cegqi-si") << " " << pv << ", " << inv << " is associated with program " << prog << std::endl; + d_prog_to_sol_index[prog] = order_vars.size(); + order_vars.push_back( pv ); + } + }else{ + //does not mention the function } - }else{ - //does not mention the function } - } - //reorder the variables - Assert( d_sip->d_func_vars.size()==order_vars.size() ); - d_sip->d_func_vars.clear(); - d_sip->d_func_vars.insert( d_sip->d_func_vars.begin(), order_vars.begin(), order_vars.end() ); + //reorder the variables + Assert( d_sip->d_func_vars.size()==order_vars.size() ); + d_sip->d_func_vars.clear(); + d_sip->d_func_vars.insert( d_sip->d_func_vars.begin(), order_vars.begin(), order_vars.end() ); - //check if it is single invocation - if( !d_sip->d_conjuncts[1].empty() ){ - singleInvocation = false; - if( options::cegqiSingleInvPartial() ){ - //this enables partially single invocation techniques - d_nsingle_inv = d_sip->getNonSingleInvocation(); - d_nsingle_inv = TermDb::simpleNegate( d_nsingle_inv ); - d_full_inv = d_sip->getFullSpecification(); - d_full_inv = TermDb::simpleNegate( d_full_inv ); - singleInvocation = true; - }else if( options::sygusInvTemplMode() != SYGUS_INV_TEMPL_MODE_NONE ){ - //if we are doing invariant templates, then construct the template - std::map< Node, bool > has_inv; - std::map< Node, std::vector< Node > > inv_pre_post[2]; - for( unsigned i=0; i<d_sip->d_conjuncts[2].size(); i++ ){ - std::vector< Node > disjuncts; - Node func; - int pol = -1; - Trace("cegqi-inv") << "INV process " << d_sip->d_conjuncts[2][i] << std::endl; - d_sip->extractInvariant( d_sip->d_conjuncts[2][i], func, pol, disjuncts ); - if( pol>=0 ){ - Assert( d_nsi_op_map_to_prog.find( func )!=d_nsi_op_map_to_prog.end() ); - Node prog = d_nsi_op_map_to_prog[func]; - Trace("cegqi-inv") << "..." << ( pol==0 ? "pre" : "post" ) << "-condition for " << prog << "." << std::endl; - Node c = disjuncts.empty() ? d_qe->getTermDatabase()->d_false : ( disjuncts.size()==1 ? disjuncts[0] : NodeManager::currentNM()->mkNode( OR, disjuncts ) ); - c = pol==0 ? TermDb::simpleNegate( c ) : c; - Trace("cegqi-inv-debug") << "...extracted : " << c << std::endl; - inv_pre_post[pol][prog].push_back( c ); - has_inv[prog] = true; - }else{ - Trace("cegqi-inv") << "...no status." << std::endl; + //check if it is single invocation + if( !d_sip->d_conjuncts[1].empty() ){ + singleInvocation = false; + if( options::cegqiSingleInvPartial() ){ + //this enables partially single invocation techniques + d_nsingle_inv = d_sip->getNonSingleInvocation(); + d_nsingle_inv = TermDb::simpleNegate( d_nsingle_inv ); + d_full_inv = d_sip->getFullSpecification(); + d_full_inv = TermDb::simpleNegate( d_full_inv ); + singleInvocation = true; + }else if( options::sygusInvTemplMode() != SYGUS_INV_TEMPL_MODE_NONE ){ + //if we are doing invariant templates, then construct the template + std::map< Node, bool > has_inv; + std::map< Node, std::vector< Node > > inv_pre_post[2]; + for( unsigned i=0; i<d_sip->d_conjuncts[2].size(); i++ ){ + std::vector< Node > disjuncts; + Node func; + int pol = -1; + Trace("cegqi-inv") << "INV process " << d_sip->d_conjuncts[2][i] << std::endl; + d_sip->extractInvariant( d_sip->d_conjuncts[2][i], func, pol, disjuncts ); + if( pol>=0 ){ + Assert( d_nsi_op_map_to_prog.find( func )!=d_nsi_op_map_to_prog.end() ); + Node prog = d_nsi_op_map_to_prog[func]; + Trace("cegqi-inv") << "..." << ( pol==0 ? "pre" : "post" ) << "-condition for " << prog << "." << std::endl; + Node c = disjuncts.empty() ? d_qe->getTermDatabase()->d_false : ( disjuncts.size()==1 ? disjuncts[0] : NodeManager::currentNM()->mkNode( OR, disjuncts ) ); + c = pol==0 ? TermDb::simpleNegate( c ) : c; + Trace("cegqi-inv-debug") << "...extracted : " << c << std::endl; + inv_pre_post[pol][prog].push_back( c ); + has_inv[prog] = true; + }else{ + Trace("cegqi-inv") << "...no status." << std::endl; + } } - } - Trace("cegqi-inv") << "Constructing invariant templates..." << std::endl; - //now, contruct the template for the invariant(s) - std::map< Node, Node > prog_templ; - for( std::map< Node, bool >::iterator iti = has_inv.begin(); iti != has_inv.end(); ++iti ){ - Node prog = iti->first; - Trace("cegqi-inv") << "...for " << prog << "..." << std::endl; - Trace("cegqi-inv") << " args : "; + Trace("cegqi-inv") << "Constructing invariant templates..." << std::endl; + //now, contruct the template for the invariant(s) + std::map< Node, Node > prog_templ; + for( std::map< Node, bool >::iterator iti = has_inv.begin(); iti != has_inv.end(); ++iti ){ + Node prog = iti->first; + Trace("cegqi-inv") << "...for " << prog << "..." << std::endl; + Trace("cegqi-inv") << " args : "; + for( unsigned j=0; j<d_sip->d_si_vars.size(); j++ ){ + std::stringstream ss; + ss << "i_" << j; + Node v = NodeManager::currentNM()->mkBoundVar( ss.str(), d_sip->d_si_vars[j].getType() ); + d_prog_templ_vars[prog].push_back( v ); + Trace("cegqi-inv") << v << " "; + } + Trace("cegqi-inv") << std::endl; + Node pre = inv_pre_post[0][prog].empty() ? NodeManager::currentNM()->mkConst( false ) : + ( inv_pre_post[0][prog].size()==1 ? inv_pre_post[0][prog][0] : NodeManager::currentNM()->mkNode( OR, inv_pre_post[0][prog] ) ); + d_trans_pre[prog] = pre.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() ); + Node post = inv_pre_post[1][prog].empty() ? NodeManager::currentNM()->mkConst( true ) : + ( inv_pre_post[1][prog].size()==1 ? inv_pre_post[1][prog][0] : NodeManager::currentNM()->mkNode( AND, inv_pre_post[1][prog] ) ); + d_trans_post[prog] = post.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() ); + Trace("cegqi-inv") << " precondition : " << d_trans_pre[prog] << std::endl; + Trace("cegqi-inv") << " postcondition : " << d_trans_post[prog] << std::endl; + Node invariant = single_inv_app_map[prog]; + invariant = invariant.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() ); + Trace("cegqi-inv") << " invariant : " << invariant << std::endl; + //construct template + Node templ; + if( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_PRE ){ + //templ = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant ), d_trans_post[prog] ); + templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant ); + }else{ + Assert( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_POST ); + //templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant ) ); + templ = NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant ); + } + visited.clear(); + templ = addDeepEmbedding( templ, visited ); + Trace("cegqi-inv") << " template : " << templ << std::endl; + prog_templ[prog] = templ; + } + Node bd = d_sip->d_conjuncts[2].size()==1 ? d_sip->d_conjuncts[2][0] : NodeManager::currentNM()->mkNode( AND, d_sip->d_conjuncts[2] ); + visited.clear(); + bd = addDeepEmbedding( bd, visited ); + Trace("cegqi-inv") << " body : " << bd << std::endl; + bd = substituteInvariantTemplates( bd, prog_templ, d_prog_templ_vars ); + Trace("cegqi-inv-debug") << " templ-subs body : " << bd << std::endl; + //make inner existential + std::vector< Node > new_var_bv; for( unsigned j=0; j<d_sip->d_si_vars.size(); j++ ){ std::stringstream ss; - ss << "i_" << j; - Node v = NodeManager::currentNM()->mkBoundVar( ss.str(), d_sip->d_si_vars[j].getType() ); - d_prog_templ_vars[prog].push_back( v ); - Trace("cegqi-inv") << v << " "; + ss << "ss_" << j; + new_var_bv.push_back( NodeManager::currentNM()->mkBoundVar( ss.str(), d_sip->d_si_vars[j].getType() ) ); } - Trace("cegqi-inv") << std::endl; - Node pre = inv_pre_post[0][prog].empty() ? NodeManager::currentNM()->mkConst( false ) : - ( inv_pre_post[0][prog].size()==1 ? inv_pre_post[0][prog][0] : NodeManager::currentNM()->mkNode( OR, inv_pre_post[0][prog] ) ); - d_trans_pre[prog] = pre.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() ); - Node post = inv_pre_post[1][prog].empty() ? NodeManager::currentNM()->mkConst( true ) : - ( inv_pre_post[1][prog].size()==1 ? inv_pre_post[1][prog][0] : NodeManager::currentNM()->mkNode( AND, inv_pre_post[1][prog] ) ); - d_trans_post[prog] = post.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() ); - Trace("cegqi-inv") << " precondition : " << d_trans_pre[prog] << std::endl; - Trace("cegqi-inv") << " postcondition : " << d_trans_post[prog] << std::endl; - Node invariant = single_inv_app_map[prog]; - invariant = invariant.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), d_prog_templ_vars[prog].begin(), d_prog_templ_vars[prog].end() ); - Trace("cegqi-inv") << " invariant : " << invariant << std::endl; - //construct template - Node templ; - if( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_PRE ){ - //templ = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant ), d_trans_post[prog] ); - templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], invariant ); - }else{ - Assert( options::sygusInvTemplMode() == SYGUS_INV_TEMPL_MODE_POST ); - //templ = NodeManager::currentNM()->mkNode( OR, d_trans_pre[prog], NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant ) ); - templ = NodeManager::currentNM()->mkNode( AND, d_trans_post[prog], invariant ); + bd = bd.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), new_var_bv.begin(), new_var_bv.end() ); + Assert( q[1].getKind()==NOT && q[1][0].getKind()==FORALL ); + for( unsigned j=0; j<q[1][0][0].getNumChildren(); j++ ){ + new_var_bv.push_back( q[1][0][0][j] ); } - visited.clear(); - templ = addDeepEmbedding( templ, visited ); - Trace("cegqi-inv") << " template : " << templ << std::endl; - prog_templ[prog] = templ; - } - Node bd = d_sip->d_conjuncts[2].size()==1 ? d_sip->d_conjuncts[2][0] : NodeManager::currentNM()->mkNode( AND, d_sip->d_conjuncts[2] ); - visited.clear(); - bd = addDeepEmbedding( bd, visited ); - Trace("cegqi-inv") << " body : " << bd << std::endl; - bd = substituteInvariantTemplates( bd, prog_templ, d_prog_templ_vars ); - Trace("cegqi-inv-debug") << " templ-subs body : " << bd << std::endl; - //make inner existential - std::vector< Node > new_var_bv; - for( unsigned j=0; j<d_sip->d_si_vars.size(); j++ ){ - std::stringstream ss; - ss << "ss_" << j; - new_var_bv.push_back( NodeManager::currentNM()->mkBoundVar( ss.str(), d_sip->d_si_vars[j].getType() ) ); - } - bd = bd.substitute( d_sip->d_si_vars.begin(), d_sip->d_si_vars.end(), new_var_bv.begin(), new_var_bv.end() ); - Assert( q[1].getKind()==NOT && q[1][0].getKind()==FORALL ); - for( unsigned j=0; j<q[1][0][0].getNumChildren(); j++ ){ - new_var_bv.push_back( q[1][0][0][j] ); - } - if( !new_var_bv.empty() ){ - Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, new_var_bv ); - bd = NodeManager::currentNM()->mkNode( FORALL, bvl, bd ).negate(); + if( !new_var_bv.empty() ){ + Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, new_var_bv ); + bd = NodeManager::currentNM()->mkNode( FORALL, bvl, bd ).negate(); + } + //make outer universal + bd = NodeManager::currentNM()->mkNode( FORALL, q[0], bd ); + bd = Rewriter::rewrite( bd ); + Trace("cegqi-inv") << " rtempl-subs body : " << bd << std::endl; + d_quant = bd; } - //make outer universal - bd = NodeManager::currentNM()->mkNode( FORALL, q[0], bd ); - bd = Rewriter::rewrite( bd ); - Trace("cegqi-inv") << " rtempl-subs body : " << bd << std::endl; - d_quant = bd; + }else{ + //we are fully single invocation } }else{ - //we are fully single invocation + Trace("cegqi-si") << "...property is not single invocation, involves functions with different argument sorts." << std::endl; + singleInvocation = false; } - }else{ - Trace("cegqi-si") << "...property is not single invocation, involves functions with different argument sorts." << std::endl; - singleInvocation = false; } if( singleInvocation ){ d_single_inv = d_sip->getSingleInvocation(); @@ -534,6 +548,7 @@ bool CegConjectureSingleInv::doAddInstantiation( std::vector< Node >& subs ){ return false; }else{ Trace("cegqi-engine") << siss.str() << std::endl; + Assert( d_single_inv_var.size()==subs.size() ); Node lem = d_single_inv[1].substitute( d_single_inv_var.begin(), d_single_inv_var.end(), subs.begin(), subs.end() ); if( d_qe->getTermDatabase()->containsVtsTerm( lem ) ){ Trace("cegqi-engine-debug") << "Rewrite based on vts symbols..." << std::endl; @@ -595,6 +610,7 @@ bool CegConjectureSingleInv::check( std::vector< Node >& lems ) { for( unsigned i=0; i<d_sip->d_all_vars.size(); i++ ){ subs.push_back( NodeManager::currentNM()->mkSkolem( "kv", d_sip->d_all_vars[i].getType(), "created for verifying nsi" ) ); } + Assert( d_sip->d_all_vars.size()==subs.size() ); inst = inst.substitute( d_sip->d_all_vars.begin(), d_sip->d_all_vars.end(), subs.begin(), subs.end() ); Trace("cegqi-nsi") << "NSI : verification : " << inst << std::endl; Trace("cegqi-lemma") << "Cegqi::Lemma : verification lemma : " << inst << std::endl; @@ -751,6 +767,7 @@ Node CegConjectureSingleInv::getSolution( unsigned sol_index, TypeNode stn, int& std::sort( indices.begin(), indices.end(), ssii ); Trace("csi-sol") << "Construct solution" << std::endl; s = constructSolution( indices, sol_index, 0 ); + Assert( vars.size()==d_sol->d_varList.size() ); s = s.substitute( vars.begin(), vars.end(), d_sol->d_varList.begin(), d_sol->d_varList.end() ); } d_orig_solution = s; @@ -826,8 +843,8 @@ Node CegConjectureSingleInv::reconstructToSyntax( Node s, TypeNode stn, int& rec } bool CegConjectureSingleInv::needsCheck() { - if( options::cegqiSingleInvMultiInstAbort() ){ - if( !hasITEs() ){ + if( options::cegqiSingleInvMode()==CEGQI_SI_MODE_ALL_ABORT ){ + if( !d_has_ites ){ return d_inst.empty(); } } @@ -922,6 +939,7 @@ void SingleInvocationPartition::process( Node n ) { std::vector< Node > funcs; //normalize the invocations if( !terms.empty() ){ + Assert( terms.size()==subs.size() ); cr = cr.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() ); } std::vector< Node > children; @@ -940,6 +958,7 @@ void SingleInvocationPartition::process( Node n ) { } Trace("si-prt") << std::endl; cr = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( OR, children ); + Assert( terms.size()==subs.size() ); cr = cr.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() ); Trace("si-prt-debug") << "...normalized invocations to " << cr << std::endl; //now must check if it has other bound variables @@ -974,6 +993,7 @@ void SingleInvocationPartition::process( Node n ) { } } } + Assert( terms.size()==subs.size() ); cr = cr.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() ); } cr = Rewriter::rewrite( cr ); @@ -982,6 +1002,7 @@ void SingleInvocationPartition::process( Node n ) { TermDb::getBoundVars( cr, d_all_vars ); if( singleInvocation ){ //replace with single invocation formulation + Assert( si_terms.size()==si_subs.size() ); cr = cr.substitute( si_terms.begin(), si_terms.end(), si_subs.begin(), si_subs.end() ); cr = Rewriter::rewrite( cr ); Trace("si-prt") << ".....si version=" << cr << std::endl; diff --git a/src/theory/quantifiers/ce_guided_single_inv.h b/src/theory/quantifiers/ce_guided_single_inv.h index 4d2f9a0e5..4d2f9a0e5 100644..100755 --- a/src/theory/quantifiers/ce_guided_single_inv.h +++ b/src/theory/quantifiers/ce_guided_single_inv.h diff --git a/src/theory/quantifiers/ce_guided_single_inv_ei.cpp b/src/theory/quantifiers/ce_guided_single_inv_ei.cpp index 6394fca3d..6394fca3d 100644..100755 --- a/src/theory/quantifiers/ce_guided_single_inv_ei.cpp +++ b/src/theory/quantifiers/ce_guided_single_inv_ei.cpp diff --git a/src/theory/quantifiers/ce_guided_single_inv_ei.h b/src/theory/quantifiers/ce_guided_single_inv_ei.h index 42e0b0820..42e0b0820 100644..100755 --- a/src/theory/quantifiers/ce_guided_single_inv_ei.h +++ b/src/theory/quantifiers/ce_guided_single_inv_ei.h diff --git a/src/theory/quantifiers/ce_guided_single_inv_sol.cpp b/src/theory/quantifiers/ce_guided_single_inv_sol.cpp index 240c2ed12..240c2ed12 100644..100755 --- a/src/theory/quantifiers/ce_guided_single_inv_sol.cpp +++ b/src/theory/quantifiers/ce_guided_single_inv_sol.cpp diff --git a/src/theory/quantifiers/ce_guided_single_inv_sol.h b/src/theory/quantifiers/ce_guided_single_inv_sol.h index cb6f6bc41..cb6f6bc41 100644..100755 --- a/src/theory/quantifiers/ce_guided_single_inv_sol.h +++ b/src/theory/quantifiers/ce_guided_single_inv_sol.h diff --git a/src/theory/quantifiers/ceg_instantiator.cpp b/src/theory/quantifiers/ceg_instantiator.cpp index da488ea98..cd263e90c 100644..100755 --- a/src/theory/quantifiers/ceg_instantiator.cpp +++ b/src/theory/quantifiers/ceg_instantiator.cpp @@ -22,6 +22,9 @@ #include "theory/quantifiers/term_database.h" #include "theory/theory_engine.h" +#include "theory/bv/theory_bv_utils.h" +#include "util/bitvector.h" + //#define MBP_STRICT_ASSERTIONS using namespace std; @@ -466,6 +469,36 @@ bool CegInstantiator::doAddInstantiation( SolvedForm& sf, SolvedForm& ssf, std:: } } } + /* TODO: algebraic reasoning for bitvector instantiation + else if( pvtn.isBitVector() ){ + if( atom.getKind()==BITVECTOR_ULT || atom.getKind()==BITVECTOR_ULE ){ + for( unsigned t=0; t<2; t++ ){ + if( atom[t]==pv ){ + computeProgVars( atom[1-t] ); + if( d_inelig.find( atom[1-t] )==d_inelig.end() ){ + //only ground terms TODO: more + if( d_prog_var[atom[1-t]].empty() ){ + Node veq_c; + Node uval; + if( ( !pol && atom.getKind()==BITVECTOR_ULT ) || ( pol && atom.getKind()==BITVECTOR_ULE ) ){ + uval = atom[1-t]; + }else{ + uval = NodeManager::currentNM()->mkNode( (atom.getKind()==BITVECTOR_ULT)==(t==1) ? BITVECTOR_PLUS : BITVECTOR_SUB, atom[1-t], + bv::utils::mkConst(pvtn.getConst<BitVectorSize>(), 1) ); + } + if( subs_proc[uval].find( veq_c )==subs_proc[uval].end() ){ + subs_proc[uval][veq_c] = true; + if( doAddInstantiationInc( uval, pv, veq_c, 0, sf, ssf, vars, btyp, theta, i, effort, cons, curr_var ) ){ + return true; + } + } + } + } + } + } + } + } + */ } } } @@ -685,7 +718,7 @@ bool CegInstantiator::doAddInstantiation( SolvedForm& sf, SolvedForm& ssf, std:: //[5] resort to using value in model // do so if we are in effort=1, or if the variable is boolean, or if we are solving for a subfield of a datatype - if( ( effort>0 || pvtn.isBoolean() || !curr_var.empty() ) && d_qe->getTermDatabase()->isClosedEnumerableType( pvtn ) ){ + if( ( effort>0 || pvtn.isBoolean() || pvtn.isBitVector() || !curr_var.empty() ) && d_qe->getTermDatabase()->isClosedEnumerableType( pvtn ) ){ Node mv = getModelValue( pv ); Node pv_coeff_m; Trace("cbqi-inst-debug") << "[5] " << i << "...try model value " << mv << std::endl; @@ -781,6 +814,7 @@ bool CegInstantiator::doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int } } if( success ){ + Trace("cbqi-inst-debug2") << "Adding to vectors..." << std::endl; vars.push_back( pv ); btyp.push_back( bt ); sf.push_back( pv, n, pv_coeff ); @@ -800,8 +834,10 @@ bool CegInstantiator::doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int curr_var.pop_back(); is_cv = true; } + Trace("cbqi-inst-debug2") << "Recurse..." << std::endl; success = doAddInstantiation( sf, ssf, vars, btyp, new_theta, curr_var.empty() ? i+1 : i, effort, cons, curr_var ); if( !success ){ + Trace("cbqi-inst-debug2") << "Removing from vectors..." << std::endl; if( is_cv ){ curr_var.push_back( pv ); } @@ -814,6 +850,7 @@ bool CegInstantiator::doAddInstantiationInc( Node n, Node pv, Node pv_coeff, int if( success ){ return true; }else{ + Trace("cbqi-inst-debug2") << "Revert substitutions..." << std::endl; //revert substitution information for( std::map< int, Node >::iterator it = prev_subs.begin(); it != prev_subs.end(); it++ ){ sf.d_subs[it->first] = it->second; @@ -1035,7 +1072,13 @@ Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node if( !it->second.isNull() ){ c_coeff = NodeManager::currentNM()->mkNode( MULT, c_coeff, it->second ); } - Node c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] ); + Assert( !c_coeff.isNull() ); + Node c; + if( msum_term[it->first].isNull() ){ + c = c_coeff; + }else{ + c = NodeManager::currentNM()->mkNode( MULT, c_coeff, msum_term[it->first] ); + } children.push_back( c ); Trace("cegqi-si-apply-subs-debug") << "Add child : " << c << std::endl; } @@ -1594,6 +1637,7 @@ int CegInstantiator::solve_arith( Node pv, Node atom, Node& veq_c, Node& val, No realPart = real_part.empty() ? d_zero : ( real_part.size()==1 ? real_part[0] : NodeManager::currentNM()->mkNode( PLUS, real_part ) ); Assert( d_out->isEligibleForInstantiation( realPart ) ); //re-isolate + Trace("cbqi-inst-debug") << "Re-isolate..." << std::endl; ires = QuantArith::isolate( pv, msum, veq_c, val, atom.getKind() ); Trace("cbqi-inst-debug") << "Isolate for mixed Int/Real : " << veq_c << " * " << pv << " " << atom.getKind() << " " << val << std::endl; Trace("cbqi-inst-debug") << " real part : " << realPart << std::endl; diff --git a/src/theory/quantifiers/ceg_instantiator.h b/src/theory/quantifiers/ceg_instantiator.h index 3d7bbcb55..3d7bbcb55 100644..100755 --- a/src/theory/quantifiers/ceg_instantiator.h +++ b/src/theory/quantifiers/ceg_instantiator.h diff --git a/src/theory/quantifiers/conjecture_generator.cpp b/src/theory/quantifiers/conjecture_generator.cpp index 2cc49ef5a..f4eb67d74 100644..100755 --- a/src/theory/quantifiers/conjecture_generator.cpp +++ b/src/theory/quantifiers/conjecture_generator.cpp @@ -285,7 +285,7 @@ Node ConjectureGenerator::getFreeVar( TypeNode tn, unsigned i ) { } bool ConjectureGenerator::isHandledTerm( TNode n ){ - return !n.getAttribute(NoMatchAttribute()) && inst::Trigger::isAtomicTrigger( n ) && ( n.getKind()!=APPLY_UF || n.getOperator().getKind()!=SKOLEM ); + return d_quantEngine->getTermDatabase()->isTermActive( n ) && inst::Trigger::isAtomicTrigger( n ) && ( n.getKind()!=APPLY_UF || n.getOperator().getKind()!=SKOLEM ); } Node ConjectureGenerator::getGroundEqc( TNode r ) { @@ -425,7 +425,7 @@ void ConjectureGenerator::check( Theory::Effort e, unsigned quant_e ) { eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee ); while( !eqc_i.isFinished() ){ TNode n = (*eqc_i); - if( getTermDatabase()->hasTermCurrent( n ) && !n.getAttribute(NoMatchAttribute()) && ( n.getKind()!=EQUAL || isFalse ) ){ + if( getTermDatabase()->hasTermCurrent( n ) && getTermDatabase()->isTermActive( n ) && ( n.getKind()!=EQUAL || isFalse ) ){ if( firstTime ){ Trace("sg-gen-eqc") << "e" << d_em[r] << " : { " << std::endl; firstTime = false; @@ -1572,7 +1572,6 @@ bool TermGenerator::getNextMatch( TermGenEnv * s, TNode eqc, std::map< TypeNode, if( d_match_status_child_num==0 ){ //initial binding TNode f = s->getTgFunc( d_typ, d_status_num ); - //std::map< TNode, TermArgTrie >::iterator it = s->getTermDatabase()->d_func_map_eqc_trie[f].d_data.find( eqc ); Assert( !eqc.isNull() ); TermArgTrie * tat = s->getTermDatabase()->getTermArgTrie( eqc, f ); if( tat ){ @@ -1726,9 +1725,9 @@ void TermGenEnv::collectSignatureInformation() { d_func_kind.clear(); d_func_args.clear(); TypeNode tnull; - for( std::map< Node, TermArgTrie >::iterator it = getTermDatabase()->d_func_map_trie.begin(); it != getTermDatabase()->d_func_map_trie.end(); ++it ){ - if( getTermDatabase()->getNumGroundTerms( it->first )>0 ){ - Node nn = getTermDatabase()->getGroundTerm( it->first, 0 ); + for( std::map< Node, std::vector< Node > >::iterator it = getTermDatabase()->d_op_map.begin(); it != getTermDatabase()->d_op_map.end(); ++it ){ + if( !it->second.empty() ){ + Node nn = it->second[0]; Trace("sg-rel-sig-debug") << "Check in signature : " << nn << std::endl; if( d_cg->isHandledTerm( nn ) && nn.getKind()!=APPLY_SELECTOR_TOTAL && !nn.getType().isBoolean() ){ bool do_enum = true; @@ -1750,7 +1749,7 @@ void TermGenEnv::collectSignatureInformation() { d_typ_tg_funcs[nn.getType()].push_back( it->first ); d_tg_func_param[it->first] = ( nn.getMetaKind() == kind::metakind::PARAMETERIZED ); Trace("sg-rel-sig") << "Will enumerate function applications of : " << it->first << ", #args = " << d_func_args[it->first].size() << ", kind = " << nn.getKind() << std::endl; - getTermDatabase()->computeUfEqcTerms( it->first ); + //getTermDatabase()->computeUfEqcTerms( it->first ); } } Trace("sg-rel-sig-debug") << "Done check in signature : " << nn << std::endl; diff --git a/src/theory/quantifiers/conjecture_generator.h b/src/theory/quantifiers/conjecture_generator.h index c89d0f2ee..c89d0f2ee 100644..100755 --- a/src/theory/quantifiers/conjecture_generator.h +++ b/src/theory/quantifiers/conjecture_generator.h diff --git a/src/theory/quantifiers/equality_infer.cpp b/src/theory/quantifiers/equality_infer.cpp index c3064116f..5190025ee 100644..100755 --- a/src/theory/quantifiers/equality_infer.cpp +++ b/src/theory/quantifiers/equality_infer.cpp @@ -53,10 +53,10 @@ void EqualityInference::addToExplanation( std::vector< Node >& exp, Node e ) { } void EqualityInference::addToExplanationEqc( std::vector< Node >& exp, Node eqc ) { - NodeListMap::iterator re_i = d_rep_exp.find( eqc ); + NodeIntMap::iterator re_i = d_rep_exp.find( eqc ); if( re_i!=d_rep_exp.end() ){ - for( unsigned i=0; i<(*re_i).second->size(); i++ ){ - addToExplanation( exp, (*(*re_i).second)[i] ); + for( int i=0; i<(*re_i).second; i++ ){ + addToExplanation( exp, d_rep_exp_data[eqc][i] ); } } //for( unsigned i=0; i<d_eqci[n]->d_rep_exp.size(); i++ ){ @@ -65,16 +65,19 @@ void EqualityInference::addToExplanationEqc( std::vector< Node >& exp, Node eqc } void EqualityInference::addToExplanationEqc( Node eqc, std::vector< Node >& exp_to_add ) { - NodeListMap::iterator re_i = d_rep_exp.find( eqc ); - NodeList* re; + NodeIntMap::iterator re_i = d_rep_exp.find( eqc ); + int n_re = 0; if( re_i != d_rep_exp.end() ){ - re = (*re_i).second; - }else{ - re = new(d_c->getCMM()) NodeList( true, d_c, false, context::ContextMemoryAllocator<TNode>(d_c->getCMM()) ); - d_rep_exp.insertDataFromContextMemory( eqc, re ); + n_re = (*re_i).second; } + d_rep_exp[eqc] = n_re + exp_to_add.size(); for( unsigned i=0; i<exp_to_add.size(); i++ ){ - re->push_back( exp_to_add[i] ); + if( n_re<(int)d_rep_exp_data[eqc].size() ){ + d_rep_exp_data[eqc][n_re] = exp_to_add[i]; + }else{ + d_rep_exp_data[eqc].push_back( exp_to_add[i] ); + } + n_re++; } //for( unsigned i=0; i<exp_to_add.size(); i++ ){ // eqci->d_rep_exp.push_back( exp_to_add[i] ); @@ -204,16 +207,18 @@ void EqualityInference::eqNotifyNewClass(TNode t) { void EqualityInference::addToUseList( Node used, Node eqc ) { #if 1 - NodeListMap::iterator ul_i = d_uselist.find( used ); - NodeList* ul; + NodeIntMap::iterator ul_i = d_uselist.find( used ); + int n_ul = 0; if( ul_i != d_uselist.end() ){ - ul = (*ul_i).second; - }else{ - ul = new(d_c->getCMM()) NodeList( true, d_c, false, context::ContextMemoryAllocator<TNode>(d_c->getCMM()) ); - d_uselist.insertDataFromContextMemory( used, ul ); + n_ul = (*ul_i).second; } + d_uselist[ used ] = n_ul + 1; Trace("eq-infer-debug") << " add to use list : " << used << " -> " << eqc << std::endl; - (*ul).push_back( eqc ); + if( n_ul<(int)d_uselist_data[used].size() ){ + d_uselist_data[used][n_ul] = eqc; + }else{ + d_uselist_data[used].push_back( eqc ); + } #else std::map< Node, EqcInfo * >::iterator itu = d_eqci.find( used ); EqcInfo * eqci_used; @@ -356,12 +361,12 @@ void EqualityInference::eqNotifyMerge(TNode t1, TNode t2) { //go through all equivalence classes that may refer to v_solve std::map< Node, bool > processed; processed[v_solve] = true; - NodeListMap::iterator ul_i = d_uselist.find( v_solve ); + NodeIntMap::iterator ul_i = d_uselist.find( v_solve ); if( ul_i != d_uselist.end() ){ - NodeList* ul = (*ul_i).second; - Trace("eq-infer-debug") << " use list size = " << ul->size() << std::endl; - for( unsigned j=0; j<ul->size(); j++ ){ - Node r = (*ul)[j]; + int n_ul = (*ul_i).second; + Trace("eq-infer-debug") << " use list size = " << n_ul << std::endl; + for( int j=0; j<n_ul; j++ ){ + Node r = d_uselist_data[v_solve][j]; //Trace("eq-infer-debug") << " use list size = " << eqci_solved->d_uselist.size() << std::endl; //for( unsigned j=0; j<eqci_solved->d_uselist.size(); j++ ){ // Node r = eqci_solved->d_uselist[j]; diff --git a/src/theory/quantifiers/equality_infer.h b/src/theory/quantifiers/equality_infer.h index 93c7bd080..80d6ef98b 100644..100755 --- a/src/theory/quantifiers/equality_infer.h +++ b/src/theory/quantifiers/equality_infer.h @@ -39,7 +39,7 @@ class EqualityInference typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap; typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap; typedef context::CDChunkList<Node> NodeList; - typedef context::CDHashMap< Node, NodeList *, NodeHashFunction > NodeListMap; + typedef context::CDHashMap< Node, int, NodeHashFunction > NodeIntMap; private: context::Context * d_c; Node d_one; @@ -67,11 +67,13 @@ private: BoolMap d_elim_vars; std::map< Node, EqcInfo * > d_eqci; NodeMap d_rep_to_eqc; - NodeListMap d_rep_exp; + NodeIntMap d_rep_exp; + std::map< Node, std::vector< Node > > d_rep_exp_data; /** set eqc rep */ void setEqcRep( Node t, Node r, std::vector< Node >& exp_to_add, EqcInfo * eqci ); /** use list */ - NodeListMap d_uselist; + NodeIntMap d_uselist; + std::map< Node, std::vector< Node > > d_uselist_data; void addToUseList( Node used, Node eqc ); /** pending merges */ NodeList d_pending_merges; diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp index a833f48d2..670f0eff3 100644..100755 --- a/src/theory/quantifiers/first_order_model.cpp +++ b/src/theory/quantifiers/first_order_model.cpp @@ -406,8 +406,8 @@ Node FirstOrderModelIG::evaluateTerm( Node n, int& depIndex, RepSetIterator* ri //check the type of n if( n.getKind()==INST_CONSTANT ){ int v = n.getAttribute(InstVarNumAttribute()); - depIndex = ri->d_var_order[ v ]; - val = ri->getTerm( v ); + depIndex = ri->getIndexOrder( v ); + val = ri->getCurrentTerm( v ); }else if( n.getKind()==ITE ){ int depIndex1, depIndex2; int eval = evaluate( n[0], depIndex1, ri ); diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h index cbe83cfa5..cbe83cfa5 100644..100755 --- a/src/theory/quantifiers/first_order_model.h +++ b/src/theory/quantifiers/first_order_model.h diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp index 33c853328..a0665cb7f 100644..100755 --- a/src/theory/quantifiers/full_model_check.cpp +++ b/src/theory/quantifiers/full_model_check.cpp @@ -405,7 +405,7 @@ void FullModelChecker::processBuildModel(TheoryModel* m, bool fullModel){ bool needsDefault = true; for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){ Node n = fm->d_uf_terms[op][i]; - if( !n.getAttribute(NoMatchAttribute()) ){ + if( d_qe->getTermDatabase()->isTermActive( n ) ){ add_conds.push_back( n ); add_values.push_back( n ); Node r = fm->getUsedRepresentative(n); @@ -764,7 +764,7 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No Trace("fmc-exh-debug") << "Set element domains..." << std::endl; //set the domains based on the entry for (unsigned i=0; i<c.getNumChildren(); i++) { - if (riter.d_enum_type[i]==RepSetIterator::ENUM_DOMAIN_ELEMENTS) { + if( riter.d_enum_type[i]==RepSetIterator::ENUM_DOMAIN_ELEMENTS || riter.d_enum_type[i]==RepSetIterator::ENUM_SET_MEMBERS ){ TypeNode tn = c[i].getType(); if( d_rep_ids.find(tn)!=d_rep_ids.end() ){ if( fm->isInterval(c[i]) || fm->isStar(c[i]) ){ @@ -773,6 +773,7 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No if (d_rep_ids[tn].find(c[i])!=d_rep_ids[tn].end()) { riter.d_domain[i].clear(); riter.d_domain[i].push_back(d_rep_ids[tn][c[i]]); + riter.d_enum_type[i] = RepSetIterator::ENUM_DOMAIN_ELEMENTS; }else{ Trace("fmc-exh") << "---- Does not have rep : " << c[i] << " for type " << tn << std::endl; return false; @@ -792,7 +793,7 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No std::vector< Node > ev_inst; std::vector< Node > inst; for( int i=0; i<riter.getNumTerms(); i++ ){ - Node rr = riter.getTerm( i ); + Node rr = riter.getCurrentTerm( i ); Node r = rr; //if( r.getType().isSort() ){ r = fm->getUsedRepresentative( r ); @@ -826,18 +827,18 @@ bool FullModelChecker::exhaustiveInstantiate(FirstOrderModelFmc * fm, Node f, No int index = riter.increment(); Trace("fmc-exh-debug") << "Incremented index " << index << std::endl; if( !riter.isFinished() ){ - if (index>=0 && riter.d_index[index]>0 && addedLemmas>0 && riter.d_enum_type[index]==RepSetIterator::ENUM_RANGE) { + if (index>=0 && riter.d_index[index]>0 && addedLemmas>0 && riter.d_enum_type[index]==RepSetIterator::ENUM_INT_RANGE) { Trace("fmc-exh-debug") << "Since this is a range enumeration, skip to the next..." << std::endl; riter.increment2( index-1 ); } } } d_addedLemmas += addedLemmas; - Trace("fmc-exh") << "----Finished Exhaustive instantiate, lemmas = " << addedLemmas << ", incomplete=" << riter.d_incomplete << std::endl; - return addedLemmas>0 || !riter.d_incomplete; + Trace("fmc-exh") << "----Finished Exhaustive instantiate, lemmas = " << addedLemmas << ", incomplete=" << riter.isIncomplete() << std::endl; + return addedLemmas>0 || !riter.isIncomplete(); }else{ Trace("fmc-exh") << "----Finished Exhaustive instantiate, failed." << std::endl; - return false; + return !riter.isIncomplete(); } } diff --git a/src/theory/quantifiers/full_model_check.h b/src/theory/quantifiers/full_model_check.h index 411b7a5eb..411b7a5eb 100644..100755 --- a/src/theory/quantifiers/full_model_check.h +++ b/src/theory/quantifiers/full_model_check.h diff --git a/src/theory/quantifiers/fun_def_engine.cpp b/src/theory/quantifiers/fun_def_engine.cpp index cf1d14663..cf1d14663 100644..100755 --- a/src/theory/quantifiers/fun_def_engine.cpp +++ b/src/theory/quantifiers/fun_def_engine.cpp diff --git a/src/theory/quantifiers/fun_def_engine.h b/src/theory/quantifiers/fun_def_engine.h index 3b95281c0..3b95281c0 100644..100755 --- a/src/theory/quantifiers/fun_def_engine.h +++ b/src/theory/quantifiers/fun_def_engine.h diff --git a/src/theory/quantifiers/fun_def_process.cpp b/src/theory/quantifiers/fun_def_process.cpp index 9109aab8a..9109aab8a 100644..100755 --- a/src/theory/quantifiers/fun_def_process.cpp +++ b/src/theory/quantifiers/fun_def_process.cpp diff --git a/src/theory/quantifiers/fun_def_process.h b/src/theory/quantifiers/fun_def_process.h index 1f6ee6562..1f6ee6562 100644..100755 --- a/src/theory/quantifiers/fun_def_process.h +++ b/src/theory/quantifiers/fun_def_process.h diff --git a/src/theory/quantifiers/inst_match.cpp b/src/theory/quantifiers/inst_match.cpp index 8818175db..8818175db 100644..100755 --- a/src/theory/quantifiers/inst_match.cpp +++ b/src/theory/quantifiers/inst_match.cpp diff --git a/src/theory/quantifiers/inst_match.h b/src/theory/quantifiers/inst_match.h index ad287c1a3..ad287c1a3 100644..100755 --- a/src/theory/quantifiers/inst_match.h +++ b/src/theory/quantifiers/inst_match.h diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp index bf05de3bb..2d3bf76f6 100644..100755 --- a/src/theory/quantifiers/inst_match_generator.cpp +++ b/src/theory/quantifiers/inst_match_generator.cpp @@ -32,6 +32,7 @@ namespace theory { namespace inst { InstMatchGenerator::InstMatchGenerator( Node pat ){ + d_cg = NULL; d_needsReset = true; d_active_add = false; Assert( quantifiers::TermDb::hasInstConstAttr(pat) ); @@ -43,12 +44,20 @@ InstMatchGenerator::InstMatchGenerator( Node pat ){ } InstMatchGenerator::InstMatchGenerator() { + d_cg = NULL; d_needsReset = true; d_active_add = false; d_next = NULL; d_matchPolicy = MATCH_GEN_DEFAULT; } +InstMatchGenerator::~InstMatchGenerator() throw() { + for( unsigned i=0; i<d_children.size(); i++ ){ + delete d_children[i]; + } + delete d_cg; +} + void InstMatchGenerator::setActiveAdd(bool val){ d_active_add = val; if( d_next!=NULL ){ @@ -150,7 +159,7 @@ void InstMatchGenerator::initialize( Node q, QuantifiersEngine* qe, std::vector< d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern ); } }else{ - d_cg = new CandidateGeneratorQueue; + d_cg = new CandidateGeneratorQueue( qe ); Trace("inst-match-gen-warn") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; d_matchPolicy = MATCH_GEN_INTERNAL_ERROR; } @@ -249,7 +258,7 @@ bool InstMatchGenerator::getMatch( Node f, Node t, InstMatch& m, QuantifiersEngi Trace("matching-debug2") << "Reset children..." << std::endl; //now, fit children into match //we will be requesting candidates for matching terms for each child - for( int i=0; i<(int)d_children.size(); i++ ){ + for( unsigned i=0; i<d_children.size(); i++ ){ d_children[i]->reset( t[ d_children_index[i] ], qe ); } Trace("matching-debug2") << "Continue next " << d_next << std::endl; @@ -484,7 +493,7 @@ d_f( q ){ } Debug("smart-multi-trigger") << std::endl; } - for( int i=0; i<(int)pats.size(); i++ ){ + for( unsigned i=0; i<pats.size(); i++ ){ Node n = pats[i]; //make the match generator d_children.push_back( InstMatchGenerator::mkInstMatchGenerator(q, n, qe ) ); @@ -492,7 +501,7 @@ d_f( q ){ std::vector< int > unique_vars; std::map< int, bool > shared_vars; int numSharedVars = 0; - for( int j=0; j<(int)d_var_contains[n].size(); j++ ){ + for( unsigned j=0; j<d_var_contains[n].size(); j++ ){ if( d_var_to_node[ d_var_contains[n][j] ].size()==1 ){ Debug("smart-multi-trigger") << "Var " << d_var_contains[n][j] << " is unique to " << pats[i] << std::endl; unique_vars.push_back( d_var_contains[n][j] ); @@ -503,7 +512,7 @@ d_f( q ){ } //we use the latest shared variables, then unique variables std::vector< int > vars; - int index = i==0 ? (int)(pats.size()-1) : (i-1); + unsigned index = i==0 ? pats.size()-1 : (i-1); while( numSharedVars>0 && index!=i ){ for( std::map< int, bool >::iterator it = shared_vars.begin(); it != shared_vars.end(); ++it ){ if( it->second ){ @@ -519,16 +528,24 @@ d_f( q ){ } vars.insert( vars.end(), unique_vars.begin(), unique_vars.end() ); Debug("smart-multi-trigger") << " Index[" << i << "]: "; - for( int i=0; i<(int)vars.size(); i++ ){ - Debug("smart-multi-trigger") << vars[i] << " "; + for( unsigned j=0; j<vars.size(); j++ ){ + Debug("smart-multi-trigger") << vars[j] << " "; } Debug("smart-multi-trigger") << std::endl; //make ordered inst match trie - InstMatchTrie::ImtIndexOrder* imtio = new InstMatchTrie::ImtIndexOrder; - imtio->d_order.insert( imtio->d_order.begin(), vars.begin(), vars.end() ); - d_children_trie.push_back( InstMatchTrieOrdered( imtio ) ); + d_imtio[i] = new InstMatchTrie::ImtIndexOrder; + d_imtio[i]->d_order.insert( d_imtio[i]->d_order.begin(), vars.begin(), vars.end() ); + d_children_trie.push_back( InstMatchTrieOrdered( d_imtio[i] ) ); } +} +InstMatchGeneratorMulti::~InstMatchGeneratorMulti() throw() { + for( unsigned i=0; i<d_children.size(); i++ ){ + delete d_children[i]; + } + for( std::map< unsigned, InstMatchTrie::ImtIndexOrder* >::iterator it = d_imtio.begin(); it != d_imtio.end(); ++it ){ + delete it->second; + } } /** reset instantiation round (call this whenever equivalence classes have changed) */ @@ -697,7 +714,7 @@ int InstMatchGeneratorMulti::addTerm( Node q, Node t, QuantifiersEngine* qe ){ return addedLemmas; } -InstMatchGeneratorSimple::InstMatchGeneratorSimple( Node q, Node pat ) : d_f( q ), d_match_pattern( pat ) { +InstMatchGeneratorSimple::InstMatchGeneratorSimple( Node q, Node pat, QuantifiersEngine* qe ) : d_f( q ), d_match_pattern( pat ) { if( d_match_pattern.getKind()==NOT ){ d_match_pattern = d_match_pattern[0]; d_pol = false; @@ -720,10 +737,11 @@ InstMatchGeneratorSimple::InstMatchGeneratorSimple( Node q, Node pat ) : d_f( q } d_match_pattern_arg_types.push_back( d_match_pattern[i].getType() ); } + d_op = qe->getTermDatabase()->getMatchOperator( d_match_pattern ); } void InstMatchGeneratorSimple::resetInstantiationRound( QuantifiersEngine* qe ) { - d_op = qe->getTermDatabase()->getMatchOperator( d_match_pattern ); + } int InstMatchGeneratorSimple::addInstantiations( Node q, InstMatch& baseMatch, QuantifiersEngine* qe ){ @@ -751,6 +769,7 @@ int InstMatchGeneratorSimple::addInstantiations( Node q, InstMatch& baseMatch, Q tat = NULL; } } + Debug("simple-trigger-debug") << "Adding instantiations based on " << tat << " from " << d_op << " " << d_eqc << std::endl; if( tat ){ InstMatch m( q ); m.add( baseMatch ); diff --git a/src/theory/quantifiers/inst_match_generator.h b/src/theory/quantifiers/inst_match_generator.h index a1d907001..096774c51 100644..100755 --- a/src/theory/quantifiers/inst_match_generator.h +++ b/src/theory/quantifiers/inst_match_generator.h @@ -91,7 +91,7 @@ public: InstMatchGenerator( Node pat ); InstMatchGenerator(); /** destructor */ - ~InstMatchGenerator() throw() {} + virtual ~InstMatchGenerator() throw(); /** The pattern we are producing matches for. If null, this is a multi trigger that is merging matches from d_children. */ @@ -125,7 +125,7 @@ public: class VarMatchGeneratorBooleanTerm : public InstMatchGenerator { public: VarMatchGeneratorBooleanTerm( Node var, Node comp ); - ~VarMatchGeneratorBooleanTerm() throw() {} + virtual ~VarMatchGeneratorBooleanTerm() throw() {} Node d_comp; bool d_rm_prev; /** reset instantiation round (call this at beginning of instantiation round) */ @@ -142,7 +142,7 @@ public: class VarMatchGeneratorTermSubs : public InstMatchGenerator { public: VarMatchGeneratorTermSubs( Node var, Node subs ); - ~VarMatchGeneratorTermSubs() throw() {} + virtual ~VarMatchGeneratorTermSubs() throw() {} TNode d_var; TypeNode d_var_type; Node d_subs; @@ -183,6 +183,8 @@ private: int d_matchPolicy; /** children generators */ std::vector< InstMatchGenerator* > d_children; + /** order */ + std::map< unsigned, InstMatchTrie::ImtIndexOrder* > d_imtio; /** inst match tries for each child */ std::vector< InstMatchTrieOrdered > d_children_trie; /** calculate matches */ @@ -191,7 +193,7 @@ public: /** constructors */ InstMatchGeneratorMulti( Node q, std::vector< Node >& pats, QuantifiersEngine* qe ); /** destructor */ - ~InstMatchGeneratorMulti() throw() {} + virtual ~InstMatchGeneratorMulti() throw(); /** reset instantiation round (call this whenever equivalence classes have changed) */ void resetInstantiationRound( QuantifiersEngine* qe ); /** reset, eqc is the equivalence class to search in (any if eqc=null) */ @@ -224,7 +226,7 @@ private: void addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat ); public: /** constructors */ - InstMatchGeneratorSimple( Node q, Node pat ); + InstMatchGeneratorSimple( Node q, Node pat, QuantifiersEngine* qe ); /** destructor */ ~InstMatchGeneratorSimple() throw() {} /** reset instantiation round (call this whenever equivalence classes have changed) */ diff --git a/src/theory/quantifiers/inst_propagator.cpp b/src/theory/quantifiers/inst_propagator.cpp index d4be58636..41c9c40c8 100644..100755 --- a/src/theory/quantifiers/inst_propagator.cpp +++ b/src/theory/quantifiers/inst_propagator.cpp @@ -34,6 +34,7 @@ bool EqualityQueryInstProp::reset( Theory::Effort e ) { d_uf.clear(); d_uf_exp.clear(); d_diseq_list.clear(); + d_uf_func_map_trie.clear(); return true; } @@ -103,8 +104,7 @@ TNode EqualityQueryInstProp::getCongruentTerm( Node f, std::vector< TNode >& arg if( !t.isNull() ){ return t; }else{ - //TODO? - return TNode::null(); + return d_uf_func_map_trie[f].existsTerm( args ); } } @@ -118,6 +118,7 @@ Node EqualityQueryInstProp::getRepresentativeExp( Node a, std::vector< Node >& e Node ar = getUfRepresentative( a, exp ); if( !ar.isNull() ){ if( engine_has_a || getEngine()->hasTerm( ar ) ){ + Trace("qip-eq") << "getRepresentativeExp " << a << " returns " << ar << std::endl; Assert( getEngine()->hasTerm( ar ) ); Assert( getEngine()->getRepresentative( ar )==ar ); return ar; @@ -168,6 +169,21 @@ bool EqualityQueryInstProp::areDisequalExp( Node a, Node b, std::vector< Node >& } } +TNode EqualityQueryInstProp::getCongruentTermExp( Node f, std::vector< TNode >& args, std::vector< Node >& exp ) { + TNode t = d_qe->getTermDatabase()->getCongruentTerm( f, args ); + if( !t.isNull() ){ + return t; + }else{ + TNode tt = d_uf_func_map_trie[f].existsTerm( args ); + if( !tt.isNull() ){ + //TODO? + return tt; + }else{ + return tt; + } + } +} + Node EqualityQueryInstProp::getUfRepresentative( Node a, std::vector< Node >& exp ) { Assert( exp.empty() ); std::map< Node, Node >::iterator it = d_uf.find( a ); @@ -252,7 +268,7 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No } } } - + if( swap ){ //swap Node temp_r = ar; @@ -262,7 +278,7 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No Assert( !getEngine()->hasTerm( ar ) || getEngine()->hasTerm( br ) ); Assert( ar!=br ); - + std::vector< Node > exp_d; if( areDisequalExp( ar, br, exp_d ) ){ if( pol ){ @@ -279,18 +295,20 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No Assert( d_uf_exp[ar].empty() ); Assert( d_uf_exp[br].empty() ); + //registerUfTerm( ar ); d_uf[ar] = br; merge_exp( d_uf_exp[ar], exp_a ); merge_exp( d_uf_exp[ar], exp_b ); merge_exp( d_uf_exp[ar], reason ); + //registerUfTerm( br ); d_uf[br] = br; d_uf_exp[br].clear(); Trace("qip-eq") << "EqualityQueryInstProp::setEqual : merge " << ar << " -> " << br << ", exp size = " << d_uf_exp[ar].size() << ", status = " << status << std::endl; a = ar; b = br; - + //carry disequality list std::map< Node, std::map< Node, std::vector< Node > > >::iterator itd = d_diseq_list.find( ar ); if( itd!=d_diseq_list.end() ){ @@ -302,13 +320,13 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No } } } - + return status; }else{ Trace("qip-eq") << "EqualityQueryInstProp::setEqual : disequal " << ar << " <> " << br << std::endl; Assert( d_diseq_list[ar].find( br )==d_diseq_list[ar].end() ); Assert( d_diseq_list[br].find( ar )==d_diseq_list[br].end() ); - + merge_exp( d_diseq_list[ar][br], reason ); merge_exp( d_diseq_list[br][ar], reason ); return STATUS_NONE; @@ -316,187 +334,234 @@ int EqualityQueryInstProp::setEqual( Node& a, Node& b, bool pol, std::vector< No } } -void EqualityQueryInstProp::addArgument( std::vector< Node >& args, std::vector< Node >& props, Node n, bool is_prop, bool pol ) { - if( is_prop ){ - if( isLiteral( n ) ){ - props.push_back( pol ? n : n.negate() ); - return; +void EqualityQueryInstProp::registerUfTerm( TNode n ) { + if( d_uf.find( n )==d_uf.end() ){ + if( !getEngine()->hasTerm( n ) ){ + TNode f = d_qe->getTermDatabase()->getMatchOperator( n ); + if( !f.isNull() ){ + std::vector< TNode > args; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( !getEngine()->hasTerm( n[i] ) ){ + return; + }else{ + args.push_back( n[i] ); + } + } + d_uf_func_map_trie[f].addTerm( n, args ); + } } } +} + +//void EqualityQueryInstProp::addArgument( std::vector< Node >& args, std::vector< Node >& props, Node n, bool is_prop, bool pol ) { +void EqualityQueryInstProp::addArgument( Node n, std::vector< Node >& args, std::vector< Node >& watch, bool is_watch ) { + if( is_watch ){ + watch.push_back( n ); + } args.push_back( n ); } -bool EqualityQueryInstProp::isLiteral( Node n ) { - Kind ak = n.getKind()==NOT ? n[0].getKind() : n.getKind(); - Assert( ak!=NOT ); - return ak!=AND && ak!=OR && ak!=IFF && ak!=ITE; +bool EqualityQueryInstProp::isPropagateLiteral( Node n ) { + if( n==d_true || n==d_false ){ + return false; + }else{ + Kind ak = n.getKind()==NOT ? n[0].getKind() : n.getKind(); + Assert( ak!=NOT ); + return ak!=AND && ak!=OR && ak!=IFF && ak!=ITE; + } +} + +void EqualityQueryInstProp::setWatchList( Node n, std::vector< Node >& watch, std::map< Node, std::vector< Node > >& watch_list_out ) { + if( watch.empty() ){ + watch.push_back( n ); + } + for( unsigned j=0; j<watch.size(); j++ ){ + Trace("qip-eval") << "Watch : " << n << " -> " << watch[j] << std::endl; + watch_list_out[n].push_back( watch[j] ); + } +} + +void EqualityQueryInstProp::collectWatchList( Node n, std::map< Node, std::vector< Node > >& watch_list_out, std::vector< Node >& watch_list ) { + std::map< Node, std::vector< Node > >::iterator it = watch_list_out.find( n ); + if( it!=watch_list_out.end() && std::find( watch_list.begin(), watch_list.end(), n )==watch_list.end() ){ + watch_list.push_back( n ); + for( unsigned j=0; j<it->second.size(); j++ ){ + collectWatchList( it->second[j], watch_list_out, watch_list ); + } + } } -//this is identical to TermDb::evaluateTerm2, but tracks more information -Node EqualityQueryInstProp::evaluateTermExp( Node n, std::vector< Node >& exp, std::map< Node, Node >& visited, bool hasPol, bool pol, - std::map< Node, bool >& watch_list_out, std::vector< Node >& props ) { - std::map< Node, Node >::iterator itv = visited.find( n ); - if( itv != visited.end() ){ +//this is similar to TermDb::evaluateTerm2, but tracks more information +Node EqualityQueryInstProp::evaluateTermExp( Node n, std::vector< Node >& exp, std::map< int, std::map< Node, Node > >& visited, + bool hasPol, bool pol, std::map< Node, std::vector< Node > >& watch_list_out, std::vector< Node >& props ) { + int polIndex = hasPol ? ( pol ? 1 : -1 ) : 0; + std::map< Node, Node >::iterator itv = visited[polIndex].find( n ); + if( itv!=visited[polIndex].end() ){ return itv->second; }else{ - visited[n] = n; - Trace("qip-eval") << "evaluate term : " << n << std::endl; - std::vector< Node > exp_n; - Node ret = getRepresentativeExp( n, exp_n ); - if( ret.isNull() ){ - //term is not known to be equal to a representative in equality engine, evaluate it - Kind k = n.getKind(); - if( k==FORALL ){ - ret = Node::null(); - }else{ - std::map< Node, bool > watch_list_out_curr; - TNode f = d_qe->getTermDatabase()->getMatchOperator( n ); - std::vector< Node > args; - bool ret_set = false; - bool childChanged = false; - int abort_i = -1; - //get the child entailed polarity - Assert( n.getKind()!=IMPLIES ); - bool newHasPol, newPol; - QuantPhaseReq::getEntailPolarity( n, 0, hasPol, pol, newHasPol, newPol ); - //for each child - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - Node c = evaluateTermExp( n[i], exp, visited, newHasPol, newPol, watch_list_out_curr, props ); - if( c.isNull() ){ - ret = Node::null(); - ret_set = true; - break; - }else if( c==d_true || c==d_false ){ - //short-circuiting - if( k==kind::AND || k==kind::OR ){ - if( (k==kind::AND)==(c==d_false) ){ - ret = c; - ret_set = true; - break; - }else{ - //redundant - c = Node::null(); - childChanged = true; - } - }else if( k==kind::ITE && i==0 ){ - Assert( watch_list_out_curr.empty() ); - ret = evaluateTermExp( n[ c==d_true ? 1 : 2], exp, visited, hasPol, pol, watch_list_out_curr, props ); - ret_set = true; - break; - }else if( k==kind::NOT ){ - ret = c==d_true ? d_false : d_true; + visited[polIndex][n] = n; + Node ret; + //check if it should be propagated in this context + if( hasPol && isPropagateLiteral( n ) ){ + Assert( n.getType().isBoolean() ); + //must be Boolean + ret = evaluateTermExp( n, exp, visited, false, pol, watch_list_out, props ); + if( isPropagateLiteral( ret ) ){ + Trace("qip-eval") << "-----> propagate : " << ret << std::endl; + props.push_back( pol ? ret : ret.negate() ); + ret = pol ? d_true : d_false; + } + }else{ + Trace("qip-eval") << "evaluate term : " << n << " [" << polIndex << "]" << std::endl; + std::vector< Node > exp_n; + ret = getRepresentativeExp( n, exp_n ); + if( ret.isNull() ){ + //term is not known to be equal to a representative in equality engine, evaluate it + Kind k = n.getKind(); + if( k!=FORALL ){ + TNode f = d_qe->getTermDatabase()->getMatchOperator( n ); + std::vector< Node > args; + bool ret_set = false; + bool childChanged = false; + int abort_i = -1; + //get the child entailed polarity + Assert( n.getKind()!=IMPLIES ); + bool newHasPol, newPol; + QuantPhaseReq::getEntailPolarity( n, 0, hasPol, pol, newHasPol, newPol ); + std::vector< Node > watch; + //for each child + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + Node c = evaluateTermExp( n[i], exp, visited, newHasPol, newPol, watch_list_out, props ); + if( c.isNull() ){ + ret = Node::null(); ret_set = true; break; - } - } - if( !c.isNull() ){ - childChanged = childChanged || n[i]!=c; - if( !f.isNull() && !watch_list_out_curr.empty() ){ - // we are done if this is an UF application and an argument is unevaluated - args.push_back( c ); - abort_i = i; - break; - }else if( ( k==kind::AND || k==kind::OR ) ){ - if( c.getKind()==k ){ - //flatten - for( unsigned j=0; j<c.getNumChildren(); j++ ){ - addArgument( args, props, c[j], newHasPol, newPol ); + }else if( c==d_true || c==d_false ){ + //short-circuiting + if( k==kind::AND || k==kind::OR ){ + if( (k==kind::AND)==(c==d_false) ){ + ret = c; + ret_set = true; + break; + }else{ + //redundant + c = Node::null(); + childChanged = true; } - }else{ - addArgument( args, props, c, newHasPol, newPol ); + }else if( k==kind::ITE && i==0 ){ + ret = evaluateTermExp( n[ c==d_true ? 1 : 2], exp, visited, hasPol, pol, watch_list_out, props ); + ret_set = true; + break; + }else if( k==kind::NOT ){ + ret = c==d_true ? d_false : d_true; + ret_set = true; + break; } - //if we are in a branching position - if( hasPol && !newHasPol && args.size()>=2 ){ - //we are done if at least two args are unevaluated + } + if( !c.isNull() ){ + childChanged = childChanged || n[i]!=c; + bool is_watch = watch_list_out.find( c )!=watch_list_out.end(); + if( !f.isNull() && is_watch ){ + // we are done if this is an UF application and an argument is unevaluated + addArgument( c, args, watch, is_watch ); abort_i = i; break; + }else if( k==kind::AND || k==kind::OR || k==kind::ITE || k==IFF ){ + Trace("qip-eval-debug") << "Adding argument " << c << " to " << k << ", isProp = " << newHasPol << std::endl; + if( ( k==kind::AND || k==kind::OR ) && c.getKind()==k ){ + //flatten + for( unsigned j=0; j<c.getNumChildren(); j++ ){ + addArgument( c[j], args, watch, is_watch ); + } + }else{ + addArgument( c, args, watch, is_watch ); + } + Trace("qip-eval-debug") << "props/args = " << props.size() << "/" << args.size() << std::endl; + //if we are in a branching position + if( hasPol && !newHasPol && args.size()>=2 ){ + //we are done if at least two args are unevaluated + abort_i = i; + break; + } + }else{ + addArgument( c, args, watch, is_watch ); } - }else if( k==kind::ITE ){ - //we are done if we are ITE and condition is unevaluated - Assert( i==0 ); - args.push_back( c ); - abort_i = i; - break; - }else{ - args.push_back( c ); } } - } - //add remaining children if we aborted - if( abort_i!=-1 ){ - for( int i=(abort_i+1); i<(int)n.getNumChildren(); i++ ){ - args.push_back( n[i] ); - } - } - //copy over the watch list - for( std::map< Node, bool >::iterator itc = watch_list_out_curr.begin(); itc != watch_list_out_curr.end(); ++itc ){ - watch_list_out[itc->first] = itc->second; - } - - //if we have not short-circuited evaluation - if( !ret_set ){ - //if it is an indexed term, return the congruent term - if( !f.isNull() && watch_list_out.empty() ){ - std::vector< TNode > t_args; - for( unsigned i=0; i<args.size(); i++ ) { - t_args.push_back( args[i] ); - } - Assert( args.size()==n.getNumChildren() ); - //args contains terms known by the equality engine - TNode nn = getCongruentTerm( f, t_args ); - Trace("qip-eval") << " got congruent term " << nn << " from DB for " << n << std::endl; - if( !nn.isNull() ){ - //successfully constructed representative in EE - Assert( exp_n.empty() ); - ret = getRepresentativeExp( nn, exp_n ); - Trace("qip-eval") << "return rep, exp size = " << exp_n.size() << std::endl; - merge_exp( exp, exp_n ); - ret_set = true; - Assert( !ret.isNull() ); + //add remaining children if we aborted + if( abort_i!=-1 ){ + Trace("qip-eval-debug") << "..." << n << " aborted at " << abort_i << std::endl; + for( int i=(abort_i+1); i<(int)n.getNumChildren(); i++ ){ + args.push_back( n[i] ); } } + //if we have not short-circuited evaluation if( !ret_set ){ - if( childChanged ){ - Trace("qip-eval") << "return rewrite" << std::endl; - if( ( k==kind::AND || k==kind::OR ) ){ - if( args.empty() ){ - ret = k==kind::AND ? d_true : d_false; - ret_set = true; - }else if( args.size()==1 ){ - ret = args[0]; - ret_set = true; - } + //if it is an indexed term, return the congruent term + if( !f.isNull() && watch.empty() ){ + std::vector< TNode > t_args; + for( unsigned i=0; i<args.size(); i++ ) { + Trace("qip-eval") << "arg " << i << " : " << args[i] << std::endl; + t_args.push_back( args[i] ); + } + Assert( args.size()==n.getNumChildren() ); + //args contains terms known by the equality engine + TNode nn = getCongruentTerm( f, t_args ); + Trace("qip-eval") << " got congruent term " << nn << " for " << n << std::endl; + if( !nn.isNull() ){ + //successfully constructed representative in EE + Assert( exp_n.empty() ); + ret = getRepresentativeExp( nn, exp_n ); + Trace("qip-eval") << "return rep, exp size = " << exp_n.size() << std::endl; + merge_exp( exp, exp_n ); + ret_set = true; + Assert( !ret.isNull() ); + Assert( ret!=n ); + // we have that n == ret, check if the union find should be updated TODO? }else{ - Assert( args.size()==n.getNumChildren() ); + watch.push_back( ret ); } - if( !ret_set ){ - if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){ - args.insert( args.begin(), n.getOperator() ); + } + if( !ret_set ){ + if( childChanged || args.size()!=n.getNumChildren() ){ + Trace("qip-eval") << "return rewrite" << std::endl; + if( k==kind::AND || k==kind::OR ){ + if( args.empty() ){ + ret = k==kind::AND ? d_true : d_false; + ret_set = true; + }else if( args.size()==1 ){ + //need to re-evaluate (may be new propagations) + ret = evaluateTermExp( args[0], exp, visited, hasPol, pol, watch_list_out, props ); + ret_set = true; + } + }else{ + Assert( args.size()==n.getNumChildren() ); } - ret = NodeManager::currentNM()->mkNode( k, args ); - ret = Rewriter::rewrite( ret ); - //re-evaluate - Node ret_eval = getRepresentativeExp( ret, exp_n ); - if( !ret_eval.isNull() ){ - ret = ret_eval; - watch_list_out.clear(); - }else{ - watch_list_out[ret] = true; + if( !ret_set ){ + if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){ + args.insert( args.begin(), n.getOperator() ); + } + ret = NodeManager::currentNM()->mkNode( k, args ); + setWatchList( ret, watch, watch_list_out ); + ret = Rewriter::rewrite( ret ); + //need to re-evaluate + ret = evaluateTermExp( ret, exp, visited, hasPol, pol, watch_list_out, props ); } + }else{ + ret = n; + setWatchList( ret, watch, watch_list_out ); } - }else{ - ret = n; - watch_list_out[ret] = true; } } } + }else{ + Trace("qip-eval") << "...exists in ee, return rep, exp size = " << exp_n.size() << std::endl; + merge_exp( exp, exp_n ); } - }else{ - Trace("qip-eval") << "...exists in ee, return rep, exp size = " << exp_n.size() << std::endl; - merge_exp( exp, exp_n ); } - Trace("qip-eval") << "evaluated term : " << n << ", got : " << ret << ", exp size = " << exp.size() << std::endl; - visited[n] = ret; + + Trace("qip-eval") << "evaluated term : " << n << " [" << polIndex << "], got : " << ret << ", exp size = " << exp.size() << ", watch list size = " << watch_list_out.size() << std::endl; + visited[polIndex][n] = ret; return ret; } } @@ -545,6 +610,7 @@ bool InstPropagator::reset( Theory::Effort e ) { d_watch_list.clear(); d_update_list.clear(); d_relevant_inst.clear(); + d_has_relevant_inst = false; return d_qy.reset( e ); } @@ -556,10 +622,7 @@ bool InstPropagator::notifyInstantiation( unsigned quant_e, Node q, Node lem, st Trace("qip-prop") << " " << terms[i] << std::endl; } } - unsigned id = d_icount; - d_icount++; - Trace("qip-prop") << "...assign id=" << id << std::endl; - d_ii[id].init( q, lem, terms, body ); + unsigned id = allocateInstantiation( q, lem, terms, body ); //initialize the information if( cacheConclusion( id, body ) ){ Assert( d_update_list.empty() ); @@ -582,35 +645,67 @@ bool InstPropagator::notifyInstantiation( unsigned quant_e, Node q, Node lem, st return !d_conflict; }else{ Assert( false ); - return true; + return false; + } +} + +void InstPropagator::filterInstantiations() { + if( d_has_relevant_inst ){ + //now, inform quantifiers engine which instances should be retracted + Trace("qip-prop-debug") << "...remove instantiation ids : "; + for( std::map< unsigned, InstInfo >::iterator it = d_ii.begin(); it != d_ii.end(); ++it ){ + if( !it->second.d_q.isNull() ){ + if( d_relevant_inst.find( it->first )==d_relevant_inst.end() ){ + if( !d_qe->removeInstantiation( it->second.d_q, it->second.d_lem, it->second.d_terms ) ){ + Trace("qip-warn") << "WARNING : did not remove instantiation id " << it->first << std::endl; + Assert( false ); + }else{ + Trace("qip-prop-debug") << it->first << " "; + } + }else{ + //mark the quantified formula as relevant + d_qe->markRelevant( it->second.d_q ); + } + } + } + Trace("qip-prop-debug") << std::endl; + Trace("quant-engine-conflict") << "-----> InstPropagator::" << ( d_conflict ? "conflict" : "propagate" ) << " with " << d_relevant_inst.size() << " instances." << std::endl; } } +unsigned InstPropagator::allocateInstantiation( Node q, Node lem, std::vector< Node >& terms, Node body ) { + unsigned id = d_icount; + d_icount++; + Trace("qip-prop") << "...assign id=" << id << std::endl; + d_ii[id].init( q, lem, terms, body ); + return id; +} + bool InstPropagator::update( unsigned id, InstInfo& ii, bool firstTime ) { Assert( !d_conflict ); Assert( ii.d_active ); Trace("qip-prop-debug") << "Update info [" << id << "]..." << std::endl; //update the evaluation of the current lemma - std::map< Node, Node > visited; - std::map< Node, bool > watch_list; + std::map< Node, std::vector< Node > > watch_list_out; + std::map< int, std::map< Node, Node > > visited; + std::vector< Node > exp; std::vector< Node > props; - Node eval = d_qy.evaluateTermExp( ii.d_curr, ii.d_curr_exp, visited, true, true, watch_list, props ); + Node eval = d_qy.evaluateTermExp( ii.d_curr, exp, visited, true, true, watch_list_out, props ); + EqualityQueryInstProp::merge_exp( ii.d_curr_exp, exp ); if( eval.isNull() ){ ii.d_active = false; }else if( firstTime || eval!=ii.d_curr ){ - if( EqualityQueryInstProp::isLiteral( eval ) ){ - props.push_back( eval ); - eval = d_qy.d_true; - watch_list.clear(); - } + std::vector< Node > watch_list; + d_qy.collectWatchList( eval, watch_list_out, watch_list ); if( Trace.isOn("qip-prop") ){ Trace("qip-prop") << "Update info [" << id << "]..." << std::endl; - Trace("qip-prop") << "...updated lemma " << ii.d_curr << " -> " << eval << ", exp = "; + Trace("qip-prop") << "...updated lemma " << ii.d_curr << " -> " << eval << std::endl; + Trace("qip-prop") << "...explanation = "; debugPrintExplanation( ii.d_curr_exp, "qip-prop" ); Trace("qip-prop") << std::endl; Trace("qip-prop") << "...watch list: " << std::endl; - for( std::map< Node, bool >::iterator itw = watch_list.begin(); itw!=watch_list.end(); ++itw ){ - Trace("qip-prop") << " " << itw->first << std::endl; + for( unsigned i=0; i<watch_list.size(); i++ ){ + Trace("qip-prop") << " " << watch_list[i] << std::endl; } Trace("qip-prop") << "...new propagations: " << std::endl; for( unsigned i=0; i<props.size(); i++ ){ @@ -627,8 +722,13 @@ bool InstPropagator::update( unsigned id, InstInfo& ii, bool firstTime ) { }else{ for( unsigned i=0; i<props.size(); i++ ){ Trace("qip-prop-debug2") << "Process propagation " << props[i] << std::endl; + Assert( d_qy.isPropagateLiteral( props[i] ) ); //if we haven't propagated this literal yet if( cacheConclusion( id, props[i], 1 ) ){ + //watch list for propagated literal: may not yet be purely EE representatives + std::vector< Node > prop_watch_list; + d_qy.collectWatchList( props[i], watch_list_out, prop_watch_list ); + Node lit = props[i].getKind()==NOT ? props[i][0] : props[i]; bool pol = props[i].getKind()!=NOT; if( lit.getKind()==EQUAL ){ @@ -647,10 +747,10 @@ bool InstPropagator::update( unsigned id, InstInfo& ii, bool firstTime ) { ii.d_curr = eval; //update the watch list Trace("qip-prop-debug") << "...updating watch list for [" << id << "], curr is " << ii.d_curr << std::endl; - //Here, we need to be notified of enough terms such that if we are not notified, then update( ii ) will return no propagations. - // Similar to two-watched literals, but since we are in UF, we need to watch all terms on a complete path of two terms. - for( std::map< Node, bool >::iterator itw = watch_list.begin(); itw != watch_list.end(); ++itw ){ - d_watch_list[ itw->first ][ id ] = true; + //Here, we need to be notified of enough terms such that if we are not notified, then update( id, ii ) will return no propagations. + // Similar to two-watched literals, but since we are taking into account UF, we need to watch all terms on a complete path of two terms. + for( unsigned i=0; i<watch_list.size(); i++ ){ + d_watch_list[ watch_list[i] ][ id ] = true; } }else{ Trace("qip-prop-debug") << "...conclusion " << eval << " is duplicate." << std::endl; @@ -682,10 +782,12 @@ void InstPropagator::propagate( Node a, Node b, bool pol, std::vector< Node >& e } if( pol ){ if( status==EqualityQueryInstProp::STATUS_MERGED_KNOWN ){ + Trace("qip-rlv-propagate") << "Relevant propagation : " << a << ( pol ? " == " : " != " ) << b << std::endl; Assert( d_qy.getEngine()->hasTerm( a ) ); Assert( d_qy.getEngine()->hasTerm( b ) ); Trace("qip-prop-debug") << "...equality between known terms." << std::endl; addRelevantInstances( exp, "qip-propagate" ); + //d_has_relevant_inst = true; } Trace("qip-prop-debug") << "...merged representatives " << a << " and " << b << std::endl; for( unsigned i=0; i<2; i++ ){ @@ -712,25 +814,7 @@ void InstPropagator::conflict( std::vector< Node >& exp ) { d_conflict = true; d_relevant_inst.clear(); addRelevantInstances( exp, "qip-propagate" ); - - //now, inform quantifiers engine which instances should be retracted - Trace("qip-prop-debug") << "...remove instantiation ids : "; - for( std::map< unsigned, InstInfo >::iterator it = d_ii.begin(); it != d_ii.end(); ++it ){ - if( d_relevant_inst.find( it->first )==d_relevant_inst.end() ){ - if( !d_qe->removeInstantiation( it->second.d_q, it->second.d_lem, it->second.d_terms ) ){ - Trace("qip-warn") << "WARNING : did not remove instantiation id " << it->first << std::endl; - Assert( false ); - }else{ - Trace("qip-prop-debug") << it->first << " "; - } - }else{ - //mark the quantified formula as relevant - d_qe->markRelevant( it->second.d_q ); - } - } - Trace("qip-prop-debug") << std::endl; - //will interupt the quantifiers engine - Trace("quant-engine-conflict") << "-----> InstPropagator::conflict with " << exp.size() << " instances." << std::endl; + d_has_relevant_inst = true; } bool InstPropagator::cacheConclusion( unsigned id, Node body, int prop_index ) { diff --git a/src/theory/quantifiers/inst_propagator.h b/src/theory/quantifiers/inst_propagator.h index 0c02c7f95..6201cf152 100644..100755 --- a/src/theory/quantifiers/inst_propagator.h +++ b/src/theory/quantifiers/inst_propagator.h @@ -64,9 +64,11 @@ public: bool areEqualExp( Node a, Node b, std::vector< Node >& exp ); /** returns true is a and b are disequal in the current context */ bool areDisequalExp( Node a, Node b, std::vector< Node >& exp ); + /** get congruent term */ + TNode getCongruentTermExp( Node f, std::vector< TNode >& args, std::vector< Node >& exp ); private: /** term index */ - std::map< Node, TermArgTrie > d_func_map_trie; + std::map< Node, TermArgTrie > d_uf_func_map_trie; /** union find for terms beyond what is stored in equality engine */ std::map< Node, Node > d_uf; std::map< Node, std::vector< Node > > d_uf_exp; @@ -74,7 +76,9 @@ private: /** disequality list, stores explanations */ std::map< Node, std::map< Node, std::vector< Node > > > d_diseq_list; /** add arg */ - void addArgument( std::vector< Node >& args, std::vector< Node >& props, Node n, bool is_prop, bool pol ); + void addArgument( Node n, std::vector< Node >& args, std::vector< Node >& watch, bool is_watch ); + /** register term */ + void registerUfTerm( TNode n ); public: enum { STATUS_CONFLICT, @@ -89,10 +93,13 @@ public: public: //for explanations static void merge_exp( std::vector< Node >& v, std::vector< Node >& v_to_merge, int up_to_size = -1 ); + //for watch list + static void setWatchList( Node n, std::vector< Node >& watch, std::map< Node, std::vector< Node > >& watch_list_out ); + static void collectWatchList( Node n, std::map< Node, std::vector< Node > >& watch_list_out, std::vector< Node >& watch_list ); - Node evaluateTermExp( Node n, std::vector< Node >& exp, std::map< Node, Node >& visited, bool hasPol, bool pol, - std::map< Node, bool >& watch_list_out, std::vector< Node >& props ); - static bool isLiteral( Node n ); + Node evaluateTermExp( Node n, std::vector< Node >& exp, std::map< int, std::map< Node, Node > >& visited, + bool hasPol, bool pol, std::map< Node, std::vector< Node > >& watch_list_out, std::vector< Node >& props ); + bool isPropagateLiteral( Node n ); }; class InstPropagator : public QuantifiersUtil { @@ -104,13 +111,18 @@ private: InstPropagator& d_ip; public: InstantiationNotifyInstPropagator(InstPropagator& ip): d_ip(ip) {} - virtual bool notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ) { - return d_ip.notifyInstantiation( quant_e, q, lem, terms, body ); + virtual bool notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ) { + return d_ip.notifyInstantiation( quant_e, q, lem, terms, body ); } + virtual void filterInstantiations() { d_ip.filterInstantiations(); } }; InstantiationNotifyInstPropagator d_notify; /** notify instantiation method */ bool notifyInstantiation( unsigned quant_e, Node q, Node lem, std::vector< Node >& terms, Node body ); + /** remove instance ids */ + void filterInstantiations(); + /** allocate instantiation */ + unsigned allocateInstantiation( Node q, Node lem, std::vector< Node >& terms, Node body ); /** equality query */ EqualityQueryInstProp d_qy; class InstInfo { @@ -137,13 +149,13 @@ private: std::vector< unsigned > d_update_list; /** relevant instances */ std::map< unsigned, bool > d_relevant_inst; + bool d_has_relevant_inst; private: bool update( unsigned id, InstInfo& i, bool firstTime = false ); void propagate( Node a, Node b, bool pol, std::vector< Node >& exp ); void conflict( std::vector< Node >& exp ); bool cacheConclusion( unsigned id, Node body, int prop_index = 0 ); void addRelevantInstances( std::vector< Node >& exp, const char * c ); - void debugPrintExplanation( std::vector< Node >& exp, const char * c ); public: InstPropagator( QuantifiersEngine* qe ); diff --git a/src/theory/quantifiers/inst_strategy_cbqi.cpp b/src/theory/quantifiers/inst_strategy_cbqi.cpp index 149330c61..523d868b5 100644..100755 --- a/src/theory/quantifiers/inst_strategy_cbqi.cpp +++ b/src/theory/quantifiers/inst_strategy_cbqi.cpp @@ -190,7 +190,7 @@ bool InstStrategyCbqi::hasNonCbqiOperator( Node n, std::map< Node, bool >& visit bool InstStrategyCbqi::hasNonCbqiVariable( Node q ){ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ TypeNode tn = q[0][i].getType(); - if( !tn.isInteger() && !tn.isReal() && !tn.isBoolean() ){ + if( !tn.isInteger() && !tn.isReal() && !tn.isBoolean() && !tn.isBitVector() ){ if( options::cbqiSplx() ){ return true; }else{ @@ -242,7 +242,7 @@ Node InstStrategyCbqi::getNextDecisionRequest(){ Node cel = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( q ); bool value; if( !d_quantEngine->getValuation().hasSatValue( cel, value ) ){ - Trace("cbqi-debug2") << "CBQI: get next decision " << cel << std::endl; + Trace("cbqi-dec") << "CBQI: get next decision " << cel << std::endl; return cel; } } @@ -692,8 +692,10 @@ CegInstantiator * InstStrategyCegqi::getInstantiator( Node q ) { void InstStrategyCegqi::registerQuantifier( Node q ) { if( options::cbqiPreRegInst() ){ - //just get the instantiator - getInstantiator( q ); + if( doCbqi( q ) ){ + //just get the instantiator + getInstantiator( q ); + } } } diff --git a/src/theory/quantifiers/inst_strategy_cbqi.h b/src/theory/quantifiers/inst_strategy_cbqi.h index 8ed59778b..8ed59778b 100644..100755 --- a/src/theory/quantifiers/inst_strategy_cbqi.h +++ b/src/theory/quantifiers/inst_strategy_cbqi.h diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp index 630880690..efd765c86 100644..100755 --- a/src/theory/quantifiers/inst_strategy_e_matching.cpp +++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp @@ -34,9 +34,10 @@ using namespace CVC4::theory::quantifiers; struct sortQuantifiersForSymbol { QuantifiersEngine* d_qe; + std::map< Node, Node > d_op_map; bool operator() (Node i, Node j) { - int nqfsi = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( i.getOperator() ); - int nqfsj = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( j.getOperator() ); + int nqfsi = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_op_map[i] ); + int nqfsj = d_qe->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_op_map[j] ); if( nqfsi<nqfsj ){ return true; }else if( nqfsi>nqfsj ){ @@ -83,9 +84,8 @@ int InstStrategyUserPatterns::process( Node f, Theory::Effort effort, int e ){ Trace("inst-alg") << "-> User-provided instantiate " << f << "..." << std::endl; if( d_quantEngine->getInstUserPatMode()==USER_PAT_MODE_RESORT ){ - int matchOption = 0; for( unsigned i=0; i<d_user_gen_wait[f].size(); i++ ){ - Trigger * t = Trigger::mkTrigger( d_quantEngine, f, d_user_gen_wait[f][i], matchOption, true, Trigger::TR_RETURN_NULL ); + Trigger * t = Trigger::mkTrigger( d_quantEngine, f, d_user_gen_wait[f][i], true, Trigger::TR_RETURN_NULL ); if( t ){ d_user_gen[f].push_back( t ); } @@ -134,11 +134,10 @@ void InstStrategyUserPatterns::addUserPattern( Node q, Node pat ){ if( usable ){ Trace("user-pat") << "Add user pattern: " << pat << " for " << q << std::endl; //check match option - int matchOption = 0; if( d_quantEngine->getInstUserPatMode()==USER_PAT_MODE_RESORT ){ d_user_gen_wait[q].push_back( nodes ); }else{ - Trigger * t = Trigger::mkTrigger( d_quantEngine, q, nodes, matchOption, true, Trigger::TR_MAKE_NEW ); + Trigger * t = Trigger::mkTrigger( d_quantEngine, q, nodes, true, Trigger::TR_MAKE_NEW ); if( t ){ d_user_gen[q].push_back( t ); }else{ @@ -279,8 +278,8 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ Trace("auto-gen-trigger-debug") << "Collected pat terms for " << bd << ", no-patterns : " << d_user_no_gen[f].size() << std::endl; for( unsigned i=0; i<patTermsF.size(); i++ ){ Assert( tinfo.find( patTermsF[i] )!=tinfo.end() ); - Trace("auto-gen-trigger-debug") << " " << patTermsF[i]; - Trace("auto-gen-trigger-debug") << " info[" << tinfo[patTermsF[i]].d_reqPol << ", " << tinfo[patTermsF[i]].d_reqPolEq << ", " << tinfo[patTermsF[i]].d_fv.size() << "]" << std::endl; + Trace("auto-gen-trigger-debug") << " " << patTermsF[i] << std::endl; + Trace("auto-gen-trigger-debug2") << " info = [" << tinfo[patTermsF[i]].d_reqPol << ", " << tinfo[patTermsF[i]].d_reqPolEq << ", " << tinfo[patTermsF[i]].d_fv.size() << "]" << std::endl; } Trace("auto-gen-trigger-debug") << std::endl; } @@ -306,10 +305,28 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ last_weight = curr_w; } } + d_num_trigger_vars[f] = vcMap.size(); + if( d_num_trigger_vars[f]>0 && d_num_trigger_vars[f]<f[0].getNumChildren() ){ + Trace("auto-gen-trigger-partial") << "Quantified formula : " << f << std::endl; + Trace("auto-gen-trigger-partial") << "...does not contain all variables in triggers!!!" << std::endl; + if( options::partialTriggers() ){ + std::vector< Node > vcs[2]; + for( unsigned i=0; i<f[0].getNumChildren(); i++ ){ + Node ic = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ); + vcs[ vcMap.find( ic )==vcMap.end() ? 0 : 1 ].push_back( f[0][i] ); + } + for( unsigned i=0; i<2; i++ ){ + d_vc_partition[i][f] = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, vcs[i] ); + } + }else{ + return; + } + } for( unsigned i=0; i<patTermsF.size(); i++ ){ Node pat = patTermsF[i]; if( rmPatTermsF.find( pat )==rmPatTermsF.end() ){ Trace("auto-gen-trigger-debug") << "...processing pattern " << pat << std::endl; + Node mpat = pat; //process the pattern: if it has a required polarity, consider it Assert( tinfo.find( pat )!=tinfo.end() ); int rpol = tinfo[pat].d_reqPol; @@ -317,19 +334,30 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ unsigned num_fv = tinfo[pat].d_fv.size(); Trace("auto-gen-trigger-debug") << "...required polarity for " << pat << " is " << rpol << ", eq=" << rpoleq << std::endl; if( rpol!=0 ){ + Assert( rpol==1 || rpol==-1 ); if( Trigger::isRelationalTrigger( pat ) ){ pat = rpol==-1 ? pat.negate() : pat; }else{ Assert( Trigger::isAtomicTrigger( pat ) ); if( pat.getType().isBoolean() && rpoleq.isNull() ){ - pat = NodeManager::currentNM()->mkNode( IFF, pat, NodeManager::currentNM()->mkConst( rpol==-1 ) ).negate(); + if( options::literalMatchMode()==LITERAL_MATCH_USE ){ + pat = NodeManager::currentNM()->mkNode( IFF, pat, NodeManager::currentNM()->mkConst( rpol==-1 ) ).negate(); + }else if( options::literalMatchMode()!=LITERAL_MATCH_NONE ){ + pat = NodeManager::currentNM()->mkNode( IFF, pat, NodeManager::currentNM()->mkConst( rpol==1 ) ); + } }else{ Assert( !rpoleq.isNull() ); if( rpol==-1 ){ - //all equivalence classes except rpoleq - pat = NodeManager::currentNM()->mkNode( EQUAL, pat, rpoleq ).negate(); + if( options::literalMatchMode()!=LITERAL_MATCH_NONE ){ + //all equivalence classes except rpoleq + pat = NodeManager::currentNM()->mkNode( EQUAL, pat, rpoleq ).negate(); + } }else if( rpol==1 ){ - //all equivalence classes that are not disequal to rpoleq TODO + if( options::literalMatchMode()==LITERAL_MATCH_AGG ){ + //only equivalence class rpoleq + pat = NodeManager::currentNM()->mkNode( EQUAL, pat, rpoleq ); + } + //all equivalence classes that are not disequal to rpoleq TODO? } } } @@ -337,10 +365,10 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ }else{ if( Trigger::isRelationalTrigger( pat ) ){ //consider both polarities - addPatternToPool( f, pat.negate(), num_fv ); + addPatternToPool( f, pat.negate(), num_fv, mpat ); } } - addPatternToPool( f, pat, num_fv ); + addPatternToPool( f, pat, num_fv, mpat ); } } //tinfo not used below this point @@ -372,19 +400,23 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ if( options::relevantTriggers() ){ sortQuantifiersForSymbol sqfs; sqfs.d_qe = d_quantEngine; + for( unsigned i=0; i<patTerms.size(); i++ ){ + Assert( d_pat_to_mpat.find( patTerms[i] )!=d_pat_to_mpat.end() ); + Assert( d_pat_to_mpat[patTerms[i]].hasOperator() ); + sqfs.d_op_map[ patTerms[i] ] = d_pat_to_mpat[patTerms[i]].getOperator(); + } //sort based on # occurrences (this will cause Trigger to select rarer symbols) std::sort( patTerms.begin(), patTerms.end(), sqfs ); Debug("relevant-trigger") << "Terms based on relevance: " << std::endl; for( unsigned i=0; i<patTerms.size(); i++ ){ - Debug("relevant-trigger") << " " << patTerms[i] << " ("; - Debug("relevant-trigger") << d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[i].getOperator() ) << ")" << std::endl; + Debug("relevant-trigger") << " " << patTerms[i] << " from " << d_pat_to_mpat[patTerms[i]] << " ("; + Debug("relevant-trigger") << d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( d_pat_to_mpat[patTerms[i]].getOperator() ) << ")" << std::endl; } } //now, generate the trigger... - int matchOption = 0; Trigger* tr = NULL; if( d_is_single_trigger[ patTerms[0] ] ){ - tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], matchOption, false, Trigger::TR_RETURN_NULL ); + tr = Trigger::mkTrigger( d_quantEngine, f, patTerms[0], false, Trigger::TR_RETURN_NULL, d_num_trigger_vars[f] ); d_single_trigger_gen[ patTerms[0] ] = true; }else{ //only generate multi trigger if option set, or if no single triggers exist @@ -402,29 +434,14 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ d_made_multi_trigger[f] = true; } //will possibly want to get an old trigger - tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, false, Trigger::TR_GET_OLD ); + tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, false, Trigger::TR_GET_OLD, d_num_trigger_vars[f] ); } if( tr ){ - unsigned tindex; - if( tr->isMultiTrigger() ){ - //disable all other multi triggers - for( std::map< Trigger*, bool >::iterator it = d_auto_gen_trigger[1][f].begin(); it != d_auto_gen_trigger[1][f].end(); ++it ){ - d_auto_gen_trigger[1][f][ it->first ] = false; - } - tindex = 1; - }else{ - tindex = 0; - } - //making it during an instantiation round, so must reset - if( d_auto_gen_trigger[tindex][f].find( tr )==d_auto_gen_trigger[tindex][f].end() ){ - tr->resetInstantiationRound(); - tr->reset( Node::null() ); - } - d_auto_gen_trigger[tindex][f][tr] = true; + addTrigger( tr, f ); //if we are generating additional triggers... - if( tindex==0 ){ - int index = 0; - if( index<(int)patTerms.size() ){ + if( !tr->isMultiTrigger() ){ + unsigned index = 0; + if( index<patTerms.size() ){ //Notice() << "check add additional" << std::endl; //check if similar patterns exist, and if so, add them additionally int nqfs_curr = 0; @@ -433,18 +450,13 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ } index++; bool success = true; - while( success && index<(int)patTerms.size() && d_is_single_trigger[ patTerms[index] ] ){ + while( success && index<patTerms.size() && d_is_single_trigger[ patTerms[index] ] ){ success = false; if( !options::relevantTriggers() || d_quantEngine->getQuantifierRelevance()->getNumQuantifiersForSymbol( patTerms[index].getOperator() )<=nqfs_curr ){ d_single_trigger_gen[ patTerms[index] ] = true; - Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], matchOption, false, Trigger::TR_RETURN_NULL ); - if( tr2 ){ - //Notice() << "Add additional trigger " << patTerms[index] << std::endl; - tr2->resetInstantiationRound(); - tr2->reset( Node::null() ); - d_auto_gen_trigger[0][f][tr2] = true; - } + Trigger* tr2 = Trigger::mkTrigger( d_quantEngine, f, patTerms[index], false, Trigger::TR_RETURN_NULL, d_num_trigger_vars[f] ); + addTrigger( tr2, f ); success = true; } index++; @@ -457,8 +469,10 @@ void InstStrategyAutoGenTriggers::generateTriggers( Node f ){ } } -void InstStrategyAutoGenTriggers::addPatternToPool( Node q, Node pat, unsigned num_fv ) { - if( num_fv==q[0].getNumChildren() && ( options::pureThTriggers() || !Trigger::isPureTheoryTrigger( pat ) ) ){ +void InstStrategyAutoGenTriggers::addPatternToPool( Node q, Node pat, unsigned num_fv, Node mpat ) { + d_pat_to_mpat[pat] = mpat; + unsigned num_vars = options::partialTriggers() ? d_num_trigger_vars[q] : q[0].getNumChildren(); + if( num_fv==num_vars && ( options::pureThTriggers() || !Trigger::isPureTheoryTrigger( pat ) ) ){ d_patTerms[0][q].push_back( pat ); d_is_single_trigger[ pat ] = true; }else{ @@ -467,6 +481,38 @@ void InstStrategyAutoGenTriggers::addPatternToPool( Node q, Node pat, unsigned n } } + +void InstStrategyAutoGenTriggers::addTrigger( inst::Trigger * tr, Node q ) { + if( tr ){ + if( d_num_trigger_vars[q]<q[0].getNumChildren() ){ + //partial trigger : generate implication to mark user pattern + Node ipl = NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, d_quantEngine->getTermDatabase()->getVariableNode( tr->getInstPattern(), q ) ); + Node qq = NodeManager::currentNM()->mkNode( FORALL, d_vc_partition[1][q], NodeManager::currentNM()->mkNode( FORALL, d_vc_partition[0][q], q[1] ), ipl ); + Trace("auto-gen-trigger-partial") << "Make partially specified user pattern: " << std::endl; + Trace("auto-gen-trigger-partial") << " " << qq << std::endl; + Node lem = NodeManager::currentNM()->mkNode( OR, q.negate(), qq ); + d_quantEngine->addLemma( lem ); + }else{ + unsigned tindex; + if( tr->isMultiTrigger() ){ + //disable all other multi triggers + for( std::map< Trigger*, bool >::iterator it = d_auto_gen_trigger[1][q].begin(); it != d_auto_gen_trigger[1][q].end(); ++it ){ + d_auto_gen_trigger[1][q][ it->first ] = false; + } + tindex = 1; + }else{ + tindex = 0; + } + //making it during an instantiation round, so must reset + if( d_auto_gen_trigger[tindex][q].find( tr )==d_auto_gen_trigger[tindex][q].end() ){ + tr->resetInstantiationRound(); + tr->reset( Node::null() ); + } + d_auto_gen_trigger[tindex][q][tr] = true; + } + } +} + bool InstStrategyAutoGenTriggers::hasUserPatterns( Node q ) { if( q.getNumChildren()==3 ){ std::map< Node, bool >::iterator it = d_hasUserPatterns.find( q ); @@ -519,8 +565,7 @@ bool InstStrategyLocalTheoryExt::isLocalTheoryExt( Node f ) { Trace("local-t-ext") << " " << patTerms[i] << std::endl; } Trace("local-t-ext") << std::endl; - int matchOption = 0; - Trigger * tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, matchOption, true, Trigger::TR_GET_OLD ); + Trigger * tr = Trigger::mkTrigger( d_quantEngine, f, patTerms, true, Trigger::TR_GET_OLD ); d_lte_trigger[f] = tr; }else{ Trace("local-t-ext") << "No local theory extensions trigger for " << f << "." << std::endl; diff --git a/src/theory/quantifiers/inst_strategy_e_matching.h b/src/theory/quantifiers/inst_strategy_e_matching.h index 028f24b27..e6d993294 100644..100755 --- a/src/theory/quantifiers/inst_strategy_e_matching.h +++ b/src/theory/quantifiers/inst_strategy_e_matching.h @@ -83,14 +83,18 @@ private: std::map< Node, std::map< inst::Trigger*, bool > > d_processed_trigger; //instantiation no patterns std::map< Node, std::vector< Node > > d_user_no_gen; + // number of trigger variables per quantifier + std::map< Node, unsigned > d_num_trigger_vars; + std::map< Node, Node > d_vc_partition[2]; + std::map< Node, Node > d_pat_to_mpat; private: /** process functions */ void processResetInstantiationRound( Theory::Effort effort ); int process( Node q, Theory::Effort effort, int e ); /** generate triggers */ void generateTriggers( Node q ); - void addPatternToPool( Node q, Node pat, unsigned num_fv ); - //bool addTrigger( inst::Trigger * tr, Node f, unsigned r ); + void addPatternToPool( Node q, Node pat, unsigned num_fv, Node mpat ); + void addTrigger( inst::Trigger * tr, Node f ); /** has user patterns */ bool hasUserPatterns( Node q ); /** has user patterns */ diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp index 955dc5d86..db597d031 100644..100755 --- a/src/theory/quantifiers/instantiation_engine.cpp +++ b/src/theory/quantifiers/instantiation_engine.cpp @@ -137,11 +137,7 @@ void InstantiationEngine::check( Theory::Effort e, unsigned quant_e ){ doInstantiationRound( e ); if( d_quantEngine->inConflict() ){ Assert( d_quantEngine->getNumLemmasWaiting()>lastWaiting ); - Trace("inst-engine") << "Conflict = " << d_quantEngine->getNumLemmasWaiting() << " / " << d_quantEngine->getNumLemmasAddedThisRound(); - if( lastWaiting>0 ){ - Trace("inst-engine") << " (prev " << lastWaiting << ")"; - } - Trace("inst-engine") << std::endl; + Trace("inst-engine") << "Conflict, added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl; }else if( d_quantEngine->hasAddedLemma() ){ Trace("inst-engine") << "Added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl; } diff --git a/src/theory/quantifiers/instantiation_engine.h b/src/theory/quantifiers/instantiation_engine.h index d2b3740a1..d2b3740a1 100644..100755 --- a/src/theory/quantifiers/instantiation_engine.h +++ b/src/theory/quantifiers/instantiation_engine.h diff --git a/src/theory/quantifiers/kinds b/src/theory/quantifiers/kinds index b03c4ad3b..b03c4ad3b 100644..100755 --- a/src/theory/quantifiers/kinds +++ b/src/theory/quantifiers/kinds diff --git a/src/theory/quantifiers/local_theory_ext.cpp b/src/theory/quantifiers/local_theory_ext.cpp index ada28c084..ada28c084 100644..100755 --- a/src/theory/quantifiers/local_theory_ext.cpp +++ b/src/theory/quantifiers/local_theory_ext.cpp diff --git a/src/theory/quantifiers/local_theory_ext.h b/src/theory/quantifiers/local_theory_ext.h index 94abf3c90..94abf3c90 100644..100755 --- a/src/theory/quantifiers/local_theory_ext.h +++ b/src/theory/quantifiers/local_theory_ext.h diff --git a/src/theory/quantifiers/macros.cpp b/src/theory/quantifiers/macros.cpp index 582599680..582599680 100644..100755 --- a/src/theory/quantifiers/macros.cpp +++ b/src/theory/quantifiers/macros.cpp diff --git a/src/theory/quantifiers/macros.h b/src/theory/quantifiers/macros.h index 39ec2f0a1..39ec2f0a1 100644..100755 --- a/src/theory/quantifiers/macros.h +++ b/src/theory/quantifiers/macros.h diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp index 3ae36b1d4..10a5ae41b 100644..100755 --- a/src/theory/quantifiers/model_builder.cpp +++ b/src/theory/quantifiers/model_builder.cpp @@ -66,7 +66,7 @@ void QModelBuilder::debugModel( FirstOrderModel* fm ){ tests++; std::vector< Node > terms; for( int k=0; k<riter.getNumTerms(); k++ ){ - terms.push_back( riter.getTerm( k ) ); + terms.push_back( riter.getCurrentTerm( k ) ); } Node n = d_qe->getInstantiation( f, vars, terms ); Node val = fm->getValue( n ); @@ -84,7 +84,9 @@ void QModelBuilder::debugModel( FirstOrderModel* fm ){ } Trace("quant-check-model") << "." << std::endl; }else{ - Trace("quant-check-model") << "Warning: Could not test quantifier " << f << std::endl; + if( riter.isIncomplete() ){ + Trace("quant-check-model") << "Warning: Could not test quantifier " << f << std::endl; + } } } } @@ -114,7 +116,7 @@ bool TermArgBasisTrie::addTerm2( FirstOrderModel* fm, Node n, int argIndex ){ QModelBuilderIG::QModelBuilderIG( context::Context* c, QuantifiersEngine* qe ) : -QModelBuilder( c, qe ) { +QModelBuilder( c, qe ), d_basisNoMatch( c ) { } @@ -302,7 +304,7 @@ void QModelBuilderIG::analyzeModel( FirstOrderModel* fm ){ for( size_t i=0; i<fmig->d_uf_terms[op].size(); i++ ){ Node n = fmig->d_uf_terms[op][i]; //for calculating if op is constant - if( !n.getAttribute(NoMatchAttribute()) ){ + if( d_qe->getTermDatabase()->isTermActive( n ) ){ Node v = fmig->getRepresentative( n ); if( i==0 ){ d_uf_prefs[op].d_const_val = v; @@ -312,12 +314,11 @@ void QModelBuilderIG::analyzeModel( FirstOrderModel* fm ){ } } //for calculating terms that we don't need to consider - if( !n.getAttribute(NoMatchAttribute()) || n.getAttribute(ModelBasisArgAttribute())!=0 ){ - if( !n.getAttribute(BasisNoMatchAttribute()) ){ + if( d_qe->getTermDatabase()->isTermActive( n ) || n.getAttribute(ModelBasisArgAttribute())!=0 ){ + if( d_basisNoMatch.find( n )==d_basisNoMatch.end() ){ //need to consider if it is not congruent modulo model basis if( !tabt.addTerm( fmig, n ) ){ - BasisNoMatchAttribute bnma; - n.setAttribute(bnma,true); + d_basisNoMatch[n] = true; } } } @@ -382,8 +383,8 @@ bool QModelBuilderIG::isQuantifierActive( Node f ){ } bool QModelBuilderIG::isTermActive( Node n ){ - return !n.getAttribute(NoMatchAttribute()) || //it is not congruent to another active term - ( n.getAttribute(ModelBasisArgAttribute())!=0 && !n.getAttribute(BasisNoMatchAttribute()) ); //or it has model basis arguments + return d_qe->getTermDatabase()->isTermActive( n ) || //it is not congruent to another active term + ( n.getAttribute(ModelBasisArgAttribute())!=0 && d_basisNoMatch.find( n )==d_basisNoMatch.end() ); //or it has model basis arguments //and is not congruent modulo model basis //to another active term } @@ -400,15 +401,19 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i Debug("inst-fmf-ei") << "Begin instantiation..." << std::endl; while( !riter.isFinished() && ( d_addedLemmas==0 || !options::fmfOneInstPerRound() ) ){ d_triedLemmas++; - for( int i=0; i<(int)riter.d_index.size(); i++ ){ - Trace("try") << i << " : " << riter.d_index[i] << " : " << riter.getTerm( i ) << std::endl; + if( Debug.isOn("inst-fmf-ei-debug") ){ + for( int i=0; i<(int)riter.d_index.size(); i++ ){ + Debug("inst-fmf-ei-debug") << i << " : " << riter.d_index[i] << " : " << riter.getCurrentTerm( i ) << std::endl; + } } int eval = 0; int depIndex; //see if instantiation is already true in current model - Debug("fmf-model-eval") << "Evaluating "; - riter.debugPrintSmall("fmf-model-eval"); - Debug("fmf-model-eval") << "Done calculating terms." << std::endl; + if( Debug.isOn("fmf-model-eval") ){ + Debug("fmf-model-eval") << "Evaluating "; + riter.debugPrintSmall("fmf-model-eval"); + Debug("fmf-model-eval") << "Done calculating terms." << std::endl; + } //if evaluate(...)==1, then the instantiation is already true in the model // depIndex is the index of the least significant variable that this evaluation relies upon depIndex = riter.getNumTerms()-1; @@ -426,7 +431,7 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i //instantiation was not shown to be true, construct the match InstMatch m( f ); for( int i=0; i<riter.getNumTerms(); i++ ){ - m.set( d_qe, riter.d_index_order[i], riter.getTerm( i ) ); + m.set( d_qe, i, riter.getCurrentTerm( i ) ); } Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl; //add as instantiation @@ -464,8 +469,8 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i Trace("model-engine-warn") << std::endl; } } - //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round - d_incomplete_check = riter.d_incomplete; + //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round + d_incomplete_check = riter.isIncomplete(); return true; }else{ return false; @@ -667,7 +672,7 @@ int QModelBuilderDefault::doInstGen( FirstOrderModel* fm, Node f ){ //if applicable, try to add exceptions here if( !tr_terms.empty() ){ //make a trigger for these terms, add instantiations - inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms, 0, true, inst::Trigger::TR_MAKE_NEW ); + inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms, true, inst::Trigger::TR_MAKE_NEW ); //Notice() << "Trigger = " << (*tr) << std::endl; tr->resetInstantiationRound(); tr->reset( Node::null() ); diff --git a/src/theory/quantifiers/model_builder.h b/src/theory/quantifiers/model_builder.h index 906673903..e4f9529a8 100644..100755 --- a/src/theory/quantifiers/model_builder.h +++ b/src/theory/quantifiers/model_builder.h @@ -57,15 +57,6 @@ public: -/** Attribute true for nodes that should not be used when considered for inst-gen basis */ -struct BasisNoMatchAttributeId {}; -/** use the special for boolean flag */ -typedef expr::Attribute< BasisNoMatchAttributeId, - bool, - expr::attr::NullCleanupStrategy, - true // context dependent - > BasisNoMatchAttribute; - class TermArgBasisTrie { private: bool addTerm2( FirstOrderModel* fm, Node n, int argIndex ); @@ -85,7 +76,9 @@ public: */ class QModelBuilderIG : public QModelBuilder { + typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap; protected: + BoolMap d_basisNoMatch; //map from operators to model preference data std::map< Node, uf::UfModelPreferenceData > d_uf_prefs; //built model uf diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp index 0bbca88eb..5d575969f 100644..100755 --- a/src/theory/quantifiers/model_engine.cpp +++ b/src/theory/quantifiers/model_engine.cpp @@ -153,27 +153,23 @@ int ModelEngine::checkModel(){ //d_quantEngine->getEqualityQuery()->flattenRepresentatives( fm->d_rep_set.d_type_reps ); //for debugging - if( Trace.isOn("model-engine") || Trace.isOn("model-engine-debug") ){ - for( std::map< TypeNode, std::vector< Node > >::iterator it = fm->d_rep_set.d_type_reps.begin(); - it != fm->d_rep_set.d_type_reps.end(); ++it ){ - if( it->first.isSort() ){ - Trace("model-engine") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl; - if( Trace.isOn("model-engine-debug") ){ - Trace("model-engine-debug") << " Reps : "; - for( size_t i=0; i<it->second.size(); i++ ){ - Trace("model-engine-debug") << it->second[i] << " "; - } - Trace("model-engine-debug") << std::endl; - Trace("model-engine-debug") << " Term reps : "; - for( size_t i=0; i<it->second.size(); i++ ){ - Node r = d_quantEngine->getEqualityQuery()->getInternalRepresentative( it->second[i], Node::null(), 0 ); - Trace("model-engine-debug") << r << " "; - } - Trace("model-engine-debug") << std::endl; - Node mbt = d_quantEngine->getTermDatabase()->getModelBasisTerm(it->first); - Trace("model-engine-debug") << " Basis term : " << mbt << std::endl; - } + for( std::map< TypeNode, std::vector< Node > >::iterator it = fm->d_rep_set.d_type_reps.begin(); + it != fm->d_rep_set.d_type_reps.end(); ++it ){ + if( it->first.isSort() ){ + Trace("model-engine") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl; + Trace("model-engine-debug") << " Reps : "; + for( size_t i=0; i<it->second.size(); i++ ){ + Trace("model-engine-debug") << it->second[i] << " "; } + Trace("model-engine-debug") << std::endl; + Trace("model-engine-debug") << " Term reps : "; + for( size_t i=0; i<it->second.size(); i++ ){ + Node r = d_quantEngine->getEqualityQuery()->getInternalRepresentative( it->second[i], Node::null(), 0 ); + Trace("model-engine-debug") << r << " "; + } + Trace("model-engine-debug") << std::endl; + Node mbt = d_quantEngine->getTermDatabase()->getModelBasisTerm(it->first); + Trace("model-engine-debug") << " Basis term : " << mbt << std::endl; } } @@ -221,11 +217,12 @@ int ModelEngine::checkModel(){ //print debug information if( d_quantEngine->inConflict() ){ - Trace("model-engine") << "Conflict = " << d_quantEngine->getNumLemmasWaiting() << " / " << d_quantEngine->getNumLemmasAddedThisRound() << std::endl; + Trace("model-engine") << "Conflict, added lemmas = "; }else{ - Trace("model-engine") << "Added Lemmas = " << d_addedLemmas << " / " << d_triedLemmas << " / "; - Trace("model-engine") << d_totalLemmas << std::endl; - } + Trace("model-engine") << "Added Lemmas = "; + } + Trace("model-engine") << d_addedLemmas << " / " << d_triedLemmas << " / "; + Trace("model-engine") << d_totalLemmas << std::endl; return d_addedLemmas; } @@ -281,15 +278,15 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){ //create a rep set iterator and iterate over the (relevant) domain of the quantifier RepSetIterator riter( d_quantEngine, &(d_quantEngine->getModel()->d_rep_set) ); if( riter.setQuantifier( f ) ){ - Trace("fmf-exh-inst") << "...exhaustive instantiation set, incomplete=" << riter.d_incomplete << "..." << std::endl; - if( !riter.d_incomplete ){ + Trace("fmf-exh-inst") << "...exhaustive instantiation set, incomplete=" << riter.isIncomplete() << "..." << std::endl; + if( !riter.isIncomplete() ){ int triedLemmas = 0; int addedLemmas = 0; while( !riter.isFinished() && ( addedLemmas==0 || !options::fmfOneInstPerRound() ) ){ //instantiation was not shown to be true, construct the match InstMatch m( f ); for( int i=0; i<riter.getNumTerms(); i++ ){ - m.set( d_quantEngine, riter.d_index_order[i], riter.getTerm( i ) ); + m.set( d_quantEngine, i, riter.getCurrentTerm( i ) ); } Debug("fmf-model-eval") << "* Add instantiation " << m << std::endl; triedLemmas++; @@ -309,11 +306,10 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){ d_statistics.d_exh_inst_lemmas += addedLemmas; } }else{ - Trace("fmf-exh-inst") << "...exhaustive instantiation failed to set, incomplete=" << riter.d_incomplete << "..." << std::endl; - Assert( riter.d_incomplete ); + Trace("fmf-exh-inst") << "...exhaustive instantiation did set, incomplete=" << riter.isIncomplete() << "..." << std::endl; } //if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round - d_incomplete_check = d_incomplete_check || riter.d_incomplete; + d_incomplete_check = d_incomplete_check || riter.isIncomplete(); } } diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h index 12f18aa08..12f18aa08 100644..100755 --- a/src/theory/quantifiers/model_engine.h +++ b/src/theory/quantifiers/model_engine.h diff --git a/src/theory/quantifiers/quant_conflict_find.cpp b/src/theory/quantifiers/quant_conflict_find.cpp index ca87a607d..bac2aa35c 100644..100755 --- a/src/theory/quantifiers/quant_conflict_find.cpp +++ b/src/theory/quantifiers/quant_conflict_find.cpp @@ -49,6 +49,7 @@ QuantInfo::~QuantInfo() { void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) { d_q = q; + d_extra_var.clear(); for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ d_match.push_back( TNode::null() ); d_match_term.push_back( TNode::null() ); @@ -77,33 +78,31 @@ void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) { } } */ - if( d_mg->isValid() ){ - for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){ - if( d_vars[j].getKind()!=BOUND_VARIABLE ){ - d_var_mg[j] = NULL; - bool is_tsym = false; - if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){ - is_tsym = true; - d_tsym_vars.push_back( j ); - } - if( !is_tsym || options::qcfTConstraint() ){ - d_var_mg[j] = new MatchGen( this, d_vars[j], true ); - } - if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){ - Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl; - d_mg->setInvalid(); - break; - }else{ - std::vector< int > bvars; - d_var_mg[j]->determineVariableOrder( this, bvars ); - } + for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){ + if( d_vars[j].getKind()!=BOUND_VARIABLE ){ + d_var_mg[j] = NULL; + bool is_tsym = false; + if( !MatchGen::isHandledUfTerm( d_vars[j] ) && d_vars[j].getKind()!=ITE ){ + is_tsym = true; + d_tsym_vars.push_back( j ); + } + if( !is_tsym || options::qcfTConstraint() ){ + d_var_mg[j] = new MatchGen( this, d_vars[j], true ); + } + if( !d_var_mg[j] || !d_var_mg[j]->isValid() ){ + Trace("qcf-invalid") << "QCF invalid : cannot match for " << d_vars[j] << std::endl; + d_mg->setInvalid(); + break; + }else{ + std::vector< int > bvars; + d_var_mg[j]->determineVariableOrder( this, bvars ); } - } - if( d_mg->isValid() ){ - std::vector< int > bvars; - d_mg->determineVariableOrder( this, bvars ); } } + if( d_mg->isValid() ){ + std::vector< int > bvars; + d_mg->determineVariableOrder( this, bvars ); + } }else{ Trace("qcf-invalid") << "QCF invalid : body of formula cannot be processed." << std::endl; } @@ -113,14 +112,15 @@ void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) { //optimization : record variable argument positions for terms that must be matched std::vector< TNode > vars; //TODO: revisit this, makes QCF faster, but misses conflicts due to caring about paths that may not be relevant (starExec jobs 14136/14137) - //if( options::qcfSkipRd() ){ - // for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){ - // vars.push_back( d_vars[j] ); - // } - //} - //get all variables that are always relevant - std::map< TNode, bool > visited; - getPropagateVars( vars, q[1], false, visited ); + if( options::qcfSkipRd() ){ + for( unsigned j=q[0].getNumChildren(); j<d_vars.size(); j++ ){ + vars.push_back( d_vars[j] ); + } + }else{ + //get all variables that are always relevant + std::map< TNode, bool > visited; + getPropagateVars( p, vars, q[1], false, visited ); + } for( unsigned j=0; j<vars.size(); j++ ){ Node v = vars[j]; TNode f = p->getTermDatabase()->getMatchOperator( v ); @@ -141,7 +141,7 @@ void QuantInfo::initialize( QuantConflictFind * p, Node q, Node qn ) { } } -void QuantInfo::getPropagateVars( std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited ){ +void QuantInfo::getPropagateVars( QuantConflictFind * p, std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited ){ std::map< TNode, bool >::iterator itv = visited.find( n ); if( itv==visited.end() ){ visited[n] = true; @@ -150,6 +150,12 @@ void QuantInfo::getPropagateVars( std::vector< TNode >& vars, TNode n, bool pol, if( d_var_num.find( n )!=d_var_num.end() ){ Assert( std::find( vars.begin(), vars.end(), n )==vars.end() ); vars.push_back( n ); + TNode f = p->getTermDatabase()->getMatchOperator( n ); + if( !f.isNull() ){ + if( std::find( p->d_func_rel_dom[f].begin(), p->d_func_rel_dom[f].end(), d_q )==p->d_func_rel_dom[f].end() ){ + p->d_func_rel_dom[f].push_back( d_q ); + } + } }else if( MatchGen::isHandledBoolConnective( n ) ){ Assert( n.getKind()!=IMPLIES ); QuantPhaseReq::getEntailPolarity( n, 0, true, pol, rec, newPol ); @@ -157,12 +163,16 @@ void QuantInfo::getPropagateVars( std::vector< TNode >& vars, TNode n, bool pol, Trace("qcf-opt-debug") << "getPropagateVars " << n << ", pol = " << pol << ", rec = " << rec << std::endl; if( rec ){ for( unsigned i=0; i<n.getNumChildren(); i++ ){ - getPropagateVars( vars, n[i], pol, visited ); + getPropagateVars( p, vars, n[i], pol, visited ); } } } } +bool QuantInfo::isBaseMatchComplete() { + return d_vars_set.size()==(d_q[0].getNumChildren()+d_extra_var.size()); +} + void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) { Trace("qcf-qregister-debug2") << "Register : " << n << std::endl; if( n.getKind()==FORALL ){ @@ -209,7 +219,6 @@ void QuantInfo::flatten( Node n, bool beneathQuant ) { if( n.getKind()==BOUND_VARIABLE ){ d_inMatchConstraint[n] = true; } - //if( MatchGen::isHandledUfTerm( n ) || n.getKind()==ITE ){ if( d_var_num.find( n )==d_var_num.end() ){ Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl; d_var_num[n] = d_vars.size(); @@ -219,6 +228,8 @@ void QuantInfo::flatten( Node n, bool beneathQuant ) { d_match_term.push_back( TNode::null() ); if( n.getKind()==ITE ){ registerNode( n, false, false ); + }else if( n.getKind()==BOUND_VARIABLE ){ + d_extra_var.push_back( n ); }else{ for( unsigned i=0; i<n.getNumChildren(); i++ ){ flatten( n[i], beneathQuant ); @@ -233,13 +244,15 @@ void QuantInfo::flatten( Node n, bool beneathQuant ) { } -void QuantInfo::reset_round( QuantConflictFind * p ) { +bool QuantInfo::reset_round( QuantConflictFind * p ) { for( unsigned i=0; i<d_match.size(); i++ ){ d_match[i] = TNode::null(); d_match_term[i] = TNode::null(); } + d_vars_set.clear(); d_curr_var_deq.clear(); d_tconstraints.clear(); + //add built-in variable constraints for( unsigned r=0; r<2; r++ ){ for( std::map< int, std::vector< Node > >::iterator it = d_var_constraint[r].begin(); @@ -257,7 +270,7 @@ void QuantInfo::reset_round( QuantConflictFind * p ) { d_mg->d_children.clear(); d_mg->d_n = NodeManager::currentNM()->mkConst( true ); d_mg->d_type = MatchGen::typ_ground; - return; + return false; } } } @@ -268,6 +281,7 @@ void QuantInfo::reset_round( QuantConflictFind * p ) { } //now, reset for matching d_mg->reset( p, false, this ); + return true; } int QuantInfo::getCurrentRepVar( int v ) { @@ -377,11 +391,12 @@ int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, boo } } } - d_match[v] = TNode::null(); + unsetMatch( p, v ); return 1; }else{ //std::map< int, TNode >::iterator itm = d_match.find( v ); bool isGroundRep = false; + bool isGround = false; if( vn!=-1 ){ Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl; //std::map< int, TNode >::iterator itmn = d_match.find( vn ); @@ -428,13 +443,14 @@ int QuantInfo::addConstraint( QuantConflictFind * p, int v, TNode n, int vn, boo Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl; if( d_match[v].isNull() ){ //isGroundRep = true; ?? + isGround = true; }else{ //compare ground values Debug("qcf-match-debug") << " -> Ground value, compare " << d_match[v] << " "<< n << std::endl; return p->areMatchEqual( d_match[v], n ) ? 0 : -1; } } - if( setMatch( p, v, n, isGroundRep ) ){ + if( setMatch( p, v, n, isGroundRep, isGround ) ){ Debug("qcf-match-debug") << " -> success" << std::endl; return 1; }else{ @@ -500,7 +516,7 @@ bool QuantInfo::isConstrainedVar( int v ) { } } -bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep ) { +bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep, bool isGround ) { if( getCurrentCanBeEqual( p, v, n ) ){ if( isGroundRep ){ //fail if n does not exist in the relevant domain of each of the argument positions @@ -518,6 +534,12 @@ bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRe } } Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl; + if( isGround ){ + if( d_vars[v].getKind()==BOUND_VARIABLE ){ + d_vars_set[v] = true; + Debug("qcf-match-debug") << "---- now bound " << d_vars_set.size() << " / " << d_q[0].getNumChildren() << " base variables." << std::endl; + } + } d_match[v] = n; return true; }else{ @@ -525,6 +547,14 @@ bool QuantInfo::setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRe } } +void QuantInfo::unsetMatch( QuantConflictFind * p, int v ) { + Debug("qcf-match-debug") << "-- unbind : " << v << std::endl; + if( d_vars[v].getKind()==BOUND_VARIABLE && d_vars_set.find( v )!=d_vars_set.end() ){ + d_vars_set.erase( v ); + } + d_match[ v ] = TNode::null(); +} + bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) { for( int i=0; i<getNumVars(); i++ ){ //std::map< int, TNode >::iterator it = d_match.find( i ); @@ -538,6 +568,42 @@ bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) { } bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ) { + if( options::qcfEagerTest() ){ + //check whether the instantiation evaluates as expected + if( p->d_effort==QuantConflictFind::effort_conflict ){ + Trace("qcf-instance-check") << "Possible conflict instance for " << d_q << " : " << std::endl; + std::map< TNode, TNode > subs; + for( unsigned i=0; i<terms.size(); i++ ){ + Trace("qcf-instance-check") << " " << terms[i] << std::endl; + subs[d_q[0][i]] = terms[i]; + } + for( unsigned i=0; i<d_extra_var.size(); i++ ){ + Node n = getCurrentExpValue( d_extra_var[i] ); + Trace("qcf-instance-check") << " " << d_extra_var[i] << " -> " << n << std::endl; + subs[d_extra_var[i]] = n; + } + if( !p->getTermDatabase()->isEntailed( d_q[1], subs, false, false ) ){ + Trace("qcf-instance-check") << "...not entailed to be false." << std::endl; + return true; + } + }else{ + Node inst = p->d_quantEngine->getInstantiation( d_q, terms ); + Node inst_eval = p->getTermDatabase()->evaluateTerm( inst, NULL, options::qcfTConstraint() ); + if( Trace.isOn("qcf-instance-check") ){ + Trace("qcf-instance-check") << "Possible propagating instance for " << d_q << " : " << std::endl; + for( unsigned i=0; i<terms.size(); i++ ){ + Trace("qcf-instance-check") << " " << terms[i] << std::endl; + } + Trace("qcf-instance-check") << "...evaluates to " << inst_eval << std::endl; + } + if( inst_eval.isNull() || inst_eval==p->getTermDatabase()->d_true || !isPropagatingInstance( p, inst_eval ) ){ + Trace("qcf-instance-check") << "...spurious." << std::endl; + return true; + }else{ + Trace("qcf-instance-check") << "...not spurious." << std::endl; + } + } + } if( !d_tconstraints.empty() ){ //check constraints for( std::map< Node, bool >::iterator it = d_tconstraints.begin(); it != d_tconstraints.end(); ++it ){ @@ -552,6 +618,26 @@ bool QuantInfo::isTConstraintSpurious( QuantConflictFind * p, std::vector< Node return false; } +bool QuantInfo::isPropagatingInstance( QuantConflictFind * p, Node n ) { + if( n.getKind()==FORALL ){ + //TODO? + return true; + }else if( n.getKind()==NOT || n.getKind()==AND || n.getKind()==OR || n.getKind()==EQUAL || n.getKind()==ITE || n.getKind()==IFF ){ + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + if( !isPropagatingInstance( p, n[i] ) ){ + return false; + } + } + return true; + }else{ + if( p->getEqualityEngine()->hasTerm( n ) || isGroundSubterm( n ) ){ + return true; + } + } + Trace("qcf-instance-check-debug") << "...not propagating instance because of " << n << std::endl; + return false; +} + bool QuantInfo::entailmentTest( QuantConflictFind * p, Node lit, bool chEnt ) { Trace("qcf-tconstraint-debug") << "Check : " << lit << std::endl; Node rew = Rewriter::rewrite( lit ); @@ -606,6 +692,9 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign doFail = true; success = false; }else{ + if( isBaseMatchComplete() && options::qcfEagerTest() ){ + return true; + } //solve for interpreted symbol matches // this breaks the invariant that all introduced constraints are over existing terms for( int i=(int)(d_tsym_vars.size()-1); i>=0; i-- ){ @@ -636,7 +725,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign if( !z.isNull() ){ Trace("qcf-tconstraint-debug") << "...set " << d_vars[vn] << " = " << z << std::endl; assigned.push_back( vn ); - if( !setMatch( p, vn, z, false ) ){ + if( !setMatch( p, vn, z, false, true ) ){ success = false; break; } @@ -678,7 +767,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign if( !sum.isNull() ){ assigned.push_back( slv_v ); Trace("qcf-tconstraint-debug") << "...set " << d_vars[slv_v] << " = " << sum << std::endl; - if( !setMatch( p, slv_v, sum, false ) ){ + if( !setMatch( p, slv_v, sum, false, true ) ){ success = false; } p->d_tempCache.push_back( sum ); @@ -764,7 +853,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign int currIndex = d_una_eqc_count[d_una_index]; d_una_eqc_count[d_una_index]++; Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl; - if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex], true ) ){ + if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex], true, true ) ){ d_match_term[d_unassigned[d_una_index]] = TNode::null(); Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl; d_una_index++; @@ -813,9 +902,7 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign } return true; }else{ - for( unsigned i=0; i<assigned.size(); i++ ){ - d_match[ assigned[i] ] = TNode::null(); - } + revertMatch( p, assigned ); assigned.clear(); return false; } @@ -837,9 +924,9 @@ void QuantInfo::getMatch( std::vector< Node >& terms ){ } } -void QuantInfo::revertMatch( std::vector< int >& assigned ) { +void QuantInfo::revertMatch( QuantConflictFind * p, std::vector< int >& assigned ) { for( unsigned i=0; i<assigned.size(); i++ ){ - d_match[ assigned[i] ] = TNode::null(); + unsetMatch( p, assigned[i] ); } } @@ -899,26 +986,7 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ) if( isVar ){ Assert( qi->d_var_num.find( n )!=qi->d_var_num.end() ); if( n.getKind()==ITE ){ - /* - d_type = typ_ite_var; - d_type_not = false; - d_n = n; - d_children.push_back( MatchGen( qi, d_n[0] ) ); - if( d_children[0].isValid() ){ - d_type = typ_ite_var; - for( unsigned i=1; i<=2; i++ ){ - Node nn = n.eqNode( n[i] ); - d_children.push_back( MatchGen( qi, nn ) ); - d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 ); - if( !d_children[d_children.size()-1].isValid() ){ - setInvalid(); - break; - } - } - }else{ -*/ - d_type = typ_invalid; - //} + d_type = typ_invalid; }else{ d_type = isHandledUfTerm( n ) ? typ_var : typ_tsym; d_qni_var_num[0] = qi->getVarNum( n ); @@ -961,26 +1029,6 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ) break; } } - /* - else if( isTop && n.getKind()==OR && d_children[d_children.size()-1].d_type==typ_var_eq ){ - Trace("qcf-qregister-debug") << "Remove child, make built-in constraint" << std::endl; - //if variable equality/disequality at top level, remove immediately - bool cIsNot = d_children[d_children.size()-1].d_type_not; - Node cn = d_children[d_children.size()-1].d_n; - Assert( cn.getKind()==EQUAL ); - Assert( p->d_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) ); - //make it a built-in constraint instead - for( unsigned i=0; i<2; i++ ){ - if( p->d_qinfo[q].isVar( cn[i] ) ){ - int v = p->d_qinfo[q].getVarNum( cn[i] ); - Node cno = cn[i==0 ? 1 : 0]; - p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno ); - break; - } - } - d_children.pop_back(); - } - */ } }else{ d_type = typ_invalid; @@ -1003,6 +1051,7 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ) } }else{ d_qni_gterm[i] = d_n[i]; + qi->setGroundSubterm( d_n[i] ); } } d_type = d_n.getKind()==EQUAL ? typ_eq : typ_tconstraint; @@ -1013,21 +1062,8 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ) //we will just evaluate d_n = n; d_type = typ_ground; + qi->setGroundSubterm( d_n ); } - //if( d_type!=typ_invalid ){ - //determine an efficient children ordering - //if( !d_children.empty() ){ - //for( unsigned i=0; i<d_children.size(); i++ ){ - // d_children_order.push_back( i ); - //} - //if( !d_n.isNull() && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ) ){ - //sort based on the type of the constraint : ground comes first, then literals, then others - //MatchGenSort mgs; - //mgs.d_mg = this; - //std::sort( d_children_order.begin(), d_children_order.end(), mgs ); - //} - //} - //} } Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = "; debugPrintType( "qcf-qregister-debug", d_type, true ); @@ -1036,78 +1072,96 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar ) } -void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ) { - int v = qi->getVarNum( n ); - if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){ - cbvars.push_back( v ); - } - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - collectBoundVar( qi, n[i], cbvars ); +void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars, std::map< Node, bool >& visited, bool& hasNested ) { + if( visited.find( n )==visited.end() ){ + visited[n] = true; + if( n.getKind()==FORALL ){ + hasNested = true; + } + int v = qi->getVarNum( n ); + if( v!=-1 && std::find( cbvars.begin(), cbvars.end(), v )==cbvars.end() ){ + cbvars.push_back( v ); + } + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + collectBoundVar( qi, n[i], cbvars, visited, hasNested ); + } } } void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ) { - Trace("qcf-qregister-debug") << "Determine variable order " << d_n << std::endl; - bool isCom = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ); - std::map< int, std::vector< int > > c_to_vars; - std::map< int, std::vector< int > > vars_to_c; - std::map< int, int > vb_count; - std::map< int, int > vu_count; - std::vector< bool > assigned; - Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl; - for( unsigned i=0; i<d_children.size(); i++ ){ - collectBoundVar( qi, d_children[i].d_n, c_to_vars[i] ); - assigned.push_back( false ); - vb_count[i] = 0; - vu_count[i] = 0; - for( unsigned j=0; j<c_to_vars[i].size(); j++ ){ - int v = c_to_vars[i][j]; - vars_to_c[v].push_back( i ); - if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){ - vu_count[i]++; - if( !isCom ){ - bvars.push_back( v ); + Trace("qcf-qregister-debug") << "Determine variable order " << d_n << ", #bvars = " << bvars.size() << std::endl; + bool isComm = d_type==typ_formula && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ); + if( isComm ){ + std::map< int, std::vector< int > > c_to_vars; + std::map< int, std::vector< int > > vars_to_c; + std::map< int, int > vb_count; + std::map< int, int > vu_count; + std::map< int, bool > has_nested; + std::vector< bool > assigned; + Trace("qcf-qregister-debug") << "Calculate bound variables..." << std::endl; + for( unsigned i=0; i<d_children.size(); i++ ){ + std::map< Node, bool > visited; + has_nested[i] = false; + collectBoundVar( qi, d_children[i].d_n, c_to_vars[i], visited, has_nested[i] ); + assigned.push_back( false ); + vb_count[i] = 0; + vu_count[i] = 0; + for( unsigned j=0; j<c_to_vars[i].size(); j++ ){ + int v = c_to_vars[i][j]; + vars_to_c[v].push_back( i ); + if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){ + vu_count[i]++; + }else{ + vb_count[i]++; } - }else{ - vb_count[i]++; } } - } - if( isCom ){ - //children that bind the least number of unbound variables go first + //children that bind no unbound variable, then the most number of bound, unbound variables go first + Trace("qcf-qregister-vo") << "Variable order for " << d_n << " : " << std::endl; do { + int min_score0 = -1; int min_score = -1; int min_score_index = -1; for( unsigned i=0; i<d_children.size(); i++ ){ if( !assigned[i] ){ - int score = vu_count[i]; - if( min_score==-1 || score<min_score ){ + Trace("qcf-qregister-debug2") << "Child " << i << " has b/ub : " << vb_count[i] << "/" << vu_count[i] << std::endl; + int score0 = 0;//has_nested[i] ? 0 : 1; + int score; + if( !options::qcfVoExp() ){ + score = vu_count[i]; + }else{ + score = vu_count[i]==0 ? 0 : ( 1 + qi->d_vars.size()*( qi->d_vars.size() - vb_count[i] ) + ( qi->d_vars.size() - vu_count[i] ) ); + } + if( min_score==-1 || score0<min_score0 || ( score0==min_score0 && score<min_score ) ){ + min_score0 = score0; min_score = score; min_score_index = i; } } } - Trace("qcf-qregister-debug") << "...assign child " << min_score_index << "/" << d_children.size() << std::endl; + Trace("qcf-qregister-vo") << " " << d_children_order.size()+1 << ": " << d_children[min_score_index].d_n << " : "; + Trace("qcf-qregister-vo") << vu_count[min_score_index] << " " << vb_count[min_score_index] << " " << has_nested[min_score_index] << std::endl; + Trace("qcf-qregister-debug") << "...assign child " << min_score_index << std::endl; + Trace("qcf-qregister-debug") << "...score : " << min_score << std::endl; Assert( min_score_index!=-1 ); //add to children order d_children_order.push_back( min_score_index ); assigned[min_score_index] = true; - //if( vb_count[min_score_index]==0 ){ - // d_independent.push_back( min_score_index ); - //} //determine order internal to children d_children[min_score_index].determineVariableOrder( qi, bvars ); Trace("qcf-qregister-debug") << "...bind variables" << std::endl; //now, make it a bound variable - for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){ - int v = c_to_vars[min_score_index][i]; - if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){ - for( unsigned j=0; j<vars_to_c[v].size(); j++ ){ - int vc = vars_to_c[v][j]; - vu_count[vc]--; - vb_count[vc]++; + if( vu_count[min_score_index]>0 ){ + for( unsigned i=0; i<c_to_vars[min_score_index].size(); i++ ){ + int v = c_to_vars[min_score_index][i]; + if( std::find( bvars.begin(), bvars.end(), v )==bvars.end() ){ + for( unsigned j=0; j<vars_to_c[v].size(); j++ ){ + int vc = vars_to_c[v][j]; + vu_count[vc]--; + vb_count[vc]++; + } + bvars.push_back( v ); } - bvars.push_back( v ); } } Trace("qcf-qregister-debug") << "...done assign child " << min_score_index << std::endl; @@ -1117,6 +1171,16 @@ void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars for( unsigned i=0; i<d_children.size(); i++ ){ d_children_order.push_back( i ); d_children[i].determineVariableOrder( qi, bvars ); + //now add to bvars + std::map< Node, bool > visited; + std::vector< int > cvars; + bool has_nested = false; + collectBoundVar( qi, d_children[i].d_n, cvars, visited, has_nested ); + for( unsigned j=0; j<cvars.size(); j++ ){ + if( std::find( bvars.begin(), bvars.end(), cvars[j] )==bvars.end() ){ + bvars.push_back( cvars[j] ); + } + } } } } @@ -1169,15 +1233,20 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) { d_qni.clear(); d_qni_bound.clear(); d_child_counter = -1; + d_use_children = true; d_tgt_orig = d_tgt; //set up processing matches if( d_type==typ_invalid ){ - //do nothing + d_use_children = false; }else if( d_type==typ_ground ){ + d_use_children = false; if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){ d_child_counter = 0; } + }else if( qi->isBaseMatchComplete() && options::qcfEagerTest() ){ + d_use_children = false; + d_child_counter = 0; }else if( d_type==typ_bool_var ){ //get current value of the variable TNode n = qi->getCurrentValue( d_n ); @@ -1195,7 +1264,7 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) { }else{ //unassigned, set match to true/false d_qni_bound[0] = vn; - qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false, false ); + qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false, false, true ); d_child_counter = 0; } if( d_child_counter==0 ){ @@ -1203,11 +1272,14 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) { } }else if( d_type==typ_var ){ Assert( isHandledUfTerm( d_n ) ); - Node f = getMatchOperator( p, d_n ); + TNode f = getMatchOperator( p, d_n ); Debug("qcf-match-debug") << " reset: Var will match operators of " << f << std::endl; TermArgTrie * qni = p->getTermDatabase()->getTermArgTrie( Node::null(), f ); if( qni!=NULL ){ d_qn.push_back( qni ); + }else{ + //inform irrelevant quantifiers + p->setIrrelevantFunction( f ); } d_matched_basis = false; }else if( d_type==typ_tsym || d_type==typ_tconstraint ){ @@ -1257,7 +1329,7 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) { } } }else{ - //otherwise, add a constraint to a variable + //otherwise, add a constraint to a variable TODO: this may be over-eager at effort > conflict, since equality may be a propagation if( vn[1]!=-1 && vn[0]==-1 ){ //swap Node t = nn[1]; @@ -1292,7 +1364,9 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) { d_qn.push_back( NULL ); }else{ if( d_tgt && d_n.getKind()==FORALL ){ - //do nothing + //fail + }else if( d_n.getKind()==FORALL && p->d_effort==QuantConflictFind::effort_conflict && !options::qcfNestedConflict() ){ + //fail }else{ //reset the first child to d_tgt d_child_counter = 0; @@ -1309,7 +1383,7 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) { Debug("qcf-match") << " Get next match for : " << d_n << ", type = "; debugPrintType( "qcf-match", d_type ); Debug("qcf-match") << ", children = " << d_children.size() << ", binding = " << d_binding << std::endl; - if( d_type==typ_invalid || d_type==typ_ground ){ + if( !d_use_children ){ if( d_child_counter==0 ){ d_child_counter = -1; return true; @@ -1423,7 +1497,7 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) { for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){ Debug("qcf-match") << " Clean up bound var " << it->second << std::endl; Assert( it->second<qi->getNumVars() ); - qi->d_match[ it->second ] = TNode::null(); + qi->unsetMatch( p, it->second ); qi->d_match_term[ it->second ] = TNode::null(); } d_qni_bound.clear(); @@ -1654,7 +1728,7 @@ bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) { if( it != d_qn[index]->d_data.end() ) { d_qni.push_back( it ); //set the match - if( it->first.getType().isComparableTo( qi->d_var_types[repVar] ) && qi->setMatch( p, d_qni_bound[index], it->first, true ) ){ + if( it->first.getType().isComparableTo( qi->d_var_types[repVar] ) && qi->setMatch( p, d_qni_bound[index], it->first, true, true ) ){ Debug("qcf-match-debug") << " Binding variable" << std::endl; if( d_qn.size()<d_qni_size ){ d_qn.push_back( &it->second ); @@ -1699,7 +1773,7 @@ bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) { d_qni[index]++; if( d_qni[index]!=d_qn[index]->d_data.end() ){ success = true; - if( qi->setMatch( p, itb->second, d_qni[index]->first, true ) ){ + if( qi->setMatch( p, itb->second, d_qni[index]->first, true, true ) ){ Debug("qcf-match-debug") << " Bind next variable" << std::endl; if( d_qn.size()<d_qni_size ){ d_qn.push_back( &d_qni[index]->second ); @@ -1709,7 +1783,7 @@ bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) { invalidMatch = true; } }else{ - qi->d_match[ itb->second ] = TNode::null(); + qi->unsetMatch( p, itb->second ); qi->d_match_term[ itb->second ] = TNode::null(); Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl; } @@ -1779,7 +1853,7 @@ void MatchGen::setInvalid() { } bool MatchGen::isHandledBoolConnective( TNode n ) { - return n.getType().isBoolean() && TermDb::isBoolConnective( n.getKind() ); + return TermDb::isBoolConnective( n.getKind() ) && ( n.getKind()!=ITE || n.getType().isBoolean() ); } bool MatchGen::isHandledUfTerm( TNode n ) { @@ -1835,28 +1909,31 @@ void QuantConflictFind::registerQuantifier( Node q ) { if( d_quantEngine->hasOwnership( q, this ) ){ d_quants.push_back( q ); d_quant_id[q] = d_quants.size(); - Trace("qcf-qregister") << "Register "; - debugPrintQuant( "qcf-qregister", q ); - Trace("qcf-qregister") << " : " << q << std::endl; + if( Trace.isOn("qcf-qregister") ){ + Trace("qcf-qregister") << "Register "; + debugPrintQuant( "qcf-qregister", q ); + Trace("qcf-qregister") << " : " << q << std::endl; + } //make QcfNode structure Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl; d_qinfo[q].initialize( this, q, q[1] ); //debug print - Trace("qcf-qregister") << "- Flattened structure is :" << std::endl; - Trace("qcf-qregister") << " "; - debugPrintQuantBody( "qcf-qregister", q, q[1] ); - Trace("qcf-qregister") << std::endl; - if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){ - Trace("qcf-qregister") << " with additional constraints : " << std::endl; - for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){ - Trace("qcf-qregister") << " ?x" << j << " = "; - debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false ); - Trace("qcf-qregister") << std::endl; - } - } - - Trace("qcf-qregister") << "Done registering quantifier." << std::endl; + if( Trace.isOn("qcf-qregister") ){ + Trace("qcf-qregister") << "- Flattened structure is :" << std::endl; + Trace("qcf-qregister") << " "; + debugPrintQuantBody( "qcf-qregister", q, q[1] ); + Trace("qcf-qregister") << std::endl; + if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){ + Trace("qcf-qregister") << " with additional constraints : " << std::endl; + for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){ + Trace("qcf-qregister") << " ?x" << j << " = "; + debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false ); + Trace("qcf-qregister") << std::endl; + } + } + Trace("qcf-qregister") << "Done registering quantifier." << std::endl; + } } } @@ -1933,6 +2010,18 @@ void QuantConflictFind::reset_round( Theory::Effort level ) { d_needs_computeRelEqr = true; } +void QuantConflictFind::setIrrelevantFunction( TNode f ) { + if( d_irr_func.find( f )==d_irr_func.end() ){ + d_irr_func[f] = true; + std::map< TNode, std::vector< Node > >::iterator it = d_func_rel_dom.find( f ); + if( it != d_func_rel_dom.end()){ + for( unsigned j=0; j<it->second.size(); j++ ){ + d_irr_quant[it->second[j]] = true; + } + } + } +} + /** check */ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { if( quant_e==QuantifiersEngine::QEFFORT_CONFLICT ){ @@ -1955,14 +2044,9 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { } computeRelevantEqr(); - //determine order for quantified formulas - std::vector< Node > qorder; - for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ - Node q = d_quantEngine->getModel()->getAssertedQuantifier( i, true ); - if( d_quantEngine->hasOwnership( q, this ) ){ - qorder.push_back( q ); - } - } + d_irr_func.clear(); + d_irr_quant.clear(); + if( Trace.isOn("qcf-debug") ){ Trace("qcf-debug") << std::endl; debugPrint("qcf-debug"); @@ -1973,77 +2057,83 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { for( short e = effort_conflict; e<=end_e; e++ ){ d_effort = e; Trace("qcf-check") << "Checking quantified formulas at effort " << e << "..." << std::endl; - for( unsigned j=0; j<qorder.size(); j++ ){ - Node q = qorder[j]; - QuantInfo * qi = &d_qinfo[q]; - - Assert( d_qinfo.find( q )!=d_qinfo.end() ); - if( qi->matchGeneratorIsValid() ){ - Trace("qcf-check") << "Check quantified formula "; - debugPrintQuant("qcf-check", q); - Trace("qcf-check") << " : " << q << "..." << std::endl; - - Trace("qcf-check-debug") << "Reset round..." << std::endl; - qi->reset_round( this ); - //try to make a matches making the body false - Trace("qcf-check-debug") << "Get next match..." << std::endl; - while( qi->getNextMatch( this ) ){ - Trace("qcf-inst") << "*** Produced match at effort " << e << " : " << std::endl; - qi->debugPrintMatch("qcf-inst"); - Trace("qcf-inst") << std::endl; - std::vector< int > assigned; - if( !qi->isMatchSpurious( this ) ){ - if( qi->completeMatch( this, assigned ) ){ - std::vector< Node > terms; - qi->getMatch( terms ); - if( !qi->isTConstraintSpurious( this, terms ) ){ - //for debugging - if( Debug.isOn("qcf-check-inst") ){ - Node inst = d_quantEngine->getInstantiation( q, terms ); - Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl; - Assert( !getTermDatabase()->isEntailed( inst, true ) ); - Assert( getTermDatabase()->isEntailed( inst, false ) || e>effort_conflict ); - } - if( d_quantEngine->addInstantiation( q, terms ) ){ - Trace("qcf-check") << " ... Added instantiation" << std::endl; - Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl; - qi->debugPrintMatch("qcf-inst"); - Trace("qcf-inst") << std::endl; - ++addedLemmas; - if( e==effort_conflict ){ - d_quantEngine->markRelevant( q ); - ++(d_statistics.d_conflict_inst); - if( options::qcfAllConflict() ){ - isConflict = true; + for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){ + Node q = d_quantEngine->getModel()->getAssertedQuantifier( i, true ); + if( d_quantEngine->hasOwnership( q, this ) && d_irr_quant.find( q )==d_irr_quant.end() ){ + QuantInfo * qi = &d_qinfo[q]; + + Assert( d_qinfo.find( q )!=d_qinfo.end() ); + if( qi->matchGeneratorIsValid() ){ + Trace("qcf-check") << "Check quantified formula "; + debugPrintQuant("qcf-check", q); + Trace("qcf-check") << " : " << q << "..." << std::endl; + + Trace("qcf-check-debug") << "Reset round..." << std::endl; + if( qi->reset_round( this ) ){ + //try to make a matches making the body false + Trace("qcf-check-debug") << "Get next match..." << std::endl; + while( qi->getNextMatch( this ) ){ + Trace("qcf-inst") << "*** Produced match at effort " << e << " : " << std::endl; + qi->debugPrintMatch("qcf-inst"); + Trace("qcf-inst") << std::endl; + if( !qi->isMatchSpurious( this ) ){ + std::vector< int > assigned; + if( qi->completeMatch( this, assigned ) ){ + std::vector< Node > terms; + qi->getMatch( terms ); + bool tcs = qi->isTConstraintSpurious( this, terms ); + if( !tcs ){ + //for debugging + if( Debug.isOn("qcf-check-inst") ){ + Node inst = d_quantEngine->getInstantiation( q, terms ); + Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl; + Assert( !getTermDatabase()->isEntailed( inst, true ) ); + Assert( getTermDatabase()->isEntailed( inst, false ) || e>effort_conflict ); + } + if( d_quantEngine->addInstantiation( q, terms ) ){ + Trace("qcf-check") << " ... Added instantiation" << std::endl; + Trace("qcf-inst") << "*** Was from effort " << e << " : " << std::endl; + qi->debugPrintMatch("qcf-inst"); + Trace("qcf-inst") << std::endl; + ++addedLemmas; + if( e==effort_conflict ){ + d_quantEngine->markRelevant( q ); + ++(d_statistics.d_conflict_inst); + if( options::qcfAllConflict() ){ + isConflict = true; + }else{ + d_conflict.set( true ); + } + break; + }else if( e==effort_prop_eq ){ + d_quantEngine->markRelevant( q ); + ++(d_statistics.d_prop_inst); + } }else{ - d_conflict.set( true ); + Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl; + //this should only happen if the algorithm generates the same propagating instance twice this round + //in this case, break to avoid exponential behavior + break; } - break; - }else if( e==effort_prop_eq ){ - d_quantEngine->markRelevant( q ); - ++(d_statistics.d_prop_inst); + }else{ + Trace("qcf-inst") << " ... Spurious instantiation (match is T-inconsistent)" << std::endl; } + //clean up assigned + qi->revertMatch( this, assigned ); + d_tempCache.clear(); }else{ - Trace("qcf-inst") << " ... Failed to add instantiation" << std::endl; - //this should only happen if the algorithm generates the same propagating instance twice this round - //in this case, break to avoid exponential behavior - break; + Trace("qcf-inst") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl; } + }else{ + Trace("qcf-inst") << " ... Spurious instantiation (match is inconsistent)" << std::endl; } - //clean up assigned - qi->revertMatch( assigned ); - d_tempCache.clear(); - }else{ - Trace("qcf-inst") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl; } - }else{ - Trace("qcf-inst") << " ... Spurious instantiation (match is inconsistent)" << std::endl; + Trace("qcf-check") << "Done, conflict = " << d_conflict << std::endl; + if( d_conflict ){ + break; + } } } - Trace("qcf-check") << "Done, conflict = " << d_conflict << std::endl; - if( d_conflict ){ - break; - } } } if( addedLemmas>0 ){ @@ -2074,17 +2164,9 @@ void QuantConflictFind::check( Theory::Effort level, unsigned quant_e ) { void QuantConflictFind::computeRelevantEqr() { if( d_needs_computeRelEqr ){ d_needs_computeRelEqr = false; - Trace("qcf-check") << "Compute relevant equalities..." << std::endl; - //d_uf_terms.clear(); - //d_eqc_uf_terms.clear(); + Trace("qcf-check") << "Compute relevant equivalence classes..." << std::endl; d_eqcs.clear(); - //d_arg_reps.clear(); - //double clSet = 0; - //if( Trace.isOn("qcf-opt") ){ - // clSet = double(clock())/double(CLOCKS_PER_SEC); - //} - //now, store matches eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() ); while( !eqcs_i.isFinished() ){ Node r = (*eqcs_i); diff --git a/src/theory/quantifiers/quant_conflict_find.h b/src/theory/quantifiers/quant_conflict_find.h index 8b42b0916..47a66b1b1 100644..100755 --- a/src/theory/quantifiers/quant_conflict_find.h +++ b/src/theory/quantifiers/quant_conflict_find.h @@ -35,6 +35,7 @@ class MatchGen { private: //current children information int d_child_counter; + bool d_use_children; //children of this object std::vector< int > d_children_order; unsigned getNumChildren() { return d_children.size(); } @@ -61,7 +62,7 @@ private: std::map< int, Node > d_ground_eval; //determine variable order void determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars ); - void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ); + void collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars, std::map< Node, bool >& visited, bool& hasNested ); public: //type of the match generator enum { @@ -116,7 +117,16 @@ private: //for completing match std::vector< int > d_una_eqc_count; //optimization: track which arguments variables appear under UF terms in std::map< int, std::map< TNode, std::vector< unsigned > > > d_var_rel_dom; - void getPropagateVars( std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited ); + void getPropagateVars( QuantConflictFind * p, std::vector< TNode >& vars, TNode n, bool pol, std::map< TNode, bool >& visited ); + //optimization: number of variables set, to track when we can stop + std::map< int, bool > d_vars_set; + std::map< Node, bool > d_ground_terms; + std::vector< Node > d_extra_var; +public: + void setGroundSubterm( Node t ) { d_ground_terms[t] = true; } + bool isGroundSubterm( Node t ) { return d_ground_terms.find( t )!=d_ground_terms.end(); } + bool isBaseMatchComplete(); + bool isPropagatingInstance( QuantConflictFind * p, Node n ); public: QuantInfo(); ~QuantInfo(); @@ -146,7 +156,7 @@ public: } Node d_q; - void reset_round( QuantConflictFind * p ); + bool reset_round( QuantConflictFind * p ); public: //initialize void initialize( QuantConflictFind * p, Node q, Node qn ); @@ -161,12 +171,13 @@ public: bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false ); int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity ); int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove ); - bool setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep ); + bool setMatch( QuantConflictFind * p, int v, TNode n, bool isGroundRep, bool isGround ); + void unsetMatch( QuantConflictFind * p, int v ); bool isMatchSpurious( QuantConflictFind * p ); bool isTConstraintSpurious( QuantConflictFind * p, std::vector< Node >& terms ); bool entailmentTest( QuantConflictFind * p, Node lit, bool chEnt = true ); bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false ); - void revertMatch( std::vector< int >& assigned ); + void revertMatch( QuantConflictFind * p, std::vector< int >& assigned ); void debugPrintMatch( const char * c ); bool isConstrainedVar( int v ); public: @@ -184,6 +195,11 @@ private: std::map< Kind, Node > d_zero; //for storing nodes created during t-constraint solving (prevents memory leaks) std::vector< Node > d_tempCache; + //optimization: list of quantifiers that depend on ground function applications + std::map< TNode, std::vector< Node > > d_func_rel_dom; + std::map< TNode, bool > d_irr_func; + std::map< Node, bool > d_irr_quant; + void setIrrelevantFunction( TNode f ); private: std::map< Node, Node > d_op_node; int d_fid_count; diff --git a/src/theory/quantifiers/quant_equality_engine.cpp b/src/theory/quantifiers/quant_equality_engine.cpp index 3f89a799c..3f89a799c 100644..100755 --- a/src/theory/quantifiers/quant_equality_engine.cpp +++ b/src/theory/quantifiers/quant_equality_engine.cpp diff --git a/src/theory/quantifiers/quant_equality_engine.h b/src/theory/quantifiers/quant_equality_engine.h index 26654de4d..26654de4d 100644..100755 --- a/src/theory/quantifiers/quant_equality_engine.h +++ b/src/theory/quantifiers/quant_equality_engine.h diff --git a/src/theory/quantifiers/quant_split.cpp b/src/theory/quantifiers/quant_split.cpp index 9fb943e5e..5aff1a848 100644..100755 --- a/src/theory/quantifiers/quant_split.cpp +++ b/src/theory/quantifiers/quant_split.cpp @@ -48,11 +48,11 @@ void QuantDSplit::preRegisterQuantifier( Node q ) { }else{ int score = -1; if( options::quantDynamicSplit()==quantifiers::QUANT_DSPLIT_MODE_AGG ){ - score = dt.isUFinite() ? 1 : -1; + score = dt.isInterpretedFinite() ? 1 : -1; }else if( options::quantDynamicSplit()==quantifiers::QUANT_DSPLIT_MODE_DEFAULT ){ - score = dt.isUFinite() ? 1 : -1; + score = dt.isInterpretedFinite() ? 1 : -1; } - Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is score " << score << " (" << dt.isUFinite() << " " << dt.isFinite() << ")" << std::endl; + Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is score " << score << " (" << dt.isInterpretedFinite() << " " << dt.isFinite() << ")" << std::endl; if( score>max_score ){ max_index = i; max_score = score; diff --git a/src/theory/quantifiers/quant_split.h b/src/theory/quantifiers/quant_split.h index d36824998..d36824998 100644..100755 --- a/src/theory/quantifiers/quant_split.h +++ b/src/theory/quantifiers/quant_split.h diff --git a/src/theory/quantifiers/quant_util.cpp b/src/theory/quantifiers/quant_util.cpp index 3b7787a20..b9aab0236 100644..100755 --- a/src/theory/quantifiers/quant_util.cpp +++ b/src/theory/quantifiers/quant_util.cpp @@ -33,22 +33,15 @@ eq::EqualityEngine * QuantifiersModule::getEqualityEngine() { } bool QuantifiersModule::areEqual( TNode n1, TNode n2 ) { - eq::EqualityEngine * ee = getEqualityEngine(); - return n1==n2 || ( ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areEqual( n1, n2 ) ); + return d_quantEngine->getEqualityQuery()->areEqual( n1, n2 ); } bool QuantifiersModule::areDisequal( TNode n1, TNode n2 ) { - eq::EqualityEngine * ee = getEqualityEngine(); - return n1!=n2 && ee->hasTerm( n1 ) && ee->hasTerm( n2 ) && ee->areDisequal( n1, n2, false ); + return d_quantEngine->getEqualityQuery()->areDisequal( n1, n2 ); } TNode QuantifiersModule::getRepresentative( TNode n ) { - eq::EqualityEngine * ee = getEqualityEngine(); - if( ee->hasTerm( n ) ){ - return ee->getRepresentative( n ); - }else{ - return n; - } + return d_quantEngine->getEqualityQuery()->getRepresentative( n ); } quantifiers::TermDb * QuantifiersModule::getTermDatabase() { @@ -389,7 +382,7 @@ void QuantPhaseReq::computePhaseReqs( Node n, bool polarity, std::map< Node, int } void QuantPhaseReq::getPolarity( Node n, int child, bool hasPol, bool pol, bool& newHasPol, bool& newPol ) { - if( n.getKind()==AND || n.getKind()==OR ){ + if( n.getKind()==AND || n.getKind()==OR || n.getKind()==SEP_STAR ){ newHasPol = hasPol; newPol = pol; }else if( n.getKind()==IMPLIES ){ diff --git a/src/theory/quantifiers/quant_util.h b/src/theory/quantifiers/quant_util.h index 79cdae437..79cdae437 100644..100755 --- a/src/theory/quantifiers/quant_util.h +++ b/src/theory/quantifiers/quant_util.h diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp index b797f4ce9..b797f4ce9 100644..100755 --- a/src/theory/quantifiers/quantifiers_attributes.cpp +++ b/src/theory/quantifiers/quantifiers_attributes.cpp diff --git a/src/theory/quantifiers/quantifiers_attributes.h b/src/theory/quantifiers/quantifiers_attributes.h index 53cef796a..53cef796a 100644..100755 --- a/src/theory/quantifiers/quantifiers_attributes.h +++ b/src/theory/quantifiers/quantifiers_attributes.h diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp index 5aae4d640..68f824c57 100644..100755 --- a/src/theory/quantifiers/quantifiers_rewriter.cpp +++ b/src/theory/quantifiers/quantifiers_rewriter.cpp @@ -48,7 +48,7 @@ bool QuantifiersRewriter::isClause( Node n ){ bool QuantifiersRewriter::isLiteral( Node n ){ switch( n.getKind() ){ case NOT: - return isLiteral( n[0] ); + return n[0].getKind()!=NOT && isLiteral( n[0] ); break; case OR: case AND: @@ -59,7 +59,8 @@ bool QuantifiersRewriter::isLiteral( Node n ){ return false; break; case EQUAL: - return n[0].getType()!=NodeManager::currentNM()->booleanType(); + //for boolean terms + return !n[0].getType().isBoolean(); break; default: break; @@ -185,19 +186,10 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) { if( in.getKind()==kind::EXISTS || in.getKind()==kind::FORALL ){ Trace("quantifiers-rewrite-debug") << "pre-rewriting " << in << std::endl; std::vector< Node > args; - for( int i=0; i<(int)in[0].getNumChildren(); i++ ){ - args.push_back( in[0][i] ); - } - Node body = in[1]; + Node body = in; bool doRewrite = false; - std::vector< Node > ipl; - while( body.getNumChildren()>=2 && body.getKind()==in.getKind() ){ - if( body.getNumChildren()==3 ){ - for( unsigned i=0; i<body[2].getNumChildren(); i++ ){ - ipl.push_back( body[2][i] ); - } - } - for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ + while( body.getNumChildren()==2 && body.getKind()==body[1].getKind() ){ + for( unsigned i=0; i<body[0].getNumChildren(); i++ ){ args.push_back( body[0][i] ); } body = body[1]; @@ -205,16 +197,11 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) { } if( doRewrite ){ std::vector< Node > children; + for( unsigned i=0; i<body[0].getNumChildren(); i++ ){ + args.push_back( body[0][i] ); + } children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST,args) ); - children.push_back( body ); - if( in.getNumChildren()==3 ){ - for( unsigned i=0; i<in[2].getNumChildren(); i++ ){ - ipl.push_back( in[2][i] ); - } - } - if( !ipl.empty() ){ - children.push_back( NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, ipl ) ); - } + children.push_back( body[1] ); Node n = NodeManager::currentNM()->mkNode( in.getKind(), children ); if( in!=n ){ Trace("quantifiers-pre-rewrite") << "*** pre-rewrite " << in << std::endl; @@ -244,7 +231,7 @@ RewriteResponse QuantifiersRewriter::postRewrite(TNode in) { ret = ret.negate(); status = REWRITE_AGAIN_FULL; }else if( in.getKind()==FORALL ){ - if( in[1].isConst() ){ + if( in[1].isConst() && in.getNumChildren()==2 ){ return RewriteResponse( status, in[1] ); }else{ //compute attributes @@ -273,121 +260,98 @@ RewriteResponse QuantifiersRewriter::postRewrite(TNode in) { return RewriteResponse( status, ret ); } -Node QuantifiersRewriter::computeElimSymbols( Node body ) { - if( isLiteral( body ) ){ - return body; - }else{ - bool childrenChanged = false; - Kind k = body.getKind(); - if( body.getKind()==IMPLIES ){ - k = OR; - childrenChanged = true; - }else if( body.getKind()==XOR ){ - k = IFF; +bool QuantifiersRewriter::addCheckElimChild( std::vector< Node >& children, Node c, Kind k, std::map< Node, bool >& lit_pol, bool& childrenChanged ){ + if( ( k==OR || k==AND ) && options::elimTautQuant() ){ + Node lit = c.getKind()==NOT ? c[0] : c; + bool pol = c.getKind()!=NOT; + std::map< Node, bool >::iterator it = lit_pol.find( lit ); + if( it==lit_pol.end() ){ + lit_pol[lit] = pol; + children.push_back( c ); + }else{ childrenChanged = true; - } - std::vector< Node > children; - std::map< Node, bool > lit_pol; - for( unsigned i=0; i<body.getNumChildren(); i++ ){ - Node c = computeElimSymbols( body[i] ); - if( i==0 && ( body.getKind()==IMPLIES || body.getKind()==XOR ) ){ - c = c.negate(); - } - if( ( k==OR || k==AND ) && options::elimTautQuant() ){ - Node lit = c.getKind()==NOT ? c[0] : c; - bool pol = c.getKind()!=NOT; - std::map< Node, bool >::iterator it = lit_pol.find( lit ); - if( it==lit_pol.end() ){ - lit_pol[lit] = pol; - children.push_back( c ); - }else{ - childrenChanged = true; - if( it->second!=pol ){ - return NodeManager::currentNM()->mkConst( k==OR ); - } - } - }else{ - children.push_back( c ); + if( it->second!=pol ){ + return false; } - childrenChanged = childrenChanged || c!=body[i]; - } - //if( body.getKind()==ITE && isLiteral( body[0] ) ){ - // ret = NodeManager::currentNM()->mkNode( AND, NodeManager::currentNM()->mkNode( OR, body[0].negate(), body[1] ), - // NodeManager::currentNM()->mkNode( OR, body[0], body[2] ) ); - //} - if( childrenChanged ){ - return ( children.size()==1 && k!=NOT ) ? children[0] : NodeManager::currentNM()->mkNode( k, children ); - }else{ - return body; } + }else{ + children.push_back( c ); } + return true; } -Node QuantifiersRewriter::computeNNF( Node body ){ - if( body.getKind()==NOT ){ +// eliminates IMPLIES/XOR, removes duplicates/infers tautologies of AND/OR, and computes NNF +Node QuantifiersRewriter::computeElimSymbols( Node body ) { + Kind ok = body.getKind(); + Kind k = ok; + bool negAllCh = false; + bool negCh1 = false; + if( ok==IMPLIES ){ + k = OR; + negCh1 = true; + }else if( ok==XOR ){ + k = IFF; + negCh1 = true; + }else if( ok==NOT ){ if( body[0].getKind()==NOT ){ - return computeNNF( body[0][0] ); - }else if( isLiteral( body[0] ) ){ - return body; + return computeElimSymbols( body[0][0] ); + }else if( body[0].getKind()==OR || body[0].getKind()==IMPLIES ){ + k = AND; + negAllCh = true; + negCh1 = body[0].getKind()==IMPLIES; + body = body[0]; + }else if( body[0].getKind()==AND ){ + k = OR; + negAllCh = true; + body = body[0]; + }else if( body[0].getKind()==XOR || body[0].getKind()==IFF ){ + k = IFF; + negCh1 = ( body[0].getKind()==IFF ); + body = body[0]; + }else if( body[0].getKind()==ITE ){ + k = body[0].getKind(); + negAllCh = true; + negCh1 = true; + body = body[0]; }else{ - std::vector< Node > children; - Kind k = body[0].getKind(); - - if( body[0].getKind()==OR || body[0].getKind()==AND ){ - k = body[0].getKind()==AND ? OR : AND; - for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ - Node nc = computeNNF( body[0][i].notNode() ); - if( nc.getKind()==k ){ - for( unsigned j=0; j<nc.getNumChildren(); j++ ){ - children.push_back( nc[j] ); - } - }else{ - children.push_back( nc ); - } - } - }else if( body[0].getKind()==IFF ){ - for( int i=0; i<2; i++ ){ - Node nn = i==0 ? body[0][i] : body[0][i].notNode(); - children.push_back( computeNNF( nn ) ); - } - }else if( body[0].getKind()==ITE ){ - for( int i=0; i<3; i++ ){ - Node nn = i==0 ? body[0][i] : body[0][i].notNode(); - children.push_back( computeNNF( nn ) ); - } - }else{ - Notice() << "Unhandled Quantifiers NNF: " << body << std::endl; - return body; - } - return NodeManager::currentNM()->mkNode( k, children ); + return body; } - }else if( isLiteral( body ) ){ + }else if( ok!=IFF && ok!=ITE && ok!=AND && ok!=OR ){ + //a literal return body; - }else{ - std::vector< Node > children; - bool childrenChanged = false; - bool isAssoc = body.getKind()==AND || body.getKind()==OR; - for( int i=0; i<(int)body.getNumChildren(); i++ ){ - Node nc = computeNNF( body[i] ); - if( isAssoc && nc.getKind()==body.getKind() ){ - for( unsigned j=0; j<nc.getNumChildren(); j++ ){ - children.push_back( nc[j] ); + } + bool childrenChanged = false; + std::vector< Node > children; + std::map< Node, bool > lit_pol; + for( unsigned i=0; i<body.getNumChildren(); i++ ){ + Node c = computeElimSymbols( ( i==0 && negCh1 )!=negAllCh ? body[i].negate() : body[i] ); + bool success = true; + if( c.getKind()==k && ( k==OR || k==AND ) ){ + //flatten + childrenChanged = true; + for( unsigned j=0; j<c.getNumChildren(); j++ ){ + if( !addCheckElimChild( children, c[j], k, lit_pol, childrenChanged ) ){ + success = false; + break; } - childrenChanged = true; - }else{ - children.push_back( nc ); - childrenChanged = childrenChanged || nc!=body[i]; } - } - if( childrenChanged ){ - return NodeManager::currentNM()->mkNode( body.getKind(), children ); }else{ - return body; + success = addCheckElimChild( children, c, k, lit_pol, childrenChanged ); } + if( !success ){ + // tautology + Assert( k==OR || k==AND ); + return NodeManager::currentNM()->mkConst( k==OR ); + } + childrenChanged = childrenChanged || c!=body[i]; + } + if( childrenChanged || k!=ok ){ + return ( children.size()==1 && k!=NOT ) ? children[0] : NodeManager::currentNM()->mkNode( k, children ); + }else{ + return body; } } - void QuantifiersRewriter::computeDtTesterIteSplit( Node n, std::map< Node, Node >& pcons, std::map< Node, std::map< int, Node > >& ncons, std::vector< Node >& conj ){ if( n.getKind()==ITE && n[0].getKind()==APPLY_TESTER && n[1].getType().isBoolean() ){ @@ -463,6 +427,8 @@ int getEntailedCond( Node n, std::map< Node, bool >& currCond ){ std::map< Node, bool >::iterator it = currCond.find( n ); if( it!=currCond.end() ){ return it->second ? 1 : -1; + }else if( n.getKind()==NOT ){ + return -getEntailedCond( n[0], currCond ); }else if( n.getKind()==AND || n.getKind()==OR ){ bool hasZero = false; for( unsigned i=0; i<n.getNumChildren(); i++ ){ @@ -483,8 +449,7 @@ int getEntailedCond( Node n, std::map< Node, bool >& currCond ){ }else if( res==-1 ){ return getEntailedCond( n[2], currCond ); } - } - if( n.getKind()==IFF || n.getKind()==ITE ){ + }else if( n.getKind()==IFF || n.getKind()==ITE ){ unsigned start = n.getKind()==IFF ? 0 : 1; int res1 = 0; for( unsigned j=start; j<=(start+1); j++ ){ @@ -1049,144 +1014,6 @@ Node QuantifiersRewriter::computeVarElimination( Node body, std::vector< Node >& return body; } -Node QuantifiersRewriter::computeClause( Node n ){ - Assert( isClause( n ) ); - if( isLiteral( n ) ){ - return n; - }else{ - NodeBuilder<> t(OR); - if( n.getKind()==NOT ){ - if( n[0].getKind()==NOT ){ - return computeClause( n[0][0] ); - }else{ - //De-Morgan's law - Assert( n[0].getKind()==AND ); - for( int i=0; i<(int)n[0].getNumChildren(); i++ ){ - Node nn = computeClause( n[0][i].notNode() ); - addNodeToOrBuilder( nn, t ); - } - } - }else{ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - Node nn = computeClause( n[i] ); - addNodeToOrBuilder( nn, t ); - } - } - return t.constructNode(); - } -} - -Node QuantifiersRewriter::computeCNF( Node n, std::vector< Node >& args, NodeBuilder<>& defs, bool forcePred ){ - if( isLiteral( n ) ){ - return n; - }else if( !forcePred && isClause( n ) ){ - return computeClause( n ); - }else{ - Kind k = n.getKind(); - NodeBuilder<> t(k); - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - Node nc = n[i]; - Node ncnf = computeCNF( nc, args, defs, k!=OR ); - if( k==OR ){ - addNodeToOrBuilder( ncnf, t ); - }else{ - t << ncnf; - } - } - if( !forcePred && k==OR ){ - return t.constructNode(); - }else{ - //compute the free variables - Node nt = t; - std::vector< Node > activeArgs; - computeArgVec( args, activeArgs, nt ); - std::vector< TypeNode > argTypes; - for( int i=0; i<(int)activeArgs.size(); i++ ){ - argTypes.push_back( activeArgs[i].getType() ); - } - //create the predicate - Assert( argTypes.size()>0 ); - TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, NodeManager::currentNM()->booleanType() ); - std::stringstream ss; - ss << "cnf_" << n.getKind() << "_" << n.getId(); - Node op = NodeManager::currentNM()->mkSkolem( ss.str(), typ, "was created by the quantifiers rewriter" ); - std::vector< Node > predArgs; - predArgs.push_back( op ); - predArgs.insert( predArgs.end(), activeArgs.begin(), activeArgs.end() ); - Node pred = NodeManager::currentNM()->mkNode( APPLY_UF, predArgs ); - Trace("quantifiers-rewrite-cnf-debug") << "Made predicate " << pred << " for " << nt << std::endl; - //create the bound var list - Node bvl = NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, activeArgs ); - //now, look at the structure of nt - if( nt.getKind()==NOT ){ - //case for NOT - for( int i=0; i<2; i++ ){ - NodeBuilder<> tt(OR); - tt << ( i==0 ? nt[0].notNode() : nt[0] ); - tt << ( i==0 ? pred.notNode() : pred ); - defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); - } - }else if( nt.getKind()==OR ){ - //case for OR - for( int i=0; i<(int)nt.getNumChildren(); i++ ){ - NodeBuilder<> tt(OR); - tt << nt[i].notNode() << pred; - defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); - } - NodeBuilder<> tt(OR); - for( int i=0; i<(int)nt.getNumChildren(); i++ ){ - tt << nt[i]; - } - tt << pred.notNode(); - defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); - }else if( nt.getKind()==AND ){ - //case for AND - for( int i=0; i<(int)nt.getNumChildren(); i++ ){ - NodeBuilder<> tt(OR); - tt << nt[i] << pred.notNode(); - defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); - } - NodeBuilder<> tt(OR); - for( int i=0; i<(int)nt.getNumChildren(); i++ ){ - tt << nt[i].notNode(); - } - tt << pred; - defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); - }else if( nt.getKind()==IFF ){ - //case for IFF - for( int i=0; i<4; i++ ){ - NodeBuilder<> tt(OR); - tt << ( ( i==0 || i==3 ) ? nt[0].notNode() : nt[0] ); - tt << ( ( i==1 || i==3 ) ? nt[1].notNode() : nt[1] ); - tt << ( ( i==0 || i==1 ) ? pred.notNode() : pred ); - defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); - } - }else if( nt.getKind()==ITE ){ - //case for ITE - for( int j=1; j<=2; j++ ){ - for( int i=0; i<2; i++ ){ - NodeBuilder<> tt(OR); - tt << ( ( j==1 ) ? nt[0].notNode() : nt[0] ); - tt << ( ( i==1 ) ? nt[j].notNode() : nt[j] ); - tt << ( ( i==0 ) ? pred.notNode() : pred ); - defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); - } - } - for( int i=0; i<2; i++ ){ - NodeBuilder<> tt(OR); - tt << ( i==0 ? nt[1].notNode() : nt[1] ); - tt << ( i==0 ? nt[2].notNode() : nt[2] ); - tt << ( i==1 ? pred.notNode() : pred ); - defs << NodeManager::currentNM()->mkNode( FORALL, bvl, tt.constructNode() ); - } - }else{ - Notice() << "Unhandled Quantifiers CNF: " << nt << std::endl; - } - return pred; - } - } -} - Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, bool pol ){ if( body.getKind()==FORALL ){ if( pol && ( options::prenexQuant()==PRENEX_ALL || body.getNumChildren()==2 ) ){ @@ -1194,15 +1021,13 @@ Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, b std::vector< Node > subs; //for doing prenexing of same-signed quantifiers //must rename each variable that already exists - for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ - //if( std::find( args.begin(), args.end(), body[0][i] )!=args.end() ){ + for( unsigned i=0; i<body[0].getNumChildren(); i++ ){ terms.push_back( body[0][i] ); subs.push_back( NodeManager::currentNM()->mkBoundVar( body[0][i].getType() ) ); } args.insert( args.end(), subs.begin(), subs.end() ); Node newBody = body[1]; newBody = newBody.substitute( terms.begin(), terms.end(), subs.begin(), subs.end() ); - Debug("quantifiers-substitute-debug") << "Did substitute have an effect" << (body[1] != newBody) << body[1] << " became " << newBody << endl; return newBody; }else{ return body; @@ -1211,7 +1036,7 @@ Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, b Assert( body.getKind()!=EXISTS ); bool childrenChanged = false; std::vector< Node > newChildren; - for( int i=0; i<(int)body.getNumChildren(); i++ ){ + for( unsigned i=0; i<body.getNumChildren(); i++ ){ bool newHasPol; bool newPol; QuantPhaseReq::getPolarity( body, i, true, pol, newHasPol, newPol ); @@ -1237,7 +1062,7 @@ Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, b } } -Node QuantifiersRewriter::computeSplit( Node f, std::vector< Node >& args, Node body ) { +Node QuantifiersRewriter::computeSplit( std::vector< Node >& args, Node body, QAttributes& qa ) { Assert( body.getKind()==OR ); size_t var_found_count = 0; size_t eqc_count = 0; @@ -1253,8 +1078,8 @@ Node QuantifiersRewriter::computeSplit( Node f, std::vector< Node >& args, Node Node n = body[i]; std::vector< Node > lit_args; computeArgVec( args, lit_args, n ); - if (lit_args.empty()) { - lits.push_back(n); + if( lit_args.empty() ){ + lits.push_back( n ); }else { //collect the equivalence classes this literal belongs to, and the new variables it contributes std::vector< int > eqcs; @@ -1306,8 +1131,8 @@ Node QuantifiersRewriter::computeSplit( Node f, std::vector< Node >& args, Node eqc_to_lit[eqcz].push_back(n); } } - if ( eqc_active>1 || !lits.empty() ){ - Trace("clause-split-debug") << "Split clause " << f << std::endl; + if ( eqc_active>1 || !lits.empty() || var_to_eqc.size()!=args.size() ){ + Trace("clause-split-debug") << "Split quantified formula with body " << body << std::endl; Trace("clause-split-debug") << " Ground literals: " << std::endl; for( size_t i=0; i<lits.size(); i++) { Trace("clause-split-debug") << " " << lits[i] << std::endl; @@ -1330,27 +1155,21 @@ Node QuantifiersRewriter::computeSplit( Node f, std::vector< Node >& args, Node Node fa = NodeManager::currentNM()->mkNode( FORALL, bvl, body ); lits.push_back(fa); } - Assert( lits.size()>1 ); - Node nf = NodeManager::currentNM()->mkNode(OR,lits); + Assert( !lits.empty() ); + Node nf = lits.size()==1 ? lits[0] : NodeManager::currentNM()->mkNode(OR,lits); Trace("clause-split-debug") << "Made node : " << nf << std::endl; return nf; + }else{ + return mkForAll( args, body, qa ); } - return f; } Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, QAttributes& qa ){ - std::vector< Node > activeArgs; - //if cegqi is on, may be synthesis conjecture, in which case we want to keep all variables - if( options::ceGuidedInst() && qa.d_sygus ){ - activeArgs.insert( activeArgs.end(), args.begin(), args.end() ); - }else{ - computeArgVec2( args, activeArgs, body, qa.d_ipl ); - } - if( activeArgs.empty() ){ + if( args.empty() ){ return body; }else{ std::vector< Node > children; - children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, activeArgs ) ); + children.push_back( NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, args ) ); children.push_back( body ); if( !qa.d_ipl.isNull() ){ children.push_back( qa.d_ipl ); @@ -1359,82 +1178,59 @@ Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, QAttri } } -Node QuantifiersRewriter::computeMiniscoping( Node f, std::vector< Node >& args, Node body, QAttributes& qa ){ +//computes miniscoping, also eliminates variables that do not occur free in body +Node QuantifiersRewriter::computeMiniscoping( std::vector< Node >& args, Node body, QAttributes& qa ){ if( body.getKind()==FORALL ){ - //combine arguments + //combine prenex std::vector< Node > newArgs; - for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ + newArgs.insert( newArgs.end(), args.begin(), args.end() ); + for( unsigned i=0; i<body[0].getNumChildren(); i++ ){ newArgs.push_back( body[0][i] ); } - newArgs.insert( newArgs.end(), args.begin(), args.end() ); - return mkForAll( newArgs, body[ 1 ], qa ); - }else{ - if( body.getKind()==NOT ){ - //push not downwards - if( body[0].getKind()==NOT ){ - return computeMiniscoping( f, args, body[0][0], qa ); - }else if( body[0].getKind()==AND ){ - if( options::miniscopeQuantFreeVar() ){ - NodeBuilder<> t(kind::OR); - for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ - t << ( body[0][i].getKind()==NOT ? body[0][i][0] : body[0][i].notNode() ); - } - return computeMiniscoping( f, args, t.constructNode(), qa ); - } - }else if( body[0].getKind()==OR ){ - if( options::miniscopeQuant() ){ - NodeBuilder<> t(kind::AND); - for( int i=0; i<(int)body[0].getNumChildren(); i++ ){ - Node trm = body[0][i].negate(); - t << computeMiniscoping( f, args, trm, qa ); - } - return t.constructNode(); + return mkForAll( newArgs, body[1], qa ); + }else if( body.getKind()==AND ){ + if( options::miniscopeQuant() ){ + //break apart + NodeBuilder<> t(kind::AND); + for( unsigned i=0; i<body.getNumChildren(); i++ ){ + t << computeMiniscoping( args, body[i], qa ); + } + Node retVal = t; + return retVal; + } + }else if( body.getKind()==OR ){ + if( options::quantSplit() ){ + //splitting subsumes free variable miniscoping, apply it with higher priority + return computeSplit( args, body, qa ); + }else if( options::miniscopeQuantFreeVar() ){ + Node newBody = body; + NodeBuilder<> body_split(kind::OR); + NodeBuilder<> tb(kind::OR); + for( unsigned i=0; i<body.getNumChildren(); i++ ){ + Node trm = body[i]; + if( TermDb::containsTerms( body[i], args ) ){ + tb << trm; + }else{ + body_split << trm; } } - }else if( body.getKind()==AND ){ - if( options::miniscopeQuant() ){ - //break apart - NodeBuilder<> t(kind::AND); - for( unsigned i=0; i<body.getNumChildren(); i++ ){ - t << computeMiniscoping( f, args, body[i], qa ); - } - Node retVal = t; - return retVal; - } - }else if( body.getKind()==OR ){ - if( options::quantSplit() ){ - //splitting subsumes free variable miniscoping, apply it with higher priority - Node nf = computeSplit( f, args, body ); - if( nf!=f ){ - return nf; - } - }else if( options::miniscopeQuantFreeVar() ){ - Node newBody = body; - NodeBuilder<> body_split(kind::OR); - NodeBuilder<> tb(kind::OR); - for( unsigned i=0; i<body.getNumChildren(); i++ ){ - Node trm = body[i]; - if( TermDb::containsTerms( body[i], args ) ){ - tb << trm; - }else{ - body_split << trm; - } - } - if( tb.getNumChildren()==0 ){ - return body_split; - }else if( body_split.getNumChildren()>0 ){ - newBody = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb; - body_split << mkForAll( args, newBody, qa ); - return body_split.getNumChildren()==1 ? body_split.getChild( 0 ) : body_split; - } + if( tb.getNumChildren()==0 ){ + return body_split; + }else if( body_split.getNumChildren()>0 ){ + newBody = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb; + std::vector< Node > activeArgs; + computeArgVec2( args, activeArgs, newBody, qa.d_ipl ); + body_split << mkForAll( activeArgs, newBody, qa ); + return body_split.getNumChildren()==1 ? body_split.getChild( 0 ) : body_split; } } + }else if( body.getKind()==NOT ){ + Assert( isLiteral( body[0] ) ); } - //if( body==f[1] ){ - // return f; - //}else{ - return mkForAll( args, body, qa ); - //} + //remove variables that don't occur + std::vector< Node > activeArgs; + computeArgVec2( args, activeArgs, body, qa.d_ipl ); + return mkForAll( activeArgs, body, qa ); } Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& args, Node body ){ @@ -1552,19 +1348,14 @@ bool QuantifiersRewriter::doOperation( Node q, int computeOption, QAttributes& q return is_std; }else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){ return options::aggressiveMiniscopeQuant() && is_std; - }else if( computeOption==COMPUTE_NNF ){ - return true; }else if( computeOption==COMPUTE_PROCESS_TERMS ){ - return true; - //return options::iteLiftQuant()!=ITE_LIFT_QUANT_MODE_NONE || options::iteCondVarSplitQuant(); + return options::condRewriteQuant(); }else if( computeOption==COMPUTE_COND_SPLIT ){ return ( options::iteDtTesterSplitQuant() || options::condVarSplitQuant() ) && !is_strict_trigger; }else if( computeOption==COMPUTE_PRENEX ){ return options::prenexQuant()!=PRENEX_NONE && !options::aggressiveMiniscopeQuant() && is_std; }else if( computeOption==COMPUTE_VAR_ELIMINATION ){ return ( options::varElimQuant() || options::dtVarExpandQuant() || options::purifyQuant() ) && is_std; - //}else if( computeOption==COMPUTE_CNF ){ - // return options::cnfQuant(); }else if( computeOption==COMPUTE_PURIFY_EXPAND ){ return options::purifyQuant() && is_std; }else{ @@ -1584,11 +1375,9 @@ Node QuantifiersRewriter::computeOperation( Node f, int computeOption, QAttribut n = computeElimSymbols( n ); }else if( computeOption==COMPUTE_MINISCOPING ){ //return directly - return computeMiniscoping( f, args, n, qa ); + return computeMiniscoping( args, n, qa ); }else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){ return computeAggressiveMiniscoping( args, n ); - }else if( computeOption==COMPUTE_NNF ){ - n = computeNNF( n ); }else if( computeOption==COMPUTE_PROCESS_TERMS ){ std::vector< Node > new_conds; n = computeProcessTerms( n, args, new_conds, f, qa ); @@ -1602,9 +1391,6 @@ Node QuantifiersRewriter::computeOperation( Node f, int computeOption, QAttribut n = computePrenex( n, args, true ); }else if( computeOption==COMPUTE_VAR_ELIMINATION ){ n = computeVarElimination( n, args, qa ); - //}else if( computeOption==COMPUTE_CNF ){ - //n = computeCNF( n, args, defs, false ); - //ipl = Node::null(); }else if( computeOption==COMPUTE_PURIFY_EXPAND ){ std::vector< Node > conj; computePurifyExpand( n, conj, args, qa ); @@ -1738,15 +1524,15 @@ struct ContainsQuantAttributeId {}; typedef expr::Attribute<ContainsQuantAttributeId, uint64_t> ContainsQuantAttribute; // check if the given node contains a universal quantifier -bool QuantifiersRewriter::containsQuantifiers(Node n) { +bool QuantifiersRewriter::containsQuantifiers( Node n ){ if( n.hasAttribute(ContainsQuantAttribute()) ){ return n.getAttribute(ContainsQuantAttribute())==1; - } else if(n.getKind() == kind::FORALL) { + }else if( n.getKind() == kind::FORALL ){ return true; - } else { + }else{ bool cq = false; for( unsigned i = 0; i < n.getNumChildren(); ++i ){ - if( containsQuantifiers(n[i]) ){ + if( containsQuantifiers( n[i] ) ){ cq = true; break; } diff --git a/src/theory/quantifiers/quantifiers_rewriter.h b/src/theory/quantifiers/quantifiers_rewriter.h index 2071d1793..776517109 100644..100755 --- a/src/theory/quantifiers/quantifiers_rewriter.h +++ b/src/theory/quantifiers/quantifiers_rewriter.h @@ -38,6 +38,7 @@ public: static int getPurifyId( Node n ); static int getPurifyIdLit( Node n ); private: + static bool addCheckElimChild( std::vector< Node >& children, Node c, Kind k, std::map< Node, bool >& lit_pol, bool& childrenChanged ); static void addNodeToOrBuilder( Node n, NodeBuilder<>& t ); static Node mkForAll( std::vector< Node >& args, Node body, QAttributes& qa ); static void computeArgs( std::vector< Node >& args, std::map< Node, bool >& activeMap, Node n, std::map< Node, bool >& visited ); @@ -46,7 +47,6 @@ private: static Node computeProcessTerms2( Node body, bool hasPol, bool pol, std::map< Node, bool >& currCond, int nCurrCond, std::map< Node, Node >& cache, std::map< Node, Node >& icache, std::vector< Node >& new_vars, std::vector< Node >& new_conds ); - static Node computeClause( Node n ); static void computeDtTesterIteSplit( Node n, std::map< Node, Node >& pcons, std::map< Node, std::map< int, Node > >& ncons, std::vector< Node >& conj ); static bool isConditionalVariableElim( Node n, int pol=0 ); static bool isVariableElim( Node v, Node s, std::map< Node, std::vector< int > >& var_parent ); @@ -57,15 +57,13 @@ private: static Node computeVarElimination2( Node body, std::vector< Node >& args, QAttributes& qa, std::map< Node, std::vector< int > >& var_parent ); private: static Node computeElimSymbols( Node body ); - static Node computeMiniscoping( Node f, std::vector< Node >& args, Node body, QAttributes& qa ); + static Node computeMiniscoping( std::vector< Node >& args, Node body, QAttributes& qa ); static Node computeAggressiveMiniscoping( std::vector< Node >& args, Node body ); - static Node computeNNF( Node body ); //cache is dependent upon currCond, icache is not, new_conds are negated conditions static Node computeProcessTerms( Node body, std::vector< Node >& new_vars, std::vector< Node >& new_conds, Node q, QAttributes& qa ); static Node computeCondSplit( Node body, QAttributes& qa ); - static Node computeCNF( Node body, std::vector< Node >& args, NodeBuilder<>& defs, bool forcePred ); static Node computePrenex( Node body, std::vector< Node >& args, bool pol ); - static Node computeSplit( Node f, std::vector< Node >& args, Node body ); + static Node computeSplit( std::vector< Node >& args, Node body, QAttributes& qa ); static Node computeVarElimination( Node body, std::vector< Node >& args, QAttributes& qa ); static Node computePurify( Node body, std::vector< Node >& args, std::map< Node, std::vector< int > >& var_parent ); static void computePurifyExpand( Node body, std::vector< Node >& conj, std::vector< Node >& args, QAttributes& qa ); @@ -74,7 +72,6 @@ private: COMPUTE_ELIM_SYMBOLS = 0, COMPUTE_MINISCOPING, COMPUTE_AGGRESSIVE_MINISCOPING, - COMPUTE_NNF, COMPUTE_PROCESS_TERMS, COMPUTE_PRENEX, COMPUTE_VAR_ELIMINATION, diff --git a/src/theory/quantifiers/relevant_domain.cpp b/src/theory/quantifiers/relevant_domain.cpp index b353fce2f..b4b51fd84 100644..100755 --- a/src/theory/quantifiers/relevant_domain.cpp +++ b/src/theory/quantifiers/relevant_domain.cpp @@ -110,7 +110,7 @@ void RelevantDomain::compute(){ for( unsigned i=0; i<sz; i++ ){ Node n = it->second[i]; //if it is a non-redundant term - if( !n.getAttribute(NoMatchAttribute()) ){ + if( db->isTermActive( n ) ){ for( unsigned j=0; j<n.getNumChildren(); j++ ){ RDomain * rf = getRDomain( op, j ); rf->addTerm( n[j] ); diff --git a/src/theory/quantifiers/relevant_domain.h b/src/theory/quantifiers/relevant_domain.h index 2b90520fd..2b90520fd 100644..100755 --- a/src/theory/quantifiers/relevant_domain.h +++ b/src/theory/quantifiers/relevant_domain.h diff --git a/src/theory/quantifiers/rewrite_engine.cpp b/src/theory/quantifiers/rewrite_engine.cpp index 5365dbcfa..2c58b8f77 100644..100755 --- a/src/theory/quantifiers/rewrite_engine.cpp +++ b/src/theory/quantifiers/rewrite_engine.cpp @@ -175,7 +175,7 @@ int RewriteEngine::checkRewriteRule( Node f, Theory::Effort e ) { for( unsigned j=0; j<to_remove.size(); j++ ){ Node ns = d_quantEngine->getSubstitute( to_remove[j], inst ); Trace("rewrite-engine-inst-debug") << "Will remove : " << ns << std::endl; - ns.setAttribute(NoMatchAttribute(),true); + d_quantEngine->getTermDatabase()->setTermInactive( ns ); } */ }else{ diff --git a/src/theory/quantifiers/rewrite_engine.h b/src/theory/quantifiers/rewrite_engine.h index 424530696..424530696 100644..100755 --- a/src/theory/quantifiers/rewrite_engine.h +++ b/src/theory/quantifiers/rewrite_engine.h diff --git a/src/theory/quantifiers/symmetry_breaking.cpp b/src/theory/quantifiers/symmetry_breaking.cpp index 2a2b13583..2a2b13583 100644..100755 --- a/src/theory/quantifiers/symmetry_breaking.cpp +++ b/src/theory/quantifiers/symmetry_breaking.cpp diff --git a/src/theory/quantifiers/symmetry_breaking.h b/src/theory/quantifiers/symmetry_breaking.h index 38fea4f45..e682955e7 100644..100755 --- a/src/theory/quantifiers/symmetry_breaking.h +++ b/src/theory/quantifiers/symmetry_breaking.h @@ -42,9 +42,7 @@ class SubsortSymmetryBreaker { typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap; typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap; typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap; - //typedef context::CDChunkList<int> IntList; typedef context::CDList<Node> NodeList; - typedef context::CDHashMap<Node, NodeList*, NodeHashFunction> NodeListMap; private: /** quantifiers engine */ QuantifiersEngine* d_qe; diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp index 8b09d8e5d..d3a5e178f 100644..100755 --- a/src/theory/quantifiers/term_database.cpp +++ b/src/theory/quantifiers/term_database.cpp @@ -84,13 +84,13 @@ void TermArgTrie::debugPrint( const char * c, Node n, unsigned depth ) { } } -TermDb::TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe ) : d_quantEngine( qe ), d_op_id_count( 0 ), d_typ_id_count( 0 ) { +TermDb::TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe ) : d_quantEngine( qe ), d_inactive_map( c ), d_op_id_count( 0 ), d_typ_id_count( 0 ) { d_true = NodeManager::currentNM()->mkConst( true ); d_false = NodeManager::currentNM()->mkConst( false ); d_zero = NodeManager::currentNM()->mkConst( Rational( 0 ) ); d_one = NodeManager::currentNM()->mkConst( Rational( 1 ) ); if( options::ceGuidedInst() ){ - d_sygus_tdb = new TermDbSygus; + d_sygus_tdb = new TermDbSygus( c, qe ); }else{ d_sygus_tdb = NULL; } @@ -163,9 +163,18 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant, bool wi //if this is an atomic trigger, consider adding it if( inst::Trigger::isAtomicTrigger( n ) ){ Trace("term-db") << "register term in db " << n << std::endl; + if( options::finiteModelFind() ){ + computeModelBasisArgAttribute( n ); + } + Node op = getMatchOperator( n ); + Trace("term-db-debug") << " match operator is : " << op << std::endl; d_op_map[op].push_back( n ); added.insert( n ); + + if( d_sygus_tdb ){ + d_sygus_tdb->registerEvalTerm( n ); + } if( options::eagerInstQuant() ){ for( unsigned i=0; i<n.getNumChildren(); i++ ){ @@ -178,6 +187,8 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant, bool wi } } } + }else{ + setTermInactive( n ); } rec = true; } @@ -210,7 +221,7 @@ void TermDb::computeUfEqcTerms( TNode f ) { for( unsigned i=0; i<d_op_map[f].size(); i++ ){ TNode n = d_op_map[f][i]; if( hasTermCurrent( n ) ){ - if( !n.getAttribute(NoMatchAttribute()) ){ + if( isTermActive( n ) ){ computeArgReps( n ); TNode r = ee->hasTerm( n ) ? ee->getRepresentative( n ) : n; d_func_map_eqc_trie[f].d_data[r].addTerm( n, d_arg_reps[n] ); @@ -220,7 +231,84 @@ void TermDb::computeUfEqcTerms( TNode f ) { } } +void TermDb::computeUfTerms( TNode f ) { + if( d_op_nonred_count.find( f )==d_op_nonred_count.end() ){ + d_op_nonred_count[ f ] = 0; + std::map< Node, std::vector< Node > >::iterator it = d_op_map.find( f ); + if( it!=d_op_map.end() ){ + eq::EqualityEngine* ee = d_quantEngine->getMasterEqualityEngine(); + Trace("term-db-debug") << "Adding terms for operator " << f << std::endl; + unsigned congruentCount = 0; + unsigned nonCongruentCount = 0; + unsigned alreadyCongruentCount = 0; + unsigned relevantCount = 0; + for( unsigned i=0; i<it->second.size(); i++ ){ + Node n = it->second[i]; + //to be added to term index, term must be relevant, and exist in EE + if( hasTermCurrent( n ) && ee->hasTerm( n ) ){ + relevantCount++; + if( isTermActive( n ) ){ + computeArgReps( n ); + + Trace("term-db-debug") << "Adding term " << n << " with arg reps : "; + for( unsigned i=0; i<d_arg_reps[n].size(); i++ ){ + Trace("term-db-debug") << d_arg_reps[n][i] << " "; + if( std::find( d_func_map_rel_dom[f][i].begin(), + d_func_map_rel_dom[f][i].end(), d_arg_reps[n][i] ) == d_func_map_rel_dom[f][i].end() ){ + d_func_map_rel_dom[f][i].push_back( d_arg_reps[n][i] ); + } + } + Trace("term-db-debug") << std::endl; + Trace("term-db-debug") << " and value : " << ee->getRepresentative( n ) << std::endl; + Node at = d_func_map_trie[ f ].addOrGetTerm( n, d_arg_reps[n] ); + Trace("term-db-debug2") << "...add term returned " << at << std::endl; + if( at!=n && ee->areEqual( at, n ) ){ + setTermInactive( n ); + Trace("term-db-debug") << n << " is redundant." << std::endl; + congruentCount++; + }else{ + if( at!=n && ee->areDisequal( at, n, false ) ){ + std::vector< Node > lits; + lits.push_back( NodeManager::currentNM()->mkNode( at.getType().isBoolean() ? IFF : EQUAL, at, n ) ); + for( unsigned i=0; i<at.getNumChildren(); i++ ){ + if( at[i]!=n[i] ){ + lits.push_back( NodeManager::currentNM()->mkNode( at[i].getType().isBoolean() ? IFF : EQUAL, at[i], n[i] ).negate() ); + } + } + Node lem = lits.size()==1 ? lits[0] : NodeManager::currentNM()->mkNode( OR, lits ); + if( Trace.isOn("term-db-lemma") ){ + Trace("term-db-lemma") << "Disequal congruent terms : " << at << " " << n << "!!!!" << std::endl; + if( !d_quantEngine->getTheoryEngine()->needCheck() ){ + Trace("term-db-lemma") << " all theories passed with no lemmas." << std::endl; + } + Trace("term-db-lemma") << " add lemma : " << lem << std::endl; + } + d_quantEngine->addLemma( lem ); + d_consistent_ee = false; + return; + } + nonCongruentCount++; + d_op_nonred_count[ f ]++; + } + }else{ + Trace("term-db-debug") << n << " is already redundant." << std::endl; + alreadyCongruentCount++; + } + }else{ + Trace("term-db-debug") << n << " is not relevant." << std::endl; + } + } + if( Trace.isOn("tdb") ){ + Trace("tdb") << "Term db size [" << f << "] : " << nonCongruentCount << " / "; + Trace("tdb") << ( nonCongruentCount + congruentCount ) << " / " << ( nonCongruentCount + congruentCount + alreadyCongruentCount ) << " / "; + Trace("tdb") << relevantCount << " / " << it->second.size() << std::endl; + } + } + } +} + bool TermDb::inRelevantDomain( TNode f, unsigned i, TNode r ) { + computeUfTerms( f ); Assert( d_quantEngine->getTheoryEngine()->getMasterEqualityEngine()->getRepresentative( r )==r ); std::map< Node, std::map< unsigned, std::vector< Node > > >::iterator it = d_func_map_rel_dom.find( f ); if( it != d_func_map_rel_dom.end() ){ @@ -237,25 +325,23 @@ bool TermDb::inRelevantDomain( TNode f, unsigned i, TNode r ) { //return a term n' equivalent to n // maximal subterms of n' are representatives in the equality engine qy -Node TermDb::evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy ) { +Node TermDb::evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy, bool useEntailmentTests ) { std::map< TNode, Node >::iterator itv = visited.find( n ); if( itv != visited.end() ){ return itv->second; } Trace("term-db-eval") << "evaluate term : " << n << std::endl; - Node ret; - if( n.getKind()==BOUND_VARIABLE ){ - return n; + Node ret = n; + if( n.getKind()==FORALL || n.getKind()==BOUND_VARIABLE ){ + //do nothing }else if( !qy->hasTerm( n ) ){ //term is not known to be equal to a representative in equality engine, evaluate it - if( n.getKind()==FORALL ){ - ret = Node::null(); - }else if( n.hasOperator() ){ + if( n.hasOperator() ){ TNode f = getMatchOperator( n ); std::vector< TNode > args; bool ret_set = false; for( unsigned i=0; i<n.getNumChildren(); i++ ){ - TNode c = evaluateTerm2( n[i], visited, qy ); + TNode c = evaluateTerm2( n[i], visited, qy, useEntailmentTests ); if( c.isNull() ){ ret = Node::null(); ret_set = true; @@ -267,7 +353,7 @@ Node TermDb::evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQ ret_set = true; break; }else if( n.getKind()==kind::ITE && i==0 ){ - ret = evaluateTerm2( n[ c==d_true ? 1 : 2], visited, qy ); + ret = evaluateTerm2( n[ c==d_true ? 1 : 2], visited, qy, useEntailmentTests ); ret_set = true; break; } @@ -295,6 +381,22 @@ Node TermDb::evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQ } ret = NodeManager::currentNM()->mkNode( n.getKind(), args ); ret = Rewriter::rewrite( ret ); + if( ret.getKind()==kind::EQUAL ){ + if( qy->areDisequal( ret[0], ret[1] ) ){ + ret = d_false; + } + } + if( useEntailmentTests ){ + if( ret.getKind()==kind::EQUAL || ret.getKind()==kind::GEQ ){ + for( unsigned j=0; j<2; j++ ){ + std::pair<bool, Node> et = d_quantEngine->getTheoryEngine()->entailmentCheck(THEORY_OF_TYPE_BASED, j==0 ? ret : ret.negate() ); + if( et.first ){ + ret = j==0 ? d_true : d_false; + break; + } + } + } + } } } } @@ -316,14 +418,16 @@ TNode TermDb::getEntailedTerm2( TNode n, std::map< TNode, TNode >& subs, bool su return n; }else if( n.getKind()==BOUND_VARIABLE ){ if( hasSubs ){ - Assert( subs.find( n )!=subs.end() ); - Trace("term-db-entail") << "...substitution is : " << subs[n] << std::endl; - if( subsRep ){ - Assert( qy->getEngine()->hasTerm( subs[n] ) ); - Assert( qy->getEngine()->getRepresentative( subs[n] )==subs[n] ); - return subs[n]; - }else{ - return getEntailedTerm2( subs[n], subs, subsRep, hasSubs, qy ); + std::map< TNode, TNode >::iterator it = subs.find( n ); + if( it!=subs.end() ){ + Trace("term-db-entail") << "...substitution is : " << it->second << std::endl; + if( subsRep ){ + Assert( qy->getEngine()->hasTerm( it->second ) ); + Assert( qy->getEngine()->getRepresentative( it->second )==it->second ); + return it->second; + }else{ + return getEntailedTerm2( it->second, subs, subsRep, hasSubs, qy ); + } } } }else if( n.getKind()==ITE ){ @@ -355,12 +459,12 @@ TNode TermDb::getEntailedTerm2( TNode n, std::map< TNode, TNode >& subs, bool su return TNode::null(); } -Node TermDb::evaluateTerm( TNode n, EqualityQuery * qy ) { +Node TermDb::evaluateTerm( TNode n, EqualityQuery * qy, bool useEntailmentTests ) { if( qy==NULL ){ qy = d_quantEngine->getEqualityQuery(); } std::map< TNode, Node > visited; - return evaluateTerm2( n, visited, qy ); + return evaluateTerm2( n, visited, qy, useEntailmentTests ); } TNode TermDb::getEntailedTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep, EqualityQuery * qy ) { @@ -436,6 +540,8 @@ bool TermDb::isEntailed2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, return qy->getEngine()->getRepresentative( n1 ) == ( pol ? d_true : d_false ); } } + }else if( n.getKind()==FORALL && !pol ){ + return isEntailed2( n[1], subs, subsRep, hasSubs, pol, qy ); } return false; } @@ -457,6 +563,18 @@ bool TermDb::isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, return isEntailed2( n, subs, subsRep, true, pol, qy ); } +bool TermDb::isTermActive( Node n ) { + return d_inactive_map.find( n )==d_inactive_map.end(); + //return !n.getAttribute(NoMatchAttribute()); +} + +void TermDb::setTermInactive( Node n ) { + d_inactive_map[n] = true; + //Trace("term-db-debug2") << "set no match attribute" << std::endl; + //NoMatchAttribute nma; + //n.setAttribute(nma,true); +} + bool TermDb::hasTermCurrent( Node n, bool useMode ) { if( !useMode ){ return d_has_map.find( n )!=d_has_map.end(); @@ -556,10 +674,6 @@ void TermDb::presolve() { } bool TermDb::reset( Theory::Effort effort ){ - int nonCongruentCount = 0; - int congruentCount = 0; - int alreadyCongruentCount = 0; - int nonRelevantCount = 0; d_op_nonred_count.clear(); d_arg_reps.clear(); d_func_map_trie.clear(); @@ -614,89 +728,20 @@ bool TermDb::reset( Theory::Effort effort ){ } } +/* //rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){ - d_op_nonred_count[ it->first ] = 0; - Trace("term-db-debug") << "Adding terms for operator " << it->first << std::endl; - for( unsigned i=0; i<it->second.size(); i++ ){ - Node n = it->second[i]; - //to be added to term index, term must be relevant, and exist in EE - if( hasTermCurrent( n ) && ee->hasTerm( n ) ){ - if( !n.getAttribute(NoMatchAttribute()) ){ - if( options::finiteModelFind() ){ - computeModelBasisArgAttribute( n ); - } - computeArgReps( n ); - - Trace("term-db-debug") << "Adding term " << n << " with arg reps : "; - for( unsigned i=0; i<d_arg_reps[n].size(); i++ ){ - Trace("term-db-debug") << d_arg_reps[n][i] << " "; - if( std::find( d_func_map_rel_dom[it->first][i].begin(), - d_func_map_rel_dom[it->first][i].end(), d_arg_reps[n][i] ) == d_func_map_rel_dom[it->first][i].end() ){ - d_func_map_rel_dom[it->first][i].push_back( d_arg_reps[n][i] ); - } - } - Trace("term-db-debug") << std::endl; - if( ee->hasTerm( n ) ){ - Trace("term-db-debug") << " and value : " << ee->getRepresentative( n ) << std::endl; - } - Node at = d_func_map_trie[ it->first ].addOrGetTerm( n, d_arg_reps[n] ); - if( at!=n && ee->areEqual( at, n ) ){ - NoMatchAttribute nma; - n.setAttribute(nma,true); - Trace("term-db-debug") << n << " is redundant." << std::endl; - congruentCount++; - }else{ - if( at!=n && ee->areDisequal( at, n, false ) ){ - std::vector< Node > lits; - lits.push_back( NodeManager::currentNM()->mkNode( at.getType().isBoolean() ? IFF : EQUAL, at, n ) ); - for( unsigned i=0; i<at.getNumChildren(); i++ ){ - if( at[i]!=n[i] ){ - lits.push_back( NodeManager::currentNM()->mkNode( at[i].getType().isBoolean() ? IFF : EQUAL, at[i], n[i] ).negate() ); - } - } - Node lem = lits.size()==1 ? lits[0] : NodeManager::currentNM()->mkNode( OR, lits ); - if( Trace.isOn("term-db-lemma") ){ - Trace("term-db-lemma") << "Disequal congruent terms : " << at << " " << n << "!!!!" << std::endl; - if( !d_quantEngine->getTheoryEngine()->needCheck() ){ - Trace("term-db-lemma") << " all theories passed with no lemmas." << std::endl; - } - Trace("term-db-lemma") << " add lemma : " << lem << std::endl; - } - d_quantEngine->addLemma( lem ); - d_consistent_ee = false; - return false; - } - nonCongruentCount++; - d_op_nonred_count[ it->first ]++; - } - }else{ - Trace("term-db-debug") << n << " is already redundant." << std::endl; - congruentCount++; - alreadyCongruentCount++; - } - }else{ - Trace("term-db-debug") << n << " is not relevant." << std::endl; - nonRelevantCount++; - } - } - } - Trace("term-db-stats") << "TermDb: Reset" << std::endl; - Trace("term-db-stats") << "Non-Congruent/Congruent/Non-Relevant = "; - Trace("term-db-stats") << nonCongruentCount << " / " << congruentCount << " (" << alreadyCongruentCount << ") / " << nonRelevantCount << std::endl; - if( Trace.isOn("term-db-index") ){ - Trace("term-db-index") << "functions : " << std::endl; - for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){ - if( it->second.size()>0 ){ - Trace("term-db-index") << "- " << it->first << std::endl; - d_func_map_trie[ it->first ].debugPrint("term-db-index", it->second[0]); - } + computeUfTerms( it->first ); + if( !d_consistent_ee ){ + return false; } } +*/ return true; } TermArgTrie * TermDb::getTermArgTrie( Node f ) { + computeUfTerms( f ); std::map< Node, TermArgTrie >::iterator itut = d_func_map_trie.find( f ); if( itut!=d_func_map_trie.end() ){ return &itut->second; @@ -725,11 +770,18 @@ TermArgTrie * TermDb::getTermArgTrie( Node eqc, Node f ) { } TNode TermDb::getCongruentTerm( Node f, Node n ) { - computeArgReps( n ); - return d_func_map_trie[f].existsTerm( d_arg_reps[n] ); + computeUfTerms( f ); + std::map< Node, TermArgTrie >::iterator itut = d_func_map_trie.find( f ); + if( itut!=d_func_map_trie.end() ){ + computeArgReps( n ); + return itut->second.existsTerm( d_arg_reps[n] ); + }else{ + return TNode::null(); + } } TNode TermDb::getCongruentTerm( Node f, std::vector< TNode >& args ) { + computeUfTerms( f ); return d_func_map_trie[f].existsTerm( args ); } @@ -822,6 +874,7 @@ void TermDb::makeInstantiationConstantsFor( Node q ){ Debug("quantifiers-engine") << "Instantiation constants for " << q << " : " << std::endl; for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ d_vars[q].push_back( q[0][i] ); + d_var_num[q][q[0][i]] = i; //make instantiation constants Node ic = NodeManager::currentNM()->mkInstConstant( q[0][i].getType() ); d_inst_constants_map[ic] = q; @@ -832,9 +885,8 @@ void TermDb::makeInstantiationConstantsFor( Node q ){ ic.setAttribute( ivna, i ); InstConstantAttribute ica; ic.setAttribute( ica, q ); - //also set the no-match attribute - NoMatchAttribute nma; - ic.setAttribute(nma,true); + //also set the term inactive + setTermInactive( ic ); } } } @@ -892,11 +944,6 @@ Node TermDb::getInstConstAttr( Node n ) { } InstConstantAttribute ica; n.setAttribute(ica, q); - if( !q.isNull() ){ - //also set the no-match attribute - NoMatchAttribute nma; - n.setAttribute(nma,true); - } } return n.getAttribute(InstConstantAttribute()); } @@ -1005,9 +1052,12 @@ Node TermDb::getCounterexampleLiteral( Node q ){ Node TermDb::getInstConstantNode( Node n, Node q ){ makeInstantiationConstantsFor( q ); - Node n2 = n.substitute( d_vars[q].begin(), d_vars[q].end(), - d_inst_constants[q].begin(), d_inst_constants[q].end() ); - return n2; + return n.substitute( d_vars[q].begin(), d_vars[q].end(), d_inst_constants[q].begin(), d_inst_constants[q].end() ); +} + +Node TermDb::getVariableNode( Node n, Node q ) { + makeInstantiationConstantsFor( q ); + return n.substitute( d_inst_constants[q].begin(), d_inst_constants[q].end(), d_vars[q].begin(), d_vars[q].end() ); } Node TermDb::getInstantiatedNode( Node n, Node q, std::vector< Node >& terms ) { @@ -1512,7 +1562,7 @@ struct sortTermOrder { //this function makes a canonical representation of a term ( // - orders variables left to right // - if apply_torder, then sort direct subterms of commutative operators -Node TermDb::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs, bool apply_torder ) { +Node TermDb::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs, bool apply_torder, std::map< TNode, Node >& visited ) { Trace("canon-term-debug") << "Get canonical term for " << n << std::endl; if( n.getKind()==BOUND_VARIABLE ){ std::map< TNode, TNode >::iterator it = subs.find( n ); @@ -1529,32 +1579,38 @@ Node TermDb::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_coun return it->second; } }else if( n.getNumChildren()>0 ){ - //collect children - Trace("canon-term-debug") << "Collect children" << std::endl; - std::vector< Node > cchildren; - for( unsigned i=0; i<n.getNumChildren(); i++ ){ - cchildren.push_back( n[i] ); - } - //if applicable, first sort by term order - if( apply_torder && isComm( n.getKind() ) ){ - Trace("canon-term-debug") << "Sort based on commutative operator " << n.getKind() << std::endl; - sortTermOrder sto; - sto.d_tdb = this; - std::sort( cchildren.begin(), cchildren.end(), sto ); - } - //now make canonical - Trace("canon-term-debug") << "Make canonical children" << std::endl; - for( unsigned i=0; i<cchildren.size(); i++ ){ - cchildren[i] = getCanonicalTerm( cchildren[i], var_count, subs, apply_torder ); - } - if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){ - Trace("canon-term-debug") << "Insert operator " << n.getOperator() << std::endl; - cchildren.insert( cchildren.begin(), n.getOperator() ); - } - Trace("canon-term-debug") << "...constructing for " << n << "." << std::endl; - Node ret = NodeManager::currentNM()->mkNode( n.getKind(), cchildren ); - Trace("canon-term-debug") << "...constructed " << ret << " for " << n << "." << std::endl; - return ret; + std::map< TNode, Node >::iterator it = visited.find( n ); + if( it!=visited.end() ){ + return it->second; + }else{ + //collect children + Trace("canon-term-debug") << "Collect children" << std::endl; + std::vector< Node > cchildren; + for( unsigned i=0; i<n.getNumChildren(); i++ ){ + cchildren.push_back( n[i] ); + } + //if applicable, first sort by term order + if( apply_torder && isComm( n.getKind() ) ){ + Trace("canon-term-debug") << "Sort based on commutative operator " << n.getKind() << std::endl; + sortTermOrder sto; + sto.d_tdb = this; + std::sort( cchildren.begin(), cchildren.end(), sto ); + } + //now make canonical + Trace("canon-term-debug") << "Make canonical children" << std::endl; + for( unsigned i=0; i<cchildren.size(); i++ ){ + cchildren[i] = getCanonicalTerm( cchildren[i], var_count, subs, apply_torder, visited ); + } + if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){ + Trace("canon-term-debug") << "Insert operator " << n.getOperator() << std::endl; + cchildren.insert( cchildren.begin(), n.getOperator() ); + } + Trace("canon-term-debug") << "...constructing for " << n << "." << std::endl; + Node ret = NodeManager::currentNM()->mkNode( n.getKind(), cchildren ); + Trace("canon-term-debug") << "...constructed " << ret << " for " << n << "." << std::endl; + visited[n] = ret; + return ret; + } }else{ Trace("canon-term-debug") << "...return 0-child term." << std::endl; return n; @@ -1564,7 +1620,8 @@ Node TermDb::getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_coun Node TermDb::getCanonicalTerm( TNode n, bool apply_torder ){ std::map< TypeNode, unsigned > var_count; std::map< TNode, TNode > subs; - return getCanonicalTerm( n, var_count, subs, apply_torder ); + std::map< TNode, Node > visited; + return getCanonicalTerm( n, var_count, subs, apply_torder, visited ); } void TermDb::getVtsTerms( std::vector< Node >& t, bool isFree, bool create, bool inc_delta ) { @@ -1790,6 +1847,18 @@ bool TermDb::getEnsureTypeCondition( Node n, TypeNode tn, std::vector< Node >& c } } +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 ); + } + getRelevancyCondition( n[0], cond ); + } +} + bool TermDb::containsTerm2( Node n, Node t, std::map< Node, bool >& visited ) { if( n==t ){ return true; @@ -1856,7 +1925,7 @@ bool TermDb::containsUninterpretedConstant( Node n ) { bool ret = false; if( n.getKind()==UNINTERPRETED_CONSTANT ){ ret = true; - }else{ + }else{ for( unsigned i=0; i<n.getNumChildren(); i++ ){ if( containsUninterpretedConstant( n[i] ) ){ ret = true; @@ -1884,7 +1953,8 @@ Node TermDb::simpleNegate( Node n ){ bool TermDb::isAssoc( Kind k ) { return k==PLUS || k==MULT || k==AND || k==OR || k==XOR || k==IFF || - k==BITVECTOR_PLUS || k==BITVECTOR_MULT || k==BITVECTOR_AND || k==BITVECTOR_OR || k==BITVECTOR_XOR || k==BITVECTOR_XNOR || k==BITVECTOR_CONCAT; + k==BITVECTOR_PLUS || k==BITVECTOR_MULT || k==BITVECTOR_AND || k==BITVECTOR_OR || k==BITVECTOR_XOR || k==BITVECTOR_XNOR || k==BITVECTOR_CONCAT || + k==STRING_CONCAT; } bool TermDb::isComm( Kind k ) { @@ -2184,11 +2254,15 @@ bool TermDb::isQAttrQuantElimPartial( Node q ) { } } -TermDbSygus::TermDbSygus(){ +TermDbSygus::TermDbSygus( context::Context* c, QuantifiersEngine* qe ) : d_quantEngine( qe ){ d_true = NodeManager::currentNM()->mkConst( true ); d_false = NodeManager::currentNM()->mkConst( false ); } +bool TermDbSygus::reset( Theory::Effort e ) { + return true; +} + TNode TermDbSygus::getVar( TypeNode tn, int i ) { while( i>=(int)d_fv[tn].size() ){ std::stringstream ss; @@ -2400,8 +2474,8 @@ Node TermDbSygus::sygusToBuiltin( Node n, TypeNode tn ) { 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; - Assert( n.getKind()==APPLY_CONSTRUCTOR ); 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; @@ -3051,6 +3125,7 @@ void TermDbSygus::printSygusTerm( std::ostream& out, Node n, std::vector< Node > std::string name = std::string( str.begin() + found +1, str.end() ); out << name; }else{ + Trace("ajr-temp") << "[[print operator " << op << "]]" << std::endl; out << op; } if( n.getNumChildren()>0 ){ @@ -3118,3 +3193,91 @@ void TermDbSygus::printSygusTerm( std::ostream& out, Node n, std::vector< Node > out << n; } } + +Node TermDbSygus::getAnchor( Node n ) { + if( n.getKind()==APPLY_SELECTOR_TOTAL ){ + return getAnchor( n[0] ); + }else{ + return n; + } +} + +void TermDbSygus::registerEvalTerm( Node n ) { + if( options::sygusDirectEval() ){ + if( n.getKind()==APPLY_UF && !n.getType().isBoolean() ){ + Trace("sygus-eager") << "TermDbSygus::eager: Register eval term : " << n << std::endl; + TypeNode tn = n[0].getType(); + if( datatypes::DatatypesRewriter::isTypeDatatype(tn) ){ + const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); + if( dt.isSygus() ){ + Node f = n.getOperator(); + Trace("sygus-eager") << "...the evaluation function is : " << f << std::endl; + if( n[0].getKind()!=APPLY_CONSTRUCTOR ){ + d_evals[n[0]].push_back( n ); + TypeNode tn = n[0].getType(); + Assert( datatypes::DatatypesRewriter::isTypeDatatype(tn) ); + const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); + Node var_list = Node::fromExpr( dt.getSygusVarList() ); + Assert( dt.isSygus() ); + d_eval_args[n[0]].push_back( std::vector< Node >() ); + 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] ); + } + } + Node a = getAnchor( n[0] ); + d_subterms[a][n[0]] = true; + } + } + } + } + } +} + +void TermDbSygus::registerModelValue( Node a, Node v, std::vector< Node >& lems ) { + std::map< Node, std::map< Node, bool > >::iterator its = d_subterms.find( a ); + if( its!=d_subterms.end() ){ + Trace("sygus-eager") << "registerModelValue : " << a << ", has " << its->second.size() << " registered subterms." << std::endl; + for( std::map< Node, bool >::iterator itss = its->second.begin(); itss != its->second.end(); ++itss ){ + Node n = itss->first; + Trace("sygus-eager-debug") << "...process : " << n << std::endl; + std::map< Node, std::vector< std::vector< Node > > >::iterator it = d_eval_args.find( n ); + if( it!=d_eval_args.end() && !it->second.empty() ){ + TNode at = a; + TNode vt = v; + Node vn = n.substitute( at, vt ); + vn = Rewriter::rewrite( vn ); + unsigned start = d_node_mv_args_proc[n][vn]; + Node antec = n.eqNode( vn ).negate(); + TypeNode tn = n.getType(); + Assert( datatypes::DatatypesRewriter::isTypeDatatype(tn) ); + const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); + Assert( dt.isSygus() ); + Trace("sygus-eager") << "TermDbSygus::eager: Register model value : " << vn << " for " << n << std::endl; + Trace("sygus-eager") << "...it has " << it->second.size() << " evaluations, already processed " << start << "." << std::endl; + Node bTerm = d_quantEngine->getTermDatabaseSygus()->sygusToBuiltin( vn, tn ); + Trace("sygus-eager") << "Built-in term : " << bTerm << std::endl; + std::vector< Node > vars; + Node var_list = Node::fromExpr( dt.getSygusVarList() ); + for( unsigned j=0; j<var_list.getNumChildren(); j++ ){ + vars.push_back( var_list[j] ); + } + //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() ); + Node lem = NodeManager::currentNM()->mkNode( n.getType().isBoolean() ? IFF : EQUAL, d_evals[n][i], sBTerm ); + lem = NodeManager::currentNM()->mkNode( OR, antec, lem ); + Trace("sygus-eager") << "Lemma : " << lem << std::endl; + lems.push_back( lem ); + } + d_node_mv_args_proc[n][vn] = it->second.size(); + } + } + } +} + diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h index a62b343a2..7ab3668eb 100644..100755 --- a/src/theory/quantifiers/term_database.h +++ b/src/theory/quantifiers/term_database.h @@ -47,15 +47,6 @@ typedef expr::Attribute< SygusAttributeId, bool > SygusAttribute; struct SynthesisAttributeId {}; typedef expr::Attribute< SynthesisAttributeId, bool > SynthesisAttribute; -/** Attribute true for nodes that should not be used for matching */ -struct NoMatchAttributeId {}; -/** use the special for boolean flag */ -typedef expr::Attribute< NoMatchAttributeId, - bool, - expr::attr::NullCleanupStrategy, - true // context dependent - > NoMatchAttribute; - // attribute for "contains instantiation constants from" struct InstConstantAttributeId {}; typedef expr::Attribute<InstConstantAttributeId, Node> InstConstantAttribute; @@ -179,6 +170,7 @@ class TermDb : public QuantifiersUtil { friend class ::CVC4::theory::quantifiers::ConjectureGenerator; friend class ::CVC4::theory::quantifiers::TermGenEnv; typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap; + typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap; private: /** reference to the quantifiers engine */ QuantifiersEngine* d_quantEngine; @@ -211,6 +203,8 @@ private: std::map< Node, std::vector< Node > > d_op_map; /** map from type nodes to terms of that type */ std::map< TypeNode, std::vector< Node > > d_type_map; + /** inactive map */ + NodeBoolMap d_inactive_map; /** count number of non-redundant ground terms per operator */ std::map< Node, int > d_op_nonred_count; @@ -228,7 +222,7 @@ private: /** set has term */ void setHasTerm( Node n ); /** evaluate term */ - Node evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy ); + Node evaluateTerm2( TNode n, std::map< TNode, Node >& visited, EqualityQuery * qy, bool useEntailmentTests ); TNode getEntailedTerm2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, EqualityQuery * qy ); bool isEntailed2( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool hasSubs, bool pol, EqualityQuery * qy ); public: @@ -254,18 +248,23 @@ public: void computeArgReps( TNode n ); /** compute uf eqc terms */ void computeUfEqcTerms( TNode f ); + /** compute uf terms */ + void computeUfTerms( TNode f ); /** in relevant domain */ bool inRelevantDomain( TNode f, unsigned i, TNode r ); /** evaluate a term under a substitution. Return representative in EE if possible. * subsRep is whether subs contains only representatives */ - Node evaluateTerm( TNode n, EqualityQuery * qy = NULL ); + Node evaluateTerm( TNode n, EqualityQuery * qy = NULL, bool useEntailmentTests = false ); /** get entailed term, does not construct new terms, less aggressive */ TNode getEntailedTerm( TNode n, EqualityQuery * qy = NULL ); TNode getEntailedTerm( TNode n, std::map< TNode, TNode >& subs, bool subsRep, EqualityQuery * qy = NULL ); /** is entailed (incomplete check) */ bool isEntailed( TNode n, bool pol, EqualityQuery * qy = NULL ); bool isEntailed( TNode n, std::map< TNode, TNode >& subs, bool subsRep, bool pol, EqualityQuery * qy = NULL ); + /** is active */ + bool isTermActive( Node n ); + void setTermInactive( Node n ); /** has term */ bool hasTermCurrent( Node n, bool useMode = true ); /** is term eligble for instantiation? */ @@ -274,7 +273,7 @@ public: Node getEligibleTermInEqc( TNode r ); /** is inst closure */ bool isInstClosure( Node r ); - + //for model basis private: //map from types to model basis terms @@ -301,6 +300,7 @@ public: private: /** map from universal quantifiers to the list of variables */ std::map< Node, std::vector< Node > > d_vars; + std::map< Node, std::map< Node, unsigned > > d_var_num; /** map from universal quantifiers to the list of instantiation constants */ std::map< Node, std::vector< Node > > d_inst_constants; /** map from universal quantifiers to their inst constant body */ @@ -312,6 +312,8 @@ private: /** make instantiation constants for */ void makeInstantiationConstantsFor( Node q ); public: + /** get variable number */ + unsigned getVariableNum( Node q, Node v ) { return d_var_num[q][v]; } /** get the i^th instantiation constant of q */ Node getInstantiationConstant( Node q, int i ) const; /** get number of instantiation constants for q */ @@ -327,6 +329,7 @@ public: instantiation. */ Node getInstConstantNode( Node n, Node q ); + Node getVariableNode( Node n, Node q ); /** get substituted node */ Node getInstantiatedNode( Node n, Node q, std::vector< Node >& terms ); @@ -419,7 +422,8 @@ private: //free variables std::map< TypeNode, std::vector< Node > > d_cn_free_var; // get canonical term, return null if it contains a term apart from handled signature - Node getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs, bool apply_torder ); + Node getCanonicalTerm( TNode n, std::map< TypeNode, unsigned >& var_count, std::map< TNode, TNode >& subs, bool apply_torder, + std::map< TNode, Node >& visited ); public: /** get id for operator */ int getIdForOperator( Node op ); @@ -461,6 +465,8 @@ public: static Node ensureType( Node n, TypeNode tn ); /** get ensure type condition */ static bool getEnsureTypeCondition( Node n, TypeNode tn, std::vector< Node >& cond ); + /** get relevancy condition */ + static void getRelevancyCondition( Node n, std::vector< Node >& cond ); private: //helper for contains term static bool containsTerm2( Node n, Node t, std::map< Node, bool >& visited ); @@ -541,6 +547,8 @@ public: class TermDbSygus { private: + /** reference to the quantifiers engine */ + QuantifiersEngine* d_quantEngine; std::map< TypeNode, std::vector< Node > > d_fv; std::map< Node, TypeNode > d_fv_stype; std::map< Node, int > d_fv_num; @@ -554,7 +562,6 @@ public: private: std::map< TypeNode, std::map< int, Node > > d_generic_base; std::map< TypeNode, std::vector< Node > > d_generic_templ; - Node getGenericBase( TypeNode tn, const Datatype& dt, int c ); bool getMatch( Node p, Node n, std::map< int, Node >& s ); bool getMatch2( Node p, Node n, std::map< int, Node >& s, std::vector< int >& new_s ); public: @@ -581,7 +588,11 @@ private: std::map< TypeNode, std::map< Node, Node > > d_sygus_to_builtin; std::map< TypeNode, std::map< Node, Node > > d_builtin_const_to_sygus; public: - TermDbSygus(); + TermDbSygus( context::Context* c, QuantifiersEngine* qe ); + ~TermDbSygus(){} + bool reset( Theory::Effort e ); + std::string identify() const { return "TermDbSygus"; } + bool isRegistered( TypeNode tn ); TypeNode sygusToBuiltinType( TypeNode tn ); int getKindArg( TypeNode tn, Kind k ); @@ -615,6 +626,7 @@ public: /** get value */ Node getTypeMaxValue( TypeNode tn ); TypeNode getSygusTypeForVar( Node v ); + Node getGenericBase( TypeNode tn, const Datatype& dt, int c ); Node mkGeneric( const Datatype& dt, int c, std::map< TypeNode, int >& var_count, std::map< int, Node >& pre ); Node sygusToBuiltin( Node n, TypeNode tn ); Node builtinToSygusConst( Node c, TypeNode tn, int rcons_depth = 0 ); @@ -633,6 +645,18 @@ public: static Kind getOperatorKind( Node op ); /** print sygus term */ static void printSygusTerm( std::ostream& out, Node n, std::vector< Node >& lvs ); + + /** get anchor */ + static Node getAnchor( Node n ); +//for eager instantiation +private: + std::map< Node, std::map< Node, bool > > d_subterms; + std::map< Node, std::vector< Node > > d_evals; + std::map< Node, std::vector< std::vector< Node > > > d_eval_args; + std::map< Node, std::map< Node, unsigned > > d_node_mv_args_proc; +public: + void registerEvalTerm( Node n ); + void registerModelValue( Node n, Node v, std::vector< Node >& lems ); }; }/* CVC4::theory::quantifiers namespace */ diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp index efe40aaa8..7ad13b3a8 100644..100755 --- a/src/theory/quantifiers/theory_quantifiers.cpp +++ b/src/theory/quantifiers/theory_quantifiers.cpp @@ -72,8 +72,11 @@ void TheoryQuantifiers::notifyEq(TNode lhs, TNode rhs) { void TheoryQuantifiers::preRegisterTerm(TNode n) { Debug("quantifiers-prereg") << "TheoryQuantifiers::preRegisterTerm() " << n << endl; - if( n.getKind()==FORALL && !TermDb::hasInstConstAttr(n) ){ - getQuantifiersEngine()->registerQuantifier( n ); + if( n.getKind()==FORALL ){ + if( !options::cbqi() || options::recurseCbqi() || !TermDb::hasInstConstAttr(n) ){ + getQuantifiersEngine()->registerQuantifier( n ); + Debug("quantifiers-prereg") << "TheoryQuantifiers::preRegisterTerm() done " << n << endl; + } } } diff --git a/src/theory/quantifiers/theory_quantifiers.h b/src/theory/quantifiers/theory_quantifiers.h index 6775e0536..6775e0536 100644..100755 --- a/src/theory/quantifiers/theory_quantifiers.h +++ b/src/theory/quantifiers/theory_quantifiers.h diff --git a/src/theory/quantifiers/theory_quantifiers_type_rules.h b/src/theory/quantifiers/theory_quantifiers_type_rules.h index 6ba57afb4..6ba57afb4 100644..100755 --- a/src/theory/quantifiers/theory_quantifiers_type_rules.h +++ b/src/theory/quantifiers/theory_quantifiers_type_rules.h diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp index 38635b37b..ee091919d 100644..100755 --- a/src/theory/quantifiers/trigger.cpp +++ b/src/theory/quantifiers/trigger.cpp @@ -43,9 +43,8 @@ void TriggerTermInfo::init( Node q, Node n, int reqPol, Node reqPolEq ){ } /** trigger class constructor */ -Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption ) - : d_quantEngine( qe ), d_f( f ) -{ +Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes ) + : d_quantEngine( qe ), d_f( f ) { d_nodes.insert( d_nodes.begin(), nodes.begin(), nodes.end() ); Trace("trigger") << "Trigger for " << f << ": " << std::endl; for( unsigned i=0; i<d_nodes.size(); i++ ){ @@ -53,7 +52,7 @@ Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int } if( d_nodes.size()==1 ){ if( isSimpleTrigger( d_nodes[0] ) ){ - d_mg = new InstMatchGeneratorSimple( f, d_nodes[0] ); + d_mg = new InstMatchGeneratorSimple( f, d_nodes[0], qe ); }else{ d_mg = InstMatchGenerator::mkInstMatchGenerator( f, d_nodes[0], qe ); d_mg->setActiveAdd(true); @@ -87,7 +86,7 @@ Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int } Trigger::~Trigger() { - if(d_mg != NULL) { delete d_mg; } + delete d_mg; } void Trigger::resetInstantiationRound(){ @@ -112,6 +111,10 @@ int Trigger::addTerm( Node t ){ return d_mg->addTerm( d_f, t, d_quantEngine ); } +Node Trigger::getInstPattern(){ + return NodeManager::currentNM()->mkNode( INST_PATTERN, d_nodes ); +} + int Trigger::addInstantiations( InstMatch& baseMatch ){ int addedLemmas = d_mg->addInstantiations( d_f, baseMatch, d_quantEngine ); if( addedLemmas>0 ){ @@ -124,77 +127,85 @@ int Trigger::addInstantiations( InstMatch& baseMatch ){ return addedLemmas; } -Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool keepAll, int trOption ){ - std::vector< Node > trNodes; - if( !keepAll ){ - //only take nodes that contribute variables to the trigger when added - std::vector< Node > temp; - temp.insert( temp.begin(), nodes.begin(), nodes.end() ); - std::map< Node, bool > vars; - std::map< Node, std::vector< Node > > patterns; - size_t varCount = 0; - std::map< Node, std::vector< Node > > varContains; - quantifiers::TermDb::getVarContains( f, temp, varContains ); - for( unsigned i=0; i<temp.size(); i++ ){ - bool foundVar = false; +bool Trigger::mkTriggerTerms( Node q, std::vector< Node >& nodes, unsigned n_vars, std::vector< Node >& trNodes ) { + //only take nodes that contribute variables to the trigger when added + std::vector< Node > temp; + temp.insert( temp.begin(), nodes.begin(), nodes.end() ); + std::map< Node, bool > vars; + std::map< Node, std::vector< Node > > patterns; + size_t varCount = 0; + std::map< Node, std::vector< Node > > varContains; + quantifiers::TermDb::getVarContains( q, temp, varContains ); + for( unsigned i=0; i<temp.size(); i++ ){ + bool foundVar = false; + for( unsigned j=0; j<varContains[ temp[i] ].size(); j++ ){ + Node v = varContains[ temp[i] ][j]; + Assert( quantifiers::TermDb::getInstConstAttr(v)==q ); + if( vars.find( v )==vars.end() ){ + varCount++; + vars[ v ] = true; + foundVar = true; + } + } + if( foundVar ){ + trNodes.push_back( temp[i] ); for( unsigned j=0; j<varContains[ temp[i] ].size(); j++ ){ Node v = varContains[ temp[i] ][j]; - Assert( quantifiers::TermDb::getInstConstAttr(v)==f ); - if( vars.find( v )==vars.end() ){ - varCount++; - vars[ v ] = true; - foundVar = true; - } - } - if( foundVar ){ - trNodes.push_back( temp[i] ); - for( unsigned j=0; j<varContains[ temp[i] ].size(); j++ ){ - Node v = varContains[ temp[i] ][j]; - patterns[ v ].push_back( temp[i] ); - } - } - if( varCount==f[0].getNumChildren() ){ - break; + patterns[ v ].push_back( temp[i] ); } } - if( varCount<f[0].getNumChildren() && !options::partialTriggers() ){ - Trace("trigger-debug") << "Don't consider trigger since it does not contain all variables in " << f << std::endl; - for( unsigned i=0; i<nodes.size(); i++) { - Trace("trigger-debug") << nodes[i] << " "; - } - Trace("trigger-debug") << std::endl; + if( varCount==n_vars ){ + break; + } + } + if( varCount<n_vars ){ + Trace("trigger-debug") << "Don't consider trigger since it does not contain specified number of variables." << std::endl; + for( unsigned i=0; i<nodes.size(); i++) { + Trace("trigger-debug") << nodes[i] << " "; + } + Trace("trigger-debug") << std::endl; - //do not generate multi-trigger if it does not contain all variables - return NULL; - }else{ - //now, minimize the trigger - for( unsigned i=0; i<trNodes.size(); i++ ){ - bool keepPattern = false; - Node n = trNodes[i]; + //do not generate multi-trigger if it does not contain all variables + return false; + }else{ + //now, minimize the trigger + for( unsigned i=0; i<trNodes.size(); i++ ){ + bool keepPattern = false; + Node n = trNodes[i]; + for( unsigned j=0; j<varContains[ n ].size(); j++ ){ + Node v = varContains[ n ][j]; + if( patterns[v].size()==1 ){ + keepPattern = true; + break; + } + } + if( !keepPattern ){ + //remove from pattern vector for( unsigned j=0; j<varContains[ n ].size(); j++ ){ Node v = varContains[ n ][j]; - if( patterns[v].size()==1 ){ - keepPattern = true; - break; - } - } - if( !keepPattern ){ - //remove from pattern vector - for( unsigned j=0; j<varContains[ n ].size(); j++ ){ - Node v = varContains[ n ][j]; - for( unsigned k=0; k<patterns[v].size(); k++ ){ - if( patterns[v][k]==n ){ - patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 ); - break; - } + for( unsigned k=0; k<patterns[v].size(); k++ ){ + if( patterns[v][k]==n ){ + patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 ); + break; } } - //remove from trigger nodes - trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 ); - i--; } + //remove from trigger nodes + trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 ); + i--; } } + } + return true; +} + +Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, bool keepAll, int trOption, unsigned use_n_vars ){ + std::vector< Node > trNodes; + if( !keepAll ){ + unsigned n_vars = use_n_vars==0 ? f[0].getNumChildren() : use_n_vars; + if( !mkTriggerTerms( f, nodes, n_vars, trNodes ) ){ + return NULL; + } }else{ trNodes.insert( trNodes.begin(), nodes.begin(), nodes.end() ); } @@ -211,15 +222,15 @@ Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& } } } - Trigger* t = new Trigger( qe, f, trNodes, matchOption ); + Trigger* t = new Trigger( qe, f, trNodes ); qe->getTriggerDatabase()->addTrigger( trNodes, t ); return t; } -Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, int matchOption, bool keepAll, int trOption ){ +Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, bool keepAll, int trOption, unsigned use_n_vars ){ std::vector< Node > nodes; nodes.push_back( n ); - return mkTrigger( qe, f, nodes, matchOption, keepAll, trOption ); + return mkTrigger( qe, f, nodes, keepAll, trOption, use_n_vars ); } bool Trigger::isUsable( Node n, Node q ){ @@ -273,7 +284,7 @@ bool Trigger::isUsableEqTerms( Node q, Node n1, Node n2 ) { return true; } } - }else if( isAtomicTrigger( n1 ) && isUsable( n1, q ) ){ + }else if( isUsableAtomicTrigger( n1, q ) ){ if( options::relationalTriggers() && n2.getKind()==INST_CONSTANT && !quantifiers::TermDb::containsTerm( n1, n2 ) ){ return true; }else if( !quantifiers::TermDb::hasInstConstAttr(n2) ){ @@ -328,24 +339,25 @@ Node Trigger::getIsUsableTrigger( Node n, Node q ) { return rtr2; } }else{ - bool usable = quantifiers::TermDb::getInstConstAttr(n)==q && isAtomicTrigger( n ) && isUsable( n, q ); - Trace("trigger-debug") << n << " usable : " << (quantifiers::TermDb::getInstConstAttr(n)==q) << " " << isAtomicTrigger( n ) << " " << isUsable( n, q ) << std::endl; - if( usable ){ + Trace("trigger-debug") << n << " usable : " << ( quantifiers::TermDb::getInstConstAttr(n)==q ) << " " << isAtomicTrigger( n ) << " " << isUsable( n, q ) << std::endl; + if( isUsableAtomicTrigger( n, q ) ){ return pol ? n : NodeManager::currentNM()->mkNode( IFF, n, NodeManager::currentNM()->mkConst( true ) ).notNode(); } } return Node::null(); } +bool Trigger::isUsableAtomicTrigger( Node n, Node q ) { + return quantifiers::TermDb::getInstConstAttr( n )==q && isAtomicTrigger( n ) && isUsable( n, q ); +} + bool Trigger::isUsableTrigger( Node n, Node q ){ Node nu = getIsUsableTrigger( n, q ); return !nu.isNull(); } bool Trigger::isAtomicTrigger( Node n ){ - Kind k = n.getKind(); - return ( k==APPLY_UF && !n.getOperator().getAttribute(NoMatchAttribute()) ) || - ( k!=APPLY_UF && isAtomicTriggerKind( k ) ); + return isAtomicTriggerKind( n.getKind() ); } bool Trigger::isAtomicTriggerKind( Kind k ) { @@ -363,8 +375,13 @@ bool Trigger::isRelationalTriggerKind( Kind k ) { } bool Trigger::isCbqiKind( Kind k ) { - return quantifiers::TermDb::isBoolConnective( k ) || k==PLUS || k==GEQ || k==EQUAL || k==MULT || - k==APPLY_CONSTRUCTOR || k==APPLY_SELECTOR_TOTAL || k==APPLY_TESTER; + if( quantifiers::TermDb::isBoolConnective( k ) || k==PLUS || k==GEQ || k==EQUAL || k==MULT ){ + return true; + }else{ + //CBQI typically works for satisfaction-complete theories + TheoryId t = kindToTheoryId( k ); + return t==THEORY_BV || t==THEORY_DATATYPES; + } } bool Trigger::isSimpleTrigger( Node n ){ diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h index 41f2a1c38..a3da4d398 100644..100755 --- a/src/theory/quantifiers/trigger.h +++ b/src/theory/quantifiers/trigger.h @@ -76,6 +76,8 @@ class Trigger { int addTerm( Node t ); /** return whether this is a multi-trigger */ bool isMultiTrigger() { return d_nodes.size()>1; } + /** get inst pattern list */ + Node getInstPattern(); /** add all available instantiations exhaustively, in any equivalence class if limitInst>0, limitInst is the max # of instantiations to try */ @@ -84,8 +86,6 @@ class Trigger { ie : quantifier engine; f : forall something .... nodes : (multi-)trigger - matchOption : which policy to use for creating matches - (one of InstMatchGenerator::MATCH_GEN_* ) keepAll: don't remove unneeded patterns; trOption : policy for dealing with triggers that already existed (see below) @@ -95,18 +95,19 @@ class Trigger { TR_GET_OLD, //return a previous trigger if it had already been created TR_RETURN_NULL //return null if a duplicate is found }; - static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, - std::vector< Node >& nodes, int matchOption = 0, - bool keepAll = true, int trOption = TR_MAKE_NEW ); - static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, Node n, - int matchOption = 0, bool keepAll = true, - int trOption = TR_MAKE_NEW ); + //nodes input, trNodes output + static bool mkTriggerTerms( Node q, std::vector< Node >& nodes, unsigned n_vars, std::vector< Node >& trNodes ); + static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, + bool keepAll = true, int trOption = TR_MAKE_NEW, unsigned use_n_vars = 0 ); + static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, Node n, bool keepAll = true, + int trOption = TR_MAKE_NEW, unsigned use_n_vars = 0 ); static void collectPatTerms( Node q, Node n, std::vector< Node >& patTerms, quantifiers::TriggerSelMode tstrt, std::vector< Node >& exclude, std::map< Node, TriggerTermInfo >& tinfo, bool filterInst = false ); /** is usable trigger */ static bool isUsableTrigger( Node n, Node q ); static Node getIsUsableTrigger( Node n, Node q ); + static bool isUsableAtomicTrigger( Node n, Node q ); static bool isAtomicTrigger( Node n ); static bool isAtomicTriggerKind( Kind k ); static bool isRelationalTrigger( Node n ); @@ -135,7 +136,7 @@ class Trigger { } private: /** trigger constructor */ - Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes, int matchOption = 0 ); + Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes ); /** is subterm of trigger usable */ static bool isUsable( Node n, Node q ); |