/********************* */ /*! \file ceg_instantiator.cpp ** \verbatim ** Top contributors (to current version): ** Andrew Reynolds, Tim King ** This file is part of the CVC4 project. ** Copyright (c) 2009-2017 by the authors listed in the file AUTHORS ** in the top-level source directory) and their institutional affiliations. ** All rights reserved. See the file COPYING in the top-level source ** directory for licensing information.\endverbatim ** ** \brief Implementation of counterexample-guided quantifier instantiation **/ #include "theory/quantifiers/ceg_instantiator.h" #include "theory/quantifiers/ceg_t_instantiator.h" #include "options/quantifiers_options.h" #include "smt/term_formula_removal.h" #include "theory/quantifiers/first_order_model.h" #include "theory/quantifiers/quantifiers_rewriter.h" #include "theory/quantifiers/term_database.h" #include "theory/quantifiers/term_enumeration.h" #include "theory/quantifiers/term_util.h" #include "theory/quantifiers/trigger.h" #include "theory/theory_engine.h" using namespace std; using namespace CVC4; using namespace CVC4::kind; using namespace CVC4::context; using namespace CVC4::theory; using namespace CVC4::theory::quantifiers; CegInstantiator::CegInstantiator( QuantifiersEngine * qe, CegqiOutput * out, bool use_vts_delta, bool use_vts_inf ) : d_qe( qe ), d_out( out ), d_use_vts_delta( use_vts_delta ), d_use_vts_inf( use_vts_inf ){ d_is_nested_quant = false; } CegInstantiator::~CegInstantiator() { for( std::map< Node, Instantiator * >::iterator it = d_instantiator.begin(); it != d_instantiator.end(); ++it ){ delete it->second; } } void CegInstantiator::computeProgVars( Node n ){ if( d_prog_var.find( n )==d_prog_var.end() ){ d_prog_var[n].clear(); if (n.getKind() == kind::CHOICE) { Assert(d_prog_var.find(n[0][0]) == d_prog_var.end()); d_prog_var[n[0][0]].clear(); } if (d_vars_set.find(n) != d_vars_set.end()) { d_prog_var[n].insert(n); }else if( !d_out->isEligibleForInstantiation( n ) ){ d_inelig.insert(n); return; } for( unsigned i=0; i d_vars.size() || !d_var_order_index.empty(); std::vector< Instantiator * > pp_inst; std::map< Instantiator *, Node > pp_inst_to_var; std::vector< Node > lemmas; for( std::map< Node, Instantiator * >::iterator ita = d_active_instantiators.begin(); ita != d_active_instantiators.end(); ++ita ){ if( ita->second->needsPostProcessInstantiationForVariable( this, sf, ita->first, effort ) ){ needsPostprocess = true; pp_inst_to_var[ ita->second ] = ita->first; } } if( needsPostprocess ){ //must make copy so that backtracking reverts sf SolvedForm sf_tmp = sf; bool postProcessSuccess = true; for( std::map< Instantiator *, Node >::iterator itp = pp_inst_to_var.begin(); itp != pp_inst_to_var.end(); ++itp ){ if( !itp->first->postProcessInstantiationForVariable( this, sf_tmp, itp->second, effort, lemmas ) ){ postProcessSuccess = false; break; } } if( postProcessSuccess ){ return doAddInstantiation( sf_tmp.d_vars, sf_tmp.d_subs, lemmas ); }else{ return false; } }else{ return doAddInstantiation( sf.d_vars, sf.d_subs, lemmas ); } }else{ //Node v = d_single_inv_map_to_prog[d_single_inv[0][i]]; bool is_cv = false; Node pv; if( d_stack_vars.empty() ){ pv = d_vars[i]; }else{ pv = d_stack_vars.back(); is_cv = true; d_stack_vars.pop_back(); } registerInstantiationVariable( pv, i ); //get the instantiator object Instantiator * vinst = NULL; std::map< Node, Instantiator * >::iterator itin = d_instantiator.find( pv ); if( itin!=d_instantiator.end() ){ vinst = itin->second; } Assert( vinst!=NULL ); d_active_instantiators[pv] = vinst; vinst->reset( this, sf, pv, effort ); TypeNode pvtn = pv.getType(); TypeNode pvtnb = pvtn.getBaseType(); Node pvr = pv; if( d_qe->getMasterEqualityEngine()->hasTerm( pv ) ){ pvr = d_qe->getMasterEqualityEngine()->getRepresentative( pv ); } Trace("cbqi-inst-debug") << "[Find instantiation for " << pv << "], rep=" << pvr << ", instantiator is " << vinst->identify() << std::endl; Node pv_value; if( options::cbqiModel() ){ pv_value = getModelValue( pv ); Trace("cbqi-bound2") << "...M( " << pv << " ) = " << pv_value << std::endl; } //if in effort=2, we must choose at least one model value if( (i+1) >::iterator it_eqc = d_curr_eqc.find( pvr ); if( it_eqc!=d_curr_eqc.end() ){ //std::vector< Node > eq_candidates; Trace("cbqi-inst-debug2") << "...eqc has size " << it_eqc->second.size() << std::endl; for( unsigned k=0; ksecond.size(); k++ ){ Node n = it_eqc->second[k]; if( n!=pv ){ Trace("cbqi-inst-debug") << "...try based on equal term " << n << std::endl; //must be an eligible term if( isEligible( n ) ){ Node ns; TermProperties pv_prop; //coefficient of pv in the equality we solve (null is 1) bool proc = false; if( !d_prog_var[n].empty() ){ ns = applySubstitution( pvtn, n, sf, pv_prop, false ); if( !ns.isNull() ){ computeProgVars( ns ); //substituted version must be new and cannot contain pv proc = d_prog_var[ns].find( pv )==d_prog_var[ns].end(); } }else{ ns = n; proc = true; } if( proc ){ if( vinst->processEqualTerm( this, sf, pv, pv_prop, ns, effort ) ){ return true; } } } } } if( vinst->processEqualTerms( this, sf, pv, it_eqc->second, effort ) ){ return true; } }else{ Trace("cbqi-inst-debug2") << "...eqc not found." << std::endl; } //[3] : we can solve an equality for pv ///iterate over equivalence classes to find cases where we can solve for the variable if( vinst->hasProcessEquality( this, sf, pv, effort ) ){ Trace("cbqi-inst-debug") << "[3] try based on solving equalities." << std::endl; for( unsigned k=0; k >::iterator it_reqc = d_curr_eqc.find( r ); std::vector< Node > lhs; std::vector< bool > lhs_v; std::vector< TermProperties > lhs_prop; Assert( it_reqc!=d_curr_eqc.end() ); for( unsigned kk=0; kksecond.size(); kk++ ){ Node n = it_reqc->second[kk]; Trace("cbqi-inst-debug2") << "...look at term " << n << std::endl; //must be an eligible term if( isEligible( n ) ){ Node ns; TermProperties pv_prop; if( !d_prog_var[n].empty() ){ ns = applySubstitution( pvtn, n, sf, pv_prop ); if( !ns.isNull() ){ computeProgVars( ns ); } }else{ ns = n; } if( !ns.isNull() ){ bool hasVar = d_prog_var[ns].find( pv )!=d_prog_var[ns].end(); Trace("cbqi-inst-debug2") << "... " << ns << " has var " << pv << " : " << hasVar << std::endl; std::vector< TermProperties > term_props; std::vector< Node > terms; term_props.push_back( pv_prop ); terms.push_back( ns ); for( unsigned j=0; jhasProcessAssertion( this, sf, pv, effort ) ){ Trace("cbqi-inst-debug") << "[4] try based on assertions." << std::endl; std::unordered_set< Node, NodeHashFunction > lits; //unsigned rmax = Theory::theoryOf( pv )==Theory::theoryOf( pv.getType() ) ? 1 : 2; for( unsigned r=0; r<2; r++ ){ TheoryId tid = r==0 ? Theory::theoryOf( pvtn ) : THEORY_UF; Trace("cbqi-inst-debug2") << " look at assertions of " << tid << std::endl; std::map< TheoryId, std::vector< Node > >::iterator ita = d_curr_asserts.find( tid ); if( ita!=d_curr_asserts.end() ){ for (unsigned j = 0; jsecond.size(); j++) { Node lit = ita->second[j]; if( lits.find(lit)==lits.end() ){ lits.insert(lit); Node plit = vinst->hasProcessAssertion(this, sf, pv, lit, effort); if (!plit.isNull()) { Trace("cbqi-inst-debug2") << " look at " << lit; if (plit != lit) { Trace("cbqi-inst-debug2") << "...processed to : " << plit; } Trace("cbqi-inst-debug2") << std::endl; // apply substitutions Node slit = applySubstitutionToLiteral(plit, sf); if( !slit.isNull() ){ Trace("cbqi-inst-debug") << "...try based on literal " << slit << std::endl; // check if contains pv if( hasVariable( slit, pv ) ){ if (vinst->processAssertion(this, sf, pv, slit, lit, effort)) { return true; } } } } } } } } if (vinst->processAssertions(this, sf, pv, effort)) { return true; } } } //[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 bool use_model_value = vinst->useModelValue( this, sf, pv, effort ); if( ( effort>0 || use_model_value || is_cv ) && vinst->allowModelValue( this, sf, pv, effort ) ){ #ifdef CVC4_ASSERTIONS if( pvtn.isReal() && options::cbqiNestedQE() && !options::cbqiAll() ){ Trace("cbqi-warn") << "Had to resort to model value." << std::endl; Assert( false ); } #endif Node mv = getModelValue( pv ); TermProperties pv_prop_m; Trace("cbqi-inst-debug") << "[5] " << i << "...try model value " << mv << std::endl; int new_effort = use_model_value ? effort : 1; if( doAddInstantiationInc( pv, mv, pv_prop_m, sf, new_effort ) ){ return true; } } Trace("cbqi-inst-debug") << "[No instantiation found for " << pv << "]" << std::endl; if( is_cv ){ d_stack_vars.push_back( pv ); } d_active_instantiators.erase( pv ); unregisterInstantiationVariable( pv ); return false; } } void CegInstantiator::pushStackVariable( Node v ) { d_stack_vars.push_back( v ); } void CegInstantiator::popStackVariable() { Assert( !d_stack_vars.empty() ); d_stack_vars.pop_back(); } bool CegInstantiator::doAddInstantiationInc(Node pv, Node n, TermProperties& pv_prop, SolvedForm& sf, unsigned effort, bool revertOnSuccess) { Node cnode = pv_prop.getCacheNode(); if( d_curr_subs_proc[pv][n].find( cnode )==d_curr_subs_proc[pv][n].end() ){ d_curr_subs_proc[pv][n][cnode] = true; if( Trace.isOn("cbqi-inst") ){ for( unsigned j=0; j " << n << std::endl; Assert( n.getType().isSubtypeOf( pv.getType() ) ); } //must ensure variables have been computed for n computeProgVars( n ); Assert( d_inelig.find( n )==d_inelig.end() ); //substitute into previous substitutions, when applicable std::vector< Node > a_var; a_var.push_back( pv ); std::vector< Node > a_subs; a_subs.push_back( n ); std::vector< TermProperties > a_prop; a_prop.push_back( pv_prop ); std::vector< Node > a_non_basic; if( !pv_prop.isBasic() ){ a_non_basic.push_back( pv ); } bool success = true; std::map< int, Node > prev_subs; std::map< int, TermProperties > prev_prop; std::map< int, Node > prev_sym_subs; std::vector< Node > new_non_basic; Trace("cbqi-inst-debug2") << "Applying substitutions to previous substitution terms..." << std::endl; for( unsigned j=0; j n } // based on the above substitution, we have: // x = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> n } // is equivalent to // a_pv_prop.getModifiedTerm( x ) = new_subs // thus we must compose substitutions: // a_pv_prop.getModifiedTerm( sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) ) = new_subs prev_prop[j] = sf.d_props[j]; bool prev_basic = sf.d_props[j].isBasic(); // now compose the property sf.d_props[j].composeProperty( a_pv_prop ); // if previously was basic, becomes non-basic if( prev_basic && !sf.d_props[j].isBasic() ){ Assert( std::find( sf.d_non_basic.begin(), sf.d_non_basic.end(), sf.d_vars[j] )==sf.d_non_basic.end() ); new_non_basic.push_back( sf.d_vars[j] ); sf.d_non_basic.push_back( sf.d_vars[j] ); } } if( sf.d_subs[j]!=prev_subs[j] ){ computeProgVars( sf.d_subs[j] ); Assert( d_inelig.find( sf.d_subs[j] )==d_inelig.end() ); } Trace("cbqi-inst-debug2") << "Subs " << j << " " << sf.d_subs[j] << std::endl; }else{ Trace("cbqi-inst-debug2") << "...failed to apply substitution to " << sf.d_subs[j] << std::endl; success = false; break; } }else{ Trace("cbqi-inst-debug2") << "Skip " << j << " " << sf.d_subs[j] << std::endl; } } if( success ){ Trace("cbqi-inst-debug2") << "Adding to vectors..." << std::endl; sf.push_back( pv, n, pv_prop ); Trace("cbqi-inst-debug2") << "Recurse..." << std::endl; unsigned i = d_curr_index[pv]; success = doAddInstantiation( sf, d_stack_vars.empty() ? i+1 : i, effort ); if (!success || revertOnSuccess) { Trace("cbqi-inst-debug2") << "Removing from vectors..." << std::endl; sf.pop_back( pv, n, pv_prop ); } } if (success && !revertOnSuccess) { 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; } for( std::map< int, TermProperties >::iterator it = prev_prop.begin(); it != prev_prop.end(); it++ ){ sf.d_props[it->first] = it->second; } for( unsigned i=0; i& vars, std::vector< Node >& subs, std::vector< Node >& lemmas ) { if( vars.size()>d_vars.size() ){ Trace("cbqi-inst-debug") << "Reconstructing instantiations...." << std::endl; std::map< Node, Node > subs_map; for( unsigned i=0; i::iterator it = subs_map.find( d_vars[i] ); Assert( it!=subs_map.end() ); Node n = it->second; Trace("cbqi-inst-debug") << " " << d_vars[i] << " -> " << n << std::endl; subs.push_back( n ); } } if( !d_var_order_index.empty() ){ std::vector< Node > subs_orig; subs_orig.insert( subs_orig.end(), subs.begin(), subs.end() ); subs.clear(); for( unsigned i=0; idoAddInstantiation( subs ); for( unsigned i=0; iaddLemma( lemmas[i] ); } return ret; } bool CegInstantiator::canApplyBasicSubstitution( Node n, std::vector< Node >& non_basic ){ Assert( d_prog_var.find( n )!=d_prog_var.end() ); if( !non_basic.empty() ){ for (std::unordered_set::iterator it = d_prog_var[n].begin(); it != d_prog_var[n].end(); ++it) { if (std::find(non_basic.begin(), non_basic.end(), *it) != non_basic.end()) { return false; } } } return true; } Node CegInstantiator::applySubstitution( TypeNode tn, Node n, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop, std::vector< Node >& non_basic, TermProperties& pv_prop, bool try_coeff ) { computeProgVars( n ); Assert( n==Rewriter::rewrite( n ) ); bool is_basic = canApplyBasicSubstitution( n, non_basic ); if( Trace.isOn("cegqi-si-apply-subs-debug") ){ Trace("cegqi-si-apply-subs-debug") << "is_basic = " << is_basic << " " << tn << std::endl; for( unsigned i=0; i " << subs[i] << " types : " << vars[i].getType() << " -> " << subs[i].getType() << std::endl; Assert( subs[i].getType().isSubtypeOf( vars[i].getType() ) ); } } Node nret; if( is_basic ){ nret = n.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); }else{ if( !tn.isInteger() ){ //can do basic substitution instead with divisions std::vector< Node > nvars; std::vector< Node > nsubs; for( unsigned i=0; imkNode( MULT, subs[i], NodeManager::currentNM()->mkConst( Rational(1)/prop[i].d_coeff.getConst() ) ); nn = NodeManager::currentNM()->mkNode( kind::TO_INTEGER, nn ); nn = Rewriter::rewrite( nn ); nsubs.push_back( nn ); }else{ nsubs.push_back( subs[i] ); } } nret = n.substitute( vars.begin(), vars.end(), nsubs.begin(), nsubs.end() ); }else if( try_coeff ){ //must convert to monomial representation std::map< Node, Node > msum; if( QuantArith::getMonomialSum( n, msum ) ){ std::map< Node, Node > msum_coeff; std::map< Node, Node > msum_term; for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ //check if in substitution std::vector< Node >::iterator its = std::find( vars.begin(), vars.end(), it->first ); if( its!=vars.end() ){ int index = its-vars.begin(); if( prop[index].d_coeff.isNull() ){ //apply substitution msum_term[it->first] = subs[index]; }else{ //apply substitution, multiply to ensure no divisibility conflict msum_term[it->first] = subs[index]; //relative coefficient msum_coeff[it->first] = prop[index].d_coeff; if( pv_prop.d_coeff.isNull() ){ pv_prop.d_coeff = prop[index].d_coeff; }else{ pv_prop.d_coeff = NodeManager::currentNM()->mkNode( MULT, pv_prop.d_coeff, prop[index].d_coeff ); } } }else{ msum_term[it->first] = it->first; } } //make sum with normalized coefficient if( !pv_prop.d_coeff.isNull() ){ pv_prop.d_coeff = Rewriter::rewrite( pv_prop.d_coeff ); Trace("cegqi-si-apply-subs-debug") << "Combined coeff : " << pv_prop.d_coeff << std::endl; std::vector< Node > children; for( std::map< Node, Node >::iterator it = msum.begin(); it != msum.end(); ++it ){ Node c_coeff; if( !msum_coeff[it->first].isNull() ){ c_coeff = Rewriter::rewrite( NodeManager::currentNM()->mkConst( pv_prop.d_coeff.getConst() / msum_coeff[it->first].getConst() ) ); }else{ c_coeff = pv_prop.d_coeff; } if( !it->second.isNull() ){ c_coeff = NodeManager::currentNM()->mkNode( MULT, c_coeff, it->second ); } 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; } Node nretc = children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( PLUS, children ); nretc = Rewriter::rewrite( nretc ); //ensure that nret does not contain vars if( !TermUtil::containsTerms( nretc, vars ) ){ //result is ( nret / pv_prop.d_coeff ) nret = nretc; }else{ Trace("cegqi-si-apply-subs-debug") << "Failed, since result " << nretc << " contains free variable." << std::endl; } }else{ //implies that we have a monomial that has a free variable Trace("cegqi-si-apply-subs-debug") << "Failed to find coefficient during substitution, implies monomial with free variable." << std::endl; } }else{ Trace("cegqi-si-apply-subs-debug") << "Failed to find monomial sum " << n << std::endl; } } } if( n!=nret && !nret.isNull() ){ nret = Rewriter::rewrite( nret ); } return nret; } Node CegInstantiator::applySubstitutionToLiteral( Node lit, std::vector< Node >& vars, std::vector< Node >& subs, std::vector< TermProperties >& prop, std::vector< Node >& non_basic ) { computeProgVars( lit ); bool is_basic = canApplyBasicSubstitution( lit, non_basic ); Node lret; if( is_basic ){ lret = lit.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() ); }else{ Node atom = lit.getKind()==NOT ? lit[0] : lit; bool pol = lit.getKind()!=NOT; //arithmetic inequalities and disequalities if( atom.getKind()==GEQ || ( atom.getKind()==EQUAL && !pol && atom[0].getType().isReal() ) ){ Assert( atom.getKind()!=GEQ || atom[1].isConst() ); Node atom_lhs; Node atom_rhs; if( atom.getKind()==GEQ ){ atom_lhs = atom[0]; atom_rhs = atom[1]; }else{ atom_lhs = NodeManager::currentNM()->mkNode( MINUS, atom[0], atom[1] ); atom_lhs = Rewriter::rewrite( atom_lhs ); atom_rhs = getQuantifiersEngine()->getTermUtil()->d_zero; } //must be an eligible term if( isEligible( atom_lhs ) ){ //apply substitution to LHS of atom TermProperties atom_lhs_prop; atom_lhs = applySubstitution( NodeManager::currentNM()->realType(), atom_lhs, vars, subs, prop, non_basic, atom_lhs_prop ); if( !atom_lhs.isNull() ){ if( !atom_lhs_prop.d_coeff.isNull() ){ atom_rhs = Rewriter::rewrite( NodeManager::currentNM()->mkNode( MULT, atom_lhs_prop.d_coeff, atom_rhs ) ); } lret = NodeManager::currentNM()->mkNode( atom.getKind(), atom_lhs, atom_rhs ); if( !pol ){ lret = lret.negate(); } } } }else{ // don't know how to apply substitution to literal } } if( lit!=lret && !lret.isNull() ){ lret = Rewriter::rewrite( lret ); } return lret; } bool CegInstantiator::check() { if( d_qe->getTheoryEngine()->needCheck() ){ Trace("cbqi-engine") << " CEGQI instantiator : wait until all ground theories are finished." << std::endl; return false; } processAssertions(); for( unsigned r=0; r<2; r++ ){ SolvedForm sf; d_stack_vars.clear(); d_bound_var_index.clear(); //try to add an instantiation if( doAddInstantiation( sf, 0, r==0 ? 0 : 2 ) ){ return true; } } Trace("cbqi-engine") << " WARNING : unable to find CEGQI single invocation instantiation." << std::endl; return false; } void collectPresolveEqTerms( Node n, std::map< Node, std::vector< Node > >& teq ) { if( n.getKind()==FORALL || n.getKind()==EXISTS ){ //do nothing }else{ if( n.getKind()==EQUAL ){ for( unsigned i=0; i<2; i++ ){ std::map< Node, std::vector< Node > >::iterator it = teq.find( n[i] ); if( it!=teq.end() ){ Node nn = n[ i==0 ? 1 : 0 ]; if( std::find( it->second.begin(), it->second.end(), nn )==it->second.end() ){ it->second.push_back( nn ); Trace("cbqi-presolve") << " - " << n[i] << " = " << nn << std::endl; } } } } for( unsigned i=0; i& vars, std::vector< Node >& terms, std::map< Node, std::vector< Node > >& teq, Node f, std::vector< Node >& conj ) { if( conj.size()<1000 ){ if( terms.size()==f[0].getNumChildren() ){ Node c = f[1].substitute( vars.begin(), vars.end(), terms.begin(), terms.end() ); conj.push_back( c ); }else{ unsigned i = terms.size(); Node v = f[0][i]; terms.push_back( Node::null() ); for( unsigned j=0; j ps_vars; std::map< Node, std::vector< Node > > teq; for( unsigned i=0; i terms; std::vector< Node > conj; getPresolveEqConjuncts( ps_vars, terms, teq, q, conj ); if( !conj.empty() ){ Node lem = conj.size()==1 ? conj[0] : NodeManager::currentNM()->mkNode( AND, conj ); Node g = NodeManager::currentNM()->mkSkolem( "g", NodeManager::currentNM()->booleanType() ); lem = NodeManager::currentNM()->mkNode( OR, g, lem ); Trace("cbqi-presolve-debug") << "Presolve lemma : " << lem << std::endl; d_qe->getOutputChannel().lemma( lem, false, true ); } } } void collectTheoryIds( TypeNode tn, std::map< TypeNode, bool >& visited, std::vector< TheoryId >& tids ){ std::map< TypeNode, bool >::iterator itt = visited.find( tn ); if( itt==visited.end() ){ visited[tn] = true; TheoryId tid = Theory::theoryOf( tn ); if( std::find( tids.begin(), tids.end(), tid )==tids.end() ){ tids.push_back( tid ); } if( tn.isDatatype() ){ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype(); for( unsigned i=0; ihasTerm( pv ) ){ Node pvr = ee->getRepresentative( pv ); if( d_curr_eqc.find( pvr )==d_curr_eqc.end() ){ Trace("cbqi-proc") << "Collect equivalence class " << pvr << std::endl; eq::EqClassIterator eqc_i = eq::EqClassIterator( pvr, ee ); while( !eqc_i.isFinished() ){ d_curr_eqc[pvr].push_back( *eqc_i ); ++eqc_i; } } } } //collect assertions for relevant theories for( unsigned i=0; igetTheoryEngine()->theoryOf( tid ); if( theory && d_qe->getTheoryEngine()->isTheoryEnabled(tid) ){ Trace("cbqi-proc") << "Collect assertions from theory " << tid << std::endl; d_curr_asserts[tid].clear(); //collect all assertions from theory for( context::CDList::const_iterator it = theory->facts_begin(); it != theory->facts_end(); ++ it) { Node lit = (*it).assertion; Node atom = lit.getKind()==NOT ? lit[0] : lit; if( d_is_nested_quant || std::find( d_ce_atoms.begin(), d_ce_atoms.end(), atom )!=d_ce_atoms.end() ){ d_curr_asserts[tid].push_back( lit ); Trace("cbqi-proc-debug") << "...add : " << lit << std::endl; }else{ Trace("cbqi-proc") << "...do not consider literal " << tid << " : " << lit << " since it is not part of CE body." << std::endl; } if( lit.getKind()==EQUAL ){ std::map< Node, std::map< Node, Node > >::iterator itae = d_aux_eq.find( lit ); if( itae!=d_aux_eq.end() ){ for( std::map< Node, Node >::iterator itae2 = itae->second.begin(); itae2 != itae->second.end(); ++itae2 ){ aux_subs[ itae2->first ] = itae2->second; Trace("cbqi-proc") << "......add substitution : " << itae2->first << " -> " << itae2->second << std::endl; } } }else if( atom.getKind()==BOOLEAN_TERM_VARIABLE ){ if( std::find( d_aux_vars.begin(), d_aux_vars.end(), atom )!=d_aux_vars.end() ){ Node val = NodeManager::currentNM()->mkConst( lit.getKind()!=NOT ); aux_subs[ atom ] = val; Trace("cbqi-proc") << "......add substitution : " << atom << " -> " << val << std::endl; } } } } } //collect equivalence classes that correspond to relevant theories Trace("cbqi-proc-debug") << "...collect typed equivalence classes" << std::endl; eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee ); while( !eqcs_i.isFinished() ){ Node r = *eqcs_i; TypeNode rtn = r.getType(); TheoryId tid = Theory::theoryOf( rtn ); //if we care about the theory of this eqc if( std::find( d_tids.begin(), d_tids.end(), tid )!=d_tids.end() ){ if( rtn.isInteger() || rtn.isReal() ){ rtn = rtn.getBaseType(); } Trace("cbqi-proc-debug") << "...type eqc: " << r << std::endl; d_curr_type_eqc[rtn].push_back( r ); if( d_curr_eqc.find( r )==d_curr_eqc.end() ){ Trace("cbqi-proc") << "Collect equivalence class " << r << std::endl; Trace("cbqi-proc-debug") << " "; eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee ); while( !eqc_i.isFinished() ){ Trace("cbqi-proc-debug") << *eqc_i << " "; d_curr_eqc[r].push_back( *eqc_i ); ++eqc_i; } Trace("cbqi-proc-debug") << std::endl; } } ++eqcs_i; } //construct substitution from auxiliary variable equalities (if e.g. ITE removal was applied to CE body of quantified formula) std::vector< Node > subs_lhs; std::vector< Node > subs_rhs; for( unsigned i=0; i::iterator it = aux_subs.find( r ); if( it!=aux_subs.end() ){ addToAuxVarSubstitution( subs_lhs, subs_rhs, r, it->second ); }else{ Trace("cbqi-proc") << "....no substitution found for auxiliary variable " << r << "!!! type is " << r.getType() << std::endl; Assert( false ); } } //apply substitutions to everything, if necessary if( !subs_lhs.empty() ){ Trace("cbqi-proc") << "Applying substitution : " << std::endl; for( unsigned i=0; i " << subs_rhs[i] << std::endl; } for( std::map< TheoryId, std::vector< Node > >::iterator it = d_curr_asserts.begin(); it != d_curr_asserts.end(); ++it ){ for( unsigned i=0; isecond.size(); i++ ){ Node lit = it->second[i]; lit = lit.substitute( subs_lhs.begin(), subs_lhs.end(), subs_rhs.begin(), subs_rhs.end() ); lit = Rewriter::rewrite( lit ); it->second[i] = lit; } } for( std::map< Node, std::vector< Node > >::iterator it = d_curr_eqc.begin(); it != d_curr_eqc.end(); ++it ){ for( unsigned i=0; isecond.size(); i++ ){ Node n = it->second[i]; n = n.substitute( subs_lhs.begin(), subs_lhs.end(), subs_rhs.begin(), subs_rhs.end() ); n = Rewriter::rewrite( n ); it->second[i] = n; } } } //remove unecessary assertions for( std::map< TheoryId, std::vector< Node > >::iterator it = d_curr_asserts.begin(); it != d_curr_asserts.end(); ++it ){ std::vector< Node > akeep; for( unsigned i=0; isecond.size(); i++ ){ Node n = it->second[i]; //must be an eligible term if( isEligible( n ) ){ //must contain at least one variable if( !d_prog_var[n].empty() ){ Trace("cbqi-proc") << "...literal[" << it->first << "] : " << n << std::endl; akeep.push_back( n ); }else{ Trace("cbqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains no relevant variables." << std::endl; } }else{ Trace("cbqi-proc") << "...remove literal from " << it->first << " : " << n << " since it contains ineligible terms." << std::endl; } } it->second.clear(); it->second.insert( it->second.end(), akeep.begin(), akeep.end() ); } //remove duplicate terms from eqc for( std::map< Node, std::vector< Node > >::iterator it = d_curr_eqc.begin(); it != d_curr_eqc.end(); ++it ){ std::vector< Node > new_eqc; for( unsigned i=0; isecond.size(); i++ ){ if( std::find( new_eqc.begin(), new_eqc.end(), it->second[i] )==new_eqc.end() ){ new_eqc.push_back( it->second[i] ); } } it->second.clear(); it->second.insert( it->second.end(), new_eqc.begin(), new_eqc.end() ); } } void CegInstantiator::addToAuxVarSubstitution( std::vector< Node >& subs_lhs, std::vector< Node >& subs_rhs, Node l, Node r ) { r = r.substitute( subs_lhs.begin(), subs_lhs.end(), subs_rhs.begin(), subs_rhs.end() ); std::vector< Node > cl; cl.push_back( l ); std::vector< Node > cr; cr.push_back( r ); for( unsigned i=0; igetModel()->getValue( n ); } Node CegInstantiator::getBoundVariable(TypeNode tn) { unsigned index = 0; std::unordered_map::iterator itb = d_bound_var_index.find(tn); if (itb != d_bound_var_index.end()) { index = itb->second; } d_bound_var_index[tn] = index + 1; while (index >= d_bound_var[tn].size()) { std::stringstream ss; ss << "x" << index; Node x = NodeManager::currentNM()->mkBoundVar(ss.str(), tn); d_bound_var[tn].push_back(x); } return d_bound_var[tn][index]; } void CegInstantiator::collectCeAtoms( Node n, std::map< Node, bool >& visited ) { if( n.getKind()==FORALL ){ d_is_nested_quant = true; }else if( visited.find( n )==visited.end() ){ visited[n] = true; if( TermUtil::isBoolConnectiveTerm( n ) ){ for( unsigned i=0; i& lems, std::vector< Node >& ce_vars ) { //Assert( d_vars.empty() ); d_vars.clear(); d_vars.insert( d_vars.end(), ce_vars.begin(), ce_vars.end() ); d_vars_set.insert(ce_vars.begin(), ce_vars.end()); //determine variable order: must do Reals before Ints if( !d_vars.empty() ){ TypeNode tn0 = d_vars[0].getType(); bool doSort = false; std::map< Node, unsigned > voo; for( unsigned i=0; igetTheoryEngine()->getTermFormulaRemover()->run(lems, iteSkolemMap); //Assert( d_aux_vars.empty() ); d_aux_vars.clear(); d_aux_eq.clear(); for(IteSkolemMap::iterator i = iteSkolemMap.begin(); i != iteSkolemMap.end(); ++i) { Trace("cbqi-debug") << " Auxiliary var (from ITE) : " << i->first << std::endl; d_aux_vars.push_back( i->first ); } for( unsigned i=0; i visited; collectTheoryIds( pvtn, visited, d_tids ); } } } Instantiator::Instantiator( QuantifiersEngine * qe, TypeNode tn ) : d_type( tn ){ d_closed_enum_type = qe->getTermEnumeration()->isClosedEnumerableType(tn); } bool Instantiator::processEqualTerm( CegInstantiator * ci, SolvedForm& sf, Node pv, TermProperties& pv_prop, Node n, unsigned effort ) { pv_prop.d_type = 0; return ci->doAddInstantiationInc( pv, n, pv_prop, sf, effort ); }