summaryrefslogtreecommitdiff
path: root/src/theory
diff options
context:
space:
mode:
authorFrançois Bobot <francois@bobot.eu>2012-07-27 13:36:32 +0000
committerFrançois Bobot <francois@bobot.eu>2012-07-27 13:36:32 +0000
commit4bfa927dac67bbcadf219f70e61f1d123e33944b (patch)
treef295343430799748de8b9a823f1a3c641c096905 /src/theory
parent988c97d92fa617c5dccaeb1ef33121bfa6459afc (diff)
Merge quantifiers2-trunk:
- new syntax for rewrite rules - better rewrite rules theory - remove the rewriting with rewrite rules during ppRewrite temporarily - theory can define their own candidate generator - define a general candidate generator (inefficient ask to every theory) - split inst_match between the pattern matching used for quantifiers (inst_match.*) and the one used for rewrite rules (rr_inst_match.*): - the pattern matching is less exhaustive for quantifiers, - the one for rewrite rules can use efficient-e-matching.
Diffstat (limited to 'src/theory')
-rw-r--r--src/theory/Makefile.am6
-rw-r--r--src/theory/arith/theory_arith_instantiator.cpp2
-rw-r--r--src/theory/arrays/theory_arrays_instantiator.cpp14
-rw-r--r--src/theory/arrays/theory_arrays_instantiator.h6
-rw-r--r--src/theory/datatypes/Makefile.am3
-rw-r--r--src/theory/datatypes/theory_datatypes.h8
-rw-r--r--src/theory/datatypes/theory_datatypes_candidate_generator.h67
-rw-r--r--src/theory/datatypes/theory_datatypes_instantiator.cpp12
-rw-r--r--src/theory/datatypes/theory_datatypes_instantiator.h9
-rw-r--r--src/theory/inst_match.cpp77
-rw-r--r--src/theory/inst_match.h132
-rw-r--r--src/theory/instantiator_default.cpp2
-rw-r--r--src/theory/quantifiers/instantiation_engine.cpp4
-rw-r--r--src/theory/quantifiers/model_engine.cpp3
-rw-r--r--src/theory/quantifiers/rep_set_iterator.cpp2
-rw-r--r--src/theory/quantifiers/term_database.cpp689
-rw-r--r--src/theory/quantifiers/term_database.h8
-rw-r--r--src/theory/quantifiers/theory_quantifiers.h3
-rw-r--r--src/theory/quantifiers_engine.cpp279
-rw-r--r--src/theory/quantifiers_engine.h46
-rw-r--r--src/theory/rewriterules/theory_rewriterules.cpp328
-rw-r--r--src/theory/rewriterules/theory_rewriterules.h33
-rw-r--r--src/theory/rewriterules/theory_rewriterules_params.h14
-rw-r--r--src/theory/rewriterules/theory_rewriterules_rules.cpp131
-rw-r--r--src/theory/rewriterules/theory_rewriterules_type_rules.h6
-rw-r--r--src/theory/rr_inst_match.cpp1447
-rw-r--r--src/theory/rr_inst_match.h263
-rw-r--r--src/theory/rr_inst_match_impl.h128
-rw-r--r--src/theory/rr_trigger.cpp523
-rw-r--r--src/theory/rr_trigger.h176
-rw-r--r--src/theory/theory.h10
-rw-r--r--src/theory/theory_engine.h11
-rw-r--r--src/theory/trigger.cpp1
-rw-r--r--src/theory/trigger.h3
-rw-r--r--src/theory/uf/equality_engine.cpp4
-rw-r--r--src/theory/uf/equality_engine.h4
-rw-r--r--src/theory/uf/inst_strategy.cpp3
-rw-r--r--src/theory/uf/inst_strategy.h9
-rw-r--r--src/theory/uf/theory_uf_candidate_generator.cpp11
-rw-r--r--src/theory/uf/theory_uf_candidate_generator.h147
-rw-r--r--src/theory/uf/theory_uf_instantiator.cpp595
-rw-r--r--src/theory/uf/theory_uf_instantiator.h364
42 files changed, 4790 insertions, 793 deletions
diff --git a/src/theory/Makefile.am b/src/theory/Makefile.am
index 1aae03aa5..2bd85f712 100644
--- a/src/theory/Makefile.am
+++ b/src/theory/Makefile.am
@@ -40,8 +40,12 @@ libtheory_la_SOURCES = \
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 \
inst_match.h \
- inst_match_impl.h \
inst_match.cpp \
trigger.h \
trigger.cpp \
diff --git a/src/theory/arith/theory_arith_instantiator.cpp b/src/theory/arith/theory_arith_instantiator.cpp
index c4cb2f493..ab3a1548e 100644
--- a/src/theory/arith/theory_arith_instantiator.cpp
+++ b/src/theory/arith/theory_arith_instantiator.cpp
@@ -376,7 +376,7 @@ bool InstantiatorTheoryArith::doInstantiation2( Node f, Node term, ArithVar x, I
}
instVal = Rewriter::rewrite( instVal );
//use as instantiation value for var
- m.d_map[ var ] = instVal;
+ m.set(var, instVal);
Debug("quant-arith") << "Add instantiation " << m << std::endl;
return d_quantEngine->addInstantiation( f, m );
}
diff --git a/src/theory/arrays/theory_arrays_instantiator.cpp b/src/theory/arrays/theory_arrays_instantiator.cpp
index 2e446c57f..ca9001fe5 100644
--- a/src/theory/arrays/theory_arrays_instantiator.cpp
+++ b/src/theory/arrays/theory_arrays_instantiator.cpp
@@ -17,6 +17,7 @@
#include "theory/theory_engine.h"
#include "theory/arrays/theory_arrays_instantiator.h"
#include "theory/arrays/theory_arrays.h"
+#include "theory/uf/theory_uf_candidate_generator.h"
using namespace std;
using namespace CVC4;
@@ -83,3 +84,16 @@ Node InstantiatorTheoryArrays::getRepresentative( Node a ){
}
}
+rrinst::CandidateGenerator* InstantiatorTheoryArrays::getRRCanGenClasses(){
+ arrays::TheoryArrays* ar = static_cast<arrays::TheoryArrays *>(getTheory());
+ eq::EqualityEngine* ee =
+ static_cast<eq::EqualityEngine*>(ar->getEqualityEngine());
+ return new eq::rrinst::CandidateGeneratorTheoryEeClasses(ee);
+}
+
+rrinst::CandidateGenerator* InstantiatorTheoryArrays::getRRCanGenClass(){
+ arrays::TheoryArrays* ar = static_cast<arrays::TheoryArrays *>(getTheory());
+ eq::EqualityEngine* ee =
+ static_cast<eq::EqualityEngine*>(ar->getEqualityEngine());
+ return new eq::rrinst::CandidateGeneratorTheoryEeClass(ee);
+}
diff --git a/src/theory/arrays/theory_arrays_instantiator.h b/src/theory/arrays/theory_arrays_instantiator.h
index ade43fdb0..f711229b2 100644
--- a/src/theory/arrays/theory_arrays_instantiator.h
+++ b/src/theory/arrays/theory_arrays_instantiator.h
@@ -21,6 +21,7 @@
#define __CVC4__INSTANTIATOR_THEORY_ARRAYS_H
#include "theory/quantifiers_engine.h"
+#include "theory/uf/equality_engine.h"
namespace CVC4 {
namespace theory {
@@ -48,10 +49,13 @@ public:
bool areEqual( Node a, Node b );
bool areDisequal( Node a, Node b );
Node getRepresentative( Node a );
+ /** general creators of candidate generators */
+ rrinst::CandidateGenerator* getRRCanGenClasses();
+ rrinst::CandidateGenerator* getRRCanGenClass();
};/* class Instantiatior */
}
}
}
-#endif \ No newline at end of file
+#endif
diff --git a/src/theory/datatypes/Makefile.am b/src/theory/datatypes/Makefile.am
index 14bbf64d4..f282ce74d 100644
--- a/src/theory/datatypes/Makefile.am
+++ b/src/theory/datatypes/Makefile.am
@@ -16,6 +16,7 @@ libdatatypes_la_SOURCES = \
explanation_manager.h \
explanation_manager.cpp \
theory_datatypes_instantiator.h \
- theory_datatypes_instantiator.cpp
+ theory_datatypes_instantiator.cpp \
+ theory_datatypes_candidate_generator.h
EXTRA_DIST = kinds
diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h
index 783c0ebc7..80c20a7d9 100644
--- a/src/theory/datatypes/theory_datatypes.h
+++ b/src/theory/datatypes/theory_datatypes.h
@@ -38,9 +38,17 @@ namespace theory {
namespace datatypes {
class InstantiatorTheoryDatatypes;
+class EqualityQueryTheory;
+
+namespace rrinst{
+ class CandidateGeneratorTheoryClass;
+}
class TheoryDatatypes : public Theory {
friend class InstantiatorTheoryDatatypes;
+ friend class EqualityQueryTheory;
+ friend class rrinst::CandidateGeneratorTheoryClass;
+
private:
typedef context::CDChunkList<TNode> EqList;
typedef context::CDHashMap<Node, EqList*, NodeHashFunction> EqLists;
diff --git a/src/theory/datatypes/theory_datatypes_candidate_generator.h b/src/theory/datatypes/theory_datatypes_candidate_generator.h
new file mode 100644
index 000000000..46c7ce7fb
--- /dev/null
+++ b/src/theory/datatypes/theory_datatypes_candidate_generator.h
@@ -0,0 +1,67 @@
+/********************* */
+/*! \file theory_uf_candidate generator.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 Theory datatypes candidate generator
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY_DATATYPES_CANDIDATE_GENERATOR_H
+#define __CVC4__THEORY_DATATYPES_CANDIDATE_GENERATOR_H
+
+#include "theory/quantifiers_engine.h"
+#include "theory/datatypes/theory_datatypes.h"
+#include "theory/rr_inst_match.h"
+
+namespace CVC4 {
+namespace theory {
+namespace datatypes {
+
+namespace rrinst {
+typedef CVC4::theory::rrinst::CandidateGenerator CandidateGenerator;
+
+// Just iterate amoung the equivalence class of the given node
+// node::Null() *can't* be given to reset
+class CandidateGeneratorTheoryClass : public CandidateGenerator{
+private:
+ //instantiator pointer
+ TheoryDatatypes* d_th;
+ //the equality class iterator
+ TheoryDatatypes::EqListN::const_iterator d_eqc_i;
+ TheoryDatatypes::EqListN* d_eqc;
+public:
+ CandidateGeneratorTheoryClass( TheoryDatatypes* th): d_th( th ), d_eqc(NULL){}
+ ~CandidateGeneratorTheoryClass(){}
+ void resetInstantiationRound(){};
+ void reset( TNode n ){
+ TheoryDatatypes::EqListsN::const_iterator i = d_th->d_equivalence_class.find(n);
+ if(i == d_th->d_equivalence_class.end()){
+ d_eqc = NULL;
+ } else {
+ d_eqc = (*i).second;
+ d_eqc_i = d_eqc->begin();
+ }
+ }; //* the argument is not used
+ TNode getNextCandidate(){
+ if( d_eqc == NULL || d_eqc_i == d_eqc->end() ) return Node::null();
+ return *(d_eqc_i++);
+ };
+};
+
+
+}
+}
+}
+}
+
+#endif /* __CVC4__THEORY_DATATYPES_CANDIDATE_GENERATOR_H */
diff --git a/src/theory/datatypes/theory_datatypes_instantiator.cpp b/src/theory/datatypes/theory_datatypes_instantiator.cpp
index 9495e4d48..57e9324df 100644
--- a/src/theory/datatypes/theory_datatypes_instantiator.cpp
+++ b/src/theory/datatypes/theory_datatypes_instantiator.cpp
@@ -15,6 +15,7 @@
**/
#include "theory/datatypes/theory_datatypes_instantiator.h"
+#include "theory/datatypes/theory_datatypes_candidate_generator.h"
#include "theory/datatypes/theory_datatypes.h"
#include "theory/theory_engine.h"
#include "theory/quantifiers/term_database.h"
@@ -26,9 +27,9 @@ using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::datatypes;
-InstantiatorTheoryDatatypes::InstantiatorTheoryDatatypes(context::Context* c, QuantifiersEngine* ie, Theory* th) :
-Instantiator( c, ie, th ){
+InstantiatorTheoryDatatypes::InstantiatorTheoryDatatypes(context::Context* c, QuantifiersEngine* ie, TheoryDatatypes* th) :
+Instantiator( c, ie, th ){
}
void InstantiatorTheoryDatatypes::assertNode( Node assertion ){
@@ -60,7 +61,7 @@ int InstantiatorTheoryDatatypes::process( Node f, Theory::Effort effort, int e )
if( i.getType().isDatatype() ){
Node n = getValueFor( i );
Debug("quant-datatypes-debug") << "Value for " << i << " is " << n << std::endl;
- m.d_map[ i ] = n;
+ m.set(i,n);
}
}
d_quantEngine->addInstantiation( f, m );
@@ -168,3 +169,8 @@ bool InstantiatorTheoryDatatypes::areDisequal( Node a, Node b ){
Node InstantiatorTheoryDatatypes::getRepresentative( Node a ){
return ((TheoryDatatypes*)d_th)->getRepresentative( a );
}
+
+CVC4::theory::rrinst::CandidateGenerator* InstantiatorTheoryDatatypes::getRRCanGenClass(){
+ TheoryDatatypes* th = static_cast<TheoryDatatypes *>(getTheory());
+ return new datatypes::rrinst::CandidateGeneratorTheoryClass(th);
+}
diff --git a/src/theory/datatypes/theory_datatypes_instantiator.h b/src/theory/datatypes/theory_datatypes_instantiator.h
index a080465af..fd7190a22 100644
--- a/src/theory/datatypes/theory_datatypes_instantiator.h
+++ b/src/theory/datatypes/theory_datatypes_instantiator.h
@@ -28,10 +28,12 @@ namespace CVC4 {
namespace theory {
namespace datatypes {
+class TheoryDatatypes;
+
class InstantiatorTheoryDatatypes : public Instantiator{
friend class QuantifiersEngine;
public:
- InstantiatorTheoryDatatypes(context::Context* c, QuantifiersEngine* ie, Theory* th);
+ InstantiatorTheoryDatatypes(context::Context* c, QuantifiersEngine* ie, TheoryDatatypes* th);
~InstantiatorTheoryDatatypes() {}
/** assertNode function, assertion is asserted to theory */
@@ -59,10 +61,13 @@ public:
bool areEqual( Node a, Node b );
bool areDisequal( Node a, Node b );
Node getRepresentative( Node a );
+ /** general creators of candidate generators */
+ CVC4::theory::rrinst::CandidateGenerator* getRRCanGenClass();
};/* class InstantiatiorTheoryDatatypes */
+
}
}
}
-#endif \ No newline at end of file
+#endif
diff --git a/src/theory/inst_match.cpp b/src/theory/inst_match.cpp
index abcf5aa7f..4f1bfe67e 100644
--- a/src/theory/inst_match.cpp
+++ b/src/theory/inst_match.cpp
@@ -30,6 +30,7 @@ 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 ){
@@ -71,16 +72,24 @@ InstMatch::InstMatch( InstMatch* m ) {
d_map = m->d_map;
}
-bool InstMatch::setMatch( EqualityQuery* q, Node v, Node m ){
- if( d_map.find( v )==d_map.end() ){
- d_map[v] = m;
+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{
- return q->areEqual( d_map[v], m );
+ 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() ){
@@ -174,7 +183,7 @@ void InstMatch::computeTermVec( const std::vector< Node >& vars, std::vector< No
void InstMatchTrie::addInstMatch2( QuantifiersEngine* qe, Node f, InstMatch& m, int index, ImtIndexOrder* imtio ){
if( long(index)<long(f[0].getNumChildren()) && ( !imtio || long(index)<long(imtio->d_order.size()) ) ){
int i_index = imtio ? imtio->d_order[index] : index;
- Node n = m.d_map[ qe->getTermDatabase()->getInstantiationConstant( f, i_index ) ];
+ Node n = m.get( qe->getTermDatabase()->getInstantiationConstant( f, i_index ) );
d_data[n].addInstMatch2( qe, f, m, index+1, imtio );
}
}
@@ -185,7 +194,7 @@ bool InstMatchTrie::existsInstMatch( QuantifiersEngine* qe, Node f, InstMatch& m
return true;
}else{
int i_index = imtio ? imtio->d_order[index] : index;
- Node n = m.d_map[ qe->getTermDatabase()->getInstantiationConstant( f, i_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 ) ){
@@ -301,10 +310,10 @@ void InstMatchGenerator::initializePattern( Node pat, QuantifiersEngine* qe ){
//we will be producing candidates via literal matching heuristics
if( d_pattern.getKind()!=NOT ){
//candidates will be all equalities
- d_cg = new uf::CandidateGeneratorTheoryUfLitEq( ith, d_match_pattern );
+ d_cg = new uf::inst::CandidateGeneratorTheoryUfLitEq( ith, d_match_pattern );
}else{
//candidates will be all disequalities
- d_cg = new uf::CandidateGeneratorTheoryUfLitDeq( ith, d_match_pattern );
+ d_cg = new uf::inst::CandidateGeneratorTheoryUfLitDeq( ith, d_match_pattern );
}
}else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF || d_pattern.getKind()==NOT ){
Assert( d_matchPolicy==MATCH_GEN_DEFAULT );
@@ -313,20 +322,16 @@ void InstMatchGenerator::initializePattern( Node pat, QuantifiersEngine* qe ){
}else{
Assert( Trigger::isAtomicTrigger( d_match_pattern ) );
//we are matching only in a particular equivalence class
- d_cg = new uf::CandidateGeneratorTheoryUf( ith, d_match_pattern.getOperator() );
+ d_cg = new uf::inst::CandidateGeneratorTheoryUf( ith, 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 ){
- //we will manually add candidates to queue
- d_cg = new CandidateGeneratorQueue;
- //register this candidate generator
- ith->registerCandidateGenerator( d_cg, d_match_pattern );
- }else{
- //we will be scanning lists trying to find d_match_pattern.getOperator()
- d_cg = new uf::CandidateGeneratorTheoryUf( ith, d_match_pattern.getOperator() );
- }
+ //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 uf::inst::CandidateGeneratorTheoryUf( ith, d_match_pattern.getOperator() );
}else{
d_cg = new CandidateGeneratorQueue;
if( !Trigger::getPatternArithmetic( d_match_pattern.getAttribute(InstConstantAttribute()), d_match_pattern, d_arith_coeffs ) ){
@@ -347,7 +352,7 @@ void InstMatchGenerator::initializePattern( Node pat, QuantifiersEngine* qe ){
/** get match (not modulo equality) */
bool InstMatchGenerator::getMatch( Node t, InstMatch& m, QuantifiersEngine* qe ){
Debug("matching") << "Matching " << t << " against pattern " << d_match_pattern << " ("
- << m.d_map.size() << ")" << ", " << d_children.size() << std::endl;
+ << m.size() << ")" << ", " << d_children.size() << std::endl;
Assert( !d_match_pattern.isNull() );
if( qe->d_optMatchIgnoreModelBasis && t.getAttribute(ModelBasisAttribute()) ){
return true;
@@ -373,9 +378,9 @@ bool InstMatchGenerator::getMatch( Node t, InstMatch& m, QuantifiersEngine* qe )
//match is in conflict
Debug("matching-debug") << "Match in conflict " << t[i] << " and "
<< d_match_pattern[i] << " because "
- << partial[0].d_map[d_match_pattern[i]]
+ << partial[0].get(d_match_pattern[i])
<< std::endl;
- Debug("matching-fail") << "Match fail: " << partial[0].d_map[d_match_pattern[i]] << " and " << t[i] << std::endl;
+ Debug("matching-fail") << "Match fail: " << partial[0].get(d_match_pattern[i]) << " and " << t[i] << std::endl;
return false;
}
}
@@ -443,14 +448,14 @@ bool InstMatchGenerator::getMatchArithmetic( Node t, InstMatch& m, QuantifiersEn
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.d_map.find( it->first )==m.d_map.end() ){
+ 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.d_map[ it->first ] << std::endl;
- Node tm = m.d_map[ it->first ];
+ 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 );
}
@@ -473,12 +478,12 @@ bool InstMatchGenerator::getMatchArithmetic( Node t, InstMatch& m, QuantifiersEn
Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst<Rational>() );
tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm );
}
- m.d_map[ ic ] = Rewriter::rewrite( 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.d_map.find( it->first )==m.d_map.end() ){
- m.d_map[ it->first ] = NodeManager::currentNM()->mkConst( Rational(0) );
+ if( m.find( it->first )==m.end() ){
+ m.set( it->first, NodeManager::currentNM()->mkConst( Rational(0) ) );
}
}
}
@@ -754,7 +759,7 @@ void InstMatchGeneratorMulti::processNewInstantiations( QuantifiersEngine* qe, I
}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.d_map.find( curr_ic )==m.d_map.end() ){
+ 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 ) );
@@ -765,14 +770,14 @@ void InstMatchGeneratorMulti::processNewInstantiations( QuantifiersEngine* qe, I
//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.d_map[ curr_ic ] = it->first;
+ 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.d_map[ curr_ic ];
+ 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,
@@ -819,7 +824,7 @@ void InstMatchGeneratorMulti::processNewInstantiations2( QuantifiersEngine* qe,
//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.d_map[ curr_ic ] = it->first;
+ mn.set( curr_ic, it->first);
processNewInstantiations2( qe, mn, addedLemmas, unique_var_tries, uvtIndex, &(it->second), trieIndex+1 );
}
}else{
@@ -875,11 +880,11 @@ void InstMatchGeneratorSimple::addInstantiations( InstMatch& m, QuantifiersEngin
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.d_map[ ic ].isNull() || m.d_map[ ic ]==t ){
- Node prev = m.d_map[ ic ];
- m.d_map[ ic ] = t;
+ 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.d_map[ ic ] = prev;
+ m.set( ic, prev);
}
}
}else{
@@ -897,7 +902,7 @@ int InstMatchGeneratorSimple::addTerm( Node f, Node t, QuantifiersEngine* qe ){
InstMatch m;
for( int i=0; i<(int)t.getNumChildren(); i++ ){
if( d_match_pattern[i].getKind()==INST_CONSTANT ){
- m.d_map[d_match_pattern[i]] = t[i];
+ m.set(d_match_pattern[i], t[i]);
}else if( !qe->getEqualityQuery()->areEqual( d_match_pattern[i], t[i] ) ){
return 0;
}
diff --git a/src/theory/inst_match.h b/src/theory/inst_match.h
index 7cc5b2249..31a59b261 100644
--- a/src/theory/inst_match.h
+++ b/src/theory/inst_match.h
@@ -44,14 +44,40 @@ typedef expr::Attribute< NoMatchAttributeId,
true // context dependent
> NoMatchAttribute;
+// attribute for "contains instantiation constants from"
+struct InstConstantAttributeId {};
+typedef expr::Attribute<InstConstantAttributeId, Node> InstConstantAttribute;
+
+struct InstLevelAttributeId {};
+typedef expr::Attribute<InstLevelAttributeId, uint64_t> InstLevelAttribute;
+
+struct InstVarNumAttributeId {};
+typedef expr::Attribute<InstVarNumAttributeId, uint64_t> InstVarNumAttribute;
+
+// Attribute that tell if a node have been asserted in this branch
+struct AvailableInTermDbId {};
+/** use the special for boolean flag */
+typedef expr::Attribute<AvailableInTermDbId,
+ bool,
+ expr::attr::NullCleanupStrategy,
+ true // context dependent
+ > AvailableInTermDb;
+
+
class QuantifiersEngine;
+namespace quantifiers{
+ class TermArgTrie;
+}
-namespace uf {
+namespace uf{
class InstantiatorTheoryUf;
class TheoryUF;
}/* CVC4::theory::uf namespace */
-class CandidateGenerator {
+namespace inst {
+
+class CandidateGenerator
+{
public:
CandidateGenerator(){}
~CandidateGenerator(){}
@@ -95,7 +121,7 @@ public:
class EqualityQuery {
public:
EqualityQuery(){}
- ~EqualityQuery(){}
+ virtual ~EqualityQuery(){};
/** contains term */
virtual bool hasTerm( Node a ) = 0;
/** get the representative of the equivalence class of a */
@@ -113,12 +139,16 @@ public:
/** 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, Node v, Node 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
@@ -140,10 +170,30 @@ public:
void computeTermVec( const std::vector< Node >& vars, std::vector< Node >& match );
/** clear */
void clear(){ d_map.clear(); }
+ /** erase */
+ template<class Iterator>
+ 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(); }
- /* map from variable to ground terms */
- std::map< Node, Node > d_map;
+ /** 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;
@@ -207,67 +257,6 @@ public:
}
};/* class InstMatchTrieOrdered */
-template<bool modEq = false>
-class InstMatchTrie2 {
-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) CVC4_UNDEFINED;
- Tree(size_t l): level(l) {};
- ~Tree(){
- for(typename MLevel::iterator i = e.begin(); i!=e.end(); ++i)
- delete(i->second);
- };
- };/* class InstMatchTrie2::Tree */
-
-
- typedef std::pair<Tree *, TNode> 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);
- }
- };/* class InstMatchTrie2::CleanUp */
-
- EqualityQuery* d_eQ;
- eq::EqualityEngine* d_eE;
-
- /* before for the order of destruction */
- Tree d_data;
-
- context::Context* d_context;
- context::CDList<Mod, CleanUp, std::allocator<Mod> > d_mods;
-
- typedef std::map<Node, Node>::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;
-
-public:
- InstMatchTrie2(context::Context* c, QuantifiersEngine* q);
- InstMatchTrie2(const InstMatchTrie2&) CVC4_UNDEFINED;
- const InstMatchTrie2& operator=(const InstMatchTrie2 & e) CVC4_UNDEFINED;
- /** add match m in the trie,
- modEq specify to take into account equalities,
- return true if it was never seen */
- bool addInstMatch( InstMatch& m);
-};/* class InstMatchTrie2 */
-
/** base class for producing InstMatch objects */
class IMGenerator {
public:
@@ -405,10 +394,6 @@ public:
int addTerm( Node f, Node t, QuantifiersEngine* qe );
};/* class InstMatchGeneratorMulti */
-namespace quantifiers{
- class TermArgTrie;
-}
-
/** smart (single)-trigger implementation */
class InstMatchGeneratorSimple : public IMGenerator {
private:
@@ -438,6 +423,11 @@ public:
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 */
diff --git a/src/theory/instantiator_default.cpp b/src/theory/instantiator_default.cpp
index a1766ce3c..cff16962a 100644
--- a/src/theory/instantiator_default.cpp
+++ b/src/theory/instantiator_default.cpp
@@ -46,7 +46,7 @@ int InstantiatorDefault::process( Node f, Theory::Effort effort, int e ){
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.d_map[ i ] = val;
+ m.set( i, val);
}
}
d_quantEngine->addInstantiation( f, m );
diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp
index fae54c151..2b79cd8b9 100644
--- a/src/theory/quantifiers/instantiation_engine.cpp
+++ b/src/theory/quantifiers/instantiation_engine.cpp
@@ -104,7 +104,7 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){
int e_use = e;
if( e_use>=0 ){
//use each theory instantiator to instantiate f
- for( int i=0; i<theory::THEORY_LAST; i++ ){
+ for( theory::TheoryId i=theory::THEORY_FIRST; i<theory::THEORY_LAST; ++i ){
if( d_quantEngine->getInstantiator( i ) ){
Debug("inst-engine-debug") << "Do " << d_quantEngine->getInstantiator( i )->identify() << " " << e_use << std::endl;
int quantStatus = d_quantEngine->getInstantiator( i )->doInstantiation( f, effort, e_use );
@@ -126,7 +126,7 @@ bool InstantiationEngine::doInstantiationRound( Theory::Effort effort ){
//Notice() << "All instantiators finished, # added lemmas = " << (int)d_lemmas_waiting.size() << std::endl;
if( !d_quantEngine->hasAddedLemma() ){
Debug("inst-engine-stuck") << "No instantiations produced at this state: " << std::endl;
- for( int i=0; i<theory::THEORY_LAST; i++ ){
+ for( theory::TheoryId i=theory::THEORY_FIRST; i<theory::THEORY_LAST; ++i ){
if( d_quantEngine->getInstantiator( i ) ){
d_quantEngine->getInstantiator( i )->debugPrint("inst-engine-stuck");
Debug("inst-engine-stuck") << std::endl;
diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp
index ad259f864..663f270eb 100644
--- a/src/theory/quantifiers/model_engine.cpp
+++ b/src/theory/quantifiers/model_engine.cpp
@@ -39,6 +39,7 @@ using namespace CVC4::kind;
using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
+using namespace CVC4::theory::inst;
ModelEngineBuilder::ModelEngineBuilder( QuantifiersEngine* qe ) :
TheoryEngineModelBuilder( qe->getTheoryEngine() ),
@@ -503,7 +504,7 @@ int ModelEngine::initializeQuantifier( Node f ){
ics.push_back( ic );
terms.push_back( t );
//calculate the basis match for f
- d_builder.d_quant_basis_match[f].d_map[ ic ] = t;
+ d_builder.d_quant_basis_match[f].set( ic, t);
}
++(d_statistics.d_num_quants_init);
//register model basis body
diff --git a/src/theory/quantifiers/rep_set_iterator.cpp b/src/theory/quantifiers/rep_set_iterator.cpp
index 02041480f..a29f815db 100644
--- a/src/theory/quantifiers/rep_set_iterator.cpp
+++ b/src/theory/quantifiers/rep_set_iterator.cpp
@@ -97,7 +97,7 @@ bool RepSetIterator::isFinished(){
void RepSetIterator::getMatch( QuantifiersEngine* qe, InstMatch& m ){
for( int i=0; i<(int)d_index.size(); i++ ){
- m.d_map[ qe->getTermDatabase()->getInstantiationConstant( d_f, d_index_order[i] ) ] = getTerm( i );
+ m.set( qe->getTermDatabase()->getInstantiationConstant( d_f, d_index_order[i] ), getTerm( i ));
}
}
diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp
index 55ea693ef..55715353d 100644
--- a/src/theory/quantifiers/term_database.cpp
+++ b/src/theory/quantifiers/term_database.cpp
@@ -1,324 +1,365 @@
-/********************* */
-/*! \file term_database.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 term databse class
- **/
-
- #include "theory/quantifiers/term_database.h"
- #include "theory/quantifiers_engine.h"
- #include "theory/uf/theory_uf_instantiator.h"
- #include "theory/theory_engine.h"
- #include "theory/quantifiers/first_order_model.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-
- bool TermArgTrie::addTerm2( QuantifiersEngine* qe, Node n, int argIndex ){
- if( argIndex<(int)n.getNumChildren() ){
- Node r = qe->getEqualityQuery()->getRepresentative( n[ argIndex ] );
- std::map< Node, TermArgTrie >::iterator it = d_data.find( r );
- if( it==d_data.end() ){
- d_data[r].addTerm2( qe, n, argIndex+1 );
- return true;
- }else{
- return it->second.addTerm2( qe, n, argIndex+1 );
- }
- }else{
- //store n in d_data (this should be interpretted as the "data" and not as a reference to a child)
- d_data[n].d_data.clear();
- return false;
- }
- }
-
- void TermDb::addTerm( Node n, std::vector< Node >& added, bool withinQuant ){
- //don't add terms in quantifier bodies
- if( !withinQuant || Options::current()->registerQuantBodyTerms ){
- if( d_processed.find( n )==d_processed.end() ){
- d_processed[n] = true;
- //if this is an atomic trigger, consider adding it
- if( Trigger::isAtomicTrigger( n ) ){
- if( !n.hasAttribute(InstConstantAttribute()) ){
- Debug("term-db") << "register trigger term " << n << std::endl;
- //Notice() << "register trigger term " << n << std::endl;
- Node op = n.getOperator();
- d_op_map[op].push_back( n );
- d_type_map[ n.getType() ].push_back( n );
- added.push_back( n );
-
- uf::InstantiatorTheoryUf* d_ith = (uf::InstantiatorTheoryUf*)d_quantEngine->getInstantiator( THEORY_UF );
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- addTerm( n[i], added, withinQuant );
- if( Options::current()->efficientEMatching ){
- if( d_parents[n[i]][op].empty() ){
- //must add parent to equivalence class info
- Node nir = d_ith->getRepresentative( n[i] );
- uf::EqClassInfo* eci_nir = d_ith->getEquivalenceClassInfo( nir );
- if( eci_nir ){
- eci_nir->d_pfuns[ op ] = true;
- }
- }
- //add to parent structure
- if( std::find( d_parents[n[i]][op][i].begin(), d_parents[n[i]][op][i].end(), n )==d_parents[n[i]][op][i].end() ){
- d_parents[n[i]][op][i].push_back( n );
- }
- }
- }
- if( Options::current()->efficientEMatching ){
- //new term, add n to candidate generators
- for( int i=0; i<(int)d_ith->d_cand_gens[op].size(); i++ ){
- d_ith->d_cand_gens[op][i]->addCandidate( n );
- }
- }
- if( Options::current()->eagerInstQuant ){
- if( !n.hasAttribute(InstLevelAttribute()) && n.getAttribute(InstLevelAttribute())==0 ){
- int addedLemmas = 0;
- for( int i=0; i<(int)d_ith->d_op_triggers[op].size(); i++ ){
- addedLemmas += d_ith->d_op_triggers[op][i]->addTerm( n );
- }
- //Message() << "Terms, added lemmas: " << addedLemmas << std::endl;
- d_quantEngine->flushLemmas( &d_quantEngine->getTheoryEngine()->getTheory( THEORY_QUANTIFIERS )->getOutputChannel() );
- }
- }
- }
- }
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- addTerm( n[i], added, withinQuant );
- }
- }
- }
- }
-
- void TermDb::reset( Theory::Effort effort ){
- int nonCongruentCount = 0;
- int congruentCount = 0;
- int alreadyCongruentCount = 0;
- //rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms
- for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){
- if( !it->second.empty() ){
- if( it->second[0].getType()==NodeManager::currentNM()->booleanType() ){
- d_pred_map_trie[ 0 ][ it->first ].d_data.clear();
- d_pred_map_trie[ 1 ][ it->first ].d_data.clear();
- }else{
- d_func_map_trie[ it->first ].d_data.clear();
- for( int i=0; i<(int)it->second.size(); i++ ){
- Node n = it->second[i];
- if( !n.getAttribute(NoMatchAttribute()) ){
- if( !d_func_map_trie[ it->first ].addTerm( d_quantEngine, n ) ){
- NoMatchAttribute nma;
- n.setAttribute(nma,true);
- congruentCount++;
- }else{
- nonCongruentCount++;
- }
- }else{
- congruentCount++;
- alreadyCongruentCount++;
- }
- }
- }
- }
- }
- for( int i=0; i<2; i++ ){
- Node n = NodeManager::currentNM()->mkConst( i==1 );
- eq::EqClassIterator eqc( d_quantEngine->getEqualityQuery()->getRepresentative( n ),
- ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine() );
- while( !eqc.isFinished() ){
- Node en = (*eqc);
- if( en.getKind()==APPLY_UF && !en.hasAttribute(InstConstantAttribute()) ){
- if( !en.getAttribute(NoMatchAttribute()) ){
- Node op = en.getOperator();
- if( !d_pred_map_trie[i][op].addTerm( d_quantEngine, en ) ){
- NoMatchAttribute nma;
- en.setAttribute(nma,true);
- congruentCount++;
- }else{
- nonCongruentCount++;
- }
- }else{
- alreadyCongruentCount++;
- }
- }
- ++eqc;
- }
- }
- Debug("term-db-cong") << "TermDb: Reset" << std::endl;
- Debug("term-db-cong") << "Congruent/Non-Congruent = ";
- Debug("term-db-cong") << congruentCount << "(" << alreadyCongruentCount << ") / " << nonCongruentCount << std::endl;
-}
-
-void TermDb::registerModelBasis( Node n, Node gn ){
- if( d_model_basis.find( n )==d_model_basis.end() ){
- d_model_basis[n] = gn;
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- registerModelBasis( n[i], gn[i] );
- }
- }
-}
-
-Node TermDb::getModelBasisTerm( TypeNode tn, int i ){
- if( d_model_basis_term.find( tn )==d_model_basis_term.end() ){
- std::stringstream ss;
- ss << Expr::setlanguage(Options::current()->outputLanguage);
- ss << "e_" << tn;
- d_model_basis_term[tn] = NodeManager::currentNM()->mkVar( ss.str(), tn );
- ModelBasisAttribute mba;
- d_model_basis_term[tn].setAttribute(mba,true);
- }
- return d_model_basis_term[tn];
-}
-
-Node TermDb::getModelBasisOpTerm( Node op ){
- if( d_model_basis_op_term.find( op )==d_model_basis_op_term.end() ){
- TypeNode t = op.getType();
- std::vector< Node > children;
- children.push_back( op );
- for( size_t i=0; i<t.getNumChildren()-1; i++ ){
- children.push_back( getModelBasisTerm( t[i] ) );
- }
- d_model_basis_op_term[op] = NodeManager::currentNM()->mkNode( APPLY_UF, children );
- }
- return d_model_basis_op_term[op];
-}
-
-void TermDb::computeModelBasisArgAttribute( Node n ){
- if( !n.hasAttribute(ModelBasisArgAttribute()) ){
- uint64_t val = 0;
- //determine if it has model basis attribute
- for( int j=0; j<(int)n.getNumChildren(); j++ ){
- if( n[j].getAttribute(ModelBasisAttribute()) ){
- val = 1;
- break;
- }
- }
- ModelBasisArgAttribute mbaa;
- n.setAttribute( mbaa, val );
- }
-}
-
-void TermDb::makeInstantiationConstantsFor( Node f ){
- if( d_inst_constants.find( f )==d_inst_constants.end() ){
- Debug("quantifiers-engine") << "Instantiation constants for " << f << " : " << std::endl;
- for( int i=0; i<(int)f[0].getNumChildren(); i++ ){
- d_vars[f].push_back( f[0][i] );
- //make instantiation constants
- Node ic = NodeManager::currentNM()->mkInstConstant( f[0][i].getType() );
- d_inst_constants_map[ic] = f;
- d_inst_constants[ f ].push_back( ic );
- Debug("quantifiers-engine") << " " << ic << std::endl;
- //set the var number attribute
- InstVarNumAttribute ivna;
- ic.setAttribute(ivna,i);
- }
- }
-}
-
-void TermDb::setInstantiationLevelAttr( Node n, uint64_t level ){
- if( !n.hasAttribute(InstLevelAttribute()) ){
- InstLevelAttribute ila;
- n.setAttribute(ila,level);
- }
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- setInstantiationLevelAttr( n[i], level );
- }
-}
-
-
-void TermDb::setInstantiationConstantAttr( Node n, Node f ){
- if( !n.hasAttribute(InstConstantAttribute()) ){
- bool setAttr = false;
- if( n.getKind()==INST_CONSTANT ){
- setAttr = true;
- }else{
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- setInstantiationConstantAttr( n[i], f );
- if( n[i].hasAttribute(InstConstantAttribute()) ){
- setAttr = true;
- }
- }
- }
- if( setAttr ){
- InstConstantAttribute ica;
- n.setAttribute(ica,f);
- //also set the no-match attribute
- NoMatchAttribute nma;
- n.setAttribute(nma,true);
- }
- }
-}
-
-
-Node TermDb::getCounterexampleBody( Node f ){
- std::map< Node, Node >::iterator it = d_counterexample_body.find( f );
- if( it==d_counterexample_body.end() ){
- makeInstantiationConstantsFor( f );
- Node n = getSubstitutedNode( f[1], f );
- d_counterexample_body[ f ] = n;
- return n;
- }else{
- return it->second;
- }
-}
-
-Node TermDb::getSkolemizedBody( Node f ){
- Assert( f.getKind()==FORALL );
- if( d_skolem_body.find( f )==d_skolem_body.end() ){
- std::vector< Node > vars;
- for( int i=0; i<(int)f[0].getNumChildren(); i++ ){
- Node skv = NodeManager::currentNM()->mkSkolem( f[0][i].getType() );
- d_skolem_constants[ f ].push_back( skv );
- vars.push_back( f[0][i] );
- }
- d_skolem_body[ f ] = f[ 1 ].substitute( vars.begin(), vars.end(),
- d_skolem_constants[ f ].begin(), d_skolem_constants[ f ].end() );
- if( f.hasAttribute(InstLevelAttribute()) ){
- setInstantiationLevelAttr( d_skolem_body[ f ], f.getAttribute(InstLevelAttribute()) );
- }
- }
- return d_skolem_body[ f ];
-}
-
-
-Node TermDb::getSubstitutedNode( Node n, Node f ){
- return convertNodeToPattern(n,f,d_vars[f],d_inst_constants[ f ]);
-}
-
-Node TermDb::convertNodeToPattern( Node n, Node f, const std::vector<Node> & vars,
- const std::vector<Node> & inst_constants){
- Node n2 = n.substitute( vars.begin(), vars.end(),
- inst_constants.begin(),
- inst_constants.end() );
- setInstantiationConstantAttr( n2, f );
- return n2;
-}
-
-Node TermDb::getFreeVariableForInstConstant( Node n ){
- TypeNode tn = n.getType();
- if( d_free_vars.find( tn )==d_free_vars.end() ){
- //if integer or real, make zero
- if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){
- Rational z(0);
- d_free_vars[tn] = NodeManager::currentNM()->mkConst( z );
- }else{
- if( d_type_map[ tn ].empty() ){
- d_free_vars[tn] = NodeManager::currentNM()->mkVar( tn );
- }else{
- d_free_vars[tn] = d_type_map[ tn ][ 0 ];
- }
- }
- }
- return d_free_vars[tn];
-} \ No newline at end of file
+/********************* */
+/*! \file term_database.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: none
+ ** Minor contributors (to current version): bobot
+ ** 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 term databse class
+ **/
+
+ #include "theory/quantifiers/term_database.h"
+ #include "theory/quantifiers_engine.h"
+ #include "theory/uf/theory_uf_instantiator.h"
+ #include "theory/theory_engine.h"
+ #include "theory/quantifiers/first_order_model.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+
+using namespace CVC4::theory::inst;
+ bool TermArgTrie::addTerm2( QuantifiersEngine* qe, Node n, int argIndex ){
+ if( argIndex<(int)n.getNumChildren() ){
+ Node r = qe->getEqualityQuery()->getRepresentative( n[ argIndex ] );
+ std::map< Node, TermArgTrie >::iterator it = d_data.find( r );
+ if( it==d_data.end() ){
+ d_data[r].addTerm2( qe, n, argIndex+1 );
+ return true;
+ }else{
+ return it->second.addTerm2( qe, n, argIndex+1 );
+ }
+ }else{
+ //store n in d_data (this should be interpretted as the "data" and not as a reference to a child)
+ d_data[n].d_data.clear();
+ return false;
+ }
+ }
+
+void addTermEfficient( Node n, std::set< Node >& added){
+ static AvailableInTermDb aitdi;
+ if (Trigger::isAtomicTrigger( n ) && !n.getAttribute(aitdi)){
+ //Already processed but new in this branch
+ n.setAttribute(aitdi,true);
+ added.insert( n );
+ for( size_t i=0; i< n.getNumChildren(); i++ ){
+ addTermEfficient(n[i],added);
+ }
+ }
+
+}
+
+
+void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
+ //don't add terms in quantifier bodies
+ if( withinQuant && !Options::current()->registerQuantBodyTerms ){
+ return;
+ }
+ if( d_processed.find( n )==d_processed.end() ){
+ ++(d_quantEngine->d_statistics.d_term_in_termdb);
+ d_processed.insert(n);
+ n.setAttribute(AvailableInTermDb(),true);
+ //if this is an atomic trigger, consider adding it
+ //Call the children?
+ if( Trigger::isAtomicTrigger( n ) || n.getKind() == kind::APPLY_CONSTRUCTOR ){
+ if( !n.hasAttribute(InstConstantAttribute()) ){
+ Debug("term-db") << "register trigger term " << n << std::endl;
+ //std::cout << "register trigger term " << n << std::endl;
+ Node op = n.getOperator();
+ d_op_map[op].push_back( n );
+ d_type_map[ n.getType() ].push_back( n );
+ added.insert( n );
+
+ uf::InstantiatorTheoryUf* d_ith = (uf::InstantiatorTheoryUf*)d_quantEngine->getInstantiator( THEORY_UF );
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ addTerm( n[i], added, withinQuant );
+ if( Options::current()->efficientEMatching ){
+ if( d_parents[n[i]][op].empty() ){
+ //must add parent to equivalence class info
+ Node nir = d_ith->getRepresentative( n[i] );
+ uf::EqClassInfo* eci_nir = d_ith->getEquivalenceClassInfo( nir );
+ if( eci_nir ){
+ eci_nir->d_pfuns[ op ] = true;
+ }
+ }
+ //add to parent structure
+ if( std::find( d_parents[n[i]][op][i].begin(), d_parents[n[i]][op][i].end(), n )==d_parents[n[i]][op][i].end() ){
+ d_parents[n[i]][op][i].push_back( n );
+ Assert(!getParents(n[i],op,i).empty());
+ }
+ }
+ if( Options::current()->eagerInstQuant ){
+ if( !n.hasAttribute(InstLevelAttribute()) && n.getAttribute(InstLevelAttribute())==0 ){
+ int addedLemmas = 0;
+ for( int i=0; i<(int)d_ith->d_op_triggers[op].size(); i++ ){
+ addedLemmas += d_ith->d_op_triggers[op][i]->addTerm( n );
+ }
+ //Message() << "Terms, added lemmas: " << addedLemmas << std::endl;
+ d_quantEngine->flushLemmas( &d_quantEngine->getTheoryEngine()->getTheory( THEORY_QUANTIFIERS )->getOutputChannel() );
+ }
+ }
+ }
+ }
+ }else{
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ addTerm( n[i], added, withinQuant );
+ }
+ }
+ }else{
+ if( Options::current()->efficientEMatching &&
+ !n.hasAttribute(InstConstantAttribute())){
+ //Efficient e-matching must be notified
+ //The term in triggers are not important here
+ Debug("term-db") << "New in this branch term " << n << std::endl;
+ addTermEfficient(n,added);
+ }
+ }
+};
+
+ void TermDb::reset( Theory::Effort effort ){
+ int nonCongruentCount = 0;
+ int congruentCount = 0;
+ int alreadyCongruentCount = 0;
+ //rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms
+ for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){
+ if( !it->second.empty() ){
+ if( it->second[0].getType()==NodeManager::currentNM()->booleanType() ){
+ d_pred_map_trie[ 0 ][ it->first ].d_data.clear();
+ d_pred_map_trie[ 1 ][ it->first ].d_data.clear();
+ }else{
+ d_func_map_trie[ it->first ].d_data.clear();
+ for( int i=0; i<(int)it->second.size(); i++ ){
+ Node n = it->second[i];
+ if( !n.getAttribute(NoMatchAttribute()) ){
+ if( !d_func_map_trie[ it->first ].addTerm( d_quantEngine, n ) ){
+ NoMatchAttribute nma;
+ n.setAttribute(nma,true);
+ congruentCount++;
+ }else{
+ nonCongruentCount++;
+ }
+ }else{
+ congruentCount++;
+ alreadyCongruentCount++;
+ }
+ }
+ }
+ }
+ }
+ for( int i=0; i<2; i++ ){
+ Node n = NodeManager::currentNM()->mkConst( i==1 );
+ eq::EqClassIterator eqc( d_quantEngine->getEqualityQuery()->getRepresentative( n ),
+ ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine() );
+ while( !eqc.isFinished() ){
+ Node en = (*eqc);
+ if( en.getKind()==APPLY_UF && !en.hasAttribute(InstConstantAttribute()) ){
+ if( !en.getAttribute(NoMatchAttribute()) ){
+ Node op = en.getOperator();
+ if( !d_pred_map_trie[i][op].addTerm( d_quantEngine, en ) ){
+ NoMatchAttribute nma;
+ en.setAttribute(nma,true);
+ congruentCount++;
+ }else{
+ nonCongruentCount++;
+ }
+ }else{
+ alreadyCongruentCount++;
+ }
+ }
+ ++eqc;
+ }
+ }
+ Debug("term-db-cong") << "TermDb: Reset" << std::endl;
+ Debug("term-db-cong") << "Congruent/Non-Congruent = ";
+ Debug("term-db-cong") << congruentCount << "(" << alreadyCongruentCount << ") / " << nonCongruentCount << std::endl;
+}
+
+void TermDb::registerModelBasis( Node n, Node gn ){
+ if( d_model_basis.find( n )==d_model_basis.end() ){
+ d_model_basis[n] = gn;
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ registerModelBasis( n[i], gn[i] );
+ }
+ }
+}
+
+Node TermDb::getModelBasisTerm( TypeNode tn, int i ){
+ if( d_model_basis_term.find( tn )==d_model_basis_term.end() ){
+ std::stringstream ss;
+ ss << Expr::setlanguage(Options::current()->outputLanguage);
+ ss << "e_" << tn;
+ d_model_basis_term[tn] = NodeManager::currentNM()->mkVar( ss.str(), tn );
+ ModelBasisAttribute mba;
+ d_model_basis_term[tn].setAttribute(mba,true);
+ }
+ return d_model_basis_term[tn];
+}
+
+Node TermDb::getModelBasisOpTerm( Node op ){
+ if( d_model_basis_op_term.find( op )==d_model_basis_op_term.end() ){
+ TypeNode t = op.getType();
+ std::vector< Node > children;
+ children.push_back( op );
+ for( size_t i=0; i<t.getNumChildren()-1; i++ ){
+ children.push_back( getModelBasisTerm( t[i] ) );
+ }
+ d_model_basis_op_term[op] = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ }
+ return d_model_basis_op_term[op];
+}
+
+void TermDb::computeModelBasisArgAttribute( Node n ){
+ if( !n.hasAttribute(ModelBasisArgAttribute()) ){
+ uint64_t val = 0;
+ //determine if it has model basis attribute
+ for( int j=0; j<(int)n.getNumChildren(); j++ ){
+ if( n[j].getAttribute(ModelBasisAttribute()) ){
+ val = 1;
+ break;
+ }
+ }
+ ModelBasisArgAttribute mbaa;
+ n.setAttribute( mbaa, val );
+ }
+}
+
+void TermDb::makeInstantiationConstantsFor( Node f ){
+ if( d_inst_constants.find( f )==d_inst_constants.end() ){
+ Debug("quantifiers-engine") << "Instantiation constants for " << f << " : " << std::endl;
+ for( int i=0; i<(int)f[0].getNumChildren(); i++ ){
+ d_vars[f].push_back( f[0][i] );
+ //make instantiation constants
+ Node ic = NodeManager::currentNM()->mkInstConstant( f[0][i].getType() );
+ d_inst_constants_map[ic] = f;
+ d_inst_constants[ f ].push_back( ic );
+ Debug("quantifiers-engine") << " " << ic << std::endl;
+ //set the var number attribute
+ InstVarNumAttribute ivna;
+ ic.setAttribute(ivna,i);
+ }
+ }
+}
+
+void TermDb::setInstantiationLevelAttr( Node n, uint64_t level ){
+ if( !n.hasAttribute(InstLevelAttribute()) ){
+ InstLevelAttribute ila;
+ n.setAttribute(ila,level);
+ }
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ setInstantiationLevelAttr( n[i], level );
+ }
+}
+
+
+void TermDb::setInstantiationConstantAttr( Node n, Node f ){
+ if( !n.hasAttribute(InstConstantAttribute()) ){
+ bool setAttr = false;
+ if( n.getKind()==INST_CONSTANT ){
+ setAttr = true;
+ }else{
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ setInstantiationConstantAttr( n[i], f );
+ if( n[i].hasAttribute(InstConstantAttribute()) ){
+ setAttr = true;
+ }
+ }
+ }
+ if( setAttr ){
+ InstConstantAttribute ica;
+ n.setAttribute(ica,f);
+ //also set the no-match attribute
+ NoMatchAttribute nma;
+ n.setAttribute(nma,true);
+ }
+ }
+}
+
+
+Node TermDb::getCounterexampleBody( Node f ){
+ std::map< Node, Node >::iterator it = d_counterexample_body.find( f );
+ if( it==d_counterexample_body.end() ){
+ makeInstantiationConstantsFor( f );
+ Node n = getSubstitutedNode( f[1], f );
+ d_counterexample_body[ f ] = n;
+ return n;
+ }else{
+ return it->second;
+ }
+}
+
+Node TermDb::getSkolemizedBody( Node f ){
+ Assert( f.getKind()==FORALL );
+ if( d_skolem_body.find( f )==d_skolem_body.end() ){
+ std::vector< Node > vars;
+ for( int i=0; i<(int)f[0].getNumChildren(); i++ ){
+ Node skv = NodeManager::currentNM()->mkSkolem( f[0][i].getType() );
+ d_skolem_constants[ f ].push_back( skv );
+ vars.push_back( f[0][i] );
+ }
+ d_skolem_body[ f ] = f[ 1 ].substitute( vars.begin(), vars.end(),
+ d_skolem_constants[ f ].begin(), d_skolem_constants[ f ].end() );
+ if( f.hasAttribute(InstLevelAttribute()) ){
+ setInstantiationLevelAttr( d_skolem_body[ f ], f.getAttribute(InstLevelAttribute()) );
+ }
+ }
+ return d_skolem_body[ f ];
+}
+
+
+Node TermDb::getSubstitutedNode( Node n, Node f ){
+ return convertNodeToPattern(n,f,d_vars[f],d_inst_constants[ f ]);
+}
+
+Node TermDb::convertNodeToPattern( Node n, Node f, const std::vector<Node> & vars,
+ const std::vector<Node> & inst_constants){
+ Node n2 = n.substitute( vars.begin(), vars.end(),
+ inst_constants.begin(),
+ inst_constants.end() );
+ setInstantiationConstantAttr( n2, f );
+ return n2;
+}
+
+Node TermDb::getFreeVariableForInstConstant( Node n ){
+ TypeNode tn = n.getType();
+ if( d_free_vars.find( tn )==d_free_vars.end() ){
+ //if integer or real, make zero
+ if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){
+ Rational z(0);
+ d_free_vars[tn] = NodeManager::currentNM()->mkConst( z );
+ }else{
+ if( d_type_map[ tn ].empty() ){
+ d_free_vars[tn] = NodeManager::currentNM()->mkVar( tn );
+ }else{
+ d_free_vars[tn] = d_type_map[ tn ][ 0 ];
+ }
+ }
+ }
+ return d_free_vars[tn];
+}
+
+const std::vector<Node> & TermDb::getParents(TNode n, TNode f, int arg){
+ std::hash_map< Node, std::hash_map< Node, std::hash_map< int, std::vector< Node > >,NodeHashFunction >,NodeHashFunction >::const_iterator
+ rn = d_parents.find( n );
+ if( rn !=d_parents.end() ){
+ std::hash_map< Node, std::hash_map< int, std::vector< Node > > , NodeHashFunction > ::const_iterator
+ rf = rn->second.find(f);
+ if( rf != rn->second.end() ){
+ std::hash_map< int, std::vector< Node > > ::const_iterator
+ ra = rf->second.find(arg);
+ if( ra != rf->second.end() ){
+ return ra->second;
+ }
+ }
+ }
+ static std::vector<Node> empty;
+ return empty;
+}
diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h
index 5bf3d7900..5004a82dc 100644
--- a/src/theory/quantifiers/term_database.h
+++ b/src/theory/quantifiers/term_database.h
@@ -48,7 +48,7 @@ private:
/** calculated no match terms */
bool d_matching_active;
/** terms processed */
- std::map< Node, bool > d_processed;
+ std::hash_set< Node, NodeHashFunction > d_processed;
public:
TermDb( QuantifiersEngine* qe ) : d_quantEngine( qe ), d_matching_active( true ){}
~TermDb(){}
@@ -61,7 +61,7 @@ public:
/** map from type nodes to terms of that type */
std::map< TypeNode, std::vector< Node > > d_type_map;
/** add a term to the database */
- void addTerm( Node n, std::vector< Node >& added, bool withinQuant = false );
+ void addTerm( Node n, std::set< Node >& added, bool withinQuant = false );
/** reset (calculate which terms are active) */
void reset( Theory::Effort effort );
/** set active */
@@ -75,7 +75,9 @@ public:
has operator "op", and n'["index"] = n.
for example, d_parents[n][f][1] = { f( t1, n ), f( t2, n ), ... }
*/
- std::map< Node, std::map< Node, std::map< int, std::vector< Node > > > > d_parents;
+ /* Todo replace int by size_t */
+ std::hash_map< Node, std::hash_map< Node, std::hash_map< int, std::vector< Node > >, NodeHashFunction > , NodeHashFunction > d_parents;
+ const std::vector<Node> & getParents(TNode n, TNode f, int arg);
private:
//map from types to model basis terms
std::map< TypeNode, Node > d_model_basis_term;
diff --git a/src/theory/quantifiers/theory_quantifiers.h b/src/theory/quantifiers/theory_quantifiers.h
index 517786400..1e42abd22 100644
--- a/src/theory/quantifiers/theory_quantifiers.h
+++ b/src/theory/quantifiers/theory_quantifiers.h
@@ -30,10 +30,11 @@
#include <map>
namespace CVC4 {
+class TheoryEngine;
+
namespace theory {
namespace quantifiers {
-class TheoryEngine;
class ModelEngine;
class InstantiationEngine;
diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp
index e4e3df9be..448224b81 100644
--- a/src/theory/quantifiers_engine.cpp
+++ b/src/theory/quantifiers_engine.cpp
@@ -32,6 +32,7 @@ using namespace CVC4;
using namespace CVC4::kind;
using namespace CVC4::context;
using namespace CVC4::theory;
+using namespace CVC4::theory::inst;
//#define COMPUTE_RELEVANCE
//#define REWRITE_ASSERTED_QUANTIFIERS
@@ -93,7 +94,11 @@ d_active( c ){
d_optInstLimit = 0;
}
-Instantiator* QuantifiersEngine::getInstantiator( int id ){
+QuantifiersEngine::~QuantifiersEngine(){
+ delete(d_term_db);
+}
+
+Instantiator* QuantifiersEngine::getInstantiator( theory::TheoryId id ){
return d_te->getTheory( id )->getInstantiator();
}
@@ -212,7 +217,7 @@ void QuantifiersEngine::registerQuantifier( Node f ){
void QuantifiersEngine::registerPattern( std::vector<Node> & pattern) {
for(std::vector<Node>::iterator p = pattern.begin(); p != pattern.end(); ++p){
- std::vector< Node > added;
+ std::set< Node > added;
getTermDatabase()->addTerm(*p,added);
}
}
@@ -236,7 +241,7 @@ void QuantifiersEngine::propagate( Theory::Effort level ){
}
void QuantifiersEngine::resetInstantiationRound( Theory::Effort level ){
- for( int i=0; i<theory::THEORY_LAST; i++ ){
+ for( theory::TheoryId i=theory::THEORY_FIRST; i<theory::THEORY_LAST; ++i ){
if( getInstantiator( i ) ){
getInstantiator( i )->resetInstantiationRound( level );
}
@@ -245,13 +250,19 @@ void QuantifiersEngine::resetInstantiationRound( Theory::Effort level ){
}
void QuantifiersEngine::addTermToDatabase( Node n, bool withinQuant ){
- std::vector< Node > added;
- getTermDatabase()->addTerm( n, added, withinQuant );
-#ifdef COMPUTE_RELEVANCE
- for( int i=0; i<(int)added.size(); i++ ){
- if( !withinQuant ){
- setRelevance( added[i].getOperator(), 0 );
+ std::set< Node > added;
+ getTermDatabase()->addTerm( n, added, withinQuant );
+ if( Options::current()->efficientEMatching ){
+ uf::InstantiatorTheoryUf* d_ith = (uf::InstantiatorTheoryUf*)getInstantiator( THEORY_UF );
+ d_ith->newTerms(added);
}
+#ifdef COMPUTE_RELEVANCE
+ //added contains also the Node that just have been asserted in this branch
+ for( std::set< Node >::iterator i=added.begin(), end=added.end();
+ i!=end; i++ ){
+ if( !withinQuant ){
+ setRelevance( i->getOperator(), 0 );
+ }
}
#endif
@@ -530,7 +541,15 @@ QuantifiersEngine::Statistics::Statistics():
d_triggers("QuantifiersEngine::Triggers", 0),
d_simple_triggers("QuantifiersEngine::Triggers_Simple", 0),
d_multi_triggers("QuantifiersEngine::Triggers_Multi", 0),
- d_multi_trigger_instantiations("QuantifiersEngine::Multi_Trigger_Instantiations", 0)
+ d_multi_trigger_instantiations("QuantifiersEngine::Multi_Trigger_Instantiations", 0),
+ d_term_in_termdb("QuantifiersEngine::Term_in_TermDb", 0),
+ d_num_mono_candidates("QuantifiersEngine::NumMonoCandidates", 0),
+ d_num_mono_candidates_new_term("QuantifiersEngine::NumMonoCandidatesNewTerm", 0),
+ d_num_multi_candidates("QuantifiersEngine::NumMultiCandidates", 0),
+ d_mono_candidates_cache_hit("QuantifiersEngine::MonoCandidatesCacheHit", 0),
+ d_mono_candidates_cache_miss("QuantifiersEngine::MonoCandidatesCacheMiss", 0),
+ d_multi_candidates_cache_hit("QuantifiersEngine::MultiCandidatesCacheHit", 0),
+ d_multi_candidates_cache_miss("QuantifiersEngine::MultiCandidatesCacheMiss", 0)
{
StatisticsRegistry::registerStat(&d_num_quant);
StatisticsRegistry::registerStat(&d_instantiation_rounds);
@@ -548,6 +567,14 @@ QuantifiersEngine::Statistics::Statistics():
StatisticsRegistry::registerStat(&d_simple_triggers);
StatisticsRegistry::registerStat(&d_multi_triggers);
StatisticsRegistry::registerStat(&d_multi_trigger_instantiations);
+ StatisticsRegistry::registerStat(&d_term_in_termdb);
+ StatisticsRegistry::registerStat(&d_num_mono_candidates);
+ StatisticsRegistry::registerStat(&d_num_mono_candidates_new_term);
+ StatisticsRegistry::registerStat(&d_num_multi_candidates);
+ StatisticsRegistry::registerStat(&d_mono_candidates_cache_hit);
+ StatisticsRegistry::registerStat(&d_mono_candidates_cache_miss);
+ StatisticsRegistry::registerStat(&d_multi_candidates_cache_hit);
+ StatisticsRegistry::registerStat(&d_multi_candidates_cache_miss);
}
QuantifiersEngine::Statistics::~Statistics(){
@@ -567,6 +594,14 @@ QuantifiersEngine::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_simple_triggers);
StatisticsRegistry::unregisterStat(&d_multi_triggers);
StatisticsRegistry::unregisterStat(&d_multi_trigger_instantiations);
+ StatisticsRegistry::unregisterStat(&d_term_in_termdb);
+ StatisticsRegistry::unregisterStat(&d_num_mono_candidates);
+ StatisticsRegistry::unregisterStat(&d_num_mono_candidates_new_term);
+ StatisticsRegistry::unregisterStat(&d_num_multi_candidates);
+ StatisticsRegistry::unregisterStat(&d_mono_candidates_cache_hit);
+ StatisticsRegistry::unregisterStat(&d_mono_candidates_cache_miss);
+ StatisticsRegistry::unregisterStat(&d_multi_candidates_cache_hit);
+ StatisticsRegistry::unregisterStat(&d_multi_candidates_cache_miss);
}
/** compute symbols */
@@ -608,7 +643,7 @@ bool EqualityQueryQuantifiersEngine::hasTerm( Node a ){
if( ee->hasTerm( a ) ){
return true;
}
- for( int i=0; i<theory::THEORY_LAST; i++ ){
+ for( theory::TheoryId i=theory::THEORY_FIRST; i<theory::THEORY_LAST; ++i ){
if( d_qe->getInstantiator( i ) ){
if( d_qe->getInstantiator( i )->hasTerm( a ) ){
return true;
@@ -623,7 +658,7 @@ Node EqualityQueryQuantifiersEngine::getRepresentative( Node a ){
if( ee->hasTerm( a ) ){
return ee->getRepresentative( a );
}
- for( int i=0; i<theory::THEORY_LAST; i++ ){
+ for( theory::TheoryId i=theory::THEORY_FIRST; i<theory::THEORY_LAST; ++i ){
if( d_qe->getInstantiator( i ) ){
if( d_qe->getInstantiator( i )->hasTerm( a ) ){
return d_qe->getInstantiator( i )->getRepresentative( a );
@@ -643,7 +678,7 @@ bool EqualityQueryQuantifiersEngine::areEqual( Node a, Node b ){
return true;
}
}
- for( int i=0; i<theory::THEORY_LAST; i++ ){
+ for( theory::TheoryId i=theory::THEORY_FIRST; i<theory::THEORY_LAST; ++i ){
if( d_qe->getInstantiator( i ) ){
if( d_qe->getInstantiator( i )->areEqual( a, b ) ){
return true;
@@ -662,7 +697,7 @@ bool EqualityQueryQuantifiersEngine::areDisequal( Node a, Node b ){
return true;
}
}
- for( int i=0; i<theory::THEORY_LAST; i++ ){
+ for( theory::TheoryId i=theory::THEORY_FIRST; i<theory::THEORY_LAST; ++i ){
if( d_qe->getInstantiator( i ) ){
if( d_qe->getInstantiator( i )->areDisequal( a, b ) ){
return true;
@@ -674,7 +709,7 @@ bool EqualityQueryQuantifiersEngine::areDisequal( Node a, Node b ){
}
Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a ){
- //for( int i=0; i<theory::THEORY_LAST; i++ ){
+ //for( theory::TheoryId i=theory::THEORY_FIRST; i<theory::THEORY_LAST; ++i ){
// if( d_qe->getInstantiator( i ) ){
// if( d_qe->getInstantiator( i )->hasTerm( a ) ){
// return d_qe->getInstantiator( i )->getInternalRepresentative( a );
@@ -684,3 +719,217 @@ Node EqualityQueryQuantifiersEngine::getInternalRepresentative( Node a ){
//return a;
return d_qe->getInstantiator( THEORY_UF )->getInternalRepresentative( a );
}
+
+inst::EqualityQuery* QuantifiersEngine::getEqualityQuery(TypeNode t) {
+ /** Should use skeleton (in order to have the type and the kind
+ or any needed other information) instead of only the type */
+
+ // TheoryId id = Theory::theoryOf(t);
+ // inst::EqualityQuery* eq = d_eq_query_arr[id];
+ // if(eq == NULL) return d_eq_query_arr[theory::THEORY_UF];
+ // else return eq;
+
+ /** hack because the generic one is too slow */
+ // TheoryId id = Theory::theoryOf(t);
+ // if( true || id == theory::THEORY_UF){
+ // uf::InstantiatorTheoryUf* ith = static_cast<uf::InstantiatorTheoryUf*>( getInstantiator( theory::THEORY_UF ));
+ // return new uf::EqualityQueryInstantiatorTheoryUf(ith);
+ // }
+ // inst::EqualityQuery* eq = d_eq_query_arr[id];
+ // if(eq == NULL) return d_eq_query_arr[theory::THEORY_UF];
+ // else return eq;
+
+
+ //Currently we use the generic EqualityQuery
+ return getEqualityQuery();
+}
+
+
+// // Just iterate amoung the equivalence class of the given node
+// // node::Null() *can't* be given to reset
+// class CandidateGeneratorClassGeneric : 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;
+// }
+// };
+// };
+
+
+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){
+ 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(){
+ for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){
+ delete(d_can_gen[i]);
+ };
+ }
+
+ void 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 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 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 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);
+ }
+
+};
+
+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): 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(){
+ for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){
+ delete(d_can_gen[i]);
+ };
+ }
+
+ void 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 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 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 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 ))
+ );
+ }
+
+};
+
+
+rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClasses() {
+ return new GenericCandidateGeneratorClasses(this);
+}
+
+rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClass() {
+ return new GenericCandidateGeneratorClass(this);
+}
+
+rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClasses(TypeNode t) {
+ // TheoryId id = Theory::theoryOf(t);
+ // rrinst::CandidateGenerator* eq = getInstantiator(id)->getRRCanGenClasses();
+ // if(eq == NULL) return getInstantiator(id)->getRRCanGenClasses();
+ // else return eq;
+ return getRRCanGenClasses();
+}
+
+rrinst::CandidateGenerator* QuantifiersEngine::getRRCanGenClass(TypeNode t) {
+ // TheoryId id = Theory::theoryOf(t);
+ // rrinst::CandidateGenerator* eq = getInstantiator(id)->getRRCanGenClass();
+ // if(eq == NULL) return getInstantiator(id)->getRRCanGenClass();
+ // else return eq;
+ return getRRCanGenClass();
+}
diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h
index 5477214b0..157c0ac53 100644
--- a/src/theory/quantifiers_engine.h
+++ b/src/theory/quantifiers_engine.h
@@ -21,7 +21,8 @@
#include "theory/theory.h"
#include "util/hash.h"
-#include "theory/trigger.h"
+#include "theory/inst_match.h"
+#include "theory/rr_inst_match.h"
#include "util/stats.h"
@@ -33,16 +34,6 @@ namespace CVC4 {
class TheoryEngine;
-// attribute for "contains instantiation constants from"
-struct InstConstantAttributeId {};
-typedef expr::Attribute<InstConstantAttributeId, Node> InstConstantAttribute;
-
-struct InstLevelAttributeId {};
-typedef expr::Attribute<InstLevelAttributeId, uint64_t> InstLevelAttribute;
-
-struct InstVarNumAttributeId {};
-typedef expr::Attribute<InstVarNumAttributeId, uint64_t> InstVarNumAttribute;
-
namespace theory {
class QuantifiersEngine;
@@ -126,7 +117,7 @@ namespace quantifiers {
class QuantifiersEngine {
friend class quantifiers::InstantiationEngine;
friend class quantifiers::ModelEngine;
- friend class InstMatch;
+ friend class inst::InstMatch;
private:
typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
/** reference to theory engine object */
@@ -139,7 +130,7 @@ private:
quantifiers::ModelEngine* d_model_engine;
/** equality query class */
EqualityQuery* d_eq_query;
-
+public:
/** list of all quantifiers (pre-rewrite) */
std::vector< Node > d_quants;
/** list of all quantifiers (post-rewrite) */
@@ -153,7 +144,7 @@ private:
/** has added lemma this round */
bool d_hasAddedLemma;
/** inst matches produced for each quantifier */
- std::map< Node, InstMatchTrie > d_inst_match_trie;
+ std::map< Node, inst::InstMatchTrie > d_inst_match_trie;
/** owner of quantifiers */
std::map< Node, Theory* > d_owner;
/** term database */
@@ -184,13 +175,24 @@ private:
public:
QuantifiersEngine(context::Context* c, TheoryEngine* te);
- ~QuantifiersEngine(){}
+ ~QuantifiersEngine();
/** get instantiator for id */
- Instantiator* getInstantiator( int id );
+ Instantiator* getInstantiator( theory::TheoryId id );
/** get theory engine */
TheoryEngine* getTheoryEngine() { return d_te; }
- /** get equality query object */
- EqualityQuery* getEqualityQuery() { return d_eq_query; }
+ /** get equality query object for the given type. The default is the
+ generic one */
+ inst::EqualityQuery* getEqualityQuery(TypeNode t);
+ inst::EqualityQuery* getEqualityQuery() {
+ return d_eq_query;
+ }
+ /** get equality query object for the given type. The default is the
+ one of UF */
+ rrinst::CandidateGenerator* getRRCanGenClasses(TypeNode t);
+ rrinst::CandidateGenerator* getRRCanGenClass(TypeNode t);
+ /* generic candidate generator */
+ rrinst::CandidateGenerator* getRRCanGenClasses();
+ rrinst::CandidateGenerator* getRRCanGenClass();
/** get instantiation engine */
quantifiers::InstantiationEngine* getInstantiationEngine() { return d_inst_engine; }
/** get model engine */
@@ -301,6 +303,14 @@ public:
IntStat d_simple_triggers;
IntStat d_multi_triggers;
IntStat d_multi_trigger_instantiations;
+ IntStat d_term_in_termdb;
+ IntStat d_num_mono_candidates;
+ IntStat d_num_mono_candidates_new_term;
+ IntStat d_num_multi_candidates;
+ IntStat d_mono_candidates_cache_hit;
+ IntStat d_mono_candidates_cache_miss;
+ IntStat d_multi_candidates_cache_hit;
+ IntStat d_multi_candidates_cache_miss;
Statistics();
~Statistics();
};/* class QuantifiersEngine::Statistics */
diff --git a/src/theory/rewriterules/theory_rewriterules.cpp b/src/theory/rewriterules/theory_rewriterules.cpp
index 265026b39..57bc6d9cf 100644
--- a/src/theory/rewriterules/theory_rewriterules.cpp
+++ b/src/theory/rewriterules/theory_rewriterules.cpp
@@ -23,6 +23,8 @@
#include "theory/rewriterules/theory_rewriterules_preprocess.h"
#include "theory/rewriter.h"
+#include "util/options.h"
+
using namespace std;
using namespace CVC4;
@@ -30,6 +32,7 @@ using namespace CVC4::kind;
using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::rewriterules;
+using namespace CVC4::theory::rrinst;
namespace CVC4 {
@@ -69,14 +72,14 @@ size_t RuleInst::findGuard(TheoryRewriteRules & re, size_t start)const{
Node g = substNode(re,rule->guards[start],cache);
switch(re.addWatchIfDontKnow(g,this,start)){
case ATRUE:
- Debug("rewriterules") << g << "is true" << std::endl;
+ Debug("rewriterules::guards") << g << "is true" << std::endl;
++start;
continue;
case AFALSE:
- Debug("rewriterules") << g << "is false" << std::endl;
+ Debug("rewriterules::guards") << g << "is false" << std::endl;
return -1;
case ADONTKNOW:
- Debug("rewriterules") << g << "is unknown" << std::endl;
+ Debug("rewriterules::guards") << g << "is unknown" << std::endl;
return start;
}
}
@@ -132,31 +135,31 @@ TheoryRewriteRules::TheoryRewriteRules(context::Context* c,
QuantifiersEngine* qe) :
Theory(THEORY_REWRITERULES, c, u, out, valuation, logicInfo, qe),
d_rules(c), d_ruleinsts(c), d_guardeds(c), d_checkLevel(c,0),
- d_explanations(c), d_ruleinsts_to_add()
+ d_explanations(c), d_ruleinsts_to_add(), d_ppAssert_on(false)
{
d_true = NodeManager::currentNM()->mkConst<bool>(true);
d_false = NodeManager::currentNM()->mkConst<bool>(false);
- Debug("rewriterules") << Node::setdepth(-1);
- Debug("rewriterules-rewrite") << Node::setdepth(-1);
}
void TheoryRewriteRules::addMatchRuleTrigger(const RewriteRule * r,
InstMatch & im,
bool delay){
++r->nb_matched;
+ ++d_statistics.d_match_found;
if(rewrite_instantiation) im.applyRewrite();
if(representative_instantiation)
im.makeRepresentative( getQuantifiersEngine() );
if(!cache_match || !r->inCache(*this,im)){
++r->nb_applied;
+ ++d_statistics.d_cache_miss;
std::vector<Node> subst;
im.computeTermVec(getQuantifiersEngine(), r->inst_vars , subst);
RuleInst * ri = new RuleInst(*this,r,subst,
r->directrr ? im.d_matched : Node::null());
- Debug("rewriterules") << "One matching found"
- << (delay? "(delayed)":"")
- << ":" << *ri << std::endl;
+ Debug("rewriterules::matching") << "One matching found"
+ << (delay? "(delayed)":"")
+ << ":" << *ri << std::endl;
// Find the first non verified guard, don't save the rule if the
// rule can already be fired In fact I save it otherwise strange
// things append.
@@ -168,6 +171,8 @@ void TheoryRewriteRules::addMatchRuleTrigger(const RewriteRule * r,
d_ruleinsts.push_back(ri);
else delete(ri);
};
+ }else{
+ ++d_statistics.d_cache_hit;
};
}
@@ -179,7 +184,11 @@ void TheoryRewriteRules::check(Effort level) {
while(!done()) {
// Get all the assertions
// TODO: Test that it have already been ppAsserted
- get();
+
+ //if we are here and ppAssert has not been done
+ // that means that ppAssert is off so we need to assert now
+ if(!d_ppAssert_on) addRewriteRule(get());
+ else get();
// Assertion assertion = get();
// TNode fact = assertion.assertion;
@@ -190,30 +199,30 @@ void TheoryRewriteRules::check(Effort level) {
};
- Debug("rewriterules") << "Check:" << d_checkLevel << (level==EFFORT_FULL? " EFFORT_FULL":"") << std::endl;
+ Debug("rewriterules::check") << "RewriteRules::Check start " << d_checkLevel << (level==EFFORT_FULL? " EFFORT_FULL":"") << std::endl;
/** Test each rewrite rule */
for(size_t rid = 0, end = d_rules.size(); rid < end; ++rid) {
RewriteRule * r = d_rules[rid];
if (level!=EFFORT_FULL && r->d_split) continue;
- Debug("rewriterules") << " rule: " << r << std::endl;
+ Debug("rewriterules::check") << "RewriteRules::Check rule: " << *r << std::endl;
Trigger & tr = r->trigger;
//reset instantiation round for trigger (set up match production)
tr.resetInstantiationRound();
- //begin iterating from the first match produced by the trigger
- tr.reset( Node::null() );
/** Test the possible matching one by one */
- InstMatch im;
- while(tr.getNextMatch( im )){
+ while(tr.getNextMatch()){
+ InstMatch im = tr.getInstMatch();
addMatchRuleTrigger(r, im, true);
- im.clear();
}
}
const bool do_notification = d_checkLevel == 0 || level==EFFORT_FULL;
bool polldone = false;
+ if(level==EFFORT_FULL) ++d_statistics.d_full_check;
+ else ++d_statistics.d_check;
+
GuardedMap::const_iterator p = d_guardeds.begin();
do{
@@ -221,7 +230,7 @@ void TheoryRewriteRules::check(Effort level) {
//dequeue instantiated rules
for(; !d_ruleinsts_to_add.empty();){
RuleInst * ri = d_ruleinsts_to_add.back(); d_ruleinsts_to_add.pop_back();
- if(simulateRewritting && ri->alreadyRewritten(*this)) break;
+ if(simulateRewritting && ri->alreadyRewritten(*this)) continue;
if(ri->findGuard(*this, 0) != ri->rule->guards.size())
d_ruleinsts.push_back(ri);
else delete(ri);
@@ -239,7 +248,7 @@ void TheoryRewriteRules::check(Effort level) {
bool value;
if(getValuation().hasSatValue(g,value)){
if(value) polldone = true; //One guard is true so pass n check
- Debug("rewriterules") << "Poll value:" << g
+ Debug("rewriterules::guards") << "Poll value:" << g
<< " is " << (value ? "true" : "false") << std::endl;
notification(g,value);
//const Guarded & glast2 = (*l)[l->size()-1];
@@ -266,14 +275,14 @@ void TheoryRewriteRules::check(Effort level) {
// If it has a value it should already has been notified
bool value; value = value; // avoiding the warning in non debug mode
Assert(!getValuation().hasSatValue(g,value));
- Debug("rewriterules") << "Narrowing on:" << g << std::endl;
+ Debug("rewriterules::check") << "RewriteRules::Check Narrowing on:" << g << std::endl;
/** Can split on already rewritten instrule... but... */
getOutputChannel().split(g);
}
}
Assert(d_ruleinsts_to_add.empty());
- Debug("rewriterules") << "Check done:" << d_checkLevel << std::endl;
+ Debug("rewriterules::check") << "RewriteRules::Check done " << d_checkLevel << std::endl;
};
@@ -283,7 +292,13 @@ Trigger TheoryRewriteRules::createTrigger( TNode n, std::vector<Node> & pattern
// Debug("rewriterules") << "createTrigger:";
getQuantifiersEngine()->registerPattern(pattern);
return *Trigger::mkTrigger(getQuantifiersEngine(),n,pattern,
- match_gen_kind, true);
+ Options::current()->efficientEMatching?
+ Trigger::MATCH_GEN_EFFICIENT_E_MATCH :
+ Trigger::MATCH_GEN_DEFAULT,
+ true,
+ Trigger::TR_MAKE_NEW,
+ false);
+ // Options::current()->smartMultiTriggers);
};
bool TheoryRewriteRules::notifyIfKnown(const GList * const ltested,
@@ -299,9 +314,9 @@ bool TheoryRewriteRules::notifyIfKnown(const GList * const ltested,
void TheoryRewriteRules::notification(GList * const lpropa, bool b){
if (b){
- for(GList::const_iterator g = lpropa->begin();
- g != lpropa->end(); ++g) {
- (*g).nextGuard(*this);
+ for(size_t ig = 0;
+ ig != lpropa->size(); ++ig) {
+ (*lpropa)[ig].nextGuard(*this);
};
lpropa->push_back(Guarded(RULEINST_TRUE,0));
}else{
@@ -315,16 +330,6 @@ void TheoryRewriteRules::notification(GList * const lpropa, bool b){
Answer TheoryRewriteRules::addWatchIfDontKnow(Node g0, const RuleInst* ri,
const size_t gid){
- /** TODO: Should use the representative of g, but should I keep the
- mapping for myself? */
- //AJR: removed this code after talking with Francois
- ///* If it false in one model (current valuation) it's false for all */
- //if (useCurrentModel){
- // Node val = getValuation().getValue(g0);
- // Debug("rewriterules") << "getValue:" << g0 << " = "
- // << val << " is " << (val == d_false) << std::endl;
- // if (val == d_false) return AFALSE;
- //};
/** Currently create a node with a literal */
Node g = getValuation().ensureLiteral(g0);
GuardedMap::iterator l_i = d_guardeds.find(g);
@@ -384,68 +389,119 @@ void TheoryRewriteRules::notifyEq(TNode lhs, TNode rhs) {
};
+Node TheoryRewriteRules::normalizeConjunction(NodeBuilder<> & conjunction){
+ Assert(conjunction.getKind() == kind::AND);
+ switch(conjunction.getNumChildren()){
+ case 0:
+ return d_true;
+ case 1:
+ return conjunction[0];
+ default:
+ return conjunction;
+ }
+
+}
+
+void explainInstantiation(const RuleInst *inst, TNode substHead, NodeBuilder<> & conjunction ){
+ TypeNode booleanType = NodeManager::currentNM()->booleanType();
+ // if the rule is directly applied by the rewriter,
+ // we should take care to use the representative that can't be directly rewritable:
+ // If "car(a)" is somewhere and we know that "a = cons(x,l)" we shouldn't
+ // add the constraint car(cons(x,l) = x because it is rewritten to x = x.
+ // But we should say cons(a) = x
+ Assert(!inst->d_matched.isNull());
+ Assert( inst->d_matched.getKind() == kind::APPLY_UF);
+ Assert( substHead.getKind() == kind::APPLY_UF );
+ Assert( inst->d_matched.getOperator() == substHead.getOperator() );
+ Assert(conjunction.getKind() == kind::AND);
+ // replace the left hand side by the term really matched
+ NodeBuilder<2> nb;
+ for(size_t i = 0,
+ iend = inst->d_matched.getNumChildren(); i < iend; ++i){
+ nb.clear( inst->d_matched[i].getType(false) == booleanType ?
+ kind::IFF : kind::EQUAL );
+ nb << inst->d_matched[i] << substHead[i];
+ conjunction << static_cast<Node>(nb);
+ }
+}
+
+Node skolemizeBody( Node f ){
+ /*TODO skolemize the subformula of s with constant or skolemize
+ directly in the body of the rewrite rule with an uninterpreted
+ function.
+ */
+ if ( f.getKind()!=EXISTS ) return f;
+ std::vector< Node > vars;
+ std::vector< Node > csts;
+ for( int i=0; i<(int)f[0].getNumChildren(); i++ ){
+ csts.push_back( NodeManager::currentNM()->mkSkolem( f[0][i].getType()) );
+ vars.push_back( f[0][i] );
+ }
+ return f[ 1 ].substitute( vars.begin(), vars.end(),
+ csts.begin(), csts.end() );
+}
+
+
void TheoryRewriteRules::propagateRule(const RuleInst * inst, TCache cache){
// Debug("rewriterules") << "A rewrite rules is verified. Add lemma:";
- Debug("rewriterules") << "propagateRule" << *inst << std::endl;
+ Debug("rewriterules::propagate") << "propagateRule" << *inst << std::endl;
const RewriteRule * rule = inst->rule;
++rule->nb_applied;
// Can be more something else than an equality in fact (eg. propagation rule)
- Node equality = inst->substNode(*this,rule->body,cache);
+ Node equality = skolemizeBody(inst->substNode(*this,rule->body,cache));
if(propagate_as_lemma){
Node lemma = equality;
- if(rule->guards.size() > 0){
- // TODO: problem with reduction rule => instead of <=>
- lemma = substGuards(inst, cache).impNode(equality);
- };
if(rule->directrr){
- TypeNode booleanType = NodeManager::currentNM()->booleanType();
- // if the rule is directly applied by the rewriter,
- // we should take care to use the representative that can't be directly rewritable:
- // If "car(a)" is somewhere and we know that "a = cons(x,l)" we shouldn't
- // add the constraint car(cons(x,l) = x because it is rewritten to x = x.
- // But we should say cons(a) = x
- Assert(lemma.getKind() == kind::EQUAL ||
- lemma.getKind() == kind::IMPLIES);
- Assert(!inst->d_matched.isNull());
- Assert( inst->d_matched.getOperator() == lemma[0].getOperator() );
- // replace the left hand side by the term really matched
+ NodeBuilder<> conjunction(kind::AND);
+ explainInstantiation(inst,
+ rule->guards.size() > 0?
+ inst->substNode(*this,rule->guards[0],cache) : equality[0],
+ conjunction);
Debug("rewriterules-directrr") << "lemma:" << lemma << " :: " << inst->d_matched;
- Node hyp;
- NodeBuilder<2> nb;
- if(inst->d_matched.getNumChildren() == 1){
- nb.clear( inst->d_matched[0].getType(false) == booleanType ?
- kind::IFF : kind::EQUAL );
- nb << inst->d_matched[0] << lemma[0][0];
- hyp = nb;
- }else{
- NodeBuilder<> andb(kind::AND);
- for(size_t i = 0,
- iend = inst->d_matched.getNumChildren(); i < iend; ++i){
- nb.clear( inst->d_matched[i].getType(false) == booleanType ?
- kind::IFF : kind::EQUAL );
- nb << inst->d_matched[i] << lemma[0][i];
- andb << static_cast<Node>(nb);
- }
- hyp = andb;
- };
- nb.clear(lemma.getKind());
- nb << inst->d_matched << lemma[1];
- lemma = hyp.impNode(static_cast<Node>(nb));
+ //rewrite rule
+ TypeNode booleanType = NodeManager::currentNM()->booleanType();
+ if(equality[1].getType(false) == booleanType)
+ equality = inst->d_matched.iffNode(equality[1]);
+ else equality = inst->d_matched.eqNode(equality[1]);
+ lemma = normalizeConjunction(conjunction).impNode(equality);
Debug("rewriterules-directrr") << " -> " << lemma << std::endl;
- };
- // Debug("rewriterules") << "lemma:" << lemma << std::endl;
+ }
+ else if(rule->guards.size() > 0){
+ // We can use implication for reduction rules since the head is known
+ // to be true
+ NodeBuilder<> conjunction(kind::AND);
+ substGuards(inst,cache,conjunction);
+ lemma = normalizeConjunction(conjunction).impNode(equality);
+ }
+ Debug("rewriterules::propagate") << "propagated " << lemma << std::endl;
getOutputChannel().lemma(lemma);
}else{
- Assert(!direct_rewrite);
- Node lemma_lit = getValuation().ensureLiteral(equality);
+ Node lemma_lit = equality;
+ if(rule->directrr && rule->guards.size() == 0)
+ lemma_lit = inst->d_matched.eqNode(equality[1]); // rewrite rules
+ lemma_lit = getValuation().ensureLiteral(lemma_lit);
ExplanationMap::const_iterator p = d_explanations.find(lemma_lit);
if(p!=d_explanations.end()) return; //Already propagated
bool value;
if(getValuation().hasSatValue(lemma_lit,value)){
/* Already assigned */
if (!value){
- Node conflict = substGuards(inst,cache,lemma_lit);
- getOutputChannel().conflict(conflict);
+ NodeBuilder<> conflict(kind::AND);
+
+ if(rule->directrr){
+ explainInstantiation(inst,
+ rule->guards.size() > 0?
+ inst->substNode(*this,rule->guards[0],cache) : equality[0],
+ conflict);
+ if(rule->guards.size() > 0){
+ //reduction rule
+ Assert(rule->guards.size() == 1);
+ conflict << inst->d_matched; //this one will be two times
+ }
+ }
+ substGuards(inst,cache,conflict);
+ conflict << lemma_lit;
+ getOutputChannel().conflict(normalizeConjunction(conflict));
};
}else{
getOutputChannel().propagate(lemma_lit);
@@ -456,57 +512,79 @@ void TheoryRewriteRules::propagateRule(const RuleInst * inst, TCache cache){
if(simulateRewritting){
static NoMatchAttribute rewrittenNodeAttribute;
// Tag the rewritted terms
- for(std::vector<Node>::iterator i = rule->to_remove.begin();
- i == rule->to_remove.end(); ++i){
- (*i).setAttribute(rewrittenNodeAttribute,true);
+ // for(std::vector<Node>::iterator i = rule->to_remove.begin();
+ // i == rule->to_remove.end(); ++i){
+ // (*i).setAttribute(rewrittenNodeAttribute,true);
+ // };
+ for(size_t i = 0; i < rule->to_remove.size(); ++i){
+ Node rewritten = inst->substNode(*this,rule->to_remove[i],cache);
+ Debug("rewriterules::simulateRewriting") << "tag " << rewritten << " as rewritten" << std::endl;
+ rewritten.setAttribute(rewrittenNodeAttribute,true);
};
+
};
- //Verify that this instantiation can't immediately fire another rule
- for(RewriteRule::BodyMatch::const_iterator p = rule->body_match.begin();
- p != rule->body_match.end(); ++p){
- RewriteRule * r = (*p).second;
- // Debug("rewriterules") << " rule: " << r << std::endl;
- // Use trigger2 since we can be in check
- Trigger & tr = r->trigger_for_body_match;
- InstMatch im;
- TNode m = inst->substNode(*this,(*p).first, cache);
- tr.getMatch(m,im);
- if(!im.empty()){
- im.d_matched = m;
- addMatchRuleTrigger(r, im);
+ if ( compute_opt && !rule->body_match.empty() ){
+
+ uf::TheoryUF* uf = static_cast<uf::TheoryUF *>(getQuantifiersEngine()->getTheoryEngine()->getTheory( theory::THEORY_UF ));
+ eq::EqualityEngine* ee =
+ static_cast<eq::EqualityEngine*>(uf->getEqualityEngine());
+
+ //Verify that this instantiation can't immediately fire another rule
+ for(RewriteRule::BodyMatch::const_iterator p = rule->body_match.begin();
+ p != rule->body_match.end(); ++p){
+ RewriteRule * r = (*p).second;
+ // Use trigger2 since we can be in check
+ ApplyMatcher * tr = r->trigger_for_body_match;
+ Assert(tr != NULL);
+ tr->resetInstantiationRound(getQuantifiersEngine());
+ InstMatch im;
+ TNode m = inst->substNode(*this,(*p).first, cache);
+ Assert( m.getKind() == kind::APPLY_UF );
+ ee->addTerm(m);
+ if( tr->reset(m,im,getQuantifiersEngine()) ){
+ im.d_matched = m;
+ Debug("rewriterules::matching") << "SimulatedRewrite: " << std::endl;
+ addMatchRuleTrigger(r, im);
+ }
}
+
}
};
-
-Node TheoryRewriteRules::substGuards(const RuleInst *inst,
+void TheoryRewriteRules::substGuards(const RuleInst *inst,
TCache cache,
- /* Already substituted */
- Node last){
+ NodeBuilder<> & conjunction){
const RewriteRule * r = inst->rule;
- /** No guards */
- const size_t size = r->guards.size();
- if(size == 0) return (last.isNull()?d_true:last);
- /** One guard */
- if(size == 1 && last.isNull()) return inst->substNode(*this,r->guards[0],cache);
/** Guards */ /* TODO remove the duplicate with a set like in uf? */
- NodeBuilder<> conjunction(kind::AND);
for(std::vector<Node>::const_iterator p = r->guards.begin();
p != r->guards.end(); ++p) {
Assert(!p->isNull());
conjunction << inst->substNode(*this,*p,cache);
};
- if (!last.isNull()) conjunction << last;
- return conjunction;
}
Node TheoryRewriteRules::explain(TNode n){
ExplanationMap::const_iterator p = d_explanations.find(n);
Assert(p!=d_explanations.end(),"I forget the explanation...");
- RuleInst i = (*p).second;
- //Notice() << n << "<-" << *(i.rule) << std::endl;
- return substGuards(&i, TCache ());
+ RuleInst inst = (*p).second;
+ const RewriteRule * rule = inst.rule;
+ TCache cache;
+ NodeBuilder<> explanation(kind::AND);
+ if(rule->directrr){
+ explainInstantiation(&inst,
+ rule->guards.size() > 0?
+ inst.substNode(*this,rule->guards[0],cache):
+ inst.substNode(*this,rule->body[0] ,cache),
+ explanation);
+ if(rule->guards.size() > 0){
+ //reduction rule
+ Assert(rule->guards.size() == 1);
+ explanation << inst.d_matched; //this one will be two times
+ }
+ };
+ substGuards(&inst, cache ,explanation);
+ return normalizeConjunction(explanation);
}
void TheoryRewriteRules::collectModelInfo( TheoryModel* m ){
@@ -515,9 +593,39 @@ void TheoryRewriteRules::collectModelInfo( TheoryModel* m ){
Theory::PPAssertStatus TheoryRewriteRules::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
addRewriteRule(in);
+ d_ppAssert_on = true;
return PP_ASSERT_STATUS_UNSOLVED;
}
+TheoryRewriteRules::Statistics::Statistics():
+ d_num_rewriterules("TheoryRewriteRules::Num_RewriteRules", 0),
+ d_check("TheoryRewriteRules::Check", 0),
+ d_full_check("TheoryRewriteRules::FullCheck", 0),
+ d_poll("TheoryRewriteRules::Poll", 0),
+ d_match_found("TheoryRewriteRules::MatchFound", 0),
+ d_cache_hit("TheoryRewriteRules::CacheHit", 0),
+ d_cache_miss("TheoryRewriteRules::CacheMiss", 0)
+{
+ StatisticsRegistry::registerStat(&d_num_rewriterules);
+ StatisticsRegistry::registerStat(&d_check);
+ StatisticsRegistry::registerStat(&d_full_check);
+ StatisticsRegistry::registerStat(&d_poll);
+ StatisticsRegistry::registerStat(&d_match_found);
+ StatisticsRegistry::registerStat(&d_cache_hit);
+ StatisticsRegistry::registerStat(&d_cache_miss);
+}
+
+TheoryRewriteRules::Statistics::~Statistics(){
+ StatisticsRegistry::unregisterStat(&d_num_rewriterules);
+ StatisticsRegistry::unregisterStat(&d_check);
+ StatisticsRegistry::unregisterStat(&d_full_check);
+ StatisticsRegistry::unregisterStat(&d_poll);
+ StatisticsRegistry::unregisterStat(&d_match_found);
+ StatisticsRegistry::unregisterStat(&d_cache_hit);
+ StatisticsRegistry::unregisterStat(&d_cache_miss);
+}
+
+
}/* CVC4::theory::rewriterules namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/rewriterules/theory_rewriterules.h b/src/theory/rewriterules/theory_rewriterules.h
index d1c3eecf3..fcbdfe8b9 100644
--- a/src/theory/rewriterules/theory_rewriterules.h
+++ b/src/theory/rewriterules/theory_rewriterules.h
@@ -27,7 +27,9 @@
#include "theory/theory_engine.h"
#include "theory/quantifiers_engine.h"
#include "context/context_mm.h"
-#include "theory/inst_match_impl.h"
+#include "theory/rr_inst_match_impl.h"
+#include "theory/rr_trigger.h"
+#include "theory/rr_inst_match.h"
#include "util/stats.h"
#include "theory/rewriterules/theory_rewriterules_preprocess.h"
#include "theory/model.h"
@@ -35,6 +37,8 @@
namespace CVC4 {
namespace theory {
namespace rewriterules {
+using namespace CVC4::theory::rrinst;
+typedef CVC4::theory::rrinst::Trigger Trigger;
typedef std::hash_map<TNode, TNode, TNodeHashFunction> TCache;
@@ -45,6 +49,7 @@ typedef std::hash_map<TNode, TNode, TNodeHashFunction> TCache;
class RewriteRule{
public:
// constant
+ const size_t id; //for debugging
const bool d_split;
mutable Trigger trigger;
std::vector<Node> guards;
@@ -58,7 +63,7 @@ typedef std::hash_map<TNode, TNode, TNodeHashFunction> TCache;
rule) */
typedef context::CDList< std::pair<TNode,RewriteRule* > > BodyMatch;
mutable BodyMatch body_match;
- mutable Trigger trigger_for_body_match; // used because we can be matching
+ mutable ApplyMatcher * trigger_for_body_match; // used because we can be matching
// trigger when we need new match.
// So currently we use another
// trigger for that.
@@ -70,7 +75,7 @@ typedef std::hash_map<TNode, TNode, TNodeHashFunction> TCache;
const bool directrr;
RewriteRule(TheoryRewriteRules & re,
- Trigger & tr, Trigger & tr2,
+ Trigger & tr, ApplyMatcher * tr2,
std::vector<Node> & g, Node b, TNode nt,
std::vector<Node> & fv,std::vector<Node> & iv,
std::vector<Node> & to_r, bool drr);
@@ -183,6 +188,7 @@ private:
inside check */
typedef std::vector< RuleInst* > QRuleInsts;
QRuleInsts d_ruleinsts_to_add;
+ bool d_ppAssert_on; //Indicate if a ppAssert have been done
public:
/** true and false for predicate */
@@ -240,15 +246,17 @@ private:
already true */
bool notifyIfKnown(const GList * const ltested, GList * const lpropa);
- Node substGuards(const RuleInst * inst,
+ void substGuards(const RuleInst * inst,
TCache cache,
- Node last = Node::null());
+ NodeBuilder<> & conjunction);
void addRewriteRule(const Node r);
void computeMatchBody ( const RewriteRule * r, size_t start = 0);
void addMatchRuleTrigger(const RewriteRule* r,
InstMatch & im, bool delay = true);
+ Node normalizeConjunction(NodeBuilder<> & conjunction);
+
/* rewrite pattern */
typedef std::hash_map< Node, rewriter::RRPpRewrite*, NodeHashFunction > RegisterRRPpRewrite;
RegisterRRPpRewrite d_registeredRRPpRewrite;
@@ -257,6 +265,21 @@ private:
rewriter::Subst & pvars,
rewriter::Subst & vars);
+ /** statistics class */
+ class Statistics {
+ public:
+ IntStat d_num_rewriterules;
+ IntStat d_check;
+ IntStat d_full_check;
+ IntStat d_poll;
+ IntStat d_match_found;
+ IntStat d_cache_hit;
+ IntStat d_cache_miss;
+ Statistics();
+ ~Statistics();
+ };
+ Statistics d_statistics;
+
};/* class TheoryRewriteRules */
}/* CVC4::theory::rewriterules namespace */
diff --git a/src/theory/rewriterules/theory_rewriterules_params.h b/src/theory/rewriterules/theory_rewriterules_params.h
index 9ab2ae3e7..de51215d1 100644
--- a/src/theory/rewriterules/theory_rewriterules_params.h
+++ b/src/theory/rewriterules/theory_rewriterules_params.h
@@ -17,7 +17,6 @@
** \todo document this file
**/
-
#ifndef __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_PARAMS_H
#define __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_PARAMS_H
@@ -58,7 +57,7 @@ static const bool representative_instantiation = false;
Allow to break loop with other theories.
*/
-static const size_t checkSlowdown = 10;
+static const size_t checkSlowdown = 0;
/**
Use the current model to eliminate guard before asking for notification
@@ -68,14 +67,7 @@ static const bool useCurrentModel = false;
/**
Simulate rewriting by tagging rewritten terms.
*/
-static const bool simulateRewritting = false;
-
-/**
- Choose the kind of matching to use:
- - InstMatchGenerator::MATCH_GEN_DEFAULT 0
- - InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH 1
-*/
-static const int match_gen_kind = 0;
+static const bool simulateRewritting = true;
/**
Do narrowing at full effort
@@ -85,7 +77,7 @@ static const bool narrowing_full_effort = false;
/**
Direct rewrite: Add rewrite rules directly in the rewriter.
*/
-static const bool direct_rewrite = true;
+static const bool direct_rewrite = false;
}/* CVC4::theory::rewriterules namespace */
}/* CVC4::theory namespace */
diff --git a/src/theory/rewriterules/theory_rewriterules_rules.cpp b/src/theory/rewriterules/theory_rewriterules_rules.cpp
index c3116aba0..1ad8fdaa7 100644
--- a/src/theory/rewriterules/theory_rewriterules_rules.cpp
+++ b/src/theory/rewriterules/theory_rewriterules_rules.cpp
@@ -21,6 +21,7 @@
#include "theory/rewriterules/theory_rewriterules_params.h"
#include "theory/rewriterules/theory_rewriterules_preprocess.h"
#include "theory/rewriterules/theory_rewriterules.h"
+#include "util/options.h"
#include "theory/quantifiers/term_database.h"
@@ -30,12 +31,46 @@ using namespace CVC4::kind;
using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::rewriterules;
+using namespace CVC4::theory::rrinst;
namespace CVC4 {
namespace theory {
namespace rewriterules {
+// 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 pattern, const std::vector<Node> & vars){
+ typedef std::vector<std::pair<TNode,TNode> > tstack;
+ tstack stack(1,std::make_pair(t0,pattern)); // t * pat
+
+ while(!stack.empty()){
+ const std::pair<TNode,TNode> 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;
+}
+
+
void TheoryRewriteRules::computeMatchBody ( const RewriteRule * rule,
size_t start){
std::vector<TNode> stack(1,rule->new_terms);
@@ -50,9 +85,9 @@ void TheoryRewriteRules::computeMatchBody ( const RewriteRule * rule,
if( t.getKind() == APPLY_UF ){
for(size_t rid = start, end = d_rules.size(); rid < end; ++rid) {
RewriteRule * r = d_rules[rid];
- if(r->d_split) continue;
- Trigger & tr = const_cast<Trigger &> (r->trigger_for_body_match);
- if(!tr.nonunifiable(t, rule->free_vars)){
+ if(r->d_split || r->trigger_for_body_match == NULL) continue;
+ //the split rules are not computed and the one with multi-pattern
+ if( !nonunifiable(t, r->trigger_for_body_match->d_pattern, rule->free_vars)){
rule->body_match.push_back(std::make_pair(t,r));
}
}
@@ -74,7 +109,10 @@ inline void addPattern(TheoryRewriteRules & re,
TNode r){
if (tri.getKind() == kind::NOT && tri[0].getKind() == kind::APPLY_UF)
tri = tri[0];
- pattern.push_back(re.getQuantifiersEngine()->getTermDatabase()->
+ pattern.push_back(
+ Options::current()->rewriteRulesAsAxioms?
+ static_cast<Node>(tri):
+ re.getQuantifiersEngine()->getTermDatabase()->
convertNodeToPattern(tri,r,vars,inst_constants));
}
@@ -106,6 +144,7 @@ bool checkPatternVars(const std::vector<Node> & pattern,
void TheoryRewriteRules::addRewriteRule(const Node r)
{
Assert(r.getKind() == kind::REWRITE_RULE);
+ Kind rrkind = r[2].getKind();
/* Replace variables by Inst_* variable and tag the terms that
contain them */
std::vector<Node> vars;
@@ -125,16 +164,20 @@ void TheoryRewriteRules::addRewriteRule(const Node r)
when fired */
/* shortcut */
TNode head = r[2][0];
- switch(r[2].getKind()){
+ TypeNode booleanType = NodeManager::currentNM()->booleanType();
+ switch(rrkind){
case kind::RR_REWRITE:
/* Equality */
to_remove.push_back(head);
addPattern(*this,head,pattern,vars,inst_constants,r);
- body = head.eqNode(body);
+ if(head.getType(false) == booleanType) body = head.iffNode(body);
+ else body = head.eqNode(body);
break;
case kind::RR_REDUCTION:
/** Add head to remove */
- to_remove.push_back(head);
+ for(Node::iterator i = head.begin(); i != head.end(); ++i) {
+ to_remove.push_back(*i);
+ };
case kind::RR_DEDUCTION:
/** Add head to guards and pattern */
switch(head.getKind()){
@@ -171,32 +214,65 @@ void TheoryRewriteRules::addRewriteRule(const Node r)
};
/* Add the other triggers */
if( r[2].getNumChildren() >= 3 )
- for(Node::iterator i = r[2][2].begin(); i != r[2][2].end(); ++i) {
+ for(Node::iterator i = r[2][2][0].begin(); i != r[2][2][0].end(); ++i) {
// todo test during typing that its a good term (no not, atom, or term...)
- addPattern(*this,(*i)[0],pattern,vars,inst_constants,r);
+ addPattern(*this,*i,pattern,vars,inst_constants,r);
};
// Assert(pattern.size() == 1, "currently only single pattern are supported");
+
+
+
+
+ //If we convert to usual axioms
+ if(Options::current()->rewriteRulesAsAxioms){
+ NodeBuilder<> forallB(kind::FORALL);
+ forallB << r[0];
+ NodeBuilder<> guardsB(kind::AND);
+ guardsB.append(guards);
+ forallB << normalizeConjunction(guardsB).impNode(body);
+ NodeBuilder<> patternB(kind::INST_PATTERN);
+ patternB.append(pattern);
+ NodeBuilder<> patternListB(kind::INST_PATTERN_LIST);
+ patternListB << static_cast<Node>(patternB);
+ forallB << static_cast<Node>(patternListB);
+ getOutputChannel().lemma((Node) forallB);
+ return;
+ }
+
+ //turn all to propagate
+ // if(true){
+ // NodeBuilder<> guardsB(kind::AND);
+ // guardsB.append(guards);
+ // body = normalizeConjunction(guardsB).impNode(body);
+ // guards.clear();
+ // rrkind = kind::RR_DEDUCTION;
+ // }
+
+
//Every variable must be seen in the pattern
if (!checkPatternVars(pattern,inst_constants)){
- Warning() << "The rule" << r <<
+ Warning() << Node::setdepth(-1) << "The rule" << r <<
" has been removed since it doesn't contain every variables."
<< std::endl;
return;
}
+
//Add to direct rewrite rule
bool directrr = false;
if(direct_rewrite &&
- ((guards.size() == 0 && r[2].getKind() == kind::RR_REWRITE) ||
- (guards.size() == 1 && r[2].getKind() == kind::RR_REDUCTION))
+ guards.size() == 0 && rrkind == kind::RR_REWRITE
&& pattern.size() == 1){
directrr = addRewritePattern(pattern[0],new_terms, inst_constants, vars);
}
+
// final construction
Trigger trigger = createTrigger(r,pattern);
- Trigger trigger2 = createTrigger(r,pattern); //Hack
- RewriteRule * rr = new RewriteRule(*this, trigger, trigger2,
+ ApplyMatcher * applymatcher =
+ pattern.size() == 1 && pattern[0].getKind() == kind::APPLY_UF?
+ new ApplyMatcher(pattern[0],getQuantifiersEngine()) : NULL;
+ RewriteRule * rr = new RewriteRule(*this, trigger, applymatcher,
guards, body, new_terms,
vars, inst_constants, to_remove,
directrr);
@@ -209,7 +285,7 @@ void TheoryRewriteRules::addRewriteRule(const Node r)
computeMatchBody(d_rules[rid],
d_rules.size() - 1);
- Debug("rewriterules") << "created rewriterule"<< (rr->d_split?"(split)":"") << ":(" << d_rules.size() - 1 << ")"
+ Debug("rewriterules::new") << "created rewriterule"<< (rr->d_split?"(split)":"") << ":(" << d_rules.size() - 1 << ")"
<< *rr << std::endl;
}
@@ -227,7 +303,7 @@ bool willDecide(TNode node, bool positive = true){
case XOR:
return true;
case IMPLIES:
- return false;
+ return true;
case ITE:
return true;
case NOT:
@@ -237,45 +313,50 @@ bool willDecide(TNode node, bool positive = true){
}
}
-
+static size_t id_next = 0;
RewriteRule::RewriteRule(TheoryRewriteRules & re,
- Trigger & tr, Trigger & tr2,
+ Trigger & tr, ApplyMatcher * applymatcher,
std::vector<Node> & g, Node b, TNode nt,
std::vector<Node> & fv,std::vector<Node> & iv,
std::vector<Node> & to_r, bool drr) :
- d_split(willDecide(b)),
+ id(++id_next), d_split(willDecide(b)),
trigger(tr), body(b), new_terms(nt), free_vars(), inst_vars(),
- body_match(re.getSatContext()),trigger_for_body_match(tr2),
+ body_match(re.getSatContext()),trigger_for_body_match(applymatcher),
d_cache(re.getSatContext(),re.getQuantifiersEngine()), directrr(drr){
free_vars.swap(fv); inst_vars.swap(iv); guards.swap(g); to_remove.swap(to_r);
};
bool RewriteRule::inCache(TheoryRewriteRules & re, InstMatch & im)const{
- return !d_cache.addInstMatch(im);
+ bool res = !d_cache.addInstMatch(im);
+ Debug("rewriterules::matching") << "rewriterules::cache " << im
+ << (res ? " HIT" : " MISS") << std::endl;
+ return res;
};
/** A rewrite rule */
void RewriteRule::toStream(std::ostream& out) const{
+ out << "[" << id << "] ";
for(std::vector<Node>::const_iterator
iter = guards.begin(); iter != guards.end(); ++iter){
out << *iter;
};
out << "=>" << body << std::endl;
- out << "[";
+ out << "{";
for(BodyMatch::const_iterator
iter = body_match.begin(); iter != body_match.end(); ++iter){
- out << (*iter).first << "(" << (*iter).second << ")" << ",";
+ out << (*iter).first << "[" << (*iter).second->id << "]" << ",";
};
- out << "]" << (directrr?"*":"") << std::endl;
+ out << "}" << (directrr?"*":"") << std::endl;
}
RewriteRule::~RewriteRule(){
- Debug("rewriterule-stats") << *this
+ Debug("rewriterule::stats") << *this
<< " (" << nb_matched
<< "," << nb_applied
<< "," << nb_propagated
<< ")" << std::endl;
+ delete(trigger_for_body_match);
}
bool TheoryRewriteRules::addRewritePattern(TNode pattern, TNode body,
diff --git a/src/theory/rewriterules/theory_rewriterules_type_rules.h b/src/theory/rewriterules/theory_rewriterules_type_rules.h
index 8bc4522a1..605324b20 100644
--- a/src/theory/rewriterules/theory_rewriterules_type_rules.h
+++ b/src/theory/rewriterules/theory_rewriterules_type_rules.h
@@ -45,16 +45,16 @@ public:
Assert(n.getKind() == kind::REWRITE_RULE && n.getNumChildren()==3 );
if( check ){
if( n[ 0 ].getType(check)!=nodeManager->boundVarListType() ){
- throw TypeCheckingExceptionPrivate(n,
+ throw TypeCheckingExceptionPrivate(n[0],
"first argument of rewrite rule is not bound var list");
}
if( n[ 1 ].getType(check)!=nodeManager->booleanType() ){
- throw TypeCheckingExceptionPrivate(n,
+ throw TypeCheckingExceptionPrivate(n[1],
"guard of rewrite rule is not an actual guard");
}
if( n[2].getType(check) !=
TypeNode(nodeManager->mkTypeConst<TypeConstant>(RRHB_TYPE))){
- throw TypeCheckingExceptionPrivate(n,
+ throw TypeCheckingExceptionPrivate(n[2],
"not a correct rewrite rule");
}
}
diff --git a/src/theory/rr_inst_match.cpp b/src/theory/rr_inst_match.cpp
new file mode 100644
index 000000000..3ba0c8d32
--- /dev/null
+++ b/src/theory/rr_inst_match.cpp
@@ -0,0 +1,1447 @@
+/********************* */
+/*! \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/rr_inst_match.h"
+#include "theory/rr_trigger.h"
+#include "theory/rr_inst_match_impl.h"
+#include "theory/theory_engine.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/uf/theory_uf_instantiator.h"
+#include "theory/uf/theory_uf_candidate_generator.h"
+#include "theory/datatypes/theory_datatypes_candidate_generator.h"
+#include "theory/uf/equality_engine.h"
+#include "theory/arrays/theory_arrays.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<bool modEq>
+class InstMatchTrie2Pairs
+{
+ typename std::vector< std::vector < typename InstMatchTrie2Gen<modEq>::Tree > > d_data;
+ InstMatchTrie2Gen<modEq> 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<modEq>::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<Node> & vars){
+ if(pat.isNull()) return true;
+
+ typedef std::vector<std::pair<TNode,TNode> > tstack;
+ tstack stack(1,std::make_pair(t0,pat)); // t * pat
+
+ while(!stack.empty()){
+ const std::pair<TNode,TNode> 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<TNode,size_t,EqualityQuery*> >::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 CG, class M>
+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 M>
+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 M, class Test >
+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<TNode,bool>*/ {
+ 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<TNode,bool>*/ {
+ 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<TNode,bool>*/ {
+ 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<TNode,bool>*/ {
+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<uf::TheoryUF *>(qe->getTheoryEngine()->getTheory( theory::THEORY_UF ));
+ eq::EqualityEngine* ee =
+ static_cast<eq::EqualityEngine*>(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<uf::TheoryUF::NotifyClass>* ee = (static_cast<uf::TheoryUF*>(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< datatypes::rrinst::CandidateGeneratorTheoryClass, 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<datatypes::TheoryDatatypes *>(qe->getTheoryEngine()->getTheory( theory::THEORY_DATATYPES ));
+ datatypes::rrinst::CandidateGeneratorTheoryClass cdtDtEq(dt);
+ /* 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<arrays::TheoryArrays *>(qe->getTheoryEngine()->getTheory( theory::THEORY_ARRAY ));
+ eq::EqualityEngine* ee =
+ static_cast<eq::EqualityEngine*>(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<uf::TheoryUF::NotifyClass>* ee = (static_cast<uf::TheoryUF*>(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 <bool classes> /** 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<false>, 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<false> 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<true>, 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<true> 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<datatypes::TheoryDatatypes *>(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<arrays::TheoryArrays *>(te->getTheory( theory::THEORY_ARRAY ));
+ eq::EqualityEngine* ee =
+ static_cast<eq::EqualityEngine*>(ar->getEqualityEngine());
+ return new CandidateGeneratorTheoryEeClasses(ee);
+ } else {
+ uf::TheoryUF* uf = static_cast<uf::TheoryUF*>(te->getTheory( theory::THEORY_UF ));
+ eq::EqualityEngine* ee =
+ static_cast<eq::EqualityEngine*>(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<Node> & 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<uf::TheoryUF*>(qe->getTheoryEngine()->getTheory( theory::THEORY_UF ));
+ eq::EqualityEngine* ee =
+ static_cast<eq::EqualityEngine*>(uf->getEqualityEngine());
+ CandidateGeneratorTheoryEeClasses cdtUfEq(ee);
+ /* Create a matcher from the candidate generator */
+ AuxMatcher1 am1(cdtUfEq,am2);
+ return am1;
+ }
+public:
+ UfEqMatcher( std::vector<Node> & 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<Node,bool>*/ {
+ 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<uf::TheoryUF*>(qe->getTheoryEngine()->getTheory( theory::THEORY_UF ));
+ eq::EqualityEngine* ee =
+ static_cast<eq::EqualityEngine*>(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<uf::TheoryUF*>(qe->getTheoryEngine()->getTheory( theory::THEORY_UF )))->getEqualityEngine()->
+ getRepresentative(NodeManager::currentNM()->mkConst<bool>(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 ) ){
+ std::cout << "(?) 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<ArithMatcher, LegalTypeTest>
+ am2(am3,LegalTypeTest(pat.getType()));
+ /* generator */
+ uf::TheoryUF* uf = static_cast<uf::TheoryUF*>(qe->getTheoryEngine()->getTheory( theory::THEORY_UF ));
+ eq::EqualityEngine* ee =
+ static_cast<eq::EqualityEngine*> (uf->getEqualityEngine());
+ CandidateGeneratorTheoryEeClass cdtUfEq(ee);
+ return new CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass,
+ TestMatcher<ArithMatcher, LegalTypeTest> > (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;
+ std::cout << "(?) 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<ArithMatcher, LegalTest>
+ am2(am3,LegalTest());
+ /* generator */
+ TermDb* tdb = qe->getTermDatabase();
+ CandidateGeneratorTheoryUfType cdtUfEq(pat.getType(),tdb);
+ typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryUfType,
+ TestMatcher<ArithMatcher, LegalTest> > AuxMatcher1;
+ return new PatOfMatcher<AuxMatcher1>(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<Rational>() );
+ 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<true> d_cache;
+ std::vector<Node> 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
new file mode 100644
index 000000000..d89b221bb
--- /dev/null
+++ b/src/theory/rr_inst_match.h
@@ -0,0 +1,263 @@
+/********************* */
+/*! \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__RR_INST_MATCH_H
+#define __CVC4__RR_INST_MATCH_H
+
+#include "theory/theory.h"
+#include "util/hash.h"
+#include "util/ntuple.h"
+
+#include <ext/hash_set>
+#include <iostream>
+#include <map>
+
+#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"
+
+//#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::current()->cbqi || !n.hasAttribute(InstConstantAttribute())) &&
+ ( !Options::current()->efficientEMatching || n.hasAttribute(AvailableInTermDb()) );
+}
+
+};
+
+
+inline std::ostream& operator<<(std::ostream& out, const InstMatch& m) {
+ m.toStream(out);
+ return out;
+}
+
+template<bool modEq = false> class InstMatchTrie2;
+template<bool modEq = false> class InstMatchTrie2Pairs;
+
+template<bool modEq = false>
+class InstMatchTrie2Gen
+{
+ friend class InstMatchTrie2<modEq>;
+ friend class InstMatchTrie2Pairs<modEq>;
+
+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<Tree *, TNode> 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<Mod, CleanUp, std::allocator<Mod> > d_mods;
+
+
+ typedef std::map<Node, Node>::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<bool modEq>
+class InstMatchTrie2
+{
+ typename InstMatchTrie2Gen<modEq>::Tree d_data;
+ InstMatchTrie2Gen<modEq> 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<Node> & 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
new file mode 100644
index 000000000..04a15d41f
--- /dev/null
+++ b/src/theory/rr_inst_match_impl.h
@@ -0,0 +1,128 @@
+/********************* */
+/*! \file inst_match_impl.h
+ ** \verbatim
+ ** Original author: bobot
+ ** Major contributors: none
+ ** Minor contributors (to current version): taking, 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/uf/theory_uf_candidate_generator.h"
+#include "theory/uf/equality_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace rrinst {
+
+template<bool modEq>
+InstMatchTrie2Gen<modEq>::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<bool modEq>
+void InstMatchTrie2Gen<modEq>::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 modEq>
+bool InstMatchTrie2Gen<modEq>::existsInstMatch(InstMatchTrie2Gen<modEq>::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<modEq>::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<modEq>::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 modEq>
+bool InstMatchTrie2Gen<modEq>::
+addInstMatch( InstMatch& m, InstMatchTrie2Gen<modEq>::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
new file mode 100644
index 000000000..579608b59
--- /dev/null
+++ b/src/theory/rr_trigger.cpp
@@ -0,0 +1,523 @@
+/********************* */
+/*! \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/rr_trigger.h"
+#include "theory/theory_engine.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/uf/theory_uf_instantiator.h"
+#include "theory/uf/theory_uf_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
new file mode 100644
index 000000000..7ea4ee1a3
--- /dev/null
+++ b/src/theory/rr_trigger.h
@@ -0,0 +1,176 @@
+/********************* */
+/*! \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__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.h b/src/theory/theory.h
index 7d003bf25..0cf7a8774 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -52,6 +52,10 @@ class InstStrategy;
class QuantifiersEngine;
class TheoryModel;
+namespace rrinst{
+class CandidateGenerator;
+}
+
/**
* Information about an assertion for the theories.
*/
@@ -834,6 +838,12 @@ public:
virtual bool areDisequal( Node a, Node b ) { return false; }
virtual Node getRepresentative( Node a ) { return a; }
virtual Node getInternalRepresentative( Node a ) { return getRepresentative( a ); }
+public:
+ /** A Creator of CandidateGenerator for classes (one element in each
+ equivalence class) and class (every element of one equivalence
+ class) */
+ virtual rrinst::CandidateGenerator* getRRCanGenClasses(){ return NULL; };
+ virtual rrinst::CandidateGenerator* getRRCanGenClass(){ return NULL; };
};/* class Instantiator */
inline Assertion Theory::get() {
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index f55c7c258..449f4adc3 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -450,6 +450,13 @@ public:
}
/**
+ * Get a pointer to the underlying user context.
+ */
+ inline context::Context* getUserContext() const {
+ return d_userContext;
+ }
+
+ /**
* Get a pointer to the underlying quantifiers engine.
*/
theory::QuantifiersEngine* getQuantifiersEngine() const {
@@ -677,8 +684,8 @@ public:
}
/** Get the theory for id */
- theory::Theory* getTheory(int id) {
- return d_theoryTable[id];
+ theory::Theory* getTheory(theory::TheoryId theoryId) {
+ return d_theoryTable[theoryId];
}
/**
diff --git a/src/theory/trigger.cpp b/src/theory/trigger.cpp
index 55ca07d77..14ba88ba1 100644
--- a/src/theory/trigger.cpp
+++ b/src/theory/trigger.cpp
@@ -26,6 +26,7 @@ using namespace CVC4;
using namespace CVC4::kind;
using namespace CVC4::context;
using namespace CVC4::theory;
+using namespace CVC4::theory::inst;
//#define NESTED_PATTERN_SELECTION
diff --git a/src/theory/trigger.h b/src/theory/trigger.h
index 476ef392e..84bc7ac2e 100644
--- a/src/theory/trigger.h
+++ b/src/theory/trigger.h
@@ -23,6 +23,7 @@
namespace CVC4 {
namespace theory {
+namespace inst {
//a collect of nodes representing a trigger
class Trigger {
@@ -163,6 +164,8 @@ inline std::ostream& operator<<(std::ostream& out, const Trigger & tr) {
return out;
}
+}/* CVC4::theory::inst namespace */
+
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp
index fe75b5f59..9376c858d 100644
--- a/src/theory/uf/equality_engine.cpp
+++ b/src/theory/uf/equality_engine.cpp
@@ -65,6 +65,10 @@ void EqualityEngine::init() {
d_triggerDatabaseAllocatedSize = 100000;
d_triggerDatabase = (char*) malloc(d_triggerDatabaseAllocatedSize);
+ //We can't notify during the initialization because it notifies
+ // QuantifiersEngine.AddTermToDatabase that try to access to the uf
+ // instantiator that currently doesn't exist.
+ ScopedBool sb(d_performNotify, false);
addTerm(d_true);
addTerm(d_false);
diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h
index 9228e29d4..0b461131e 100644
--- a/src/theory/uf/equality_engine.h
+++ b/src/theory/uf/equality_engine.h
@@ -794,7 +794,7 @@ class EqClassesIterator {
public:
- EqClassesIterator() { }
+ EqClassesIterator(): d_ee(NULL), d_it(0){ }
EqClassesIterator(eq::EqualityEngine* ee) : d_ee(ee) {
d_it = 0;
if ( d_it < d_ee->d_nodesCount &&
@@ -840,7 +840,7 @@ class EqClassIterator {
public:
- EqClassIterator() { }
+ EqClassIterator(): d_ee(NULL){ }
EqClassIterator(Node eqc, eq::EqualityEngine* ee) : d_ee(ee) {
Assert( d_ee->getRepresentative(eqc) == eqc );
d_rep = eqc;
diff --git a/src/theory/uf/inst_strategy.cpp b/src/theory/uf/inst_strategy.cpp
index 669df055a..5696251ed 100644
--- a/src/theory/uf/inst_strategy.cpp
+++ b/src/theory/uf/inst_strategy.cpp
@@ -28,6 +28,7 @@ using namespace CVC4::kind;
using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::uf;
+using namespace CVC4::theory::inst;
#define USE_SINGLE_TRIGGER_BEFORE_MULTI_TRIGGER
//#define MULTI_TRIGGER_FULL_EFFORT_HALF
@@ -83,7 +84,7 @@ void InstStrategyCheckCESolved::calcSolved( Node f ){
Node i = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j );
Node rep = d_th->getInternalRepresentative( i );
if( !rep.hasAttribute(InstConstantAttribute()) ){
- d_th->d_baseMatch[f].d_map[ i ] = rep;
+ d_th->d_baseMatch[f].set(i,rep);
}else{
d_solved[ f ] = false;
}
diff --git a/src/theory/uf/inst_strategy.h b/src/theory/uf/inst_strategy.h
index 09b8087f2..a0091c4b4 100644
--- a/src/theory/uf/inst_strategy.h
+++ b/src/theory/uf/inst_strategy.h
@@ -20,6 +20,7 @@
#define __CVC4__INST_STRATEGY_H
#include "theory/quantifiers_engine.h"
+#include "theory/trigger.h"
#include "context/context.h"
#include "context/context_mm.h"
@@ -59,7 +60,7 @@ private:
/** InstantiatorTheoryUf class */
InstantiatorTheoryUf* d_th;
/** explicitly provided patterns */
- std::map< Node, std::vector< Trigger* > > d_user_gen;
+ std::map< Node, std::vector< inst::Trigger* > > d_user_gen;
/** counter for quantifiers */
std::map< Node, int > d_counter;
/** process functions */
@@ -75,7 +76,7 @@ public:
/** get num patterns */
int getNumUserGenerators( Node f ) { return (int)d_user_gen[f].size(); }
/** get user pattern */
- Trigger* getUserGenerator( Node f, int i ) { return d_user_gen[f][ i ]; }
+ inst::Trigger* getUserGenerator( Node f, int i ) { return d_user_gen[f][ i ]; }
/** identify */
std::string identify() const { return std::string("UserPatterns"); }
};/* class InstStrategyUserPatterns */
@@ -99,7 +100,7 @@ private:
/** generate additional triggers */
bool d_generate_additional;
/** triggers for each quantifier */
- std::map< Node, std::map< Trigger*, bool > > d_auto_gen_trigger;
+ std::map< Node, std::map< inst::Trigger*, bool > > d_auto_gen_trigger;
std::map< Node, int > d_counter;
/** single, multi triggers for each quantifier */
std::map< Node, std::vector< Node > > d_patTerms[2];
@@ -120,7 +121,7 @@ public:
~InstStrategyAutoGenTriggers(){}
public:
/** get auto-generated trigger */
- Trigger* getAutoGenTrigger( Node f );
+ inst::Trigger* getAutoGenTrigger( Node f );
/** identify */
std::string identify() const { return std::string("AutoGenTriggers"); }
/** set regenerate frequency, if fr<0, turn off regenerate */
diff --git a/src/theory/uf/theory_uf_candidate_generator.cpp b/src/theory/uf/theory_uf_candidate_generator.cpp
index 5342188f7..80151d1e1 100644
--- a/src/theory/uf/theory_uf_candidate_generator.cpp
+++ b/src/theory/uf/theory_uf_candidate_generator.cpp
@@ -26,6 +26,11 @@ using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::uf;
+namespace CVC4{
+namespace theory{
+namespace uf{
+namespace inst{
+
CandidateGeneratorTheoryUf::CandidateGeneratorTheoryUf( InstantiatorTheoryUf* ith, Node op ) :
d_op( op ), d_ith( ith ), d_term_iter( -2 ){
Assert( !d_op.isNull() );
@@ -45,6 +50,7 @@ void CandidateGeneratorTheoryUf::reset( Node eqc ){
d_retNode = Node::null();
}else{
d_retNode = eqc;
+
}
d_term_iter = -1;
}
@@ -169,3 +175,8 @@ Node CandidateGeneratorTheoryUfLitDeq::getNextCandidate(){
}
return Node::null();
}
+
+}
+}
+}
+}
diff --git a/src/theory/uf/theory_uf_candidate_generator.h b/src/theory/uf/theory_uf_candidate_generator.h
index 668d619db..a06f04f99 100644
--- a/src/theory/uf/theory_uf_candidate_generator.h
+++ b/src/theory/uf/theory_uf_candidate_generator.h
@@ -20,11 +20,155 @@
#define __CVC4__THEORY_UF_CANDIDATE_GENERATOR_H
#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/term_database.h"
#include "theory/uf/theory_uf_instantiator.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_iter<d_term_iter_limit ){
+ TNode n = d_tdb->d_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_iter<d_term_iter_limit ){
+ TNode n = d_tdb->d_type_map[d_type][d_term_iter];
+ ++d_term_iter;
+ return n;
+ } else return Node::null();
+ };
+};
+
+} /* namespace rrinst */
+
+namespace inst{
+typedef CVC4::theory::inst::CandidateGenerator CandidateGenerator;
+
+//Old CandidateGenerator
class CandidateGeneratorTheoryUfDisequal;
@@ -108,7 +252,8 @@ public:
};
-}
+}/* CVC4::theory::uf::inst namespace */
+}/* CVC4::theory::uf namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/uf/theory_uf_instantiator.cpp b/src/theory/uf/theory_uf_instantiator.cpp
index e3999c163..257bed0a2 100644
--- a/src/theory/uf/theory_uf_instantiator.cpp
+++ b/src/theory/uf/theory_uf_instantiator.cpp
@@ -17,6 +17,7 @@
#include "theory/uf/theory_uf_instantiator.h"
#include "theory/theory_engine.h"
#include "theory/uf/theory_uf.h"
+#include "theory/uf/theory_uf_candidate_generator.h"
#include "theory/uf/equality_engine.h"
#include "theory/quantifiers/term_database.h"
@@ -26,6 +27,15 @@ using namespace CVC4::kind;
using namespace CVC4::context;
using namespace CVC4::theory;
using namespace CVC4::theory::uf;
+using namespace CVC4::theory::inst;
+
+namespace CVC4 {
+namespace theory {
+namespace uf {
+
+inline std::ostream& operator<<(std::ostream& out, const InstantiatorTheoryUf::Ips& ips) {
+ return out;
+};
EqClassInfo::EqClassInfo( context::Context* c ) : d_funs( c ), d_pfuns( c ), d_disequal( c ){
@@ -33,13 +43,15 @@ EqClassInfo::EqClassInfo( context::Context* c ) : d_funs( c ), d_pfuns( c ), d_d
//set member
void EqClassInfo::setMember( Node n, quantifiers::TermDb* db ){
- if( n.getKind()==APPLY_UF ){
- d_funs[n.getOperator()] = true;
+ if( n.hasOperator() ){
+ d_funs.insertAtContextLevelZero(n.getOperator(),true);
}
//add parent functions
- for( std::map< Node, std::map< int, std::vector< Node > > >::iterator it = db->d_parents[n].begin();
+ for( std::hash_map< Node, std::hash_map< int, std::vector< Node > >, NodeHashFunction >::iterator it = db->d_parents[n].begin();
it != db->d_parents[n].end(); ++it ){
- d_pfuns[ it->first ] = true;
+ //TODO Is it true to do it at level 0? That depend when SetMember is called
+ // At worst it is a good overapproximation
+ d_pfuns.insertAtContextLevelZero( it->first, true);
}
}
@@ -62,6 +74,20 @@ void EqClassInfo::merge( EqClassInfo* eci ){
}
}
+inline void outputEqClassInfo( const char* c, const EqClassInfo* eci){
+ Debug(c) << " funs:";
+ for( EqClassInfo::BoolMap::iterator it = eci->d_funs.begin(); it != eci->d_funs.end(); it++ ) {
+ Debug(c) << (*it).first << ",";
+ }
+ Debug(c) << std::endl << "pfuns:";
+ for( EqClassInfo::BoolMap::iterator it = eci->d_pfuns.begin(); it != eci->d_pfuns.end(); it++ ) {
+ Debug(c) << (*it).first << ",";
+ }
+ Debug(c) << std::endl;
+}
+
+
+
InstantiatorTheoryUf::InstantiatorTheoryUf(context::Context* c, CVC4::theory::QuantifiersEngine* qe, Theory* th) :
Instantiator( c, qe, th )
{
@@ -221,21 +247,92 @@ void InstantiatorTheoryUf::newEqClass( TNode n ){
d_quantEngine->addTermToDatabase( n );
}
+void InstantiatorTheoryUf::newTerms(SetNode& s){
+ static NoMatchAttribute rewrittenNodeAttribute;
+ /* op -> nodes (if the set is empty, the op is not interesting) */
+ std::hash_map< TNode, SetNode, TNodeHashFunction > h;
+ /* types -> nodes (if the set is empty, the type is not interesting) */
+ std::hash_map< TypeNode, SetNode, TypeNodeHashFunction > tyh;
+ for(SetNode::iterator i=s.begin(), end=s.end(); i != end; ++i){
+ if (i->getAttribute(rewrittenNodeAttribute)) continue; /* skip it */
+ if( !d_cand_gens.empty() ){
+ // op
+ TNode op = i->getOperator();
+ std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator
+ is = h.find(op);
+ if(is == h.end()){
+ std::pair<std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator,bool>
+ p = h.insert(make_pair(op,SetNode()));
+ is = p.first;
+ if(d_cand_gens.find(op) != d_cand_gens.end()){
+ is->second.insert(*i);
+ } /* else we have inserted an empty set */
+ }else if(!is->second.empty()){
+ is->second.insert(*i);
+ }
+ }
+ if( !d_cand_gen_types.empty() ){
+ //type
+ TypeNode ty = i->getType();
+ std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator
+ is = tyh.find(ty);
+ if(is == tyh.end()){
+ std::pair<std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator,bool>
+ p = tyh.insert(make_pair(ty,SetNode()));
+ is = p.first;
+ if(d_cand_gen_types.find(ty) != d_cand_gen_types.end()){
+ is->second.insert(*i);
+ } /* else we have inserted an empty set */
+ }else if(!is->second.empty()){
+ is->second.insert(*i);
+ }
+ }
+ }
+ //op
+ for(std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator i=h.begin(), end=h.end();
+ i != end; ++i){
+ //new term, add n to candidate generators
+ if(i->second.empty()) continue;
+ std::map< Node, NodeNewTermDispatcher >::iterator
+ inpc = d_cand_gens.find(i->first);
+ //we know that this op exists
+ Assert(inpc != d_cand_gens.end());
+ inpc->second.send(i->second);
+ }
+ //type
+ for(std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator i=tyh.begin(), end=tyh.end();
+ i != end; ++i){
+ //new term, add n to candidate generators
+ if(i->second.empty()) continue;
+ std::map< TypeNode, NodeNewTermDispatcher >::iterator
+ inpc = d_cand_gen_types.find(i->first);
+ //we know that this op exists
+ Assert(inpc != d_cand_gen_types.end());
+ inpc->second.send(i->second);
+ }
+
+}
+
+
/** merge */
void InstantiatorTheoryUf::merge( TNode a, TNode b ){
if( Options::current()->efficientEMatching ){
+ //merge eqc_ops of b into a
+ EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a );
+ EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( b );
+
if( a.getKind()!=IFF && a.getKind()!=EQUAL && b.getKind()!=IFF && b.getKind()!=EQUAL ){
Debug("efficient-e-match") << "Merging " << a << " with " << b << std::endl;
//determine new candidates for instantiation
- computeCandidatesPcPairs( a, b );
- computeCandidatesPcPairs( b, a );
- computeCandidatesPpPairs( a, b );
- computeCandidatesPpPairs( b, a );
+ computeCandidatesPcPairs( a, eci_a, b, eci_b );
+ computeCandidatesPcPairs( b, eci_b, a, eci_a );
+ computeCandidatesPpPairs( a, eci_a, b, eci_b );
+ computeCandidatesPpPairs( b, eci_b, a, eci_a );
}
- //merge eqc_ops of b into a
- EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a );
- EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( b );
+ computeCandidatesConstants( a, eci_a, b, eci_b);
+ computeCandidatesConstants( b, eci_b, a, eci_a);
+
eci_a->merge( eci_b );
}
}
@@ -258,97 +355,99 @@ EqClassInfo* InstantiatorTheoryUf::getOrCreateEquivalenceClassInfo( Node n ){
return d_eqc_ops[n];
}
-void InstantiatorTheoryUf::computeCandidatesPcPairs( Node a, Node b ){
+void InstantiatorTheoryUf::computeCandidatesPcPairs( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){
Debug("efficient-e-match") << "Compute candidates for pc pairs..." << std::endl;
Debug("efficient-e-match") << " Eq class = [";
outputEqClass( "efficient-e-match", a);
Debug("efficient-e-match") << "]" << std::endl;
- EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a );
- EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( a );
+ outputEqClassInfo("efficient-e-match",eci_a);
for( BoolMap::iterator it = eci_a->d_funs.begin(); it != eci_a->d_funs.end(); it++ ) {
//the child function: a member of eq_class( a ) has top symbol g, in other words g is in funs( a )
Node g = (*it).first;
Debug("efficient-e-match") << " Checking application " << g << std::endl;
//look at all parent/child pairs
- for( std::map< Node, std::map< Node, std::vector< InvertedPathString > > >::iterator itf = d_pc_pairs[g].begin();
+ for( std::map< Node, std::vector< std::pair< NodePcDispatcher*, Ips > > >::iterator itf = d_pc_pairs[g].begin();
itf != d_pc_pairs[g].end(); ++itf ){
//f/g is a parent/child pair
Node f = itf->first;
- if( eci_b->hasParent( f ) || true ){
+ if( eci_b->hasParent( f ) ){
//DO_THIS: determine if f in pfuns( b ), only do the follow if so
Debug("efficient-e-match") << " Checking parent application " << f << std::endl;
//scan through the list of inverted path strings/candidate generators
- for( std::map< Node, std::vector< InvertedPathString > >::iterator cit = itf->second.begin();
- cit != itf->second.end(); ++cit ){
- Node pat = cit->first;
- Debug("efficient-e-match") << " Checking pattern " << pat << std::endl;
- for( int c=0; c<(int)cit->second.size(); c++ ){
- Debug("efficient-e-match") << " Check inverted path string for pattern ";
- outputInvertedPathString( "efficient-e-match", cit->second[c] );
- Debug("efficient-e-match") << std::endl;
-
- //collect all new relevant terms
- std::vector< Node > terms;
- terms.push_back( b );
- collectTermsIps( cit->second[c], terms );
- if( !terms.empty() ){
- Debug("efficient-e-match") << " -> Added terms (" << (int)terms.size() << "): ";
- //add them as candidates to the candidate generator
- for( int t=0; t<(int)terms.size(); t++ ){
- Debug("efficient-e-match") << terms[t] << " ";
- //Notice() << "Add candidate (PC) " << terms[t] << std::endl;
- for( int cg=0; cg<(int)d_pat_cand_gens[pat].size(); cg++ ){
- d_pat_cand_gens[pat][cg]->addCandidate( terms[t] );
- }
- }
- Debug("efficient-e-match") << std::endl;
- }
+ for( std::vector< std::pair< NodePcDispatcher*, Ips > >::iterator cit = itf->second.begin();
+ cit != itf->second.end(); ++cit ){
+#ifdef CVC4_DEBUG
+ Debug("efficient-e-match") << " Checking pattern " << cit->first->pat << std::endl;
+#endif
+ Debug("efficient-e-match") << " Check inverted path string for pattern ";
+ outputIps( "efficient-e-match", cit->second );
+ Debug("efficient-e-match") << std::endl;
+
+ //collect all new relevant terms
+ SetNode terms;
+ terms.insert( b );
+ collectTermsIps( cit->second, terms );
+ if( terms.empty() ) continue;
+ Debug("efficient-e-match") << " -> Added terms (" << terms.size() << "): ";
+ for( SetNode::const_iterator t=terms.begin(), end=terms.end();
+ t!=end; ++t ){
+ Debug("efficient-e-match") << (*t) << " ";
}
+ Debug("efficient-e-match") << std::endl;
+ //add them as candidates to the candidate generator
+ cit->first->send(terms);
}
}
}
}
}
-void InstantiatorTheoryUf::computeCandidatesPpPairs( Node a, Node b ){
+void InstantiatorTheoryUf::computeCandidatesPpPairs( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){
Debug("efficient-e-match") << "Compute candidates for pp pairs..." << std::endl;
- EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a );
- EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( a );
- for( std::map< Node, std::map< Node, std::map< Node, std::vector< IpsPair > > > >::iterator it = d_pp_pairs.begin();
+ for( std::map< Node, std::map< Node, std::vector< triple< NodePpDispatcher*, Ips, Ips > > > >::iterator it = d_pp_pairs.begin();
it != d_pp_pairs.end(); ++it ){
Node f = it->first;
if( eci_a->hasParent( f ) ){
Debug("efficient-e-match") << " Checking parent application " << f << std::endl;
- for( std::map< Node, std::map< Node, std::vector< IpsPair > > >::iterator it2 = it->second.begin();
+ for( std::map< Node, std::vector< triple<NodePpDispatcher*, Ips, Ips> > >::iterator it2 = it->second.begin();
it2 != it->second.end(); ++it2 ){
Node g = it2->first;
if( eci_b->hasParent( g ) ){
Debug("efficient-e-match") << " Checking parent application " << g << std::endl;
//if f in pfuns( a ) and g is in pfuns( b ), only do the follow if so
- for( std::map< Node, std::vector< IpsPair > >::iterator cit = it2->second.begin();
+ for( std::vector< triple<NodePpDispatcher*, Ips, Ips> > ::iterator cit = it2->second.begin();
cit != it2->second.end(); ++cit ){
- Node pat = cit->first;
- for( int c=0; c<(int)cit->second.size(); c++ ){
- std::vector< Node > a_terms;
- a_terms.push_back( a );
- if( !a_terms.empty() ){
- collectTermsIps( cit->second[c].first, a_terms );
- std::vector< Node > b_terms;
- b_terms.push_back( b );
- collectTermsIps( cit->second[c].first, b_terms );
- //take intersection
- for( int t=0; t<(int)a_terms.size(); t++ ){
- if( std::find( b_terms.begin(), b_terms.end(), a_terms[t] )!=b_terms.end() ){
- //Notice() << "Add candidate (PP) " << a_terms[t] << std::endl;
- Debug("efficient-e-match") << " -> Add term " << a_terms[t] << std::endl;
- //add to all candidate generators having this term
- for( int cg=0; cg<(int)d_pat_cand_gens[pat].size(); cg++ ){
- d_pat_cand_gens[pat][cg]->addCandidate( a_terms[t] );
- }
- }
- }
- }
+#ifdef CVC4_DEBUG
+ Debug("efficient-e-match") << " Checking pattern " << cit->first->pat1 << " and " << cit->first->pat2 << std::endl;
+#endif
+ Debug("efficient-e-match") << " Check inverted path string ";
+ outputIps( "efficient-e-match", cit->second );
+ SetNode a_terms;
+ a_terms.insert( a );
+ collectTermsIps( cit->second, a_terms );
+ if( a_terms.empty() ) continue;
+ Debug("efficient-e-match") << " And check inverted path string ";
+ outputIps( "efficient-e-match", cit->third );
+ SetNode b_terms;
+ b_terms.insert( b );
+ collectTermsIps( cit->third, b_terms );
+ if( b_terms.empty() ) continue;
+ //Start debug
+ Debug("efficient-e-match") << " -> Possibly Added termsA (" << a_terms.size() << "): ";
+ for( SetNode::const_iterator t=a_terms.begin(), end=a_terms.end();
+ t!=end; ++t ){
+ Debug("efficient-e-match") << (*t) << " ";
+ }
+ Debug("efficient-e-match") << std::endl;
+ Debug("efficient-e-match") << " -> Possibly Added termsB (" << b_terms.size() << "): ";
+ for( SetNode::const_iterator t=b_terms.begin(), end=b_terms.end();
+ t!=end; ++t ){
+ Debug("efficient-e-match") << (*t) << " ";
}
+ Debug("efficient-e-match") << std::endl;
+ //End debug
+
+ cit->first->send(a_terms,b_terms);
}
}
}
@@ -356,39 +455,87 @@ void InstantiatorTheoryUf::computeCandidatesPpPairs( Node a, Node b ){
}
}
-void InstantiatorTheoryUf::collectTermsIps( InvertedPathString& ips, std::vector< Node >& terms, int index ){
- if( index<(int)ips.size() && !terms.empty() ){
+
+void InstantiatorTheoryUf::computeCandidatesConstants( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){
+ Debug("efficient-e-match") << "Compute candidates constants for cc pairs..." << std::endl;
+ Debug("efficient-e-match") << " Eq class = [";
+ outputEqClass( "efficient-e-match", a);
+ Debug("efficient-e-match") << "]" << std::endl;
+ outputEqClassInfo("efficient-e-match",eci_a);
+ for( std::map< Node, std::map< Node, NodePcDispatcher* > >::iterator
+ it = d_cc_pairs.begin(), end = d_cc_pairs.end();
+ it != end; ++it ) {
+ Debug("efficient-e-match") << " Checking application " << it->first << std::endl;
+ if( !eci_b->hasFunction(it->first) ) continue;
+ for( std::map< Node, NodePcDispatcher* >::iterator
+ itc = it->second.begin(), end = it->second.end();
+ itc != end; ++itc ) {
+ //The constant
+ Debug("efficient-e-match") << " Checking constant " << a << std::endl;
+ if(getRepresentative(itc->first) != a) continue;
+ SetNode s;
+ eq::EqClassIterator eqc_iter( b, &((TheoryUF*)d_th)->d_equalityEngine );
+ while( !eqc_iter.isFinished() ){
+ Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter)
+ << std::endl;
+ if( (*eqc_iter).hasOperator() && (*eqc_iter).getOperator() == it->first ) s.insert(*eqc_iter);
+ eqc_iter++;
+ }
+
+ if( s.empty() ) continue;
+ Debug("efficient-e-match") << " -> Added terms (" << s.size() << "): ";
+ for( SetNode::const_iterator t=s.begin(), end=s.end();
+ t!=end; ++t ){
+ Debug("efficient-e-match") << (*t) << " ";
+ }
+ Debug("efficient-e-match") << std::endl;
+ itc->second->send(s);
+ }
+ }
+}
+
+void InstantiatorTheoryUf::collectTermsIps( Ips& ips, SetNode & terms ){
+ Assert( ips.size() > 0);
+ return collectTermsIps( ips, terms, ips.size() - 1);
+}
+
+void InstantiatorTheoryUf::collectTermsIps( Ips& ips, SetNode& terms, int index ){
+ if( !terms.empty() ){
Debug("efficient-e-match-debug") << "> Process " << index << std::endl;
Node f = ips[index].first;
int arg = ips[index].second;
//for each term in terms, determine if any term (modulo equality) has parent "f" from position "arg"
- bool addRep = ( index!=(int)ips.size()-1 );
- std::vector< Node > newTerms;
- for( int t=0; t<(int)terms.size(); t++ ){
- collectParentsTermsIps( terms[t], f, arg, newTerms, addRep );
+ bool addRep = ( index!=0 ); // We want to keep the top symbol for the last
+ SetNode newTerms;
+ for( SetNode::const_iterator t=terms.begin(), end=terms.end();
+ t!=end; ++t ){
+ collectParentsTermsIps( *t, f, arg, newTerms, addRep );
}
- terms.clear();
- terms.insert( terms.begin(), newTerms.begin(), newTerms.end() );
+ terms.swap(newTerms);
Debug("efficient-e-match-debug") << "> Terms are now: ";
- for( int t=0; t<(int)terms.size(); t++ ){
- Debug("efficient-e-match-debug") << terms[t] << " ";
+ for( SetNode::const_iterator t=terms.begin(), end=terms.end();
+ t!=end; ++t ){
+ Debug("efficient-e-match-debug") << *t << " ";
}
Debug("efficient-e-match-debug") << std::endl;
- collectTermsIps( ips, terms, index+1 );
+ if(index!=0) collectTermsIps( ips, terms, index-1 );
}
}
-bool InstantiatorTheoryUf::collectParentsTermsIps( Node n, Node f, int arg, std::vector< Node >& terms, bool addRep, bool modEq ){
+bool InstantiatorTheoryUf::collectParentsTermsIps( Node n, Node f, int arg, SetNode & terms, bool addRep, bool modEq ){ //modEq default true
bool addedTerm = false;
- if( ((TheoryUF*)d_th)->d_equalityEngine.hasTerm( n ) && modEq ){
+
+ if( modEq && ((TheoryUF*)d_th)->d_equalityEngine.hasTerm( n )){
Assert( getRepresentative( n )==n );
//collect modulo equality
//DO_THIS: this should (if necessary) compute a current set of (f, arg) parents for n and cache it
- eq::EqClassIterator eqc_iter( getRepresentative( n ), &((TheoryUF*)d_th)->d_equalityEngine );
+ eq::EqClassIterator eqc_iter( n, &((TheoryUF*)d_th)->d_equalityEngine );
while( !eqc_iter.isFinished() ){
+ Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter)
+ << std::endl;
if( collectParentsTermsIps( (*eqc_iter), f, arg, terms, addRep, false ) ){
//if only one argument, we know we can stop (since all others added will be congruent)
if( f.getType().getNumChildren()==2 ){
@@ -401,90 +548,263 @@ bool InstantiatorTheoryUf::collectParentsTermsIps( Node n, Node f, int arg, std:
}else{
quantifiers::TermDb* db = d_quantEngine->getTermDatabase();
//see if parent f exists from argument arg
- if( db->d_parents.find( n )!=db->d_parents.end() ){
- if( db->d_parents[n].find( f )!=db->d_parents[n].end() ){
- if( db->d_parents[n][f].find( arg )!=db->d_parents[n][f].end() ){
- for( int i=0; i<(int)db->d_parents[n][f][arg].size(); i++ ){
- Node t = db->d_parents[n][f][arg][i];
- if( addRep ){
- t = getRepresentative( t );
- }
- if( std::find( terms.begin(), terms.end(), t )==terms.end() ){
- terms.push_back( t );
- }
- addedTerm = true;
- }
- }
- }
+ const std::vector<Node> & parents = db->getParents(n,f,arg);
+ for( size_t i=0; i<parents.size(); ++i ){
+ TNode t = parents[i];
+ if(!CandidateGenerator::isLegalCandidate(t)) continue;
+ if( addRep ) t = getRepresentative( t );
+ terms.insert(t);
+ addedTerm = true;
}
}
return addedTerm;
}
-void InstantiatorTheoryUf::registerPatternElementPairs2( Node opat, Node pat, InvertedPathString& ips,
- std::map< Node, std::vector< std::pair< Node, InvertedPathString > > >& ips_map ){
- Assert( pat.getKind()==APPLY_UF );
+void InstantiatorTheoryUf::registerPatternElementPairs2( Node pat, Ips& ips, PpIpsMap & pp_ips_map, NodePcDispatcher* npc ){
+ Assert( pat.hasOperator() );
//add information for possible pp-pair
+ ips.push_back( std::pair< Node, int >( pat.getOperator(), 0 ) ); //0 is just a dumb value
+
for( int i=0; i<(int)pat.getNumChildren(); i++ ){
if( pat[i].getKind()==INST_CONSTANT ){
- ips_map[ pat[i] ].push_back( std::pair< Node, InvertedPathString >( pat.getOperator(), InvertedPathString( ips ) ) );
+ ips.back().second = i;
+ pp_ips_map[ pat[i] ].push_back( make_pair( pat.getOperator(), Ips( ips ) ) );
}
}
- ips.push_back( std::pair< Node, int >( pat.getOperator(), 0 ) );
+
for( int i=0; i<(int)pat.getNumChildren(); i++ ){
if( pat[i].getKind()==APPLY_UF ){
ips.back().second = i;
- registerPatternElementPairs2( opat, pat[i], ips, ips_map );
+ registerPatternElementPairs2( pat[i], ips, pp_ips_map, npc );
Debug("pattern-element-opt") << "Found pc-pair ( " << pat.getOperator() << ", " << pat[i].getOperator() << " )" << std::endl;
Debug("pattern-element-opt") << " Path = ";
- outputInvertedPathString( "pattern-element-opt", ips );
+ outputIps( "pattern-element-opt", ips );
Debug("pattern-element-opt") << std::endl;
//pat.getOperator() and pat[i].getOperator() are a pc-pair
- d_pc_pairs[ pat[i].getOperator() ][ pat.getOperator() ][opat].push_back( InvertedPathString( ips ) );
+ d_pc_pairs[ pat[i].getOperator() ][ pat.getOperator() ]
+ .push_back( make_pair(npc,Ips(ips)) );
}
}
ips.pop_back();
}
-void InstantiatorTheoryUf::registerPatternElementPairs( Node pat ){
- InvertedPathString ips;
- std::map< Node, std::vector< std::pair< Node, InvertedPathString > > > ips_map;
- registerPatternElementPairs2( pat, pat, ips, ips_map );
- for( std::map< Node, std::vector< std::pair< Node, InvertedPathString > > >::iterator it = ips_map.begin(); it != ips_map.end(); ++it ){
- for( int j=0; j<(int)it->second.size(); j++ ){
- for( int k=j+1; k<(int)it->second.size(); k++ ){
+void InstantiatorTheoryUf::registerPatternElementPairs( Node pat, PpIpsMap & pp_ips_map,
+ NodePcDispatcher* npc,
+ NodePpDispatcher* npp){
+ Ips ips;
+ registerPatternElementPairs2( pat, ips, pp_ips_map, npc );
+ for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){
+ // for each variable construct all the pp-pair
+ for( size_t j=0; j<it->second.size(); j++ ){
+ for( size_t k=j+1; k<it->second.size(); k++ ){
//found a pp-pair
Debug("pattern-element-opt") << "Found pp-pair ( " << it->second[j].first << ", " << it->second[k].first << " )" << std::endl;
Debug("pattern-element-opt") << " Paths = ";
- outputInvertedPathString( "pattern-element-opt", it->second[j].second );
+ outputIps( "pattern-element-opt", it->second[j].second );
Debug("pattern-element-opt") << " and ";
- outputInvertedPathString( "pattern-element-opt", it->second[k].second );
+ outputIps( "pattern-element-opt", it->second[k].second );
Debug("pattern-element-opt") << std::endl;
- d_pp_pairs[ it->second[j].first ][ it->second[k].first ][pat].push_back( IpsPair( it->second[j].second, it->second[k].second ) );
+ d_pp_pairs[ it->second[j].first ][ it->second[k].first ]
+ .push_back( make_triple( npp, it->second[j].second, it->second[k].second ));
}
}
}
+};
+
+void findPpSite(Node pat, InstantiatorTheoryUf::Ips& ips, InstantiatorTheoryUf::PpIpsMap & pp_ips_map){
+ Assert( pat.getKind()==APPLY_UF );
+ //add information for possible pp-pair
+
+ ips.push_back( make_pair( pat.getOperator(), 0) );
+ for( size_t i=0; i<pat.getNumChildren(); i++ ){
+ if( pat[i].getKind()==INST_CONSTANT ){
+ ips.back().second = i;
+ pp_ips_map[ pat[i] ].push_back( make_pair( pat.getOperator(), InstantiatorTheoryUf::Ips( ips ) ) );
+ }
+ }
+
+ for( size_t i=0; i<pat.getNumChildren(); i++ ){
+ if( pat[i].getKind()==APPLY_UF ){
+ ips.back().second = i;
+ findPpSite( pat[i], ips, pp_ips_map );
+ }
+ }
+ ips.pop_back();
}
-void InstantiatorTheoryUf::registerCandidateGenerator( CandidateGenerator* cg, Node pat ){
- Debug("efficient-e-match") << "Register candidate generator..." << pat << std::endl;
- if( d_pat_cand_gens.find( pat )==d_pat_cand_gens.end() ){
- registerPatternElementPairs( pat );
+void InstantiatorTheoryUf::combineMultiPpIpsMap(PpIpsMap & pp_ips_map, MultiPpIpsMap & multi_pp_ips_map,
+ EfficientHandler& eh, size_t index2,const std::vector<Node> & pats){
+ hash_map<size_t,NodePpDispatcher*> npps;
+ for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){
+ MultiPpIpsMap::iterator mit = multi_pp_ips_map.find(it->first);
+ if(mit == multi_pp_ips_map.end()) continue;
+ // for each variable construct all the pp-pair
+ // j the last pattern treated
+ for( std::vector< std::pair< Node, Ips > >::iterator j=it->second.begin(), jend = it->second.end() ;
+ j != jend; ++j){
+ // k one of the previous one
+ for( std::vector< triple< size_t, Node, Ips > >::iterator k=mit->second.begin(), kend = mit->second.end() ;
+ k != kend; ++k){
+ //found a pp-pair
+ Debug("pattern-element-opt") << "Found multi-pp-pair ( " << j->first
+ << ", " << k->second << " in "<< k->first
+ << " )" << std::endl;
+ Debug("pattern-element-opt") << " Paths = ";
+ outputIps( "pattern-element-opt", j->second );
+ Debug("pattern-element-opt") << " and ";
+ outputIps( "pattern-element-opt", k->third );
+ Debug("pattern-element-opt") << std::endl;
+ NodePpDispatcher* dispatcher;
+ hash_map<size_t,NodePpDispatcher*>::iterator inpp = npps.find(k->first);
+ if( inpp != npps.end() ) dispatcher = inpp->second;
+ else{
+ dispatcher = new NodePpDispatcher();
+#ifdef CVC4_DEBUG
+ dispatcher->pat1 = pats[index2];
+ dispatcher->pat2 = pats[k->first];
+#endif
+ dispatcher->addPpDispatcher(&eh,index2,k->first);
+ };
+ d_pp_pairs[ j->first ][ k->second ].push_back( make_triple( dispatcher, j->second, k->third ));
+ }
+ }
}
- d_pat_cand_gens[pat].push_back( cg );
- //take all terms from the uf term db and add to candidate generator
- Node op = pat.getOperator();
- quantifiers::TermDb* db = d_quantEngine->getTermDatabase();
- for( int i=0; i<(int)db->d_op_map[op].size(); i++ ){
- cg->addCandidate( db->d_op_map[op][i] );
+ /** Put pp_ips_map to multi_pp_ips_map */
+ for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){
+ for( std::vector< std::pair< Node, Ips > >::iterator j=it->second.begin(), jend = it->second.end() ;
+ j != jend; ++j){
+ multi_pp_ips_map[it->first].push_back(make_triple(index2, j->first, j->second));
+ }
+ }
+
+}
+
+
+void InstantiatorTheoryUf::registerEfficientHandler( EfficientHandler& handler,
+ const std::vector< Node > & pats ){
+ Assert(pats.size() > 0);
+
+ MultiPpIpsMap multi_pp_ips_map;
+ PpIpsMap pp_ips_map;
+ //In a multi-pattern Pattern that is only a variable are specials,
+ //if the variable appears in another pattern, it can be discarded.
+ //Otherwise new term of this term can be candidate. So we stock them
+ //here before adding them.
+ std::vector< size_t > patVars;
+
+ Debug("pattern-element-opt") << "Register patterns" << pats << std::endl;
+ for(size_t i = 0; i < pats.size(); ++i){
+ if( pats[i].getKind() == kind::INST_CONSTANT){
+ patVars.push_back(i);
+ continue;
+ }
+ //to complete
+ if( pats[i].getKind() == kind::NOT && pats[i][0].getKind() == kind::EQUAL){
+ Node cst = NodeManager::currentNM()->mkConst<bool>(false);
+ TNode op = pats[i][0].getOperator();
+ if(d_cc_pairs[op][cst] == NULL){
+ d_cc_pairs[op][cst] = new NodePcDispatcher();
+ }
+ d_cc_pairs[op][cst]->addPcDispatcher(&handler,i);
+ continue;
+ }
+ //end to complete
+ Debug("pattern-element-opt") << " Register candidate generator..." << pats[i] << std::endl;
+ /* Has the pattern already been seen */
+ if( d_pat_cand_gens.find( pats[i] )==d_pat_cand_gens.end() ){
+ NodePcDispatcher* npc = new NodePcDispatcher();
+ NodePpDispatcher* npp = new NodePpDispatcher();
+#ifdef CVC4_DEBUG
+ npc->pat = pats[i];
+ npp->pat1 = pats[i];
+ npp->pat2 = pats[i];
+#endif
+ d_pat_cand_gens[pats[i]] = make_pair(npc,npp);
+ registerPatternElementPairs( pats[i], pp_ips_map, npc, npp );
+ }else{
+ Ips ips;
+ findPpSite(pats[i],ips,pp_ips_map);
+ }
+ //Has the top operator already been seen */
+ TNode op = pats[i].getOperator();
+ d_pat_cand_gens[pats[i]].first->addPcDispatcher(&handler,i);
+ d_pat_cand_gens[pats[i]].second->addPpDispatcher(&handler,i,i);
+ d_cand_gens[op].addNewTermDispatcher(&handler,i);
+
+ combineMultiPpIpsMap(pp_ips_map,multi_pp_ips_map,handler,i,pats);
+
+ pp_ips_map.clear();
+ }
+
+ for(size_t i = 0; i < patVars.size(); ++i){
+ TNode var = pats[patVars[i]];
+ Assert( var.getKind() == kind::INST_CONSTANT );
+ if( multi_pp_ips_map.find(var) != multi_pp_ips_map.end() ){
+ //The variable appear in another pattern, skip it
+ continue;
+ };
+ d_cand_gen_types[var.getType()].addNewTermDispatcher(&handler,patVars[i]);
}
- d_cand_gens[op].push_back( cg );
+ //take all terms from the uf term db and add to candidate generator
+ if( pats[0].getKind() == kind::INST_CONSTANT ){
+ TypeNode ty = pats[0].getType();
+ rrinst::CandidateGenerator* cg = d_quantEngine->getRRCanGenClasses(ty);
+ cg->reset(Node::null());
+ TNode c;
+ SetNode ele;
+ while( !(c = cg->getNextCandidate()).isNull() ){
+ if( c.getType() == ty ) ele.insert(c);
+ }
+ if( !ele.empty() ){
+ // for(std::vector<Node>::iterator i = db->d_op_map[op].begin(), end = db->d_op_map[op].end(); i != end; ++i){
+ // if(CandidateGenerator::isLegalCandidate(*i)) ele.insert(*i);
+ // }
+ if(Debug.isOn("efficient-e-match-stats")){
+ Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl;
+ }
+ handler.addMonoCandidate(ele, 0);
+ }
+
+ } else if( pats[0].getKind() == kind::NOT && pats[0][0].getKind() == kind::EQUAL){
+ Node cst = NodeManager::currentNM()->mkConst<bool>(false);
+ TNode op = pats[0][0].getOperator();
+ cst = getRepresentative(cst);
+ SetNode ele;
+ eq::EqClassIterator eqc_iter( cst, &((TheoryUF*)d_th)->d_equalityEngine );
+ while( !eqc_iter.isFinished() ){
+ Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter)
+ << std::endl;
+ if( (*eqc_iter).hasOperator() && (*eqc_iter).getOperator() == op ) ele.insert(*eqc_iter);
+ eqc_iter++;
+ }
+ if( !ele.empty() ){
+ if(Debug.isOn("efficient-e-match-stats")){
+ Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl;
+ }
+ handler.addMonoCandidate(ele, 0);
+ }
+
+ } else {
+ Node op = pats[0].getOperator();
+ TermDb* db = d_quantEngine->getTermDatabase();
+ if(db->d_op_map[op].begin() != db->d_op_map[op].end()){
+ SetNode ele;
+ // for(std::vector<Node>::iterator i = db->d_op_map[op].begin(), end = db->d_op_map[op].end(); i != end; ++i){
+ // if(CandidateGenerator::isLegalCandidate(*i)) ele.insert(*i);
+ // }
+ ele.insert(db->d_op_map[op].begin(), db->d_op_map[op].end());
+ if(Debug.isOn("efficient-e-match-stats")){
+ Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl;
+ }
+ handler.addMonoCandidate(ele, 0);
+ }
+ }
Debug("efficient-e-match") << "Done." << std::endl;
}
-void InstantiatorTheoryUf::registerTrigger( Trigger* tr, Node op ){
+void InstantiatorTheoryUf::registerTrigger( theory::inst::Trigger* tr, Node op ){
if( std::find( d_op_triggers[op].begin(), d_op_triggers[op].end(), tr )==d_op_triggers[op].end() ){
d_op_triggers[op].push_back( tr );
}
@@ -506,9 +826,28 @@ void InstantiatorTheoryUf::outputEqClass( const char* c, Node n ){
}
}
-void InstantiatorTheoryUf::outputInvertedPathString( const char* c, InvertedPathString& ips ){
+void InstantiatorTheoryUf::outputIps( const char* c, Ips& ips ){
for( int i=0; i<(int)ips.size(); i++ ){
if( i>0 ){ Debug( c ) << "."; }
Debug( c ) << ips[i].first << "." << ips[i].second;
}
}
+
+rrinst::CandidateGenerator* InstantiatorTheoryUf::getRRCanGenClasses(){
+ uf::TheoryUF* uf = static_cast<uf::TheoryUF*>(getTheory());
+ eq::EqualityEngine* ee =
+ static_cast<eq::EqualityEngine*>(uf->getEqualityEngine());
+ return new eq::rrinst::CandidateGeneratorTheoryEeClasses(ee);
+}
+
+rrinst::CandidateGenerator* InstantiatorTheoryUf::getRRCanGenClass(){
+ uf::TheoryUF* uf = static_cast<uf::TheoryUF*>(getTheory());
+ eq::EqualityEngine* ee =
+ static_cast<eq::EqualityEngine*>(uf->getEqualityEngine());
+ return new eq::rrinst::CandidateGeneratorTheoryEeClass(ee);
+}
+
+
+} /* namespace uf */
+} /* namespace theory */
+} /* namespace cvc4 */
diff --git a/src/theory/uf/theory_uf_instantiator.h b/src/theory/uf/theory_uf_instantiator.h
index 4ddc01986..3a2a5cc0e 100644
--- a/src/theory/uf/theory_uf_instantiator.h
+++ b/src/theory/uf/theory_uf_instantiator.h
@@ -27,6 +27,9 @@
#include "util/stats.h"
#include "theory/uf/theory_uf.h"
+#include "theory/trigger.h"
+#include "util/ntuple.h"
+#include "context/cdqueue.h"
namespace CVC4 {
namespace theory {
@@ -38,6 +41,300 @@ namespace quantifiers{
namespace uf {
class InstantiatorTheoryUf;
+class HandlerPcDispatcher;
+class HandlerPpDispatcher;
+
+typedef std::set<Node> SetNode;
+
+template<class T>
+class CleanUpPointer{
+public:
+ inline void operator()(T** e){
+ delete(*e);
+ };
+};
+
+class EfficientHandler{
+public:
+ typedef std::pair< Node, size_t > MonoCandidate;
+ typedef std::pair< MonoCandidate, MonoCandidate > MultiCandidate;
+ typedef std::pair< SetNode, size_t > MonoCandidates;
+ typedef std::pair< MonoCandidates, MonoCandidates > MultiCandidates;
+private:
+ /* Queue of candidates */
+ typedef context::CDQueue< MonoCandidates *, CleanUpPointer<MonoCandidates> > MonoCandidatesQueue;
+ typedef context::CDQueue< MultiCandidates *, CleanUpPointer<MultiCandidates> > MultiCandidatesQueue;
+ MonoCandidatesQueue d_monoCandidates;
+ typedef uf::SetNode::iterator SetNodeIter;
+ context::CDO<SetNodeIter> d_si;
+ context::CDO<bool> d_mono_not_first;
+
+ MonoCandidatesQueue d_monoCandidatesNewTerm;
+ context::CDO<SetNodeIter> d_si_new_term;
+ context::CDO<bool> d_mono_not_first_new_term;
+
+
+ MultiCandidatesQueue d_multiCandidates;
+ context::CDO<SetNodeIter> d_si1;
+ context::CDO<SetNodeIter> d_si2;
+ context::CDO<bool> d_multi_not_first;
+
+
+ friend class InstantiatorTheoryUf;
+ friend class HandlerPcDispatcher;
+ friend class HandlerPpDispatcher;
+ friend class HandlerNewTermDispatcher;
+protected:
+ void addMonoCandidate(SetNode & s, size_t index){
+ Assert(!s.empty());
+ d_monoCandidates.push(new MonoCandidates(s,index));
+ }
+ void addMonoCandidateNewTerm(SetNode & s, size_t index){
+ Assert(!s.empty());
+ d_monoCandidatesNewTerm.push(new MonoCandidates(s,index));
+ }
+ void addMultiCandidate(SetNode & s1, size_t index1, SetNode & s2, size_t index2){
+ Assert(!s1.empty() && !s2.empty());
+ d_multiCandidates.push(new MultiCandidates(MonoCandidates(s1,index1),
+ MonoCandidates(s2,index2)));
+ }
+public:
+ EfficientHandler(context::Context * c):
+ //false for d_mono_not_first beacause its the default constructor
+ d_monoCandidates(c), d_si(c), d_mono_not_first(c,false),
+ d_monoCandidatesNewTerm(c), d_si_new_term(c),
+ d_mono_not_first_new_term(c,false),
+ d_multiCandidates(c) , d_si1(c), d_si2(c), d_multi_not_first(c,false) {};
+
+ bool getNextMonoCandidate(MonoCandidate & candidate){
+ if(d_monoCandidates.empty()) return false;
+ const MonoCandidates * front = d_monoCandidates.front();
+ SetNodeIter si_tmp;
+ if(!d_mono_not_first){
+ Assert(front->first.begin() != front->first.end());
+ d_mono_not_first = true;
+ si_tmp=front->first.begin();
+ }else{
+ si_tmp = d_si;
+ ++si_tmp;
+ };
+ if(si_tmp != front->first.end()){
+ candidate.first = (*si_tmp);
+ candidate.second = front->second;
+ d_si = si_tmp;
+ Debug("efficienthandler") << "Mono produces " << candidate.first << " for " << candidate.second << std::endl;
+ return true;
+ };
+ d_monoCandidates.pop();
+ d_mono_not_first = false;
+ return getNextMonoCandidate(candidate);
+ };
+
+ bool getNextMonoCandidateNewTerm(MonoCandidate & candidate){
+ if(d_monoCandidatesNewTerm.empty()) return false;
+ const MonoCandidates * front = d_monoCandidatesNewTerm.front();
+ SetNodeIter si_tmp;
+ if(!d_mono_not_first_new_term){
+ Assert(front->first.begin() != front->first.end());
+ d_mono_not_first_new_term = true;
+ si_tmp=front->first.begin();
+ }else{
+ si_tmp = d_si_new_term;
+ ++si_tmp;
+ };
+ if(si_tmp != front->first.end()){
+ candidate.first = (*si_tmp);
+ candidate.second = front->second;
+ d_si_new_term = si_tmp;
+ Debug("efficienthandler") << "Mono produces " << candidate.first << " for " << candidate.second << std::endl;
+ return true;
+ };
+ d_monoCandidatesNewTerm.pop();
+ d_mono_not_first_new_term = false;
+ return getNextMonoCandidateNewTerm(candidate);
+ };
+
+ bool getNextMultiCandidate(MultiCandidate & candidate){
+ if(d_multiCandidates.empty()) return false;
+ const MultiCandidates* front = d_multiCandidates.front();
+ SetNodeIter si1_tmp;
+ SetNodeIter si2_tmp;
+ if(!d_multi_not_first){
+ Assert(front->first.first.begin() != front->first.first.end());
+ Assert(front->second.first.begin() != front->second.first.end());
+ si1_tmp = front->first.first.begin();
+ si2_tmp = front->second.first.begin();
+ }else{
+ si1_tmp = d_si1;
+ si2_tmp = d_si2;
+ ++si2_tmp;
+ };
+ if(si2_tmp != front->second.first.end()){
+ candidate.first.first = *si1_tmp;
+ candidate.first.second = front->first.second;
+ candidate.second.first = *si2_tmp;
+ candidate.second.second = front->second.second;
+ if(!d_multi_not_first){d_si1 = si1_tmp; d_multi_not_first = true; };
+ d_si2 = si2_tmp;
+ Debug("efficienthandler") << "Multi1 produces "
+ << candidate.first.first << " for "
+ << candidate.first.second << " and "
+ << candidate.second.first << " for "
+ << candidate.second.second << " and "
+ << std::endl;
+ return true;
+ }; // end of the second set
+ si2_tmp = front->second.first.begin();
+ ++si1_tmp;
+ if(si1_tmp != front->first.first.end()){
+ candidate.first.first = *si1_tmp;
+ candidate.first.second = front->first.second;
+ candidate.second.first = *si2_tmp;
+ candidate.second.second = front->second.second;
+ d_si1 = si1_tmp;
+ d_si2 = si2_tmp;
+ Debug("efficienthandler") << "Multi2 produces "
+ << candidate.first.first << " for "
+ << candidate.first.second << " and "
+ << candidate.second.first << " for "
+ << candidate.second.second << " and "
+ << std::endl;
+ return true;
+ }; // end of the first set
+ d_multiCandidates.pop();
+ d_multi_not_first = false;
+ return getNextMultiCandidate(candidate);
+ }
+};
+
+class PcDispatcher{
+public:
+ virtual ~PcDispatcher(){};
+ /* Send the node to the dispatcher */
+ virtual void send(SetNode & s) = 0;
+};
+
+
+class HandlerPcDispatcher: public PcDispatcher{
+ EfficientHandler* d_handler;
+ size_t d_index;
+public:
+ HandlerPcDispatcher(EfficientHandler* handler, size_t index):
+ d_handler(handler), d_index(index) {};
+ void send(SetNode & s){
+ d_handler->addMonoCandidate(s,d_index);
+ }
+};
+
+
+/** All the dispatcher that correspond to this node */
+class NodePcDispatcher: public PcDispatcher{
+#ifdef CVC4_DEBUG
+public:
+ Node pat;
+#endif/* CVC4_DEBUG*/
+private:
+ std::vector<HandlerPcDispatcher> d_dis;
+public:
+ void send(SetNode & s){
+ Assert(!s.empty());
+ for(std::vector<HandlerPcDispatcher>::iterator i = d_dis.begin(), end = d_dis.end();
+ i != end; ++i){
+ (*i).send(s);
+ }
+ }
+ void addPcDispatcher(EfficientHandler* handler, size_t index){
+ d_dis.push_back(HandlerPcDispatcher(handler,index));
+ }
+};
+
+
+class HandlerNewTermDispatcher: public PcDispatcher{
+ EfficientHandler* d_handler;
+ size_t d_index;
+public:
+ HandlerNewTermDispatcher(EfficientHandler* handler, size_t index):
+ d_handler(handler), d_index(index) {};
+ void send(SetNode & s){
+ d_handler->addMonoCandidateNewTerm(s,d_index);
+ }
+};
+
+/** All the dispatcher that correspond to this node */
+class NodeNewTermDispatcher: public PcDispatcher{
+#ifdef CVC4_DEBUG
+public:
+ Node pat;
+#endif/* CVC4_DEBUG*/
+private:
+ std::vector<HandlerNewTermDispatcher> d_dis;
+public:
+ void send(SetNode & s){
+ Assert(!s.empty());
+ for(std::vector<HandlerNewTermDispatcher>::iterator i = d_dis.begin(), end = d_dis.end();
+ i != end; ++i){
+ (*i).send(s);
+ }
+ }
+ void addNewTermDispatcher(EfficientHandler* handler, size_t index){
+ d_dis.push_back(HandlerNewTermDispatcher(handler,index));
+ }
+};
+
+class PpDispatcher{
+public:
+ virtual ~PpDispatcher(){};
+ /* Send the node to the dispatcher */
+ virtual void send(SetNode & s1, SetNode & s2, SetNode & sinter) = 0;
+};
+
+
+class HandlerPpDispatcher: public PpDispatcher{
+ EfficientHandler* d_handler;
+ size_t d_index1;
+ size_t d_index2;
+public:
+ HandlerPpDispatcher(EfficientHandler* handler, size_t index1, size_t index2):
+ d_handler(handler), d_index1(index1), d_index2(index2) {};
+ void send(SetNode & s1, SetNode & s2, SetNode & sinter){
+ if(d_index1 == d_index2){
+ if(!sinter.empty())
+ d_handler->addMonoCandidate(sinter,d_index1);
+ }else{
+ d_handler->addMultiCandidate(s1,d_index1,s2,d_index2);
+ }
+ }
+};
+
+
+/** All the dispatcher that correspond to this node */
+class NodePpDispatcher: public PpDispatcher{
+#ifdef CVC4_DEBUG
+public:
+ Node pat1;
+ Node pat2;
+#endif/* CVC4_DEBUG */
+private:
+ std::vector<HandlerPpDispatcher> d_dis;
+ void send(SetNode & s1, SetNode & s2, SetNode & inter){
+ for(std::vector<HandlerPpDispatcher>::iterator i = d_dis.begin(), end = d_dis.end();
+ i != end; ++i){
+ (*i).send(s1,s2,inter);
+ }
+ }
+public:
+ void send(SetNode & s1, SetNode & s2){
+ // can be done in HandlerPpDispatcher lazily
+ Assert(!s1.empty() && !s2.empty());
+ SetNode inter;
+ std::set_intersection( s1.begin(), s1.end(), s2.begin(), s2.end(),
+ std::inserter( inter, inter.begin() ) );
+ send(s1,s2,inter);
+ }
+ void addPpDispatcher(EfficientHandler* handler, size_t index1, size_t index2){
+ d_dis.push_back(HandlerPpDispatcher(handler,index1,index2));
+ }
+};
//equivalence class info
class EqClassInfo
@@ -68,7 +365,7 @@ public:
};
class InstantiatorTheoryUf : public Instantiator{
- friend class ::CVC4::theory::InstMatchGenerator;
+ friend class ::CVC4::theory::inst::InstMatchGenerator;
friend class ::CVC4::theory::quantifiers::TermDb;
protected:
typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap;
@@ -82,7 +379,14 @@ protected:
InstStrategyUserPatterns* d_isup;
public:
InstantiatorTheoryUf(context::Context* c, CVC4::theory::QuantifiersEngine* qe, Theory* th);
- ~InstantiatorTheoryUf() {}
+ ~InstantiatorTheoryUf() {
+ for(std::map< Node, std::pair<NodePcDispatcher*, NodePpDispatcher*> >::iterator
+ i = d_pat_cand_gens.begin(), end = d_pat_cand_gens.end();
+ i != end; i++){
+ delete(i->second.first);
+ delete(i->second.second);
+ }
+ }
/** assertNode method */
void assertNode( Node assertion );
/** Pre-register a term. Done one time for a Node, ever. */
@@ -127,6 +431,9 @@ public:
bool areDisequal( Node a, Node b );
Node getRepresentative( Node a );
Node getInternalRepresentative( Node a );
+ /** general creators of candidate generators */
+ rrinst::CandidateGenerator* getRRCanGenClasses();
+ rrinst::CandidateGenerator* getRRCanGenClass();
/** new node */
void newEqClass( TNode n );
/** merge */
@@ -136,47 +443,66 @@ public:
/** get equivalence class info */
EqClassInfo* getEquivalenceClassInfo( Node n );
EqClassInfo* getOrCreateEquivalenceClassInfo( Node n );
+ typedef std::vector< std::pair< Node, int > > Ips;
+ typedef std::map< Node, std::vector< std::pair< Node, Ips > > > PpIpsMap;
+ typedef std::map< Node, std::vector< triple< size_t, Node, Ips > > > MultiPpIpsMap;
+
private:
- typedef std::vector< std::pair< Node, int > > InvertedPathString;
- typedef std::pair< InvertedPathString, InvertedPathString > IpsPair;
/** Parent/Child Pairs (for efficient E-matching)
So, for example, if we have the pattern f( g( x ) ), then d_pc_pairs[g][f][f( g( x ) )] = { f.0 }.
*/
- std::map< Node, std::map< Node, std::map< Node, std::vector< InvertedPathString > > > > d_pc_pairs;
+ std::map< Node, std::map< Node, std::vector< std::pair< NodePcDispatcher*, Ips > > > > d_pc_pairs;
/** Parent/Parent Pairs (for efficient E-matching) */
- std::map< Node, std::map< Node, std::map< Node, std::vector< IpsPair > > > > d_pp_pairs;
+ std::map< Node, std::map< Node, std::vector< triple< NodePpDispatcher*, Ips, Ips > > > > d_pp_pairs;
+ /** Constants/Child Pairs
+ So, for example, if we have the pattern f( x ) = c, then d_pc_pairs[f][c] = ..., pcdispatcher, ...
+ */
+ //TODO constant in pattern can use the same thing just add an Ips
+ std::map< Node, std::map< Node, NodePcDispatcher* > > d_cc_pairs;
/** list of all candidate generators for each operator */
- std::map< Node, std::vector< CandidateGenerator* > > d_cand_gens;
+ std::map< Node, NodeNewTermDispatcher > d_cand_gens;
+ /** list of all candidate generators for each type */
+ std::map< TypeNode, NodeNewTermDispatcher > d_cand_gen_types;
/** map from patterns to candidate generators */
- std::map< Node, std::vector< CandidateGenerator* > > d_pat_cand_gens;
+ std::map< Node, std::pair<NodePcDispatcher*, NodePpDispatcher*> > d_pat_cand_gens;
/** helper functions */
- void registerPatternElementPairs2( Node opat, Node pat, InvertedPathString& ips,
- std::map< Node, std::vector< std::pair< Node, InvertedPathString > > >& ips_map );
- void registerPatternElementPairs( Node pat );
+ void registerPatternElementPairs2( Node pat, Ips& ips,
+ PpIpsMap & pp_ips_map, NodePcDispatcher* npc);
+ void registerPatternElementPairs( Node pat, PpIpsMap & pp_ips_map,
+ NodePcDispatcher* npc, NodePpDispatcher* npp);
+ /** find the pp-pair between pattern inside multi-pattern*/
+ void combineMultiPpIpsMap(PpIpsMap & pp_ips_map, MultiPpIpsMap & multi_pp_ips_map,
+ EfficientHandler& eh, size_t index2,
+ const std::vector<Node> & pats); //pats for debug
/** compute candidates for pc pairs */
- void computeCandidatesPcPairs( Node a, Node b );
+ void computeCandidatesPcPairs( Node a, EqClassInfo*, Node b, EqClassInfo* );
/** compute candidates for pp pairs */
- void computeCandidatesPpPairs( Node a, Node b );
+ void computeCandidatesPpPairs( Node a, EqClassInfo*, Node b, EqClassInfo* );
+ /** compute candidates for cc pairs */
+ void computeCandidatesConstants( Node a, EqClassInfo*, Node b, EqClassInfo* );
/** collect terms based on inverted path string */
- void collectTermsIps( InvertedPathString& ips, std::vector< Node >& terms, int index = 0 );
- bool collectParentsTermsIps( Node n, Node f, int arg, std::vector< Node >& terms, bool addRep, bool modEq = true );
+ void collectTermsIps( Ips& ips, SetNode& terms, int index);
+ bool collectParentsTermsIps( Node n, Node f, int arg, SetNode& terms, bool addRep, bool modEq = true );
public:
+ void collectTermsIps( Ips& ips, SetNode& terms);
/** Register candidate generator cg for pattern pat. (for use with efficient e-matching)
This request will ensure that calls will be made to cg->addCandidate( n ) for all
ground terms n that are relevant for matching with pat.
*/
- void registerCandidateGenerator( CandidateGenerator* cg, Node pat );
private:
/** triggers */
- std::map< Node, std::vector< Trigger* > > d_op_triggers;
+ std::map< Node, std::vector< inst::Trigger* > > d_op_triggers;
public:
/** register trigger (for eager quantifier instantiation) */
- void registerTrigger( Trigger* tr, Node op );
+ void registerTrigger( inst::Trigger* tr, Node op );
+ void registerEfficientHandler( EfficientHandler& eh, const std::vector<Node> & pat );
+public:
+ void newTerms(SetNode& s);
public:
/** output eq class */
void outputEqClass( const char* c, Node n );
/** output inverted path string */
- void outputInvertedPathString( const char* c, InvertedPathString& ips );
+ void outputIps( const char* c, Ips& ips );
};/* class InstantiatorTheoryUf */
/** equality query object using instantiator theory uf */
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback