summaryrefslogtreecommitdiff
path: root/src/theory/quantifiers/cegqi/ceg_instantiator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/theory/quantifiers/cegqi/ceg_instantiator.cpp')
-rw-r--r--src/theory/quantifiers/cegqi/ceg_instantiator.cpp1337
1 files changed, 1337 insertions, 0 deletions
diff --git a/src/theory/quantifiers/cegqi/ceg_instantiator.cpp b/src/theory/quantifiers/cegqi/ceg_instantiator.cpp
new file mode 100644
index 000000000..d7d46bb4b
--- /dev/null
+++ b/src/theory/quantifiers/cegqi/ceg_instantiator.cpp
@@ -0,0 +1,1337 @@
+/********************* */
+/*! \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/cegqi/ceg_instantiator.h"
+#include "theory/quantifiers/cegqi/ceg_t_instantiator.h"
+
+#include "options/quantifiers_options.h"
+#include "smt/term_formula_removal.h"
+#include "theory/arith/arith_msum.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/ematching/trigger.h"
+#include "theory/theory_engine.h"
+
+using namespace std;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+std::ostream& operator<<(std::ostream& os, CegInstEffort e)
+{
+ switch (e)
+ {
+ case CEG_INST_EFFORT_NONE: os << "?"; break;
+ case CEG_INST_EFFORT_STANDARD: os << "STANDARD"; break;
+ case CEG_INST_EFFORT_STANDARD_MV: os << "STANDARD_MV"; break;
+ case CEG_INST_EFFORT_FULL: os << "FULL"; break;
+ default: Unreachable();
+ }
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os, CegInstPhase phase)
+{
+ switch (phase)
+ {
+ case CEG_INST_PHASE_NONE: os << "?"; break;
+ case CEG_INST_PHASE_EQC: os << "eqc"; break;
+ case CEG_INST_PHASE_EQUAL: os << "eq"; break;
+ case CEG_INST_PHASE_ASSERTION: os << "as"; break;
+ case CEG_INST_PHASE_MVALUE: os << "mv"; break;
+ default: Unreachable();
+ }
+ return os;
+}
+
+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),
+ d_effort(CEG_INST_EFFORT_NONE)
+{
+}
+
+CegInstantiator::~CegInstantiator() {
+ for (std::pair<Node, Instantiator*> inst : d_instantiator)
+ {
+ delete inst.second;
+ }
+ for (std::pair<TheoryId, InstantiatorPreprocess*> instp : d_tipp)
+ {
+ delete instp.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<n.getNumChildren(); i++ ){
+ computeProgVars( n[i] );
+ if( d_inelig.find( n[i] )!=d_inelig.end() ){
+ d_inelig.insert(n);
+ }
+ // all variables in child are contained in this
+ d_prog_var[n].insert(d_prog_var[n[i]].begin(), d_prog_var[n[i]].end());
+ }
+ // selectors applied to program variables are also variables
+ if (n.getKind() == APPLY_SELECTOR_TOTAL
+ && d_prog_var[n].find(n[0]) != d_prog_var[n].end())
+ {
+ d_prog_var[n].insert(n);
+ }
+ if (n.getKind() == kind::CHOICE)
+ {
+ d_prog_var.erase(n[0][0]);
+ }
+ }
+}
+
+bool CegInstantiator::isEligible( Node n ) {
+ //compute d_subs_fv, which program variables are contained in n, and determines if eligible
+ computeProgVars( n );
+ return d_inelig.find( n )==d_inelig.end();
+}
+
+bool CegInstantiator::hasVariable( Node n, Node pv ) {
+ computeProgVars( n );
+ return d_prog_var[n].find( pv )!=d_prog_var[n].end();
+}
+
+void CegInstantiator::activateInstantiationVariable(Node v, unsigned index)
+{
+ if( d_instantiator.find( v )==d_instantiator.end() ){
+ TypeNode tn = v.getType();
+ Instantiator * vinst;
+ if( tn.isReal() ){
+ vinst = new ArithInstantiator( d_qe, tn );
+ }else if( tn.isSort() ){
+ Assert( options::quantEpr() );
+ vinst = new EprInstantiator( d_qe, tn );
+ }else if( tn.isDatatype() ){
+ vinst = new DtInstantiator( d_qe, tn );
+ }else if( tn.isBitVector() ){
+ vinst = new BvInstantiator( d_qe, tn );
+ }else if( tn.isBoolean() ){
+ vinst = new ModelValueInstantiator( d_qe, tn );
+ }else{
+ //default
+ vinst = new Instantiator( d_qe, tn );
+ }
+ d_instantiator[v] = vinst;
+ }
+ d_curr_subs_proc[v].clear();
+ d_curr_index[v] = index;
+ d_curr_iphase[v] = CEG_INST_PHASE_NONE;
+}
+
+void CegInstantiator::registerTheoryIds(TypeNode tn,
+ std::map<TypeNode, bool>& visited)
+{
+ if (visited.find(tn) == visited.end())
+ {
+ visited[tn] = true;
+ TheoryId tid = Theory::theoryOf(tn);
+ registerTheoryId(tid);
+ if (tn.isDatatype())
+ {
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
+ for (unsigned i = 0; i < dt.getNumConstructors(); i++)
+ {
+ for (unsigned j = 0; j < dt[i].getNumArgs(); j++)
+ {
+ registerTheoryIds(
+ TypeNode::fromType(
+ ((SelectorType)dt[i][j].getType()).getRangeType()),
+ visited);
+ }
+ }
+ }
+ }
+}
+
+void CegInstantiator::registerTheoryId(TheoryId tid)
+{
+ if (std::find(d_tids.begin(), d_tids.end(), tid) == d_tids.end())
+ {
+ // setup any theory-specific preprocessors here
+ if (tid == THEORY_BV)
+ {
+ d_tipp[tid] = new BvInstantiatorPreprocess;
+ }
+ d_tids.push_back(tid);
+ }
+}
+
+void CegInstantiator::registerVariable(Node v, bool is_aux)
+{
+ Assert(std::find(d_vars.begin(), d_vars.end(), v) == d_vars.end());
+ Assert(std::find(d_aux_vars.begin(), d_aux_vars.end(), v)
+ == d_aux_vars.end());
+ if (!is_aux)
+ {
+ d_vars.push_back(v);
+ d_vars_set.insert(v);
+ }
+ else
+ {
+ d_aux_vars.push_back(v);
+ }
+ TypeNode vtn = v.getType();
+ Trace("cbqi-proc-debug") << "Collect theory ids from type " << vtn << " of "
+ << v << std::endl;
+ // collect relevant theories for this variable
+ std::map<TypeNode, bool> visited;
+ registerTheoryIds(vtn, visited);
+}
+
+void CegInstantiator::deactivateInstantiationVariable(Node v)
+{
+ d_curr_subs_proc.erase( v );
+ d_curr_index.erase( v );
+ d_curr_iphase.erase(v);
+}
+
+bool CegInstantiator::constructInstantiation(SolvedForm& sf, unsigned i)
+{
+ if( i==d_vars.size() ){
+ //solved for all variables, now construct instantiation
+ bool needsPostprocess =
+ sf.d_vars.size() > d_input_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, d_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, d_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();
+ }
+ activateInstantiationVariable(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, d_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 d_effort is full, we must choose at least one model value
+ if ((i + 1) < d_vars.size() || d_effort != CEG_INST_EFFORT_FULL)
+ {
+ //[1] easy case : pv is in the equivalence class as another term not containing pv
+ Trace("cbqi-inst-debug") << "[1] try based on equivalence class." << std::endl;
+ d_curr_iphase[pv] = CEG_INST_PHASE_EQC;
+ std::map< Node, std::vector< Node > >::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; k<it_eqc->second.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, d_effort))
+ {
+ return true;
+ }
+ // Do not consider more than one equal term,
+ // this helps non-monotonic strategies that may encounter
+ // duplicate instantiations.
+ break;
+ }
+ }
+ }
+ }
+ if (vinst->processEqualTerms(this, sf, pv, it_eqc->second, d_effort))
+ {
+ return true;
+ }
+ }else{
+ Trace("cbqi-inst-debug2") << "...eqc not found." << std::endl;
+ }
+
+ //[2] : 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, d_effort))
+ {
+ Trace("cbqi-inst-debug") << "[2] try based on solving equalities." << std::endl;
+ d_curr_iphase[pv] = CEG_INST_PHASE_EQUAL;
+ for( unsigned k=0; k<d_curr_type_eqc[pvtnb].size(); k++ ){
+ Node r = d_curr_type_eqc[pvtnb][k];
+ std::map< Node, std::vector< Node > >::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; kk<it_reqc->second.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; j<lhs.size(); j++ ){
+ //if this term or the another has pv in it, try to solve for it
+ if( hasVar || lhs_v[j] ){
+ Trace("cbqi-inst-debug") << "... " << i << "...try based on equality " << lhs[j] << " = " << ns << std::endl;
+ term_props.push_back( lhs_prop[j] );
+ terms.push_back( lhs[j] );
+ if (vinst->processEquality(
+ this, sf, pv, term_props, terms, d_effort))
+ {
+ return true;
+ }
+ term_props.pop_back();
+ terms.pop_back();
+ }
+ }
+ lhs.push_back( ns );
+ lhs_v.push_back( hasVar );
+ lhs_prop.push_back( pv_prop );
+ }else{
+ Trace("cbqi-inst-debug2") << "... term " << n << " is ineligible after substitution." << std::endl;
+ }
+ }else{
+ Trace("cbqi-inst-debug2") << "... term " << n << " is ineligible." << std::endl;
+ }
+ }
+ }
+ }
+
+ //[3] directly look at assertions
+ if (vinst->hasProcessAssertion(this, sf, pv, d_effort))
+ {
+ Trace("cbqi-inst-debug") << "[3] try based on assertions." << std::endl;
+ d_curr_iphase[pv] = CEG_INST_PHASE_ASSERTION;
+ 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; j<ita->second.size(); j++) {
+ Node lit = ita->second[j];
+ if( lits.find(lit)==lits.end() ){
+ lits.insert(lit);
+ Node plit;
+ if (options::cbqiRepeatLit() || !isSolvedAssertion(lit))
+ {
+ plit =
+ vinst->hasProcessAssertion(this, sf, pv, lit, d_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() ){
+ // check if contains pv
+ if( hasVariable( slit, pv ) ){
+ Trace("cbqi-inst-debug") << "...try based on literal "
+ << slit << "," << std::endl;
+ Trace("cbqi-inst-debug") << "...from " << lit
+ << std::endl;
+ if (vinst->processAssertion(
+ this, sf, pv, slit, lit, d_effort))
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (vinst->processAssertions(this, sf, pv, d_effort))
+ {
+ return true;
+ }
+ }
+ }
+
+ //[4] resort to using value in model. We do so if:
+ // - if the instantiator uses model values at this effort, or
+ // - if we are solving for a subfield of a datatype (is_cv).
+ if ((vinst->useModelValue(this, sf, pv, d_effort) || is_cv)
+ && vinst->allowModelValue(this, sf, pv, d_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") << "[4] " << i << "...try model value " << mv << std::endl;
+ d_curr_iphase[pv] = CEG_INST_PHASE_MVALUE;
+ CegInstEffort prev = d_effort;
+ if (d_effort < CEG_INST_EFFORT_STANDARD_MV)
+ {
+ // update the effort level to indicate we have used a model value
+ d_effort = CEG_INST_EFFORT_STANDARD_MV;
+ }
+ if (constructInstantiationInc(pv, mv, pv_prop_m, sf))
+ {
+ return true;
+ }
+ d_effort = prev;
+ }
+ 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 );
+ deactivateInstantiationVariable(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::constructInstantiationInc(Node pv,
+ Node n,
+ TermProperties& pv_prop,
+ SolvedForm& sf,
+ 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-debug") ){
+ for( unsigned j=0; j<sf.d_subs.size(); j++ ){
+ Trace("cbqi-inst-debug") << " ";
+ }
+ Trace("cbqi-inst-debug") << sf.d_subs.size() << ": (" << d_curr_iphase[pv]
+ << ") ";
+ Node mod_pv = pv_prop.getModifiedTerm( pv );
+ Trace("cbqi-inst-debug") << mod_pv << " -> " << 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<sf.d_subs.size(); j++ ){
+ Trace("cbqi-inst-debug2") << " Apply for " << sf.d_subs[j] << std::endl;
+ Assert( d_prog_var.find( sf.d_subs[j] )!=d_prog_var.end() );
+ if( d_prog_var[sf.d_subs[j]].find( pv )!=d_prog_var[sf.d_subs[j]].end() ){
+ prev_subs[j] = sf.d_subs[j];
+ TNode tv = pv;
+ TNode ts = n;
+ TermProperties a_pv_prop;
+ Node new_subs = applySubstitution( sf.d_vars[j].getType(), sf.d_subs[j], a_var, a_subs, a_prop, a_non_basic, a_pv_prop, true );
+ if( !new_subs.isNull() ){
+ sf.d_subs[j] = new_subs;
+ // the substitution apply to this term resulted in a non-basic substitution relationship
+ if( !a_pv_prop.isBasic() ){
+ // we are processing:
+ // sf.d_props[j].getModifiedTerm( sf.d_vars[j] ) = sf.d_subs[j] { pv_prop.getModifiedTerm( pv ) -> 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 = constructInstantiation(sf, d_stack_vars.empty() ? i + 1 : i);
+ 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<new_non_basic.size(); i++ ){
+ sf.d_non_basic.pop_back();
+ }
+ return success;
+ }
+ }else{
+ //already tried this substitution
+ return false;
+ }
+}
+
+bool CegInstantiator::doAddInstantiation( std::vector< Node >& vars, std::vector< Node >& subs, std::vector< Node >& lemmas ) {
+ if (vars.size() > d_input_vars.size() || !d_var_order_index.empty())
+ {
+ Trace("cbqi-inst-debug") << "Reconstructing instantiations...." << std::endl;
+ std::map< Node, Node > subs_map;
+ for( unsigned i=0; i<subs.size(); i++ ){
+ subs_map[vars[i]] = subs[i];
+ }
+ subs.clear();
+ for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
+ {
+ std::map<Node, Node>::iterator it = subs_map.find(d_input_vars[i]);
+ Assert( it!=subs_map.end() );
+ Node n = it->second;
+ Trace("cbqi-inst-debug") << " " << d_input_vars[i] << " -> " << n
+ << std::endl;
+ Assert(n.getType().isSubtypeOf(d_input_vars[i].getType()));
+ subs.push_back( n );
+ }
+ }
+ if (Trace.isOn("cbqi-inst"))
+ {
+ Trace("cbqi-inst") << "Ceg Instantiator produced : " << std::endl;
+ for (unsigned i = 0, size = d_input_vars.size(); i < size; ++i)
+ {
+ Node v = d_input_vars[i];
+ Trace("cbqi-inst") << i << " (" << d_curr_iphase[v] << ") : "
+ << v << " -> " << subs[i] << std::endl;
+ Assert(subs[i].getType().isSubtypeOf(v.getType()));
+ }
+ }
+ Trace("cbqi-inst-debug") << "Do the instantiation...." << std::endl;
+ bool ret = d_out->doAddInstantiation( subs );
+ for( unsigned i=0; i<lemmas.size(); i++ ){
+ d_out->addLemma( 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<Node, NodeHashFunction>::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.size(); i++ ){
+ Trace("cegqi-si-apply-subs-debug") << " " << vars[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; i<vars.size(); i++ ){
+ if( !prop[i].d_coeff.isNull() ){
+ Assert( vars[i].getType().isInteger() );
+ Assert( prop[i].d_coeff.isConst() );
+ Node nn = NodeManager::currentNM()->mkNode( MULT, subs[i], NodeManager::currentNM()->mkConst( Rational(1)/prop[i].d_coeff.getConst<Rational>() ) );
+ 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 (ArithMSum::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<Rational>() / msum_coeff[it->first].getConst<Rational>() ) );
+ }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++ ){
+ d_effort = r == 0 ? CEG_INST_EFFORT_STANDARD : CEG_INST_EFFORT_FULL;
+ SolvedForm sf;
+ d_stack_vars.clear();
+ d_bound_var_index.clear();
+ d_solved_asserts.clear();
+ //try to add an instantiation
+ if (constructInstantiation(sf, 0))
+ {
+ 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<n.getNumChildren(); i++ ){
+ collectPresolveEqTerms( n[i], teq );
+ }
+ }
+}
+
+void getPresolveEqConjuncts( std::vector< Node >& 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<teq[v].size(); j++ ){
+ terms[i] = teq[v][j];
+ getPresolveEqConjuncts( vars, terms, teq, f, conj );
+ }
+ terms.pop_back();
+ }
+ }
+}
+
+void CegInstantiator::presolve( Node q ) {
+ //at preregister time, add proxy of obvious instantiations up front, which helps learning during preprocessing
+ //only if no nested quantifiers
+ if( !QuantifiersRewriter::containsQuantifiers( q[1] ) ){
+ std::vector< Node > ps_vars;
+ std::map< Node, std::vector< Node > > teq;
+ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+ ps_vars.push_back( q[0][i] );
+ teq[q[0][i]].clear();
+ }
+ collectPresolveEqTerms( q[1], teq );
+ std::vector< Node > 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 CegInstantiator::processAssertions() {
+ Trace("cbqi-proc") << "--- Process assertions, #var = " << d_vars.size() << ", #aux-var = " << d_aux_vars.size() << std::endl;
+ d_curr_asserts.clear();
+ d_curr_eqc.clear();
+ d_curr_type_eqc.clear();
+
+ // must use master equality engine to avoid value instantiations
+ eq::EqualityEngine* ee = d_qe->getMasterEqualityEngine();
+ //to eliminate identified illegal terms
+ std::map< Node, Node > aux_subs;
+
+ //for each variable
+ for( unsigned i=0; i<d_vars.size(); i++ ){
+ Node pv = d_vars[i];
+ TypeNode pvtn = pv.getType();
+ Trace("cbqi-proc-debug") << "Collect theory ids from type " << pvtn << " of " << pv << std::endl;
+ //collect information about eqc
+ if( ee->hasTerm( 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; i<d_tids.size(); i++ ){
+ TheoryId tid = d_tids[i];
+ Theory* theory = d_qe->getTheoryEngine()->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<Assertion>::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<d_aux_vars.size(); i++ ){
+ Node r = d_aux_vars[i];
+ std::map< Node, Node >::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_lhs.size(); i++ ){
+ Trace("cbqi-proc") << " " << subs_lhs[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; i<it->second.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; i<it->second.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; i<it->second.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; i<it->second.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; i<subs_lhs.size(); i++ ){
+ Node nr = subs_rhs[i].substitute( cl.begin(), cl.end(), cr.begin(), cr.end() );
+ nr = Rewriter::rewrite( nr );
+ subs_rhs[i] = nr;
+ }
+
+ subs_lhs.push_back( l );
+ subs_rhs.push_back( r );
+}
+
+Node CegInstantiator::getModelValue( Node n ) {
+ return d_qe->getModel()->getValue( n );
+}
+
+Node CegInstantiator::getBoundVariable(TypeNode tn)
+{
+ unsigned index = 0;
+ std::unordered_map<TypeNode, unsigned, TypeNodeHashFunction>::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];
+}
+
+bool CegInstantiator::isSolvedAssertion(Node n) const
+{
+ return d_solved_asserts.find(n) != d_solved_asserts.end();
+}
+
+void CegInstantiator::markSolved(Node n, bool solved)
+{
+ if (solved)
+ {
+ d_solved_asserts.insert(n);
+ }
+ else if (isSolvedAssertion(n))
+ {
+ d_solved_asserts.erase(n);
+ }
+}
+
+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<n.getNumChildren(); i++ ){
+ collectCeAtoms( n[i], visited );
+ }
+ }else{
+ if( std::find( d_ce_atoms.begin(), d_ce_atoms.end(), n )==d_ce_atoms.end() ){
+ Trace("cbqi-ce-atoms") << "CE atoms : " << n << std::endl;
+ d_ce_atoms.push_back( n );
+ }
+ }
+ }
+}
+
+void CegInstantiator::registerCounterexampleLemma( std::vector< Node >& lems, std::vector< Node >& ce_vars ) {
+ Trace("cbqi-reg") << "Register counterexample lemma..." << std::endl;
+ d_input_vars.clear();
+ d_input_vars.insert(d_input_vars.end(), ce_vars.begin(), ce_vars.end());
+
+ //Assert( d_vars.empty() );
+ d_vars.clear();
+ registerTheoryId(THEORY_UF);
+ for (unsigned i = 0; i < ce_vars.size(); i++)
+ {
+ Trace("cbqi-reg") << " register input variable : " << ce_vars[i] << std::endl;
+ registerVariable(ce_vars[i]);
+ }
+
+ // preprocess with all relevant instantiator preprocessors
+ Trace("cbqi-debug") << "Preprocess based on theory-specific methods..."
+ << std::endl;
+ std::vector<Node> pvars;
+ pvars.insert(pvars.end(), d_vars.begin(), d_vars.end());
+ for (std::pair<const TheoryId, InstantiatorPreprocess*>& p : d_tipp)
+ {
+ p.second->registerCounterexampleLemma(lems, pvars);
+ }
+ // must register variables generated by preprocessors
+ Trace("cbqi-debug") << "Register variables from theory-specific methods "
+ << d_input_vars.size() << " " << pvars.size() << " ..."
+ << std::endl;
+ for (unsigned i = d_input_vars.size(), size = pvars.size(); i < size; ++i)
+ {
+ Trace("cbqi-reg") << " register theory preprocess variable : " << pvars[i]
+ << std::endl;
+ registerVariable(pvars[i]);
+ }
+
+ //remove ITEs
+ IteSkolemMap iteSkolemMap;
+ d_qe->getTheoryEngine()->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-reg") << " register aux variable : " << i->first << std::endl;
+ registerVariable(i->first, true);
+ }
+ for( unsigned i=0; i<lems.size(); i++ ){
+ Trace("cbqi-debug") << "Counterexample lemma (pre-rewrite) " << i << " : " << lems[i] << std::endl;
+ Node rlem = lems[i];
+ rlem = Rewriter::rewrite( rlem );
+ Trace("cbqi-debug") << "Counterexample lemma (post-rewrite) " << i << " : " << rlem << std::endl;
+ //record the literals that imply auxiliary variables to be equal to terms
+ if( lems[i].getKind()==ITE && rlem.getKind()==ITE ){
+ if( lems[i][1].getKind()==EQUAL && lems[i][2].getKind()==EQUAL && lems[i][1][0]==lems[i][2][0] ){
+ if( std::find( d_aux_vars.begin(), d_aux_vars.end(), lems[i][1][0] )!=d_aux_vars.end() ){
+ Node v = lems[i][1][0];
+ for( unsigned r=1; r<=2; r++ ){
+ d_aux_eq[rlem[r]][v] = lems[i][r][1];
+ Trace("cbqi-debug") << " " << rlem[r] << " implies " << v << " = " << lems[i][r][1] << std::endl;
+ }
+ }
+ }
+ }
+ /*else if( lems[i].getKind()==EQUAL && lems[i][0].getType().isBoolean() ){
+ //Boolean terms
+ if( std::find( d_aux_vars.begin(), d_aux_vars.end(), lems[i][0] )!=d_aux_vars.end() ){
+ Node v = lems[i][0];
+ d_aux_eq[rlem][v] = lems[i][1];
+ Trace("cbqi-debug") << " " << rlem << " implies " << v << " = " << lems[i][1] << std::endl;
+ }
+ }*/
+ lems[i] = rlem;
+ }
+
+ // determine variable order: must do Reals before Ints
+ Trace("cbqi-debug") << "Determine variable order..." << std::endl;
+ if (!d_vars.empty())
+ {
+ std::map<Node, unsigned> voo;
+ bool doSort = false;
+ std::vector<Node> vars;
+ std::map<TypeNode, std::vector<Node> > tvars;
+ for (unsigned i = 0, size = d_vars.size(); i < size; i++)
+ {
+ voo[d_vars[i]] = i;
+ d_var_order_index.push_back(0);
+ TypeNode tn = d_vars[i].getType();
+ if (tn.isInteger())
+ {
+ doSort = true;
+ tvars[tn].push_back(d_vars[i]);
+ }
+ else
+ {
+ vars.push_back(d_vars[i]);
+ }
+ }
+ if (doSort)
+ {
+ Trace("cbqi-debug") << "Sort variables based on ordering." << std::endl;
+ for (std::pair<const TypeNode, std::vector<Node> >& vs : tvars)
+ {
+ vars.insert(vars.end(), vs.second.begin(), vs.second.end());
+ }
+
+ Trace("cbqi-debug") << "Consider variables in this order : " << std::endl;
+ for (unsigned i = 0; i < vars.size(); i++)
+ {
+ d_var_order_index[voo[vars[i]]] = i;
+ Trace("cbqi-debug") << " " << vars[i] << " : " << vars[i].getType()
+ << ", index was : " << voo[vars[i]] << std::endl;
+ d_vars[i] = vars[i];
+ }
+ Trace("cbqi-debug") << std::endl;
+ }
+ else
+ {
+ d_var_order_index.clear();
+ }
+ }
+
+ //collect atoms from all lemmas: we will only do bounds coming from original body
+ d_is_nested_quant = false;
+ std::map< Node, bool > visited;
+ for( unsigned i=0; i<lems.size(); i++ ){
+ collectCeAtoms( lems[i], visited );
+ }
+}
+
+
+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,
+ CegInstEffort effort)
+{
+ pv_prop.d_type = 0;
+ return ci->constructInstantiationInc(pv, n, pv_prop, sf);
+}
+
+} /* CVC4::theory::quantifiers namespace */
+} /* CVC4::theory namespace */
+} /* CVC4 namespace */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback