From: Morgan Deters Date: Tue, 31 Jul 2012 21:24:31 +0000 (+0000) Subject: Moving some instantiation-related stuff from src/theory to src/theory/quantifiers... X-Git-Tag: cvc5-1.0.0~7904 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b88133bc679c541798c2063fec2bc441e744328a;p=cvc5.git Moving some instantiation-related stuff from src/theory to src/theory/quantifiers and src/theory/rewriterules. This unclutters the src/theory directory somewhat. The namespaces weren't changed, only the file locations. --- diff --git a/src/theory/Makefile.am b/src/theory/Makefile.am index 7a4cde04d..8f6ab76c2 100644 --- a/src/theory/Makefile.am +++ b/src/theory/Makefile.am @@ -38,23 +38,8 @@ libtheory_la_SOURCES = \ unconstrained_simplifier.cpp \ quantifiers_engine.h \ quantifiers_engine.cpp \ - instantiator_default.h \ - instantiator_default.cpp \ - rr_inst_match.h \ - rr_inst_match_impl.h \ - rr_inst_match.cpp \ - rr_trigger.h \ - rr_trigger.cpp \ - rr_candidate_generator.h \ - rr_candidate_generator.cpp \ - inst_match.h \ - inst_match.cpp \ - trigger.h \ - trigger.cpp \ model.h \ - model.cpp \ - candidate_generator.h \ - candidate_generator.cpp + model.cpp nodist_libtheory_la_SOURCES = \ rewriter_tables.h \ diff --git a/src/theory/arrays/theory_arrays_instantiator.cpp b/src/theory/arrays/theory_arrays_instantiator.cpp index f5a722737..844a11c31 100644 --- a/src/theory/arrays/theory_arrays_instantiator.cpp +++ b/src/theory/arrays/theory_arrays_instantiator.cpp @@ -18,7 +18,7 @@ #include "theory/arrays/theory_arrays_instantiator.h" #include "theory/arrays/theory_arrays.h" #include "theory/quantifiers/options.h" -#include "theory/rr_candidate_generator.h" +#include "theory/rewriterules/rr_candidate_generator.h" using namespace std; using namespace CVC4; diff --git a/src/theory/candidate_generator.cpp b/src/theory/candidate_generator.cpp deleted file mode 100644 index de98d709d..000000000 --- a/src/theory/candidate_generator.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/********************* */ -/*! \file candidate_generator.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: mdeters - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Implementation of theory uf candidate generator class - **/ - -#include "theory/candidate_generator.h" -#include "theory/theory_engine.h" -#include "theory/uf/theory_uf.h" -#include "theory/quantifiers/term_database.h" -#include "theory/inst_match.h" -#include "theory/quantifiers_engine.h" - -using namespace std; -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::context; -using namespace CVC4::theory; -using namespace CVC4::theory::inst; - -bool CandidateGenerator::isLegalCandidate( Node n ){ - return ( !n.getAttribute(NoMatchAttribute()) && ( !options::cbqi() || !n.hasAttribute(InstConstantAttribute()) ) ); -} - -void CandidateGeneratorQueue::addCandidate( Node n ) { - if( isLegalCandidate( n ) ){ - d_candidates.push_back( n ); - } -} - -void CandidateGeneratorQueue::reset( Node eqc ){ - if( d_candidate_index>0 ){ - d_candidates.erase( d_candidates.begin(), d_candidates.begin() + d_candidate_index ); - d_candidate_index = 0; - } - if( !eqc.isNull() ){ - d_candidates.push_back( eqc ); - } -} -Node CandidateGeneratorQueue::getNextCandidate(){ - if( d_candidate_index<(int)d_candidates.size() ){ - Node n = d_candidates[d_candidate_index]; - d_candidate_index++; - return n; - }else{ - d_candidate_index = 0; - d_candidates.clear(); - return Node::null(); - } -} - -#if 0 - -CandidateGeneratorQE::CandidateGeneratorQE( QuantifiersEngine* qe, Node op ) : - d_op( op ), d_qe( qe ), d_term_iter( -2 ){ - Assert( !d_op.isNull() ); -} -void CandidateGeneratorQE::resetInstantiationRound(){ - d_term_iter_limit = d_qe->getTermDatabase()->d_op_map[d_op].size(); -} - -void CandidateGeneratorQE::reset( Node eqc ){ - if( eqc.isNull() ){ - d_term_iter = 0; - }else{ - //create an equivalence class iterator in eq class eqc - if( d_qe->getEqualityQuery()->getEngine()->hasTerm( eqc ) ){ - eqc = d_qe->getEqualityQuery()->getEngine()->getRepresentative( eqc ); - d_eqc = eq::EqClassIterator( eqc, d_qe->getEqualityQuery()->getEngine() ); - d_retNode = Node::null(); - }else{ - d_retNode = eqc; - } - d_term_iter = -1; - } -} - -Node CandidateGeneratorQE::getNextCandidate(){ - if( d_term_iter>=0 ){ - //get next candidate term in the uf term database - while( d_term_itergetTermDatabase()->d_op_map[d_op][d_term_iter]; - d_term_iter++; - if( isLegalCandidate( n ) ){ - return n; - } - } - }else if( d_term_iter==-1 ){ - if( d_retNode.isNull() ){ - //get next candidate term in equivalence class - while( !d_eqc.isFinished() ){ - Node n = (*d_eqc); - ++d_eqc; - if( n.hasOperator() && n.getOperator()==d_op ){ - if( isLegalCandidate( n ) ){ - return n; - } - } - } - }else{ - Node ret; - if( d_retNode.hasOperator() && d_retNode.getOperator()==d_op ){ - ret = d_retNode; - } - d_term_iter = -2; //done returning matches - return ret; - } - } - return Node::null(); -} - -#else - - -CandidateGeneratorQE::CandidateGeneratorQE( QuantifiersEngine* qe, Node op ) : - d_op( op ), d_qe( qe ), d_term_iter( -1 ){ - Assert( !d_op.isNull() ); -} -void CandidateGeneratorQE::resetInstantiationRound(){ - d_term_iter_limit = d_qe->getTermDatabase()->d_op_map[d_op].size(); -} - -void CandidateGeneratorQE::reset( Node eqc ){ - d_term_iter = 0; - if( eqc.isNull() ){ - d_using_term_db = true; - }else{ - //create an equivalence class iterator in eq class eqc - d_eqc.clear(); - d_qe->getEqualityQuery()->getEquivalenceClass( eqc, d_eqc ); - d_using_term_db = false; - } -} - -Node CandidateGeneratorQE::getNextCandidate(){ - if( d_term_iter>=0 ){ - if( d_using_term_db ){ - //get next candidate term in the uf term database - while( d_term_itergetTermDatabase()->d_op_map[d_op][d_term_iter]; - d_term_iter++; - if( isLegalCandidate( n ) ){ - return n; - } - } - }else{ - while( d_term_iter<(int)d_eqc.size() ){ - Node n = d_eqc[d_term_iter]; - d_term_iter++; - if( n.hasOperator() && n.getOperator()==d_op ){ - if( isLegalCandidate( n ) ){ - return n; - } - } - } - } - } - return Node::null(); -} - -#endif - -//CandidateGeneratorQEDisequal::CandidateGeneratorQEDisequal( QuantifiersEngine* qe, Node eqc ) : -// d_qe( qe ), d_eq_class( eqc ){ -// d_eci = NULL; -//} -//void CandidateGeneratorQEDisequal::resetInstantiationRound(){ -// -//} -////we will iterate over all terms that are disequal from eqc -//void CandidateGeneratorQEDisequal::reset( Node eqc ){ -// //Assert( !eqc.isNull() ); -// ////begin iterating over equivalence classes that are disequal from eqc -// //d_eci = d_ith->getEquivalenceClassInfo( eqc ); -// //if( d_eci ){ -// // d_eqci_iter = d_eci->d_disequal.begin(); -// //} -//} -//Node CandidateGeneratorQEDisequal::getNextCandidate(){ -// //if( d_eci ){ -// // while( d_eqci_iter != d_eci->d_disequal.end() ){ -// // if( (*d_eqci_iter).second ){ -// // //we have an equivalence class that is disequal from eqc -// // d_cg->reset( (*d_eqci_iter).first ); -// // Node n = d_cg->getNextCandidate(); -// // //if there is a candidate in this equivalence class, return it -// // if( !n.isNull() ){ -// // return n; -// // } -// // } -// // ++d_eqci_iter; -// // } -// //} -// return Node::null(); -//} - - -CandidateGeneratorQELitEq::CandidateGeneratorQELitEq( QuantifiersEngine* qe, Node mpat ) : - d_match_pattern( mpat ), d_qe( qe ){ - -} -void CandidateGeneratorQELitEq::resetInstantiationRound(){ - -} -void CandidateGeneratorQELitEq::reset( Node eqc ){ - d_eq = eq::EqClassesIterator( d_qe->getEqualityQuery()->getEngine() ); -} -Node CandidateGeneratorQELitEq::getNextCandidate(){ - while( d_eq.isFinished() ){ - Node n = (*d_eq); - ++d_eq; - if( n.getType()==d_match_pattern[0].getType() ){ - //an equivalence class with the same type as the pattern, return reflexive equality - return NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), n, n ); - } - } - return Node::null(); -} - - -CandidateGeneratorQELitDeq::CandidateGeneratorQELitDeq( QuantifiersEngine* qe, Node mpat ) : - d_match_pattern( mpat ), d_qe( qe ){ - -} -void CandidateGeneratorQELitDeq::resetInstantiationRound(){ - -} -void CandidateGeneratorQELitDeq::reset( Node eqc ){ - Node false_term = d_qe->getEqualityQuery()->getEngine()->getRepresentative( NodeManager::currentNM()->mkConst(false) ); - d_eqc_false = eq::EqClassIterator( false_term, d_qe->getEqualityQuery()->getEngine() ); -} -Node CandidateGeneratorQELitDeq::getNextCandidate(){ - //get next candidate term in equivalence class - while( !d_eqc_false.isFinished() ){ - Node n = (*d_eqc_false); - ++d_eqc_false; - if( n.getKind()==d_match_pattern.getKind() ){ - //found an iff or equality, try to match it - //DO_THIS: cache to avoid redundancies? - //DO_THIS: do we need to try the symmetric equality for n? or will it also exist in the eq class of false? - return n; - } - } - return Node::null(); -} diff --git a/src/theory/candidate_generator.h b/src/theory/candidate_generator.h deleted file mode 100644 index 134b0e1b7..000000000 --- a/src/theory/candidate_generator.h +++ /dev/null @@ -1,187 +0,0 @@ -/********************* */ -/*! \file candidate_generator.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Theory uf candidate generator - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__CANDIDATE_GENERATOR_H -#define __CVC4__CANDIDATE_GENERATOR_H - -#include "theory/theory.h" -#include "theory/uf/equality_engine.h" - -namespace CVC4 { -namespace theory { - -class QuantifiersEngine; - -namespace inst { - -/** base class for generating candidates for matching */ -class CandidateGenerator { -public: - CandidateGenerator(){} - ~CandidateGenerator(){} - - /** Get candidates functions. These set up a context to get all match candidates. - cg->reset( eqc ); - do{ - Node cand = cg->getNextCandidate(); - //....... - }while( !cand.isNull() ); - - eqc is the equivalence class you are searching in - */ - virtual void reset( Node eqc ) = 0; - virtual Node getNextCandidate() = 0; - /** add candidate to list of nodes returned by this generator */ - virtual void addCandidate( Node n ) {} - /** call this at the beginning of each instantiation round */ - virtual void resetInstantiationRound() = 0; -public: - /** legal candidate */ - static bool isLegalCandidate( Node n ); -};/* class CandidateGenerator */ - -/** candidate generator queue (for manual candidate generation) */ -class CandidateGeneratorQueue : public CandidateGenerator { -private: - std::vector< Node > d_candidates; - int d_candidate_index; -public: - CandidateGeneratorQueue() : d_candidate_index( 0 ){} - ~CandidateGeneratorQueue(){} - - void addCandidate( Node n ); - - void resetInstantiationRound(){} - void reset( Node eqc ); - Node getNextCandidate(); -};/* class CandidateGeneratorQueue */ - -class CandidateGeneratorQEDisequal; - -#if 0 - -class CandidateGeneratorQE : public CandidateGenerator -{ - friend class CandidateGeneratorQEDisequal; -private: - //operator you are looking for - Node d_op; - //instantiator pointer - QuantifiersEngine* d_qe; - //the equality class iterator - eq::EqClassIterator d_eqc; - int d_term_iter; - int d_term_iter_limit; -private: - Node d_retNode; -public: - CandidateGeneratorQE( QuantifiersEngine* qe, Node op ); - ~CandidateGeneratorQE(){} - - void resetInstantiationRound(); - void reset( Node eqc ); - Node getNextCandidate(); -}; - -#else - -class CandidateGeneratorQE : public CandidateGenerator -{ - friend class CandidateGeneratorQEDisequal; -private: - //operator you are looking for - Node d_op; - //instantiator pointer - QuantifiersEngine* d_qe; - //the equality class iterator - std::vector< Node > d_eqc; - int d_term_iter; - int d_term_iter_limit; - bool d_using_term_db; -public: - CandidateGeneratorQE( QuantifiersEngine* qe, Node op ); - ~CandidateGeneratorQE(){} - - void resetInstantiationRound(); - void reset( Node eqc ); - Node getNextCandidate(); -}; - -#endif - -//class CandidateGeneratorQEDisequal : public CandidateGenerator -//{ -//private: -// //equivalence class -// Node d_eq_class; -// //equivalence class info -// EqClassInfo* d_eci; -// //equivalence class iterator -// EqClassInfo::BoolMap::const_iterator d_eqci_iter; -// //instantiator pointer -// QuantifiersEngine* d_qe; -//public: -// CandidateGeneratorQEDisequal( QuantifiersEngine* qe, Node eqc ); -// ~CandidateGeneratorQEDisequal(){} -// -// void resetInstantiationRound(); -// void reset( Node eqc ); //should be what you want to be disequal from -// Node getNextCandidate(); -//}; - -class CandidateGeneratorQELitEq : public CandidateGenerator -{ -private: - //the equality classes iterator - eq::EqClassesIterator d_eq; - //equality you are trying to match equalities for - Node d_match_pattern; - //einstantiator pointer - QuantifiersEngine* d_qe; -public: - CandidateGeneratorQELitEq( QuantifiersEngine* qe, Node mpat ); - ~CandidateGeneratorQELitEq(){} - - void resetInstantiationRound(); - void reset( Node eqc ); - Node getNextCandidate(); -}; - -class CandidateGeneratorQELitDeq : public CandidateGenerator -{ -private: - //the equality class iterator for false - eq::EqClassIterator d_eqc_false; - //equality you are trying to match disequalities for - Node d_match_pattern; - //einstantiator pointer - QuantifiersEngine* d_qe; -public: - CandidateGeneratorQELitDeq( QuantifiersEngine* qe, Node mpat ); - ~CandidateGeneratorQELitDeq(){} - - void resetInstantiationRound(); - void reset( Node eqc ); - Node getNextCandidate(); -}; - -}/* CVC4::theory::inst namespace */ -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ - -#endif /* __CVC4__THEORY_UF_INSTANTIATOR_H */ diff --git a/src/theory/datatypes/theory_datatypes_instantiator.cpp b/src/theory/datatypes/theory_datatypes_instantiator.cpp index 8ecf37fe2..23f3e8950 100644 --- a/src/theory/datatypes/theory_datatypes_instantiator.cpp +++ b/src/theory/datatypes/theory_datatypes_instantiator.cpp @@ -19,7 +19,7 @@ #include "theory/theory_engine.h" #include "theory/quantifiers/options.h" #include "theory/quantifiers/term_database.h" -#include "theory/rr_candidate_generator.h" +#include "theory/rewriterules/rr_candidate_generator.h" using namespace std; using namespace CVC4; diff --git a/src/theory/inst_match.cpp b/src/theory/inst_match.cpp deleted file mode 100644 index f7c21c555..000000000 --- a/src/theory/inst_match.cpp +++ /dev/null @@ -1,880 +0,0 @@ -/********************* */ -/*! \file inst_match.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Implementation of inst match class - **/ - -#include "theory/inst_match.h" -#include "theory/theory_engine.h" -#include "theory/quantifiers_engine.h" -#include "theory/candidate_generator.h" -#include "theory/uf/theory_uf_instantiator.h" -#include "theory/uf/equality_engine.h" -#include "theory/quantifiers/options.h" -#include "theory/quantifiers/model_engine.h" -#include "theory/quantifiers/term_database.h" -#include "theory/quantifiers/first_order_model.h" -#include "theory/quantifiers/term_database.h" - -using namespace std; -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::context; -using namespace CVC4::theory; -using namespace CVC4::theory::inst; - - -InstMatch::InstMatch() { -} - -InstMatch::InstMatch( InstMatch* m ) { - d_map = m->d_map; -} - -bool InstMatch::setMatch( EqualityQuery* q, TNode v, TNode m, bool & set ){ - std::map< Node, Node >::iterator vn = d_map.find( v ); - if( vn==d_map.end() ){ - set = true; - this->set(v,m); - Debug("matching-debug") << "Add partial " << v << "->" << m << std::endl; - return true; - }else{ - set = false; - return q->areEqual( vn->second, m ); - } -} - -bool InstMatch::setMatch( EqualityQuery* q, TNode v, TNode m ){ - bool set; - return setMatch(q,v,m,set); -} - -bool InstMatch::add( InstMatch& m ){ - for( std::map< Node, Node >::iterator it = m.d_map.begin(); it != m.d_map.end(); ++it ){ - if( d_map.find( it->first )==d_map.end() ){ - d_map[it->first] = it->second; - } - } - return true; -} - -bool InstMatch::merge( EqualityQuery* q, InstMatch& m ){ - for( std::map< Node, Node >::iterator it = m.d_map.begin(); it != m.d_map.end(); ++it ){ - if( d_map.find( it->first )==d_map.end() ){ - d_map[ it->first ] = it->second; - }else{ - if( it->second!=d_map[it->first] ){ - if( !q->areEqual( it->second, d_map[it->first] ) ){ - d_map.clear(); - return false; - } - } - } - } - return true; -} - -void InstMatch::debugPrint( const char* c ){ - for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ - Debug( c ) << " " << it->first << " -> " << it->second << std::endl; - } - //if( !d_splits.empty() ){ - // Debug( c ) << " Conditions: "; - // for( std::map< Node, Node >::iterator it = d_splits.begin(); it !=d_splits.end(); ++it ){ - // Debug( c ) << it->first << " = " << it->second << " "; - // } - // Debug( c ) << std::endl; - //} -} - -void InstMatch::makeComplete( Node f, QuantifiersEngine* qe ){ - for( int i=0; i<(int)qe->getTermDatabase()->d_inst_constants[f].size(); i++ ){ - Node ic = qe->getTermDatabase()->d_inst_constants[f][i]; - if( d_map.find( ic )==d_map.end() ){ - d_map[ ic ] = qe->getTermDatabase()->getFreeVariableForInstConstant( ic ); - } - } -} - -void InstMatch::makeInternal( QuantifiersEngine* qe ){ - if( options::cbqi() ){ - for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ - if( it->second.hasAttribute(InstConstantAttribute()) ){ - d_map[ it->first ] = qe->getEqualityQuery()->getInternalRepresentative( it->second ); - if( it->second.hasAttribute(InstConstantAttribute()) ){ - d_map[ it->first ] = qe->getTermDatabase()->getFreeVariableForInstConstant( it->first ); - } - } - } - } -} - -void InstMatch::makeRepresentative( QuantifiersEngine* qe ){ - for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ - d_map[ it->first ] = qe->getEqualityQuery()->getInternalRepresentative( it->second ); - if( options::cbqi() && it->second.hasAttribute(InstConstantAttribute()) ){ - d_map[ it->first ] = qe->getTermDatabase()->getFreeVariableForInstConstant( it->first ); - } - } -} - -void InstMatch::applyRewrite(){ - for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ - it->second = Rewriter::rewrite(it->second); - } -} - -void InstMatch::computeTermVec( QuantifiersEngine* qe, const std::vector< Node >& vars, std::vector< Node >& match ){ - for( int i=0; i<(int)vars.size(); i++ ){ - std::map< Node, Node >::iterator it = d_map.find( vars[i] ); - if( it!=d_map.end() && !it->second.isNull() ){ - match.push_back( it->second ); - }else{ - match.push_back( qe->getTermDatabase()->getFreeVariableForInstConstant( vars[i] ) ); - } - } -} -void InstMatch::computeTermVec( const std::vector< Node >& vars, std::vector< Node >& match ){ - for( int i=0; i<(int)vars.size(); i++ ){ - match.push_back( d_map[ vars[i] ] ); - } -} - - -/** add match m for quantifier f starting at index, take into account equalities q, return true if successful */ -void InstMatchTrie::addInstMatch2( QuantifiersEngine* qe, Node f, InstMatch& m, int index, ImtIndexOrder* imtio ){ - if( long(index)d_order.size()) ) ){ - int i_index = imtio ? imtio->d_order[index] : index; - Node n = m.get( qe->getTermDatabase()->getInstantiationConstant( f, i_index ) ); - d_data[n].addInstMatch2( qe, f, m, index+1, imtio ); - } -} - -/** exists match */ -bool InstMatchTrie::existsInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq, int index, ImtIndexOrder* imtio ){ - if( long(index)==long(f[0].getNumChildren()) || ( imtio && long(index)==long(imtio->d_order.size()) ) ){ - return true; - }else{ - int i_index = imtio ? imtio->d_order[index] : index; - Node n = m.get( qe->getTermDatabase()->getInstantiationConstant( f, i_index ) ); - std::map< Node, InstMatchTrie >::iterator it = d_data.find( n ); - if( it!=d_data.end() ){ - if( it->second.existsInstMatch( qe, f, m, modEq, index+1, imtio ) ){ - return true; - } - } - if( modEq ){ - //check modulo equality if any other instantiation match exists - if( qe->getEqualityQuery()->getEngine()->hasTerm( n ) ){ - eq::EqClassIterator eqc( qe->getEqualityQuery()->getEngine()->getRepresentative( n ), - qe->getEqualityQuery()->getEngine() ); - while( !eqc.isFinished() ){ - Node en = (*eqc); - if( en!=n ){ - std::map< Node, InstMatchTrie >::iterator itc = d_data.find( en ); - if( itc!=d_data.end() ){ - if( itc->second.existsInstMatch( qe, f, m, modEq, index+1, imtio ) ){ - return true; - } - } - } - ++eqc; - } - } - //for( std::map< Node, InstMatchTrie >::iterator itc = d_data.begin(); itc != d_data.end(); ++itc ){ - // if( itc->first!=n && qe->getEqualityQuery()->areEqual( n, itc->first ) ){ - // if( itc->second.existsInstMatch( qe, f, m, modEq, index+1 ) ){ - // return true; - // } - // } - //} - } - return false; - } -} - -bool InstMatchTrie::addInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq, ImtIndexOrder* imtio ){ - if( !existsInstMatch( qe, f, m, modEq, 0, imtio ) ){ - addInstMatch2( qe, f, m, 0, imtio ); - return true; - }else{ - return false; - } -} - -InstMatchGenerator::InstMatchGenerator( Node pat, QuantifiersEngine* qe, int matchPolicy ) : d_matchPolicy( matchPolicy ){ - initializePattern( pat, qe ); -} - -InstMatchGenerator::InstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe, int matchPolicy ) : d_matchPolicy( matchPolicy ){ - if( pats.size()==1 ){ - initializePattern( pats[0], qe ); - }else{ - initializePatterns( pats, qe ); - } -} - -void InstMatchGenerator::initializePatterns( std::vector< Node >& pats, QuantifiersEngine* qe ){ - int childMatchPolicy = d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ? 0 : d_matchPolicy; - for( int i=0; i<(int)pats.size(); i++ ){ - d_children.push_back( new InstMatchGenerator( pats[i], qe, childMatchPolicy ) ); - } - d_pattern = Node::null(); - d_match_pattern = Node::null(); - d_cg = NULL; -} - -void InstMatchGenerator::initializePattern( Node pat, QuantifiersEngine* qe ){ - Debug("inst-match-gen") << "Pattern term is " << pat << std::endl; - Assert( pat.hasAttribute(InstConstantAttribute()) ); - d_pattern = pat; - d_match_pattern = pat; - if( d_match_pattern.getKind()==NOT ){ - //we want to add the children of the NOT - d_match_pattern = d_pattern[0]; - } - if( d_match_pattern.getKind()==IFF || d_match_pattern.getKind()==EQUAL ){ - if( !d_match_pattern[0].hasAttribute(InstConstantAttribute()) ){ - Assert( d_match_pattern[1].hasAttribute(InstConstantAttribute()) ); - //swap sides - d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_pattern[1], d_match_pattern[0] ); - d_pattern = pat.getKind()==NOT ? d_pattern.notNode() : d_pattern; - if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching - d_match_pattern = d_match_pattern[1]; - }else{ - d_match_pattern = d_pattern[0][0]; - } - }else if( !d_match_pattern[1].hasAttribute(InstConstantAttribute()) ){ - Assert( d_match_pattern[0].hasAttribute(InstConstantAttribute()) ); - if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching - d_match_pattern = d_match_pattern[0]; - } - } - } - int childMatchPolicy = MATCH_GEN_DEFAULT; - for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ - if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){ - if( d_match_pattern[i].getKind()!=INST_CONSTANT ){ - d_children.push_back( new InstMatchGenerator( d_match_pattern[i], qe, childMatchPolicy ) ); - d_children_index.push_back( i ); - } - } - } - - Debug("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl; - - //create candidate generator - if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){ - Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); - //we will be producing candidates via literal matching heuristics - if( d_pattern.getKind()!=NOT ){ - //candidates will be all equalities - d_cg = new inst::CandidateGeneratorQELitEq( qe, d_match_pattern ); - }else{ - //candidates will be all disequalities - d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern ); - } - }else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF || d_pattern.getKind()==NOT ){ - Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); - if( d_pattern.getKind()==NOT ){ - Unimplemented("Disequal generator unimplemented"); - }else{ - Assert( Trigger::isAtomicTrigger( d_match_pattern ) ); - //we are matching only in a particular equivalence class - d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() ); - //store the equivalence class that we will call d_cg->reset( ... ) on - d_eq_class = d_pattern[1]; - } - }else if( Trigger::isAtomicTrigger( d_match_pattern ) ){ - //if( d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ){ - //Warning() << "Currently efficient e matching is not taken into account for quantifiers: " << d_pattern << std::endl; - //} - //we will be scanning lists trying to find d_match_pattern.getOperator() - d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() ); - }else{ - d_cg = new CandidateGeneratorQueue; - if( !Trigger::getPatternArithmetic( d_match_pattern.getAttribute(InstConstantAttribute()), d_match_pattern, d_arith_coeffs ) ){ - Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; - Warning() << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; - d_matchPolicy = MATCH_GEN_INTERNAL_ERROR; - }else{ - Debug("matching-arith") << "Generated arithmetic pattern for " << d_match_pattern << ": " << std::endl; - for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ - Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; - } - //we will treat this as match gen internal arithmetic - d_matchPolicy = MATCH_GEN_INTERNAL_ARITHMETIC; - } - } -} - -/** get match (not modulo equality) */ -bool InstMatchGenerator::getMatch( Node t, InstMatch& m, QuantifiersEngine* qe ){ - Debug("matching") << "Matching " << t << " against pattern " << d_match_pattern << " (" - << m.size() << ")" << ", " << d_children.size() << std::endl; - Assert( !d_match_pattern.isNull() ); - if( qe->d_optMatchIgnoreModelBasis && t.getAttribute(ModelBasisAttribute()) ){ - return true; - }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ARITHMETIC ){ - return getMatchArithmetic( t, m, qe ); - }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ERROR ){ - return false; - }else{ - EqualityQuery* q = qe->getEqualityQuery(); - //add m to partial match vector - std::vector< InstMatch > partial; - partial.push_back( InstMatch( &m ) ); - //if t is null - Assert( !t.isNull() ); - Assert( !t.hasAttribute(InstConstantAttribute()) ); - Assert( t.getKind()==d_match_pattern.getKind() ); - Assert( !Trigger::isAtomicTrigger( d_match_pattern ) || t.getOperator()==d_match_pattern.getOperator() ); - //first, check if ground arguments are not equal, or a match is in conflict - for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ - if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){ - if( d_match_pattern[i].getKind()==INST_CONSTANT ){ - if( !partial[0].setMatch( q, d_match_pattern[i], t[i] ) ){ - //match is in conflict - Debug("matching-debug") << "Match in conflict " << t[i] << " and " - << d_match_pattern[i] << " because " - << partial[0].get(d_match_pattern[i]) - << std::endl; - Debug("matching-fail") << "Match fail: " << partial[0].get(d_match_pattern[i]) << " and " << t[i] << std::endl; - return false; - } - } - }else{ - if( !q->areEqual( d_match_pattern[i], t[i] ) ){ - Debug("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl; - //ground arguments are not equal - return false; - } - } - } - //now, fit children into match - //we will be requesting candidates for matching terms for each child - std::vector< Node > reps; - for( int i=0; i<(int)d_children.size(); i++ ){ - Node rep = q->getRepresentative( t[ d_children_index[i] ] ); - reps.push_back( rep ); - d_children[i]->d_cg->reset( rep ); - } - - //combine child matches - int index = 0; - while( index>=0 && index<(int)d_children.size() ){ - partial.push_back( InstMatch( &partial[index] ) ); - if( d_children[index]->getNextMatch2( partial[index+1], qe ) ){ - index++; - }else{ - d_children[index]->d_cg->reset( reps[index] ); - partial.pop_back(); - if( !partial.empty() ){ - partial.pop_back(); - } - index--; - } - } - if( index>=0 ){ - m = partial.back(); - return true; - }else{ - return false; - } - } -} - -bool InstMatchGenerator::getNextMatch2( InstMatch& m, QuantifiersEngine* qe, bool saveMatched ){ - bool success = false; - Node t; - do{ - //get the next candidate term t - t = d_cg->getNextCandidate(); - //if t not null, try to fit it into match m - if( !t.isNull() && t.getType()==d_match_pattern.getType() ){ - success = getMatch( t, m, qe ); - } - }while( !success && !t.isNull() ); - if (saveMatched) m.d_matched = t; - return success; -} - -bool InstMatchGenerator::getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ){ - Debug("matching-arith") << "Matching " << t << " " << d_match_pattern << std::endl; - if( !d_arith_coeffs.empty() ){ - NodeBuilder<> tb(kind::PLUS); - Node ic = Node::null(); - for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ - Debug("matching-arith") << it->first << " -> " << it->second << std::endl; - if( !it->first.isNull() ){ - if( m.find( it->first )==m.end() ){ - //see if we can choose this to set - if( ic.isNull() && ( it->second.isNull() || !it->first.getType().isInteger() ) ){ - ic = it->first; - } - }else{ - Debug("matching-arith") << "already set " << m.get( it->first ) << std::endl; - Node tm = m.get( it->first ); - if( !it->second.isNull() ){ - tm = NodeManager::currentNM()->mkNode( MULT, it->second, tm ); - } - tb << tm; - } - }else{ - tb << it->second; - } - } - if( !ic.isNull() ){ - Node tm; - if( tb.getNumChildren()==0 ){ - tm = t; - }else{ - tm = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb; - tm = NodeManager::currentNM()->mkNode( MINUS, t, tm ); - } - if( !d_arith_coeffs[ ic ].isNull() ){ - Assert( !ic.getType().isInteger() ); - Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst() ); - tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm ); - } - m.set( ic, Rewriter::rewrite( tm )); - //set the rest to zeros - for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ - if( !it->first.isNull() ){ - if( m.find( it->first )==m.end() ){ - m.set( it->first, NodeManager::currentNM()->mkConst( Rational(0) ) ); - } - } - } - Debug("matching-arith") << "Setting " << ic << " to " << tm << std::endl; - return true; - }else{ - return false; - } - }else{ - return false; - } -} - - -/** reset instantiation round */ -void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){ - if( d_match_pattern.isNull() ){ - for( int i=0; i<(int)d_children.size(); i++ ){ - d_children[i]->resetInstantiationRound( qe ); - } - }else{ - if( d_cg ){ - d_cg->resetInstantiationRound(); - } - } -} - -void InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){ - if( d_match_pattern.isNull() ){ - for( int i=0; i<(int)d_children.size(); i++ ){ - d_children[i]->reset( eqc, qe ); - } - d_partial.clear(); - }else{ - if( !d_eq_class.isNull() ){ - //we have a specific equivalence class in mind - //we are producing matches for f(E) ~ t, where E is a non-ground vector of terms, and t is a ground term - //just look in equivalence class of the RHS - d_cg->reset( d_eq_class ); - }else{ - d_cg->reset( eqc ); - } - } -} - -bool InstMatchGenerator::getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - m.d_matched = Node::null(); - if( d_match_pattern.isNull() ){ - int index = (int)d_partial.size(); - while( index>=0 && index<(int)d_children.size() ){ - if( index>0 ){ - d_partial.push_back( InstMatch( &d_partial[index-1] ) ); - }else{ - d_partial.push_back( InstMatch() ); - } - if( d_children[index]->getNextMatch( d_partial[index], qe ) ){ - index++; - }else{ - d_children[index]->reset( Node::null(), qe ); - d_partial.pop_back(); - if( !d_partial.empty() ){ - d_partial.pop_back(); - } - index--; - } - } - if( index>=0 ){ - m = d_partial.back(); - d_partial.pop_back(); - return true; - }else{ - return false; - } - }else{ - bool res = getNextMatch2( m, qe, true ); - Assert(!res || !m.d_matched.isNull()); - return res; - } -} - - - -// Currently the implementation doesn't take into account that -// variable should have the same value given. -// TODO use the d_children way perhaps -// TODO replace by a real dictionnary -// We should create a real substitution? slower more precise -// We don't do that often -bool InstMatchGenerator::nonunifiable( TNode t0, const std::vector & vars){ - if(d_match_pattern.isNull()) return true; - - typedef std::vector > tstack; - tstack stack(1,std::make_pair(t0,d_match_pattern)); // t * pat - - while(!stack.empty()){ - const std::pair p = stack.back(); stack.pop_back(); - const TNode & t = p.first; - const TNode & pat = p.second; - - // t or pat is a variable currently we consider that can match anything - if( find(vars.begin(),vars.end(),t) != vars.end() ) continue; - if( pat.getKind() == INST_CONSTANT ) continue; - - // t and pat are nonunifiable - if( !Trigger::isAtomicTrigger( t ) || !Trigger::isAtomicTrigger( pat ) ) { - if(t == pat) continue; - else return true; - }; - if( t.getOperator() != pat.getOperator() ) return true; - - //put the children on the stack - for( size_t i=0; i < pat.getNumChildren(); i++ ){ - stack.push_back(std::make_pair(t[i],pat[i])); - }; - } - // The heuristic can't find non-unifiability - return false; -} - -int InstMatchGenerator::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ - //now, try to add instantiation for each match produced - int addedLemmas = 0; - InstMatch m; - while( getNextMatch( m, qe ) ){ - //m.makeInternal( d_quantEngine->getEqualityQuery() ); - m.add( baseMatch ); - if( qe->addInstantiation( f, m ) ){ - addedLemmas++; - if( qe->d_optInstLimitActive && qe->d_optInstLimit<=0 ){ - return addedLemmas; - } - } - m.clear(); - } - //return number of lemmas added - return addedLemmas; -} - -int InstMatchGenerator::addTerm( Node f, Node t, QuantifiersEngine* qe ){ - Assert( options::eagerInstQuant() ); - if( !d_match_pattern.isNull() ){ - InstMatch m; - if( getMatch( t, m, qe ) ){ - if( qe->addInstantiation( f, m ) ){ - return 1; - } - } - }else{ - for( int i=0; i<(int)d_children.size(); i++ ){ - d_children[i]->addTerm( f, t, qe ); - } - } - return 0; -} - -/** constructors */ -InstMatchGeneratorMulti::InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption ) : -d_f( f ){ - Debug("smart-multi-trigger") << "Making smart multi-trigger for " << f << std::endl; - std::map< Node, std::vector< Node > > var_contains; - Trigger::getVarContains( f, pats, var_contains ); - //convert to indicies - for( std::map< Node, std::vector< Node > >::iterator it = var_contains.begin(); it != var_contains.end(); ++it ){ - Debug("smart-multi-trigger") << "Pattern " << it->first << " contains: "; - for( int i=0; i<(int)it->second.size(); i++ ){ - Debug("smart-multi-trigger") << it->second[i] << " "; - int index = it->second[i].getAttribute(InstVarNumAttribute()); - d_var_contains[ it->first ].push_back( index ); - d_var_to_node[ index ].push_back( it->first ); - } - Debug("smart-multi-trigger") << std::endl; - } - for( int i=0; i<(int)pats.size(); i++ ){ - Node n = pats[i]; - //make the match generator - d_children.push_back( new InstMatchGenerator( n, qe, matchOption ) ); - //compute unique/shared variables - 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++ ){ - 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] ); - }else{ - shared_vars[ d_var_contains[n][j] ] = true; - numSharedVars++; - } - } - //we use the latest shared variables, then unique variables - std::vector< int > vars; - int index = i==0 ? (int)(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 ){ - if( std::find( d_var_contains[ pats[index] ].begin(), d_var_contains[ pats[index] ].end(), it->first )!= - d_var_contains[ pats[index] ].end() ){ - vars.push_back( it->first ); - shared_vars[ it->first ] = false; - numSharedVars--; - } - } - } - index = index==0 ? (int)(pats.size()-1) : (index-1); - } - 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] << " "; - } - 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 ) ); - } - -} - -/** reset instantiation round (call this whenever equivalence classes have changed) */ -void InstMatchGeneratorMulti::resetInstantiationRound( QuantifiersEngine* qe ){ - for( int i=0; i<(int)d_children.size(); i++ ){ - d_children[i]->resetInstantiationRound( qe ); - } -} - -/** reset, eqc is the equivalence class to search in (any if eqc=null) */ -void InstMatchGeneratorMulti::reset( Node eqc, QuantifiersEngine* qe ){ - for( int i=0; i<(int)d_children.size(); i++ ){ - d_children[i]->reset( eqc, qe ); - } -} - -int InstMatchGeneratorMulti::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ - int addedLemmas = 0; - Debug("smart-multi-trigger") << "Process smart multi trigger" << std::endl; - for( int i=0; i<(int)d_children.size(); i++ ){ - Debug("smart-multi-trigger") << "Calculate matches " << i << std::endl; - std::vector< InstMatch > newMatches; - InstMatch m; - while( d_children[i]->getNextMatch( m, qe ) ){ - m.makeRepresentative( qe ); - newMatches.push_back( InstMatch( &m ) ); - m.clear(); - } - for( int j=0; j<(int)newMatches.size(); j++ ){ - processNewMatch( qe, newMatches[j], i, addedLemmas ); - } - } - return addedLemmas; -} - -void InstMatchGeneratorMulti::processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ){ - //see if these produce new matches - d_children_trie[fromChildIndex].addInstMatch( qe, d_f, m, true ); - //possibly only do the following if we know that new matches will be produced? - //the issue is that instantiations are filtered in quantifiers engine, and so there is no guarentee that - // we can safely skip the following lines, even when we have already produced this match. - Debug("smart-multi-trigger") << "Child " << fromChildIndex << " produced match " << m << std::endl; - //process new instantiations - int childIndex = (fromChildIndex+1)%(int)d_children.size(); - std::vector< IndexedTrie > unique_var_tries; - processNewInstantiations( qe, m, addedLemmas, d_children_trie[childIndex].getTrie(), - unique_var_tries, 0, childIndex, fromChildIndex, true ); -} - -void InstMatchGeneratorMulti::processNewInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr, - std::vector< IndexedTrie >& unique_var_tries, - int trieIndex, int childIndex, int endChildIndex, bool modEq ){ - if( childIndex==endChildIndex ){ - //now, process unique variables - processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, 0 ); - }else if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){ - int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex]; - Node curr_ic = qe->getTermDatabase()->getInstantiationConstant( d_f, curr_index ); - if( m.find( curr_ic )==m.end() ){ - //if( d_var_to_node[ curr_index ].size()==1 ){ //FIXME - // //unique variable(s), defer calculation - // unique_var_tries.push_back( IndexedTrie( std::pair< int, int >( childIndex, trieIndex ), tr ) ); - // int newChildIndex = (childIndex+1)%(int)d_children.size(); - // processNewInstantiations( qe, m, d_children_trie[newChildIndex].getTrie(), unique_var_tries, - // 0, newChildIndex, endChildIndex, modEq ); - //}else{ - //shared and non-set variable, add to InstMatch - for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){ - InstMatch mn( &m ); - mn.set( curr_ic, it->first); - processNewInstantiations( qe, mn, addedLemmas, &(it->second), unique_var_tries, - trieIndex+1, childIndex, endChildIndex, modEq ); - } - //} - }else{ - //shared and set variable, try to merge - Node n = m.get( curr_ic ); - std::map< Node, InstMatchTrie >::iterator it = tr->d_data.find( n ); - if( it!=tr->d_data.end() ){ - processNewInstantiations( qe, m, addedLemmas, &(it->second), unique_var_tries, - trieIndex+1, childIndex, endChildIndex, modEq ); - } - if( modEq ){ - //check modulo equality for other possible instantiations - if( qe->getEqualityQuery()->getEngine()->hasTerm( n ) ){ - eq::EqClassIterator eqc( qe->getEqualityQuery()->getEngine()->getRepresentative( n ), - qe->getEqualityQuery()->getEngine() ); - while( !eqc.isFinished() ){ - Node en = (*eqc); - if( en!=n ){ - std::map< Node, InstMatchTrie >::iterator itc = tr->d_data.find( en ); - if( itc!=tr->d_data.end() ){ - processNewInstantiations( qe, m, addedLemmas, &(itc->second), unique_var_tries, - trieIndex+1, childIndex, endChildIndex, modEq ); - } - } - ++eqc; - } - } - } - } - }else{ - int newChildIndex = (childIndex+1)%(int)d_children.size(); - processNewInstantiations( qe, m, addedLemmas, d_children_trie[newChildIndex].getTrie(), unique_var_tries, - 0, newChildIndex, endChildIndex, modEq ); - } -} - -void InstMatchGeneratorMulti::processNewInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, - std::vector< IndexedTrie >& unique_var_tries, - int uvtIndex, InstMatchTrie* tr, int trieIndex ){ - if( uvtIndex<(int)unique_var_tries.size() ){ - int childIndex = unique_var_tries[uvtIndex].first.first; - if( !tr ){ - tr = unique_var_tries[uvtIndex].second; - trieIndex = unique_var_tries[uvtIndex].first.second; - } - if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){ - int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex]; - Node curr_ic = qe->getTermDatabase()->getInstantiationConstant( d_f, curr_index ); - //unique non-set variable, add to InstMatch - for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){ - InstMatch mn( &m ); - mn.set( curr_ic, it->first); - processNewInstantiations2( qe, mn, addedLemmas, unique_var_tries, uvtIndex, &(it->second), trieIndex+1 ); - } - }else{ - processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, uvtIndex+1 ); - } - }else{ - //m is an instantiation - if( qe->addInstantiation( d_f, m ) ){ - addedLemmas++; - Debug("smart-multi-trigger") << "-> Produced instantiation " << m << std::endl; - } - } -} - -int InstMatchGeneratorMulti::addTerm( Node f, Node t, QuantifiersEngine* qe ){ - Assert( options::eagerInstQuant() ); - int addedLemmas = 0; - for( int i=0; i<(int)d_children.size(); i++ ){ - if( ((InstMatchGenerator*)d_children[i])->d_match_pattern.getOperator()==t.getOperator() ){ - InstMatch m; - //if it produces a match, then process it with the rest - if( ((InstMatchGenerator*)d_children[i])->getMatch( t, m, qe ) ){ - processNewMatch( qe, m, i, addedLemmas ); - } - } - } - return addedLemmas; -} - -int InstMatchGeneratorSimple::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ - InstMatch m; - m.add( baseMatch ); - int addedLemmas = 0; - if( d_match_pattern.getType()==NodeManager::currentNM()->booleanType() ){ - for( int i=0; i<2; i++ ){ - addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_pred_map_trie[i][ d_match_pattern.getOperator() ]) ); - } - }else{ - addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_match_pattern.getOperator() ]) ); - } - return addedLemmas; -} - -void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat ){ - if( argIndex==(int)d_match_pattern.getNumChildren() ){ - //m is an instantiation - if( qe->addInstantiation( d_f, m ) ){ - addedLemmas++; - Debug("simple-multi-trigger") << "-> Produced instantiation " << m << std::endl; - } - }else{ - if( d_match_pattern[argIndex].getKind()==INST_CONSTANT ){ - Node ic = d_match_pattern[argIndex]; - for( std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){ - Node t = it->first; - if( m.get( ic ).isNull() || m.get( ic )==t ){ - Node prev = m.get( ic ); - m.set( ic, t); - addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); - m.set( ic, prev); - } - } - }else{ - Node r = qe->getEqualityQuery()->getRepresentative( d_match_pattern[argIndex] ); - std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r ); - if( it!=tat->d_data.end() ){ - addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); - } - } - } -} - -int InstMatchGeneratorSimple::addTerm( Node f, Node t, QuantifiersEngine* qe ){ - Assert( options::eagerInstQuant() ); - InstMatch m; - for( int i=0; i<(int)t.getNumChildren(); i++ ){ - if( d_match_pattern[i].getKind()==INST_CONSTANT ){ - m.set(d_match_pattern[i], t[i]); - }else if( !qe->getEqualityQuery()->areEqual( d_match_pattern[i], t[i] ) ){ - return 0; - } - } - return qe->addInstantiation( f, m ) ? 1 : 0; -} diff --git a/src/theory/inst_match.h b/src/theory/inst_match.h deleted file mode 100644 index 2b402779d..000000000 --- a/src/theory/inst_match.h +++ /dev/null @@ -1,394 +0,0 @@ -/********************* */ -/*! \file inst_match.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief inst match class - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__INST_MATCH_H -#define __CVC4__INST_MATCH_H - -#include "util/hash.h" - -#include -#include -#include - -#include "context/cdlist.h" -#include "theory/candidate_generator.h" - -//#define USE_EFFICIENT_E_MATCHING - -namespace CVC4 { -namespace theory { - -/** 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 InstConstantAttribute; - -struct InstLevelAttributeId {}; -typedef expr::Attribute InstLevelAttribute; - -struct InstVarNumAttributeId {}; -typedef expr::Attribute InstVarNumAttribute; - -// Attribute that tell if a node have been asserted in this branch -struct AvailableInTermDbId {}; -/** use the special for boolean flag */ -typedef expr::Attribute AvailableInTermDb; - - -class QuantifiersEngine; -namespace quantifiers{ - class TermArgTrie; -} - -namespace uf{ - class InstantiatorTheoryUf; - class TheoryUF; -}/* CVC4::theory::uf namespace */ - -namespace inst { - -class EqualityQuery { -public: - EqualityQuery(){} - virtual ~EqualityQuery(){}; - /** contains term */ - virtual bool hasTerm( Node a ) = 0; - /** get the representative of the equivalence class of a */ - virtual Node getRepresentative( Node a ) = 0; - /** returns true if a and b are equal in the current context */ - virtual bool areEqual( Node a, Node b ) = 0; - /** returns true is a and b are disequal in the current context */ - virtual bool areDisequal( Node a, Node b ) = 0; - /** getInternalRepresentative gets the current best representative in the equivalence class of a, based on some criteria. - If cbqi is active, this will return a term in the equivalence class of "a" that does - not contain instantiation constants, if such a term exists. - */ - virtual Node getInternalRepresentative( Node a ) = 0; - /** get the equality engine associated with this query */ - virtual eq::EqualityEngine* getEngine() = 0; - /** get the equivalence class of a */ - virtual void getEquivalenceClass( Node a, std::vector< Node >& eqc ) = 0; -};/* class EqualityQuery */ - -/** basic class defining an instantiation */ -class InstMatch { - /* map from variable to ground terms */ - std::map< Node, Node > d_map; -public: - InstMatch(); - InstMatch( InstMatch* m ); - - /** set the match of v to m */ - bool setMatch( EqualityQuery* q, TNode v, TNode m ); - /* This version tell if the variable has been set */ - bool setMatch( EqualityQuery* q, TNode v, TNode m, bool & set); - /** fill all unfilled values with m */ - bool add( InstMatch& m ); - /** if compatible, fill all unfilled values with m and return true - return false otherwise */ - bool merge( EqualityQuery* q, InstMatch& m ); - /** debug print method */ - void debugPrint( const char* c ); - /** make complete */ - void makeComplete( Node f, QuantifiersEngine* qe ); - /** make internal: ensure that no term in d_map contains instantiation constants */ - void makeInternal( QuantifiersEngine* qe ); - /** make representative */ - void makeRepresentative( QuantifiersEngine* qe ); - /** apply rewrite */ - void applyRewrite(); - /** compute d_match */ - void computeTermVec( QuantifiersEngine* qe, const std::vector< Node >& vars, std::vector< Node >& match ); - /** compute d_match */ - void computeTermVec( const std::vector< Node >& vars, std::vector< Node >& match ); - /** clear */ - void clear(){ d_map.clear(); } - /** erase */ - template - void erase(Iterator begin, Iterator end){ - for(Iterator i = begin; i != end; ++i){ - d_map.erase(*i); - }; - } - void erase(Node node){ d_map.erase(node); } - /** is_empty */ - bool empty(){ return d_map.empty(); } - /** set */ - void set(TNode var, TNode n){ - //std::cout << "var.getType() " << var.getType() << "n.getType() " << n.getType() << std::endl ; - Assert( !var.isNull() ); - Assert( n.isNull() ||// For a strange use in inst_match.cpp InstMatchGeneratorSimple::addInstantiations - var.getType() == n.getType() ); - d_map[var] = n; - } - Node get(TNode var){ return d_map[var]; } - size_t size(){ return d_map.size(); } - /* iterator */ - std::map< Node, Node >::iterator begin(){ return d_map.begin(); }; - std::map< Node, Node >::iterator end(){ return d_map.end(); }; - std::map< Node, Node >::iterator find(Node var){ return d_map.find(var); }; - /* Node used for matching the trigger only for mono-trigger (just for - efficiency because I need only that) */ - Node d_matched; - /** to stream */ - inline void toStream(std::ostream& out) const { - out << "INST_MATCH( "; - for( std::map< Node, Node >::const_iterator it = d_map.begin(); it != d_map.end(); ++it ){ - if( it != d_map.begin() ){ out << ", "; } - out << it->first << " -> " << it->second; - } - out << " )"; - } -};/* class InstMatch */ - -inline std::ostream& operator<<(std::ostream& out, const InstMatch& m) { - m.toStream(out); - return out; -} - -/** trie for InstMatch objects */ -class InstMatchTrie { -public: - class ImtIndexOrder { - public: - std::vector< int > d_order; - };/* class InstMatchTrie ImtIndexOrder */ -private: - /** add match m for quantifier f starting at index, take into account equalities q, return true if successful */ - void addInstMatch2( QuantifiersEngine* qe, Node f, InstMatch& m, int index, ImtIndexOrder* imtio ); - /** exists match */ - bool existsInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq, int index, ImtIndexOrder* imtio ); -public: - /** the data */ - std::map< Node, InstMatchTrie > d_data; -public: - InstMatchTrie(){} - ~InstMatchTrie(){} -public: - /** add match m for quantifier f, take into account equalities if modEq = true, - if imtio is non-null, this is the order to add to trie - return true if successful - */ - bool addInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq = false, ImtIndexOrder* imtio = NULL ); -};/* class InstMatchTrie */ - -class InstMatchTrieOrdered { -private: - InstMatchTrie::ImtIndexOrder* d_imtio; - InstMatchTrie d_imt; -public: - InstMatchTrieOrdered( InstMatchTrie::ImtIndexOrder* imtio ) : d_imtio( imtio ){} - ~InstMatchTrieOrdered(){} - /** get ordering */ - InstMatchTrie::ImtIndexOrder* getOrdering() { return d_imtio; } - /** get trie */ - InstMatchTrie* getTrie() { return &d_imt; } -public: - /** add match m, return true if successful */ - bool addInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq = false ){ - return d_imt.addInstMatch( qe, f, m, modEq, d_imtio ); - } -};/* class InstMatchTrieOrdered */ - -/** base class for producing InstMatch objects */ -class IMGenerator { -public: - /** reset instantiation round (call this at beginning of instantiation round) */ - virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0; - /** reset, eqc is the equivalence class to search in (any if eqc=null) */ - virtual void reset( Node eqc, QuantifiersEngine* qe ) = 0; - /** get the next match. must call reset( eqc ) before this function. */ - virtual bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) = 0; - /** return true if whatever Node is substituted for the variables the - given Node can't match the pattern */ - virtual bool nonunifiable( TNode t, const std::vector & vars) = 0; - /** add instantiations directly */ - virtual int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ) = 0; - /** add ground term t, called when t is added to term db */ - virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) = 0; -};/* class IMGenerator */ - - -class InstMatchGenerator : public IMGenerator { -private: - /** candidate generator */ - CandidateGenerator* d_cg; - /** policy to use for matching */ - int d_matchPolicy; - /** children generators */ - std::vector< InstMatchGenerator* > d_children; - std::vector< int > d_children_index; - /** partial vector */ - std::vector< InstMatch > d_partial; - /** eq class */ - Node d_eq_class; - /** for arithmetic matching */ - std::map< Node, Node > d_arith_coeffs; - /** initialize pattern */ - void initializePatterns( std::vector< Node >& pats, QuantifiersEngine* qe ); - void initializePattern( Node pat, QuantifiersEngine* qe ); -public: - enum { - //options for producing matches - MATCH_GEN_DEFAULT = 0, - MATCH_GEN_EFFICIENT_E_MATCH, //generate matches via Efficient E-matching for SMT solvers - //others (internally used) - MATCH_GEN_INTERNAL_ARITHMETIC, - MATCH_GEN_INTERNAL_ERROR, - }; -private: - /** get the next match. must call d_cg->reset( ... ) before using. - only valid for use where !d_match_pattern.isNull(). - */ - bool getNextMatch2( InstMatch& m, QuantifiersEngine* qe, bool saveMatched = false ); - /** for arithmetic */ - bool getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ); -public: - /** get the match against ground term or formula t. - d_match_pattern and t should have the same shape. - only valid for use where !d_match_pattern.isNull(). - */ - bool getMatch( Node t, InstMatch& m, QuantifiersEngine* qe ); - - /** constructors */ - InstMatchGenerator( Node pat, QuantifiersEngine* qe, int matchOption = 0 ); - InstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption = 0 ); - /** destructor */ - ~InstMatchGenerator(){} - /** The pattern we are producing matches for. - If null, this is a multi trigger that is merging matches from d_children. - */ - Node d_pattern; - /** match pattern */ - Node d_match_pattern; -public: - /** 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) */ - void reset( Node eqc, QuantifiersEngine* qe ); - /** get the next match. must call reset( eqc ) before this function. */ - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ); - /** return true if whatever Node is substituted for the variables the - given Node can't match the pattern */ - bool nonunifiable( TNode t, const std::vector & vars); - /** add instantiations */ - int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); - /** add ground term t */ - int addTerm( Node f, Node t, QuantifiersEngine* qe ); -};/* class InstMatchGenerator */ - -/** smart multi-trigger implementation */ -class InstMatchGeneratorMulti : public IMGenerator { -private: - /** indexed trie */ - typedef std::pair< std::pair< int, int >, InstMatchTrie* > IndexedTrie; - /** process new match */ - void processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ); - /** process new instantiations */ - void processNewInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr, - std::vector< IndexedTrie >& unique_var_tries, - int trieIndex, int childIndex, int endChildIndex, bool modEq ); - /** process new instantiations 2 */ - void processNewInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, - std::vector< IndexedTrie >& unique_var_tries, - int uvtIndex, InstMatchTrie* tr = NULL, int trieIndex = 0 ); -private: - /** var contains (variable indices) for each pattern node */ - std::map< Node, std::vector< int > > d_var_contains; - /** variable indices contained to pattern nodes */ - std::map< int, std::vector< Node > > d_var_to_node; - /** quantifier to use */ - Node d_f; - /** policy to use for matching */ - int d_matchPolicy; - /** children generators */ - std::vector< InstMatchGenerator* > d_children; - /** inst match tries for each child */ - std::vector< InstMatchTrieOrdered > d_children_trie; - /** calculate matches */ - void calculateMatches( QuantifiersEngine* qe ); -public: - /** constructors */ - InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption = 0 ); - /** destructor */ - ~InstMatchGeneratorMulti(){} - /** 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) */ - void reset( Node eqc, QuantifiersEngine* qe ); - /** get the next match. must call reset( eqc ) before this function. (not implemented) */ - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) { return false; } - /** return true if whatever Node is substituted for the variables the - given Node can't match the pattern */ - bool nonunifiable( TNode t, const std::vector & vars) { return true; } - /** add instantiations */ - int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); - /** add ground term t */ - int addTerm( Node f, Node t, QuantifiersEngine* qe ); -};/* class InstMatchGeneratorMulti */ - -/** smart (single)-trigger implementation */ -class InstMatchGeneratorSimple : public IMGenerator { -private: - /** quantifier for match term */ - Node d_f; - /** match term */ - Node d_match_pattern; - /** add instantiations */ - void addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat ); -public: - /** constructors */ - InstMatchGeneratorSimple( Node f, Node pat ) : d_f( f ), d_match_pattern( pat ){} - /** destructor */ - ~InstMatchGeneratorSimple(){} - /** 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) */ - void reset( Node eqc, QuantifiersEngine* qe ) {} - /** get the next match. must call reset( eqc ) before this function. (not implemented) */ - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) { return false; } - /** return true if whatever Node is substituted for the variables the - given Node can't match the pattern */ - bool nonunifiable( TNode t, const std::vector & vars) { return true; } - /** add instantiations */ - int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); - /** add ground term t, possibly add instantiations */ - int addTerm( Node f, Node t, QuantifiersEngine* qe ); -};/* class InstMatchGeneratorSimple */ - -}/* CVC4::theory::inst namespace */ - -typedef CVC4::theory::inst::InstMatch InstMatch; -typedef CVC4::theory::inst::EqualityQuery EqualityQuery; - -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ - -#endif /* __CVC4__INST_MATCH_H */ diff --git a/src/theory/instantiator_default.cpp b/src/theory/instantiator_default.cpp deleted file mode 100644 index cff16962a..000000000 --- a/src/theory/instantiator_default.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/********************* */ -/*! \file instantiator_default.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Implementation of instantiator_default class - **/ - -#include "theory/instantiator_default.h" -#include "theory/theory_engine.h" - -using namespace std; -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::context; -using namespace CVC4::theory; - -InstantiatorDefault::InstantiatorDefault(context::Context* c, QuantifiersEngine* ie, Theory* th) : - Instantiator( c, ie, th ) { -} - -void InstantiatorDefault::assertNode( Node assertion ){ -} - -void InstantiatorDefault::processResetInstantiationRound( Theory::Effort effort ){ -} - -int InstantiatorDefault::process( Node f, Theory::Effort effort, int e ){ - /* - if( e < 4 ){ - return InstStrategy::STATUS_UNFINISHED; - }else if( e == 4 ){ - Debug("quant-default") << "Process " << f << " : " << std::endl; - InstMatch m; - for( int j=0; j<(int)d_quantEngine->getNumInstantiationConstants( f ); j++ ){ - Node i = d_quantEngine->getInstantiationConstant( f, j ); - Debug("quant-default") << "Getting value for " << i << std::endl; - if( d_quantEngine->getTheoryEngine()->theoryOf( i )==getTheory() ){ //if it belongs to this theory - Node val = d_th->getValue( i ); - Debug("quant-default") << "Default Instantiate for " << d_th->getId() << ", setting " << i << " = " << val << std::endl; - m.set( i, val); - } - } - d_quantEngine->addInstantiation( f, m ); - } - */ - return InstStrategy::STATUS_UNKNOWN; -} diff --git a/src/theory/instantiator_default.h b/src/theory/instantiator_default.h deleted file mode 100644 index 967a0c1ca..000000000 --- a/src/theory/instantiator_default.h +++ /dev/null @@ -1,48 +0,0 @@ -/********************* */ -/*! \file instantiator_default.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief instantiator_default - **/ - - -#include "cvc4_private.h" - -#ifndef __CVC4__INSTANTIATOR_DEFAULT_H -#define __CVC4__INSTANTIATOR_DEFAULT_H - -#include -#include "theory/quantifiers_engine.h" - -namespace CVC4 { -namespace theory { - -class InstantiatorDefault : public Instantiator { - friend class QuantifiersEngine; -protected: - /** reset instantiation round */ - void processResetInstantiationRound(Theory::Effort effort); - /** process quantifier */ - int process( Node f, Theory::Effort effort, int e ); -public: - InstantiatorDefault(context::Context* c, QuantifiersEngine* ie, Theory* th); - ~InstantiatorDefault() { } - /** check function, assertion is asserted to theory */ - void assertNode( Node assertion ); - /** identify */ - std::string identify() const { return std::string("InstantiatorDefault"); } -};/* class InstantiatorDefault */ - -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ - -#endif /* __CVC4__INSTANTIATOR_DEFAULT_H */ diff --git a/src/theory/quantifiers/Makefile.am b/src/theory/quantifiers/Makefile.am index 5172001fc..2b16c9af3 100644 --- a/src/theory/quantifiers/Makefile.am +++ b/src/theory/quantifiers/Makefile.am @@ -15,6 +15,14 @@ libquantifiers_la_SOURCES = \ theory_quantifiers_instantiator.cpp \ instantiation_engine.h \ instantiation_engine.cpp \ + trigger.h \ + trigger.cpp \ + candidate_generator.h \ + candidate_generator.cpp \ + instantiator_default.h \ + instantiator_default.cpp \ + inst_match.h \ + inst_match.cpp \ model_engine.h \ model_engine.cpp \ inst_when_mode.cpp \ diff --git a/src/theory/quantifiers/candidate_generator.cpp b/src/theory/quantifiers/candidate_generator.cpp new file mode 100644 index 000000000..6a7c4c504 --- /dev/null +++ b/src/theory/quantifiers/candidate_generator.cpp @@ -0,0 +1,255 @@ +/********************* */ +/*! \file candidate_generator.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: mdeters + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of theory uf candidate generator class + **/ + +#include "theory/quantifiers/candidate_generator.h" +#include "theory/theory_engine.h" +#include "theory/uf/theory_uf.h" +#include "theory/quantifiers/term_database.h" +#include "theory/quantifiers/inst_match.h" +#include "theory/quantifiers_engine.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::inst; + +bool CandidateGenerator::isLegalCandidate( Node n ){ + return ( !n.getAttribute(NoMatchAttribute()) && ( !options::cbqi() || !n.hasAttribute(InstConstantAttribute()) ) ); +} + +void CandidateGeneratorQueue::addCandidate( Node n ) { + if( isLegalCandidate( n ) ){ + d_candidates.push_back( n ); + } +} + +void CandidateGeneratorQueue::reset( Node eqc ){ + if( d_candidate_index>0 ){ + d_candidates.erase( d_candidates.begin(), d_candidates.begin() + d_candidate_index ); + d_candidate_index = 0; + } + if( !eqc.isNull() ){ + d_candidates.push_back( eqc ); + } +} +Node CandidateGeneratorQueue::getNextCandidate(){ + if( d_candidate_index<(int)d_candidates.size() ){ + Node n = d_candidates[d_candidate_index]; + d_candidate_index++; + return n; + }else{ + d_candidate_index = 0; + d_candidates.clear(); + return Node::null(); + } +} + +#if 0 + +CandidateGeneratorQE::CandidateGeneratorQE( QuantifiersEngine* qe, Node op ) : + d_op( op ), d_qe( qe ), d_term_iter( -2 ){ + Assert( !d_op.isNull() ); +} +void CandidateGeneratorQE::resetInstantiationRound(){ + d_term_iter_limit = d_qe->getTermDatabase()->d_op_map[d_op].size(); +} + +void CandidateGeneratorQE::reset( Node eqc ){ + if( eqc.isNull() ){ + d_term_iter = 0; + }else{ + //create an equivalence class iterator in eq class eqc + if( d_qe->getEqualityQuery()->getEngine()->hasTerm( eqc ) ){ + eqc = d_qe->getEqualityQuery()->getEngine()->getRepresentative( eqc ); + d_eqc = eq::EqClassIterator( eqc, d_qe->getEqualityQuery()->getEngine() ); + d_retNode = Node::null(); + }else{ + d_retNode = eqc; + } + d_term_iter = -1; + } +} + +Node CandidateGeneratorQE::getNextCandidate(){ + if( d_term_iter>=0 ){ + //get next candidate term in the uf term database + while( d_term_itergetTermDatabase()->d_op_map[d_op][d_term_iter]; + d_term_iter++; + if( isLegalCandidate( n ) ){ + return n; + } + } + }else if( d_term_iter==-1 ){ + if( d_retNode.isNull() ){ + //get next candidate term in equivalence class + while( !d_eqc.isFinished() ){ + Node n = (*d_eqc); + ++d_eqc; + if( n.hasOperator() && n.getOperator()==d_op ){ + if( isLegalCandidate( n ) ){ + return n; + } + } + } + }else{ + Node ret; + if( d_retNode.hasOperator() && d_retNode.getOperator()==d_op ){ + ret = d_retNode; + } + d_term_iter = -2; //done returning matches + return ret; + } + } + return Node::null(); +} + +#else + + +CandidateGeneratorQE::CandidateGeneratorQE( QuantifiersEngine* qe, Node op ) : + d_op( op ), d_qe( qe ), d_term_iter( -1 ){ + Assert( !d_op.isNull() ); +} +void CandidateGeneratorQE::resetInstantiationRound(){ + d_term_iter_limit = d_qe->getTermDatabase()->d_op_map[d_op].size(); +} + +void CandidateGeneratorQE::reset( Node eqc ){ + d_term_iter = 0; + if( eqc.isNull() ){ + d_using_term_db = true; + }else{ + //create an equivalence class iterator in eq class eqc + d_eqc.clear(); + d_qe->getEqualityQuery()->getEquivalenceClass( eqc, d_eqc ); + d_using_term_db = false; + } +} + +Node CandidateGeneratorQE::getNextCandidate(){ + if( d_term_iter>=0 ){ + if( d_using_term_db ){ + //get next candidate term in the uf term database + while( d_term_itergetTermDatabase()->d_op_map[d_op][d_term_iter]; + d_term_iter++; + if( isLegalCandidate( n ) ){ + return n; + } + } + }else{ + while( d_term_iter<(int)d_eqc.size() ){ + Node n = d_eqc[d_term_iter]; + d_term_iter++; + if( n.hasOperator() && n.getOperator()==d_op ){ + if( isLegalCandidate( n ) ){ + return n; + } + } + } + } + } + return Node::null(); +} + +#endif + +//CandidateGeneratorQEDisequal::CandidateGeneratorQEDisequal( QuantifiersEngine* qe, Node eqc ) : +// d_qe( qe ), d_eq_class( eqc ){ +// d_eci = NULL; +//} +//void CandidateGeneratorQEDisequal::resetInstantiationRound(){ +// +//} +////we will iterate over all terms that are disequal from eqc +//void CandidateGeneratorQEDisequal::reset( Node eqc ){ +// //Assert( !eqc.isNull() ); +// ////begin iterating over equivalence classes that are disequal from eqc +// //d_eci = d_ith->getEquivalenceClassInfo( eqc ); +// //if( d_eci ){ +// // d_eqci_iter = d_eci->d_disequal.begin(); +// //} +//} +//Node CandidateGeneratorQEDisequal::getNextCandidate(){ +// //if( d_eci ){ +// // while( d_eqci_iter != d_eci->d_disequal.end() ){ +// // if( (*d_eqci_iter).second ){ +// // //we have an equivalence class that is disequal from eqc +// // d_cg->reset( (*d_eqci_iter).first ); +// // Node n = d_cg->getNextCandidate(); +// // //if there is a candidate in this equivalence class, return it +// // if( !n.isNull() ){ +// // return n; +// // } +// // } +// // ++d_eqci_iter; +// // } +// //} +// return Node::null(); +//} + + +CandidateGeneratorQELitEq::CandidateGeneratorQELitEq( QuantifiersEngine* qe, Node mpat ) : + d_match_pattern( mpat ), d_qe( qe ){ + +} +void CandidateGeneratorQELitEq::resetInstantiationRound(){ + +} +void CandidateGeneratorQELitEq::reset( Node eqc ){ + d_eq = eq::EqClassesIterator( d_qe->getEqualityQuery()->getEngine() ); +} +Node CandidateGeneratorQELitEq::getNextCandidate(){ + while( d_eq.isFinished() ){ + Node n = (*d_eq); + ++d_eq; + if( n.getType()==d_match_pattern[0].getType() ){ + //an equivalence class with the same type as the pattern, return reflexive equality + return NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), n, n ); + } + } + return Node::null(); +} + + +CandidateGeneratorQELitDeq::CandidateGeneratorQELitDeq( QuantifiersEngine* qe, Node mpat ) : + d_match_pattern( mpat ), d_qe( qe ){ + +} +void CandidateGeneratorQELitDeq::resetInstantiationRound(){ + +} +void CandidateGeneratorQELitDeq::reset( Node eqc ){ + Node false_term = d_qe->getEqualityQuery()->getEngine()->getRepresentative( NodeManager::currentNM()->mkConst(false) ); + d_eqc_false = eq::EqClassIterator( false_term, d_qe->getEqualityQuery()->getEngine() ); +} +Node CandidateGeneratorQELitDeq::getNextCandidate(){ + //get next candidate term in equivalence class + while( !d_eqc_false.isFinished() ){ + Node n = (*d_eqc_false); + ++d_eqc_false; + if( n.getKind()==d_match_pattern.getKind() ){ + //found an iff or equality, try to match it + //DO_THIS: cache to avoid redundancies? + //DO_THIS: do we need to try the symmetric equality for n? or will it also exist in the eq class of false? + return n; + } + } + return Node::null(); +} diff --git a/src/theory/quantifiers/candidate_generator.h b/src/theory/quantifiers/candidate_generator.h new file mode 100644 index 000000000..a6aa34a62 --- /dev/null +++ b/src/theory/quantifiers/candidate_generator.h @@ -0,0 +1,187 @@ +/********************* */ +/*! \file candidate_generator.h + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): mdeters + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Theory uf candidate generator + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANTIFIERS__CANDIDATE_GENERATOR_H +#define __CVC4__THEORY__QUANTIFIERS__CANDIDATE_GENERATOR_H + +#include "theory/theory.h" +#include "theory/uf/equality_engine.h" + +namespace CVC4 { +namespace theory { + +class QuantifiersEngine; + +namespace inst { + +/** base class for generating candidates for matching */ +class CandidateGenerator { +public: + CandidateGenerator(){} + ~CandidateGenerator(){} + + /** Get candidates functions. These set up a context to get all match candidates. + cg->reset( eqc ); + do{ + Node cand = cg->getNextCandidate(); + //....... + }while( !cand.isNull() ); + + eqc is the equivalence class you are searching in + */ + virtual void reset( Node eqc ) = 0; + virtual Node getNextCandidate() = 0; + /** add candidate to list of nodes returned by this generator */ + virtual void addCandidate( Node n ) {} + /** call this at the beginning of each instantiation round */ + virtual void resetInstantiationRound() = 0; +public: + /** legal candidate */ + static bool isLegalCandidate( Node n ); +};/* class CandidateGenerator */ + +/** candidate generator queue (for manual candidate generation) */ +class CandidateGeneratorQueue : public CandidateGenerator { +private: + std::vector< Node > d_candidates; + int d_candidate_index; +public: + CandidateGeneratorQueue() : d_candidate_index( 0 ){} + ~CandidateGeneratorQueue(){} + + void addCandidate( Node n ); + + void resetInstantiationRound(){} + void reset( Node eqc ); + Node getNextCandidate(); +};/* class CandidateGeneratorQueue */ + +class CandidateGeneratorQEDisequal; + +#if 0 + +class CandidateGeneratorQE : public CandidateGenerator +{ + friend class CandidateGeneratorQEDisequal; +private: + //operator you are looking for + Node d_op; + //instantiator pointer + QuantifiersEngine* d_qe; + //the equality class iterator + eq::EqClassIterator d_eqc; + int d_term_iter; + int d_term_iter_limit; +private: + Node d_retNode; +public: + CandidateGeneratorQE( QuantifiersEngine* qe, Node op ); + ~CandidateGeneratorQE(){} + + void resetInstantiationRound(); + void reset( Node eqc ); + Node getNextCandidate(); +}; + +#else + +class CandidateGeneratorQE : public CandidateGenerator +{ + friend class CandidateGeneratorQEDisequal; +private: + //operator you are looking for + Node d_op; + //instantiator pointer + QuantifiersEngine* d_qe; + //the equality class iterator + std::vector< Node > d_eqc; + int d_term_iter; + int d_term_iter_limit; + bool d_using_term_db; +public: + CandidateGeneratorQE( QuantifiersEngine* qe, Node op ); + ~CandidateGeneratorQE(){} + + void resetInstantiationRound(); + void reset( Node eqc ); + Node getNextCandidate(); +}; + +#endif + +//class CandidateGeneratorQEDisequal : public CandidateGenerator +//{ +//private: +// //equivalence class +// Node d_eq_class; +// //equivalence class info +// EqClassInfo* d_eci; +// //equivalence class iterator +// EqClassInfo::BoolMap::const_iterator d_eqci_iter; +// //instantiator pointer +// QuantifiersEngine* d_qe; +//public: +// CandidateGeneratorQEDisequal( QuantifiersEngine* qe, Node eqc ); +// ~CandidateGeneratorQEDisequal(){} +// +// void resetInstantiationRound(); +// void reset( Node eqc ); //should be what you want to be disequal from +// Node getNextCandidate(); +//}; + +class CandidateGeneratorQELitEq : public CandidateGenerator +{ +private: + //the equality classes iterator + eq::EqClassesIterator d_eq; + //equality you are trying to match equalities for + Node d_match_pattern; + //einstantiator pointer + QuantifiersEngine* d_qe; +public: + CandidateGeneratorQELitEq( QuantifiersEngine* qe, Node mpat ); + ~CandidateGeneratorQELitEq(){} + + void resetInstantiationRound(); + void reset( Node eqc ); + Node getNextCandidate(); +}; + +class CandidateGeneratorQELitDeq : public CandidateGenerator +{ +private: + //the equality class iterator for false + eq::EqClassIterator d_eqc_false; + //equality you are trying to match disequalities for + Node d_match_pattern; + //einstantiator pointer + QuantifiersEngine* d_qe; +public: + CandidateGeneratorQELitDeq( QuantifiersEngine* qe, Node mpat ); + ~CandidateGeneratorQELitDeq(){} + + void resetInstantiationRound(); + void reset( Node eqc ); + Node getNextCandidate(); +}; + +}/* CVC4::theory::inst namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ + +#endif /* __CVC4__THEORY__QUANTIFIERS__CANDIDATE_GENERATOR_H */ diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h index afa8dab79..8ad911452 100644 --- a/src/theory/quantifiers/first_order_model.h +++ b/src/theory/quantifiers/first_order_model.h @@ -80,10 +80,10 @@ public: TermDb* getTermDatabase(); /** to stream function */ void toStream( std::ostream& out ); -}; +};/* class FirstOrderModel */ -} -} -} +}/* CVC4::theory::quantifiers namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ -#endif +#endif /* __CVC4__FIRST_ORDER_MODEL_H */ diff --git a/src/theory/quantifiers/inst_match.cpp b/src/theory/quantifiers/inst_match.cpp new file mode 100644 index 000000000..271e04968 --- /dev/null +++ b/src/theory/quantifiers/inst_match.cpp @@ -0,0 +1,880 @@ +/********************* */ +/*! \file inst_match.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of inst match class + **/ + +#include "theory/quantifiers/inst_match.h" +#include "theory/theory_engine.h" +#include "theory/quantifiers_engine.h" +#include "theory/quantifiers/candidate_generator.h" +#include "theory/uf/theory_uf_instantiator.h" +#include "theory/uf/equality_engine.h" +#include "theory/quantifiers/options.h" +#include "theory/quantifiers/model_engine.h" +#include "theory/quantifiers/term_database.h" +#include "theory/quantifiers/first_order_model.h" +#include "theory/quantifiers/term_database.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::inst; + + +InstMatch::InstMatch() { +} + +InstMatch::InstMatch( InstMatch* m ) { + d_map = m->d_map; +} + +bool InstMatch::setMatch( EqualityQuery* q, TNode v, TNode m, bool & set ){ + std::map< Node, Node >::iterator vn = d_map.find( v ); + if( vn==d_map.end() ){ + set = true; + this->set(v,m); + Debug("matching-debug") << "Add partial " << v << "->" << m << std::endl; + return true; + }else{ + set = false; + return q->areEqual( vn->second, m ); + } +} + +bool InstMatch::setMatch( EqualityQuery* q, TNode v, TNode m ){ + bool set; + return setMatch(q,v,m,set); +} + +bool InstMatch::add( InstMatch& m ){ + for( std::map< Node, Node >::iterator it = m.d_map.begin(); it != m.d_map.end(); ++it ){ + if( d_map.find( it->first )==d_map.end() ){ + d_map[it->first] = it->second; + } + } + return true; +} + +bool InstMatch::merge( EqualityQuery* q, InstMatch& m ){ + for( std::map< Node, Node >::iterator it = m.d_map.begin(); it != m.d_map.end(); ++it ){ + if( d_map.find( it->first )==d_map.end() ){ + d_map[ it->first ] = it->second; + }else{ + if( it->second!=d_map[it->first] ){ + if( !q->areEqual( it->second, d_map[it->first] ) ){ + d_map.clear(); + return false; + } + } + } + } + return true; +} + +void InstMatch::debugPrint( const char* c ){ + for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ + Debug( c ) << " " << it->first << " -> " << it->second << std::endl; + } + //if( !d_splits.empty() ){ + // Debug( c ) << " Conditions: "; + // for( std::map< Node, Node >::iterator it = d_splits.begin(); it !=d_splits.end(); ++it ){ + // Debug( c ) << it->first << " = " << it->second << " "; + // } + // Debug( c ) << std::endl; + //} +} + +void InstMatch::makeComplete( Node f, QuantifiersEngine* qe ){ + for( int i=0; i<(int)qe->getTermDatabase()->d_inst_constants[f].size(); i++ ){ + Node ic = qe->getTermDatabase()->d_inst_constants[f][i]; + if( d_map.find( ic )==d_map.end() ){ + d_map[ ic ] = qe->getTermDatabase()->getFreeVariableForInstConstant( ic ); + } + } +} + +void InstMatch::makeInternal( QuantifiersEngine* qe ){ + if( options::cbqi() ){ + for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ + if( it->second.hasAttribute(InstConstantAttribute()) ){ + d_map[ it->first ] = qe->getEqualityQuery()->getInternalRepresentative( it->second ); + if( it->second.hasAttribute(InstConstantAttribute()) ){ + d_map[ it->first ] = qe->getTermDatabase()->getFreeVariableForInstConstant( it->first ); + } + } + } + } +} + +void InstMatch::makeRepresentative( QuantifiersEngine* qe ){ + for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ + d_map[ it->first ] = qe->getEqualityQuery()->getInternalRepresentative( it->second ); + if( options::cbqi() && it->second.hasAttribute(InstConstantAttribute()) ){ + d_map[ it->first ] = qe->getTermDatabase()->getFreeVariableForInstConstant( it->first ); + } + } +} + +void InstMatch::applyRewrite(){ + for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){ + it->second = Rewriter::rewrite(it->second); + } +} + +void InstMatch::computeTermVec( QuantifiersEngine* qe, const std::vector< Node >& vars, std::vector< Node >& match ){ + for( int i=0; i<(int)vars.size(); i++ ){ + std::map< Node, Node >::iterator it = d_map.find( vars[i] ); + if( it!=d_map.end() && !it->second.isNull() ){ + match.push_back( it->second ); + }else{ + match.push_back( qe->getTermDatabase()->getFreeVariableForInstConstant( vars[i] ) ); + } + } +} +void InstMatch::computeTermVec( const std::vector< Node >& vars, std::vector< Node >& match ){ + for( int i=0; i<(int)vars.size(); i++ ){ + match.push_back( d_map[ vars[i] ] ); + } +} + + +/** add match m for quantifier f starting at index, take into account equalities q, return true if successful */ +void InstMatchTrie::addInstMatch2( QuantifiersEngine* qe, Node f, InstMatch& m, int index, ImtIndexOrder* imtio ){ + if( long(index)d_order.size()) ) ){ + int i_index = imtio ? imtio->d_order[index] : index; + Node n = m.get( qe->getTermDatabase()->getInstantiationConstant( f, i_index ) ); + d_data[n].addInstMatch2( qe, f, m, index+1, imtio ); + } +} + +/** exists match */ +bool InstMatchTrie::existsInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq, int index, ImtIndexOrder* imtio ){ + if( long(index)==long(f[0].getNumChildren()) || ( imtio && long(index)==long(imtio->d_order.size()) ) ){ + return true; + }else{ + int i_index = imtio ? imtio->d_order[index] : index; + Node n = m.get( qe->getTermDatabase()->getInstantiationConstant( f, i_index ) ); + std::map< Node, InstMatchTrie >::iterator it = d_data.find( n ); + if( it!=d_data.end() ){ + if( it->second.existsInstMatch( qe, f, m, modEq, index+1, imtio ) ){ + return true; + } + } + if( modEq ){ + //check modulo equality if any other instantiation match exists + if( qe->getEqualityQuery()->getEngine()->hasTerm( n ) ){ + eq::EqClassIterator eqc( qe->getEqualityQuery()->getEngine()->getRepresentative( n ), + qe->getEqualityQuery()->getEngine() ); + while( !eqc.isFinished() ){ + Node en = (*eqc); + if( en!=n ){ + std::map< Node, InstMatchTrie >::iterator itc = d_data.find( en ); + if( itc!=d_data.end() ){ + if( itc->second.existsInstMatch( qe, f, m, modEq, index+1, imtio ) ){ + return true; + } + } + } + ++eqc; + } + } + //for( std::map< Node, InstMatchTrie >::iterator itc = d_data.begin(); itc != d_data.end(); ++itc ){ + // if( itc->first!=n && qe->getEqualityQuery()->areEqual( n, itc->first ) ){ + // if( itc->second.existsInstMatch( qe, f, m, modEq, index+1 ) ){ + // return true; + // } + // } + //} + } + return false; + } +} + +bool InstMatchTrie::addInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq, ImtIndexOrder* imtio ){ + if( !existsInstMatch( qe, f, m, modEq, 0, imtio ) ){ + addInstMatch2( qe, f, m, 0, imtio ); + return true; + }else{ + return false; + } +} + +InstMatchGenerator::InstMatchGenerator( Node pat, QuantifiersEngine* qe, int matchPolicy ) : d_matchPolicy( matchPolicy ){ + initializePattern( pat, qe ); +} + +InstMatchGenerator::InstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe, int matchPolicy ) : d_matchPolicy( matchPolicy ){ + if( pats.size()==1 ){ + initializePattern( pats[0], qe ); + }else{ + initializePatterns( pats, qe ); + } +} + +void InstMatchGenerator::initializePatterns( std::vector< Node >& pats, QuantifiersEngine* qe ){ + int childMatchPolicy = d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ? 0 : d_matchPolicy; + for( int i=0; i<(int)pats.size(); i++ ){ + d_children.push_back( new InstMatchGenerator( pats[i], qe, childMatchPolicy ) ); + } + d_pattern = Node::null(); + d_match_pattern = Node::null(); + d_cg = NULL; +} + +void InstMatchGenerator::initializePattern( Node pat, QuantifiersEngine* qe ){ + Debug("inst-match-gen") << "Pattern term is " << pat << std::endl; + Assert( pat.hasAttribute(InstConstantAttribute()) ); + d_pattern = pat; + d_match_pattern = pat; + if( d_match_pattern.getKind()==NOT ){ + //we want to add the children of the NOT + d_match_pattern = d_pattern[0]; + } + if( d_match_pattern.getKind()==IFF || d_match_pattern.getKind()==EQUAL ){ + if( !d_match_pattern[0].hasAttribute(InstConstantAttribute()) ){ + Assert( d_match_pattern[1].hasAttribute(InstConstantAttribute()) ); + //swap sides + d_pattern = NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), d_match_pattern[1], d_match_pattern[0] ); + d_pattern = pat.getKind()==NOT ? d_pattern.notNode() : d_pattern; + if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching + d_match_pattern = d_match_pattern[1]; + }else{ + d_match_pattern = d_pattern[0][0]; + } + }else if( !d_match_pattern[1].hasAttribute(InstConstantAttribute()) ){ + Assert( d_match_pattern[0].hasAttribute(InstConstantAttribute()) ); + if( pat.getKind()!=NOT ){ //TEMPORARY until we do better implementation of disequality matching + d_match_pattern = d_match_pattern[0]; + } + } + } + int childMatchPolicy = MATCH_GEN_DEFAULT; + for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ + if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){ + if( d_match_pattern[i].getKind()!=INST_CONSTANT ){ + d_children.push_back( new InstMatchGenerator( d_match_pattern[i], qe, childMatchPolicy ) ); + d_children_index.push_back( i ); + } + } + } + + Debug("inst-match-gen") << "Pattern is " << d_pattern << ", match pattern is " << d_match_pattern << std::endl; + + //create candidate generator + if( d_match_pattern.getKind()==EQUAL || d_match_pattern.getKind()==IFF ){ + Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); + //we will be producing candidates via literal matching heuristics + if( d_pattern.getKind()!=NOT ){ + //candidates will be all equalities + d_cg = new inst::CandidateGeneratorQELitEq( qe, d_match_pattern ); + }else{ + //candidates will be all disequalities + d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern ); + } + }else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF || d_pattern.getKind()==NOT ){ + Assert( d_matchPolicy==MATCH_GEN_DEFAULT ); + if( d_pattern.getKind()==NOT ){ + Unimplemented("Disequal generator unimplemented"); + }else{ + Assert( Trigger::isAtomicTrigger( d_match_pattern ) ); + //we are matching only in a particular equivalence class + d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() ); + //store the equivalence class that we will call d_cg->reset( ... ) on + d_eq_class = d_pattern[1]; + } + }else if( Trigger::isAtomicTrigger( d_match_pattern ) ){ + //if( d_matchPolicy==MATCH_GEN_EFFICIENT_E_MATCH ){ + //Warning() << "Currently efficient e matching is not taken into account for quantifiers: " << d_pattern << std::endl; + //} + //we will be scanning lists trying to find d_match_pattern.getOperator() + d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() ); + }else{ + d_cg = new CandidateGeneratorQueue; + if( !Trigger::getPatternArithmetic( d_match_pattern.getAttribute(InstConstantAttribute()), d_match_pattern, d_arith_coeffs ) ){ + Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; + Warning() << "(?) Unknown matching pattern is " << d_match_pattern << std::endl; + d_matchPolicy = MATCH_GEN_INTERNAL_ERROR; + }else{ + Debug("matching-arith") << "Generated arithmetic pattern for " << d_match_pattern << ": " << std::endl; + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; + } + //we will treat this as match gen internal arithmetic + d_matchPolicy = MATCH_GEN_INTERNAL_ARITHMETIC; + } + } +} + +/** get match (not modulo equality) */ +bool InstMatchGenerator::getMatch( Node t, InstMatch& m, QuantifiersEngine* qe ){ + Debug("matching") << "Matching " << t << " against pattern " << d_match_pattern << " (" + << m.size() << ")" << ", " << d_children.size() << std::endl; + Assert( !d_match_pattern.isNull() ); + if( qe->d_optMatchIgnoreModelBasis && t.getAttribute(ModelBasisAttribute()) ){ + return true; + }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ARITHMETIC ){ + return getMatchArithmetic( t, m, qe ); + }else if( d_matchPolicy==MATCH_GEN_INTERNAL_ERROR ){ + return false; + }else{ + EqualityQuery* q = qe->getEqualityQuery(); + //add m to partial match vector + std::vector< InstMatch > partial; + partial.push_back( InstMatch( &m ) ); + //if t is null + Assert( !t.isNull() ); + Assert( !t.hasAttribute(InstConstantAttribute()) ); + Assert( t.getKind()==d_match_pattern.getKind() ); + Assert( !Trigger::isAtomicTrigger( d_match_pattern ) || t.getOperator()==d_match_pattern.getOperator() ); + //first, check if ground arguments are not equal, or a match is in conflict + for( int i=0; i<(int)d_match_pattern.getNumChildren(); i++ ){ + if( d_match_pattern[i].hasAttribute(InstConstantAttribute()) ){ + if( d_match_pattern[i].getKind()==INST_CONSTANT ){ + if( !partial[0].setMatch( q, d_match_pattern[i], t[i] ) ){ + //match is in conflict + Debug("matching-debug") << "Match in conflict " << t[i] << " and " + << d_match_pattern[i] << " because " + << partial[0].get(d_match_pattern[i]) + << std::endl; + Debug("matching-fail") << "Match fail: " << partial[0].get(d_match_pattern[i]) << " and " << t[i] << std::endl; + return false; + } + } + }else{ + if( !q->areEqual( d_match_pattern[i], t[i] ) ){ + Debug("matching-fail") << "Match fail arg: " << d_match_pattern[i] << " and " << t[i] << std::endl; + //ground arguments are not equal + return false; + } + } + } + //now, fit children into match + //we will be requesting candidates for matching terms for each child + std::vector< Node > reps; + for( int i=0; i<(int)d_children.size(); i++ ){ + Node rep = q->getRepresentative( t[ d_children_index[i] ] ); + reps.push_back( rep ); + d_children[i]->d_cg->reset( rep ); + } + + //combine child matches + int index = 0; + while( index>=0 && index<(int)d_children.size() ){ + partial.push_back( InstMatch( &partial[index] ) ); + if( d_children[index]->getNextMatch2( partial[index+1], qe ) ){ + index++; + }else{ + d_children[index]->d_cg->reset( reps[index] ); + partial.pop_back(); + if( !partial.empty() ){ + partial.pop_back(); + } + index--; + } + } + if( index>=0 ){ + m = partial.back(); + return true; + }else{ + return false; + } + } +} + +bool InstMatchGenerator::getNextMatch2( InstMatch& m, QuantifiersEngine* qe, bool saveMatched ){ + bool success = false; + Node t; + do{ + //get the next candidate term t + t = d_cg->getNextCandidate(); + //if t not null, try to fit it into match m + if( !t.isNull() && t.getType()==d_match_pattern.getType() ){ + success = getMatch( t, m, qe ); + } + }while( !success && !t.isNull() ); + if (saveMatched) m.d_matched = t; + return success; +} + +bool InstMatchGenerator::getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ){ + Debug("matching-arith") << "Matching " << t << " " << d_match_pattern << std::endl; + if( !d_arith_coeffs.empty() ){ + NodeBuilder<> tb(kind::PLUS); + Node ic = Node::null(); + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << it->first << " -> " << it->second << std::endl; + if( !it->first.isNull() ){ + if( m.find( it->first )==m.end() ){ + //see if we can choose this to set + if( ic.isNull() && ( it->second.isNull() || !it->first.getType().isInteger() ) ){ + ic = it->first; + } + }else{ + Debug("matching-arith") << "already set " << m.get( it->first ) << std::endl; + Node tm = m.get( it->first ); + if( !it->second.isNull() ){ + tm = NodeManager::currentNM()->mkNode( MULT, it->second, tm ); + } + tb << tm; + } + }else{ + tb << it->second; + } + } + if( !ic.isNull() ){ + Node tm; + if( tb.getNumChildren()==0 ){ + tm = t; + }else{ + tm = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb; + tm = NodeManager::currentNM()->mkNode( MINUS, t, tm ); + } + if( !d_arith_coeffs[ ic ].isNull() ){ + Assert( !ic.getType().isInteger() ); + Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst() ); + tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm ); + } + m.set( ic, Rewriter::rewrite( tm )); + //set the rest to zeros + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + if( !it->first.isNull() ){ + if( m.find( it->first )==m.end() ){ + m.set( it->first, NodeManager::currentNM()->mkConst( Rational(0) ) ); + } + } + } + Debug("matching-arith") << "Setting " << ic << " to " << tm << std::endl; + return true; + }else{ + return false; + } + }else{ + return false; + } +} + + +/** reset instantiation round */ +void InstMatchGenerator::resetInstantiationRound( QuantifiersEngine* qe ){ + if( d_match_pattern.isNull() ){ + for( int i=0; i<(int)d_children.size(); i++ ){ + d_children[i]->resetInstantiationRound( qe ); + } + }else{ + if( d_cg ){ + d_cg->resetInstantiationRound(); + } + } +} + +void InstMatchGenerator::reset( Node eqc, QuantifiersEngine* qe ){ + if( d_match_pattern.isNull() ){ + for( int i=0; i<(int)d_children.size(); i++ ){ + d_children[i]->reset( eqc, qe ); + } + d_partial.clear(); + }else{ + if( !d_eq_class.isNull() ){ + //we have a specific equivalence class in mind + //we are producing matches for f(E) ~ t, where E is a non-ground vector of terms, and t is a ground term + //just look in equivalence class of the RHS + d_cg->reset( d_eq_class ); + }else{ + d_cg->reset( eqc ); + } + } +} + +bool InstMatchGenerator::getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + m.d_matched = Node::null(); + if( d_match_pattern.isNull() ){ + int index = (int)d_partial.size(); + while( index>=0 && index<(int)d_children.size() ){ + if( index>0 ){ + d_partial.push_back( InstMatch( &d_partial[index-1] ) ); + }else{ + d_partial.push_back( InstMatch() ); + } + if( d_children[index]->getNextMatch( d_partial[index], qe ) ){ + index++; + }else{ + d_children[index]->reset( Node::null(), qe ); + d_partial.pop_back(); + if( !d_partial.empty() ){ + d_partial.pop_back(); + } + index--; + } + } + if( index>=0 ){ + m = d_partial.back(); + d_partial.pop_back(); + return true; + }else{ + return false; + } + }else{ + bool res = getNextMatch2( m, qe, true ); + Assert(!res || !m.d_matched.isNull()); + return res; + } +} + + + +// Currently the implementation doesn't take into account that +// variable should have the same value given. +// TODO use the d_children way perhaps +// TODO replace by a real dictionnary +// We should create a real substitution? slower more precise +// We don't do that often +bool InstMatchGenerator::nonunifiable( TNode t0, const std::vector & vars){ + if(d_match_pattern.isNull()) return true; + + typedef std::vector > tstack; + tstack stack(1,std::make_pair(t0,d_match_pattern)); // t * pat + + while(!stack.empty()){ + const std::pair p = stack.back(); stack.pop_back(); + const TNode & t = p.first; + const TNode & pat = p.second; + + // t or pat is a variable currently we consider that can match anything + if( find(vars.begin(),vars.end(),t) != vars.end() ) continue; + if( pat.getKind() == INST_CONSTANT ) continue; + + // t and pat are nonunifiable + if( !Trigger::isAtomicTrigger( t ) || !Trigger::isAtomicTrigger( pat ) ) { + if(t == pat) continue; + else return true; + }; + if( t.getOperator() != pat.getOperator() ) return true; + + //put the children on the stack + for( size_t i=0; i < pat.getNumChildren(); i++ ){ + stack.push_back(std::make_pair(t[i],pat[i])); + }; + } + // The heuristic can't find non-unifiability + return false; +} + +int InstMatchGenerator::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ + //now, try to add instantiation for each match produced + int addedLemmas = 0; + InstMatch m; + while( getNextMatch( m, qe ) ){ + //m.makeInternal( d_quantEngine->getEqualityQuery() ); + m.add( baseMatch ); + if( qe->addInstantiation( f, m ) ){ + addedLemmas++; + if( qe->d_optInstLimitActive && qe->d_optInstLimit<=0 ){ + return addedLemmas; + } + } + m.clear(); + } + //return number of lemmas added + return addedLemmas; +} + +int InstMatchGenerator::addTerm( Node f, Node t, QuantifiersEngine* qe ){ + Assert( options::eagerInstQuant() ); + if( !d_match_pattern.isNull() ){ + InstMatch m; + if( getMatch( t, m, qe ) ){ + if( qe->addInstantiation( f, m ) ){ + return 1; + } + } + }else{ + for( int i=0; i<(int)d_children.size(); i++ ){ + d_children[i]->addTerm( f, t, qe ); + } + } + return 0; +} + +/** constructors */ +InstMatchGeneratorMulti::InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption ) : +d_f( f ){ + Debug("smart-multi-trigger") << "Making smart multi-trigger for " << f << std::endl; + std::map< Node, std::vector< Node > > var_contains; + Trigger::getVarContains( f, pats, var_contains ); + //convert to indicies + for( std::map< Node, std::vector< Node > >::iterator it = var_contains.begin(); it != var_contains.end(); ++it ){ + Debug("smart-multi-trigger") << "Pattern " << it->first << " contains: "; + for( int i=0; i<(int)it->second.size(); i++ ){ + Debug("smart-multi-trigger") << it->second[i] << " "; + int index = it->second[i].getAttribute(InstVarNumAttribute()); + d_var_contains[ it->first ].push_back( index ); + d_var_to_node[ index ].push_back( it->first ); + } + Debug("smart-multi-trigger") << std::endl; + } + for( int i=0; i<(int)pats.size(); i++ ){ + Node n = pats[i]; + //make the match generator + d_children.push_back( new InstMatchGenerator( n, qe, matchOption ) ); + //compute unique/shared variables + 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++ ){ + 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] ); + }else{ + shared_vars[ d_var_contains[n][j] ] = true; + numSharedVars++; + } + } + //we use the latest shared variables, then unique variables + std::vector< int > vars; + int index = i==0 ? (int)(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 ){ + if( std::find( d_var_contains[ pats[index] ].begin(), d_var_contains[ pats[index] ].end(), it->first )!= + d_var_contains[ pats[index] ].end() ){ + vars.push_back( it->first ); + shared_vars[ it->first ] = false; + numSharedVars--; + } + } + } + index = index==0 ? (int)(pats.size()-1) : (index-1); + } + 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] << " "; + } + 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 ) ); + } + +} + +/** reset instantiation round (call this whenever equivalence classes have changed) */ +void InstMatchGeneratorMulti::resetInstantiationRound( QuantifiersEngine* qe ){ + for( int i=0; i<(int)d_children.size(); i++ ){ + d_children[i]->resetInstantiationRound( qe ); + } +} + +/** reset, eqc is the equivalence class to search in (any if eqc=null) */ +void InstMatchGeneratorMulti::reset( Node eqc, QuantifiersEngine* qe ){ + for( int i=0; i<(int)d_children.size(); i++ ){ + d_children[i]->reset( eqc, qe ); + } +} + +int InstMatchGeneratorMulti::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ + int addedLemmas = 0; + Debug("smart-multi-trigger") << "Process smart multi trigger" << std::endl; + for( int i=0; i<(int)d_children.size(); i++ ){ + Debug("smart-multi-trigger") << "Calculate matches " << i << std::endl; + std::vector< InstMatch > newMatches; + InstMatch m; + while( d_children[i]->getNextMatch( m, qe ) ){ + m.makeRepresentative( qe ); + newMatches.push_back( InstMatch( &m ) ); + m.clear(); + } + for( int j=0; j<(int)newMatches.size(); j++ ){ + processNewMatch( qe, newMatches[j], i, addedLemmas ); + } + } + return addedLemmas; +} + +void InstMatchGeneratorMulti::processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ){ + //see if these produce new matches + d_children_trie[fromChildIndex].addInstMatch( qe, d_f, m, true ); + //possibly only do the following if we know that new matches will be produced? + //the issue is that instantiations are filtered in quantifiers engine, and so there is no guarentee that + // we can safely skip the following lines, even when we have already produced this match. + Debug("smart-multi-trigger") << "Child " << fromChildIndex << " produced match " << m << std::endl; + //process new instantiations + int childIndex = (fromChildIndex+1)%(int)d_children.size(); + std::vector< IndexedTrie > unique_var_tries; + processNewInstantiations( qe, m, addedLemmas, d_children_trie[childIndex].getTrie(), + unique_var_tries, 0, childIndex, fromChildIndex, true ); +} + +void InstMatchGeneratorMulti::processNewInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr, + std::vector< IndexedTrie >& unique_var_tries, + int trieIndex, int childIndex, int endChildIndex, bool modEq ){ + if( childIndex==endChildIndex ){ + //now, process unique variables + processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, 0 ); + }else if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){ + int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex]; + Node curr_ic = qe->getTermDatabase()->getInstantiationConstant( d_f, curr_index ); + if( m.find( curr_ic )==m.end() ){ + //if( d_var_to_node[ curr_index ].size()==1 ){ //FIXME + // //unique variable(s), defer calculation + // unique_var_tries.push_back( IndexedTrie( std::pair< int, int >( childIndex, trieIndex ), tr ) ); + // int newChildIndex = (childIndex+1)%(int)d_children.size(); + // processNewInstantiations( qe, m, d_children_trie[newChildIndex].getTrie(), unique_var_tries, + // 0, newChildIndex, endChildIndex, modEq ); + //}else{ + //shared and non-set variable, add to InstMatch + for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){ + InstMatch mn( &m ); + mn.set( curr_ic, it->first); + processNewInstantiations( qe, mn, addedLemmas, &(it->second), unique_var_tries, + trieIndex+1, childIndex, endChildIndex, modEq ); + } + //} + }else{ + //shared and set variable, try to merge + Node n = m.get( curr_ic ); + std::map< Node, InstMatchTrie >::iterator it = tr->d_data.find( n ); + if( it!=tr->d_data.end() ){ + processNewInstantiations( qe, m, addedLemmas, &(it->second), unique_var_tries, + trieIndex+1, childIndex, endChildIndex, modEq ); + } + if( modEq ){ + //check modulo equality for other possible instantiations + if( qe->getEqualityQuery()->getEngine()->hasTerm( n ) ){ + eq::EqClassIterator eqc( qe->getEqualityQuery()->getEngine()->getRepresentative( n ), + qe->getEqualityQuery()->getEngine() ); + while( !eqc.isFinished() ){ + Node en = (*eqc); + if( en!=n ){ + std::map< Node, InstMatchTrie >::iterator itc = tr->d_data.find( en ); + if( itc!=tr->d_data.end() ){ + processNewInstantiations( qe, m, addedLemmas, &(itc->second), unique_var_tries, + trieIndex+1, childIndex, endChildIndex, modEq ); + } + } + ++eqc; + } + } + } + } + }else{ + int newChildIndex = (childIndex+1)%(int)d_children.size(); + processNewInstantiations( qe, m, addedLemmas, d_children_trie[newChildIndex].getTrie(), unique_var_tries, + 0, newChildIndex, endChildIndex, modEq ); + } +} + +void InstMatchGeneratorMulti::processNewInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, + std::vector< IndexedTrie >& unique_var_tries, + int uvtIndex, InstMatchTrie* tr, int trieIndex ){ + if( uvtIndex<(int)unique_var_tries.size() ){ + int childIndex = unique_var_tries[uvtIndex].first.first; + if( !tr ){ + tr = unique_var_tries[uvtIndex].second; + trieIndex = unique_var_tries[uvtIndex].first.second; + } + if( trieIndex<(int)d_children_trie[childIndex].getOrdering()->d_order.size() ){ + int curr_index = d_children_trie[childIndex].getOrdering()->d_order[trieIndex]; + Node curr_ic = qe->getTermDatabase()->getInstantiationConstant( d_f, curr_index ); + //unique non-set variable, add to InstMatch + for( std::map< Node, InstMatchTrie >::iterator it = tr->d_data.begin(); it != tr->d_data.end(); ++it ){ + InstMatch mn( &m ); + mn.set( curr_ic, it->first); + processNewInstantiations2( qe, mn, addedLemmas, unique_var_tries, uvtIndex, &(it->second), trieIndex+1 ); + } + }else{ + processNewInstantiations2( qe, m, addedLemmas, unique_var_tries, uvtIndex+1 ); + } + }else{ + //m is an instantiation + if( qe->addInstantiation( d_f, m ) ){ + addedLemmas++; + Debug("smart-multi-trigger") << "-> Produced instantiation " << m << std::endl; + } + } +} + +int InstMatchGeneratorMulti::addTerm( Node f, Node t, QuantifiersEngine* qe ){ + Assert( options::eagerInstQuant() ); + int addedLemmas = 0; + for( int i=0; i<(int)d_children.size(); i++ ){ + if( ((InstMatchGenerator*)d_children[i])->d_match_pattern.getOperator()==t.getOperator() ){ + InstMatch m; + //if it produces a match, then process it with the rest + if( ((InstMatchGenerator*)d_children[i])->getMatch( t, m, qe ) ){ + processNewMatch( qe, m, i, addedLemmas ); + } + } + } + return addedLemmas; +} + +int InstMatchGeneratorSimple::addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ){ + InstMatch m; + m.add( baseMatch ); + int addedLemmas = 0; + if( d_match_pattern.getType()==NodeManager::currentNM()->booleanType() ){ + for( int i=0; i<2; i++ ){ + addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_pred_map_trie[i][ d_match_pattern.getOperator() ]) ); + } + }else{ + addInstantiations( m, qe, addedLemmas, 0, &(qe->getTermDatabase()->d_func_map_trie[ d_match_pattern.getOperator() ]) ); + } + return addedLemmas; +} + +void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat ){ + if( argIndex==(int)d_match_pattern.getNumChildren() ){ + //m is an instantiation + if( qe->addInstantiation( d_f, m ) ){ + addedLemmas++; + Debug("simple-multi-trigger") << "-> Produced instantiation " << m << std::endl; + } + }else{ + if( d_match_pattern[argIndex].getKind()==INST_CONSTANT ){ + Node ic = d_match_pattern[argIndex]; + for( std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.begin(); it != tat->d_data.end(); ++it ){ + Node t = it->first; + if( m.get( ic ).isNull() || m.get( ic )==t ){ + Node prev = m.get( ic ); + m.set( ic, t); + addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); + m.set( ic, prev); + } + } + }else{ + Node r = qe->getEqualityQuery()->getRepresentative( d_match_pattern[argIndex] ); + std::map< Node, quantifiers::TermArgTrie >::iterator it = tat->d_data.find( r ); + if( it!=tat->d_data.end() ){ + addInstantiations( m, qe, addedLemmas, argIndex+1, &(it->second) ); + } + } + } +} + +int InstMatchGeneratorSimple::addTerm( Node f, Node t, QuantifiersEngine* qe ){ + Assert( options::eagerInstQuant() ); + InstMatch m; + for( int i=0; i<(int)t.getNumChildren(); i++ ){ + if( d_match_pattern[i].getKind()==INST_CONSTANT ){ + m.set(d_match_pattern[i], t[i]); + }else if( !qe->getEqualityQuery()->areEqual( d_match_pattern[i], t[i] ) ){ + return 0; + } + } + return qe->addInstantiation( f, m ) ? 1 : 0; +} diff --git a/src/theory/quantifiers/inst_match.h b/src/theory/quantifiers/inst_match.h new file mode 100644 index 000000000..fffa3bc4d --- /dev/null +++ b/src/theory/quantifiers/inst_match.h @@ -0,0 +1,394 @@ +/********************* */ +/*! \file inst_match.h + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief inst match class + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANTIFIERS__INST_MATCH_H +#define __CVC4__THEORY__QUANTIFIERS__INST_MATCH_H + +#include "util/hash.h" + +#include +#include +#include + +#include "context/cdlist.h" +#include "theory/quantifiers/candidate_generator.h" + +//#define USE_EFFICIENT_E_MATCHING + +namespace CVC4 { +namespace theory { + +/** 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 InstConstantAttribute; + +struct InstLevelAttributeId {}; +typedef expr::Attribute InstLevelAttribute; + +struct InstVarNumAttributeId {}; +typedef expr::Attribute InstVarNumAttribute; + +// Attribute that tell if a node have been asserted in this branch +struct AvailableInTermDbId {}; +/** use the special for boolean flag */ +typedef expr::Attribute AvailableInTermDb; + + +class QuantifiersEngine; +namespace quantifiers{ + class TermArgTrie; +} + +namespace uf{ + class InstantiatorTheoryUf; + class TheoryUF; +}/* CVC4::theory::uf namespace */ + +namespace inst { + +class EqualityQuery { +public: + EqualityQuery(){} + virtual ~EqualityQuery(){}; + /** contains term */ + virtual bool hasTerm( Node a ) = 0; + /** get the representative of the equivalence class of a */ + virtual Node getRepresentative( Node a ) = 0; + /** returns true if a and b are equal in the current context */ + virtual bool areEqual( Node a, Node b ) = 0; + /** returns true is a and b are disequal in the current context */ + virtual bool areDisequal( Node a, Node b ) = 0; + /** getInternalRepresentative gets the current best representative in the equivalence class of a, based on some criteria. + If cbqi is active, this will return a term in the equivalence class of "a" that does + not contain instantiation constants, if such a term exists. + */ + virtual Node getInternalRepresentative( Node a ) = 0; + /** get the equality engine associated with this query */ + virtual eq::EqualityEngine* getEngine() = 0; + /** get the equivalence class of a */ + virtual void getEquivalenceClass( Node a, std::vector< Node >& eqc ) = 0; +};/* class EqualityQuery */ + +/** basic class defining an instantiation */ +class InstMatch { + /* map from variable to ground terms */ + std::map< Node, Node > d_map; +public: + InstMatch(); + InstMatch( InstMatch* m ); + + /** set the match of v to m */ + bool setMatch( EqualityQuery* q, TNode v, TNode m ); + /* This version tell if the variable has been set */ + bool setMatch( EqualityQuery* q, TNode v, TNode m, bool & set); + /** fill all unfilled values with m */ + bool add( InstMatch& m ); + /** if compatible, fill all unfilled values with m and return true + return false otherwise */ + bool merge( EqualityQuery* q, InstMatch& m ); + /** debug print method */ + void debugPrint( const char* c ); + /** make complete */ + void makeComplete( Node f, QuantifiersEngine* qe ); + /** make internal: ensure that no term in d_map contains instantiation constants */ + void makeInternal( QuantifiersEngine* qe ); + /** make representative */ + void makeRepresentative( QuantifiersEngine* qe ); + /** apply rewrite */ + void applyRewrite(); + /** compute d_match */ + void computeTermVec( QuantifiersEngine* qe, const std::vector< Node >& vars, std::vector< Node >& match ); + /** compute d_match */ + void computeTermVec( const std::vector< Node >& vars, std::vector< Node >& match ); + /** clear */ + void clear(){ d_map.clear(); } + /** erase */ + template + void erase(Iterator begin, Iterator end){ + for(Iterator i = begin; i != end; ++i){ + d_map.erase(*i); + }; + } + void erase(Node node){ d_map.erase(node); } + /** is_empty */ + bool empty(){ return d_map.empty(); } + /** set */ + void set(TNode var, TNode n){ + //std::cout << "var.getType() " << var.getType() << "n.getType() " << n.getType() << std::endl ; + Assert( !var.isNull() ); + Assert( n.isNull() ||// For a strange use in inst_match.cpp InstMatchGeneratorSimple::addInstantiations + var.getType() == n.getType() ); + d_map[var] = n; + } + Node get(TNode var){ return d_map[var]; } + size_t size(){ return d_map.size(); } + /* iterator */ + std::map< Node, Node >::iterator begin(){ return d_map.begin(); }; + std::map< Node, Node >::iterator end(){ return d_map.end(); }; + std::map< Node, Node >::iterator find(Node var){ return d_map.find(var); }; + /* Node used for matching the trigger only for mono-trigger (just for + efficiency because I need only that) */ + Node d_matched; + /** to stream */ + inline void toStream(std::ostream& out) const { + out << "INST_MATCH( "; + for( std::map< Node, Node >::const_iterator it = d_map.begin(); it != d_map.end(); ++it ){ + if( it != d_map.begin() ){ out << ", "; } + out << it->first << " -> " << it->second; + } + out << " )"; + } +};/* class InstMatch */ + +inline std::ostream& operator<<(std::ostream& out, const InstMatch& m) { + m.toStream(out); + return out; +} + +/** trie for InstMatch objects */ +class InstMatchTrie { +public: + class ImtIndexOrder { + public: + std::vector< int > d_order; + };/* class InstMatchTrie ImtIndexOrder */ +private: + /** add match m for quantifier f starting at index, take into account equalities q, return true if successful */ + void addInstMatch2( QuantifiersEngine* qe, Node f, InstMatch& m, int index, ImtIndexOrder* imtio ); + /** exists match */ + bool existsInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq, int index, ImtIndexOrder* imtio ); +public: + /** the data */ + std::map< Node, InstMatchTrie > d_data; +public: + InstMatchTrie(){} + ~InstMatchTrie(){} +public: + /** add match m for quantifier f, take into account equalities if modEq = true, + if imtio is non-null, this is the order to add to trie + return true if successful + */ + bool addInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq = false, ImtIndexOrder* imtio = NULL ); +};/* class InstMatchTrie */ + +class InstMatchTrieOrdered { +private: + InstMatchTrie::ImtIndexOrder* d_imtio; + InstMatchTrie d_imt; +public: + InstMatchTrieOrdered( InstMatchTrie::ImtIndexOrder* imtio ) : d_imtio( imtio ){} + ~InstMatchTrieOrdered(){} + /** get ordering */ + InstMatchTrie::ImtIndexOrder* getOrdering() { return d_imtio; } + /** get trie */ + InstMatchTrie* getTrie() { return &d_imt; } +public: + /** add match m, return true if successful */ + bool addInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m, bool modEq = false ){ + return d_imt.addInstMatch( qe, f, m, modEq, d_imtio ); + } +};/* class InstMatchTrieOrdered */ + +/** base class for producing InstMatch objects */ +class IMGenerator { +public: + /** reset instantiation round (call this at beginning of instantiation round) */ + virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0; + /** reset, eqc is the equivalence class to search in (any if eqc=null) */ + virtual void reset( Node eqc, QuantifiersEngine* qe ) = 0; + /** get the next match. must call reset( eqc ) before this function. */ + virtual bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) = 0; + /** return true if whatever Node is substituted for the variables the + given Node can't match the pattern */ + virtual bool nonunifiable( TNode t, const std::vector & vars) = 0; + /** add instantiations directly */ + virtual int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ) = 0; + /** add ground term t, called when t is added to term db */ + virtual int addTerm( Node f, Node t, QuantifiersEngine* qe ) = 0; +};/* class IMGenerator */ + + +class InstMatchGenerator : public IMGenerator { +private: + /** candidate generator */ + CandidateGenerator* d_cg; + /** policy to use for matching */ + int d_matchPolicy; + /** children generators */ + std::vector< InstMatchGenerator* > d_children; + std::vector< int > d_children_index; + /** partial vector */ + std::vector< InstMatch > d_partial; + /** eq class */ + Node d_eq_class; + /** for arithmetic matching */ + std::map< Node, Node > d_arith_coeffs; + /** initialize pattern */ + void initializePatterns( std::vector< Node >& pats, QuantifiersEngine* qe ); + void initializePattern( Node pat, QuantifiersEngine* qe ); +public: + enum { + //options for producing matches + MATCH_GEN_DEFAULT = 0, + MATCH_GEN_EFFICIENT_E_MATCH, //generate matches via Efficient E-matching for SMT solvers + //others (internally used) + MATCH_GEN_INTERNAL_ARITHMETIC, + MATCH_GEN_INTERNAL_ERROR, + }; +private: + /** get the next match. must call d_cg->reset( ... ) before using. + only valid for use where !d_match_pattern.isNull(). + */ + bool getNextMatch2( InstMatch& m, QuantifiersEngine* qe, bool saveMatched = false ); + /** for arithmetic */ + bool getMatchArithmetic( Node t, InstMatch& m, QuantifiersEngine* qe ); +public: + /** get the match against ground term or formula t. + d_match_pattern and t should have the same shape. + only valid for use where !d_match_pattern.isNull(). + */ + bool getMatch( Node t, InstMatch& m, QuantifiersEngine* qe ); + + /** constructors */ + InstMatchGenerator( Node pat, QuantifiersEngine* qe, int matchOption = 0 ); + InstMatchGenerator( std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption = 0 ); + /** destructor */ + ~InstMatchGenerator(){} + /** The pattern we are producing matches for. + If null, this is a multi trigger that is merging matches from d_children. + */ + Node d_pattern; + /** match pattern */ + Node d_match_pattern; +public: + /** 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) */ + void reset( Node eqc, QuantifiersEngine* qe ); + /** get the next match. must call reset( eqc ) before this function. */ + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ); + /** return true if whatever Node is substituted for the variables the + given Node can't match the pattern */ + bool nonunifiable( TNode t, const std::vector & vars); + /** add instantiations */ + int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); + /** add ground term t */ + int addTerm( Node f, Node t, QuantifiersEngine* qe ); +};/* class InstMatchGenerator */ + +/** smart multi-trigger implementation */ +class InstMatchGeneratorMulti : public IMGenerator { +private: + /** indexed trie */ + typedef std::pair< std::pair< int, int >, InstMatchTrie* > IndexedTrie; + /** process new match */ + void processNewMatch( QuantifiersEngine* qe, InstMatch& m, int fromChildIndex, int& addedLemmas ); + /** process new instantiations */ + void processNewInstantiations( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, InstMatchTrie* tr, + std::vector< IndexedTrie >& unique_var_tries, + int trieIndex, int childIndex, int endChildIndex, bool modEq ); + /** process new instantiations 2 */ + void processNewInstantiations2( QuantifiersEngine* qe, InstMatch& m, int& addedLemmas, + std::vector< IndexedTrie >& unique_var_tries, + int uvtIndex, InstMatchTrie* tr = NULL, int trieIndex = 0 ); +private: + /** var contains (variable indices) for each pattern node */ + std::map< Node, std::vector< int > > d_var_contains; + /** variable indices contained to pattern nodes */ + std::map< int, std::vector< Node > > d_var_to_node; + /** quantifier to use */ + Node d_f; + /** policy to use for matching */ + int d_matchPolicy; + /** children generators */ + std::vector< InstMatchGenerator* > d_children; + /** inst match tries for each child */ + std::vector< InstMatchTrieOrdered > d_children_trie; + /** calculate matches */ + void calculateMatches( QuantifiersEngine* qe ); +public: + /** constructors */ + InstMatchGeneratorMulti( Node f, std::vector< Node >& pats, QuantifiersEngine* qe, int matchOption = 0 ); + /** destructor */ + ~InstMatchGeneratorMulti(){} + /** 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) */ + void reset( Node eqc, QuantifiersEngine* qe ); + /** get the next match. must call reset( eqc ) before this function. (not implemented) */ + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) { return false; } + /** return true if whatever Node is substituted for the variables the + given Node can't match the pattern */ + bool nonunifiable( TNode t, const std::vector & vars) { return true; } + /** add instantiations */ + int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); + /** add ground term t */ + int addTerm( Node f, Node t, QuantifiersEngine* qe ); +};/* class InstMatchGeneratorMulti */ + +/** smart (single)-trigger implementation */ +class InstMatchGeneratorSimple : public IMGenerator { +private: + /** quantifier for match term */ + Node d_f; + /** match term */ + Node d_match_pattern; + /** add instantiations */ + void addInstantiations( InstMatch& m, QuantifiersEngine* qe, int& addedLemmas, int argIndex, quantifiers::TermArgTrie* tat ); +public: + /** constructors */ + InstMatchGeneratorSimple( Node f, Node pat ) : d_f( f ), d_match_pattern( pat ){} + /** destructor */ + ~InstMatchGeneratorSimple(){} + /** 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) */ + void reset( Node eqc, QuantifiersEngine* qe ) {} + /** get the next match. must call reset( eqc ) before this function. (not implemented) */ + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) { return false; } + /** return true if whatever Node is substituted for the variables the + given Node can't match the pattern */ + bool nonunifiable( TNode t, const std::vector & vars) { return true; } + /** add instantiations */ + int addInstantiations( Node f, InstMatch& baseMatch, QuantifiersEngine* qe ); + /** add ground term t, possibly add instantiations */ + int addTerm( Node f, Node t, QuantifiersEngine* qe ); +};/* class InstMatchGeneratorSimple */ + +}/* CVC4::theory::inst namespace */ + +typedef CVC4::theory::inst::InstMatch InstMatch; +typedef CVC4::theory::inst::EqualityQuery EqualityQuery; + +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ + +#endif /* __CVC4__THEORY__QUANTIFIERS__INST_MATCH_H */ diff --git a/src/theory/quantifiers/instantiation_engine.h b/src/theory/quantifiers/instantiation_engine.h index 13de210ab..37ee6d801 100644 --- a/src/theory/quantifiers/instantiation_engine.h +++ b/src/theory/quantifiers/instantiation_engine.h @@ -16,8 +16,8 @@ #include "cvc4_private.h" -#ifndef __CVC4__INSTANTIATION_ENGINE_H -#define __CVC4__INSTANTIATION_ENGINE_H +#ifndef __CVC4__THEORY__QUANTIFIERS__INSTANTIATION_ENGINE_H +#define __CVC4__THEORY__QUANTIFIERS__INSTANTIATION_ENGINE_H #include "theory/quantifiers_engine.h" #include "theory/quantifiers/theory_quantifiers.h" @@ -69,10 +69,10 @@ public: public: /** get the corresponding counterexample literal for quantified formula node n */ Node getCounterexampleLiteralFor( Node f ) { return d_ce_lit.find( f )==d_ce_lit.end() ? Node::null() : d_ce_lit[ f ]; } -}; +};/* class InstantiationEngine */ -} -} -} +}/* CVC4::theory::quantifiers namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ -#endif +#endif /* __CVC4__THEORY__QUANTIFIERS__INSTANTIATION_ENGINE_H */ diff --git a/src/theory/quantifiers/instantiator_default.cpp b/src/theory/quantifiers/instantiator_default.cpp new file mode 100644 index 000000000..ca29f27b6 --- /dev/null +++ b/src/theory/quantifiers/instantiator_default.cpp @@ -0,0 +1,56 @@ +/********************* */ +/*! \file instantiator_default.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of instantiator_default class + **/ + +#include "theory/quantifiers/instantiator_default.h" +#include "theory/theory_engine.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; + +InstantiatorDefault::InstantiatorDefault(context::Context* c, QuantifiersEngine* ie, Theory* th) : + Instantiator( c, ie, th ) { +} + +void InstantiatorDefault::assertNode( Node assertion ){ +} + +void InstantiatorDefault::processResetInstantiationRound( Theory::Effort effort ){ +} + +int InstantiatorDefault::process( Node f, Theory::Effort effort, int e ){ + /* + if( e < 4 ){ + return InstStrategy::STATUS_UNFINISHED; + }else if( e == 4 ){ + Debug("quant-default") << "Process " << f << " : " << std::endl; + InstMatch m; + for( int j=0; j<(int)d_quantEngine->getNumInstantiationConstants( f ); j++ ){ + Node i = d_quantEngine->getInstantiationConstant( f, j ); + Debug("quant-default") << "Getting value for " << i << std::endl; + if( d_quantEngine->getTheoryEngine()->theoryOf( i )==getTheory() ){ //if it belongs to this theory + Node val = d_th->getValue( i ); + Debug("quant-default") << "Default Instantiate for " << d_th->getId() << ", setting " << i << " = " << val << std::endl; + m.set( i, val); + } + } + d_quantEngine->addInstantiation( f, m ); + } + */ + return InstStrategy::STATUS_UNKNOWN; +} diff --git a/src/theory/quantifiers/instantiator_default.h b/src/theory/quantifiers/instantiator_default.h new file mode 100644 index 000000000..8e0a8de73 --- /dev/null +++ b/src/theory/quantifiers/instantiator_default.h @@ -0,0 +1,48 @@ +/********************* */ +/*! \file instantiator_default.h + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief instantiator_default + **/ + + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANTIFIERS__INSTANTIATOR_DEFAULT_H +#define __CVC4__THEORY__QUANTIFIERS__INSTANTIATOR_DEFAULT_H + +#include +#include "theory/quantifiers_engine.h" + +namespace CVC4 { +namespace theory { + +class InstantiatorDefault : public Instantiator { + friend class QuantifiersEngine; +protected: + /** reset instantiation round */ + void processResetInstantiationRound(Theory::Effort effort); + /** process quantifier */ + int process( Node f, Theory::Effort effort, int e ); +public: + InstantiatorDefault(context::Context* c, QuantifiersEngine* ie, Theory* th); + ~InstantiatorDefault() { } + /** check function, assertion is asserted to theory */ + void assertNode( Node assertion ); + /** identify */ + std::string identify() const { return std::string("InstantiatorDefault"); } +};/* class InstantiatorDefault */ + +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ + +#endif /* __CVC4__THEORY__QUANTIFIERS__INSTANTIATOR_DEFAULT_H */ diff --git a/src/theory/quantifiers/model_builder.h b/src/theory/quantifiers/model_builder.h index 05eb8f55f..344b731e0 100644 --- a/src/theory/quantifiers/model_builder.h +++ b/src/theory/quantifiers/model_builder.h @@ -16,8 +16,8 @@ #include "cvc4_private.h" -#ifndef __CVC4__QUANTIFIERS_MODEL_BUILDER_H -#define __CVC4__QUANTIFIERS_MODEL_BUILDER_H +#ifndef __CVC4__THEORY__QUANTIFIERS__MODEL_BUILDER_H +#define __CVC4__THEORY__QUANTIFIERS__MODEL_BUILDER_H #include "theory/quantifiers_engine.h" #include "theory/model.h" @@ -82,10 +82,10 @@ public: ~Statistics(); }; Statistics d_statistics; -}; +};/* class ModelEngineBuilder */ -} -} -} +}/* CVC4::theory::quantifiers namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ -#endif +#endif /* __CVC4__THEORY__QUANTIFIERS__MODEL_BUILDER_H */ diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h index 1139332fe..f5d1db736 100644 --- a/src/theory/quantifiers/model_engine.h +++ b/src/theory/quantifiers/model_engine.h @@ -16,8 +16,8 @@ #include "cvc4_private.h" -#ifndef __CVC4__QUANTIFIERS_MODEL_ENGINE_H -#define __CVC4__QUANTIFIERS_MODEL_ENGINE_H +#ifndef __CVC4__THEORY__QUANTIFIERS__MODEL_ENGINE_H +#define __CVC4__THEORY__QUANTIFIERS__MODEL_ENGINE_H #include "theory/quantifiers_engine.h" #include "theory/quantifiers/model_builder.h" @@ -81,10 +81,10 @@ public: ~Statistics(); }; Statistics d_statistics; -}; +};/* class ModelEngine */ -} -} -} +}/* CVC4::theory::quantifiers namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ -#endif +#endif /* __CVC4__THEORY__QUANTIFIERS__MODEL_ENGINE_H */ diff --git a/src/theory/quantifiers/relevant_domain.h b/src/theory/quantifiers/relevant_domain.h index 8c8ea6a42..6ce47d114 100644 --- a/src/theory/quantifiers/relevant_domain.h +++ b/src/theory/quantifiers/relevant_domain.h @@ -16,8 +16,8 @@ #include "cvc4_private.h" -#ifndef __CVC4__RELEVANT_DOMAIN_H -#define __CVC4__RELEVANT_DOMAIN_H +#ifndef __CVC4__THEORY__QUANTIFIERS__RELEVANT_DOMAIN_H +#define __CVC4__THEORY__QUANTIFIERS__RELEVANT_DOMAIN_H #include "theory/quantifiers/first_order_model.h" @@ -45,10 +45,10 @@ public: void compute(); //relevant instantiation domain for each quantifier std::map< Node, std::vector< RepDomain > > d_quant_inst_domain; -}; +};/* class RelevantDomain */ -} -} -} +}/* CVC4::theory::quantifiers namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ -#endif +#endif /* __CVC4__THEORY__QUANTIFIERS__RELEVANT_DOMAIN_H */ diff --git a/src/theory/quantifiers/rep_set_iterator.h b/src/theory/quantifiers/rep_set_iterator.h index a5ec266a9..85a2f3fd2 100644 --- a/src/theory/quantifiers/rep_set_iterator.h +++ b/src/theory/quantifiers/rep_set_iterator.h @@ -16,8 +16,8 @@ #include "cvc4_private.h" -#ifndef __CVC4__REP_SET_ITERATOR_H -#define __CVC4__REP_SET_ITERATOR_H +#ifndef __CVC4__THEORY__QUANTIFIERS__REP_SET_ITERATOR_H +#define __CVC4__THEORY__QUANTIFIERS__REP_SET_ITERATOR_H #include "theory/quantifiers_engine.h" #include "theory/quantifiers/first_order_model.h" @@ -110,11 +110,10 @@ public: int d_eval_uf_terms; int d_eval_lits; int d_eval_lits_unknown; -}; - +};/* class RepSetEvaluator */ -} -} -} +}/* CVC4::theory::quantifiers namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ #endif diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h index 2af6992f7..8106b5715 100644 --- a/src/theory/quantifiers/term_database.h +++ b/src/theory/quantifiers/term_database.h @@ -16,8 +16,8 @@ #include "cvc4_private.h" -#ifndef __CVC4__QUANTIFIERS_TERM_DATABASE_H -#define __CVC4__QUANTIFIERS_TERM_DATABASE_H +#ifndef __CVC4__THEORY__QUANTIFIERS__TERM_DATABASE_H +#define __CVC4__THEORY__QUANTIFIERS__TERM_DATABASE_H #include "theory/theory.h" @@ -149,8 +149,8 @@ public: Node getFreeVariableForInstConstant( Node n ); };/* class TermDb */ -} -} -} +}/* CVC4::theory::quantifiers namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ -#endif +#endif /* __CVC4__THEORY__QUANTIFIERS__TERM_DATABASE_H */ diff --git a/src/theory/quantifiers/theory_quantifiers_instantiator.h b/src/theory/quantifiers/theory_quantifiers_instantiator.h index bf17495a1..e837811b0 100644 --- a/src/theory/quantifiers/theory_quantifiers_instantiator.h +++ b/src/theory/quantifiers/theory_quantifiers_instantiator.h @@ -17,8 +17,8 @@ #include "cvc4_private.h" -#ifndef __CVC4__INSTANTIATOR_QUANTIFIERS_H -#define __CVC4__INSTANTIATOR_QUANTIFIERS_H +#ifndef __CVC4__THEORY__QUANTIFIERS__THEORY_QUANTIFIERS_INSTANTIATOR_H +#define __CVC4__THEORY__QUANTIFIERS__THEORY_QUANTIFIERS_INSTANTIATOR_H #include "theory/quantifiers_engine.h" @@ -51,10 +51,10 @@ private: ~Statistics(); }; Statistics d_statistics; -};/* class InstantiatiorTheoryArith */ +};/* class InstantiatiorTheoryQuantifiers */ -} -} -} +}/* CVC4::theory::quantifiers namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ -#endif \ No newline at end of file +#endif /* __CVC4__THEORY__QUANTIFIERS__THEORY_QUANTIFIERS_INSTANTIATOR_H */ diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp new file mode 100644 index 000000000..4bb85287e --- /dev/null +++ b/src/theory/quantifiers/trigger.cpp @@ -0,0 +1,558 @@ +/********************* */ +/*! \file trigger.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of trigger class + **/ + +#include "theory/quantifiers/trigger.h" +#include "theory/theory_engine.h" +#include "theory/quantifiers_engine.h" +#include "theory/uf/theory_uf_instantiator.h" +#include "theory/quantifiers/candidate_generator.h" +#include "theory/uf/equality_engine.h" +#include "theory/quantifiers/options.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::inst; + +//#define NESTED_PATTERN_SELECTION + +Trigger* Trigger::TrTrie::getTrigger2( std::vector< Node >& nodes ){ + if( nodes.empty() ){ + return d_tr; + }else{ + Node n = nodes.back(); + nodes.pop_back(); + if( d_children.find( n )!=d_children.end() ){ + return d_children[n]->getTrigger2( nodes ); + }else{ + return NULL; + } + } +} +void Trigger::TrTrie::addTrigger2( std::vector< Node >& nodes, Trigger* t ){ + if( nodes.empty() ){ + d_tr = t; + }else{ + Node n = nodes.back(); + nodes.pop_back(); + if( d_children.find( n )==d_children.end() ){ + d_children[n] = new TrTrie; + } + d_children[n]->addTrigger2( nodes, t ); + } +} + +/** trigger static members */ +std::map< TNode, std::vector< TNode > > Trigger::d_var_contains; +Trigger::TrTrie Trigger::d_tr_trie; + +/** trigger class constructor */ +Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool smartTriggers ) : +d_quantEngine( qe ), d_f( f ){ + d_nodes.insert( d_nodes.begin(), nodes.begin(), nodes.end() ); + if( smartTriggers ){ + if( d_nodes.size()==1 ){ + if( isSimpleTrigger( d_nodes[0] ) ){ + d_mg = new InstMatchGeneratorSimple( f, d_nodes[0] ); + }else{ + d_mg = new InstMatchGenerator( d_nodes[0], qe, matchOption ); + } + }else{ + d_mg = new InstMatchGeneratorMulti( f, d_nodes, qe, matchOption ); + } + }else{ + d_mg = new InstMatchGenerator( d_nodes, qe, matchOption ); + } + Debug("trigger") << "Trigger for " << f << ": " << std::endl; + for( int i=0; i<(int)d_nodes.size(); i++ ){ + Debug("trigger") << " " << d_nodes[i] << std::endl; + } + Debug("trigger") << std::endl; + if( d_nodes.size()==1 ){ + if( isSimpleTrigger( d_nodes[0] ) ){ + ++(qe->d_statistics.d_triggers); + }else{ + ++(qe->d_statistics.d_simple_triggers); + } + }else{ + Debug("multi-trigger") << "Multi-trigger " << (*this) << std::endl; + //Notice() << "Multi-trigger for " << f << " : " << std::endl; + //Notice() << " " << (*this) << std::endl; + ++(qe->d_statistics.d_multi_triggers); + } + //Notice() << "Trigger : " << (*this) << " for " << f << std::endl; + if( options::eagerInstQuant() ){ + Theory* th_uf = qe->getTheoryEngine()->getTheory( theory::THEORY_UF ); + uf::InstantiatorTheoryUf* ith = (uf::InstantiatorTheoryUf*)th_uf->getInstantiator(); + for( int i=0; i<(int)d_nodes.size(); i++ ){ + ith->registerTrigger( this, d_nodes[i].getOperator() ); + } + } +} +void Trigger::computeVarContains( Node n ) { + if( d_var_contains.find( n )==d_var_contains.end() ){ + d_var_contains[n].clear(); + computeVarContains2( n, n ); + } +} + +void Trigger::computeVarContains2( Node n, Node parent ){ + if( n.getKind()==INST_CONSTANT ){ + if( std::find( d_var_contains[parent].begin(), d_var_contains[parent].end(), n )==d_var_contains[parent].end() ){ + d_var_contains[parent].push_back( n ); + } + }else{ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + computeVarContains2( n[i], parent ); + } + } +} + +void Trigger::resetInstantiationRound(){ + d_mg->resetInstantiationRound( d_quantEngine ); +} + +void Trigger::reset( Node eqc ){ + d_mg->reset( eqc, d_quantEngine ); +} + +bool Trigger::getNextMatch( InstMatch& m ){ + bool retVal = d_mg->getNextMatch( m, d_quantEngine ); + //m.makeInternal( d_quantEngine->getEqualityQuery() ); + return retVal; +} + +bool Trigger::getMatch( Node t, InstMatch& m ){ + //FIXME: this assumes d_mg is an inst match generator + return ((InstMatchGenerator*)d_mg)->getMatch( t, m, d_quantEngine ); +} + +int Trigger::addTerm( Node t ){ + return d_mg->addTerm( d_f, t, d_quantEngine ); +} + +int Trigger::addInstantiations( InstMatch& baseMatch ){ + int addedLemmas = d_mg->addInstantiations( d_f, baseMatch, d_quantEngine ); + if( addedLemmas>0 ){ + Debug("inst-trigger") << "Added " << addedLemmas << " lemmas, trigger was "; + for( int i=0; i<(int)d_nodes.size(); i++ ){ + Debug("inst-trigger") << d_nodes[i] << " "; + } + Debug("inst-trigger") << std::endl; + } + return addedLemmas; +} + +Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool keepAll, int trOption, + bool smartTriggers ){ + 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; + for( int i=0; i<(int)temp.size(); i++ ){ + bool foundVar = false; + computeVarContains( temp[i] ); + for( int j=0; j<(int)d_var_contains[ temp[i] ].size(); j++ ){ + Node v = d_var_contains[ temp[i] ][j]; + if( v.getAttribute(InstConstantAttribute())==f ){ + if( vars.find( v )==vars.end() ){ + vars[ v ] = true; + foundVar = true; + } + } + } + if( foundVar ){ + trNodes.push_back( temp[i] ); + for( int j=0; j<(int)d_var_contains[ temp[i] ].size(); j++ ){ + Node v = d_var_contains[ temp[i] ][j]; + patterns[ v ].push_back( temp[i] ); + } + } + } + //now, minimalize the trigger + for( int i=0; i<(int)trNodes.size(); i++ ){ + bool keepPattern = false; + Node n = trNodes[i]; + for( int j=0; j<(int)d_var_contains[ n ].size(); j++ ){ + Node v = d_var_contains[ n ][j]; + if( patterns[v].size()==1 ){ + keepPattern = true; + break; + } + } + if( !keepPattern ){ + //remove from pattern vector + for( int j=0; j<(int)d_var_contains[ n ].size(); j++ ){ + Node v = d_var_contains[ n ][j]; + for( int k=0; k<(int)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--; + } + } + }else{ + trNodes.insert( trNodes.begin(), nodes.begin(), nodes.end() ); + } + + //check for duplicate? + if( trOption==TR_MAKE_NEW ){ + //static int trNew = 0; + //static int trOld = 0; + //Trigger* t = d_tr_trie.getTrigger( trNodes ); + //if( t ){ + // trOld++; + //}else{ + // trNew++; + //} + //if( (trNew+trOld)%100==0 ){ + // Notice() << "Trigger new old = " << trNew << " " << trOld << std::endl; + //} + }else{ + Trigger* t = d_tr_trie.getTrigger( trNodes ); + if( t ){ + if( trOption==TR_GET_OLD ){ + //just return old trigger + return t; + }else{ + return NULL; + } + } + } + Trigger* t = new Trigger( qe, f, trNodes, matchOption, smartTriggers ); + d_tr_trie.addTrigger( trNodes, t ); + return t; +} +Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, int matchOption, bool keepAll, int trOption, bool smartTriggers ){ + std::vector< Node > nodes; + nodes.push_back( n ); + return mkTrigger( qe, f, nodes, matchOption, keepAll, trOption, smartTriggers ); +} + +bool Trigger::isUsableTrigger( std::vector< Node >& nodes, Node f ){ + for( int i=0; i<(int)nodes.size(); i++ ){ + if( !isUsableTrigger( nodes[i], f ) ){ + return false; + } + } + return true; +} + +bool Trigger::isUsable( Node n, Node f ){ + if( n.getAttribute(InstConstantAttribute())==f ){ + if( !isAtomicTrigger( n ) && n.getKind()!=INST_CONSTANT ){ + std::map< Node, Node > coeffs; + return getPatternArithmetic( f, n, coeffs ); + }else{ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( !isUsable( n[i], f ) ){ + return false; + } + } + return true; + } + }else{ + return true; + } +} + +bool Trigger::isUsableTrigger( Node n, Node f ){ + //return n.getAttribute(InstConstantAttribute())==f && n.getKind()==APPLY_UF; + return n.getAttribute(InstConstantAttribute())==f && isAtomicTrigger( n ) && isUsable( n, f ); +} + +bool Trigger::isAtomicTrigger( Node n ){ + return n.getKind()==APPLY_UF || n.getKind()==SELECT || n.getKind()==STORE || + n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR || n.getKind()==APPLY_TESTER; +} +bool Trigger::isSimpleTrigger( Node n ){ + if( isAtomicTrigger( n ) ){ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( n[i].getKind()!=INST_CONSTANT && n[i].hasAttribute(InstConstantAttribute()) ){ + return false; + } + } + return true; + }else{ + return false; + } +} + +/** filter all nodes that have instances */ +void Trigger::filterInstances( std::vector< Node >& nodes ){ + std::vector< bool > active; + active.resize( nodes.size(), true ); + for( int i=0; i<(int)nodes.size(); i++ ){ + for( int j=i+1; j<(int)nodes.size(); j++ ){ + if( active[i] && active[j] ){ + int result = isInstanceOf( nodes[i], nodes[j] ); + if( result==1 ){ + active[j] = false; + }else if( result==-1 ){ + active[i] = false; + } + } + } + } + std::vector< Node > temp; + for( int i=0; i<(int)nodes.size(); i++ ){ + if( active[i] ){ + temp.push_back( nodes[i] ); + } + } + nodes.clear(); + nodes.insert( nodes.begin(), temp.begin(), temp.end() ); +} + + +bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt ){ + if( patMap.find( n )==patMap.end() ){ + patMap[ n ] = false; + if( tstrt==TS_MIN_TRIGGER ){ + if( n.getKind()==FORALL ){ +#ifdef NESTED_PATTERN_SELECTION + //return collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt ); + return collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt ); +#else + return false; +#endif + }else{ + bool retVal = false; + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){ + retVal = true; + } + } + if( retVal ){ + return true; + }else if( isUsableTrigger( n, f ) ){ + patMap[ n ] = true; + return true; + }else{ + return false; + } + } + }else{ + bool retVal = false; + if( isUsableTrigger( n, f ) ){ + patMap[ n ] = true; + if( tstrt==TS_MAX_TRIGGER ){ + return true; + }else{ + retVal = true; + } + } + if( n.getKind()==FORALL ){ +#ifdef NESTED_PATTERN_SELECTION + //if( collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt ) ){ + // retVal = true; + //} + if( collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt ) ){ + retVal = true; + } +#endif + }else{ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){ + retVal = true; + } + } + } + return retVal; + } + }else{ + return patMap[ n ]; + } +} + +void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst ){ + std::map< Node, bool > patMap; + if( filterInst ){ + //immediately do not consider any term t for which another term is an instance of t + std::vector< Node > patTerms2; + collectPatTerms( qe, f, n, patTerms2, TS_ALL, false ); + std::vector< Node > temp; + temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() ); + filterInstances( temp ); + if( temp.size()!=patTerms2.size() ){ + Debug("trigger-filter-instance") << "Filtered an instance: " << std::endl; + Debug("trigger-filter-instance") << "Old: "; + for( int i=0; i<(int)patTerms2.size(); i++ ){ + Debug("trigger-filter-instance") << patTerms2[i] << " "; + } + Debug("trigger-filter-instance") << std::endl << "New: "; + for( int i=0; i<(int)temp.size(); i++ ){ + Debug("trigger-filter-instance") << temp[i] << " "; + } + Debug("trigger-filter-instance") << std::endl; + } + if( tstrt==TS_ALL ){ + patTerms.insert( patTerms.begin(), temp.begin(), temp.end() ); + return; + }else{ + //do not consider terms that have instances + for( int i=0; i<(int)patTerms2.size(); i++ ){ + if( std::find( temp.begin(), temp.end(), patTerms2[i] )==temp.end() ){ + patMap[ patTerms2[i] ] = false; + } + } + } + } + collectPatTerms2( qe, f, n, patMap, tstrt ); + for( std::map< Node, bool >::iterator it = patMap.begin(); it != patMap.end(); ++it ){ + if( it->second ){ + patTerms.push_back( it->first ); + } + } +} + +/** is n1 an instance of n2 or vice versa? */ +int Trigger::isInstanceOf( Node n1, Node n2 ){ + if( n1==n2 ){ + return 1; + }else if( n1.getKind()==n2.getKind() ){ + if( n1.getKind()==APPLY_UF ){ + if( n1.getOperator()==n2.getOperator() ){ + int result = 0; + for( int i=0; i<(int)n1.getNumChildren(); i++ ){ + if( n1[i]!=n2[i] ){ + int cResult = isInstanceOf( n1[i], n2[i] ); + if( cResult==0 ){ + return 0; + }else if( cResult!=result ){ + if( result!=0 ){ + return 0; + }else{ + result = cResult; + } + } + } + } + return result; + } + } + return 0; + }else if( n2.getKind()==INST_CONSTANT ){ + computeVarContains( n1 ); + //if( std::find( d_var_contains[ n1 ].begin(), d_var_contains[ n1 ].end(), n2 )!=d_var_contains[ n1 ].end() ){ + // return 1; + //} + if( d_var_contains[ n1 ].size()==1 && d_var_contains[ n1 ][ 0 ]==n2 ){ + return 1; + } + }else if( n1.getKind()==INST_CONSTANT ){ + computeVarContains( n2 ); + //if( std::find( d_var_contains[ n2 ].begin(), d_var_contains[ n2 ].end(), n1 )!=d_var_contains[ n2 ].end() ){ + // return -1; + //} + if( d_var_contains[ n2 ].size()==1 && d_var_contains[ n2 ][ 0 ]==n1 ){ + return 1; + } + } + return 0; +} + +bool Trigger::isVariableSubsume( Node n1, Node n2 ){ + if( n1==n2 ){ + return true; + }else{ + //Notice() << "is variable subsume ? " << n1 << " " << n2 << std::endl; + computeVarContains( n1 ); + computeVarContains( n2 ); + for( int i=0; i<(int)d_var_contains[n2].size(); i++ ){ + if( std::find( d_var_contains[n1].begin(), d_var_contains[n1].end(), d_var_contains[n2][i] )==d_var_contains[n1].end() ){ + //Notice() << "no" << std::endl; + return false; + } + } + //Notice() << "yes" << std::endl; + return true; + } +} + +void Trigger::getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains ){ + for( int i=0; i<(int)pats.size(); i++ ){ + computeVarContains( pats[i] ); + varContains[ pats[i] ].clear(); + for( int j=0; j<(int)d_var_contains[pats[i]].size(); j++ ){ + if( d_var_contains[pats[i]][j].getAttribute(InstConstantAttribute())==f ){ + varContains[ pats[i] ].push_back( d_var_contains[pats[i]][j] ); + } + } + } +} + +void Trigger::getVarContainsNode( Node f, Node n, std::vector< Node >& varContains ){ + computeVarContains( n ); + for( int j=0; j<(int)d_var_contains[n].size(); j++ ){ + if( d_var_contains[n][j].getAttribute(InstConstantAttribute())==f ){ + varContains.push_back( d_var_contains[n][j] ); + } + } +} + +bool Trigger::getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coeffs ){ + if( n.getKind()==PLUS ){ + Assert( coeffs.empty() ); + NodeBuilder<> t(kind::PLUS); + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( n[i].hasAttribute(InstConstantAttribute()) ){ + if( n[i].getKind()==INST_CONSTANT ){ + if( n[i].getAttribute(InstConstantAttribute())==f ){ + coeffs[ n[i] ] = Node::null(); + }else{ + coeffs.clear(); + return false; + } + }else if( !getPatternArithmetic( f, n[i], coeffs ) ){ + coeffs.clear(); + return false; + } + }else{ + t << n[i]; + } + } + if( t.getNumChildren()==0 ){ + coeffs[ Node::null() ] = NodeManager::currentNM()->mkConst( Rational(0) ); + }else if( t.getNumChildren()==1 ){ + coeffs[ Node::null() ] = t.getChild( 0 ); + }else{ + coeffs[ Node::null() ] = t; + } + return true; + }else if( n.getKind()==MULT ){ + if( n[0].getKind()==INST_CONSTANT && n[0].getAttribute(InstConstantAttribute())==f ){ + Assert( !n[1].hasAttribute(InstConstantAttribute()) ); + coeffs[ n[0] ] = n[1]; + return true; + }else if( n[1].getKind()==INST_CONSTANT && n[1].getAttribute(InstConstantAttribute())==f ){ + Assert( !n[0].hasAttribute(InstConstantAttribute()) ); + coeffs[ n[1] ] = n[0]; + return true; + } + } + return false; +} diff --git a/src/theory/quantifiers/trigger.h b/src/theory/quantifiers/trigger.h new file mode 100644 index 000000000..207cef5d9 --- /dev/null +++ b/src/theory/quantifiers/trigger.h @@ -0,0 +1,171 @@ +/********************* */ +/*! \file trigger.h + ** \verbatim + ** Original author: ajreynol + ** Major contributors: none + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief trigger class + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__QUANTIFIERS__TRIGGER_H +#define __CVC4__THEORY__QUANTIFIERS__TRIGGER_H + +#include "theory/quantifiers/inst_match.h" + +namespace CVC4 { +namespace theory { +namespace inst { + +//a collect of nodes representing a trigger +class Trigger { +private: + /** computation of variable contains */ + static std::map< TNode, std::vector< TNode > > d_var_contains; + static void computeVarContains( Node n ); + static void computeVarContains2( Node n, Node parent ); +private: + /** the quantifiers engine */ + QuantifiersEngine* d_quantEngine; + /** the quantifier this trigger is for */ + Node d_f; + /** match generators */ + IMGenerator* d_mg; +private: + /** a trie of triggers */ + class TrTrie { + private: + Trigger* getTrigger2( std::vector< Node >& nodes ); + void addTrigger2( std::vector< Node >& nodes, Trigger* t ); + public: + TrTrie() : d_tr( NULL ){} + Trigger* d_tr; + std::map< TNode, TrTrie* > d_children; + Trigger* getTrigger( std::vector< Node >& nodes ){ + std::vector< Node > temp; + temp.insert( temp.begin(), nodes.begin(), nodes.end() ); + std::sort( temp.begin(), temp.end() ); + return getTrigger2( temp ); + } + void addTrigger( std::vector< Node >& nodes, Trigger* t ){ + std::vector< Node > temp; + temp.insert( temp.begin(), nodes.begin(), nodes.end() ); + std::sort( temp.begin(), temp.end() ); + return addTrigger2( temp, t ); + } + };/* class Trigger::TrTrie */ + /** all triggers will be stored in this trie */ + static TrTrie d_tr_trie; +private: + /** trigger constructor */ + Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes, int matchOption = 0, bool smartTriggers = false ); +public: + ~Trigger(){} +public: + std::vector< Node > d_nodes; +public: + void debugPrint( const char* c ); + IMGenerator* getGenerator() { return d_mg; } +public: + /** reset instantiation round (call this whenever equivalence classes have changed) */ + void resetInstantiationRound(); + /** reset, eqc is the equivalence class to search in (search in any if eqc=null) */ + void reset( Node eqc ); + /** get next match. must call reset( eqc ) once before this function. */ + bool getNextMatch( InstMatch& m ); + /** get the match against ground term or formula t. + the trigger and t should have the same shape. + Currently the trigger should not be a multi-trigger. + */ + bool getMatch( Node t, InstMatch& m); + /** add ground term t, called when t is added to the TermDb */ + int addTerm( Node t ); + /** return true if whatever Node is subsituted for the variables the + given Node can't match the pattern */ + bool nonunifiable( TNode t, const std::vector & vars){ + return d_mg->nonunifiable(t,vars); + } + /** return whether this is a multi-trigger */ + bool isMultiTrigger() { return d_nodes.size()>1; } +public: + /** add all available instantiations exhaustively, in any equivalence class + if limitInst>0, limitInst is the max # of instantiations to try */ + int addInstantiations( InstMatch& baseMatch ); + /** mkTrigger method + 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) + */ + enum{ + TR_MAKE_NEW, //make new trigger even if it already may exist + 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, + bool smartTriggers = false ); + static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, Node n, + int matchOption = 0, bool keepAll = true, int trOption = TR_MAKE_NEW, + bool smartTriggers = false ); +private: + /** is subterm of trigger usable */ + static bool isUsable( Node n, Node f ); + /** collect all APPLY_UF pattern terms for f in n */ + static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt ); +public: + //different strategies for choosing trigger terms + enum { + TS_MAX_TRIGGER = 0, + TS_MIN_TRIGGER, + TS_ALL, + }; + static void collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst = false ); +public: + /** is usable trigger */ + static bool isUsableTrigger( std::vector< Node >& nodes, Node f ); + static bool isUsableTrigger( Node n, Node f ); + static bool isAtomicTrigger( Node n ); + static bool isSimpleTrigger( Node n ); + /** filter all nodes that have instances */ + static void filterInstances( std::vector< Node >& nodes ); + /** -1: n1 is an instance of n2, 1: n1 is an instance of n2 */ + static int isInstanceOf( Node n1, Node n2 ); + /** variables subsume, return true if n1 contains all free variables in n2 */ + static bool isVariableSubsume( Node n1, Node n2 ); + /** get var contains */ + static void getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains ); + static void getVarContainsNode( Node f, Node n, std::vector< Node >& varContains ); + /** get pattern arithmetic */ + static bool getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coeffs ); + + inline void toStream(std::ostream& out) const { + out << "TRIGGER( "; + for( int i=0; i<(int)d_nodes.size(); i++ ){ + if( i>0 ){ out << ", "; } + out << d_nodes[i]; + } + out << " )"; + } +}; + +inline std::ostream& operator<<(std::ostream& out, const Trigger & tr) { + tr.toStream(out); + return out; +} + +}/* CVC4::theory::inst namespace */ +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ + +#endif /* __CVC4__THEORY__QUANTIFIERS__TRIGGER_H */ diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp index 4d94d8d83..df08312b1 100644 --- a/src/theory/quantifiers_engine.cpp +++ b/src/theory/quantifiers_engine.cpp @@ -27,7 +27,7 @@ #include "theory/quantifiers/instantiation_engine.h" #include "theory/quantifiers/first_order_model.h" #include "theory/quantifiers/term_database.h" -#include "theory/rr_candidate_generator.h" +#include "theory/rewriterules/rr_candidate_generator.h" using namespace std; using namespace CVC4; @@ -793,4 +793,4 @@ rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClass(TypeNode t) { // if(eq == NULL) return getInstantiator(id)->getRRCanGenClass(); // else return eq; return getRRCanGenClass(); -} \ No newline at end of file +} diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h index 2ae620e3d..5afc34bf6 100644 --- a/src/theory/quantifiers_engine.h +++ b/src/theory/quantifiers_engine.h @@ -21,8 +21,8 @@ #include "theory/theory.h" #include "util/hash.h" -#include "theory/inst_match.h" -#include "theory/rr_inst_match.h" +#include "theory/quantifiers/inst_match.h" +#include "theory/rewriterules/rr_inst_match.h" #include "util/stats.h" diff --git a/src/theory/rewriterules/Makefile.am b/src/theory/rewriterules/Makefile.am index 46cffda11..a9eddb812 100644 --- a/src/theory/rewriterules/Makefile.am +++ b/src/theory/rewriterules/Makefile.am @@ -13,7 +13,14 @@ librewriterules_la_SOURCES = \ theory_rewriterules_rewriter.h \ theory_rewriterules_type_rules.h \ theory_rewriterules_preprocess.h \ - theory_rewriterules_params.h + theory_rewriterules_params.h \ + rr_inst_match.h \ + rr_inst_match_impl.h \ + rr_inst_match.cpp \ + rr_trigger.h \ + rr_trigger.cpp \ + rr_candidate_generator.h \ + rr_candidate_generator.cpp EXTRA_DIST = \ kinds diff --git a/src/theory/rewriterules/rr_candidate_generator.cpp b/src/theory/rewriterules/rr_candidate_generator.cpp new file mode 100644 index 000000000..f01497bda --- /dev/null +++ b/src/theory/rewriterules/rr_candidate_generator.cpp @@ -0,0 +1,125 @@ +/********************* */ +/*! \file rr_candidate_generator.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: bobot + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of rr candidate generator class + **/ + +#include "theory/rewriterules/rr_candidate_generator.h" +#include "theory/theory_engine.h" +#include "theory/uf/theory_uf.h" +#include "theory/quantifiers/term_database.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::rrinst; + +GenericCandidateGeneratorClasses::GenericCandidateGeneratorClasses(QuantifiersEngine * qe){ + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + if(qe->getInstantiator(i) != NULL) + d_can_gen[i] = qe->getInstantiator(i)->getRRCanGenClasses(); + else d_can_gen[i] = NULL; + } +} + +GenericCandidateGeneratorClasses::~GenericCandidateGeneratorClasses(){ + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + delete(d_can_gen[i]); + } +} + +void GenericCandidateGeneratorClasses::resetInstantiationRound(){ + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + if(d_can_gen[i] != NULL) d_can_gen[i]->resetInstantiationRound(); + } + d_can_gen_id=THEORY_FIRST; +} + +void GenericCandidateGeneratorClasses::reset(TNode eqc){ + Assert(eqc.isNull()); + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + if(d_can_gen[i] != NULL) d_can_gen[i]->reset(eqc); + } + d_can_gen_id=THEORY_FIRST; + lookForNextTheory(); +} + +TNode GenericCandidateGeneratorClasses::getNextCandidate(){ + Assert(THEORY_FIRST <= d_can_gen_id && d_can_gen_id <= THEORY_LAST); + /** No more */ + if(d_can_gen_id == THEORY_LAST) return TNode::null(); + /** Try with this theory */ + TNode cand = d_can_gen[d_can_gen_id]->getNextCandidate(); + if( !cand.isNull() ) return cand; + lookForNextTheory(); + return getNextCandidate(); +} + +void GenericCandidateGeneratorClasses::lookForNextTheory(){ + do{ /* look for the next available generator */ + ++d_can_gen_id; + } while( d_can_gen_id < THEORY_LAST && d_can_gen[d_can_gen_id] == NULL); +} + +GenericCandidateGeneratorClass::GenericCandidateGeneratorClass(QuantifiersEngine * qe): d_qe(qe) { + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + if(d_qe->getInstantiator(i) != NULL) + d_can_gen[i] = d_qe->getInstantiator(i)->getRRCanGenClass(); + else d_can_gen[i] = NULL; + } +} + +GenericCandidateGeneratorClass::~GenericCandidateGeneratorClass(){ + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + delete(d_can_gen[i]); + } +} + +void GenericCandidateGeneratorClass::resetInstantiationRound(){ + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + if(d_can_gen[i] != NULL) d_can_gen[i]->resetInstantiationRound(); + } + d_can_gen_id=THEORY_FIRST; +} + +void GenericCandidateGeneratorClass::reset(TNode eqc){ + for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ + if(d_can_gen[i] != NULL) d_can_gen[i]->reset(eqc); + } + d_can_gen_id=THEORY_FIRST; + d_node = eqc; + lookForNextTheory(); +} + +TNode GenericCandidateGeneratorClass::getNextCandidate(){ + Assert(THEORY_FIRST <= d_can_gen_id && d_can_gen_id <= THEORY_LAST); + /** No more */ + if(d_can_gen_id == THEORY_LAST) return TNode::null(); + /** Try with this theory */ + TNode cand = d_can_gen[d_can_gen_id]->getNextCandidate(); + if( !cand.isNull() ) return cand; + lookForNextTheory(); + return getNextCandidate(); +} + +void GenericCandidateGeneratorClass::lookForNextTheory(){ + do{ /* look for the next available generator, where the element is */ + ++d_can_gen_id; + } while( + d_can_gen_id < THEORY_LAST && + (d_can_gen[d_can_gen_id] == NULL || + !d_qe->getInstantiator( d_can_gen_id )->hasTerm( d_node )) + ); +} diff --git a/src/theory/rewriterules/rr_candidate_generator.h b/src/theory/rewriterules/rr_candidate_generator.h new file mode 100644 index 000000000..560504fba --- /dev/null +++ b/src/theory/rewriterules/rr_candidate_generator.h @@ -0,0 +1,209 @@ +/********************* */ +/*! \file rr_candidate_generator.h + ** \verbatim + ** Original author: ajreynol + ** Major contributors: bobot + ** Minor contributors (to current version): mdeters + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief rr candidate generator + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__REWRITERULES__RR_CANDIDATE_GENERATOR_H +#define __CVC4__THEORY__REWRITERULES__RR_CANDIDATE_GENERATOR_H + +#include "theory/quantifiers_engine.h" +#include "theory/quantifiers/term_database.h" +#include "theory/rewriterules/rr_inst_match.h" + +using namespace CVC4::theory::quantifiers; + +namespace CVC4 { +namespace theory { +namespace eq { + +namespace rrinst{ +typedef CVC4::theory::rrinst::CandidateGenerator CandidateGenerator; + +//New CandidateGenerator. They have a simpler semantic than the old one + +// Just iterate amoung the equivalence classes +// node::Null() must be given to reset +class CandidateGeneratorTheoryEeClasses : public CandidateGenerator{ +private: + //the equality classes iterator + eq::EqClassesIterator d_eq; + //equalityengine pointer + EqualityEngine* d_ee; +public: + CandidateGeneratorTheoryEeClasses( EqualityEngine * ee): d_ee( ee ){} + ~CandidateGeneratorTheoryEeClasses(){} + void resetInstantiationRound(){}; + void reset( TNode eqc ){ + Assert(eqc.isNull()); + d_eq = eq::EqClassesIterator( d_ee ); + }; //* the argument is not used + TNode getNextCandidate(){ + if( !d_eq.isFinished() ) return (*(d_eq++)); + else return Node::null(); + }; +}; + +// Just iterate amoung the equivalence class of the given node +// node::Null() *can't* be given to reset +class CandidateGeneratorTheoryEeClass : public CandidateGenerator{ +private: + //instantiator pointer + EqualityEngine* d_ee; + //the equality class iterator + eq::EqClassIterator d_eqc; + /* For the case where the given term doesn't exists in uf */ + Node d_retNode; +public: + CandidateGeneratorTheoryEeClass( EqualityEngine* ee): d_ee( ee ){} + ~CandidateGeneratorTheoryEeClass(){} + void resetInstantiationRound(){}; + void reset( TNode eqc ){ + Assert(!eqc.isNull()); + if( d_ee->hasTerm( eqc ) ){ + /* eqc is in uf */ + eqc = d_ee->getRepresentative( eqc ); + d_eqc = eq::EqClassIterator( eqc, d_ee ); + d_retNode = Node::null(); + }else{ + /* If eqc if not a term known by uf, it is the only one in its + equivalence class. So we will return only it */ + d_retNode = eqc; + d_eqc = eq::EqClassIterator(); + } + }; //* the argument is not used + TNode getNextCandidate(){ + if(d_retNode.isNull()){ + if( !d_eqc.isFinished() ) return (*(d_eqc++)); + else return Node::null(); + }else{ + /* the case where eqc not in uf */ + Node ret = d_retNode; + d_retNode = Node::null(); /* d_eqc.isFinished() must be true */ + return ret; + } + }; +}; + + +} /* namespace rrinst */ +} /* namespace eq */ + +namespace uf{ +namespace rrinst { + +typedef CVC4::theory::rrinst::CandidateGenerator CandidateGenerator; + +class CandidateGeneratorTheoryUfOp : public CandidateGenerator{ +private: + Node d_op; + //instantiator pointer + TermDb* d_tdb; + // Since new term can appears we restrict ourself to the one that + // exists at resetInstantiationRound + size_t d_term_iter_limit; + size_t d_term_iter; +public: + CandidateGeneratorTheoryUfOp(Node op, TermDb* tdb): d_op(op), d_tdb( tdb ){} + ~CandidateGeneratorTheoryUfOp(){} + void resetInstantiationRound(){ + d_term_iter_limit = d_tdb->d_op_map[d_op].size(); + }; + void reset( TNode eqc ){ + Assert(eqc.isNull()); + d_term_iter = 0; + }; //* the argument is not used + TNode getNextCandidate(){ + if( d_term_iterd_op_map[d_op][d_term_iter]; + ++d_term_iter; + return n; + } else return Node::null(); + }; +}; + +class CandidateGeneratorTheoryUfType : public CandidateGenerator{ +private: + TypeNode d_type; + //instantiator pointer + TermDb* d_tdb; + // Since new term can appears we restrict ourself to the one that + // exists at resetInstantiationRound + size_t d_term_iter_limit; + size_t d_term_iter; +public: + CandidateGeneratorTheoryUfType(TypeNode type, TermDb* tdb): d_type(type), d_tdb( tdb ){} + ~CandidateGeneratorTheoryUfType(){} + void resetInstantiationRound(){ + d_term_iter_limit = d_tdb->d_type_map[d_type].size(); + }; + void reset( TNode eqc ){ + Assert(eqc.isNull()); + d_term_iter = 0; + }; //* the argument is not used + TNode getNextCandidate(){ + if( d_term_iterd_type_map[d_type][d_term_iter]; + ++d_term_iter; + return n; + } else return Node::null(); + }; +}; + +} /* namespace rrinst */ +} /* namespace uf */ + +class GenericCandidateGeneratorClasses: public rrinst::CandidateGenerator{ + + /** The candidate generators */ + rrinst::CandidateGenerator* d_can_gen[theory::THEORY_LAST]; + /** The current theory which candidategenerator is used */ + TheoryId d_can_gen_id; + +public: + GenericCandidateGeneratorClasses(QuantifiersEngine * qe); + ~GenericCandidateGeneratorClasses(); + + void resetInstantiationRound(); + void reset(TNode eqc); + TNode getNextCandidate(); + void lookForNextTheory(); +}; + +class GenericCandidateGeneratorClass: public rrinst::CandidateGenerator{ + + /** The candidate generators */ + rrinst::CandidateGenerator* d_can_gen[theory::THEORY_LAST]; + /** The current theory which candidategenerator is used */ + TheoryId d_can_gen_id; + /** current node to look for equivalence class */ + Node d_node; + /** QuantifierEngine */ + QuantifiersEngine* d_qe; + +public: + GenericCandidateGeneratorClass(QuantifiersEngine * qe); + ~GenericCandidateGeneratorClass(); + void resetInstantiationRound(); + + void reset(TNode eqc); + TNode getNextCandidate(); + void lookForNextTheory(); +}; + +}/* CVC4::theory namespace */ +}/* CVC4 namespace */ + +#endif /* __CVC4__THEORY__REWRITERULES__RR_CANDIDATE_GENERATOR_H */ diff --git a/src/theory/rewriterules/rr_inst_match.cpp b/src/theory/rewriterules/rr_inst_match.cpp new file mode 100644 index 000000000..25b184fe2 --- /dev/null +++ b/src/theory/rewriterules/rr_inst_match.cpp @@ -0,0 +1,1447 @@ +/********************* */ +/*! \file rr_inst_match.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: bobot + ** Minor contributors (to current version): mdeters + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of inst match class + **/ + +#include "theory/quantifiers/inst_match.h" +#include "theory/theory_engine.h" +#include "theory/quantifiers_engine.h" +#include "theory/uf/theory_uf_instantiator.h" +#include "theory/uf/equality_engine.h" +#include "theory/arrays/theory_arrays.h" +#include "theory/datatypes/theory_datatypes.h" +#include "theory/rewriterules/rr_inst_match.h" +#include "theory/rewriterules/rr_trigger.h" +#include "theory/rewriterules/rr_inst_match_impl.h" +#include "theory/rewriterules/rr_candidate_generator.h" + +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::rrinst; +using namespace CVC4::theory::uf::rrinst; +using namespace CVC4::theory::eq::rrinst; + +namespace CVC4{ +namespace theory{ +namespace rrinst{ + +typedef CVC4::theory::inst::InstMatch InstMatch; +typedef CVC4::theory::inst::CandidateGeneratorQueue CandidateGeneratorQueue; + +template +class InstMatchTrie2Pairs +{ + typename std::vector< std::vector < typename InstMatchTrie2Gen::Tree > > d_data; + InstMatchTrie2Gen d_backtrack; +public: + InstMatchTrie2Pairs(context::Context* c, QuantifiersEngine* q, size_t n): + d_backtrack(c,q) { + // resize to a triangle + // + // | * + // | * * + // | * * * + // | -----> i + d_data.resize(n); + for(size_t i=0; i < n; ++i){ + d_data[i].resize(i+1,typename InstMatchTrie2Gen::Tree(0)); + } + }; + InstMatchTrie2Pairs(const InstMatchTrie2Pairs &) CVC4_UNDEFINED; + const InstMatchTrie2Pairs & operator =(const InstMatchTrie2Pairs & e) CVC4_UNDEFINED; + /** add match m in the trie, + return true if it was never seen */ + inline bool addInstMatch( size_t i, size_t j, InstMatch& m){ + size_t k = std::min(i,j); + size_t l = std::max(i,j); + return d_backtrack.addInstMatch(m,&(d_data[l][k])); + }; + inline bool addInstMatch( size_t i, InstMatch& m){ + return d_backtrack.addInstMatch(m,&(d_data[i][i])); + }; + +}; + + +// Currently the implementation doesn't take into account that +// variable should have the same value given. +// TODO use the d_children way perhaps +// TODO replace by a real dictionnary +// We should create a real substitution? slower more precise +// We don't do that often +bool nonunifiable( TNode t0, TNode pat, const std::vector & vars){ + if(pat.isNull()) return true; + + typedef std::vector > tstack; + tstack stack(1,std::make_pair(t0,pat)); // t * pat + + while(!stack.empty()){ + const std::pair p = stack.back(); stack.pop_back(); + const TNode & t = p.first; + const TNode & pat = p.second; + + // t or pat is a variable currently we consider that can match anything + if( find(vars.begin(),vars.end(),t) != vars.end() ) continue; + if( pat.getKind() == INST_CONSTANT ) continue; + + // t and pat are nonunifiable + if( !Trigger::isAtomicTrigger( t ) || !Trigger::isAtomicTrigger( pat ) ) { + if(t == pat) continue; + else return true; + }; + if( t.getOperator() != pat.getOperator() ) return true; + + //put the children on the stack + for( size_t i=0; i < pat.getNumChildren(); i++ ){ + stack.push_back(std::make_pair(t[i],pat[i])); + }; + } + // The heuristic can't find non-unifiability + return false; +}; + +/** New things */ +class DumbMatcher: public Matcher{ + void resetInstantiationRound( QuantifiersEngine* qe ){}; + bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ){ + return false; + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return false; + } +}; + +class DumbPatMatcher: public PatMatcher{ + void resetInstantiationRound( QuantifiersEngine* qe ){}; + bool reset( InstMatch& m, QuantifiersEngine* qe ){ + return false; + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return false; + } +}; + + +/* The order of the matching is: + reset arg1, nextMatch arg1, reset arg2, nextMatch arg2, ... */ +ApplyMatcher::ApplyMatcher( Node pat, QuantifiersEngine* qe): d_pattern(pat){ + // Assert( pat.hasAttribute(InstConstantAttribute()) ); + + //set-up d_variables, d_constants, d_childrens + for( size_t i=0; i< d_pattern.getNumChildren(); ++i ){ + EqualityQuery* q = qe->getEqualityQuery(d_pattern[i].getType()); + Assert( q != NULL ); + if( d_pattern[i].hasAttribute(InstConstantAttribute()) ){ + if( d_pattern[i].getKind()==INST_CONSTANT ){ + //It's a variable + d_variables.push_back(make_triple((TNode)d_pattern[i],i,q)); + }else{ + //It's neither a constant argument neither a variable + //we create the matcher for the subpattern + d_childrens.push_back(make_triple(mkMatcher((TNode)d_pattern[i], qe),i,q)); + }; + }else{ + // It's a constant + d_constants.push_back(make_triple((TNode)d_pattern[i],i,q)); + } + } +} + +void ApplyMatcher::resetInstantiationRound( QuantifiersEngine* qe ){ + for( size_t i=0; i< d_childrens.size(); i++ ){ + d_childrens[i].first->resetInstantiationRound( qe ); + } +} + +bool ApplyMatcher::reset(TNode t, InstMatch & m, QuantifiersEngine* qe){ + Debug("matching") << "Matching " << t << " against pattern " << d_pattern << " (" + << m.size() << ")" << std::endl; + + //if t is null + Assert( !t.isNull() ); + Assert( !t.hasAttribute(InstConstantAttribute()) ); + Assert( t.getKind()==d_pattern.getKind() ); + Assert( (t.getKind()!=APPLY_UF && t.getKind()!=APPLY_CONSTRUCTOR) + || t.getOperator()==d_pattern.getOperator() ); + + typedef std::vector< triple >::iterator iterator; + for(iterator i = d_constants.begin(), end = d_constants.end(); + i != end; ++i){ + if( !i->third->areEqual( i->first, t[i->second] ) ){ + Debug("matching-fail") << "Match fail arg: " << i->first << " and " << t[i->second] << std::endl; + //setMatchFail( qe, d_pattern[i], t[i] ); + //ground arguments are not equal + return false; + } + } + + d_binded.clear(); + bool set; + for(iterator i = d_variables.begin(), end = d_variables.end(); + i != end; ++i){ + if( !m.setMatch( i->third, i->first, t[i->second], set) ){ + //match is in conflict + Debug("matching-debug") << "Match in conflict " << t[i->second] << " and " + << i->first << " because " + << m.get(i->first) + << std::endl; + Debug("matching-fail") << "Match fail: " << m.get(i->first) << " and " << t[i->second] << std::endl; + //setMatchFail( qe, partial[0].d_map[d_pattern[i]], t[i] ); + m.erase(d_binded.begin(), d_binded.end()); + return false; + }else{ + if(set){ //The variable has just been set + d_binded.push_back(i->first); + } + } + } + + //now, fit children into match + //we will be requesting candidates for matching terms for each child + d_reps.clear(); + for( size_t i=0; i< d_childrens.size(); i++ ){ + Debug("matching-debug") << "Take the representative of " << t[ d_childrens[i].second ] << std::endl; + Assert( d_childrens[i].third->hasTerm(t[ d_childrens[i].second ]) ); + Node rep = d_childrens[i].third->getRepresentative( t[ d_childrens[i].second ] ); + d_reps.push_back( rep ); + } + + if(d_childrens.size() == 0) return true; + else return getNextMatch(m, qe, true); +} + +bool ApplyMatcher::getNextMatch(InstMatch& m, QuantifiersEngine* qe, bool reset){ + Assert(d_childrens.size() > 0); + const size_t max = d_childrens.size() - 1; + size_t index = reset ? 0 : max; + Assert(d_childrens.size() == d_reps.size()); + while(true){ + if(reset ? + d_childrens[index].first->reset( d_reps[index], m, qe ) : + d_childrens[index].first->getNextMatch( m, qe )){ + if(index==max) return true; + ++index; + reset=true; + }else{ + if(index==0){ + m.erase(d_binded.begin(), d_binded.end()); + return false; + } + --index; + reset=false; + }; + } +} + +bool ApplyMatcher::getNextMatch(InstMatch& m, QuantifiersEngine* qe){ + if(d_childrens.size() == 0){ + m.erase(d_binded.begin(), d_binded.end()); + return false; + } else return getNextMatch(m, qe, false); +} + +/** Proxy that call the sub-matcher on the result return by the given candidate generator */ +template +class CandidateGeneratorMatcher: public Matcher{ + /** candidate generator */ + CG d_cg; + /** the sub-matcher */ + M d_m; +public: + CandidateGeneratorMatcher(CG cg, M m): d_cg(cg), d_m(m) + {/* last is Null */}; + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cg.resetInstantiationRound(); + d_m.resetInstantiationRound(qe); + }; + bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ){ + d_cg.reset(n); + return findMatch(m,qe); + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + // The sub-matcher has another match + return d_m.getNextMatch(m, qe) || findMatch(m,qe); + } +private: + bool findMatch( InstMatch& m, QuantifiersEngine* qe ){ + // Otherwise try to find a new candidate that has at least one match + while(true){ + TNode n = d_cg.getNextCandidate();//kept somewhere Term-db + Debug("matching") << "GenCand " << n << " (" << this << ")" << std::endl; + if(n.isNull()) return false; + if(d_m.reset(n,m,qe)) return true; + }; + } +}; + +/** Proxy that call the sub-matcher on the result return by the given candidate generator */ +template +class PatOfMatcher: public PatMatcher{ + M d_m; +public: + inline PatOfMatcher(M m): d_m(m){} + void resetInstantiationRound(QuantifiersEngine* qe){ + d_m.resetInstantiationRound(qe); + } + bool reset(InstMatch& m, QuantifiersEngine* qe){ + return d_m.reset(Node::null(),m,qe); + }; + bool getNextMatch(InstMatch& m, QuantifiersEngine* qe){ + return d_m.getNextMatch(m,qe); + }; +}; + +class ArithMatcher: public Matcher{ +private: + /** for arithmetic matching */ + std::map< Node, Node > d_arith_coeffs; + /** get the match against ground term or formula t. + d_match_mattern and t should have the same shape. + only valid for use where !d_match_pattern.isNull(). + */ + /** the variable that are set by this matcher */ + std::vector< TNode > d_binded; /* TNode because the variables are already in d_arith_coeffs */ + Node d_pattern; //for debugging +public: + ArithMatcher(Node pat, QuantifiersEngine* qe); + void resetInstantiationRound( QuantifiersEngine* qe ){}; + bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ); + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ); +}; + +/** Match just a variable */ +class VarMatcher: public Matcher{ + Node d_var; + bool d_binded; /* True if the reset bind the variable to some value */ + EqualityQuery* d_q; +public: + VarMatcher(Node var, QuantifiersEngine* qe): d_var(var), d_binded(false){ + d_q = qe->getEqualityQuery(var.getType()); + } + void resetInstantiationRound( QuantifiersEngine* qe ){}; + bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ){ + if(!m.setMatch( d_q, d_var, n, d_binded )){ + //match is in conflict + Debug("matching-fail") << "Match fail: " << m.get(d_var) + << " and " << n << std::endl; + return false; + } else return true; + }; + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + //match is in conflict + if (d_binded) m.erase(d_var); + return false; + } +}; + +template +class TestMatcher: public Matcher{ + M d_m; + Test d_test; +public: + inline TestMatcher(M m, Test test): d_m(m), d_test(test){} + inline void resetInstantiationRound(QuantifiersEngine* qe){ + d_m.resetInstantiationRound(qe); + } + inline bool reset(TNode n, InstMatch& m, QuantifiersEngine* qe){ + return d_test(n) && d_m.reset(n, m, qe); + } + inline bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_m.getNextMatch(m, qe); + } +}; + +class LegalOpTest/*: public unary_function*/ { + Node d_op; +public: + inline LegalOpTest(Node op): d_op(op){} + inline bool operator() (TNode n) { + return + CandidateGenerator::isLegalCandidate(n) && + // ( // n.getKind()==SELECT || n.getKind()==STORE || + // n.getKind()==APPLY_UF || n.getKind()==APPLY_CONSTRUCTOR) && + n.hasOperator() && + n.getOperator()==d_op; + }; +}; + +class LegalKindTest/* : public unary_function*/ { + Kind d_kind; +public: + inline LegalKindTest(Kind kind): d_kind(kind){} + inline bool operator() (TNode n) { + return + CandidateGenerator::isLegalCandidate(n) && + n.getKind()==d_kind; + }; +}; + +class LegalTypeTest/* : public unary_function*/ { + TypeNode d_type; +public: + inline LegalTypeTest(TypeNode type): d_type(type){} + inline bool operator() (TNode n) { + return + CandidateGenerator::isLegalCandidate(n) && + n.getType()==d_type; + }; +}; + +class LegalTest/* : public unary_function*/ { +public: + inline bool operator() (TNode n) { + return CandidateGenerator::isLegalCandidate(n); + }; +}; + +size_t numFreeVar(TNode t){ + size_t n = 0; + for( size_t i=0, size =t.getNumChildren(); i < size; ++i ){ + if( t[i].hasAttribute(InstConstantAttribute()) ){ + if( t[i].getKind()==INST_CONSTANT ){ + //variable + ++n; + }else{ + //neither variable nor constant + n += numFreeVar(t[i]); + } + } + } + return n; +} + +class OpMatcher: public Matcher{ + /* The matcher */ + typedef ApplyMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2> AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ + Assert( pat.getKind() == kind::APPLY_UF ); + /** In reverse order of matcher sequence */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good operator */ + AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator())); + /** Iter on the equivalence class of the given term */ + uf::TheoryUF* uf = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )); + eq::EqualityEngine* ee = static_cast(uf->getEqualityEngine()); + CandidateGeneratorTheoryEeClass cdtUfEq(ee); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtUfEq,am2); + return am1; + } + size_t d_num_var; + Node d_pat; +public: + OpMatcher( Node pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)),d_num_var(numFreeVar(pat)), + d_pat(pat) {} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ + // size_t m_size = m.d_map.size(); + // if(m_size == d_num_var){ + // uf::EqualityEngine* ee = (static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )))->getEqualityEngine(); + // std::cout << "!"; + // return ee->areEqual(m.subst(d_pat),t); + // }else{ + // std::cout << m.d_map.size() << std::endl; + return d_cgm.reset(t, m, qe); + // } + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +class DatatypesMatcher: public Matcher{ + /* The matcher */ + typedef ApplyMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2> AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ + Assert( pat.getKind() == kind::APPLY_CONSTRUCTOR, + "For datatypes only constructor are accepted in pattern" ); + /** In reverse order of matcher sequence */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good operator */ + AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator())); + /** Iter on the equivalence class of the given term */ + datatypes::TheoryDatatypes* dt = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_DATATYPES )); + eq::EqualityEngine* ee = static_cast(dt->getEqualityEngine()); + CandidateGeneratorTheoryEeClass cdtDtEq(ee); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtDtEq,am2); + return am1; + } + Node d_pat; +public: + DatatypesMatcher( Node pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)), + d_pat(pat) {} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ + Debug("matching") << "datatypes: " << t << " matches " << d_pat << std::endl; + return d_cgm.reset(t, m, qe); + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +class ArrayMatcher: public Matcher{ + /* The matcher */ + typedef ApplyMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalKindTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2> AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ + Assert( pat.getKind() == kind::SELECT || pat.getKind() == kind::STORE ); + /** In reverse order of matcher sequence */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good operator */ + AuxMatcher2 am2(am3, LegalKindTest(pat.getKind())); + /** Iter on the equivalence class of the given term */ + arrays::TheoryArrays* ar = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_ARRAY )); + eq::EqualityEngine* ee = + static_cast(ar->getEqualityEngine()); + CandidateGeneratorTheoryEeClass cdtUfEq(ee); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtUfEq,am2); + return am1; + } + size_t d_num_var; + Node d_pat; +public: + ArrayMatcher( Node pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)),d_num_var(numFreeVar(pat)), + d_pat(pat) {} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ + // size_t m_size = m.d_map.size(); + // if(m_size == d_num_var){ + // uf::EqualityEngine* ee = (static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )))->getEqualityEngine(); + // std::cout << "!"; + // return ee->areEqual(m.subst(d_pat),t); + // }else{ + // std::cout << m.d_map.size() << std::endl; + return d_cgm.reset(t, m, qe); + // } + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +class AllOpMatcher: public PatMatcher{ + /* The matcher */ + typedef ApplyMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryUfOp, AuxMatcher2> AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ + Assert( pat.hasOperator() ); + /** In reverse order of matcher sequence */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good operator */ + AuxMatcher2 am2(am3,LegalTest()); + /** Iter on the equivalence class of the given term */ + TermDb* tdb = qe->getTermDatabase(); + CandidateGeneratorTheoryUfOp cdtUfEq(pat.getOperator(),tdb); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtUfEq,am2); + return am1; + } + size_t d_num_var; + Node d_pat; +public: + AllOpMatcher( TNode pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)), d_num_var(numFreeVar(pat)), + d_pat(pat) {} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( InstMatch& m, QuantifiersEngine* qe ){ + // std::cout << m.d_map.size() << "/" << d_num_var << std::endl; + return d_cgm.reset(Node::null(), m, qe); + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +template /** true classes | false class */ +class GenericCandidateGeneratorClasses: public CandidateGenerator{ +private: + CandidateGenerator* d_cg; + QuantifiersEngine* d_qe; + +public: + void mkCandidateGenerator(){ + if(classes) + d_cg = d_qe->getRRCanGenClasses(); + else + d_cg = d_qe->getRRCanGenClass(); + } + + GenericCandidateGeneratorClasses(QuantifiersEngine* qe): + d_qe(qe) { + mkCandidateGenerator(); + } + ~GenericCandidateGeneratorClasses(){ + delete(d_cg); + } + const GenericCandidateGeneratorClasses & operator =(const GenericCandidateGeneratorClasses & m){ + mkCandidateGenerator(); + return m; + }; + GenericCandidateGeneratorClasses(const GenericCandidateGeneratorClasses & m): + d_qe(m.d_qe){ + mkCandidateGenerator(); + } + void resetInstantiationRound(){ + d_cg->resetInstantiationRound(); + }; + void reset( TNode eqc ){ + Assert( !classes || eqc.isNull() ); + d_cg->reset(eqc); + }; //* the argument is not used + TNode getNextCandidate(){ + return d_cg->getNextCandidate(); + }; +}; /* MetaCandidateGeneratorClasses */ + + +class GenericMatcher: public Matcher{ + /* The matcher */ + typedef ApplyMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< GenericCandidateGeneratorClasses, AuxMatcher2> AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ + /** In reverse order of matcher sequence */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good operator */ + AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator())); + /** Iter on the equivalence class of the given term */ + GenericCandidateGeneratorClasses cdtG(qe); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtG,am2); + return am1; + } + Node d_pat; +public: + GenericMatcher( Node pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)), + d_pat(pat) {} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.reset(t, m, qe); + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + + +class GenericPatMatcher: public PatMatcher{ + /* The matcher */ + typedef ApplyMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< GenericCandidateGeneratorClasses, AuxMatcher2> AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ + /** In reverse order of matcher sequence */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good operator */ + AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator())); + /** Iter on the equivalence class of the given term */ + GenericCandidateGeneratorClasses cdtG(qe); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtG,am2); + return am1; + } + Node d_pat; +public: + GenericPatMatcher( Node pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)), + d_pat(pat) {} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.reset(Node::null(), m, qe); + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +class MetaCandidateGeneratorClasses: public CandidateGenerator{ +private: + CandidateGenerator* d_cg; + TypeNode d_ty; + TheoryEngine* d_te; + +public: + CandidateGenerator* mkCandidateGenerator(TypeNode ty, TheoryEngine* te){ + Debug("inst-match-gen") << "MetaCandidateGenerator for type: " << ty + << " Theory : " << Theory::theoryOf(ty) << std::endl; + if( Theory::theoryOf(ty) == theory::THEORY_DATATYPES ){ + // datatypes::TheoryDatatypes* dt = static_cast(te->getTheory( theory::THEORY_DATATYPES )); + // return new datatypes::rrinst::CandidateGeneratorTheoryClasses(dt); + Unimplemented("MetaCandidateGeneratorClasses for THEORY_DATATYPES"); + }else if ( Theory::theoryOf(ty) == theory::THEORY_ARRAY ){ + arrays::TheoryArrays* ar = static_cast(te->getTheory( theory::THEORY_ARRAY )); + eq::EqualityEngine* ee = + static_cast(ar->getEqualityEngine()); + return new CandidateGeneratorTheoryEeClasses(ee); + } else { + uf::TheoryUF* uf = static_cast(te->getTheory( theory::THEORY_UF )); + eq::EqualityEngine* ee = + static_cast(uf->getEqualityEngine()); + return new CandidateGeneratorTheoryEeClasses(ee); + } + } + MetaCandidateGeneratorClasses(TypeNode ty, TheoryEngine* te): + d_ty(ty), d_te(te) { + d_cg = mkCandidateGenerator(ty,te); + } + ~MetaCandidateGeneratorClasses(){ + delete(d_cg); + } + const MetaCandidateGeneratorClasses & operator =(const MetaCandidateGeneratorClasses & m){ + d_cg = mkCandidateGenerator(m.d_ty, m.d_te); + return m; + }; + MetaCandidateGeneratorClasses(const MetaCandidateGeneratorClasses & m): + d_ty(m.d_ty), d_te(m.d_te){ + d_cg = mkCandidateGenerator(m.d_ty, m.d_te); + } + void resetInstantiationRound(){ + d_cg->resetInstantiationRound(); + }; + void reset( TNode eqc ){ + d_cg->reset(eqc); + }; //* the argument is not used + TNode getNextCandidate(){ + return d_cg->getNextCandidate(); + }; +}; /* MetaCandidateGeneratorClasses */ + +/** Match just a variable */ +class AllVarMatcher: public PatMatcher{ +private: + /* generator */ + typedef VarMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalTypeTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< MetaCandidateGeneratorClasses, AuxMatcher2 > AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(TNode pat, QuantifiersEngine* qe){ + Assert( pat.getKind()==INST_CONSTANT ); + TypeNode ty = pat.getType(); + Debug("inst-match-gen") << "create AllVarMatcher for type: " << ty << std::endl; + /** In reverse order of matcher sequence */ + /** Distribute it to all the pattern */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good type */ + AuxMatcher2 am2(am3,LegalTypeTest(ty)); + /** Generate one term by eq classes */ + MetaCandidateGeneratorClasses mcdt(ty,qe->getTheoryEngine()); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(mcdt,am2); + return am1; + } +public: + AllVarMatcher( TNode pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)){} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.reset(Node::null(), m, qe); //cdtUfEq doesn't use it's argument for reset + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +/** Match all the pattern with the same term */ +class SplitMatcher: public Matcher{ +private: + const size_t size; + ApplyMatcher d_m; /** Use ApplyMatcher by creating a fake application */ +public: + SplitMatcher(std::vector< Node > pats, QuantifiersEngine* qe): + size(pats.size()), + d_m(NodeManager::currentNM()->mkNode(kind::INST_PATTERN,pats), qe) {} + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_m.resetInstantiationRound(qe); + }; + bool reset( TNode ex, InstMatch& m, QuantifiersEngine* qe ){ + NodeBuilder<> n(kind::INST_PATTERN); + for(size_t i = 0; i < size; ++i) n << ex; + Node nn = n; + return d_m.reset(nn,m,qe); + }; + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return getNextMatch(m, qe); + } +}; + + +/** Match uf term in a fixed equivalence class */ +class UfCstEqMatcher: public PatMatcher{ +private: + /* equivalence class to match */ + Node d_cst; + /* generator */ + OpMatcher d_cgm; +public: + UfCstEqMatcher( Node pat, Node cst, QuantifiersEngine* qe ): + d_cst(cst), + d_cgm(OpMatcher(pat,qe)) {}; + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.reset(d_cst, m, qe); + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +/** Match equalities */ +class UfEqMatcher: public PatMatcher{ +private: + /* generator */ + typedef SplitMatcher AuxMatcher3; + typedef TestMatcher< AuxMatcher3, LegalTypeTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClasses, AuxMatcher2 > AuxMatcher1; + AuxMatcher1 d_cgm; + static inline AuxMatcher1 createCgm(std::vector & pat, QuantifiersEngine* qe){ + Assert( pat.size() > 0); + TypeNode ty = pat[0].getType(); + for(size_t i = 1; i < pat.size(); ++i){ + Assert(pat[i].getType() == ty); + } + /** In reverse order of matcher sequence */ + /** Distribute it to all the pattern */ + AuxMatcher3 am3(pat,qe); + /** Keep only the one that have the good type */ + AuxMatcher2 am2(am3,LegalTypeTest(ty)); + /** Generate one term by eq classes */ + uf::TheoryUF* uf = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )); + eq::EqualityEngine* ee = + static_cast(uf->getEqualityEngine()); + CandidateGeneratorTheoryEeClasses cdtUfEq(ee); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtUfEq,am2); + return am1; + } +public: + UfEqMatcher( std::vector & pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)){} + + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.reset(Node::null(), m, qe); //cdtUfEq doesn't use it's argument for reset + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + + +/** Match dis-equalities */ +class UfDeqMatcher: public PatMatcher{ +private: + /* generator */ + typedef ApplyMatcher AuxMatcher3; + + class EqTest/* : public unary_function*/ { + TypeNode d_type; + public: + inline EqTest(TypeNode type): d_type(type){}; + inline bool operator() (Node n) { + return + CandidateGenerator::isLegalCandidate(n) && + n.getKind() == kind::EQUAL && + n[0].getType()==d_type; + }; + }; + typedef TestMatcher< AuxMatcher3, EqTest > AuxMatcher2; + typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2 > AuxMatcher1; + AuxMatcher1 d_cgm; + Node false_term; + static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ + Assert( pat.getKind() == kind::NOT); + TNode eq = pat[0]; + Assert( eq.getKind() == kind::EQUAL); + TypeNode ty = eq[0].getType(); + /** In reverse order of matcher sequence */ + /** Distribute it to all the pattern */ + AuxMatcher3 am3(eq,qe); + /** Keep only the one that have the good type */ + AuxMatcher2 am2(am3,EqTest(ty)); + /** Will generate all the terms of the eq class of false */ + uf::TheoryUF* uf = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )); + eq::EqualityEngine* ee = + static_cast(uf->getEqualityEngine()); + CandidateGeneratorTheoryEeClass cdtUfEq(ee); + /* Create a matcher from the candidate generator */ + AuxMatcher1 am1(cdtUfEq,am2); + return am1; + } +public: + UfDeqMatcher( Node pat, QuantifiersEngine* qe ): + d_cgm(createCgm(pat, qe)), + false_term((static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )))->getEqualityEngine()-> + getRepresentative(NodeManager::currentNM()->mkConst(false) )){}; + void resetInstantiationRound( QuantifiersEngine* qe ){ + d_cgm.resetInstantiationRound(qe); + }; + bool reset( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.reset(false_term, m, qe); + } + bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + return d_cgm.getNextMatch(m, qe); + } +}; + +Matcher* mkMatcher( Node pat, QuantifiersEngine* qe ){ + Debug("inst-match-gen") << "mkMatcher: Pattern term is " << pat << std::endl; + + // if( pat.getKind() == kind::APPLY_UF){ + // return new OpMatcher(pat, qe); + // } else if( pat.getKind() == kind::APPLY_CONSTRUCTOR ){ + // return new DatatypesMatcher(pat, qe); + // } else if( pat.getKind() == kind::SELECT || pat.getKind() == kind::STORE ){ + // return new ArrayMatcher(pat, qe); + if( pat.getKind() == kind::APPLY_UF || + pat.getKind() == kind::APPLY_CONSTRUCTOR || + pat.getKind() == kind::SELECT || pat.getKind() == kind::STORE ){ + return new GenericMatcher(pat, qe); + } else { /* Arithmetic? */ + /** TODO: something simpler to see if the pattern is a good + arithmetic pattern */ + std::map< Node, Node > d_arith_coeffs; + if( !Trigger::getPatternArithmetic( pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) ){ + Message() << "(?) Unknown matching pattern is " << pat << std::endl; + Unimplemented("pattern not implemented"); + return new DumbMatcher(); + }else{ + Debug("matching-arith") << "Generated arithmetic pattern for " << pat << ": " << std::endl; + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; + } + ArithMatcher am3 (pat, qe); + TestMatcher + am2(am3,LegalTypeTest(pat.getType())); + /* generator */ + uf::TheoryUF* uf = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )); + eq::EqualityEngine* ee = + static_cast (uf->getEqualityEngine()); + CandidateGeneratorTheoryEeClass cdtUfEq(ee); + return new CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, + TestMatcher > (cdtUfEq,am2); + } + } +}; + +PatMatcher* mkPattern( Node pat, QuantifiersEngine* qe ){ + Debug("inst-match-gen") << "Pattern term is " << pat << std::endl; + Assert( pat.hasAttribute(InstConstantAttribute()) ); + + if( pat.getKind()==kind::NOT && pat[0].getKind() == kind::EQUAL){ + /* Difference */ + return new UfDeqMatcher(pat, qe); + } else if (pat.getKind() == kind::EQUAL){ + if( !pat[0].hasAttribute(InstConstantAttribute() )){ + Assert(pat[1].hasAttribute(InstConstantAttribute())); + return new UfCstEqMatcher(pat[1], pat[0], qe); + }else if( !pat[1].hasAttribute(InstConstantAttribute() )){ + Assert(pat[0].hasAttribute(InstConstantAttribute())); + return new UfCstEqMatcher(pat[0], pat[1], qe); + }else{ + std::vector< Node > pats(pat.begin(),pat.end()); + return new UfEqMatcher(pats,qe); + } + } else if( Trigger::isAtomicTrigger( pat ) ){ + return new AllOpMatcher(pat, qe); + // return new GenericPatMatcher(pat, qe); + } else if( pat.getKind()==INST_CONSTANT ){ + // just a variable + return new AllVarMatcher(pat, qe); + } else { /* Arithmetic? */ + /** TODO: something simpler to see if the pattern is a good + arithmetic pattern */ + std::map< Node, Node > d_arith_coeffs; + if( !Trigger::getPatternArithmetic( pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) ){ + Debug("inst-match-gen") << "(?) Unknown matching pattern is " << pat << std::endl; + Message() << "(?) Unknown matching pattern is " << pat << std::endl; + return new DumbPatMatcher(); + }else{ + Debug("matching-arith") << "Generated arithmetic pattern for " << pat << ": " << std::endl; + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; + } + ArithMatcher am3 (pat, qe); + TestMatcher + am2(am3,LegalTest()); + /* generator */ + TermDb* tdb = qe->getTermDatabase(); + CandidateGeneratorTheoryUfType cdtUfEq(pat.getType(),tdb); + typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryUfType, + TestMatcher > AuxMatcher1; + return new PatOfMatcher(AuxMatcher1(cdtUfEq,am2)); + } + } +}; + +ArithMatcher::ArithMatcher(Node pat, QuantifiersEngine* qe): d_pattern(pat){ + + if(Trigger::getPatternArithmetic(pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) ) + { + Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_pattern << std::endl; + Assert(false); + }else{ + Debug("matching-arith") << "Generated arithmetic pattern for " << d_pattern << ": " << std::endl; + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; + } + } + +}; + +bool ArithMatcher::reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ + Debug("matching-arith") << "Matching " << t << " " << d_pattern << std::endl; + d_binded.clear(); + if( !d_arith_coeffs.empty() ){ + NodeBuilder<> tb(kind::PLUS); + Node ic = Node::null(); + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + Debug("matching-arith") << it->first << " -> " << it->second << std::endl; + if( !it->first.isNull() ){ + if( m.find( it->first )==m.end() ){ + //see if we can choose this to set + if( ic.isNull() && ( it->second.isNull() || !it->first.getType().isInteger() ) ){ + ic = it->first; + } + }else{ + Debug("matching-arith") << "already set " << m.get( it->first ) << std::endl; + Node tm = m.get( it->first ); + if( !it->second.isNull() ){ + tm = NodeManager::currentNM()->mkNode( MULT, it->second, tm ); + } + tb << tm; + } + }else{ + tb << it->second; + } + } + if( !ic.isNull() ){ + Node tm; + if( tb.getNumChildren()==0 ){ + tm = t; + }else{ + tm = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb; + tm = NodeManager::currentNM()->mkNode( MINUS, t, tm ); + } + if( !d_arith_coeffs[ ic ].isNull() ){ + Assert( !ic.getType().isInteger() ); + Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst() ); + tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm ); + } + m.set( ic, Rewriter::rewrite( tm )); + d_binded.push_back(ic); + //set the rest to zeros + for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ + if( !it->first.isNull() ){ + if( m.find( it->first )==m.end() ){ + m.set( it->first, NodeManager::currentNM()->mkConst( Rational(0) )); + d_binded.push_back(ic); + } + } + } + Debug("matching-arith") << "Setting " << ic << " to " << tm << std::endl; + return true; + }else{ + m.erase(d_binded.begin(), d_binded.end()); + return false; + } + }else{ + m.erase(d_binded.begin(), d_binded.end()); + return false; + } +}; + +bool ArithMatcher::getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ + m.erase(d_binded.begin(), d_binded.end()); + return false; +}; + + +class MultiPatsMatcher: public PatsMatcher{ +private: + bool d_reset_done; + std::vector< PatMatcher* > d_patterns; + InstMatch d_im; + bool reset( QuantifiersEngine* qe ){ + d_im.clear(); + d_reset_done = true; + + return getNextMatch(qe,true); + }; + + bool getNextMatch(QuantifiersEngine* qe, bool reset){ + const size_t max = d_patterns.size() - 1; + size_t index = reset ? 0 : max; + while(true){ + Debug("matching") << "MultiPatsMatcher::index " << index << "/" + << max << (reset ? " reset_phase" : "") << std::endl; + if(reset ? + d_patterns[index]->reset( d_im, qe ) : + d_patterns[index]->getNextMatch( d_im, qe )){ + if(index==max) return true; + ++index; + reset=true; + }else{ + if(index==0) return false; + --index; + reset=false; + }; + } + } + +public: + MultiPatsMatcher(std::vector< Node > & pats, QuantifiersEngine* qe): + d_reset_done(false){ + Assert(pats.size() > 0); + for( size_t i=0; i< pats.size(); i++ ){ + d_patterns.push_back(mkPattern(pats[i],qe)); + }; + }; + void resetInstantiationRound( QuantifiersEngine* qe ){ + for( size_t i=0; i< d_patterns.size(); i++ ){ + d_patterns[i]->resetInstantiationRound( qe ); + }; + d_reset_done = false; + d_im.clear(); + }; + bool getNextMatch( QuantifiersEngine* qe ){ + Assert(d_patterns.size()>0); + if(d_reset_done) return getNextMatch(qe,false); + else return reset(qe); + } + const InstMatch& getInstMatch(){return d_im;}; + + int addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe); +}; + +enum EffiStep{ + ES_STOP, + ES_GET_MONO_CANDIDATE, + ES_GET_MULTI_CANDIDATE, + ES_RESET1, + ES_RESET2, + ES_NEXT1, + ES_NEXT2, + ES_RESET_OTHER, + ES_NEXT_OTHER, +}; +static inline std::ostream& operator<<(std::ostream& out, const EffiStep& step) { + switch(step){ + case ES_STOP: out << "STOP"; break; + case ES_GET_MONO_CANDIDATE: out << "GET_MONO_CANDIDATE"; break; + case ES_GET_MULTI_CANDIDATE: out << "GET_MULTI_CANDIDATE"; break; + case ES_RESET1: out << "RESET1"; break; + case ES_RESET2: out << "RESET2"; break; + case ES_NEXT1: out << "NEXT1"; break; + case ES_NEXT2: out << "NEXT2"; break; + case ES_RESET_OTHER: out << "RESET_OTHER"; break; + case ES_NEXT_OTHER: out << "NEXT_OTHER"; break; + } + return out; +} + + +int MultiPatsMatcher::addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe){ + //now, try to add instantiation for each match produced + int addedLemmas = 0; + resetInstantiationRound( qe ); + d_im.add( baseMatch ); + while( getNextMatch( qe ) ){ + InstMatch im_copy = getInstMatch(); + //m.makeInternal( d_quantEngine->getEqualityQuery() ); + if( qe->addInstantiation( quant, im_copy ) ){ + addedLemmas++; + } + } + //return number of lemmas added + return addedLemmas; +} + +PatsMatcher* mkPatterns( std::vector< Node > pat, QuantifiersEngine* qe ){ + return new MultiPatsMatcher( pat, qe); +} + +class MultiEfficientPatsMatcher: public PatsMatcher{ +private: + bool d_phase_mono; + bool d_phase_new_term; + std::vector< PatMatcher* > d_patterns; + std::vector< Matcher* > d_direct_patterns; + InstMatch d_im; + uf::EfficientHandler d_eh; + uf::EfficientHandler::MultiCandidate d_mc; + InstMatchTrie2Pairs d_cache; + std::vector d_pats; + // bool indexDone( size_t i){ + // return i == d_c.first.second || + // ( i == d_c.second.second && d_c.second.first.empty()); + // } + + + + static const EffiStep ES_START = ES_GET_MONO_CANDIDATE; + EffiStep d_step; + + //return true if it becomes bigger than d_patterns.size() - 1 + bool incrIndex(size_t & index){ + if(index == d_patterns.size() - 1) return true; + ++index; + if(index == d_mc.first.second + || (!d_phase_mono && index == d_mc.second.second)) + return incrIndex(index); + else return false; + } + + //return true if it becomes smaller than 0 + bool decrIndex(size_t & index){ + if(index == 0) return true; + --index; + if(index == d_mc.first.second + || (!d_phase_mono && index == d_mc.second.second)) + return decrIndex(index); + else return false; + } + + bool resetOther( QuantifiersEngine* qe ){ + return getNextMatchOther(qe,true); + }; + + + bool getNextMatchOther(QuantifiersEngine* qe, bool reset){ + size_t index = reset ? 0 : d_patterns.size(); + if(!reset && decrIndex(index)) return false; + if( reset && + (index == d_mc.first.second + || (!d_phase_mono && index == d_mc.second.second)) + && incrIndex(index)) return true; + while(true){ + Debug("matching") << "MultiEfficientPatsMatcher::index " << index << "/" + << d_patterns.size() - 1 << std::endl; + if(reset ? + d_patterns[index]->reset( d_im, qe ) : + d_patterns[index]->getNextMatch( d_im, qe )){ + if(incrIndex(index)) return true; + reset=true; + }else{ + if(decrIndex(index)) return false; + reset=false; + }; + } + } + + inline EffiStep TestMonoCache(QuantifiersEngine* qe){ + if( //!d_phase_new_term || + d_pats.size() == 1) return ES_RESET_OTHER; + if(d_cache.addInstMatch(d_mc.first.second,d_im)){ + Debug("inst-match::cache") << "Cache miss" << d_im << std::endl; + ++qe->d_statistics.d_mono_candidates_cache_miss; + return ES_RESET_OTHER; + } else { + Debug("inst-match::cache") << "Cache hit" << d_im << std::endl; + ++qe->d_statistics.d_mono_candidates_cache_hit; + return ES_NEXT1; + } + // ++qe->d_statistics.d_mono_candidates_cache_miss; + // return ES_RESET_OTHER; + } + + inline EffiStep TestMultiCache(QuantifiersEngine* qe){ + if(d_cache.addInstMatch(d_mc.first.second,d_mc.second.second,d_im)){ + ++qe->d_statistics.d_multi_candidates_cache_miss; + return ES_RESET_OTHER; + } else { + ++qe->d_statistics.d_multi_candidates_cache_hit; + return ES_NEXT2; + } + } + + +public: + + bool getNextMatch( QuantifiersEngine* qe ){ + Assert( d_step == ES_START || d_step == ES_NEXT_OTHER || d_step == ES_STOP ); + while(true){ + Debug("matching") << "d_step=" << d_step << " " + << "d_im=" << d_im << std::endl; + switch(d_step){ + case ES_GET_MONO_CANDIDATE: + Assert(d_im.empty()); + if(d_phase_new_term ? d_eh.getNextMonoCandidate(d_mc.first) : d_eh.getNextMonoCandidateNewTerm(d_mc.first)){ + if(d_phase_new_term) ++qe->d_statistics.d_num_mono_candidates_new_term; + else ++qe->d_statistics.d_num_mono_candidates; + d_phase_mono = true; + d_step = ES_RESET1; + } else if (!d_phase_new_term){ + d_phase_new_term = true; + d_step = ES_GET_MONO_CANDIDATE; + } else { + d_phase_new_term = false; + d_step = ES_GET_MULTI_CANDIDATE; + } + break; + case ES_GET_MULTI_CANDIDATE: + Assert(d_im.empty()); + if(d_eh.getNextMultiCandidate(d_mc)){ + ++qe->d_statistics.d_num_multi_candidates; + d_phase_mono = false; + d_step = ES_RESET1; + } else d_step = ES_STOP; + break; + case ES_RESET1: + if(d_direct_patterns[d_mc.first.second]->reset(d_mc.first.first,d_im,qe)) + d_step = d_phase_mono ? TestMonoCache(qe) : ES_RESET2; + else d_step = d_phase_mono ? ES_GET_MONO_CANDIDATE : ES_GET_MULTI_CANDIDATE; + break; + case ES_RESET2: + Assert(!d_phase_mono); + if(d_direct_patterns[d_mc.second.second]->reset(d_mc.second.first,d_im,qe)) + d_step = TestMultiCache(qe); + else d_step = ES_NEXT1; + break; + case ES_NEXT1: + if(d_direct_patterns[d_mc.first.second]->getNextMatch(d_im,qe)) + d_step = d_phase_mono ? TestMonoCache(qe) : ES_RESET2; + else d_step = d_phase_mono ? ES_GET_MONO_CANDIDATE : ES_GET_MULTI_CANDIDATE; + break; + case ES_NEXT2: + if(d_direct_patterns[d_mc.second.second]->getNextMatch(d_im,qe)) + d_step = TestMultiCache(qe); + else d_step = ES_NEXT1; + break; + case ES_RESET_OTHER: + if(resetOther(qe)){ + d_step = ES_NEXT_OTHER; + return true; + } else d_step = d_phase_mono ? ES_NEXT1 : ES_NEXT2; + break; + case ES_NEXT_OTHER: + { + if(!getNextMatchOther(qe,false)){ + d_step = d_phase_mono ? ES_NEXT1 : ES_NEXT2; + }else{ + d_step = ES_NEXT_OTHER; + return true; + } + } + break; + case ES_STOP: + Assert(d_im.empty()); + return false; + } + } + } + + MultiEfficientPatsMatcher(std::vector< Node > & pats, QuantifiersEngine* qe): + d_eh(qe->getTheoryEngine()->getSatContext()), + d_cache(qe->getTheoryEngine()->getSatContext(),qe,pats.size()), + d_pats(pats), d_step(ES_START) { + Assert(pats.size() > 0); + for( size_t i=0; i< pats.size(); i++ ){ + d_patterns.push_back(mkPattern(pats[i],qe)); + if(pats[i].getKind()==kind::INST_CONSTANT){ + d_direct_patterns.push_back(new VarMatcher(pats[i],qe)); + } else if( pats[i].getKind() == kind::NOT && pats[i][0].getKind() == kind::EQUAL){ + d_direct_patterns.push_back(new ApplyMatcher(pats[i][0],qe)); + } else { + d_direct_patterns.push_back(new ApplyMatcher(pats[i],qe)); + } + }; + Theory* th_uf = qe->getTheoryEngine()->getTheory( theory::THEORY_UF ); + uf::InstantiatorTheoryUf* ith = (uf::InstantiatorTheoryUf*)th_uf->getInstantiator(); + ith->registerEfficientHandler(d_eh, pats); + }; + void resetInstantiationRound( QuantifiersEngine* qe ){ + Assert(d_step == ES_START || d_step == ES_STOP); + for( size_t i=0; i< d_patterns.size(); i++ ){ + d_patterns[i]->resetInstantiationRound( qe ); + d_direct_patterns[i]->resetInstantiationRound( qe ); + }; + d_step = ES_START; + d_phase_new_term = false; + Assert(d_im.empty()); + }; + + const InstMatch& getInstMatch(){return d_im;}; + + int addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe); +}; + +int MultiEfficientPatsMatcher::addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe){ + //now, try to add instantiation for each match produced + int addedLemmas = 0; + Assert(baseMatch.empty()); + resetInstantiationRound( qe ); + while( getNextMatch( qe ) ){ + InstMatch im_copy = getInstMatch(); + //m.makeInternal( d_quantEngine->getEqualityQuery() ); + if( qe->addInstantiation( quant, im_copy ) ){ + addedLemmas++; + } + } + //return number of lemmas added + return addedLemmas; +}; + +PatsMatcher* mkPatternsEfficient( std::vector< Node > pat, QuantifiersEngine* qe ){ + return new MultiEfficientPatsMatcher( pat, qe); +} + +} /* CVC4::theory::rrinst */ +} /* CVC4::theory */ +} /* CVC4 */ diff --git a/src/theory/rewriterules/rr_inst_match.h b/src/theory/rewriterules/rr_inst_match.h new file mode 100644 index 000000000..d2a246769 --- /dev/null +++ b/src/theory/rewriterules/rr_inst_match.h @@ -0,0 +1,266 @@ +/********************* */ +/*! \file rr_inst_match.h + ** \verbatim + ** Original author: ajreynol + ** Major contributors: bobot + ** Minor contributors (to current version): mdeters + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief inst match class + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__REWRITERULES__RR_INST_MATCH_H +#define __CVC4__THEORY__REWRITERULES__RR_INST_MATCH_H + +#include "theory/theory.h" +#include "util/hash.h" +#include "util/ntuple.h" + +#include +#include +#include + +#include "theory/uf/equality_engine.h" +#include "theory/uf/theory_uf.h" +#include "context/cdlist.h" + +#include "theory/quantifiers/inst_match.h" +#include "expr/node_manager.h" +#include "expr/node_builder.h" + +#include "theory/quantifiers/options.h" +#include "theory/rewriterules/options.h" + +//#define USE_EFFICIENT_E_MATCHING + +namespace CVC4 { +namespace theory { + +namespace rrinst{ + +class CandidateGenerator +{ +public: + CandidateGenerator(){} + virtual ~CandidateGenerator(){}; + + /** Get candidates functions. These set up a context to get all match candidates. + cg->reset( eqc ); + do{ + Node cand = cg->getNextCandidate(); + //....... + }while( !cand.isNull() ); + + eqc is the equivalence class you are searching in + */ + virtual void reset( TNode eqc ) = 0; + virtual TNode getNextCandidate() = 0; + /** call this at the beginning of each instantiation round */ + virtual void resetInstantiationRound() = 0; +public: + /** legal candidate */ + static inline bool isLegalCandidate( TNode n ){ + return !n.getAttribute(NoMatchAttribute()) && + ( !options::cbqi() || !n.hasAttribute(InstConstantAttribute())) && + ( !options::efficientEMatching() || n.hasAttribute(AvailableInTermDb()) ); +} + +}; + + +inline std::ostream& operator<<(std::ostream& out, const InstMatch& m) { + m.toStream(out); + return out; +} + +template class InstMatchTrie2; +template class InstMatchTrie2Pairs; + +template +class InstMatchTrie2Gen +{ + friend class InstMatchTrie2; + friend class InstMatchTrie2Pairs; + +private: + + class Tree { + public: + typedef std::hash_map< Node, Tree *, NodeHashFunction > MLevel; + MLevel e; + const size_t level; //context level of creation + Tree() CVC4_UNDEFINED; + const Tree & operator =(const Tree & t){ + Assert(t.e.empty()); Assert(e.empty()); + Assert(t.level == level); + return t; + } + Tree(size_t l): level(l) {}; + ~Tree(){ + for(typename MLevel::iterator i = e.begin(); i!=e.end(); ++i) + delete(i->second); + }; + }; + + + typedef std::pair Mod; + + class CleanUp{ + public: + inline void operator()(Mod * m){ + typename Tree::MLevel::iterator i = m->first->e.find(m->second); + Assert (i != m->first->e.end()); //should not have been already removed + m->first->e.erase(i); + }; + }; + + EqualityQuery* d_eQ; + CandidateGenerator * d_cG; + + context::Context* d_context; + context::CDList > d_mods; + + + typedef std::map::const_iterator mapIter; + + /** add the substitution given by the iterator*/ + void addSubTree( Tree * root, mapIter current, mapIter end, size_t currLevel); + /** test if it exists match, modulo uf-equations if modEq is true if + * return false the deepest point of divergence is put in [e] and + * [diverge]. + */ + bool existsInstMatch( Tree * root, + mapIter & current, mapIter & end, + Tree * & e, mapIter & diverge) const; + + /** add match m in the trie root + return true if it was never seen */ + bool addInstMatch( InstMatch& m, Tree * root); + +public: + InstMatchTrie2Gen(context::Context* c, QuantifiersEngine* q); + InstMatchTrie2Gen(const InstMatchTrie2Gen &) CVC4_UNDEFINED; + const InstMatchTrie2Gen & operator =(const InstMatchTrie2Gen & e) CVC4_UNDEFINED; +}; + +template +class InstMatchTrie2 +{ + typename InstMatchTrie2Gen::Tree d_data; + InstMatchTrie2Gen d_backtrack; +public: + InstMatchTrie2(context::Context* c, QuantifiersEngine* q): d_data(0), + d_backtrack(c,q) {}; + InstMatchTrie2(const InstMatchTrie2 &) CVC4_UNDEFINED; + const InstMatchTrie2 & operator =(const InstMatchTrie2 & e) CVC4_UNDEFINED; + /** add match m in the trie, + return true if it was never seen */ + inline bool addInstMatch( InstMatch& m){ + return d_backtrack.addInstMatch(m,&d_data); + }; + +};/* class InstMatchTrie2 */ + +class Matcher +{ +public: + /** reset instantiation round (call this whenever equivalence classes have changed) */ + virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0; + /** reset the term to match, return false if there is no such term */ + virtual bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ) = 0; + /** get the next match. If it return false once you shouldn't call + getNextMatch again before doing a reset */ + virtual bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) = 0; + /** If reset, or getNextMatch return false they remove from the + InstMatch the binding that they have previously created */ + + /** virtual Matcher in order to have definned behavior */ + virtual ~Matcher(){}; +}; + + +class ApplyMatcher: public Matcher{ +private: + /** What to check first: constant and variable */ + std::vector< triple< TNode,size_t,EqualityQuery* > > d_constants; + std::vector< triple< TNode,size_t,EqualityQuery* > > d_variables; + /** children generators, only the sub-pattern which are + neither a variable neither a constant appears */ + std::vector< triple< Matcher*, size_t, EqualityQuery* > > d_childrens; + /** the variable that have been set by this matcher (during its own reset) */ + std::vector< TNode > d_binded; /* TNode because the variable are already in d_pattern */ + /** the representant of the argument of the term given by the last reset */ + std::vector< Node > d_reps; +public: + /** The pattern we are producing matches for */ + Node d_pattern; +public: + /** constructors */ + ApplyMatcher( Node pat, QuantifiersEngine* qe); + /** destructor */ + ~ApplyMatcher(){/*TODO delete dandling pointers? */} + /** reset instantiation round (call this whenever equivalence classes have changed) */ + void resetInstantiationRound( QuantifiersEngine* qe ); + /** reset the term to match */ + bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ); + /** get the next match. */ + bool getNextMatch(InstMatch& m, QuantifiersEngine* qe); +private: + bool getNextMatch(InstMatch& m, QuantifiersEngine* qe, bool reset); +}; + + +/* Match literal so you don't choose the equivalence class( */ +class PatMatcher +{ +public: + /** reset instantiation round (call this whenever equivalence classes have changed) */ + virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0; + /** reset the matcher, return false if there is no such term */ + virtual bool reset( InstMatch& m, QuantifiersEngine* qe ) = 0; + /** get the next match. If it return false once you shouldn't call + getNextMatch again before doing a reset */ + virtual bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) = 0; + /** If reset, or getNextMatch return false they remove from the + InstMatch the binding that they have previously created */ +}; + +Matcher* mkMatcher( Node pat, QuantifiersEngine* qe ); +PatMatcher* mkPattern( Node pat, QuantifiersEngine* qe ); + +/* Match literal so you don't choose the equivalence class( */ +class PatsMatcher +{ +public: + /** reset instantiation round (call this whenever equivalence classes have changed) */ + virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0; + /** reset the matcher, return false if there is no such term */ + virtual bool getNextMatch( QuantifiersEngine* qe ) = 0; + virtual const InstMatch& getInstMatch() = 0; + /** Add directly the instantiation to quantifiers engine */ + virtual int addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe) = 0; +}; + +PatsMatcher* mkPatterns( std::vector< Node > pat, QuantifiersEngine* qe ); +PatsMatcher* mkPatternsEfficient( std::vector< Node > pat, QuantifiersEngine* qe ); + +/** return true if whatever Node is subsituted for the variables the + given Node can't match the pattern */ +bool nonunifiable( TNode t, TNode pat, const std::vector & vars); + +class InstMatchGenerator; + +}/* CVC4::theory rrinst */ + +}/* CVC4::theory namespace */ + +}/* CVC4 namespace */ + +#endif /* __CVC4__THEORY__REWRITERULES__RR_INST_MATCH_H */ diff --git a/src/theory/rewriterules/rr_inst_match_impl.h b/src/theory/rewriterules/rr_inst_match_impl.h new file mode 100644 index 000000000..aa6cf81c2 --- /dev/null +++ b/src/theory/rewriterules/rr_inst_match_impl.h @@ -0,0 +1,128 @@ +/********************* */ +/*! \file rr_inst_match_impl.h + ** \verbatim + ** Original author: bobot + ** Major contributors: none + ** Minor contributors (to current version): ajreynol, mdeters + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief inst match class + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__REWRITERULES__RR_INST_MATCH_IMPL_H +#define __CVC4__THEORY__REWRITERULES__RR_INST_MATCH_IMPL_H + +#include "theory/rewriterules/rr_inst_match.h" +#include "theory/theory_engine.h" +#include "theory/quantifiers_engine.h" +#include "theory/rewriterules/rr_candidate_generator.h" +#include "theory/uf/equality_engine.h" + +namespace CVC4 { +namespace theory { +namespace rrinst { + +template +InstMatchTrie2Gen::InstMatchTrie2Gen(context::Context* c, QuantifiersEngine* qe): + d_context(c), d_mods(c) { + d_eQ = qe->getEqualityQuery(); + d_cG = qe->getRRCanGenClass(); +}; + +/** add match m for quantifier f starting at index, take into account equalities q, return true if successful */ +template +void InstMatchTrie2Gen::addSubTree( Tree * root, mapIter current, mapIter end, size_t currLevel ) { + if( current == end ) return; + + Assert(root->e.find(current->second) == root->e.end()); + Tree * root2 = new Tree(currLevel); + root->e.insert(std::make_pair(current->second, root2)); + addSubTree(root2, ++current, end, currLevel ); +} + +/** exists match */ +template +bool InstMatchTrie2Gen::existsInstMatch(InstMatchTrie2Gen::Tree * root, + mapIter & current, mapIter & end, + Tree * & e, mapIter & diverge) const{ + if( current == end ) { + Debug("Trie2") << "Trie2 Bottom " << std::endl; + --current; + return true; + }; //Already their + + if (current->first > diverge->first){ + // this point is the deepest point currently seen map are ordered + e = root; + diverge = current; + }; + + TNode n = current->second; + typename InstMatchTrie2Gen::Tree::MLevel::iterator it = + root->e.find( n ); + if( it!=root->e.end() && + existsInstMatch( (*it).second, ++current, end, e, diverge) ){ + Debug("Trie2") << "Trie2 Directly here " << n << std::endl; + --current; + return true; + } + Assert( it==root->e.end() || e != root ); + + // Even if n is in the trie others of the equivalence class + // can also be in it since the equality can have appeared + // after they have been added + if( modEq && d_eQ->hasTerm( n ) ){ + //check modulo equality if any other instantiation match exists + d_cG->reset( d_eQ->getRepresentative( n ) ); + for(TNode en = d_cG->getNextCandidate() ; !en.isNull() ; + en = d_cG->getNextCandidate() ){ + if( en == n ) continue; // already tested + typename InstMatchTrie2Gen::Tree::MLevel::iterator itc = + root->e.find( en ); + if( itc!=root->e.end() && + existsInstMatch( (*itc).second, ++current, end, e, diverge) ){ + Debug("Trie2") << "Trie2 Indirectly here by equality " << n << " = " << en << std::endl; + --current; + return true; + } + Assert( itc==root->e.end() || e != root ); + } + } + --current; + return false; +} + +template +bool InstMatchTrie2Gen:: +addInstMatch( InstMatch& m, InstMatchTrie2Gen::Tree* e ) { + d_cG->resetInstantiationRound(); + mapIter begin = m.begin(); + mapIter end = m.end(); + mapIter diverge = begin; + if( !existsInstMatch(e, begin, end, e, diverge ) ){ + Assert(!diverge->second.isNull()); + size_t currLevel = d_context->getLevel(); + addSubTree( e, diverge, end, currLevel ); + if(e->level != currLevel) + //If same level that e, will be removed at the same time than e + d_mods.push_back(std::make_pair(e,diverge->second)); + return true; + }else{ + return false; + } +} + +}/* CVC4::theory::rrinst namespace */ + +}/* CVC4::theory namespace */ + +}/* CVC4 namespace */ + +#endif /* __CVC4__THEORY__REWRITERULES__RR_INST_MATCH_IMPL_H */ diff --git a/src/theory/rewriterules/rr_trigger.cpp b/src/theory/rewriterules/rr_trigger.cpp new file mode 100644 index 000000000..78c0e942a --- /dev/null +++ b/src/theory/rewriterules/rr_trigger.cpp @@ -0,0 +1,523 @@ +/********************* */ +/*! \file rr_trigger.cpp + ** \verbatim + ** Original author: ajreynol + ** Major contributors: mdeters + ** Minor contributors (to current version): bobot + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief Implementation of trigger class + **/ + +#include "theory/rewriterules/rr_trigger.h" +#include "theory/theory_engine.h" +#include "theory/quantifiers_engine.h" +#include "theory/uf/theory_uf_instantiator.h" +#include "theory/rewriterules/rr_candidate_generator.h" +#include "theory/uf/equality_engine.h" + +using namespace std; +using namespace CVC4; +using namespace CVC4::kind; +using namespace CVC4::context; +using namespace CVC4::theory; +using namespace CVC4::theory::rrinst; + +//#define NESTED_PATTERN_SELECTION + +Trigger* Trigger::TrTrie::getTrigger2( std::vector< Node >& nodes ){ + if( nodes.empty() ){ + return d_tr; + }else{ + Node n = nodes.back(); + nodes.pop_back(); + if( d_children.find( n )!=d_children.end() ){ + return d_children[n]->getTrigger2( nodes ); + }else{ + return NULL; + } + } +} +void Trigger::TrTrie::addTrigger2( std::vector< Node >& nodes, Trigger* t ){ + if( nodes.empty() ){ + d_tr = t; + }else{ + Node n = nodes.back(); + nodes.pop_back(); + if( d_children.find( n )==d_children.end() ){ + d_children[n] = new TrTrie; + } + d_children[n]->addTrigger2( nodes, t ); + } +} + +/** trigger static members */ +std::map< Node, std::vector< Node > > Trigger::d_var_contains; +int Trigger::trCount = 0; +Trigger::TrTrie Trigger::d_tr_trie; + +/** trigger class constructor */ +Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool smartTriggers ) : +d_quantEngine( qe ), d_f( f ){ + trCount++; + d_nodes.insert( d_nodes.begin(), nodes.begin(), nodes.end() ); + Debug("trigger") << "Trigger for " << f << ": " << d_nodes << std::endl; + if(matchOption == MATCH_GEN_DEFAULT) d_mg = mkPatterns( d_nodes, qe ); + else d_mg = mkPatternsEfficient( d_nodes, qe ); + if( d_nodes.size()==1 ){ + if( isSimpleTrigger( d_nodes[0] ) ){ + ++(qe->d_statistics.d_triggers); + }else{ + ++(qe->d_statistics.d_simple_triggers); + } + }else{ + Debug("multi-trigger") << "Multi-trigger " << (*this) << std::endl; + //std::cout << "Multi-trigger for " << f << " : " << std::endl; + //std::cout << " " << (*this) << std::endl; + ++(qe->d_statistics.d_multi_triggers); + } +} +void Trigger::computeVarContains( Node n ) { + if( d_var_contains.find( n )==d_var_contains.end() ){ + d_var_contains[n].clear(); + computeVarContains2( n, n ); + } +} + +void Trigger::computeVarContains2( Node n, Node parent ){ + if( n.getKind()==INST_CONSTANT ){ + if( std::find( d_var_contains[parent].begin(), d_var_contains[parent].end(), n )==d_var_contains[parent].end() ){ + d_var_contains[parent].push_back( n ); + } + }else{ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + computeVarContains2( n[i], parent ); + } + } +} + +void Trigger::resetInstantiationRound(){ + d_mg->resetInstantiationRound( d_quantEngine ); +} + + +bool Trigger::getNextMatch(){ + bool retVal = d_mg->getNextMatch( d_quantEngine ); + //m.makeInternal( d_quantEngine->getEqualityQuery() ); + return retVal; +} + +// bool Trigger::getMatch( Node t, InstMatch& m ){ +// //FIXME: this assumes d_mg is an inst match generator +// return ((InstMatchGenerator*)d_mg)->getMatch( t, m, d_quantEngine ); +// } + + +int Trigger::addInstantiations( InstMatch& baseMatch ){ + int addedLemmas = d_mg->addInstantiations( baseMatch, + d_nodes[0].getAttribute(InstConstantAttribute()), + d_quantEngine); + if( addedLemmas>0 ){ + Debug("inst-trigger") << "Added " << addedLemmas << " lemmas, trigger was "; + for( int i=0; i<(int)d_nodes.size(); i++ ){ + Debug("inst-trigger") << d_nodes[i] << " "; + } + Debug("inst-trigger") << std::endl; + } + return addedLemmas; +} + +Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool keepAll, int trOption, + bool smartTriggers ){ + 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; + for( int i=0; i<(int)temp.size(); i++ ){ + bool foundVar = false; + computeVarContains( temp[i] ); + for( int j=0; j<(int)d_var_contains[ temp[i] ].size(); j++ ){ + Node v = d_var_contains[ temp[i] ][j]; + if( v.getAttribute(InstConstantAttribute())==f ){ + if( vars.find( v )==vars.end() ){ + vars[ v ] = true; + foundVar = true; + } + } + } + if( foundVar ){ + trNodes.push_back( temp[i] ); + for( int j=0; j<(int)d_var_contains[ temp[i] ].size(); j++ ){ + Node v = d_var_contains[ temp[i] ][j]; + patterns[ v ].push_back( temp[i] ); + } + } + } + //now, minimalize the trigger + for( int i=0; i<(int)trNodes.size(); i++ ){ + bool keepPattern = false; + Node n = trNodes[i]; + for( int j=0; j<(int)d_var_contains[ n ].size(); j++ ){ + Node v = d_var_contains[ n ][j]; + if( patterns[v].size()==1 ){ + keepPattern = true; + break; + } + } + if( !keepPattern ){ + //remove from pattern vector + for( int j=0; j<(int)d_var_contains[ n ].size(); j++ ){ + Node v = d_var_contains[ n ][j]; + for( int k=0; k<(int)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--; + } + } + }else{ + trNodes.insert( trNodes.begin(), nodes.begin(), nodes.end() ); + } + + //check for duplicate? + if( trOption==TR_MAKE_NEW ){ + //static int trNew = 0; + //static int trOld = 0; + //Trigger* t = d_tr_trie.getTrigger( trNodes ); + //if( t ){ + // trOld++; + //}else{ + // trNew++; + //} + //if( (trNew+trOld)%100==0 ){ + // std::cout << "Trigger new old = " << trNew << " " << trOld << std::endl; + //} + }else{ + Trigger* t = d_tr_trie.getTrigger( trNodes ); + if( t ){ + if( trOption==TR_GET_OLD ){ + //just return old trigger + return t; + }else{ + return NULL; + } + } + } + Trigger* t = new Trigger( qe, f, trNodes, matchOption, smartTriggers ); + d_tr_trie.addTrigger( trNodes, t ); + return t; +} +Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, int matchOption, bool keepAll, int trOption, bool smartTriggers ){ + std::vector< Node > nodes; + nodes.push_back( n ); + return mkTrigger( qe, f, nodes, matchOption, keepAll, trOption, smartTriggers ); +} + +bool Trigger::isUsableTrigger( std::vector< Node >& nodes, Node f ){ + for( int i=0; i<(int)nodes.size(); i++ ){ + if( !isUsableTrigger( nodes[i], f ) ){ + return false; + } + } + return true; +} + +bool Trigger::isUsable( Node n, Node f ){ + if( n.getAttribute(InstConstantAttribute())==f ){ + if( !isAtomicTrigger( n ) && n.getKind()!=INST_CONSTANT ){ + std::map< Node, Node > coeffs; + return getPatternArithmetic( f, n, coeffs ); + }else{ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( !isUsable( n[i], f ) ){ + return false; + } + } + return true; + } + }else{ + return true; + } +} + +bool Trigger::isSimpleTrigger( Node n ){ + if( isAtomicTrigger( n ) ){ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( n[i].getKind()!=INST_CONSTANT && n[i].hasAttribute(InstConstantAttribute()) ){ + return false; + } + } + return true; + }else{ + return false; + } +} + +/** filter all nodes that have instances */ +void Trigger::filterInstances( std::vector< Node >& nodes ){ + std::vector< bool > active; + active.resize( nodes.size(), true ); + for( int i=0; i<(int)nodes.size(); i++ ){ + for( int j=i+1; j<(int)nodes.size(); j++ ){ + if( active[i] && active[j] ){ + int result = isInstanceOf( nodes[i], nodes[j] ); + if( result==1 ){ + active[j] = false; + }else if( result==-1 ){ + active[i] = false; + } + } + } + } + std::vector< Node > temp; + for( int i=0; i<(int)nodes.size(); i++ ){ + if( active[i] ){ + temp.push_back( nodes[i] ); + } + } + nodes.clear(); + nodes.insert( nodes.begin(), temp.begin(), temp.end() ); +} + + +bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt ){ + if( patMap.find( n )==patMap.end() ){ + patMap[ n ] = false; + if( tstrt==TS_MIN_TRIGGER ){ + if( n.getKind()==FORALL ){ +#ifdef NESTED_PATTERN_SELECTION + //return collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt ); + return collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt ); +#else + return false; +#endif + }else{ + bool retVal = false; + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){ + retVal = true; + } + } + if( retVal ){ + return true; + }else if( isUsableTrigger( n, f ) ){ + patMap[ n ] = true; + return true; + }else{ + return false; + } + } + }else{ + bool retVal = false; + if( isUsableTrigger( n, f ) ){ + patMap[ n ] = true; + if( tstrt==TS_MAX_TRIGGER ){ + return true; + }else{ + retVal = true; + } + } + if( n.getKind()==FORALL ){ +#ifdef NESTED_PATTERN_SELECTION + //if( collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt ) ){ + // retVal = true; + //} + if( collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt ) ){ + retVal = true; + } +#endif + }else{ + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){ + retVal = true; + } + } + } + return retVal; + } + }else{ + return patMap[ n ]; + } +} + +void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst ){ + std::map< Node, bool > patMap; + if( filterInst ){ + //immediately do not consider any term t for which another term is an instance of t + std::vector< Node > patTerms2; + collectPatTerms( qe, f, n, patTerms2, TS_ALL, false ); + std::vector< Node > temp; + temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() ); + filterInstances( temp ); + if( temp.size()!=patTerms2.size() ){ + Debug("trigger-filter-instance") << "Filtered an instance: " << std::endl; + Debug("trigger-filter-instance") << "Old: "; + for( int i=0; i<(int)patTerms2.size(); i++ ){ + Debug("trigger-filter-instance") << patTerms2[i] << " "; + } + Debug("trigger-filter-instance") << std::endl << "New: "; + for( int i=0; i<(int)temp.size(); i++ ){ + Debug("trigger-filter-instance") << temp[i] << " "; + } + Debug("trigger-filter-instance") << std::endl; + } + if( tstrt==TS_ALL ){ + patTerms.insert( patTerms.begin(), temp.begin(), temp.end() ); + return; + }else{ + //do not consider terms that have instances + for( int i=0; i<(int)patTerms2.size(); i++ ){ + if( std::find( temp.begin(), temp.end(), patTerms2[i] )==temp.end() ){ + patMap[ patTerms2[i] ] = false; + } + } + } + } + collectPatTerms2( qe, f, n, patMap, tstrt ); + for( std::map< Node, bool >::iterator it = patMap.begin(); it != patMap.end(); ++it ){ + if( it->second ){ + patTerms.push_back( it->first ); + } + } +} + +/** is n1 an instance of n2 or vice versa? */ +int Trigger::isInstanceOf( Node n1, Node n2 ){ + if( n1==n2 ){ + return 1; + }else if( n1.getKind()==n2.getKind() ){ + if( n1.getKind()==APPLY_UF ){ + if( n1.getOperator()==n2.getOperator() ){ + int result = 0; + for( int i=0; i<(int)n1.getNumChildren(); i++ ){ + if( n1[i]!=n2[i] ){ + int cResult = isInstanceOf( n1[i], n2[i] ); + if( cResult==0 ){ + return 0; + }else if( cResult!=result ){ + if( result!=0 ){ + return 0; + }else{ + result = cResult; + } + } + } + } + return result; + } + } + return 0; + }else if( n2.getKind()==INST_CONSTANT ){ + computeVarContains( n1 ); + //if( std::find( d_var_contains[ n1 ].begin(), d_var_contains[ n1 ].end(), n2 )!=d_var_contains[ n1 ].end() ){ + // return 1; + //} + if( d_var_contains[ n1 ].size()==1 && d_var_contains[ n1 ][ 0 ]==n2 ){ + return 1; + } + }else if( n1.getKind()==INST_CONSTANT ){ + computeVarContains( n2 ); + //if( std::find( d_var_contains[ n2 ].begin(), d_var_contains[ n2 ].end(), n1 )!=d_var_contains[ n2 ].end() ){ + // return -1; + //} + if( d_var_contains[ n2 ].size()==1 && d_var_contains[ n2 ][ 0 ]==n1 ){ + return 1; + } + } + return 0; +} + +bool Trigger::isVariableSubsume( Node n1, Node n2 ){ + if( n1==n2 ){ + return true; + }else{ + //std::cout << "is variable subsume ? " << n1 << " " << n2 << std::endl; + computeVarContains( n1 ); + computeVarContains( n2 ); + for( int i=0; i<(int)d_var_contains[n2].size(); i++ ){ + if( std::find( d_var_contains[n1].begin(), d_var_contains[n1].end(), d_var_contains[n2][i] )==d_var_contains[n1].end() ){ + //std::cout << "no" << std::endl; + return false; + } + } + //std::cout << "yes" << std::endl; + return true; + } +} + +void Trigger::getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains ){ + for( int i=0; i<(int)pats.size(); i++ ){ + computeVarContains( pats[i] ); + varContains[ pats[i] ].clear(); + for( int j=0; j<(int)d_var_contains[pats[i]].size(); j++ ){ + if( d_var_contains[pats[i]][j].getAttribute(InstConstantAttribute())==f ){ + varContains[ pats[i] ].push_back( d_var_contains[pats[i]][j] ); + } + } + } +} + +void Trigger::getVarContainsNode( Node f, Node n, std::vector< Node >& varContains ){ + computeVarContains( n ); + for( int j=0; j<(int)d_var_contains[n].size(); j++ ){ + if( d_var_contains[n][j].getAttribute(InstConstantAttribute())==f ){ + varContains.push_back( d_var_contains[n][j] ); + } + } +} + +bool Trigger::getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coeffs ){ + if( n.getKind()==PLUS ){ + Assert( coeffs.empty() ); + NodeBuilder<> t(kind::PLUS); + for( int i=0; i<(int)n.getNumChildren(); i++ ){ + if( n[i].hasAttribute(InstConstantAttribute()) ){ + if( n[i].getKind()==INST_CONSTANT ){ + if( n[i].getAttribute(InstConstantAttribute())==f ){ + coeffs[ n[i] ] = Node::null(); + }else{ + coeffs.clear(); + return false; + } + }else if( !getPatternArithmetic( f, n[i], coeffs ) ){ + coeffs.clear(); + return false; + } + }else{ + t << n[i]; + } + } + if( t.getNumChildren()==0 ){ + coeffs[ Node::null() ] = NodeManager::currentNM()->mkConst( Rational(0) ); + }else if( t.getNumChildren()==1 ){ + coeffs[ Node::null() ] = t.getChild( 0 ); + }else{ + coeffs[ Node::null() ] = t; + } + return true; + }else if( n.getKind()==MULT ){ + if( n[0].getKind()==INST_CONSTANT && n[0].getAttribute(InstConstantAttribute())==f ){ + Assert( !n[1].hasAttribute(InstConstantAttribute()) ); + coeffs[ n[0] ] = n[1]; + return true; + }else if( n[1].getKind()==INST_CONSTANT && n[1].getAttribute(InstConstantAttribute())==f ){ + Assert( !n[0].hasAttribute(InstConstantAttribute()) ); + coeffs[ n[1] ] = n[0]; + return true; + } + } + return false; +} diff --git a/src/theory/rewriterules/rr_trigger.h b/src/theory/rewriterules/rr_trigger.h new file mode 100644 index 000000000..096fbdb4f --- /dev/null +++ b/src/theory/rewriterules/rr_trigger.h @@ -0,0 +1,176 @@ +/********************* */ +/*! \file rr_trigger.h + ** \verbatim + ** Original author: ajreynol + ** Major contributors: bobot + ** Minor contributors (to current version): none + ** This file is part of the CVC4 prototype. + ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) + ** Courant Institute of Mathematical Sciences + ** New York University + ** See the file COPYING in the top-level source directory for licensing + ** information.\endverbatim + ** + ** \brief trigger class + **/ + +#include "cvc4_private.h" + +#ifndef __CVC4__THEORY__REWRITERULES__RR_TRIGGER_H +#define __CVC4__THEORY__REWRITERULES__RR_TRIGGER_H + +#include "theory/rewriterules/rr_inst_match.h" + +namespace CVC4 { +namespace theory { +namespace rrinst { + +//a collect of nodes representing a trigger +class Trigger { +public: + static int trCount; +private: + /** computation of variable contains */ + static std::map< Node, std::vector< Node > > d_var_contains; + static void computeVarContains( Node n ); + static void computeVarContains2( Node n, Node parent ); +private: + /** the quantifiers engine */ + QuantifiersEngine* d_quantEngine; + /** the quantifier this trigger is for */ + Node d_f; + /** match generators */ + PatsMatcher * d_mg; +private: + /** a trie of triggers */ + class TrTrie + { + private: + Trigger* getTrigger2( std::vector< Node >& nodes ); + void addTrigger2( std::vector< Node >& nodes, Trigger* t ); + public: + TrTrie() : d_tr( NULL ){} + Trigger* d_tr; + std::map< Node, TrTrie* > d_children; + Trigger* getTrigger( std::vector< Node >& nodes ){ + std::vector< Node > temp; + temp.insert( temp.begin(), nodes.begin(), nodes.end() ); + std::sort( temp.begin(), temp.end() ); + return getTrigger2( temp ); + } + void addTrigger( std::vector< Node >& nodes, Trigger* t ){ + std::vector< Node > temp; + temp.insert( temp.begin(), nodes.begin(), nodes.end() ); + std::sort( temp.begin(), temp.end() ); + return addTrigger2( temp, t ); + } + }; + /** all triggers will be stored in this trie */ + static TrTrie d_tr_trie; +private: + /** trigger constructor */ + Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes, int matchOption = 0, bool smartTriggers = false ); +public: + ~Trigger(){} +public: + std::vector< Node > d_nodes; +public: + void debugPrint( const char* c ); + PatsMatcher* getGenerator() { return d_mg; } +public: + /** reset instantiation round (call this whenever equivalence classes have changed) */ + void resetInstantiationRound(); + /** get next match. must call reset( eqc ) once before this function. */ + bool getNextMatch(); + const InstMatch & getInstMatch(){return d_mg->getInstMatch();}; + /** return whether this is a multi-trigger */ + bool isMultiTrigger() { return d_nodes.size()>1; } +public: + /** add all available instantiations exhaustively, in any equivalence class + if limitInst>0, limitInst is the max # of instantiations to try */ + int addInstantiations( InstMatch& baseMatch); + /** mkTrigger method + 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) + */ + enum { + //options for producing matches + MATCH_GEN_DEFAULT = 0, + MATCH_GEN_EFFICIENT_E_MATCH, //generate matches via Efficient E + }; + enum{ + TR_MAKE_NEW, //make new trigger even if it already may exist + 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, + bool smartTriggers = false ); + static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, Node n, + int matchOption = 0, bool keepAll = true, int trOption = TR_MAKE_NEW, + bool smartTriggers = false ); +private: + /** is subterm of trigger usable */ + static bool isUsable( Node n, Node f ); + /** collect all APPLY_UF pattern terms for f in n */ + static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt ); +public: + //different strategies for choosing trigger terms + enum { + TS_MAX_TRIGGER = 0, + TS_MIN_TRIGGER, + TS_ALL, + }; + static void collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst = false ); +public: + /** is usable trigger */ + static inline bool isUsableTrigger( TNode n, TNode f ){ + //return n.getAttribute(InstConstantAttribute())==f && n.getKind()==APPLY_UF; + return n.getAttribute(InstConstantAttribute())==f && isAtomicTrigger( n ) && isUsable( n, f ); + } + static inline bool isAtomicTrigger( TNode n ){ + return + n.getKind()==kind::APPLY_UF || + n.getKind()==kind::SELECT || + n.getKind()==kind::STORE; + } + static bool isUsableTrigger( std::vector< Node >& nodes, Node f ); + static bool isSimpleTrigger( Node n ); + /** filter all nodes that have instances */ + static void filterInstances( std::vector< Node >& nodes ); + /** -1: n1 is an instance of n2, 1: n1 is an instance of n2 */ + static int isInstanceOf( Node n1, Node n2 ); + /** variables subsume, return true if n1 contains all free variables in n2 */ + static bool isVariableSubsume( Node n1, Node n2 ); + /** get var contains */ + static void getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains ); + static void getVarContainsNode( Node f, Node n, std::vector< Node >& varContains ); + /** get pattern arithmetic */ + static bool getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coeffs ); + + inline void toStream(std::ostream& out) const { + out << "TRIGGER( "; + for( int i=0; i<(int)d_nodes.size(); i++ ){ + if( i>0 ){ out << ", "; } + out << d_nodes[i]; + } + out << " )"; + } +}; + +inline std::ostream& operator<<(std::ostream& out, const Trigger & tr) { + tr.toStream(out); + return out; +} + +}/* CVC4::theory::rrinst namespace */ + +}/* CVC4::theory namespace */ + +}/* CVC4 namespace */ + +#endif /* __CVC4__THEORY__REWRITERULES__RR_TRIGGER_H */ diff --git a/src/theory/rewriterules/theory_rewriterules.h b/src/theory/rewriterules/theory_rewriterules.h index fcbdfe8b9..bb5537474 100644 --- a/src/theory/rewriterules/theory_rewriterules.h +++ b/src/theory/rewriterules/theory_rewriterules.h @@ -27,9 +27,9 @@ #include "theory/theory_engine.h" #include "theory/quantifiers_engine.h" #include "context/context_mm.h" -#include "theory/rr_inst_match_impl.h" -#include "theory/rr_trigger.h" -#include "theory/rr_inst_match.h" +#include "theory/rewriterules/rr_inst_match_impl.h" +#include "theory/rewriterules/rr_trigger.h" +#include "theory/rewriterules/rr_inst_match.h" #include "util/stats.h" #include "theory/rewriterules/theory_rewriterules_preprocess.h" #include "theory/model.h" diff --git a/src/theory/rr_candidate_generator.cpp b/src/theory/rr_candidate_generator.cpp deleted file mode 100644 index a2e895c7f..000000000 --- a/src/theory/rr_candidate_generator.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/********************* */ -/*! \file rr_candidate_generator.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: bobot - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Implementation of rr candidate generator class - **/ - -#include "theory/rr_candidate_generator.h" -#include "theory/theory_engine.h" -#include "theory/uf/theory_uf.h" -#include "theory/quantifiers/term_database.h" - -using namespace std; -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::context; -using namespace CVC4::theory; -using namespace CVC4::theory::rrinst; - -GenericCandidateGeneratorClasses::GenericCandidateGeneratorClasses(QuantifiersEngine * qe){ - for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ - if(qe->getInstantiator(i) != NULL) - d_can_gen[i] = qe->getInstantiator(i)->getRRCanGenClasses(); - else d_can_gen[i] = NULL; - } -} - -GenericCandidateGeneratorClasses::~GenericCandidateGeneratorClasses(){ - for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ - delete(d_can_gen[i]); - } -} - -void GenericCandidateGeneratorClasses::resetInstantiationRound(){ - for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ - if(d_can_gen[i] != NULL) d_can_gen[i]->resetInstantiationRound(); - } - d_can_gen_id=THEORY_FIRST; -} - -void GenericCandidateGeneratorClasses::reset(TNode eqc){ - Assert(eqc.isNull()); - for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ - if(d_can_gen[i] != NULL) d_can_gen[i]->reset(eqc); - } - d_can_gen_id=THEORY_FIRST; - lookForNextTheory(); -} - -TNode GenericCandidateGeneratorClasses::getNextCandidate(){ - Assert(THEORY_FIRST <= d_can_gen_id && d_can_gen_id <= THEORY_LAST); - /** No more */ - if(d_can_gen_id == THEORY_LAST) return TNode::null(); - /** Try with this theory */ - TNode cand = d_can_gen[d_can_gen_id]->getNextCandidate(); - if( !cand.isNull() ) return cand; - lookForNextTheory(); - return getNextCandidate(); -} - -void GenericCandidateGeneratorClasses::lookForNextTheory(){ - do{ /* look for the next available generator */ - ++d_can_gen_id; - } while( d_can_gen_id < THEORY_LAST && d_can_gen[d_can_gen_id] == NULL); -} - -GenericCandidateGeneratorClass::GenericCandidateGeneratorClass(QuantifiersEngine * qe): d_qe(qe) { - for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ - if(d_qe->getInstantiator(i) != NULL) - d_can_gen[i] = d_qe->getInstantiator(i)->getRRCanGenClass(); - else d_can_gen[i] = NULL; - } -} - -GenericCandidateGeneratorClass::~GenericCandidateGeneratorClass(){ - for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ - delete(d_can_gen[i]); - } -} - -void GenericCandidateGeneratorClass::resetInstantiationRound(){ - for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ - if(d_can_gen[i] != NULL) d_can_gen[i]->resetInstantiationRound(); - } - d_can_gen_id=THEORY_FIRST; -} - -void GenericCandidateGeneratorClass::reset(TNode eqc){ - for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){ - if(d_can_gen[i] != NULL) d_can_gen[i]->reset(eqc); - } - d_can_gen_id=THEORY_FIRST; - d_node = eqc; - lookForNextTheory(); -} - -TNode GenericCandidateGeneratorClass::getNextCandidate(){ - Assert(THEORY_FIRST <= d_can_gen_id && d_can_gen_id <= THEORY_LAST); - /** No more */ - if(d_can_gen_id == THEORY_LAST) return TNode::null(); - /** Try with this theory */ - TNode cand = d_can_gen[d_can_gen_id]->getNextCandidate(); - if( !cand.isNull() ) return cand; - lookForNextTheory(); - return getNextCandidate(); -} - -void GenericCandidateGeneratorClass::lookForNextTheory(){ - do{ /* look for the next available generator, where the element is */ - ++d_can_gen_id; - } while( - d_can_gen_id < THEORY_LAST && - (d_can_gen[d_can_gen_id] == NULL || - !d_qe->getInstantiator( d_can_gen_id )->hasTerm( d_node )) - ); -} diff --git a/src/theory/rr_candidate_generator.h b/src/theory/rr_candidate_generator.h deleted file mode 100644 index 30f6c067d..000000000 --- a/src/theory/rr_candidate_generator.h +++ /dev/null @@ -1,209 +0,0 @@ -/********************* */ -/*! \file rr_candidate_generator.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: bobot - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief rr candidate generator - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__THEORY_UF_CANDIDATE_GENERATOR_H -#define __CVC4__THEORY_UF_CANDIDATE_GENERATOR_H - -#include "theory/quantifiers_engine.h" -#include "theory/quantifiers/term_database.h" -#include "theory/rr_inst_match.h" - -using namespace CVC4::theory::quantifiers; - -namespace CVC4 { -namespace theory { -namespace eq { - -namespace rrinst{ -typedef CVC4::theory::rrinst::CandidateGenerator CandidateGenerator; - -//New CandidateGenerator. They have a simpler semantic than the old one - -// Just iterate amoung the equivalence classes -// node::Null() must be given to reset -class CandidateGeneratorTheoryEeClasses : public CandidateGenerator{ -private: - //the equality classes iterator - eq::EqClassesIterator d_eq; - //equalityengine pointer - EqualityEngine* d_ee; -public: - CandidateGeneratorTheoryEeClasses( EqualityEngine * ee): d_ee( ee ){} - ~CandidateGeneratorTheoryEeClasses(){} - void resetInstantiationRound(){}; - void reset( TNode eqc ){ - Assert(eqc.isNull()); - d_eq = eq::EqClassesIterator( d_ee ); - }; //* the argument is not used - TNode getNextCandidate(){ - if( !d_eq.isFinished() ) return (*(d_eq++)); - else return Node::null(); - }; -}; - -// Just iterate amoung the equivalence class of the given node -// node::Null() *can't* be given to reset -class CandidateGeneratorTheoryEeClass : public CandidateGenerator{ -private: - //instantiator pointer - EqualityEngine* d_ee; - //the equality class iterator - eq::EqClassIterator d_eqc; - /* For the case where the given term doesn't exists in uf */ - Node d_retNode; -public: - CandidateGeneratorTheoryEeClass( EqualityEngine* ee): d_ee( ee ){} - ~CandidateGeneratorTheoryEeClass(){} - void resetInstantiationRound(){}; - void reset( TNode eqc ){ - Assert(!eqc.isNull()); - if( d_ee->hasTerm( eqc ) ){ - /* eqc is in uf */ - eqc = d_ee->getRepresentative( eqc ); - d_eqc = eq::EqClassIterator( eqc, d_ee ); - d_retNode = Node::null(); - }else{ - /* If eqc if not a term known by uf, it is the only one in its - equivalence class. So we will return only it */ - d_retNode = eqc; - d_eqc = eq::EqClassIterator(); - } - }; //* the argument is not used - TNode getNextCandidate(){ - if(d_retNode.isNull()){ - if( !d_eqc.isFinished() ) return (*(d_eqc++)); - else return Node::null(); - }else{ - /* the case where eqc not in uf */ - Node ret = d_retNode; - d_retNode = Node::null(); /* d_eqc.isFinished() must be true */ - return ret; - } - }; -}; - - -} /* namespace rrinst */ -} /* namespace eq */ - -namespace uf{ -namespace rrinst { - -typedef CVC4::theory::rrinst::CandidateGenerator CandidateGenerator; - -class CandidateGeneratorTheoryUfOp : public CandidateGenerator{ -private: - Node d_op; - //instantiator pointer - TermDb* d_tdb; - // Since new term can appears we restrict ourself to the one that - // exists at resetInstantiationRound - size_t d_term_iter_limit; - size_t d_term_iter; -public: - CandidateGeneratorTheoryUfOp(Node op, TermDb* tdb): d_op(op), d_tdb( tdb ){} - ~CandidateGeneratorTheoryUfOp(){} - void resetInstantiationRound(){ - d_term_iter_limit = d_tdb->d_op_map[d_op].size(); - }; - void reset( TNode eqc ){ - Assert(eqc.isNull()); - d_term_iter = 0; - }; //* the argument is not used - TNode getNextCandidate(){ - if( d_term_iterd_op_map[d_op][d_term_iter]; - ++d_term_iter; - return n; - } else return Node::null(); - }; -}; - -class CandidateGeneratorTheoryUfType : public CandidateGenerator{ -private: - TypeNode d_type; - //instantiator pointer - TermDb* d_tdb; - // Since new term can appears we restrict ourself to the one that - // exists at resetInstantiationRound - size_t d_term_iter_limit; - size_t d_term_iter; -public: - CandidateGeneratorTheoryUfType(TypeNode type, TermDb* tdb): d_type(type), d_tdb( tdb ){} - ~CandidateGeneratorTheoryUfType(){} - void resetInstantiationRound(){ - d_term_iter_limit = d_tdb->d_type_map[d_type].size(); - }; - void reset( TNode eqc ){ - Assert(eqc.isNull()); - d_term_iter = 0; - }; //* the argument is not used - TNode getNextCandidate(){ - if( d_term_iterd_type_map[d_type][d_term_iter]; - ++d_term_iter; - return n; - } else return Node::null(); - }; -}; - -} /* namespace rrinst */ -} /* namespace uf */ - -class GenericCandidateGeneratorClasses: public rrinst::CandidateGenerator{ - - /** The candidate generators */ - rrinst::CandidateGenerator* d_can_gen[theory::THEORY_LAST]; - /** The current theory which candidategenerator is used */ - TheoryId d_can_gen_id; - -public: - GenericCandidateGeneratorClasses(QuantifiersEngine * qe); - ~GenericCandidateGeneratorClasses(); - - void resetInstantiationRound(); - void reset(TNode eqc); - TNode getNextCandidate(); - void lookForNextTheory(); -}; - -class GenericCandidateGeneratorClass: public rrinst::CandidateGenerator{ - - /** The candidate generators */ - rrinst::CandidateGenerator* d_can_gen[theory::THEORY_LAST]; - /** The current theory which candidategenerator is used */ - TheoryId d_can_gen_id; - /** current node to look for equivalence class */ - Node d_node; - /** QuantifierEngine */ - QuantifiersEngine* d_qe; - -public: - GenericCandidateGeneratorClass(QuantifiersEngine * qe); - ~GenericCandidateGeneratorClass(); - void resetInstantiationRound(); - - void reset(TNode eqc); - TNode getNextCandidate(); - void lookForNextTheory(); -}; - -}/* CVC4::theory namespace */ -}/* CVC4 namespace */ - -#endif /* __CVC4__THEORY_UF_INSTANTIATOR_H */ diff --git a/src/theory/rr_inst_match.cpp b/src/theory/rr_inst_match.cpp deleted file mode 100644 index 0e3e7b9fa..000000000 --- a/src/theory/rr_inst_match.cpp +++ /dev/null @@ -1,1447 +0,0 @@ -/********************* */ -/*! \file rr_inst_match.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: bobot - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Implementation of inst match class - **/ - -#include "theory/inst_match.h" -#include "theory/theory_engine.h" -#include "theory/quantifiers_engine.h" -#include "theory/uf/theory_uf_instantiator.h" -#include "theory/uf/equality_engine.h" -#include "theory/arrays/theory_arrays.h" -#include "theory/datatypes/theory_datatypes.h" -#include "theory/rr_inst_match.h" -#include "theory/rr_trigger.h" -#include "theory/rr_inst_match_impl.h" -#include "theory/rr_candidate_generator.h" - -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::context; -using namespace CVC4::theory; -using namespace CVC4::theory::rrinst; -using namespace CVC4::theory::uf::rrinst; -using namespace CVC4::theory::eq::rrinst; - -namespace CVC4{ -namespace theory{ -namespace rrinst{ - -typedef CVC4::theory::inst::InstMatch InstMatch; -typedef CVC4::theory::inst::CandidateGeneratorQueue CandidateGeneratorQueue; - -template -class InstMatchTrie2Pairs -{ - typename std::vector< std::vector < typename InstMatchTrie2Gen::Tree > > d_data; - InstMatchTrie2Gen d_backtrack; -public: - InstMatchTrie2Pairs(context::Context* c, QuantifiersEngine* q, size_t n): - d_backtrack(c,q) { - // resize to a triangle - // - // | * - // | * * - // | * * * - // | -----> i - d_data.resize(n); - for(size_t i=0; i < n; ++i){ - d_data[i].resize(i+1,typename InstMatchTrie2Gen::Tree(0)); - } - }; - InstMatchTrie2Pairs(const InstMatchTrie2Pairs &) CVC4_UNDEFINED; - const InstMatchTrie2Pairs & operator =(const InstMatchTrie2Pairs & e) CVC4_UNDEFINED; - /** add match m in the trie, - return true if it was never seen */ - inline bool addInstMatch( size_t i, size_t j, InstMatch& m){ - size_t k = std::min(i,j); - size_t l = std::max(i,j); - return d_backtrack.addInstMatch(m,&(d_data[l][k])); - }; - inline bool addInstMatch( size_t i, InstMatch& m){ - return d_backtrack.addInstMatch(m,&(d_data[i][i])); - }; - -}; - - -// Currently the implementation doesn't take into account that -// variable should have the same value given. -// TODO use the d_children way perhaps -// TODO replace by a real dictionnary -// We should create a real substitution? slower more precise -// We don't do that often -bool nonunifiable( TNode t0, TNode pat, const std::vector & vars){ - if(pat.isNull()) return true; - - typedef std::vector > tstack; - tstack stack(1,std::make_pair(t0,pat)); // t * pat - - while(!stack.empty()){ - const std::pair p = stack.back(); stack.pop_back(); - const TNode & t = p.first; - const TNode & pat = p.second; - - // t or pat is a variable currently we consider that can match anything - if( find(vars.begin(),vars.end(),t) != vars.end() ) continue; - if( pat.getKind() == INST_CONSTANT ) continue; - - // t and pat are nonunifiable - if( !Trigger::isAtomicTrigger( t ) || !Trigger::isAtomicTrigger( pat ) ) { - if(t == pat) continue; - else return true; - }; - if( t.getOperator() != pat.getOperator() ) return true; - - //put the children on the stack - for( size_t i=0; i < pat.getNumChildren(); i++ ){ - stack.push_back(std::make_pair(t[i],pat[i])); - }; - } - // The heuristic can't find non-unifiability - return false; -}; - -/** New things */ -class DumbMatcher: public Matcher{ - void resetInstantiationRound( QuantifiersEngine* qe ){}; - bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ){ - return false; - } - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - return false; - } -}; - -class DumbPatMatcher: public PatMatcher{ - void resetInstantiationRound( QuantifiersEngine* qe ){}; - bool reset( InstMatch& m, QuantifiersEngine* qe ){ - return false; - } - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - return false; - } -}; - - -/* The order of the matching is: - reset arg1, nextMatch arg1, reset arg2, nextMatch arg2, ... */ -ApplyMatcher::ApplyMatcher( Node pat, QuantifiersEngine* qe): d_pattern(pat){ - // Assert( pat.hasAttribute(InstConstantAttribute()) ); - - //set-up d_variables, d_constants, d_childrens - for( size_t i=0; i< d_pattern.getNumChildren(); ++i ){ - EqualityQuery* q = qe->getEqualityQuery(d_pattern[i].getType()); - Assert( q != NULL ); - if( d_pattern[i].hasAttribute(InstConstantAttribute()) ){ - if( d_pattern[i].getKind()==INST_CONSTANT ){ - //It's a variable - d_variables.push_back(make_triple((TNode)d_pattern[i],i,q)); - }else{ - //It's neither a constant argument neither a variable - //we create the matcher for the subpattern - d_childrens.push_back(make_triple(mkMatcher((TNode)d_pattern[i], qe),i,q)); - }; - }else{ - // It's a constant - d_constants.push_back(make_triple((TNode)d_pattern[i],i,q)); - } - } -} - -void ApplyMatcher::resetInstantiationRound( QuantifiersEngine* qe ){ - for( size_t i=0; i< d_childrens.size(); i++ ){ - d_childrens[i].first->resetInstantiationRound( qe ); - } -} - -bool ApplyMatcher::reset(TNode t, InstMatch & m, QuantifiersEngine* qe){ - Debug("matching") << "Matching " << t << " against pattern " << d_pattern << " (" - << m.size() << ")" << std::endl; - - //if t is null - Assert( !t.isNull() ); - Assert( !t.hasAttribute(InstConstantAttribute()) ); - Assert( t.getKind()==d_pattern.getKind() ); - Assert( (t.getKind()!=APPLY_UF && t.getKind()!=APPLY_CONSTRUCTOR) - || t.getOperator()==d_pattern.getOperator() ); - - typedef std::vector< triple >::iterator iterator; - for(iterator i = d_constants.begin(), end = d_constants.end(); - i != end; ++i){ - if( !i->third->areEqual( i->first, t[i->second] ) ){ - Debug("matching-fail") << "Match fail arg: " << i->first << " and " << t[i->second] << std::endl; - //setMatchFail( qe, d_pattern[i], t[i] ); - //ground arguments are not equal - return false; - } - } - - d_binded.clear(); - bool set; - for(iterator i = d_variables.begin(), end = d_variables.end(); - i != end; ++i){ - if( !m.setMatch( i->third, i->first, t[i->second], set) ){ - //match is in conflict - Debug("matching-debug") << "Match in conflict " << t[i->second] << " and " - << i->first << " because " - << m.get(i->first) - << std::endl; - Debug("matching-fail") << "Match fail: " << m.get(i->first) << " and " << t[i->second] << std::endl; - //setMatchFail( qe, partial[0].d_map[d_pattern[i]], t[i] ); - m.erase(d_binded.begin(), d_binded.end()); - return false; - }else{ - if(set){ //The variable has just been set - d_binded.push_back(i->first); - } - } - } - - //now, fit children into match - //we will be requesting candidates for matching terms for each child - d_reps.clear(); - for( size_t i=0; i< d_childrens.size(); i++ ){ - Debug("matching-debug") << "Take the representative of " << t[ d_childrens[i].second ] << std::endl; - Assert( d_childrens[i].third->hasTerm(t[ d_childrens[i].second ]) ); - Node rep = d_childrens[i].third->getRepresentative( t[ d_childrens[i].second ] ); - d_reps.push_back( rep ); - } - - if(d_childrens.size() == 0) return true; - else return getNextMatch(m, qe, true); -} - -bool ApplyMatcher::getNextMatch(InstMatch& m, QuantifiersEngine* qe, bool reset){ - Assert(d_childrens.size() > 0); - const size_t max = d_childrens.size() - 1; - size_t index = reset ? 0 : max; - Assert(d_childrens.size() == d_reps.size()); - while(true){ - if(reset ? - d_childrens[index].first->reset( d_reps[index], m, qe ) : - d_childrens[index].first->getNextMatch( m, qe )){ - if(index==max) return true; - ++index; - reset=true; - }else{ - if(index==0){ - m.erase(d_binded.begin(), d_binded.end()); - return false; - } - --index; - reset=false; - }; - } -} - -bool ApplyMatcher::getNextMatch(InstMatch& m, QuantifiersEngine* qe){ - if(d_childrens.size() == 0){ - m.erase(d_binded.begin(), d_binded.end()); - return false; - } else return getNextMatch(m, qe, false); -} - -/** Proxy that call the sub-matcher on the result return by the given candidate generator */ -template -class CandidateGeneratorMatcher: public Matcher{ - /** candidate generator */ - CG d_cg; - /** the sub-matcher */ - M d_m; -public: - CandidateGeneratorMatcher(CG cg, M m): d_cg(cg), d_m(m) - {/* last is Null */}; - void resetInstantiationRound( QuantifiersEngine* qe ){ - d_cg.resetInstantiationRound(); - d_m.resetInstantiationRound(qe); - }; - bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ){ - d_cg.reset(n); - return findMatch(m,qe); - } - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - // The sub-matcher has another match - return d_m.getNextMatch(m, qe) || findMatch(m,qe); - } -private: - bool findMatch( InstMatch& m, QuantifiersEngine* qe ){ - // Otherwise try to find a new candidate that has at least one match - while(true){ - TNode n = d_cg.getNextCandidate();//kept somewhere Term-db - Debug("matching") << "GenCand " << n << " (" << this << ")" << std::endl; - if(n.isNull()) return false; - if(d_m.reset(n,m,qe)) return true; - }; - } -}; - -/** Proxy that call the sub-matcher on the result return by the given candidate generator */ -template -class PatOfMatcher: public PatMatcher{ - M d_m; -public: - inline PatOfMatcher(M m): d_m(m){} - void resetInstantiationRound(QuantifiersEngine* qe){ - d_m.resetInstantiationRound(qe); - } - bool reset(InstMatch& m, QuantifiersEngine* qe){ - return d_m.reset(Node::null(),m,qe); - }; - bool getNextMatch(InstMatch& m, QuantifiersEngine* qe){ - return d_m.getNextMatch(m,qe); - }; -}; - -class ArithMatcher: public Matcher{ -private: - /** for arithmetic matching */ - std::map< Node, Node > d_arith_coeffs; - /** get the match against ground term or formula t. - d_match_mattern and t should have the same shape. - only valid for use where !d_match_pattern.isNull(). - */ - /** the variable that are set by this matcher */ - std::vector< TNode > d_binded; /* TNode because the variables are already in d_arith_coeffs */ - Node d_pattern; //for debugging -public: - ArithMatcher(Node pat, QuantifiersEngine* qe); - void resetInstantiationRound( QuantifiersEngine* qe ){}; - bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ); - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ); -}; - -/** Match just a variable */ -class VarMatcher: public Matcher{ - Node d_var; - bool d_binded; /* True if the reset bind the variable to some value */ - EqualityQuery* d_q; -public: - VarMatcher(Node var, QuantifiersEngine* qe): d_var(var), d_binded(false){ - d_q = qe->getEqualityQuery(var.getType()); - } - void resetInstantiationRound( QuantifiersEngine* qe ){}; - bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ){ - if(!m.setMatch( d_q, d_var, n, d_binded )){ - //match is in conflict - Debug("matching-fail") << "Match fail: " << m.get(d_var) - << " and " << n << std::endl; - return false; - } else return true; - }; - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - //match is in conflict - if (d_binded) m.erase(d_var); - return false; - } -}; - -template -class TestMatcher: public Matcher{ - M d_m; - Test d_test; -public: - inline TestMatcher(M m, Test test): d_m(m), d_test(test){} - inline void resetInstantiationRound(QuantifiersEngine* qe){ - d_m.resetInstantiationRound(qe); - } - inline bool reset(TNode n, InstMatch& m, QuantifiersEngine* qe){ - return d_test(n) && d_m.reset(n, m, qe); - } - inline bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - return d_m.getNextMatch(m, qe); - } -}; - -class LegalOpTest/*: public unary_function*/ { - Node d_op; -public: - inline LegalOpTest(Node op): d_op(op){} - inline bool operator() (TNode n) { - return - CandidateGenerator::isLegalCandidate(n) && - // ( // n.getKind()==SELECT || n.getKind()==STORE || - // n.getKind()==APPLY_UF || n.getKind()==APPLY_CONSTRUCTOR) && - n.hasOperator() && - n.getOperator()==d_op; - }; -}; - -class LegalKindTest/* : public unary_function*/ { - Kind d_kind; -public: - inline LegalKindTest(Kind kind): d_kind(kind){} - inline bool operator() (TNode n) { - return - CandidateGenerator::isLegalCandidate(n) && - n.getKind()==d_kind; - }; -}; - -class LegalTypeTest/* : public unary_function*/ { - TypeNode d_type; -public: - inline LegalTypeTest(TypeNode type): d_type(type){} - inline bool operator() (TNode n) { - return - CandidateGenerator::isLegalCandidate(n) && - n.getType()==d_type; - }; -}; - -class LegalTest/* : public unary_function*/ { -public: - inline bool operator() (TNode n) { - return CandidateGenerator::isLegalCandidate(n); - }; -}; - -size_t numFreeVar(TNode t){ - size_t n = 0; - for( size_t i=0, size =t.getNumChildren(); i < size; ++i ){ - if( t[i].hasAttribute(InstConstantAttribute()) ){ - if( t[i].getKind()==INST_CONSTANT ){ - //variable - ++n; - }else{ - //neither variable nor constant - n += numFreeVar(t[i]); - } - } - } - return n; -} - -class OpMatcher: public Matcher{ - /* The matcher */ - typedef ApplyMatcher AuxMatcher3; - typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2; - typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2> AuxMatcher1; - AuxMatcher1 d_cgm; - static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ - Assert( pat.getKind() == kind::APPLY_UF ); - /** In reverse order of matcher sequence */ - AuxMatcher3 am3(pat,qe); - /** Keep only the one that have the good operator */ - AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator())); - /** Iter on the equivalence class of the given term */ - uf::TheoryUF* uf = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )); - eq::EqualityEngine* ee = static_cast(uf->getEqualityEngine()); - CandidateGeneratorTheoryEeClass cdtUfEq(ee); - /* Create a matcher from the candidate generator */ - AuxMatcher1 am1(cdtUfEq,am2); - return am1; - } - size_t d_num_var; - Node d_pat; -public: - OpMatcher( Node pat, QuantifiersEngine* qe ): - d_cgm(createCgm(pat, qe)),d_num_var(numFreeVar(pat)), - d_pat(pat) {} - - void resetInstantiationRound( QuantifiersEngine* qe ){ - d_cgm.resetInstantiationRound(qe); - }; - bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ - // size_t m_size = m.d_map.size(); - // if(m_size == d_num_var){ - // uf::EqualityEngine* ee = (static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )))->getEqualityEngine(); - // std::cout << "!"; - // return ee->areEqual(m.subst(d_pat),t); - // }else{ - // std::cout << m.d_map.size() << std::endl; - return d_cgm.reset(t, m, qe); - // } - } - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.getNextMatch(m, qe); - } -}; - -class DatatypesMatcher: public Matcher{ - /* The matcher */ - typedef ApplyMatcher AuxMatcher3; - typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2; - typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2> AuxMatcher1; - AuxMatcher1 d_cgm; - static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ - Assert( pat.getKind() == kind::APPLY_CONSTRUCTOR, - "For datatypes only constructor are accepted in pattern" ); - /** In reverse order of matcher sequence */ - AuxMatcher3 am3(pat,qe); - /** Keep only the one that have the good operator */ - AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator())); - /** Iter on the equivalence class of the given term */ - datatypes::TheoryDatatypes* dt = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_DATATYPES )); - eq::EqualityEngine* ee = static_cast(dt->getEqualityEngine()); - CandidateGeneratorTheoryEeClass cdtDtEq(ee); - /* Create a matcher from the candidate generator */ - AuxMatcher1 am1(cdtDtEq,am2); - return am1; - } - Node d_pat; -public: - DatatypesMatcher( Node pat, QuantifiersEngine* qe ): - d_cgm(createCgm(pat, qe)), - d_pat(pat) {} - - void resetInstantiationRound( QuantifiersEngine* qe ){ - d_cgm.resetInstantiationRound(qe); - }; - bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ - Debug("matching") << "datatypes: " << t << " matches " << d_pat << std::endl; - return d_cgm.reset(t, m, qe); - } - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.getNextMatch(m, qe); - } -}; - -class ArrayMatcher: public Matcher{ - /* The matcher */ - typedef ApplyMatcher AuxMatcher3; - typedef TestMatcher< AuxMatcher3, LegalKindTest > AuxMatcher2; - typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2> AuxMatcher1; - AuxMatcher1 d_cgm; - static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ - Assert( pat.getKind() == kind::SELECT || pat.getKind() == kind::STORE ); - /** In reverse order of matcher sequence */ - AuxMatcher3 am3(pat,qe); - /** Keep only the one that have the good operator */ - AuxMatcher2 am2(am3, LegalKindTest(pat.getKind())); - /** Iter on the equivalence class of the given term */ - arrays::TheoryArrays* ar = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_ARRAY )); - eq::EqualityEngine* ee = - static_cast(ar->getEqualityEngine()); - CandidateGeneratorTheoryEeClass cdtUfEq(ee); - /* Create a matcher from the candidate generator */ - AuxMatcher1 am1(cdtUfEq,am2); - return am1; - } - size_t d_num_var; - Node d_pat; -public: - ArrayMatcher( Node pat, QuantifiersEngine* qe ): - d_cgm(createCgm(pat, qe)),d_num_var(numFreeVar(pat)), - d_pat(pat) {} - - void resetInstantiationRound( QuantifiersEngine* qe ){ - d_cgm.resetInstantiationRound(qe); - }; - bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ - // size_t m_size = m.d_map.size(); - // if(m_size == d_num_var){ - // uf::EqualityEngine* ee = (static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )))->getEqualityEngine(); - // std::cout << "!"; - // return ee->areEqual(m.subst(d_pat),t); - // }else{ - // std::cout << m.d_map.size() << std::endl; - return d_cgm.reset(t, m, qe); - // } - } - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.getNextMatch(m, qe); - } -}; - -class AllOpMatcher: public PatMatcher{ - /* The matcher */ - typedef ApplyMatcher AuxMatcher3; - typedef TestMatcher< AuxMatcher3, LegalTest > AuxMatcher2; - typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryUfOp, AuxMatcher2> AuxMatcher1; - AuxMatcher1 d_cgm; - static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ - Assert( pat.hasOperator() ); - /** In reverse order of matcher sequence */ - AuxMatcher3 am3(pat,qe); - /** Keep only the one that have the good operator */ - AuxMatcher2 am2(am3,LegalTest()); - /** Iter on the equivalence class of the given term */ - TermDb* tdb = qe->getTermDatabase(); - CandidateGeneratorTheoryUfOp cdtUfEq(pat.getOperator(),tdb); - /* Create a matcher from the candidate generator */ - AuxMatcher1 am1(cdtUfEq,am2); - return am1; - } - size_t d_num_var; - Node d_pat; -public: - AllOpMatcher( TNode pat, QuantifiersEngine* qe ): - d_cgm(createCgm(pat, qe)), d_num_var(numFreeVar(pat)), - d_pat(pat) {} - - void resetInstantiationRound( QuantifiersEngine* qe ){ - d_cgm.resetInstantiationRound(qe); - }; - bool reset( InstMatch& m, QuantifiersEngine* qe ){ - // std::cout << m.d_map.size() << "/" << d_num_var << std::endl; - return d_cgm.reset(Node::null(), m, qe); - } - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.getNextMatch(m, qe); - } -}; - -template /** true classes | false class */ -class GenericCandidateGeneratorClasses: public CandidateGenerator{ -private: - CandidateGenerator* d_cg; - QuantifiersEngine* d_qe; - -public: - void mkCandidateGenerator(){ - if(classes) - d_cg = d_qe->getRRCanGenClasses(); - else - d_cg = d_qe->getRRCanGenClass(); - } - - GenericCandidateGeneratorClasses(QuantifiersEngine* qe): - d_qe(qe) { - mkCandidateGenerator(); - } - ~GenericCandidateGeneratorClasses(){ - delete(d_cg); - } - const GenericCandidateGeneratorClasses & operator =(const GenericCandidateGeneratorClasses & m){ - mkCandidateGenerator(); - return m; - }; - GenericCandidateGeneratorClasses(const GenericCandidateGeneratorClasses & m): - d_qe(m.d_qe){ - mkCandidateGenerator(); - } - void resetInstantiationRound(){ - d_cg->resetInstantiationRound(); - }; - void reset( TNode eqc ){ - Assert( !classes || eqc.isNull() ); - d_cg->reset(eqc); - }; //* the argument is not used - TNode getNextCandidate(){ - return d_cg->getNextCandidate(); - }; -}; /* MetaCandidateGeneratorClasses */ - - -class GenericMatcher: public Matcher{ - /* The matcher */ - typedef ApplyMatcher AuxMatcher3; - typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2; - typedef CandidateGeneratorMatcher< GenericCandidateGeneratorClasses, AuxMatcher2> AuxMatcher1; - AuxMatcher1 d_cgm; - static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ - /** In reverse order of matcher sequence */ - AuxMatcher3 am3(pat,qe); - /** Keep only the one that have the good operator */ - AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator())); - /** Iter on the equivalence class of the given term */ - GenericCandidateGeneratorClasses cdtG(qe); - /* Create a matcher from the candidate generator */ - AuxMatcher1 am1(cdtG,am2); - return am1; - } - Node d_pat; -public: - GenericMatcher( Node pat, QuantifiersEngine* qe ): - d_cgm(createCgm(pat, qe)), - d_pat(pat) {} - - void resetInstantiationRound( QuantifiersEngine* qe ){ - d_cgm.resetInstantiationRound(qe); - }; - bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.reset(t, m, qe); - } - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.getNextMatch(m, qe); - } -}; - - -class GenericPatMatcher: public PatMatcher{ - /* The matcher */ - typedef ApplyMatcher AuxMatcher3; - typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2; - typedef CandidateGeneratorMatcher< GenericCandidateGeneratorClasses, AuxMatcher2> AuxMatcher1; - AuxMatcher1 d_cgm; - static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ - /** In reverse order of matcher sequence */ - AuxMatcher3 am3(pat,qe); - /** Keep only the one that have the good operator */ - AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator())); - /** Iter on the equivalence class of the given term */ - GenericCandidateGeneratorClasses cdtG(qe); - /* Create a matcher from the candidate generator */ - AuxMatcher1 am1(cdtG,am2); - return am1; - } - Node d_pat; -public: - GenericPatMatcher( Node pat, QuantifiersEngine* qe ): - d_cgm(createCgm(pat, qe)), - d_pat(pat) {} - - void resetInstantiationRound( QuantifiersEngine* qe ){ - d_cgm.resetInstantiationRound(qe); - }; - bool reset( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.reset(Node::null(), m, qe); - } - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.getNextMatch(m, qe); - } -}; - -class MetaCandidateGeneratorClasses: public CandidateGenerator{ -private: - CandidateGenerator* d_cg; - TypeNode d_ty; - TheoryEngine* d_te; - -public: - CandidateGenerator* mkCandidateGenerator(TypeNode ty, TheoryEngine* te){ - Debug("inst-match-gen") << "MetaCandidateGenerator for type: " << ty - << " Theory : " << Theory::theoryOf(ty) << std::endl; - if( Theory::theoryOf(ty) == theory::THEORY_DATATYPES ){ - // datatypes::TheoryDatatypes* dt = static_cast(te->getTheory( theory::THEORY_DATATYPES )); - // return new datatypes::rrinst::CandidateGeneratorTheoryClasses(dt); - Unimplemented("MetaCandidateGeneratorClasses for THEORY_DATATYPES"); - }else if ( Theory::theoryOf(ty) == theory::THEORY_ARRAY ){ - arrays::TheoryArrays* ar = static_cast(te->getTheory( theory::THEORY_ARRAY )); - eq::EqualityEngine* ee = - static_cast(ar->getEqualityEngine()); - return new CandidateGeneratorTheoryEeClasses(ee); - } else { - uf::TheoryUF* uf = static_cast(te->getTheory( theory::THEORY_UF )); - eq::EqualityEngine* ee = - static_cast(uf->getEqualityEngine()); - return new CandidateGeneratorTheoryEeClasses(ee); - } - } - MetaCandidateGeneratorClasses(TypeNode ty, TheoryEngine* te): - d_ty(ty), d_te(te) { - d_cg = mkCandidateGenerator(ty,te); - } - ~MetaCandidateGeneratorClasses(){ - delete(d_cg); - } - const MetaCandidateGeneratorClasses & operator =(const MetaCandidateGeneratorClasses & m){ - d_cg = mkCandidateGenerator(m.d_ty, m.d_te); - return m; - }; - MetaCandidateGeneratorClasses(const MetaCandidateGeneratorClasses & m): - d_ty(m.d_ty), d_te(m.d_te){ - d_cg = mkCandidateGenerator(m.d_ty, m.d_te); - } - void resetInstantiationRound(){ - d_cg->resetInstantiationRound(); - }; - void reset( TNode eqc ){ - d_cg->reset(eqc); - }; //* the argument is not used - TNode getNextCandidate(){ - return d_cg->getNextCandidate(); - }; -}; /* MetaCandidateGeneratorClasses */ - -/** Match just a variable */ -class AllVarMatcher: public PatMatcher{ -private: - /* generator */ - typedef VarMatcher AuxMatcher3; - typedef TestMatcher< AuxMatcher3, LegalTypeTest > AuxMatcher2; - typedef CandidateGeneratorMatcher< MetaCandidateGeneratorClasses, AuxMatcher2 > AuxMatcher1; - AuxMatcher1 d_cgm; - static inline AuxMatcher1 createCgm(TNode pat, QuantifiersEngine* qe){ - Assert( pat.getKind()==INST_CONSTANT ); - TypeNode ty = pat.getType(); - Debug("inst-match-gen") << "create AllVarMatcher for type: " << ty << std::endl; - /** In reverse order of matcher sequence */ - /** Distribute it to all the pattern */ - AuxMatcher3 am3(pat,qe); - /** Keep only the one that have the good type */ - AuxMatcher2 am2(am3,LegalTypeTest(ty)); - /** Generate one term by eq classes */ - MetaCandidateGeneratorClasses mcdt(ty,qe->getTheoryEngine()); - /* Create a matcher from the candidate generator */ - AuxMatcher1 am1(mcdt,am2); - return am1; - } -public: - AllVarMatcher( TNode pat, QuantifiersEngine* qe ): - d_cgm(createCgm(pat, qe)){} - - void resetInstantiationRound( QuantifiersEngine* qe ){ - d_cgm.resetInstantiationRound(qe); - }; - bool reset( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.reset(Node::null(), m, qe); //cdtUfEq doesn't use it's argument for reset - } - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.getNextMatch(m, qe); - } -}; - -/** Match all the pattern with the same term */ -class SplitMatcher: public Matcher{ -private: - const size_t size; - ApplyMatcher d_m; /** Use ApplyMatcher by creating a fake application */ -public: - SplitMatcher(std::vector< Node > pats, QuantifiersEngine* qe): - size(pats.size()), - d_m(NodeManager::currentNM()->mkNode(kind::INST_PATTERN,pats), qe) {} - void resetInstantiationRound( QuantifiersEngine* qe ){ - d_m.resetInstantiationRound(qe); - }; - bool reset( TNode ex, InstMatch& m, QuantifiersEngine* qe ){ - NodeBuilder<> n(kind::INST_PATTERN); - for(size_t i = 0; i < size; ++i) n << ex; - Node nn = n; - return d_m.reset(nn,m,qe); - }; - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - return getNextMatch(m, qe); - } -}; - - -/** Match uf term in a fixed equivalence class */ -class UfCstEqMatcher: public PatMatcher{ -private: - /* equivalence class to match */ - Node d_cst; - /* generator */ - OpMatcher d_cgm; -public: - UfCstEqMatcher( Node pat, Node cst, QuantifiersEngine* qe ): - d_cst(cst), - d_cgm(OpMatcher(pat,qe)) {}; - void resetInstantiationRound( QuantifiersEngine* qe ){ - d_cgm.resetInstantiationRound(qe); - }; - bool reset( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.reset(d_cst, m, qe); - } - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.getNextMatch(m, qe); - } -}; - -/** Match equalities */ -class UfEqMatcher: public PatMatcher{ -private: - /* generator */ - typedef SplitMatcher AuxMatcher3; - typedef TestMatcher< AuxMatcher3, LegalTypeTest > AuxMatcher2; - typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClasses, AuxMatcher2 > AuxMatcher1; - AuxMatcher1 d_cgm; - static inline AuxMatcher1 createCgm(std::vector & pat, QuantifiersEngine* qe){ - Assert( pat.size() > 0); - TypeNode ty = pat[0].getType(); - for(size_t i = 1; i < pat.size(); ++i){ - Assert(pat[i].getType() == ty); - } - /** In reverse order of matcher sequence */ - /** Distribute it to all the pattern */ - AuxMatcher3 am3(pat,qe); - /** Keep only the one that have the good type */ - AuxMatcher2 am2(am3,LegalTypeTest(ty)); - /** Generate one term by eq classes */ - uf::TheoryUF* uf = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )); - eq::EqualityEngine* ee = - static_cast(uf->getEqualityEngine()); - CandidateGeneratorTheoryEeClasses cdtUfEq(ee); - /* Create a matcher from the candidate generator */ - AuxMatcher1 am1(cdtUfEq,am2); - return am1; - } -public: - UfEqMatcher( std::vector & pat, QuantifiersEngine* qe ): - d_cgm(createCgm(pat, qe)){} - - void resetInstantiationRound( QuantifiersEngine* qe ){ - d_cgm.resetInstantiationRound(qe); - }; - bool reset( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.reset(Node::null(), m, qe); //cdtUfEq doesn't use it's argument for reset - } - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.getNextMatch(m, qe); - } -}; - - -/** Match dis-equalities */ -class UfDeqMatcher: public PatMatcher{ -private: - /* generator */ - typedef ApplyMatcher AuxMatcher3; - - class EqTest/* : public unary_function*/ { - TypeNode d_type; - public: - inline EqTest(TypeNode type): d_type(type){}; - inline bool operator() (Node n) { - return - CandidateGenerator::isLegalCandidate(n) && - n.getKind() == kind::EQUAL && - n[0].getType()==d_type; - }; - }; - typedef TestMatcher< AuxMatcher3, EqTest > AuxMatcher2; - typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2 > AuxMatcher1; - AuxMatcher1 d_cgm; - Node false_term; - static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){ - Assert( pat.getKind() == kind::NOT); - TNode eq = pat[0]; - Assert( eq.getKind() == kind::EQUAL); - TypeNode ty = eq[0].getType(); - /** In reverse order of matcher sequence */ - /** Distribute it to all the pattern */ - AuxMatcher3 am3(eq,qe); - /** Keep only the one that have the good type */ - AuxMatcher2 am2(am3,EqTest(ty)); - /** Will generate all the terms of the eq class of false */ - uf::TheoryUF* uf = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )); - eq::EqualityEngine* ee = - static_cast(uf->getEqualityEngine()); - CandidateGeneratorTheoryEeClass cdtUfEq(ee); - /* Create a matcher from the candidate generator */ - AuxMatcher1 am1(cdtUfEq,am2); - return am1; - } -public: - UfDeqMatcher( Node pat, QuantifiersEngine* qe ): - d_cgm(createCgm(pat, qe)), - false_term((static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )))->getEqualityEngine()-> - getRepresentative(NodeManager::currentNM()->mkConst(false) )){}; - void resetInstantiationRound( QuantifiersEngine* qe ){ - d_cgm.resetInstantiationRound(qe); - }; - bool reset( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.reset(false_term, m, qe); - } - bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - return d_cgm.getNextMatch(m, qe); - } -}; - -Matcher* mkMatcher( Node pat, QuantifiersEngine* qe ){ - Debug("inst-match-gen") << "mkMatcher: Pattern term is " << pat << std::endl; - - // if( pat.getKind() == kind::APPLY_UF){ - // return new OpMatcher(pat, qe); - // } else if( pat.getKind() == kind::APPLY_CONSTRUCTOR ){ - // return new DatatypesMatcher(pat, qe); - // } else if( pat.getKind() == kind::SELECT || pat.getKind() == kind::STORE ){ - // return new ArrayMatcher(pat, qe); - if( pat.getKind() == kind::APPLY_UF || - pat.getKind() == kind::APPLY_CONSTRUCTOR || - pat.getKind() == kind::SELECT || pat.getKind() == kind::STORE ){ - return new GenericMatcher(pat, qe); - } else { /* Arithmetic? */ - /** TODO: something simpler to see if the pattern is a good - arithmetic pattern */ - std::map< Node, Node > d_arith_coeffs; - if( !Trigger::getPatternArithmetic( pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) ){ - Message() << "(?) Unknown matching pattern is " << pat << std::endl; - Unimplemented("pattern not implemented"); - return new DumbMatcher(); - }else{ - Debug("matching-arith") << "Generated arithmetic pattern for " << pat << ": " << std::endl; - for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ - Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; - } - ArithMatcher am3 (pat, qe); - TestMatcher - am2(am3,LegalTypeTest(pat.getType())); - /* generator */ - uf::TheoryUF* uf = static_cast(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )); - eq::EqualityEngine* ee = - static_cast (uf->getEqualityEngine()); - CandidateGeneratorTheoryEeClass cdtUfEq(ee); - return new CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, - TestMatcher > (cdtUfEq,am2); - } - } -}; - -PatMatcher* mkPattern( Node pat, QuantifiersEngine* qe ){ - Debug("inst-match-gen") << "Pattern term is " << pat << std::endl; - Assert( pat.hasAttribute(InstConstantAttribute()) ); - - if( pat.getKind()==kind::NOT && pat[0].getKind() == kind::EQUAL){ - /* Difference */ - return new UfDeqMatcher(pat, qe); - } else if (pat.getKind() == kind::EQUAL){ - if( !pat[0].hasAttribute(InstConstantAttribute() )){ - Assert(pat[1].hasAttribute(InstConstantAttribute())); - return new UfCstEqMatcher(pat[1], pat[0], qe); - }else if( !pat[1].hasAttribute(InstConstantAttribute() )){ - Assert(pat[0].hasAttribute(InstConstantAttribute())); - return new UfCstEqMatcher(pat[0], pat[1], qe); - }else{ - std::vector< Node > pats(pat.begin(),pat.end()); - return new UfEqMatcher(pats,qe); - } - } else if( Trigger::isAtomicTrigger( pat ) ){ - return new AllOpMatcher(pat, qe); - // return new GenericPatMatcher(pat, qe); - } else if( pat.getKind()==INST_CONSTANT ){ - // just a variable - return new AllVarMatcher(pat, qe); - } else { /* Arithmetic? */ - /** TODO: something simpler to see if the pattern is a good - arithmetic pattern */ - std::map< Node, Node > d_arith_coeffs; - if( !Trigger::getPatternArithmetic( pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) ){ - Debug("inst-match-gen") << "(?) Unknown matching pattern is " << pat << std::endl; - Message() << "(?) Unknown matching pattern is " << pat << std::endl; - return new DumbPatMatcher(); - }else{ - Debug("matching-arith") << "Generated arithmetic pattern for " << pat << ": " << std::endl; - for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ - Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; - } - ArithMatcher am3 (pat, qe); - TestMatcher - am2(am3,LegalTest()); - /* generator */ - TermDb* tdb = qe->getTermDatabase(); - CandidateGeneratorTheoryUfType cdtUfEq(pat.getType(),tdb); - typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryUfType, - TestMatcher > AuxMatcher1; - return new PatOfMatcher(AuxMatcher1(cdtUfEq,am2)); - } - } -}; - -ArithMatcher::ArithMatcher(Node pat, QuantifiersEngine* qe): d_pattern(pat){ - - if(Trigger::getPatternArithmetic(pat.getAttribute(InstConstantAttribute()), pat, d_arith_coeffs ) ) - { - Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_pattern << std::endl; - Assert(false); - }else{ - Debug("matching-arith") << "Generated arithmetic pattern for " << d_pattern << ": " << std::endl; - for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ - Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl; - } - } - -}; - -bool ArithMatcher::reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){ - Debug("matching-arith") << "Matching " << t << " " << d_pattern << std::endl; - d_binded.clear(); - if( !d_arith_coeffs.empty() ){ - NodeBuilder<> tb(kind::PLUS); - Node ic = Node::null(); - for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ - Debug("matching-arith") << it->first << " -> " << it->second << std::endl; - if( !it->first.isNull() ){ - if( m.find( it->first )==m.end() ){ - //see if we can choose this to set - if( ic.isNull() && ( it->second.isNull() || !it->first.getType().isInteger() ) ){ - ic = it->first; - } - }else{ - Debug("matching-arith") << "already set " << m.get( it->first ) << std::endl; - Node tm = m.get( it->first ); - if( !it->second.isNull() ){ - tm = NodeManager::currentNM()->mkNode( MULT, it->second, tm ); - } - tb << tm; - } - }else{ - tb << it->second; - } - } - if( !ic.isNull() ){ - Node tm; - if( tb.getNumChildren()==0 ){ - tm = t; - }else{ - tm = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb; - tm = NodeManager::currentNM()->mkNode( MINUS, t, tm ); - } - if( !d_arith_coeffs[ ic ].isNull() ){ - Assert( !ic.getType().isInteger() ); - Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst() ); - tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm ); - } - m.set( ic, Rewriter::rewrite( tm )); - d_binded.push_back(ic); - //set the rest to zeros - for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){ - if( !it->first.isNull() ){ - if( m.find( it->first )==m.end() ){ - m.set( it->first, NodeManager::currentNM()->mkConst( Rational(0) )); - d_binded.push_back(ic); - } - } - } - Debug("matching-arith") << "Setting " << ic << " to " << tm << std::endl; - return true; - }else{ - m.erase(d_binded.begin(), d_binded.end()); - return false; - } - }else{ - m.erase(d_binded.begin(), d_binded.end()); - return false; - } -}; - -bool ArithMatcher::getNextMatch( InstMatch& m, QuantifiersEngine* qe ){ - m.erase(d_binded.begin(), d_binded.end()); - return false; -}; - - -class MultiPatsMatcher: public PatsMatcher{ -private: - bool d_reset_done; - std::vector< PatMatcher* > d_patterns; - InstMatch d_im; - bool reset( QuantifiersEngine* qe ){ - d_im.clear(); - d_reset_done = true; - - return getNextMatch(qe,true); - }; - - bool getNextMatch(QuantifiersEngine* qe, bool reset){ - const size_t max = d_patterns.size() - 1; - size_t index = reset ? 0 : max; - while(true){ - Debug("matching") << "MultiPatsMatcher::index " << index << "/" - << max << (reset ? " reset_phase" : "") << std::endl; - if(reset ? - d_patterns[index]->reset( d_im, qe ) : - d_patterns[index]->getNextMatch( d_im, qe )){ - if(index==max) return true; - ++index; - reset=true; - }else{ - if(index==0) return false; - --index; - reset=false; - }; - } - } - -public: - MultiPatsMatcher(std::vector< Node > & pats, QuantifiersEngine* qe): - d_reset_done(false){ - Assert(pats.size() > 0); - for( size_t i=0; i< pats.size(); i++ ){ - d_patterns.push_back(mkPattern(pats[i],qe)); - }; - }; - void resetInstantiationRound( QuantifiersEngine* qe ){ - for( size_t i=0; i< d_patterns.size(); i++ ){ - d_patterns[i]->resetInstantiationRound( qe ); - }; - d_reset_done = false; - d_im.clear(); - }; - bool getNextMatch( QuantifiersEngine* qe ){ - Assert(d_patterns.size()>0); - if(d_reset_done) return getNextMatch(qe,false); - else return reset(qe); - } - const InstMatch& getInstMatch(){return d_im;}; - - int addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe); -}; - -enum EffiStep{ - ES_STOP, - ES_GET_MONO_CANDIDATE, - ES_GET_MULTI_CANDIDATE, - ES_RESET1, - ES_RESET2, - ES_NEXT1, - ES_NEXT2, - ES_RESET_OTHER, - ES_NEXT_OTHER, -}; -static inline std::ostream& operator<<(std::ostream& out, const EffiStep& step) { - switch(step){ - case ES_STOP: out << "STOP"; break; - case ES_GET_MONO_CANDIDATE: out << "GET_MONO_CANDIDATE"; break; - case ES_GET_MULTI_CANDIDATE: out << "GET_MULTI_CANDIDATE"; break; - case ES_RESET1: out << "RESET1"; break; - case ES_RESET2: out << "RESET2"; break; - case ES_NEXT1: out << "NEXT1"; break; - case ES_NEXT2: out << "NEXT2"; break; - case ES_RESET_OTHER: out << "RESET_OTHER"; break; - case ES_NEXT_OTHER: out << "NEXT_OTHER"; break; - } - return out; -} - - -int MultiPatsMatcher::addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe){ - //now, try to add instantiation for each match produced - int addedLemmas = 0; - resetInstantiationRound( qe ); - d_im.add( baseMatch ); - while( getNextMatch( qe ) ){ - InstMatch im_copy = getInstMatch(); - //m.makeInternal( d_quantEngine->getEqualityQuery() ); - if( qe->addInstantiation( quant, im_copy ) ){ - addedLemmas++; - } - } - //return number of lemmas added - return addedLemmas; -} - -PatsMatcher* mkPatterns( std::vector< Node > pat, QuantifiersEngine* qe ){ - return new MultiPatsMatcher( pat, qe); -} - -class MultiEfficientPatsMatcher: public PatsMatcher{ -private: - bool d_phase_mono; - bool d_phase_new_term; - std::vector< PatMatcher* > d_patterns; - std::vector< Matcher* > d_direct_patterns; - InstMatch d_im; - uf::EfficientHandler d_eh; - uf::EfficientHandler::MultiCandidate d_mc; - InstMatchTrie2Pairs d_cache; - std::vector d_pats; - // bool indexDone( size_t i){ - // return i == d_c.first.second || - // ( i == d_c.second.second && d_c.second.first.empty()); - // } - - - - static const EffiStep ES_START = ES_GET_MONO_CANDIDATE; - EffiStep d_step; - - //return true if it becomes bigger than d_patterns.size() - 1 - bool incrIndex(size_t & index){ - if(index == d_patterns.size() - 1) return true; - ++index; - if(index == d_mc.first.second - || (!d_phase_mono && index == d_mc.second.second)) - return incrIndex(index); - else return false; - } - - //return true if it becomes smaller than 0 - bool decrIndex(size_t & index){ - if(index == 0) return true; - --index; - if(index == d_mc.first.second - || (!d_phase_mono && index == d_mc.second.second)) - return decrIndex(index); - else return false; - } - - bool resetOther( QuantifiersEngine* qe ){ - return getNextMatchOther(qe,true); - }; - - - bool getNextMatchOther(QuantifiersEngine* qe, bool reset){ - size_t index = reset ? 0 : d_patterns.size(); - if(!reset && decrIndex(index)) return false; - if( reset && - (index == d_mc.first.second - || (!d_phase_mono && index == d_mc.second.second)) - && incrIndex(index)) return true; - while(true){ - Debug("matching") << "MultiEfficientPatsMatcher::index " << index << "/" - << d_patterns.size() - 1 << std::endl; - if(reset ? - d_patterns[index]->reset( d_im, qe ) : - d_patterns[index]->getNextMatch( d_im, qe )){ - if(incrIndex(index)) return true; - reset=true; - }else{ - if(decrIndex(index)) return false; - reset=false; - }; - } - } - - inline EffiStep TestMonoCache(QuantifiersEngine* qe){ - if( //!d_phase_new_term || - d_pats.size() == 1) return ES_RESET_OTHER; - if(d_cache.addInstMatch(d_mc.first.second,d_im)){ - Debug("inst-match::cache") << "Cache miss" << d_im << std::endl; - ++qe->d_statistics.d_mono_candidates_cache_miss; - return ES_RESET_OTHER; - } else { - Debug("inst-match::cache") << "Cache hit" << d_im << std::endl; - ++qe->d_statistics.d_mono_candidates_cache_hit; - return ES_NEXT1; - } - // ++qe->d_statistics.d_mono_candidates_cache_miss; - // return ES_RESET_OTHER; - } - - inline EffiStep TestMultiCache(QuantifiersEngine* qe){ - if(d_cache.addInstMatch(d_mc.first.second,d_mc.second.second,d_im)){ - ++qe->d_statistics.d_multi_candidates_cache_miss; - return ES_RESET_OTHER; - } else { - ++qe->d_statistics.d_multi_candidates_cache_hit; - return ES_NEXT2; - } - } - - -public: - - bool getNextMatch( QuantifiersEngine* qe ){ - Assert( d_step == ES_START || d_step == ES_NEXT_OTHER || d_step == ES_STOP ); - while(true){ - Debug("matching") << "d_step=" << d_step << " " - << "d_im=" << d_im << std::endl; - switch(d_step){ - case ES_GET_MONO_CANDIDATE: - Assert(d_im.empty()); - if(d_phase_new_term ? d_eh.getNextMonoCandidate(d_mc.first) : d_eh.getNextMonoCandidateNewTerm(d_mc.first)){ - if(d_phase_new_term) ++qe->d_statistics.d_num_mono_candidates_new_term; - else ++qe->d_statistics.d_num_mono_candidates; - d_phase_mono = true; - d_step = ES_RESET1; - } else if (!d_phase_new_term){ - d_phase_new_term = true; - d_step = ES_GET_MONO_CANDIDATE; - } else { - d_phase_new_term = false; - d_step = ES_GET_MULTI_CANDIDATE; - } - break; - case ES_GET_MULTI_CANDIDATE: - Assert(d_im.empty()); - if(d_eh.getNextMultiCandidate(d_mc)){ - ++qe->d_statistics.d_num_multi_candidates; - d_phase_mono = false; - d_step = ES_RESET1; - } else d_step = ES_STOP; - break; - case ES_RESET1: - if(d_direct_patterns[d_mc.first.second]->reset(d_mc.first.first,d_im,qe)) - d_step = d_phase_mono ? TestMonoCache(qe) : ES_RESET2; - else d_step = d_phase_mono ? ES_GET_MONO_CANDIDATE : ES_GET_MULTI_CANDIDATE; - break; - case ES_RESET2: - Assert(!d_phase_mono); - if(d_direct_patterns[d_mc.second.second]->reset(d_mc.second.first,d_im,qe)) - d_step = TestMultiCache(qe); - else d_step = ES_NEXT1; - break; - case ES_NEXT1: - if(d_direct_patterns[d_mc.first.second]->getNextMatch(d_im,qe)) - d_step = d_phase_mono ? TestMonoCache(qe) : ES_RESET2; - else d_step = d_phase_mono ? ES_GET_MONO_CANDIDATE : ES_GET_MULTI_CANDIDATE; - break; - case ES_NEXT2: - if(d_direct_patterns[d_mc.second.second]->getNextMatch(d_im,qe)) - d_step = TestMultiCache(qe); - else d_step = ES_NEXT1; - break; - case ES_RESET_OTHER: - if(resetOther(qe)){ - d_step = ES_NEXT_OTHER; - return true; - } else d_step = d_phase_mono ? ES_NEXT1 : ES_NEXT2; - break; - case ES_NEXT_OTHER: - { - if(!getNextMatchOther(qe,false)){ - d_step = d_phase_mono ? ES_NEXT1 : ES_NEXT2; - }else{ - d_step = ES_NEXT_OTHER; - return true; - } - } - break; - case ES_STOP: - Assert(d_im.empty()); - return false; - } - } - } - - MultiEfficientPatsMatcher(std::vector< Node > & pats, QuantifiersEngine* qe): - d_eh(qe->getTheoryEngine()->getSatContext()), - d_cache(qe->getTheoryEngine()->getSatContext(),qe,pats.size()), - d_pats(pats), d_step(ES_START) { - Assert(pats.size() > 0); - for( size_t i=0; i< pats.size(); i++ ){ - d_patterns.push_back(mkPattern(pats[i],qe)); - if(pats[i].getKind()==kind::INST_CONSTANT){ - d_direct_patterns.push_back(new VarMatcher(pats[i],qe)); - } else if( pats[i].getKind() == kind::NOT && pats[i][0].getKind() == kind::EQUAL){ - d_direct_patterns.push_back(new ApplyMatcher(pats[i][0],qe)); - } else { - d_direct_patterns.push_back(new ApplyMatcher(pats[i],qe)); - } - }; - Theory* th_uf = qe->getTheoryEngine()->getTheory( theory::THEORY_UF ); - uf::InstantiatorTheoryUf* ith = (uf::InstantiatorTheoryUf*)th_uf->getInstantiator(); - ith->registerEfficientHandler(d_eh, pats); - }; - void resetInstantiationRound( QuantifiersEngine* qe ){ - Assert(d_step == ES_START || d_step == ES_STOP); - for( size_t i=0; i< d_patterns.size(); i++ ){ - d_patterns[i]->resetInstantiationRound( qe ); - d_direct_patterns[i]->resetInstantiationRound( qe ); - }; - d_step = ES_START; - d_phase_new_term = false; - Assert(d_im.empty()); - }; - - const InstMatch& getInstMatch(){return d_im;}; - - int addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe); -}; - -int MultiEfficientPatsMatcher::addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe){ - //now, try to add instantiation for each match produced - int addedLemmas = 0; - Assert(baseMatch.empty()); - resetInstantiationRound( qe ); - while( getNextMatch( qe ) ){ - InstMatch im_copy = getInstMatch(); - //m.makeInternal( d_quantEngine->getEqualityQuery() ); - if( qe->addInstantiation( quant, im_copy ) ){ - addedLemmas++; - } - } - //return number of lemmas added - return addedLemmas; -}; - -PatsMatcher* mkPatternsEfficient( std::vector< Node > pat, QuantifiersEngine* qe ){ - return new MultiEfficientPatsMatcher( pat, qe); -} - -} /* CVC4::theory::rrinst */ -} /* CVC4::theory */ -} /* CVC4 */ diff --git a/src/theory/rr_inst_match.h b/src/theory/rr_inst_match.h deleted file mode 100644 index 468fe6a89..000000000 --- a/src/theory/rr_inst_match.h +++ /dev/null @@ -1,266 +0,0 @@ -/********************* */ -/*! \file rr_inst_match.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: bobot - ** Minor contributors (to current version): mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief inst match class - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__RR_INST_MATCH_H -#define __CVC4__RR_INST_MATCH_H - -#include "theory/theory.h" -#include "util/hash.h" -#include "util/ntuple.h" - -#include -#include -#include - -#include "theory/uf/equality_engine.h" -#include "theory/uf/theory_uf.h" -#include "context/cdlist.h" - -#include "theory/inst_match.h" -#include "expr/node_manager.h" -#include "expr/node_builder.h" - -#include "theory/quantifiers/options.h" -#include "theory/rewriterules/options.h" - -//#define USE_EFFICIENT_E_MATCHING - -namespace CVC4 { -namespace theory { - -namespace rrinst{ - -class CandidateGenerator -{ -public: - CandidateGenerator(){} - virtual ~CandidateGenerator(){}; - - /** Get candidates functions. These set up a context to get all match candidates. - cg->reset( eqc ); - do{ - Node cand = cg->getNextCandidate(); - //....... - }while( !cand.isNull() ); - - eqc is the equivalence class you are searching in - */ - virtual void reset( TNode eqc ) = 0; - virtual TNode getNextCandidate() = 0; - /** call this at the beginning of each instantiation round */ - virtual void resetInstantiationRound() = 0; -public: - /** legal candidate */ - static inline bool isLegalCandidate( TNode n ){ - return !n.getAttribute(NoMatchAttribute()) && - ( !options::cbqi() || !n.hasAttribute(InstConstantAttribute())) && - ( !options::efficientEMatching() || n.hasAttribute(AvailableInTermDb()) ); -} - -}; - - -inline std::ostream& operator<<(std::ostream& out, const InstMatch& m) { - m.toStream(out); - return out; -} - -template class InstMatchTrie2; -template class InstMatchTrie2Pairs; - -template -class InstMatchTrie2Gen -{ - friend class InstMatchTrie2; - friend class InstMatchTrie2Pairs; - -private: - - class Tree { - public: - typedef std::hash_map< Node, Tree *, NodeHashFunction > MLevel; - MLevel e; - const size_t level; //context level of creation - Tree() CVC4_UNDEFINED; - const Tree & operator =(const Tree & t){ - Assert(t.e.empty()); Assert(e.empty()); - Assert(t.level == level); - return t; - } - Tree(size_t l): level(l) {}; - ~Tree(){ - for(typename MLevel::iterator i = e.begin(); i!=e.end(); ++i) - delete(i->second); - }; - }; - - - typedef std::pair Mod; - - class CleanUp{ - public: - inline void operator()(Mod * m){ - typename Tree::MLevel::iterator i = m->first->e.find(m->second); - Assert (i != m->first->e.end()); //should not have been already removed - m->first->e.erase(i); - }; - }; - - EqualityQuery* d_eQ; - CandidateGenerator * d_cG; - - context::Context* d_context; - context::CDList > d_mods; - - - typedef std::map::const_iterator mapIter; - - /** add the substitution given by the iterator*/ - void addSubTree( Tree * root, mapIter current, mapIter end, size_t currLevel); - /** test if it exists match, modulo uf-equations if modEq is true if - * return false the deepest point of divergence is put in [e] and - * [diverge]. - */ - bool existsInstMatch( Tree * root, - mapIter & current, mapIter & end, - Tree * & e, mapIter & diverge) const; - - /** add match m in the trie root - return true if it was never seen */ - bool addInstMatch( InstMatch& m, Tree * root); - -public: - InstMatchTrie2Gen(context::Context* c, QuantifiersEngine* q); - InstMatchTrie2Gen(const InstMatchTrie2Gen &) CVC4_UNDEFINED; - const InstMatchTrie2Gen & operator =(const InstMatchTrie2Gen & e) CVC4_UNDEFINED; -}; - -template -class InstMatchTrie2 -{ - typename InstMatchTrie2Gen::Tree d_data; - InstMatchTrie2Gen d_backtrack; -public: - InstMatchTrie2(context::Context* c, QuantifiersEngine* q): d_data(0), - d_backtrack(c,q) {}; - InstMatchTrie2(const InstMatchTrie2 &) CVC4_UNDEFINED; - const InstMatchTrie2 & operator =(const InstMatchTrie2 & e) CVC4_UNDEFINED; - /** add match m in the trie, - return true if it was never seen */ - inline bool addInstMatch( InstMatch& m){ - return d_backtrack.addInstMatch(m,&d_data); - }; - -};/* class InstMatchTrie2 */ - -class Matcher -{ -public: - /** reset instantiation round (call this whenever equivalence classes have changed) */ - virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0; - /** reset the term to match, return false if there is no such term */ - virtual bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ) = 0; - /** get the next match. If it return false once you shouldn't call - getNextMatch again before doing a reset */ - virtual bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) = 0; - /** If reset, or getNextMatch return false they remove from the - InstMatch the binding that they have previously created */ - - /** virtual Matcher in order to have definned behavior */ - virtual ~Matcher(){}; -}; - - -class ApplyMatcher: public Matcher{ -private: - /** What to check first: constant and variable */ - std::vector< triple< TNode,size_t,EqualityQuery* > > d_constants; - std::vector< triple< TNode,size_t,EqualityQuery* > > d_variables; - /** children generators, only the sub-pattern which are - neither a variable neither a constant appears */ - std::vector< triple< Matcher*, size_t, EqualityQuery* > > d_childrens; - /** the variable that have been set by this matcher (during its own reset) */ - std::vector< TNode > d_binded; /* TNode because the variable are already in d_pattern */ - /** the representant of the argument of the term given by the last reset */ - std::vector< Node > d_reps; -public: - /** The pattern we are producing matches for */ - Node d_pattern; -public: - /** constructors */ - ApplyMatcher( Node pat, QuantifiersEngine* qe); - /** destructor */ - ~ApplyMatcher(){/*TODO delete dandling pointers? */} - /** reset instantiation round (call this whenever equivalence classes have changed) */ - void resetInstantiationRound( QuantifiersEngine* qe ); - /** reset the term to match */ - bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ); - /** get the next match. */ - bool getNextMatch(InstMatch& m, QuantifiersEngine* qe); -private: - bool getNextMatch(InstMatch& m, QuantifiersEngine* qe, bool reset); -}; - - -/* Match literal so you don't choose the equivalence class( */ -class PatMatcher -{ -public: - /** reset instantiation round (call this whenever equivalence classes have changed) */ - virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0; - /** reset the matcher, return false if there is no such term */ - virtual bool reset( InstMatch& m, QuantifiersEngine* qe ) = 0; - /** get the next match. If it return false once you shouldn't call - getNextMatch again before doing a reset */ - virtual bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) = 0; - /** If reset, or getNextMatch return false they remove from the - InstMatch the binding that they have previously created */ -}; - -Matcher* mkMatcher( Node pat, QuantifiersEngine* qe ); -PatMatcher* mkPattern( Node pat, QuantifiersEngine* qe ); - -/* Match literal so you don't choose the equivalence class( */ -class PatsMatcher -{ -public: - /** reset instantiation round (call this whenever equivalence classes have changed) */ - virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0; - /** reset the matcher, return false if there is no such term */ - virtual bool getNextMatch( QuantifiersEngine* qe ) = 0; - virtual const InstMatch& getInstMatch() = 0; - /** Add directly the instantiation to quantifiers engine */ - virtual int addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe) = 0; -}; - -PatsMatcher* mkPatterns( std::vector< Node > pat, QuantifiersEngine* qe ); -PatsMatcher* mkPatternsEfficient( std::vector< Node > pat, QuantifiersEngine* qe ); - -/** return true if whatever Node is subsituted for the variables the - given Node can't match the pattern */ -bool nonunifiable( TNode t, TNode pat, const std::vector & vars); - -class InstMatchGenerator; - -}/* CVC4::theory rrinst */ - -}/* CVC4::theory namespace */ - -}/* CVC4 namespace */ - -#endif /* __CVC4__RR_INST_MATCH_H */ diff --git a/src/theory/rr_inst_match_impl.h b/src/theory/rr_inst_match_impl.h deleted file mode 100644 index 4bf04cb96..000000000 --- a/src/theory/rr_inst_match_impl.h +++ /dev/null @@ -1,128 +0,0 @@ -/********************* */ -/*! \file rr_inst_match_impl.h - ** \verbatim - ** Original author: bobot - ** Major contributors: none - ** Minor contributors (to current version): ajreynol, mdeters - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief inst match class - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__RR_INST_MATCH_IMPL_H -#define __CVC4__RR_INST_MATCH_IMPL_H - -#include "theory/rr_inst_match.h" -#include "theory/theory_engine.h" -#include "theory/quantifiers_engine.h" -#include "theory/rr_candidate_generator.h" -#include "theory/uf/equality_engine.h" - -namespace CVC4 { -namespace theory { -namespace rrinst { - -template -InstMatchTrie2Gen::InstMatchTrie2Gen(context::Context* c, QuantifiersEngine* qe): - d_context(c), d_mods(c) { - d_eQ = qe->getEqualityQuery(); - d_cG = qe->getRRCanGenClass(); -}; - -/** add match m for quantifier f starting at index, take into account equalities q, return true if successful */ -template -void InstMatchTrie2Gen::addSubTree( Tree * root, mapIter current, mapIter end, size_t currLevel ) { - if( current == end ) return; - - Assert(root->e.find(current->second) == root->e.end()); - Tree * root2 = new Tree(currLevel); - root->e.insert(std::make_pair(current->second, root2)); - addSubTree(root2, ++current, end, currLevel ); -} - -/** exists match */ -template -bool InstMatchTrie2Gen::existsInstMatch(InstMatchTrie2Gen::Tree * root, - mapIter & current, mapIter & end, - Tree * & e, mapIter & diverge) const{ - if( current == end ) { - Debug("Trie2") << "Trie2 Bottom " << std::endl; - --current; - return true; - }; //Already their - - if (current->first > diverge->first){ - // this point is the deepest point currently seen map are ordered - e = root; - diverge = current; - }; - - TNode n = current->second; - typename InstMatchTrie2Gen::Tree::MLevel::iterator it = - root->e.find( n ); - if( it!=root->e.end() && - existsInstMatch( (*it).second, ++current, end, e, diverge) ){ - Debug("Trie2") << "Trie2 Directly here " << n << std::endl; - --current; - return true; - } - Assert( it==root->e.end() || e != root ); - - // Even if n is in the trie others of the equivalence class - // can also be in it since the equality can have appeared - // after they have been added - if( modEq && d_eQ->hasTerm( n ) ){ - //check modulo equality if any other instantiation match exists - d_cG->reset( d_eQ->getRepresentative( n ) ); - for(TNode en = d_cG->getNextCandidate() ; !en.isNull() ; - en = d_cG->getNextCandidate() ){ - if( en == n ) continue; // already tested - typename InstMatchTrie2Gen::Tree::MLevel::iterator itc = - root->e.find( en ); - if( itc!=root->e.end() && - existsInstMatch( (*itc).second, ++current, end, e, diverge) ){ - Debug("Trie2") << "Trie2 Indirectly here by equality " << n << " = " << en << std::endl; - --current; - return true; - } - Assert( itc==root->e.end() || e != root ); - } - } - --current; - return false; -} - -template -bool InstMatchTrie2Gen:: -addInstMatch( InstMatch& m, InstMatchTrie2Gen::Tree* e ) { - d_cG->resetInstantiationRound(); - mapIter begin = m.begin(); - mapIter end = m.end(); - mapIter diverge = begin; - if( !existsInstMatch(e, begin, end, e, diverge ) ){ - Assert(!diverge->second.isNull()); - size_t currLevel = d_context->getLevel(); - addSubTree( e, diverge, end, currLevel ); - if(e->level != currLevel) - //If same level that e, will be removed at the same time than e - d_mods.push_back(std::make_pair(e,diverge->second)); - return true; - }else{ - return false; - } -} - -}/* CVC4::theory::rrinst namespace */ - -}/* CVC4::theory namespace */ - -}/* CVC4 namespace */ - -#endif /* __CVC4__RR_INST_MATCH_IMPL_H */ diff --git a/src/theory/rr_trigger.cpp b/src/theory/rr_trigger.cpp deleted file mode 100644 index 5d56147e8..000000000 --- a/src/theory/rr_trigger.cpp +++ /dev/null @@ -1,523 +0,0 @@ -/********************* */ -/*! \file rr_trigger.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: mdeters - ** Minor contributors (to current version): bobot - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Implementation of trigger class - **/ - -#include "theory/rr_trigger.h" -#include "theory/theory_engine.h" -#include "theory/quantifiers_engine.h" -#include "theory/uf/theory_uf_instantiator.h" -#include "theory/rr_candidate_generator.h" -#include "theory/uf/equality_engine.h" - -using namespace std; -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::context; -using namespace CVC4::theory; -using namespace CVC4::theory::rrinst; - -//#define NESTED_PATTERN_SELECTION - -Trigger* Trigger::TrTrie::getTrigger2( std::vector< Node >& nodes ){ - if( nodes.empty() ){ - return d_tr; - }else{ - Node n = nodes.back(); - nodes.pop_back(); - if( d_children.find( n )!=d_children.end() ){ - return d_children[n]->getTrigger2( nodes ); - }else{ - return NULL; - } - } -} -void Trigger::TrTrie::addTrigger2( std::vector< Node >& nodes, Trigger* t ){ - if( nodes.empty() ){ - d_tr = t; - }else{ - Node n = nodes.back(); - nodes.pop_back(); - if( d_children.find( n )==d_children.end() ){ - d_children[n] = new TrTrie; - } - d_children[n]->addTrigger2( nodes, t ); - } -} - -/** trigger static members */ -std::map< Node, std::vector< Node > > Trigger::d_var_contains; -int Trigger::trCount = 0; -Trigger::TrTrie Trigger::d_tr_trie; - -/** trigger class constructor */ -Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool smartTriggers ) : -d_quantEngine( qe ), d_f( f ){ - trCount++; - d_nodes.insert( d_nodes.begin(), nodes.begin(), nodes.end() ); - Debug("trigger") << "Trigger for " << f << ": " << d_nodes << std::endl; - if(matchOption == MATCH_GEN_DEFAULT) d_mg = mkPatterns( d_nodes, qe ); - else d_mg = mkPatternsEfficient( d_nodes, qe ); - if( d_nodes.size()==1 ){ - if( isSimpleTrigger( d_nodes[0] ) ){ - ++(qe->d_statistics.d_triggers); - }else{ - ++(qe->d_statistics.d_simple_triggers); - } - }else{ - Debug("multi-trigger") << "Multi-trigger " << (*this) << std::endl; - //std::cout << "Multi-trigger for " << f << " : " << std::endl; - //std::cout << " " << (*this) << std::endl; - ++(qe->d_statistics.d_multi_triggers); - } -} -void Trigger::computeVarContains( Node n ) { - if( d_var_contains.find( n )==d_var_contains.end() ){ - d_var_contains[n].clear(); - computeVarContains2( n, n ); - } -} - -void Trigger::computeVarContains2( Node n, Node parent ){ - if( n.getKind()==INST_CONSTANT ){ - if( std::find( d_var_contains[parent].begin(), d_var_contains[parent].end(), n )==d_var_contains[parent].end() ){ - d_var_contains[parent].push_back( n ); - } - }else{ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - computeVarContains2( n[i], parent ); - } - } -} - -void Trigger::resetInstantiationRound(){ - d_mg->resetInstantiationRound( d_quantEngine ); -} - - -bool Trigger::getNextMatch(){ - bool retVal = d_mg->getNextMatch( d_quantEngine ); - //m.makeInternal( d_quantEngine->getEqualityQuery() ); - return retVal; -} - -// bool Trigger::getMatch( Node t, InstMatch& m ){ -// //FIXME: this assumes d_mg is an inst match generator -// return ((InstMatchGenerator*)d_mg)->getMatch( t, m, d_quantEngine ); -// } - - -int Trigger::addInstantiations( InstMatch& baseMatch ){ - int addedLemmas = d_mg->addInstantiations( baseMatch, - d_nodes[0].getAttribute(InstConstantAttribute()), - d_quantEngine); - if( addedLemmas>0 ){ - Debug("inst-trigger") << "Added " << addedLemmas << " lemmas, trigger was "; - for( int i=0; i<(int)d_nodes.size(); i++ ){ - Debug("inst-trigger") << d_nodes[i] << " "; - } - Debug("inst-trigger") << std::endl; - } - return addedLemmas; -} - -Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool keepAll, int trOption, - bool smartTriggers ){ - 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; - for( int i=0; i<(int)temp.size(); i++ ){ - bool foundVar = false; - computeVarContains( temp[i] ); - for( int j=0; j<(int)d_var_contains[ temp[i] ].size(); j++ ){ - Node v = d_var_contains[ temp[i] ][j]; - if( v.getAttribute(InstConstantAttribute())==f ){ - if( vars.find( v )==vars.end() ){ - vars[ v ] = true; - foundVar = true; - } - } - } - if( foundVar ){ - trNodes.push_back( temp[i] ); - for( int j=0; j<(int)d_var_contains[ temp[i] ].size(); j++ ){ - Node v = d_var_contains[ temp[i] ][j]; - patterns[ v ].push_back( temp[i] ); - } - } - } - //now, minimalize the trigger - for( int i=0; i<(int)trNodes.size(); i++ ){ - bool keepPattern = false; - Node n = trNodes[i]; - for( int j=0; j<(int)d_var_contains[ n ].size(); j++ ){ - Node v = d_var_contains[ n ][j]; - if( patterns[v].size()==1 ){ - keepPattern = true; - break; - } - } - if( !keepPattern ){ - //remove from pattern vector - for( int j=0; j<(int)d_var_contains[ n ].size(); j++ ){ - Node v = d_var_contains[ n ][j]; - for( int k=0; k<(int)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--; - } - } - }else{ - trNodes.insert( trNodes.begin(), nodes.begin(), nodes.end() ); - } - - //check for duplicate? - if( trOption==TR_MAKE_NEW ){ - //static int trNew = 0; - //static int trOld = 0; - //Trigger* t = d_tr_trie.getTrigger( trNodes ); - //if( t ){ - // trOld++; - //}else{ - // trNew++; - //} - //if( (trNew+trOld)%100==0 ){ - // std::cout << "Trigger new old = " << trNew << " " << trOld << std::endl; - //} - }else{ - Trigger* t = d_tr_trie.getTrigger( trNodes ); - if( t ){ - if( trOption==TR_GET_OLD ){ - //just return old trigger - return t; - }else{ - return NULL; - } - } - } - Trigger* t = new Trigger( qe, f, trNodes, matchOption, smartTriggers ); - d_tr_trie.addTrigger( trNodes, t ); - return t; -} -Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, int matchOption, bool keepAll, int trOption, bool smartTriggers ){ - std::vector< Node > nodes; - nodes.push_back( n ); - return mkTrigger( qe, f, nodes, matchOption, keepAll, trOption, smartTriggers ); -} - -bool Trigger::isUsableTrigger( std::vector< Node >& nodes, Node f ){ - for( int i=0; i<(int)nodes.size(); i++ ){ - if( !isUsableTrigger( nodes[i], f ) ){ - return false; - } - } - return true; -} - -bool Trigger::isUsable( Node n, Node f ){ - if( n.getAttribute(InstConstantAttribute())==f ){ - if( !isAtomicTrigger( n ) && n.getKind()!=INST_CONSTANT ){ - std::map< Node, Node > coeffs; - return getPatternArithmetic( f, n, coeffs ); - }else{ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( !isUsable( n[i], f ) ){ - return false; - } - } - return true; - } - }else{ - return true; - } -} - -bool Trigger::isSimpleTrigger( Node n ){ - if( isAtomicTrigger( n ) ){ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( n[i].getKind()!=INST_CONSTANT && n[i].hasAttribute(InstConstantAttribute()) ){ - return false; - } - } - return true; - }else{ - return false; - } -} - -/** filter all nodes that have instances */ -void Trigger::filterInstances( std::vector< Node >& nodes ){ - std::vector< bool > active; - active.resize( nodes.size(), true ); - for( int i=0; i<(int)nodes.size(); i++ ){ - for( int j=i+1; j<(int)nodes.size(); j++ ){ - if( active[i] && active[j] ){ - int result = isInstanceOf( nodes[i], nodes[j] ); - if( result==1 ){ - active[j] = false; - }else if( result==-1 ){ - active[i] = false; - } - } - } - } - std::vector< Node > temp; - for( int i=0; i<(int)nodes.size(); i++ ){ - if( active[i] ){ - temp.push_back( nodes[i] ); - } - } - nodes.clear(); - nodes.insert( nodes.begin(), temp.begin(), temp.end() ); -} - - -bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt ){ - if( patMap.find( n )==patMap.end() ){ - patMap[ n ] = false; - if( tstrt==TS_MIN_TRIGGER ){ - if( n.getKind()==FORALL ){ -#ifdef NESTED_PATTERN_SELECTION - //return collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt ); - return collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt ); -#else - return false; -#endif - }else{ - bool retVal = false; - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){ - retVal = true; - } - } - if( retVal ){ - return true; - }else if( isUsableTrigger( n, f ) ){ - patMap[ n ] = true; - return true; - }else{ - return false; - } - } - }else{ - bool retVal = false; - if( isUsableTrigger( n, f ) ){ - patMap[ n ] = true; - if( tstrt==TS_MAX_TRIGGER ){ - return true; - }else{ - retVal = true; - } - } - if( n.getKind()==FORALL ){ -#ifdef NESTED_PATTERN_SELECTION - //if( collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt ) ){ - // retVal = true; - //} - if( collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt ) ){ - retVal = true; - } -#endif - }else{ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){ - retVal = true; - } - } - } - return retVal; - } - }else{ - return patMap[ n ]; - } -} - -void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst ){ - std::map< Node, bool > patMap; - if( filterInst ){ - //immediately do not consider any term t for which another term is an instance of t - std::vector< Node > patTerms2; - collectPatTerms( qe, f, n, patTerms2, TS_ALL, false ); - std::vector< Node > temp; - temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() ); - filterInstances( temp ); - if( temp.size()!=patTerms2.size() ){ - Debug("trigger-filter-instance") << "Filtered an instance: " << std::endl; - Debug("trigger-filter-instance") << "Old: "; - for( int i=0; i<(int)patTerms2.size(); i++ ){ - Debug("trigger-filter-instance") << patTerms2[i] << " "; - } - Debug("trigger-filter-instance") << std::endl << "New: "; - for( int i=0; i<(int)temp.size(); i++ ){ - Debug("trigger-filter-instance") << temp[i] << " "; - } - Debug("trigger-filter-instance") << std::endl; - } - if( tstrt==TS_ALL ){ - patTerms.insert( patTerms.begin(), temp.begin(), temp.end() ); - return; - }else{ - //do not consider terms that have instances - for( int i=0; i<(int)patTerms2.size(); i++ ){ - if( std::find( temp.begin(), temp.end(), patTerms2[i] )==temp.end() ){ - patMap[ patTerms2[i] ] = false; - } - } - } - } - collectPatTerms2( qe, f, n, patMap, tstrt ); - for( std::map< Node, bool >::iterator it = patMap.begin(); it != patMap.end(); ++it ){ - if( it->second ){ - patTerms.push_back( it->first ); - } - } -} - -/** is n1 an instance of n2 or vice versa? */ -int Trigger::isInstanceOf( Node n1, Node n2 ){ - if( n1==n2 ){ - return 1; - }else if( n1.getKind()==n2.getKind() ){ - if( n1.getKind()==APPLY_UF ){ - if( n1.getOperator()==n2.getOperator() ){ - int result = 0; - for( int i=0; i<(int)n1.getNumChildren(); i++ ){ - if( n1[i]!=n2[i] ){ - int cResult = isInstanceOf( n1[i], n2[i] ); - if( cResult==0 ){ - return 0; - }else if( cResult!=result ){ - if( result!=0 ){ - return 0; - }else{ - result = cResult; - } - } - } - } - return result; - } - } - return 0; - }else if( n2.getKind()==INST_CONSTANT ){ - computeVarContains( n1 ); - //if( std::find( d_var_contains[ n1 ].begin(), d_var_contains[ n1 ].end(), n2 )!=d_var_contains[ n1 ].end() ){ - // return 1; - //} - if( d_var_contains[ n1 ].size()==1 && d_var_contains[ n1 ][ 0 ]==n2 ){ - return 1; - } - }else if( n1.getKind()==INST_CONSTANT ){ - computeVarContains( n2 ); - //if( std::find( d_var_contains[ n2 ].begin(), d_var_contains[ n2 ].end(), n1 )!=d_var_contains[ n2 ].end() ){ - // return -1; - //} - if( d_var_contains[ n2 ].size()==1 && d_var_contains[ n2 ][ 0 ]==n1 ){ - return 1; - } - } - return 0; -} - -bool Trigger::isVariableSubsume( Node n1, Node n2 ){ - if( n1==n2 ){ - return true; - }else{ - //std::cout << "is variable subsume ? " << n1 << " " << n2 << std::endl; - computeVarContains( n1 ); - computeVarContains( n2 ); - for( int i=0; i<(int)d_var_contains[n2].size(); i++ ){ - if( std::find( d_var_contains[n1].begin(), d_var_contains[n1].end(), d_var_contains[n2][i] )==d_var_contains[n1].end() ){ - //std::cout << "no" << std::endl; - return false; - } - } - //std::cout << "yes" << std::endl; - return true; - } -} - -void Trigger::getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains ){ - for( int i=0; i<(int)pats.size(); i++ ){ - computeVarContains( pats[i] ); - varContains[ pats[i] ].clear(); - for( int j=0; j<(int)d_var_contains[pats[i]].size(); j++ ){ - if( d_var_contains[pats[i]][j].getAttribute(InstConstantAttribute())==f ){ - varContains[ pats[i] ].push_back( d_var_contains[pats[i]][j] ); - } - } - } -} - -void Trigger::getVarContainsNode( Node f, Node n, std::vector< Node >& varContains ){ - computeVarContains( n ); - for( int j=0; j<(int)d_var_contains[n].size(); j++ ){ - if( d_var_contains[n][j].getAttribute(InstConstantAttribute())==f ){ - varContains.push_back( d_var_contains[n][j] ); - } - } -} - -bool Trigger::getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coeffs ){ - if( n.getKind()==PLUS ){ - Assert( coeffs.empty() ); - NodeBuilder<> t(kind::PLUS); - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( n[i].hasAttribute(InstConstantAttribute()) ){ - if( n[i].getKind()==INST_CONSTANT ){ - if( n[i].getAttribute(InstConstantAttribute())==f ){ - coeffs[ n[i] ] = Node::null(); - }else{ - coeffs.clear(); - return false; - } - }else if( !getPatternArithmetic( f, n[i], coeffs ) ){ - coeffs.clear(); - return false; - } - }else{ - t << n[i]; - } - } - if( t.getNumChildren()==0 ){ - coeffs[ Node::null() ] = NodeManager::currentNM()->mkConst( Rational(0) ); - }else if( t.getNumChildren()==1 ){ - coeffs[ Node::null() ] = t.getChild( 0 ); - }else{ - coeffs[ Node::null() ] = t; - } - return true; - }else if( n.getKind()==MULT ){ - if( n[0].getKind()==INST_CONSTANT && n[0].getAttribute(InstConstantAttribute())==f ){ - Assert( !n[1].hasAttribute(InstConstantAttribute()) ); - coeffs[ n[0] ] = n[1]; - return true; - }else if( n[1].getKind()==INST_CONSTANT && n[1].getAttribute(InstConstantAttribute())==f ){ - Assert( !n[0].hasAttribute(InstConstantAttribute()) ); - coeffs[ n[1] ] = n[0]; - return true; - } - } - return false; -} diff --git a/src/theory/rr_trigger.h b/src/theory/rr_trigger.h deleted file mode 100644 index bc12666d0..000000000 --- a/src/theory/rr_trigger.h +++ /dev/null @@ -1,176 +0,0 @@ -/********************* */ -/*! \file rr_trigger.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: bobot - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief trigger class - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__RR_TRIGGER_H -#define __CVC4__RR_TRIGGER_H - -#include "theory/rr_inst_match.h" - -namespace CVC4 { -namespace theory { -namespace rrinst { - -//a collect of nodes representing a trigger -class Trigger { -public: - static int trCount; -private: - /** computation of variable contains */ - static std::map< Node, std::vector< Node > > d_var_contains; - static void computeVarContains( Node n ); - static void computeVarContains2( Node n, Node parent ); -private: - /** the quantifiers engine */ - QuantifiersEngine* d_quantEngine; - /** the quantifier this trigger is for */ - Node d_f; - /** match generators */ - PatsMatcher * d_mg; -private: - /** a trie of triggers */ - class TrTrie - { - private: - Trigger* getTrigger2( std::vector< Node >& nodes ); - void addTrigger2( std::vector< Node >& nodes, Trigger* t ); - public: - TrTrie() : d_tr( NULL ){} - Trigger* d_tr; - std::map< Node, TrTrie* > d_children; - Trigger* getTrigger( std::vector< Node >& nodes ){ - std::vector< Node > temp; - temp.insert( temp.begin(), nodes.begin(), nodes.end() ); - std::sort( temp.begin(), temp.end() ); - return getTrigger2( temp ); - } - void addTrigger( std::vector< Node >& nodes, Trigger* t ){ - std::vector< Node > temp; - temp.insert( temp.begin(), nodes.begin(), nodes.end() ); - std::sort( temp.begin(), temp.end() ); - return addTrigger2( temp, t ); - } - }; - /** all triggers will be stored in this trie */ - static TrTrie d_tr_trie; -private: - /** trigger constructor */ - Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes, int matchOption = 0, bool smartTriggers = false ); -public: - ~Trigger(){} -public: - std::vector< Node > d_nodes; -public: - void debugPrint( const char* c ); - PatsMatcher* getGenerator() { return d_mg; } -public: - /** reset instantiation round (call this whenever equivalence classes have changed) */ - void resetInstantiationRound(); - /** get next match. must call reset( eqc ) once before this function. */ - bool getNextMatch(); - const InstMatch & getInstMatch(){return d_mg->getInstMatch();}; - /** return whether this is a multi-trigger */ - bool isMultiTrigger() { return d_nodes.size()>1; } -public: - /** add all available instantiations exhaustively, in any equivalence class - if limitInst>0, limitInst is the max # of instantiations to try */ - int addInstantiations( InstMatch& baseMatch); - /** mkTrigger method - 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) - */ - enum { - //options for producing matches - MATCH_GEN_DEFAULT = 0, - MATCH_GEN_EFFICIENT_E_MATCH, //generate matches via Efficient E - }; - enum{ - TR_MAKE_NEW, //make new trigger even if it already may exist - 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, - bool smartTriggers = false ); - static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, Node n, - int matchOption = 0, bool keepAll = true, int trOption = TR_MAKE_NEW, - bool smartTriggers = false ); -private: - /** is subterm of trigger usable */ - static bool isUsable( Node n, Node f ); - /** collect all APPLY_UF pattern terms for f in n */ - static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt ); -public: - //different strategies for choosing trigger terms - enum { - TS_MAX_TRIGGER = 0, - TS_MIN_TRIGGER, - TS_ALL, - }; - static void collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst = false ); -public: - /** is usable trigger */ - static inline bool isUsableTrigger( TNode n, TNode f ){ - //return n.getAttribute(InstConstantAttribute())==f && n.getKind()==APPLY_UF; - return n.getAttribute(InstConstantAttribute())==f && isAtomicTrigger( n ) && isUsable( n, f ); - } - static inline bool isAtomicTrigger( TNode n ){ - return - n.getKind()==kind::APPLY_UF || - n.getKind()==kind::SELECT || - n.getKind()==kind::STORE; - } - static bool isUsableTrigger( std::vector< Node >& nodes, Node f ); - static bool isSimpleTrigger( Node n ); - /** filter all nodes that have instances */ - static void filterInstances( std::vector< Node >& nodes ); - /** -1: n1 is an instance of n2, 1: n1 is an instance of n2 */ - static int isInstanceOf( Node n1, Node n2 ); - /** variables subsume, return true if n1 contains all free variables in n2 */ - static bool isVariableSubsume( Node n1, Node n2 ); - /** get var contains */ - static void getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains ); - static void getVarContainsNode( Node f, Node n, std::vector< Node >& varContains ); - /** get pattern arithmetic */ - static bool getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coeffs ); - - inline void toStream(std::ostream& out) const { - out << "TRIGGER( "; - for( int i=0; i<(int)d_nodes.size(); i++ ){ - if( i>0 ){ out << ", "; } - out << d_nodes[i]; - } - out << " )"; - } -}; - -inline std::ostream& operator<<(std::ostream& out, const Trigger & tr) { - tr.toStream(out); - return out; -} - -}/* CVC4::theory::rrinst namespace */ - -}/* CVC4::theory namespace */ - -}/* CVC4 namespace */ - -#endif /* __CVC4__RR_TRIGGER_H */ diff --git a/src/theory/theory.cpp b/src/theory/theory.cpp index 1301da653..77daa5f53 100644 --- a/src/theory/theory.cpp +++ b/src/theory/theory.cpp @@ -19,7 +19,7 @@ #include "theory/theory.h" #include "util/Assert.h" #include "theory/quantifiers_engine.h" -#include "theory/instantiator_default.h" +#include "theory/quantifiers/instantiator_default.h" #include diff --git a/src/theory/trigger.cpp b/src/theory/trigger.cpp deleted file mode 100644 index f895f6814..000000000 --- a/src/theory/trigger.cpp +++ /dev/null @@ -1,558 +0,0 @@ -/********************* */ -/*! \file trigger.cpp - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief Implementation of trigger class - **/ - -#include "theory/trigger.h" -#include "theory/theory_engine.h" -#include "theory/quantifiers_engine.h" -#include "theory/uf/theory_uf_instantiator.h" -#include "theory/candidate_generator.h" -#include "theory/uf/equality_engine.h" -#include "theory/quantifiers/options.h" - -using namespace std; -using namespace CVC4; -using namespace CVC4::kind; -using namespace CVC4::context; -using namespace CVC4::theory; -using namespace CVC4::theory::inst; - -//#define NESTED_PATTERN_SELECTION - -Trigger* Trigger::TrTrie::getTrigger2( std::vector< Node >& nodes ){ - if( nodes.empty() ){ - return d_tr; - }else{ - Node n = nodes.back(); - nodes.pop_back(); - if( d_children.find( n )!=d_children.end() ){ - return d_children[n]->getTrigger2( nodes ); - }else{ - return NULL; - } - } -} -void Trigger::TrTrie::addTrigger2( std::vector< Node >& nodes, Trigger* t ){ - if( nodes.empty() ){ - d_tr = t; - }else{ - Node n = nodes.back(); - nodes.pop_back(); - if( d_children.find( n )==d_children.end() ){ - d_children[n] = new TrTrie; - } - d_children[n]->addTrigger2( nodes, t ); - } -} - -/** trigger static members */ -std::map< TNode, std::vector< TNode > > Trigger::d_var_contains; -Trigger::TrTrie Trigger::d_tr_trie; - -/** trigger class constructor */ -Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool smartTriggers ) : -d_quantEngine( qe ), d_f( f ){ - d_nodes.insert( d_nodes.begin(), nodes.begin(), nodes.end() ); - if( smartTriggers ){ - if( d_nodes.size()==1 ){ - if( isSimpleTrigger( d_nodes[0] ) ){ - d_mg = new InstMatchGeneratorSimple( f, d_nodes[0] ); - }else{ - d_mg = new InstMatchGenerator( d_nodes[0], qe, matchOption ); - } - }else{ - d_mg = new InstMatchGeneratorMulti( f, d_nodes, qe, matchOption ); - } - }else{ - d_mg = new InstMatchGenerator( d_nodes, qe, matchOption ); - } - Debug("trigger") << "Trigger for " << f << ": " << std::endl; - for( int i=0; i<(int)d_nodes.size(); i++ ){ - Debug("trigger") << " " << d_nodes[i] << std::endl; - } - Debug("trigger") << std::endl; - if( d_nodes.size()==1 ){ - if( isSimpleTrigger( d_nodes[0] ) ){ - ++(qe->d_statistics.d_triggers); - }else{ - ++(qe->d_statistics.d_simple_triggers); - } - }else{ - Debug("multi-trigger") << "Multi-trigger " << (*this) << std::endl; - //Notice() << "Multi-trigger for " << f << " : " << std::endl; - //Notice() << " " << (*this) << std::endl; - ++(qe->d_statistics.d_multi_triggers); - } - //Notice() << "Trigger : " << (*this) << " for " << f << std::endl; - if( options::eagerInstQuant() ){ - Theory* th_uf = qe->getTheoryEngine()->getTheory( theory::THEORY_UF ); - uf::InstantiatorTheoryUf* ith = (uf::InstantiatorTheoryUf*)th_uf->getInstantiator(); - for( int i=0; i<(int)d_nodes.size(); i++ ){ - ith->registerTrigger( this, d_nodes[i].getOperator() ); - } - } -} -void Trigger::computeVarContains( Node n ) { - if( d_var_contains.find( n )==d_var_contains.end() ){ - d_var_contains[n].clear(); - computeVarContains2( n, n ); - } -} - -void Trigger::computeVarContains2( Node n, Node parent ){ - if( n.getKind()==INST_CONSTANT ){ - if( std::find( d_var_contains[parent].begin(), d_var_contains[parent].end(), n )==d_var_contains[parent].end() ){ - d_var_contains[parent].push_back( n ); - } - }else{ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - computeVarContains2( n[i], parent ); - } - } -} - -void Trigger::resetInstantiationRound(){ - d_mg->resetInstantiationRound( d_quantEngine ); -} - -void Trigger::reset( Node eqc ){ - d_mg->reset( eqc, d_quantEngine ); -} - -bool Trigger::getNextMatch( InstMatch& m ){ - bool retVal = d_mg->getNextMatch( m, d_quantEngine ); - //m.makeInternal( d_quantEngine->getEqualityQuery() ); - return retVal; -} - -bool Trigger::getMatch( Node t, InstMatch& m ){ - //FIXME: this assumes d_mg is an inst match generator - return ((InstMatchGenerator*)d_mg)->getMatch( t, m, d_quantEngine ); -} - -int Trigger::addTerm( Node t ){ - return d_mg->addTerm( d_f, t, d_quantEngine ); -} - -int Trigger::addInstantiations( InstMatch& baseMatch ){ - int addedLemmas = d_mg->addInstantiations( d_f, baseMatch, d_quantEngine ); - if( addedLemmas>0 ){ - Debug("inst-trigger") << "Added " << addedLemmas << " lemmas, trigger was "; - for( int i=0; i<(int)d_nodes.size(); i++ ){ - Debug("inst-trigger") << d_nodes[i] << " "; - } - Debug("inst-trigger") << std::endl; - } - return addedLemmas; -} - -Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool keepAll, int trOption, - bool smartTriggers ){ - 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; - for( int i=0; i<(int)temp.size(); i++ ){ - bool foundVar = false; - computeVarContains( temp[i] ); - for( int j=0; j<(int)d_var_contains[ temp[i] ].size(); j++ ){ - Node v = d_var_contains[ temp[i] ][j]; - if( v.getAttribute(InstConstantAttribute())==f ){ - if( vars.find( v )==vars.end() ){ - vars[ v ] = true; - foundVar = true; - } - } - } - if( foundVar ){ - trNodes.push_back( temp[i] ); - for( int j=0; j<(int)d_var_contains[ temp[i] ].size(); j++ ){ - Node v = d_var_contains[ temp[i] ][j]; - patterns[ v ].push_back( temp[i] ); - } - } - } - //now, minimalize the trigger - for( int i=0; i<(int)trNodes.size(); i++ ){ - bool keepPattern = false; - Node n = trNodes[i]; - for( int j=0; j<(int)d_var_contains[ n ].size(); j++ ){ - Node v = d_var_contains[ n ][j]; - if( patterns[v].size()==1 ){ - keepPattern = true; - break; - } - } - if( !keepPattern ){ - //remove from pattern vector - for( int j=0; j<(int)d_var_contains[ n ].size(); j++ ){ - Node v = d_var_contains[ n ][j]; - for( int k=0; k<(int)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--; - } - } - }else{ - trNodes.insert( trNodes.begin(), nodes.begin(), nodes.end() ); - } - - //check for duplicate? - if( trOption==TR_MAKE_NEW ){ - //static int trNew = 0; - //static int trOld = 0; - //Trigger* t = d_tr_trie.getTrigger( trNodes ); - //if( t ){ - // trOld++; - //}else{ - // trNew++; - //} - //if( (trNew+trOld)%100==0 ){ - // Notice() << "Trigger new old = " << trNew << " " << trOld << std::endl; - //} - }else{ - Trigger* t = d_tr_trie.getTrigger( trNodes ); - if( t ){ - if( trOption==TR_GET_OLD ){ - //just return old trigger - return t; - }else{ - return NULL; - } - } - } - Trigger* t = new Trigger( qe, f, trNodes, matchOption, smartTriggers ); - d_tr_trie.addTrigger( trNodes, t ); - return t; -} -Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, int matchOption, bool keepAll, int trOption, bool smartTriggers ){ - std::vector< Node > nodes; - nodes.push_back( n ); - return mkTrigger( qe, f, nodes, matchOption, keepAll, trOption, smartTriggers ); -} - -bool Trigger::isUsableTrigger( std::vector< Node >& nodes, Node f ){ - for( int i=0; i<(int)nodes.size(); i++ ){ - if( !isUsableTrigger( nodes[i], f ) ){ - return false; - } - } - return true; -} - -bool Trigger::isUsable( Node n, Node f ){ - if( n.getAttribute(InstConstantAttribute())==f ){ - if( !isAtomicTrigger( n ) && n.getKind()!=INST_CONSTANT ){ - std::map< Node, Node > coeffs; - return getPatternArithmetic( f, n, coeffs ); - }else{ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( !isUsable( n[i], f ) ){ - return false; - } - } - return true; - } - }else{ - return true; - } -} - -bool Trigger::isUsableTrigger( Node n, Node f ){ - //return n.getAttribute(InstConstantAttribute())==f && n.getKind()==APPLY_UF; - return n.getAttribute(InstConstantAttribute())==f && isAtomicTrigger( n ) && isUsable( n, f ); -} - -bool Trigger::isAtomicTrigger( Node n ){ - return n.getKind()==APPLY_UF || n.getKind()==SELECT || n.getKind()==STORE || - n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR || n.getKind()==APPLY_TESTER; -} -bool Trigger::isSimpleTrigger( Node n ){ - if( isAtomicTrigger( n ) ){ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( n[i].getKind()!=INST_CONSTANT && n[i].hasAttribute(InstConstantAttribute()) ){ - return false; - } - } - return true; - }else{ - return false; - } -} - -/** filter all nodes that have instances */ -void Trigger::filterInstances( std::vector< Node >& nodes ){ - std::vector< bool > active; - active.resize( nodes.size(), true ); - for( int i=0; i<(int)nodes.size(); i++ ){ - for( int j=i+1; j<(int)nodes.size(); j++ ){ - if( active[i] && active[j] ){ - int result = isInstanceOf( nodes[i], nodes[j] ); - if( result==1 ){ - active[j] = false; - }else if( result==-1 ){ - active[i] = false; - } - } - } - } - std::vector< Node > temp; - for( int i=0; i<(int)nodes.size(); i++ ){ - if( active[i] ){ - temp.push_back( nodes[i] ); - } - } - nodes.clear(); - nodes.insert( nodes.begin(), temp.begin(), temp.end() ); -} - - -bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt ){ - if( patMap.find( n )==patMap.end() ){ - patMap[ n ] = false; - if( tstrt==TS_MIN_TRIGGER ){ - if( n.getKind()==FORALL ){ -#ifdef NESTED_PATTERN_SELECTION - //return collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt ); - return collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt ); -#else - return false; -#endif - }else{ - bool retVal = false; - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){ - retVal = true; - } - } - if( retVal ){ - return true; - }else if( isUsableTrigger( n, f ) ){ - patMap[ n ] = true; - return true; - }else{ - return false; - } - } - }else{ - bool retVal = false; - if( isUsableTrigger( n, f ) ){ - patMap[ n ] = true; - if( tstrt==TS_MAX_TRIGGER ){ - return true; - }else{ - retVal = true; - } - } - if( n.getKind()==FORALL ){ -#ifdef NESTED_PATTERN_SELECTION - //if( collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt ) ){ - // retVal = true; - //} - if( collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt ) ){ - retVal = true; - } -#endif - }else{ - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){ - retVal = true; - } - } - } - return retVal; - } - }else{ - return patMap[ n ]; - } -} - -void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst ){ - std::map< Node, bool > patMap; - if( filterInst ){ - //immediately do not consider any term t for which another term is an instance of t - std::vector< Node > patTerms2; - collectPatTerms( qe, f, n, patTerms2, TS_ALL, false ); - std::vector< Node > temp; - temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() ); - filterInstances( temp ); - if( temp.size()!=patTerms2.size() ){ - Debug("trigger-filter-instance") << "Filtered an instance: " << std::endl; - Debug("trigger-filter-instance") << "Old: "; - for( int i=0; i<(int)patTerms2.size(); i++ ){ - Debug("trigger-filter-instance") << patTerms2[i] << " "; - } - Debug("trigger-filter-instance") << std::endl << "New: "; - for( int i=0; i<(int)temp.size(); i++ ){ - Debug("trigger-filter-instance") << temp[i] << " "; - } - Debug("trigger-filter-instance") << std::endl; - } - if( tstrt==TS_ALL ){ - patTerms.insert( patTerms.begin(), temp.begin(), temp.end() ); - return; - }else{ - //do not consider terms that have instances - for( int i=0; i<(int)patTerms2.size(); i++ ){ - if( std::find( temp.begin(), temp.end(), patTerms2[i] )==temp.end() ){ - patMap[ patTerms2[i] ] = false; - } - } - } - } - collectPatTerms2( qe, f, n, patMap, tstrt ); - for( std::map< Node, bool >::iterator it = patMap.begin(); it != patMap.end(); ++it ){ - if( it->second ){ - patTerms.push_back( it->first ); - } - } -} - -/** is n1 an instance of n2 or vice versa? */ -int Trigger::isInstanceOf( Node n1, Node n2 ){ - if( n1==n2 ){ - return 1; - }else if( n1.getKind()==n2.getKind() ){ - if( n1.getKind()==APPLY_UF ){ - if( n1.getOperator()==n2.getOperator() ){ - int result = 0; - for( int i=0; i<(int)n1.getNumChildren(); i++ ){ - if( n1[i]!=n2[i] ){ - int cResult = isInstanceOf( n1[i], n2[i] ); - if( cResult==0 ){ - return 0; - }else if( cResult!=result ){ - if( result!=0 ){ - return 0; - }else{ - result = cResult; - } - } - } - } - return result; - } - } - return 0; - }else if( n2.getKind()==INST_CONSTANT ){ - computeVarContains( n1 ); - //if( std::find( d_var_contains[ n1 ].begin(), d_var_contains[ n1 ].end(), n2 )!=d_var_contains[ n1 ].end() ){ - // return 1; - //} - if( d_var_contains[ n1 ].size()==1 && d_var_contains[ n1 ][ 0 ]==n2 ){ - return 1; - } - }else if( n1.getKind()==INST_CONSTANT ){ - computeVarContains( n2 ); - //if( std::find( d_var_contains[ n2 ].begin(), d_var_contains[ n2 ].end(), n1 )!=d_var_contains[ n2 ].end() ){ - // return -1; - //} - if( d_var_contains[ n2 ].size()==1 && d_var_contains[ n2 ][ 0 ]==n1 ){ - return 1; - } - } - return 0; -} - -bool Trigger::isVariableSubsume( Node n1, Node n2 ){ - if( n1==n2 ){ - return true; - }else{ - //Notice() << "is variable subsume ? " << n1 << " " << n2 << std::endl; - computeVarContains( n1 ); - computeVarContains( n2 ); - for( int i=0; i<(int)d_var_contains[n2].size(); i++ ){ - if( std::find( d_var_contains[n1].begin(), d_var_contains[n1].end(), d_var_contains[n2][i] )==d_var_contains[n1].end() ){ - //Notice() << "no" << std::endl; - return false; - } - } - //Notice() << "yes" << std::endl; - return true; - } -} - -void Trigger::getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains ){ - for( int i=0; i<(int)pats.size(); i++ ){ - computeVarContains( pats[i] ); - varContains[ pats[i] ].clear(); - for( int j=0; j<(int)d_var_contains[pats[i]].size(); j++ ){ - if( d_var_contains[pats[i]][j].getAttribute(InstConstantAttribute())==f ){ - varContains[ pats[i] ].push_back( d_var_contains[pats[i]][j] ); - } - } - } -} - -void Trigger::getVarContainsNode( Node f, Node n, std::vector< Node >& varContains ){ - computeVarContains( n ); - for( int j=0; j<(int)d_var_contains[n].size(); j++ ){ - if( d_var_contains[n][j].getAttribute(InstConstantAttribute())==f ){ - varContains.push_back( d_var_contains[n][j] ); - } - } -} - -bool Trigger::getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coeffs ){ - if( n.getKind()==PLUS ){ - Assert( coeffs.empty() ); - NodeBuilder<> t(kind::PLUS); - for( int i=0; i<(int)n.getNumChildren(); i++ ){ - if( n[i].hasAttribute(InstConstantAttribute()) ){ - if( n[i].getKind()==INST_CONSTANT ){ - if( n[i].getAttribute(InstConstantAttribute())==f ){ - coeffs[ n[i] ] = Node::null(); - }else{ - coeffs.clear(); - return false; - } - }else if( !getPatternArithmetic( f, n[i], coeffs ) ){ - coeffs.clear(); - return false; - } - }else{ - t << n[i]; - } - } - if( t.getNumChildren()==0 ){ - coeffs[ Node::null() ] = NodeManager::currentNM()->mkConst( Rational(0) ); - }else if( t.getNumChildren()==1 ){ - coeffs[ Node::null() ] = t.getChild( 0 ); - }else{ - coeffs[ Node::null() ] = t; - } - return true; - }else if( n.getKind()==MULT ){ - if( n[0].getKind()==INST_CONSTANT && n[0].getAttribute(InstConstantAttribute())==f ){ - Assert( !n[1].hasAttribute(InstConstantAttribute()) ); - coeffs[ n[0] ] = n[1]; - return true; - }else if( n[1].getKind()==INST_CONSTANT && n[1].getAttribute(InstConstantAttribute())==f ){ - Assert( !n[0].hasAttribute(InstConstantAttribute()) ); - coeffs[ n[1] ] = n[0]; - return true; - } - } - return false; -} diff --git a/src/theory/trigger.h b/src/theory/trigger.h deleted file mode 100644 index 84bc7ac2e..000000000 --- a/src/theory/trigger.h +++ /dev/null @@ -1,173 +0,0 @@ -/********************* */ -/*! \file trigger.h - ** \verbatim - ** Original author: ajreynol - ** Major contributors: none - ** Minor contributors (to current version): none - ** This file is part of the CVC4 prototype. - ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys) - ** Courant Institute of Mathematical Sciences - ** New York University - ** See the file COPYING in the top-level source directory for licensing - ** information.\endverbatim - ** - ** \brief trigger class - **/ - -#include "cvc4_private.h" - -#ifndef __CVC4__TRIGGER_H -#define __CVC4__TRIGGER_H - -#include "theory/inst_match.h" - -namespace CVC4 { -namespace theory { -namespace inst { - -//a collect of nodes representing a trigger -class Trigger { -private: - /** computation of variable contains */ - static std::map< TNode, std::vector< TNode > > d_var_contains; - static void computeVarContains( Node n ); - static void computeVarContains2( Node n, Node parent ); -private: - /** the quantifiers engine */ - QuantifiersEngine* d_quantEngine; - /** the quantifier this trigger is for */ - Node d_f; - /** match generators */ - IMGenerator* d_mg; -private: - /** a trie of triggers */ - class TrTrie { - private: - Trigger* getTrigger2( std::vector< Node >& nodes ); - void addTrigger2( std::vector< Node >& nodes, Trigger* t ); - public: - TrTrie() : d_tr( NULL ){} - Trigger* d_tr; - std::map< TNode, TrTrie* > d_children; - Trigger* getTrigger( std::vector< Node >& nodes ){ - std::vector< Node > temp; - temp.insert( temp.begin(), nodes.begin(), nodes.end() ); - std::sort( temp.begin(), temp.end() ); - return getTrigger2( temp ); - } - void addTrigger( std::vector< Node >& nodes, Trigger* t ){ - std::vector< Node > temp; - temp.insert( temp.begin(), nodes.begin(), nodes.end() ); - std::sort( temp.begin(), temp.end() ); - return addTrigger2( temp, t ); - } - };/* class Trigger::TrTrie */ - /** all triggers will be stored in this trie */ - static TrTrie d_tr_trie; -private: - /** trigger constructor */ - Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes, int matchOption = 0, bool smartTriggers = false ); -public: - ~Trigger(){} -public: - std::vector< Node > d_nodes; -public: - void debugPrint( const char* c ); - IMGenerator* getGenerator() { return d_mg; } -public: - /** reset instantiation round (call this whenever equivalence classes have changed) */ - void resetInstantiationRound(); - /** reset, eqc is the equivalence class to search in (search in any if eqc=null) */ - void reset( Node eqc ); - /** get next match. must call reset( eqc ) once before this function. */ - bool getNextMatch( InstMatch& m ); - /** get the match against ground term or formula t. - the trigger and t should have the same shape. - Currently the trigger should not be a multi-trigger. - */ - bool getMatch( Node t, InstMatch& m); - /** add ground term t, called when t is added to the TermDb */ - int addTerm( Node t ); - /** return true if whatever Node is subsituted for the variables the - given Node can't match the pattern */ - bool nonunifiable( TNode t, const std::vector & vars){ - return d_mg->nonunifiable(t,vars); - } - /** return whether this is a multi-trigger */ - bool isMultiTrigger() { return d_nodes.size()>1; } -public: - /** add all available instantiations exhaustively, in any equivalence class - if limitInst>0, limitInst is the max # of instantiations to try */ - int addInstantiations( InstMatch& baseMatch ); - /** mkTrigger method - 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) - */ - enum{ - TR_MAKE_NEW, //make new trigger even if it already may exist - 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, - bool smartTriggers = false ); - static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, Node n, - int matchOption = 0, bool keepAll = true, int trOption = TR_MAKE_NEW, - bool smartTriggers = false ); -private: - /** is subterm of trigger usable */ - static bool isUsable( Node n, Node f ); - /** collect all APPLY_UF pattern terms for f in n */ - static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt ); -public: - //different strategies for choosing trigger terms - enum { - TS_MAX_TRIGGER = 0, - TS_MIN_TRIGGER, - TS_ALL, - }; - static void collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst = false ); -public: - /** is usable trigger */ - static bool isUsableTrigger( std::vector< Node >& nodes, Node f ); - static bool isUsableTrigger( Node n, Node f ); - static bool isAtomicTrigger( Node n ); - static bool isSimpleTrigger( Node n ); - /** filter all nodes that have instances */ - static void filterInstances( std::vector< Node >& nodes ); - /** -1: n1 is an instance of n2, 1: n1 is an instance of n2 */ - static int isInstanceOf( Node n1, Node n2 ); - /** variables subsume, return true if n1 contains all free variables in n2 */ - static bool isVariableSubsume( Node n1, Node n2 ); - /** get var contains */ - static void getVarContains( Node f, std::vector< Node >& pats, std::map< Node, std::vector< Node > >& varContains ); - static void getVarContainsNode( Node f, Node n, std::vector< Node >& varContains ); - /** get pattern arithmetic */ - static bool getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coeffs ); - - inline void toStream(std::ostream& out) const { - out << "TRIGGER( "; - for( int i=0; i<(int)d_nodes.size(); i++ ){ - if( i>0 ){ out << ", "; } - out << d_nodes[i]; - } - out << " )"; - } -}; - -inline std::ostream& operator<<(std::ostream& out, const Trigger & tr) { - tr.toStream(out); - return out; -} - -}/* CVC4::theory::inst namespace */ - -}/* CVC4::theory namespace */ - -}/* CVC4 namespace */ - -#endif /* __CVC4__TRIGGER_H */ diff --git a/src/theory/uf/inst_strategy.h b/src/theory/uf/inst_strategy.h index a0091c4b4..663720326 100644 --- a/src/theory/uf/inst_strategy.h +++ b/src/theory/uf/inst_strategy.h @@ -20,7 +20,7 @@ #define __CVC4__INST_STRATEGY_H #include "theory/quantifiers_engine.h" -#include "theory/trigger.h" +#include "theory/quantifiers/trigger.h" #include "context/context.h" #include "context/context_mm.h" diff --git a/src/theory/uf/theory_uf_instantiator.cpp b/src/theory/uf/theory_uf_instantiator.cpp index ea253cbdb..90e45775b 100644 --- a/src/theory/uf/theory_uf_instantiator.cpp +++ b/src/theory/uf/theory_uf_instantiator.cpp @@ -17,7 +17,7 @@ #include "theory/uf/theory_uf_instantiator.h" #include "theory/theory_engine.h" #include "theory/uf/theory_uf.h" -#include "theory/rr_candidate_generator.h" +#include "theory/rewriterules/rr_candidate_generator.h" #include "theory/uf/equality_engine.h" #include "theory/quantifiers/options.h" #include "theory/rewriterules/options.h" diff --git a/src/theory/uf/theory_uf_instantiator.h b/src/theory/uf/theory_uf_instantiator.h index d15c0103b..59b8f36a4 100644 --- a/src/theory/uf/theory_uf_instantiator.h +++ b/src/theory/uf/theory_uf_instantiator.h @@ -27,7 +27,7 @@ #include "util/stats.h" #include "theory/uf/theory_uf.h" -#include "theory/trigger.h" +#include "theory/quantifiers/trigger.h" #include "util/ntuple.h" #include "context/cdqueue.h"