: DECLARE_DATATYPES_TOK { PARSER_STATE->checkThatLogicIsSet(); }
{ /* open a scope to keep the UnresolvedTypes contained */
PARSER_STATE->pushScope(); }
+ LPAREN_TOK RPAREN_TOK //TODO: parametric datatypes
LPAREN_TOK ( LPAREN_TOK datatypeDef[dts] RPAREN_TOK )+ RPAREN_TOK
{ PARSER_STATE->popScope();
cmd = new DatatypeDeclarationCommand(PARSER_STATE->mkMutualDatatypeTypes(dts)); }
Expr f, f2;
std::string attr;
Expr attexpr;
- std::vector<Expr> attexprs;
+ std::vector<Expr> patexprs;
std::hash_set<std::string, StringHashFunction> names;
std::vector< std::pair<std::string, Expr> > binders;
}
/* attributed expressions */
| LPAREN_TOK ATTRIBUTE_TOK term[expr, f2]
( attribute[expr, attexpr,attr]
- { if(! attexpr.isNull()) {
- attexprs.push_back(attexpr);
+ { if( attr == ":pattern" && ! attexpr.isNull()) {
+ patexprs.push_back( attexpr );
+ }else if( attr==":axiom" ){
+ //do this?
}
}
)+ RPAREN_TOK
else PARSER_STATE->parseError("Error parsing rewrite rule.");
expr = MK_EXPR( kind, args );
- } else if(! attexprs.empty()) {
- if(attexprs[0].getKind() == kind::INST_PATTERN) {
- expr2 = MK_EXPR(kind::INST_PATTERN_LIST, attexprs);
+ } else if(! patexprs.empty()) {
+ if( !f2.isNull() && f2.getKind()==kind::INST_PATTERN_LIST ){
+ for( size_t i=0; i<f2.getNumChildren(); i++ ){
+ patexprs.push_back( f2[i] );
+ }
}
+ expr2 = MK_EXPR(kind::INST_PATTERN_LIST, patexprs);
+ }else{
+ expr2 = f2;
}
}
/* constants */
rr_inst_match.cpp \
rr_trigger.h \
rr_trigger.cpp \
+ rr_candidate_generator.h \
+ rr_candidate_generator.cpp \
inst_match.h \
inst_match.cpp \
trigger.h \
trigger.cpp \
model.h \
- model.cpp
+ model.cpp \
+ candidate_generator.h \
+ candidate_generator.cpp
nodist_libtheory_la_SOURCES = \
rewriter_tables.h \
static_fact_manager.h \
static_fact_manager.cpp \
theory_arrays_instantiator.h \
- theory_arrays_instantiator.cpp
+ theory_arrays_instantiator.cpp \
+ theory_arrays_model.h \
+ theory_arrays_model.cpp
EXTRA_DIST = kinds
#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"
+#include "theory/rr_candidate_generator.h"
using namespace std;
using namespace CVC4;
}
bool InstantiatorTheoryArrays::areEqual( Node a, Node b ){
- if( hasTerm( a ) && hasTerm( b ) ){
+ if( a==b ){
+ return true;
+ }else if( hasTerm( a ) && hasTerm( b ) ){
return ((TheoryArrays*)d_th)->getEqualityEngine()->areEqual( a, b );
}else{
- return a==b;
+ return false;
}
}
bool InstantiatorTheoryArrays::areDisequal( Node a, Node b ){
- if( hasTerm( a ) && hasTerm( b ) ){
+ if( a==b ){
+ return false;
+ }else if( hasTerm( a ) && hasTerm( b ) ){
return ((TheoryArrays*)d_th)->getEqualityEngine()->areDisequal( a, b, false );
}else{
return false;
}
}
+eq::EqualityEngine* InstantiatorTheoryArrays::getEqualityEngine(){
+ return ((TheoryArrays*)d_th)->getEqualityEngine();
+}
+
+void InstantiatorTheoryArrays::getEquivalenceClass( Node a, std::vector< Node >& eqc ){
+ if( hasTerm( a ) ){
+ a = getEqualityEngine()->getRepresentative( a );
+ eq::EqClassIterator eqc_iter( a, getEqualityEngine() );
+ while( !eqc_iter.isFinished() ){
+ if( std::find( eqc.begin(), eqc.end(), *eqc_iter )==eqc.end() ){
+ eqc.push_back( *eqc_iter );
+ }
+ eqc_iter++;
+ }
+ }
+}
+
rrinst::CandidateGenerator* InstantiatorTheoryArrays::getRRCanGenClasses(){
arrays::TheoryArrays* ar = static_cast<arrays::TheoryArrays *>(getTheory());
eq::EqualityEngine* ee =
bool areEqual( Node a, Node b );
bool areDisequal( Node a, Node b );
Node getRepresentative( Node a );
+ eq::EqualityEngine* getEqualityEngine();
+ void getEquivalenceClass( Node a, std::vector< Node >& eqc );
/** general creators of candidate generators */
rrinst::CandidateGenerator* getRRCanGenClasses();
rrinst::CandidateGenerator* getRRCanGenClass();
--- /dev/null
+/********************* */\r
+/*! \file theory_arrays_model.cpp\r
+ ** \verbatim\r
+ ** Original author: ajreynol\r
+ ** Major contributors: none\r
+ ** Minor contributors (to current version): none\r
+ ** This file is part of the CVC4 prototype.\r
+ ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)\r
+ ** Courant Institute of Mathematical Sciences\r
+ ** New York University\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
+ ** \brief Implementation of theory_arrays_model class\r
+ **/\r
+\r
+#include "theory/theory_engine.h"\r
+#include "theory/arrays/theory_arrays_model.h"\r
+#include "theory/quantifiers/first_order_model.h"\r
+#include "theory/quantifiers/term_database.h"\r
+\r
+using namespace std;\r
+using namespace CVC4;\r
+using namespace CVC4::kind;\r
+using namespace CVC4::context;\r
+using namespace CVC4::theory;\r
+using namespace CVC4::theory::arrays;\r
+\r
+ArrayModel::ArrayModel( Node arr, quantifiers::FirstOrderModel* m ) : d_model( m ), d_arr( arr ){\r
+ Assert( arr.getKind()!=STORE );\r
+ //look at ground assertions\r
+ Node sel = NodeManager::currentNM()->mkNode( SELECT, arr, NodeManager::currentNM()->mkVar( arr.getType().getArrayIndexType() ) );\r
+ Node sel_op = sel.getOperator(); //FIXME: easier way to do this?\r
+ for( size_t i=0; i<d_model->getTermDatabase()->d_op_map[ sel_op ].size(); i++ ){\r
+ Node n = d_model->getTermDatabase()->d_op_map[ sel_op ][i];\r
+ Assert( n.getKind()==SELECT );\r
+ if( m->areEqual( n[0], arr ) ){\r
+ //d_model->getTermDatabase()->computeModelBasisArgAttribute( n );\r
+ //if( !n.getAttribute(NoMatchAttribute()) || n.getAttribute(ModelBasisArgAttribute())==1 ){\r
+ Node r = d_model->getRepresentative( n );\r
+ Node i = d_model->getRepresentative( n[1] );\r
+ d_values[i] = r;\r
+ //}\r
+ }\r
+ }\r
+}\r
+\r
+Node ArrayModel::getValue( Node n ){\r
+ Assert( n.getKind()==SELECT );\r
+ Assert( n[0]==d_arr );\r
+ std::map< Node, Node >::iterator it = d_values.find( n[0] );\r
+ if( it!=d_values.end() ){\r
+ return it->second;\r
+ }else{\r
+ return n;\r
+ //return d_default_value; TODO: guarentee I can return this here\r
+ }\r
+}\r
+\r
+void ArrayModel::setDefaultValue( Node v ){\r
+ d_default_value = v;\r
+}\r
+\r
+Node ArrayModel::getArrayValue(){\r
+ Node curr = d_arr; //TODO: make constant default\r
+ for( std::map< Node, Node >::iterator it = d_values.begin(); it != d_values.end(); ++it ){\r
+ curr = NodeManager::currentNM()->mkNode( STORE, curr, it->first, it->second );\r
+ }\r
+ return curr;\r
+}\r
--- /dev/null
+/********************* */\r
+/*! \file theory_arrays_model.h\r
+ ** \verbatim\r
+ ** Original author: ajreynol\r
+ ** Major contributors: none\r
+ ** Minor contributors (to current version): none\r
+ ** This file is part of the CVC4 prototype.\r
+ ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)\r
+ ** Courant Institute of Mathematical Sciences\r
+ ** New York University\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
+ ** \brief MODEL for theory of arrays\r
+ **/\r
+\r
+\r
+#include "cvc4_private.h"\r
+\r
+#ifndef __CVC4__THEORY_ARRAYS_MODEL_H\r
+#define __CVC4__THEORY_ARRAYS_MODEL_H\r
+\r
+#include "theory/quantifiers_engine.h"\r
+\r
+namespace CVC4 {\r
+namespace theory {\r
+\r
+namespace quantifiers{\r
+ class FirstOrderModel;\r
+}\r
+\r
+namespace arrays {\r
+\r
+class ArrayModel{\r
+protected:\r
+ /** reference to model */\r
+ quantifiers::FirstOrderModel* d_model;\r
+ /** the array this model is for */\r
+ Node d_arr;\r
+public:\r
+ ArrayModel(){}\r
+ ArrayModel( Node arr, quantifiers::FirstOrderModel* m );\r
+ ~ArrayModel() {}\r
+public:\r
+ /** pre-defined values */\r
+ std::map< Node, Node > d_values;\r
+ /** default value */\r
+ Node d_default_value;\r
+ /** get value, return arguments that the value depends on */\r
+ Node getValue( Node n );\r
+ /** set default */\r
+ void setDefaultValue( Node v );\r
+public:\r
+ /** get array value */\r
+ Node getArrayValue();\r
+};/* class ArrayModel */\r
+\r
+}\r
+}\r
+}\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+/********************* */\r
+/*! \file theory_uf_candidate_generator.cpp\r
+ ** \verbatim\r
+ ** Original author: ajreynol\r
+ ** Major contributors: none\r
+ ** Minor contributors (to current version): none\r
+ ** This file is part of the CVC4 prototype.\r
+ ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)\r
+ ** Courant Institute of Mathematical Sciences\r
+ ** New York University\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
+ ** \brief Implementation of theory uf candidate generator class\r
+ **/\r
+\r
+#include "theory/candidate_generator.h"\r
+#include "theory/theory_engine.h"\r
+#include "theory/uf/theory_uf.h"\r
+#include "theory/quantifiers/term_database.h"\r
+#include "theory/inst_match.h"\r
+#include "theory/quantifiers_engine.h"\r
+\r
+using namespace std;\r
+using namespace CVC4;\r
+using namespace CVC4::kind;\r
+using namespace CVC4::context;\r
+using namespace CVC4::theory;\r
+using namespace CVC4::theory::inst;\r
+\r
+bool CandidateGenerator::isLegalCandidate( Node n ){\r
+ return ( !n.getAttribute(NoMatchAttribute()) && ( !Options::current()->cbqi || !n.hasAttribute(InstConstantAttribute()) ) );\r
+}\r
+\r
+void CandidateGeneratorQueue::addCandidate( Node n ) {\r
+ if( isLegalCandidate( n ) ){\r
+ d_candidates.push_back( n );\r
+ }\r
+}\r
+\r
+void CandidateGeneratorQueue::reset( Node eqc ){\r
+ if( d_candidate_index>0 ){\r
+ d_candidates.erase( d_candidates.begin(), d_candidates.begin() + d_candidate_index );\r
+ d_candidate_index = 0;\r
+ }\r
+ if( !eqc.isNull() ){\r
+ d_candidates.push_back( eqc );\r
+ }\r
+}\r
+Node CandidateGeneratorQueue::getNextCandidate(){\r
+ if( d_candidate_index<(int)d_candidates.size() ){\r
+ Node n = d_candidates[d_candidate_index];\r
+ d_candidate_index++;\r
+ return n;\r
+ }else{\r
+ d_candidate_index = 0;\r
+ d_candidates.clear();\r
+ return Node::null();\r
+ }\r
+}\r
+\r
+#if 0\r
+\r
+CandidateGeneratorQE::CandidateGeneratorQE( QuantifiersEngine* qe, Node op ) :\r
+ d_op( op ), d_qe( qe ), d_term_iter( -2 ){\r
+ Assert( !d_op.isNull() );\r
+}\r
+void CandidateGeneratorQE::resetInstantiationRound(){\r
+ d_term_iter_limit = d_qe->getTermDatabase()->d_op_map[d_op].size();\r
+}\r
+\r
+void CandidateGeneratorQE::reset( Node eqc ){\r
+ if( eqc.isNull() ){\r
+ d_term_iter = 0;\r
+ }else{\r
+ //create an equivalence class iterator in eq class eqc\r
+ if( d_qe->getEqualityQuery()->getEngine()->hasTerm( eqc ) ){\r
+ eqc = d_qe->getEqualityQuery()->getEngine()->getRepresentative( eqc );\r
+ d_eqc = eq::EqClassIterator( eqc, d_qe->getEqualityQuery()->getEngine() );\r
+ d_retNode = Node::null();\r
+ }else{\r
+ d_retNode = eqc;\r
+ }\r
+ d_term_iter = -1;\r
+ }\r
+}\r
+\r
+Node CandidateGeneratorQE::getNextCandidate(){\r
+ if( d_term_iter>=0 ){\r
+ //get next candidate term in the uf term database\r
+ while( d_term_iter<d_term_iter_limit ){\r
+ Node n = d_qe->getTermDatabase()->d_op_map[d_op][d_term_iter];\r
+ d_term_iter++;\r
+ if( isLegalCandidate( n ) ){\r
+ return n;\r
+ }\r
+ }\r
+ }else if( d_term_iter==-1 ){\r
+ if( d_retNode.isNull() ){\r
+ //get next candidate term in equivalence class\r
+ while( !d_eqc.isFinished() ){\r
+ Node n = (*d_eqc);\r
+ ++d_eqc;\r
+ if( n.hasOperator() && n.getOperator()==d_op ){\r
+ if( isLegalCandidate( n ) ){\r
+ return n;\r
+ }\r
+ }\r
+ }\r
+ }else{\r
+ Node ret;\r
+ if( d_retNode.hasOperator() && d_retNode.getOperator()==d_op ){\r
+ ret = d_retNode;\r
+ }\r
+ d_term_iter = -2; //done returning matches\r
+ return ret;\r
+ }\r
+ }\r
+ return Node::null();\r
+}\r
+\r
+#else\r
+\r
+\r
+CandidateGeneratorQE::CandidateGeneratorQE( QuantifiersEngine* qe, Node op ) :\r
+ d_op( op ), d_qe( qe ), d_term_iter( -1 ){\r
+ Assert( !d_op.isNull() );\r
+}\r
+void CandidateGeneratorQE::resetInstantiationRound(){\r
+ d_term_iter_limit = d_qe->getTermDatabase()->d_op_map[d_op].size();\r
+}\r
+\r
+void CandidateGeneratorQE::reset( Node eqc ){\r
+ d_term_iter = 0;\r
+ if( eqc.isNull() ){\r
+ d_using_term_db = true;\r
+ }else{\r
+ //create an equivalence class iterator in eq class eqc\r
+ d_eqc.clear();\r
+ d_qe->getEqualityQuery()->getEquivalenceClass( eqc, d_eqc );\r
+ d_using_term_db = false;\r
+ }\r
+}\r
+\r
+Node CandidateGeneratorQE::getNextCandidate(){\r
+ if( d_term_iter>=0 ){\r
+ if( d_using_term_db ){\r
+ //get next candidate term in the uf term database\r
+ while( d_term_iter<d_term_iter_limit ){\r
+ Node n = d_qe->getTermDatabase()->d_op_map[d_op][d_term_iter];\r
+ d_term_iter++;\r
+ if( isLegalCandidate( n ) ){\r
+ return n;\r
+ }\r
+ }\r
+ }else{\r
+ while( d_term_iter<(int)d_eqc.size() ){\r
+ Node n = d_eqc[d_term_iter];\r
+ d_term_iter++;\r
+ if( n.hasOperator() && n.getOperator()==d_op ){\r
+ if( isLegalCandidate( n ) ){\r
+ return n;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return Node::null();\r
+}\r
+\r
+#endif\r
+\r
+//CandidateGeneratorQEDisequal::CandidateGeneratorQEDisequal( QuantifiersEngine* qe, Node eqc ) :\r
+// d_qe( qe ), d_eq_class( eqc ){\r
+// d_eci = NULL;\r
+//}\r
+//void CandidateGeneratorQEDisequal::resetInstantiationRound(){\r
+//\r
+//}\r
+////we will iterate over all terms that are disequal from eqc\r
+//void CandidateGeneratorQEDisequal::reset( Node eqc ){\r
+// //Assert( !eqc.isNull() );\r
+// ////begin iterating over equivalence classes that are disequal from eqc\r
+// //d_eci = d_ith->getEquivalenceClassInfo( eqc );\r
+// //if( d_eci ){\r
+// // d_eqci_iter = d_eci->d_disequal.begin();\r
+// //}\r
+//}\r
+//Node CandidateGeneratorQEDisequal::getNextCandidate(){\r
+// //if( d_eci ){\r
+// // while( d_eqci_iter != d_eci->d_disequal.end() ){\r
+// // if( (*d_eqci_iter).second ){\r
+// // //we have an equivalence class that is disequal from eqc\r
+// // d_cg->reset( (*d_eqci_iter).first );\r
+// // Node n = d_cg->getNextCandidate();\r
+// // //if there is a candidate in this equivalence class, return it\r
+// // if( !n.isNull() ){\r
+// // return n;\r
+// // }\r
+// // }\r
+// // ++d_eqci_iter;\r
+// // }\r
+// //}\r
+// return Node::null();\r
+//}\r
+\r
+\r
+CandidateGeneratorQELitEq::CandidateGeneratorQELitEq( QuantifiersEngine* qe, Node mpat ) :\r
+ d_match_pattern( mpat ), d_qe( qe ){\r
+\r
+}\r
+void CandidateGeneratorQELitEq::resetInstantiationRound(){\r
+\r
+}\r
+void CandidateGeneratorQELitEq::reset( Node eqc ){\r
+ d_eq = eq::EqClassesIterator( d_qe->getEqualityQuery()->getEngine() );\r
+}\r
+Node CandidateGeneratorQELitEq::getNextCandidate(){\r
+ while( d_eq.isFinished() ){\r
+ Node n = (*d_eq);\r
+ ++d_eq;\r
+ if( n.getType()==d_match_pattern[0].getType() ){\r
+ //an equivalence class with the same type as the pattern, return reflexive equality\r
+ return NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), n, n );\r
+ }\r
+ }\r
+ return Node::null();\r
+}\r
+\r
+\r
+CandidateGeneratorQELitDeq::CandidateGeneratorQELitDeq( QuantifiersEngine* qe, Node mpat ) :\r
+ d_match_pattern( mpat ), d_qe( qe ){\r
+\r
+}\r
+void CandidateGeneratorQELitDeq::resetInstantiationRound(){\r
+\r
+}\r
+void CandidateGeneratorQELitDeq::reset( Node eqc ){\r
+ Node false_term = d_qe->getEqualityQuery()->getEngine()->getRepresentative( NodeManager::currentNM()->mkConst<bool>(false) );\r
+ d_eqc_false = eq::EqClassIterator( false_term, d_qe->getEqualityQuery()->getEngine() );\r
+}\r
+Node CandidateGeneratorQELitDeq::getNextCandidate(){\r
+ //get next candidate term in equivalence class\r
+ while( !d_eqc_false.isFinished() ){\r
+ Node n = (*d_eqc_false);\r
+ ++d_eqc_false;\r
+ if( n.getKind()==d_match_pattern.getKind() ){\r
+ //found an iff or equality, try to match it\r
+ //DO_THIS: cache to avoid redundancies?\r
+ //DO_THIS: do we need to try the symmetric equality for n? or will it also exist in the eq class of false?\r
+ return n;\r
+ }\r
+ }\r
+ return Node::null();\r
+}\r
--- /dev/null
+/********************* */\r
+/*! \file candidate_generator.h\r
+ ** \verbatim\r
+ ** Original author: ajreynol\r
+ ** Major contributors: none\r
+ ** Minor contributors (to current version): mdeters\r
+ ** This file is part of the CVC4 prototype.\r
+ ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys)\r
+ ** Courant Institute of Mathematical Sciences\r
+ ** New York University\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
+ ** \brief Theory uf candidate generator\r
+ **/\r
+\r
+#include "cvc4_private.h"\r
+\r
+#ifndef __CVC4__CANDIDATE_GENERATOR_H\r
+#define __CVC4__CANDIDATE_GENERATOR_H\r
+\r
+#include "theory/theory.h"\r
+#include "theory/uf/equality_engine.h"\r
+\r
+namespace CVC4 {\r
+namespace theory {\r
+\r
+class QuantifiersEngine;\r
+\r
+namespace inst {\r
+\r
+/** base class for generating candidates for matching */\r
+class CandidateGenerator {\r
+public:\r
+ CandidateGenerator(){}\r
+ ~CandidateGenerator(){}\r
+\r
+ /** Get candidates functions. These set up a context to get all match candidates.\r
+ cg->reset( eqc );\r
+ do{\r
+ Node cand = cg->getNextCandidate();\r
+ //.......\r
+ }while( !cand.isNull() );\r
+\r
+ eqc is the equivalence class you are searching in\r
+ */\r
+ virtual void reset( Node eqc ) = 0;\r
+ virtual Node getNextCandidate() = 0;\r
+ /** add candidate to list of nodes returned by this generator */\r
+ virtual void addCandidate( Node n ) {}\r
+ /** call this at the beginning of each instantiation round */\r
+ virtual void resetInstantiationRound() = 0;\r
+public:\r
+ /** legal candidate */\r
+ static bool isLegalCandidate( Node n );\r
+};/* class CandidateGenerator */\r
+\r
+/** candidate generator queue (for manual candidate generation) */\r
+class CandidateGeneratorQueue : public CandidateGenerator {\r
+private:\r
+ std::vector< Node > d_candidates;\r
+ int d_candidate_index;\r
+public:\r
+ CandidateGeneratorQueue() : d_candidate_index( 0 ){}\r
+ ~CandidateGeneratorQueue(){}\r
+\r
+ void addCandidate( Node n );\r
+\r
+ void resetInstantiationRound(){}\r
+ void reset( Node eqc );\r
+ Node getNextCandidate();\r
+};/* class CandidateGeneratorQueue */\r
+\r
+class CandidateGeneratorQEDisequal;\r
+\r
+#if 0\r
+\r
+class CandidateGeneratorQE : public CandidateGenerator\r
+{\r
+ friend class CandidateGeneratorQEDisequal;\r
+private:\r
+ //operator you are looking for\r
+ Node d_op;\r
+ //instantiator pointer\r
+ QuantifiersEngine* d_qe;\r
+ //the equality class iterator\r
+ eq::EqClassIterator d_eqc;\r
+ int d_term_iter;\r
+ int d_term_iter_limit;\r
+private:\r
+ Node d_retNode;\r
+public:\r
+ CandidateGeneratorQE( QuantifiersEngine* qe, Node op );\r
+ ~CandidateGeneratorQE(){}\r
+\r
+ void resetInstantiationRound();\r
+ void reset( Node eqc );\r
+ Node getNextCandidate();\r
+};\r
+\r
+#else\r
+\r
+class CandidateGeneratorQE : public CandidateGenerator\r
+{\r
+ friend class CandidateGeneratorQEDisequal;\r
+private:\r
+ //operator you are looking for\r
+ Node d_op;\r
+ //instantiator pointer\r
+ QuantifiersEngine* d_qe;\r
+ //the equality class iterator\r
+ std::vector< Node > d_eqc;\r
+ int d_term_iter;\r
+ int d_term_iter_limit;\r
+ bool d_using_term_db;\r
+public:\r
+ CandidateGeneratorQE( QuantifiersEngine* qe, Node op );\r
+ ~CandidateGeneratorQE(){}\r
+\r
+ void resetInstantiationRound();\r
+ void reset( Node eqc );\r
+ Node getNextCandidate();\r
+};\r
+\r
+#endif\r
+\r
+//class CandidateGeneratorQEDisequal : public CandidateGenerator\r
+//{\r
+//private:\r
+// //equivalence class\r
+// Node d_eq_class;\r
+// //equivalence class info\r
+// EqClassInfo* d_eci;\r
+// //equivalence class iterator\r
+// EqClassInfo::BoolMap::const_iterator d_eqci_iter;\r
+// //instantiator pointer\r
+// QuantifiersEngine* d_qe;\r
+//public:\r
+// CandidateGeneratorQEDisequal( QuantifiersEngine* qe, Node eqc );\r
+// ~CandidateGeneratorQEDisequal(){}\r
+//\r
+// void resetInstantiationRound();\r
+// void reset( Node eqc ); //should be what you want to be disequal from\r
+// Node getNextCandidate();\r
+//};\r
+\r
+class CandidateGeneratorQELitEq : public CandidateGenerator\r
+{\r
+private:\r
+ //the equality classes iterator\r
+ eq::EqClassesIterator d_eq;\r
+ //equality you are trying to match equalities for\r
+ Node d_match_pattern;\r
+ //einstantiator pointer\r
+ QuantifiersEngine* d_qe;\r
+public:\r
+ CandidateGeneratorQELitEq( QuantifiersEngine* qe, Node mpat );\r
+ ~CandidateGeneratorQELitEq(){}\r
+\r
+ void resetInstantiationRound();\r
+ void reset( Node eqc );\r
+ Node getNextCandidate();\r
+};\r
+\r
+class CandidateGeneratorQELitDeq : public CandidateGenerator\r
+{\r
+private:\r
+ //the equality class iterator for false\r
+ eq::EqClassIterator d_eqc_false;\r
+ //equality you are trying to match disequalities for\r
+ Node d_match_pattern;\r
+ //einstantiator pointer\r
+ QuantifiersEngine* d_qe;\r
+public:\r
+ CandidateGeneratorQELitDeq( QuantifiersEngine* qe, Node mpat );\r
+ ~CandidateGeneratorQELitDeq(){}\r
+\r
+ void resetInstantiationRound();\r
+ void reset( Node eqc );\r
+ Node getNextCandidate();\r
+};\r
+\r
+}/* CVC4::theory::inst namespace */\r
+}/* CVC4::theory namespace */\r
+}/* CVC4 namespace */\r
+\r
+#endif /* __CVC4__THEORY_UF_INSTANTIATOR_H */\r
explanation_manager.h \
explanation_manager.cpp \
theory_datatypes_instantiator.h \
- theory_datatypes_instantiator.cpp \
- theory_datatypes_candidate_generator.h
-
+ theory_datatypes_instantiator.cpp
+
EXTRA_DIST = kinds
<< "Rewrite trivial selector " << in
<< std::endl;
return RewriteResponse(REWRITE_DONE, in[0][selectorIndex]);
- } else {
+ }
+ /*
Node gt = in.getType().mkGroundTerm();
TypeNode gtt = gt.getType();
//Assert( gtt.isDatatype() || gtt.isParametricDatatype() );
<< " to distinguished ground term "
<< in.getType().mkGroundTerm() << std::endl;
return RewriteResponse(REWRITE_DONE,gt );
- }
+ */
}
if(in.getKind() == kind::EQUAL && in[0] == in[1]) {
using namespace CVC4::theory;
using namespace CVC4::theory::datatypes;
-const DatatypeConstructor& TheoryDatatypes::getConstructor( Node cons )
-{
- Expr consExpr = cons.toExpr();
- return Datatype::datatypeOf(consExpr)[ Datatype::indexOf(consExpr) ];
-}
-
-Node TheoryDatatypes::getConstructorForSelector( Node sel )
-{
- size_t selIndex = Datatype::indexOf( sel.toExpr() );
- const Datatype& dt = ((DatatypeType)((sel.getType()[0]).toType())).getDatatype();
- for( unsigned i = 0; i<dt.getNumConstructors(); i++ ){
- if( dt[i].getNumArgs()>selIndex &&
- Node::fromExpr( dt[i][selIndex].getSelector() )==sel ){
- return Node::fromExpr( dt[i].getConstructor() );
+void TheoryDatatypes::printModelDebug(){
+ /*
+ //std::cout << "Datatypes model : " << std::endl;
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node eqc = (*eqcs_i);
+ if( eqc.getType().isDatatype() || eqc.getType().isBoolean() ){
+ //std::cout << eqc << " : " << eqc.getType() << " : " << std::endl;
+ //std::cout << " { ";
+ //add terms to model
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ while( !eqc_i.isFinished() ){
+ //std::cout << (*eqc_i) << " ";
+ ++eqc_i;
+ }
+ //std::cout << "}" << std::endl;
+ if( eqc.getType().isDatatype() ){
+ EqcInfo* ei = getOrMakeEqcInfo( eqc );
+ if( ei ){
+ //std::cout << " Instantiated : " << ( ei->d_inst ? "yes" : "no" ) << std::endl;
+ if( ei->d_constructor.get().isNull() ){
+ //std::cout << " Constructor : " << std::endl;
+ //std::cout << " Labels : ";
+ if( hasLabel( ei, eqc ) ){
+ //std::cout << getLabel( eqc );
+ }else{
+ NodeListMap::iterator lbl_i = d_labels.find( eqc );
+ if( lbl_i != d_labels.end() ){
+ NodeList* lbl = (*lbl_i).second;
+ for( NodeList::const_iterator j = lbl->begin(); j != lbl->end(); j++ ){
+ //std::cout << *j << " ";
+ }
+ }
+ }
+ //std::cout << std::endl;
+ }else{
+ //std::cout << " Constructor : " << ei->d_constructor.get() << std::endl;
+ }
+ //std::cout << " Selectors : " << ( ei->d_selectors ? "yes" : "no" ) << std::endl;
+ }
+ }
}
+ ++eqcs_i;
}
- Assert( false );
- return Node::null();
+ */
}
TheoryDatatypes::TheoryDatatypes(Context* c, UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe) :
Theory(THEORY_DATATYPES, c, u, out, valuation, logicInfo, qe),
- d_currAsserts(c),
- d_currEqualities(c),
- d_selectors(c),
- d_reps(c),
- d_selector_eq(c),
- d_equivalence_class(c),
- d_inst_map(c),
d_cycle_check(c),
d_hasSeenCycle(c, false),
- d_labels(c),
- d_ccChannel(this),
- d_cc(c, &d_ccChannel),
- d_unionFind(c),
- d_disequalities(c),
- d_em(c),
- d_cce(&d_cc){
+ d_infer(c),
+ d_infer_exp(c),
+ d_notify( *this ),
+ d_equalityEngine(d_notify, c, "theory::datatypes::TheoryDatatypes"),
+ d_labels( c ),
+ d_conflict( c, false ){
+
+ // The kinds we are treating as function application in congruence
+ d_equalityEngine.addFunctionKind(kind::APPLY_CONSTRUCTOR);
+ d_equalityEngine.addFunctionKind(kind::APPLY_SELECTOR);
+ d_equalityEngine.addFunctionKind(kind::APPLY_TESTER);
}
-
TheoryDatatypes::~TheoryDatatypes() {
}
-void TheoryDatatypes::addSharedTerm(TNode t) {
- Debug("datatypes") << "TheoryDatatypes::addSharedTerm(): "
- << t << endl;
+TheoryDatatypes::EqcInfo* TheoryDatatypes::getOrMakeEqcInfo( Node n, bool doMake ){
+ std::map< Node, EqcInfo* >::iterator eqc_i = d_eqc_info.find( n );
+ if( !hasEqcInfo( n ) ){
+ if( doMake ){
+ //add to labels
+ NodeList* lbl = new(getSatContext()->getCMM()) NodeList( true, getSatContext(), false,
+ ContextMemoryAllocator<TNode>(getSatContext()->getCMM()) );
+ d_labels.insertDataFromContextMemory( n, lbl );
+ EqcInfo* ei;
+ if( eqc_i!=d_eqc_info.end() ){
+ ei = eqc_i->second;
+ }else{
+ ei = new EqcInfo( getSatContext() );
+ d_eqc_info[n] = ei;
+ }
+ if( n.getKind()==APPLY_CONSTRUCTOR ){
+ ei->d_constructor = n;
+ }
+ return ei;
+ }else{
+ return NULL;
+ }
+ }else{
+ return (*eqc_i).second;
+ }
}
-void TheoryDatatypes::notifyCongruent(TNode lhs, TNode rhs) {
- Debug("datatypes") << "TheoryDatatypes::notifyCongruent(): "
- << lhs << " = " << rhs << endl;
- if(!hasConflict()) {
- merge(lhs,rhs);
- }
- Debug("datatypes-debug") << "TheoryDatatypes::notifyCongruent(): done." << endl;
+/** propagate */
+void TheoryDatatypes::propagate(Effort effort){
+
}
-void TheoryDatatypes::preRegisterTerm(TNode n) {
- Debug("datatypes-prereg") << "TheoryDatatypes::preRegisterTerm() " << n << endl;
- if( n.getType().isDatatype() ){
- d_preRegTerms.push_back( n );
+/** propagate */
+bool TheoryDatatypes::propagate(TNode literal){
+ Debug("dt::propagate") << "TheoryDatatypes::propagate(" << literal << ")" << std::endl;
+ // If already in conflict, no more propagation
+ if (d_conflict) {
+ Debug("dt::propagate") << "TheoryDatatypes::propagate(" << literal << "): already in conflict" << std::endl;
+ return false;
}
+ // Propagate out
+ bool ok = d_out->propagate(literal);
+ if (!ok) {
+ d_conflict = true;
+ }
+ return ok;
}
-
-void TheoryDatatypes::presolve() {
- Debug("datatypes") << "TheoryDatatypes::presolve()" << endl;
+/** explain */
+void TheoryDatatypes::explain(TNode literal, std::vector<TNode>& assumptions){
+ Debug("datatypes-explain") << "Explain " << literal << std::endl;
+ bool polarity = literal.getKind() != kind::NOT;
+ TNode atom = polarity ? literal : literal[0];
+ if (atom.getKind() == kind::EQUAL || atom.getKind() == kind::IFF) {
+ d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions);
+ } else {
+ d_equalityEngine.explainPredicate(atom, polarity, assumptions);
+ }
}
-void TheoryDatatypes::check(Effort e) {
+Node TheoryDatatypes::explain( TNode literal ){
+ std::vector< TNode > assumptions;
+ explain( literal, assumptions );
+ if( assumptions.empty() ){
+ return NodeManager::currentNM()->mkConst( true );
+ }else if( assumptions.size()==1 ){
+ return assumptions[0];
+ }else{
+ return NodeManager::currentNM()->mkNode( kind::AND, assumptions );
+ }
+}
- for( int i=0; i<(int)d_currAsserts.size(); i++ ) {
- Debug("datatypes") << "currAsserts[" << i << "] = " << d_currAsserts[i] << endl;
+/** Conflict when merging two constants */
+void TheoryDatatypes::conflict(TNode a, TNode b){
+ if (a.getKind() == kind::CONST_BOOLEAN) {
+ d_conflictNode = explain( a.iffNode(b) );
+ } else {
+ d_conflictNode = explain( a.eqNode(b) );
}
- for( int i=0; i<(int)d_currEqualities.size(); i++ ) {
- Debug("datatypes") << "currEqualities[" << i << "] = " << d_currEqualities[i] << endl;
+ Debug("datatypes-conflict") << "CONFLICT: Eq engine conflict : " << d_conflictNode << std::endl;
+ d_out->conflict( d_conflictNode );
+ d_conflict = true;
+}
+
+/** called when a new equivalance class is created */
+void TheoryDatatypes::eqNotifyNewClass(TNode t){
+ if( t.getKind()==APPLY_CONSTRUCTOR ){
+ getOrMakeEqcInfo( t, true );
}
+}
- while(!done()) {
- Node assertion = get();
- if( Debug.isOn("datatypes") || Debug.isOn("datatypes-split") || Debug.isOn("datatypes-cycles")
- || Debug.isOn("datatypes-debug-pf") || Debug.isOn("datatypes-conflict") ) {
- Notice() << "*** TheoryDatatypes::check(): " << assertion << endl;
- d_currAsserts.push_back( assertion );
- }
+/** called when two equivalance classes will merge */
+void TheoryDatatypes::eqNotifyPreMerge(TNode t1, TNode t2){
- //clear from the derived map
- d_checkMap.clear();
- collectTerms( assertion );
- if( !hasConflict() ){
- if( d_em.hasNode( assertion ) ){
- Debug("datatypes") << "Assertion has already been derived" << endl;
- d_em.assertTrue( assertion );
- } else {
- switch(assertion.getKind()) {
- case kind::EQUAL:
- case kind::IFF:
- addEquality(assertion);
- break;
- case kind::APPLY_TESTER:
- addTester( assertion );
- break;
- case kind::NOT:
- {
- switch( assertion[0].getKind()) {
- case kind::EQUAL:
- case kind::IFF:
- {
- Node a = assertion[0][0];
- Node b = assertion[0][1];
- addDisequality(assertion[0]);
- d_cc.addTerm(a);
- d_cc.addTerm(b);
- if(Debug.isOn("datatypes")) {
- Debug("datatypes") << " a == > " << a << endl
- << " b == > " << b << endl
- << " find(a) == > " << debugFind(a) << endl
- << " find(b) == > " << debugFind(b) << endl;
- }
- // There are two ways to get a conflict here.
- if(!hasConflict()) {
- if(find(a) == find(b)) {
- // We get a conflict this way if we WERE previously watching
- // a, b and were notified previously (via notifyCongruent())
- // that they were congruent.
- Node ccEq = NodeManager::currentNM()->mkNode( EQUAL, assertion[0][0], assertion[0][1] );
- NodeBuilder<> nbc(kind::AND);
- nbc << ccEq << assertion;
- Node contra = nbc;
- d_em.addNode( ccEq, &d_cce );
- d_em.addNodeConflict( contra, Reason::contradiction );
- } else {
- // If we get this far, there should be nothing conflicting due
- // to this disequality.
- Assert(!d_cc.areCongruent(a, b));
- }
- }
- }
- break;
- case kind::APPLY_TESTER:
- addTester( assertion );
- break;
- default:
- Unhandled(assertion[0].getKind());
- break;
+}
+
+/** called when two equivalance classes have merged */
+void TheoryDatatypes::eqNotifyPostMerge(TNode t1, TNode t2){
+ if( t1.getType().isDatatype() ){
+ d_pending_merge.push_back( t1.eqNode( t2 ) );
+ }
+}
+
+void TheoryDatatypes::merge( Node t1, Node t2 ){
+ if( !d_conflict ){
+ Node trep1 = t1;
+ Node trep2 = t2;
+ Debug("datatypes-debug") << "Merge " << t1 << " " << t2 << std::endl;
+ EqcInfo* eqc2 = getOrMakeEqcInfo( t2 );
+ if( eqc2 ){
+ bool checkInst = false;
+ if( !eqc2->d_constructor.get().isNull() ){
+ trep2 = eqc2->d_constructor.get();
+ }
+ EqcInfo* eqc1 = getOrMakeEqcInfo( t1 );
+ if( eqc1 ){
+ if( !eqc1->d_constructor.get().isNull() ){
+ trep1 = eqc1->d_constructor.get();
+ }
+ //check for clash
+ Node cons1 = eqc1->d_constructor;
+ Node cons2 = eqc2->d_constructor;
+ if( !cons1.isNull() && !cons2.isNull() ){
+ Debug("datatypes-debug") << "Constructors : " << cons1 << " " << cons2 << std::endl;
+ if( cons1.getOperator()!=cons2.getOperator() ){
+ //check for clash
+ d_conflictNode = explain( cons1.eqNode( cons2 ) );
+ Debug("datatypes-conflict") << "CONFLICT: Clash conflict : " << d_conflictNode << std::endl;
+ d_out->conflict( d_conflictNode );
+ d_conflict = true;
+ return;
+ }else{
+ //do unification
+ Node unifEq = cons1.eqNode( cons2 );
+ for( int i=0; i<(int)cons1.getNumChildren(); i++ ) {
+ Node eq = cons1[i].eqNode( cons2[i] );
+ d_pending.push_back( eq );
+ d_pending_exp[ eq ] = unifEq;
+ Debug("datatypes-infer") << "DtInfer : " << eq << " by " << unifEq << std::endl;
+ d_infer.push_back( eq );
+ d_infer_exp.push_back( unifEq );
}
}
- break;
- default:
- Unhandled(assertion.getKind());
- break;
}
- }
- }
- //rules to check for collapse, instantiate
- while( !hasConflict() && !d_checkMap.empty() ){
- std::map< Node, bool > temp;
- temp = d_checkMap;
- d_checkMap.clear();
- std::map< Node, bool >::iterator i;
- for( i = temp.begin(); i != temp.end(); i++ ){
- Node n = find( i->first );
- if( temp.find( n )==temp.end() || temp[n] ){
- if( !hasConflict() ) checkInstantiateEqClass( n );
- if( !hasConflict() ) updateSelectors( n );
- temp[n] = false;
+ if( eqc1->d_inst.get().isNull() && !eqc2->d_inst.get().isNull() ){
+ eqc1->d_inst.set( eqc2->d_inst );
}
+ if( cons1.isNull() && !cons2.isNull() ){
+ checkInst = true;
+ eqc1->d_constructor.set( eqc2->d_constructor );
+ }
+ }else{
+ Debug("datatypes-debug") << "No eqc info for " << t1 << ", must create" << std::endl;
+ //just copy the equivalence class information
+ eqc1 = getOrMakeEqcInfo( t1, true );
+ eqc1->d_inst.set( eqc2->d_inst );
+ eqc1->d_constructor.set( eqc2->d_constructor );
}
- }
- //if there is now a conflict
- if( hasConflict() ) {
- Debug("datatypes-conflict") << "Constructing conflict..." << endl;
- for( int i=0; i<(int)d_currAsserts.size(); i++ ) {
- Debug("datatypes-conflict") << "currAsserts[" << i << "] = " << d_currAsserts[i] << endl;
- }
- //Debug("datatypes-conflict") << d_cc << std::endl;
- Node conflict = d_em.getConflict();
- if( Debug.isOn("datatypes") || Debug.isOn("datatypes-split") ||
- Debug.isOn("datatypes-cycles") || Debug.isOn("datatypes-conflict") ){
- Notice() << "Conflict constructed : " << conflict << endl;
- }
- if( conflict.getKind()!=kind::AND ){
- conflict = NodeManager::currentNM()->mkNode(kind::AND, conflict, conflict);
- }
- d_out->conflict(conflict);
- return;
- }
- }
-
- if( e == EFFORT_FULL ) {
- Debug("datatypes-split") << "Check for splits " << e << endl;
- //do splitting
- for( EqLists::iterator i = d_labels.begin(); i != d_labels.end(); i++ ) {
- Node sf = find( (*i).first );
- if( sf.getKind() != APPLY_CONSTRUCTOR ) {
- addTermToLabels( sf );
- EqList* lbl = (sf == (*i).first) ? (*i).second : (*d_labels.find( sf )).second;
- Debug("datatypes-split") << "Check for splitting " << (*i).first
- << ", label size = " << lbl->size() << endl;
- if( lbl->empty() || (*lbl)[ lbl->size()-1 ].getKind() == NOT ) { //there are more than 1 possible constructors for sf
- const Datatype& dt = ((DatatypeType)(sf.getType()).toType()).getDatatype();
- vector< bool > possibleCons;
- possibleCons.resize( dt.getNumConstructors(), true );
- for( EqList::const_iterator j = lbl->begin(); j != lbl->end(); j++ ) {
- TNode leqn = (*j);
- possibleCons[ Datatype::indexOf( leqn[0].getOperator().toExpr() ) ] = false;
- }
- Node cons;
- bool foundSel = false;
- for( unsigned int j=0; j<possibleCons.size(); j++ ) {
- if( !foundSel && possibleCons[j] ) {
- cons = Node::fromExpr( dt[ j ].getConstructor() );
- //if there is a selector, split
- for( unsigned int k=0; k<dt[ j ].getNumArgs(); k++ ) {
- Node s = NodeManager::currentNM()->mkNode( APPLY_SELECTOR, Node::fromExpr( dt[j][k].getSelector() ), sf );
- if( d_selectors.find( s ) != d_selectors.end() ) {
- foundSel = true;
- break;
- }
- }
- }
- }
- if( !foundSel ){
- for( unsigned int j=0; j<possibleCons.size(); j++ ) {
- if( possibleCons[j] && !dt[ j ].isFinite() ) {
- Debug("datatypes") << "Did not find selector for " << sf
- << " and " << dt[ j ].getConstructor() << " is not finite." << endl;
- cons = Node::null();
- break;
- }
- }
- }
- if( !cons.isNull() ) {
- const DatatypeConstructor& cn = getConstructor( cons );
- Debug("datatypes-split") << "*************Split for possible constructor " << cons << endl;
- Node test = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( cn.getTester() ), (*i).first );
- NodeBuilder<> nb(kind::OR);
- nb << test << test.notNode();
- Node lemma = nb;
- Debug("datatypes-split") << "Lemma is " << lemma << endl;
- d_out->lemma( lemma );
+ //merge labels
+ Debug("datatypes-debug") << "Merge labels from " << eqc2 << " " << t2 << std::endl;
+ NodeListMap::iterator lbl_i = d_labels.find( t2 );
+ if( lbl_i != d_labels.end() ){
+ NodeList* lbl = (*lbl_i).second;
+ for( NodeList::const_iterator j = lbl->begin(); j != lbl->end(); ++j ){
+ addTester( *j, eqc1, t1 );
+ if( d_conflict ){
return;
}
}
- } else {
- Debug("datatypes-split") << (*i).first << " is " << sf << endl;
- Assert( sf != (*i).first );
}
- }
- }
- if( Debug.isOn("datatypes") || Debug.isOn("datatypes-split") ) {
- Notice() << "TheoryDatatypes::check(): done" << endl;
- }
-}
-
-bool TheoryDatatypes::checkTester( Node assertion, Node& conflict, unsigned& r ){
- Debug("datatypes") << "Check tester " << assertion << endl;
-
- Node tassertion = ( assertion.getKind() == NOT ) ? assertion[0] : assertion;
- Assert( find( tassertion[0] ) == tassertion[0] );
-
- //if argument is a constructor, it is trivial
- if( tassertion[0].getKind() == APPLY_CONSTRUCTOR ) {
- size_t tIndex = Datatype::indexOf(tassertion.getOperator().toExpr());
- size_t cIndex = Datatype::indexOf(tassertion[0].getOperator().toExpr());
- if( (tIndex==cIndex) == (assertion.getKind() == NOT) ) {
- conflict = assertion;
- r = Reason::idt_tclash;
- }
- return false;
- }
-
- addTermToLabels( tassertion[0] );
- EqList* lbl = (*d_labels.find( tassertion[0] )).second;
- //check if empty label (no possible constructors for term)
- for( EqList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
- Node leqn = (*i);
- Debug("datatypes-debug") << "checking " << leqn << std::endl;
- if( leqn.getKind() == kind::NOT ) {
- if( leqn[0].getOperator() == tassertion.getOperator() ) {
- if( assertion.getKind() != NOT ) {
- conflict = NodeManager::currentNM()->mkNode( AND, leqn, assertion );
- r = Reason::contradiction;
- Debug("datatypes") << "Contradictory labels " << conflict << endl;
+ //merge selectors
+ if( !eqc1->d_selectors && eqc2->d_selectors ){
+ eqc1->d_selectors = true;
+ checkInst = true;
+ }
+ if( checkInst ){
+ checkInstantiate( eqc1, t1 );
+ if( d_conflict ){
+ return;
}
- return false;
}
- }else{
- if( (leqn.getOperator() == tassertion.getOperator()) == (assertion.getKind() == NOT) ) {
- conflict = NodeManager::currentNM()->mkNode( AND, leqn, assertion );
- r = Reason::idt_tclash;
- Debug("datatypes") << "Contradictory labels(2) " << conflict << endl;
+ }
+ //add this to the transitive closure module
+ Node oldRep = trep2;
+ Node newRep = trep1;
+ if( trep1.getKind()!=APPLY_CONSTRUCTOR && trep2.getKind()==APPLY_CONSTRUCTOR ){
+ oldRep = trep1;
+ newRep = trep2;
+ }
+ bool result = d_cycle_check.addEdgeNode( oldRep, newRep );
+ d_hasSeenCycle.set( d_hasSeenCycle.get() || result );
+ Debug("datatypes-cycles") << "DtCyc: Equal " << oldRep << " -> " << newRep << " " << d_hasSeenCycle.get() << endl;
+ if( d_hasSeenCycle.get() ){
+ checkCycles();
+ if( d_conflict ){
+ return;
}
- return false;
}
}
- return true;
}
-void TheoryDatatypes::addTester( Node assertion ){
- Debug("datatypes") << "addTester " << assertion << endl;
+/** called when two equivalence classes are made disequal */
+void TheoryDatatypes::eqNotifyDisequal(TNode t1, TNode t2, TNode reason){
- //preprocess the tester
- Node tassertion = ( assertion.getKind() == NOT ) ? assertion[0] : assertion;
- //add the term into congruence closure consideration
- d_cc.addTerm( tassertion[0] );
+}
- Node assertionRep;
- Node tassertionRep;
- Node tRep = tassertion[0];
- tRep = find( tRep );
- //add label instead for the representative (if it is different)
- if( tRep != tassertion[0] ) {
- //explanation is trivial (do not add to labels)
- if( tRep.getKind()==APPLY_CONSTRUCTOR && assertion.getKind()== kind::APPLY_TESTER &&
- Datatype::indexOf(assertion.getOperator().toExpr())==Datatype::indexOf(tRep.getOperator().toExpr()) ){
- tassertionRep = NodeManager::currentNM()->mkNode( APPLY_TESTER, tassertion.getOperator(), tRep );
- assertionRep = tassertionRep;
- d_em.addNodeAxiom( assertionRep, Reason::idt_taxiom );
- return;
- }else{
- tassertionRep = NodeManager::currentNM()->mkNode( APPLY_TESTER, tassertion.getOperator(), tRep );
- assertionRep = ( assertion.getKind() == NOT ) ? tassertionRep.notNode() : tassertionRep;
- //add explanation
- Node ccEq = NodeManager::currentNM()->mkNode( EQUAL, tRep, tassertion[0] );
- d_em.addNode( ccEq, &d_cce );
- NodeBuilder<> nb2(kind::AND);
- nb2 << assertion << ccEq;
- Node expl = nb2;
- d_em.addNode( assertionRep, expl, Reason::idt_tcong );
- }
- }else{
- tassertionRep = tassertion;
- assertionRep = assertion;
- }
+TheoryDatatypes::EqcInfo::EqcInfo( context::Context* c ) :
+d_inst( c, Node::null() ), d_constructor( c, Node::null() ), d_selectors( c, false ){
- Node conflict;
- unsigned r;
- if( checkTester( assertionRep, conflict, r ) ){
- //it is not redundant/contradictory, add it to labels
- EqLists::iterator lbl_i = d_labels.find( tRep );
- EqList* lbl = (*lbl_i).second;
- lbl->push_back( assertionRep );
- Debug("datatypes") << "Add to labels " << assertionRep << endl;
- if( assertionRep.getKind()==NOT ){
- const Datatype& dt = Datatype::datatypeOf( tassertion.getOperator().toExpr() );
- //we can conclude the final one
- if( lbl->size()==dt.getNumConstructors()-1 ){
- vector< bool > possibleCons;
- possibleCons.resize( dt.getNumConstructors(), true );
- NodeBuilder<> nb(kind::AND);
- for( EqList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
- possibleCons[ Datatype::indexOf( (*i)[0].getOperator().toExpr() ) ] = false;
- nb << (*i);
- }
- int testerIndex = -1;
- for( int i=0; i<(int)possibleCons.size(); i++ ) {
- if( possibleCons[i] ){
- testerIndex = i;
- }
- }
- Assert( testerIndex!=-1 );
- assertionRep = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[unsigned(testerIndex)].getTester() ), tRep );
- Node exp = ( nb.getNumChildren() == 1 ) ? nb.getChild( 0 ) : nb;
- d_em.addNode( assertionRep, exp, Reason::idt_texhaust );
- addTester( assertionRep ); //add stronger statement
- return;
- }
- }
- if( assertionRep.getKind()==APPLY_TESTER ){
- d_checkMap[ tRep ] = true;
- }
- }else if( !conflict.isNull() ){
- d_em.addNodeConflict( conflict, r );
- }
}
-//if only one constructor remaining for t, this function will return it
-Node TheoryDatatypes::getInstantiateCons( Node t ){
- if( t.getKind() != APPLY_CONSTRUCTOR ){
- Assert( t == find( t ) );
- addTermToLabels( t );
- EqLists::iterator lbl_i = d_labels.find( t );
- if( lbl_i!=d_labels.end() ) {
- EqList* lbl = (*lbl_i).second;
- if( !lbl->empty() && (*lbl)[ lbl->size()-1 ].getKind() != NOT ) {
- const Datatype& dt = ((DatatypeType)(t.getType()).toType()).getDatatype();
- size_t testerIndex = Datatype::indexOf( (*lbl)[ lbl->size()-1 ].getOperator().toExpr() );
- return Node::fromExpr( dt[ testerIndex ].getConstructor() );
- }
+bool TheoryDatatypes::hasLabel( EqcInfo* eqc, Node n ){
+ return !eqc->d_constructor.get().isNull() || !getLabel( n ).isNull();
+}
+
+Node TheoryDatatypes::getLabel( Node n ) {
+ NodeListMap::iterator lbl_i = d_labels.find( n );
+ if( lbl_i != d_labels.end() ){
+ NodeList* lbl = (*lbl_i).second;
+ if( !(*lbl).empty() && (*lbl)[ (*lbl).size() - 1 ].getKind()==kind::APPLY_TESTER ){
+ return (*lbl)[ (*lbl).size() - 1 ];
}
}
return Node::null();
}
-void TheoryDatatypes::checkInstantiateEqClass( Node t ) {
- Debug("datatypes") << "TheoryDatatypes::checkInstantiateEqClass() " << t << endl;
- Assert( t == find( t ) );
-
- //if labels were created for t, and t has not been instantiated
- Node cons = getInstantiateCons( t );
- if( !cons.isNull() ){
- //for each term in equivalance class
- initializeEqClass( t );
- EqListN* eqc = (*d_equivalence_class.find( t )).second;
- for( EqListN::const_iterator iter = eqc->begin(); iter != eqc->end(); iter++ ) {
- Node te = *iter;
- Assert( find( te ) == t );
- if( checkInstantiate( te, cons ) ){
- return;
- }
- }
+int TheoryDatatypes::getLabelIndex( EqcInfo* eqc, Node n ){
+ if( !eqc->d_constructor.get().isNull() ){
+ return Datatype::indexOf( eqc->d_constructor.get().getOperator().toExpr() );
+ }else{
+ return Datatype::indexOf( getLabel( n ).getOperator().toExpr() );
}
}
-//pre condition: find( te ) has been proven to be the constructor cons
-//that is, is_[cons]( find( te ) ) is stored in d_labels
-bool TheoryDatatypes::checkInstantiate( Node te, Node cons )
-{
- Debug("datatypes") << "TheoryDatatypes::checkInstantiate() " << te << endl;
- //if term has not yet been instantiated
- if( d_inst_map.find( te ) == d_inst_map.end() ) {
- //find if selectors have been applied to t
- vector< Node > selectorVals;
- selectorVals.push_back( cons );
- bool foundSel = false;
- const DatatypeConstructor& cn = getConstructor( cons );
- for( unsigned int i=0; i<cn.getNumArgs(); i++ ) {
- Node s = NodeManager::currentNM()->mkNode( APPLY_SELECTOR, Node::fromExpr( cn[i].getSelector() ), te );
- if( d_selectors.find( s ) != d_selectors.end() ) {
- foundSel = true;
- s = find( s );
- }
- selectorVals.push_back( s );
- }
- if( cn.isFinite() || foundSel ) {
- d_inst_map[ te ] = true;
- Node val = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, selectorVals );
- //instantiate, add equality
- if( val.getType()!=te.getType() ){ //IDT-param
- Assert( Datatype::datatypeOf( cons.toExpr() ).isParametric() );
- Debug("datatypes-gt") << "Inst: ambiguous type for " << cons << ", ascribe to " << te.getType() << std::endl;
- const DatatypeConstructor& dtc = Datatype::datatypeOf(cons.toExpr())[Datatype::indexOf(cons.toExpr())];
- Debug("datatypes-gt") << "constructor is " << dtc << std::endl;
- Type tspec = dtc.getSpecializedConstructorType(te.getType().toType());
- Debug("datatypes-gt") << "tpec is " << tspec << std::endl;
- selectorVals[0] = NodeManager::currentNM()->mkNode(kind::APPLY_TYPE_ASCRIPTION,
- NodeManager::currentNM()->mkConst(AscriptionType(tspec)), cons);
- val = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, selectorVals );
- }
- if( find( val ) != find( te ) ) {
- //build explaination
- NodeBuilder<> nb(kind::AND);
- //explanation for tester
- Node t = find( te );
- addTermToLabels( t );
- Assert( d_labels.find( t )!=d_labels.end() );
- EqList* lbl = (*d_labels.find( t )).second;
- nb << (*lbl)[ lbl->size()-1 ]; //this should be changed to be tester for te, not t for fine-grained
- //explanation for arguments
- for( unsigned int i=0; i<cn.getNumArgs(); i++ ) {
- Node s = NodeManager::currentNM()->mkNode( APPLY_SELECTOR, Node::fromExpr( cn[i].getSelector() ), te );
- if( selectorVals[i+1]!=s ){
- Node ccEq = NodeManager::currentNM()->mkNode( EQUAL, selectorVals[i+1], s );
- d_em.addNode( ccEq, &d_cce );
- nb << ccEq;
- }else{
- //reflexive for s, if we want idt_inst to be fined grained
- //Node eq = NodeManager::currentNM()->mkNode( EQUAL, s, s );
- //d_em.addNodeAxiom( s, Reason::refl );
- }
- }
- Node jeq = ( nb.getNumChildren() == 1 ) ? nb.getChild( 0 ) : nb;
- Node newEq = NodeManager::currentNM()->mkNode( EQUAL, val, te );
- Debug("datatypes") << "Instantiate: " << newEq << "." << endl;
- d_em.addNode( newEq, jeq, Reason::idt_inst_coarse );
- //collect terms of instantiation term
- collectTerms( val, false );
- //add equality for the instantiation
- addEquality( newEq );
- return true;
+void TheoryDatatypes::getPossibleCons( EqcInfo* eqc, Node n, std::vector< bool >& pcons ){
+ const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype();
+ pcons.resize( dt.getNumConstructors(), !hasLabel( eqc, n ) );
+ if( hasLabel( eqc, n ) ){
+ pcons[ getLabelIndex( eqc, n ) ] = true;
+ }else{
+ NodeListMap::iterator lbl_i = d_labels.find( n );
+ if( lbl_i != d_labels.end() ){
+ NodeList* lbl = (*lbl_i).second;
+ for( NodeList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
+ Assert( (*i).getKind()==NOT );
+ pcons[ Datatype::indexOf( (*i)[0].getOperator().toExpr() ) ] = false;
}
- } else {
- Debug("datatypes") << "Do not Instantiate: infinite constructor, no selectors " << cons << endl;
}
- }else{
- Debug("datatypes") << "Do not Instantiate: " << te << " already instantiated" << endl;
}
- return false;
}
-bool TheoryDatatypes::collapseSelector( Node t ) {
- if( !hasConflict() && t.getKind() == APPLY_SELECTOR ) {
- //collapse constructor
- TypeNode retTyp = t.getType();
- TypeNode typ = t[0].getType();
- Node sel = t.getOperator();
- TypeNode selType = sel.getType();
- Node cons = getConstructorForSelector( sel );
- const DatatypeConstructor& cn = getConstructor( cons );
- Node tmp = find( t[0] );
- Node retNode = t;
- if( tmp.getKind() == APPLY_CONSTRUCTOR ) {
- if( tmp.getOperator() == cons ) {
- Debug("datatypes") << "Applied selector " << t << " to correct constructor." << endl;
- retNode = tmp[ Datatype::indexOf( sel.toExpr() ) ];
- } else {
- Debug("datatypes") << "Applied selector " << t << " to wrong constructor." << endl;
- retNode = retTyp.mkGroundTerm(); //IDT-param
+void TheoryDatatypes::addTester( Node t, EqcInfo* eqc, Node n ){
+ if( !d_conflict ){
+ Debug("datatypes-labels") << "Add tester " << t << " " << eqc << std::endl;
+ bool tpolarity = t.getKind()!=NOT;
+ Node tt = ( t.getKind() == NOT ) ? t[0] : t;
+ int ttindex = Datatype::indexOf( tt.getOperator().toExpr() );
+ Node j, jt;
+ if( hasLabel( eqc, n ) ){
+ int jtindex = getLabelIndex( eqc, n );
+ if( (jtindex==ttindex)!=tpolarity ){
+ d_conflict = true;
+ if( !eqc->d_constructor.get().isNull() ){
+ std::vector< TNode > assumptions;
+ explain( t, assumptions );
+ explain( eqc->d_constructor.get().eqNode( tt[0] ), assumptions );
+ d_conflictNode = NodeManager::currentNM()->mkNode( AND, assumptions );
+ Debug("datatypes-conflict") << "CONFLICT: Tester eq conflict : " << d_conflictNode << std::endl;
+ d_out->conflict( d_conflictNode );
+ return;
+ }else{
+ j = getLabel( n );
+ jt = j;
+ }
+ }else{
+ return;
}
- if( tmp!=t[0] ){
- t = NodeManager::currentNM()->mkNode( APPLY_SELECTOR, t.getOperator(), tmp );
+ }else{
+ NodeListMap::iterator lbl_i = d_labels.find( n );
+ Assert( lbl_i != d_labels.end() );
+ NodeList* lbl = (*lbl_i).second;
+ for( NodeList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
+ Assert( (*i).getKind()==NOT );
+ j = *i;
+ jt = j[0];
+ int jtindex = Datatype::indexOf( jt.getOperator().toExpr() );
+ if( jtindex==ttindex ){
+ if( tpolarity ){ //we are in conflict
+ d_conflict = true;
+ break;
+ }else{ //it is redundant
+ return;
+ }
+ }
}
- Node neq = NodeManager::currentNM()->mkNode( EQUAL, retNode, t );
- d_em.addNodeAxiom( neq, Reason::idt_collapse );
- Debug("datatypes") << "Add collapse equality " << neq << endl;
- addEquality( neq );
- return true;
- } else {
- //see whether we can prove that the selector is applied to the wrong tester
- Node tester = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( cn.getTester() ), tmp );
- Node conflict;
- unsigned r;
- checkTester( tester, conflict, r );
- if( !conflict.isNull() ) {
- Debug("datatypes") << "Applied selector " << t << " to provably wrong constructor. " << retTyp << endl;
- //conflict is c ^ tester, where conflict => false, but we want to say c => ~tester
- //must remove tester from conflict
- if( conflict.getKind()==kind::AND ){
- NodeBuilder<> jt(kind::AND);
- for( int i=0; i<(int)conflict.getNumChildren(); i++ ){
- if( conflict[i]!=tester ){
- jt << conflict[i];
+ if( !d_conflict ){
+ Debug("datatypes-labels") << "Add to labels " << t << std::endl;
+ lbl->push_back( t );
+ const Datatype& dt = ((DatatypeType)(tt[0].getType()).toType()).getDatatype();
+ Debug("datatypes-labels") << "Labels at " << lbl->size() << " / " << dt.getNumConstructors() << std::endl;
+ if( tpolarity ){
+ checkInstantiate( eqc, n );
+ }else{
+ //check if we have reached the maximum number of testers
+ // in this case, add the positive tester
+ if( lbl->size()==dt.getNumConstructors()-1 ){
+ std::vector< bool > pcons;
+ getPossibleCons( eqc, n, pcons );
+ int testerIndex = -1;
+ for( int i=0; i<(int)pcons.size(); i++ ) {
+ if( pcons[i] ){
+ testerIndex = i;
+ break;
+ }
}
+ Assert( testerIndex!=-1 );
+ std::vector< Node > eq_terms;
+ NodeBuilder<> nb(kind::AND);
+ for( NodeList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
+ nb << (*i);
+ if( std::find( eq_terms.begin(), eq_terms.end(), (*i)[0][0] )==eq_terms.end() ){
+ eq_terms.push_back( (*i)[0][0] );
+ if( (*i)[0][0]!=tt[0] ){
+ nb << (*i)[0][0].eqNode( tt[0] );
+ }
+ }
+ }
+ Node t_concl = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[unsigned(testerIndex)].getTester() ), tt[0] );
+ Node t_concl_exp = ( nb.getNumChildren() == 1 ) ? nb.getChild( 0 ) : nb;
+ d_pending.push_back( t_concl );
+ d_pending_exp[ t_concl ] = t_concl_exp;
+ Debug("datatypes-infer") << "DtInfer : " << t_concl << " by " << t_concl_exp << std::endl;
+ d_infer.push_back( t_concl );
+ d_infer_exp.push_back( t_concl_exp );
+ return;
}
- conflict = ( jt.getNumChildren()==1 ) ? jt.getChild( 0 ) : jt;
- }else{
- Assert( conflict==tester );
- conflict = Node::null();
- }
- if( conflict!=tester.notNode() ){
- d_em.addNode( tester.notNode(), conflict, r ); //note that application of r is non-standard (TODO: fix)
}
-
- if( tmp != t[0] ) {
- Node teq = NodeManager::currentNM()->mkNode( EQUAL, tmp, t[0] );
- d_em.addNode( teq, &d_cce );
- Node exp = NodeManager::currentNM()->mkNode( AND, tester.notNode(), teq );
- tester = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( cn.getTester() ), t[0] );
- d_em.addNode( tester.notNode(), exp, Reason::idt_tcong );
- }
- retNode = retTyp.mkGroundTerm(); //IDT-param
- Node neq = NodeManager::currentNM()->mkNode( EQUAL, retNode, t );
-
- d_em.addNode( neq, tester.notNode(), Reason::idt_collapse2 );
- addEquality( neq );
- return true;
}
}
- }
- return false;
-}
-
-//this function will test if each selector whose argument is in the equivalence class of "a" can be collapsed
-void TheoryDatatypes::updateSelectors( Node a ) {
- Debug("datatypes") << "updateSelectors: " << a << endl;
- EqListsN::iterator sel_a_i = d_selector_eq.find( a );
- if( sel_a_i != d_selector_eq.end() ) {
- EqListN* sel_a = (*sel_a_i).second;
- for( EqListN::const_iterator i = sel_a->begin(); i != sel_a->end(); i++ ) {
- Node s = (*i);
- //if a is still a representative, and s has not yet been collapsed
- if( find( a )==a && !d_selectors[s] ){
- Assert( s.getKind()==APPLY_SELECTOR && find( s[0] ) == a );
- if( a != s[0] ) {
- s = NodeManager::currentNM()->mkNode( APPLY_SELECTOR, s.getOperator(), a );
- collectTerms( s, false );
- }
- d_selectors[s] = collapseSelector( s );
- }
+ if( d_conflict ){
+ std::vector< TNode > assumptions;
+ explain( j, assumptions );
+ explain( t, assumptions );
+ explain( jt[0].eqNode( tt[0] ), assumptions );
+ d_conflictNode = NodeManager::currentNM()->mkNode( AND, assumptions );
+ Debug("datatypes-conflict") << "CONFLICT: Tester conflict : " << d_conflictNode << std::endl;
+ d_out->conflict( d_conflictNode );
}
}
}
-void TheoryDatatypes::collectModelInfo( TheoryModel* m ){
- //temporary
- for( int i=0; i<(int)d_preRegTerms.size(); i++ ){
- Node n = find( d_preRegTerms[i] );
- m->assertEquality( n, d_preRegTerms[i], true );
- }
-}
-void TheoryDatatypes::merge(TNode a, TNode b) {
- if( !d_merge_pending.empty() ) {
- //Debug("datatypes") << "Append to merge pending list " << d_merge_pending.size() << endl;
- d_merge_pending[d_merge_pending.size()-1].push_back( pair< Node, Node >( a, b ) );
- return;
- }
- Assert(!hasConflict());
- a = find(a);
- b = find(b);
- if( a == b) {
- return;
- }
- Debug("datatypes") << "Merge "<< a << " " << b << endl;
-
- // make "a" the one with shorter diseqList
- EqLists::iterator deq_ia = d_disequalities.find(a);
- EqLists::iterator deq_ib = d_disequalities.find(b);
+void TheoryDatatypes::check(Effort e) {
- if(deq_ia != d_disequalities.end()) {
- if(deq_ib == d_disequalities.end() ||
- (*deq_ia).second->size() > (*deq_ib).second->size()) {
- TNode tmp = a;
- a = b;
- b = tmp;
- }
- }
+ while(!done() && !d_conflict) {
+ // Get all the assertions
+ Assertion assertion = get();
+ TNode fact = assertion.assertion;
+ Debug("datatypes-assert") << "Assert " << fact << std::endl;
- //if b is a selector, swap a and b
- if( b.getKind() == APPLY_SELECTOR && a.getKind() != APPLY_SELECTOR ) {
- TNode tmp = a;
- a = b;
- b = tmp;
- }
- //make constructors the representatives
- if( a.getKind() == APPLY_CONSTRUCTOR ) {
- TNode tmp = a;
- a = b;
- b = tmp;
- }
- //make sure skolem variable is not representative
- if( b.getKind() == SKOLEM ) {
- TNode tmp = a;
- a = b;
- b = tmp;
+ //reset the maps
+ d_pending.clear();
+ d_pending_exp.clear();
+ //assert the fact
+ assertFact( fact, fact );
+ flushPendingFacts();
}
- //check for clash
- NodeBuilder<> explanation(kind::AND);
- if( a.getKind() == kind::APPLY_CONSTRUCTOR && b.getKind() == kind::APPLY_CONSTRUCTOR
- && a.getOperator()!=b.getOperator() ){
- Node ccEq = NodeManager::currentNM()->mkNode( EQUAL, a, b );
- d_em.addNode( ccEq, &d_cce );
- d_em.addNodeConflict( ccEq, Reason::idt_clash );
- Debug("datatypes") << "Clash " << a << " " << b << endl;
- return;
- }
- Debug("datatypes-debug") << "Done clash" << endl;
-
- Debug("datatypes-ae") << "Set canon: "<< a << " " << b << endl;
- // b becomes the canon of a
- d_unionFind.setCanon(a, b);
- d_reps[a] = false;
- d_reps[b] = true;
-
- //add this to the transitive closure module
- bool result = d_cycle_check.addEdgeNode( a, b );
- d_hasSeenCycle.set( d_hasSeenCycle.get() || result );
- Debug("datatypes-cycles") << "Equal " << a << " -> " << b << " " << d_hasSeenCycle.get() << endl;
- if( d_hasSeenCycle.get() ){
- checkCycles();
- if( hasConflict() ){
- return;
+ if( e == EFFORT_FULL ) {
+ Debug("datatypes-split") << "Check for splits " << e << endl;
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node n = (*eqcs_i);
+ if( n.getType().isDatatype() ){
+ EqcInfo* eqc = getOrMakeEqcInfo( n, true );
+ //if there are more than 1 possible constructors for eqc
+ if( eqc->d_constructor.get().isNull() && !hasLabel( eqc, n ) ) {
+ const Datatype& dt = ((DatatypeType)(n.getType()).toType()).getDatatype();
+ //if only one constructor, then this term must be this constructor
+ if( dt.getNumConstructors()==1 ){
+ Node t = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[0].getTester() ), n );
+ d_pending.push_back( t );
+ d_pending_exp[ t ] = NodeManager::currentNM()->mkConst( true );
+ Debug("datatypes-infer") << "DtInfer : " << t << ", trivial" << std::endl;
+ d_infer.push_back( t );
+ }else{
+ std::vector< bool > pcons;
+ getPossibleCons( eqc, n, pcons );
+ //std::cout << "pcons " << n << " = ";
+ //for( int i=0; i<(int)pcons.size(); i++ ){ //std::cout << pcons[i] << " "; }
+ //std::cout << std::endl;
+ //check if we do not need to resolve the constructor type for this equivalence class.
+ // this is if there are no selectors for this equivalence class, its type is infinite,
+ // and we are not producing a model, then do not split.
+ int consIndex = -1;
+ bool needSplit = true;
+ for( unsigned int j=0; j<pcons.size(); j++ ) {
+ if( pcons[j] ) {
+ if( consIndex==-1 ){
+ consIndex = j;
+ }
+ if( !dt[ j ].isFinite() && !eqc->d_selectors ) {//&& !Options::current()->produceModels && !Options::current()->finiteModelFind ){
+ needSplit = false;
+ }
+ }
+ }
+ if( needSplit && consIndex!=-1 ) {
+ Node test = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[consIndex].getTester() ), n );
+ Debug("datatypes-split") << "*************Split for possible constructor " << test << " for " << n << endl;
+ NodeBuilder<> nb(kind::OR);
+ nb << test << test.notNode();
+ Node lemma = nb;
+ d_out->lemma( lemma );
+ d_out->requirePhase( test, true );
+ return;
+ }else{
+ Debug("datatypes-split") << "Do not split constructor for " << n << std::endl;
+ }
+ }
+ }
+ }
+ ++eqcs_i;
}
- }
- //else{
- // checkCycles();
- // if( hasConflict() ){
- // for( int i=0; i<(int)d_currEqualities.size(); i++ ) {
- // Debug("datatypes-cycles") << "currEqualities[" << i << "] = " << d_currEqualities[i] << endl;
- // }
- // d_cycle_check.debugPrint();
- // Assert( false );
- // }
- //}
- Debug("datatypes-debug") << "Done cycles" << endl;
-
- //merge equivalence classes
- initializeEqClass( b );
- EqListN* eqc_b = (*d_equivalence_class.find( b )).second;
- EqListsN::iterator eqc_a_i = d_equivalence_class.find( a );
- if( eqc_a_i!=d_equivalence_class.end() ){
- EqListN* eqc_a = (*eqc_a_i).second;
- for( EqListN::const_iterator i = eqc_a->begin(); i != eqc_a->end(); i++ ) {
- eqc_b->push_back( *i );
+ flushPendingFacts();
+ if( !d_conflict ){
+ printModelDebug();
}
- }else{
- eqc_b->push_back( a );
}
- //merge selector lists
- EqListsN::iterator sel_a_i = d_selector_eq.find( a );
- if( sel_a_i != d_selector_eq.end() ) {
- EqListsN::iterator sel_b_i = d_selector_eq.find( b );
- EqListN* sel_b;
- if( sel_b_i == d_selector_eq.end() ) {
- sel_b = new(getSatContext()->getCMM()) EqListN(true, getSatContext(), false,
- ContextMemoryAllocator<Node>(getSatContext()->getCMM()));
- d_selector_eq.insertDataFromContextMemory(b, sel_b);
- } else {
- sel_b = (*sel_b_i).second;
- }
- EqListN* sel_a = (*sel_a_i).second;
- for( EqListN::const_iterator i = sel_a->begin(); i != sel_a->end(); i++ ) {
- sel_b->push_back( *i );
- }
- if( !sel_a->empty() ){
- d_checkMap[ b ] = true;
- }
+ if( Debug.isOn("datatypes") || Debug.isOn("datatypes-split") ) {
+ Notice() << "TheoryDatatypes::check(): done" << endl;
}
+}
- deq_ia = d_disequalities.find(a);
- map<TNode, TNode> alreadyDiseqs;
- if(deq_ia != d_disequalities.end()) {
- /*
- * Collecting the disequalities of b, no need to check for conflicts
- * since the representative of b does not change and we check all the things
- * in a's class when we look at the diseq list of find(a)
- */
- EqLists::iterator deq_ib = d_disequalities.find(b);
- if(deq_ib != d_disequalities.end()) {
- EqList* deq = (*deq_ib).second;
- for(EqList::const_iterator j = deq->begin(); j != deq->end(); j++) {
- TNode deqn = *j;
- TNode s = deqn[0];
- TNode t = deqn[1];
- TNode sp = find(s);
- TNode tp = find(t);
- Assert(sp == b || tp == b, "test1");
- if(sp == b) {
- alreadyDiseqs[tp] = deqn;
- } else {
- alreadyDiseqs[sp] = deqn;
- }
- }
- }
-
- /*
- * Looking for conflicts in the a disequality list. Note
- * that at this point a and b are already merged. Also has
- * the side effect that it adds them to the list of b (which
- * became the canonical representative)
- */
- EqList* deqa = (*deq_ia).second;
- for(EqList::const_iterator i = deqa->begin(); i != deqa->end(); i++) {
- TNode deqn = (*i);
- Assert(deqn.getKind() == kind::EQUAL || deqn.getKind() == kind::IFF);
- TNode s = deqn[0];
- TNode t = deqn[1];
-
- TNode sp = find(s);
- TNode tp = find(t);
- if(sp == tp) {
- Debug("datatypes") << "Construct standard conflict " << deqn << " " << sp << endl;
- d_em.addNode( deqn, &d_cce );
- d_em.addNodeConflict( NodeManager::currentNM()->mkNode( kind::AND, deqn, deqn.notNode() ), Reason::contradiction );
- return;
- }
- Assert( sp == b || tp == b, "test2");
-
- // make sure not to add duplicates
- if(sp == b) {
- if(alreadyDiseqs.find(tp) == alreadyDiseqs.end()) {
- appendToDiseqList(b, deqn);
- alreadyDiseqs[tp] = deqn;
- }
- } else {
- if(alreadyDiseqs.find(sp) == alreadyDiseqs.end()) {
- appendToDiseqList(b, deqn);
- alreadyDiseqs[sp] = deqn;
- }
- }
-
- }
+void TheoryDatatypes::assertFact( Node fact, Node exp ){
+ Assert( d_pending_merge.empty() );
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ if (atom.getKind() == kind::EQUAL) {
+ d_equalityEngine.assertEquality( atom, polarity, exp );
+ }else{
+ d_equalityEngine.assertPredicate( atom, polarity, exp );
+ }
+ //do all pending merges
+ int i=0;
+ while( i<(int)d_pending_merge.size() ){
+ Assert( d_pending_merge[i].getKind()==EQUAL || d_pending_merge[i].getKind()==IFF );
+ merge( d_pending_merge[i][0], d_pending_merge[i][1] );
+ i++;
+ }
+ d_pending_merge.clear();
+ //add to tester if applicable
+ if( atom.getKind()==kind::APPLY_TESTER ){
+ Node rep = getRepresentative( atom[0] );
+ EqcInfo* eqc = getOrMakeEqcInfo( rep, true );
+ addTester( fact, eqc, rep );
}
+}
- //merge labels
- EqLists::iterator lbl_i = d_labels.find( a );
- if(lbl_i != d_labels.end()) {
- EqList* lbl = (*lbl_i).second;
- for( EqList::const_iterator i = lbl->begin(); i != lbl->end(); i++ ) {
- addTester( *i );
- if( hasConflict() ) {
- return;
- }
- }
+void TheoryDatatypes::flushPendingFacts(){
+ //also assert the pending facts
+ int i = 0;
+ while( !d_conflict && i<(int)d_pending.size() ){
+ assertFact( d_pending[i], d_pending_exp[ d_pending[i] ] );
+ i++;
}
- Debug("datatypes-debug") << "Done merge labels" << endl;
+ d_pending.clear();
+ d_pending_exp.clear();
+}
- //do unification
- if( a.getKind() == APPLY_CONSTRUCTOR && b.getKind() == APPLY_CONSTRUCTOR &&
- a.getOperator() == b.getOperator() ) {
- Debug("datatypes") << "Unification: " << a << " and " << b << "." << endl;
- for( int i=0; i<(int)a.getNumChildren(); i++ ) {
- if( find( a[i] ) != find( b[i] ) ) {
- Node ccEq = NodeManager::currentNM()->mkNode( EQUAL, a, b );
- Node newEq = NodeManager::currentNM()->mkNode( EQUAL, a[i], b[i] );
- d_em.addNode( ccEq, &d_cce );
- d_em.addNode( newEq, ccEq, Reason::idt_unify );
- addEquality( newEq );
- if( hasConflict() ) {
- return;
- }
- }
+void TheoryDatatypes::preRegisterTerm(TNode n) {
+ Debug("datatypes-prereg") << "TheoryDatatypes::preRegisterTerm() " << n << endl;
+ collectTerms( n );
+ switch (n.getKind()) {
+ case kind::EQUAL:
+ // Add the trigger for equality
+ d_equalityEngine.addTriggerEquality(n);
+ break;
+ case kind::APPLY_TESTER:
+ // Get triggered for both equal and dis-equal
+ d_equalityEngine.addTriggerPredicate(n);
+ break;
+ default:
+ // Maybe it's a predicate
+ if (n.getType().isBoolean()) {
+ // Get triggered for both equal and dis-equal
+ d_equalityEngine.addTriggerPredicate(n);
+ } else {
+ // Function applications/predicates
+ d_equalityEngine.addTerm(n);
}
+ break;
}
+ Assert( d_pending.empty() );
+}
- Debug("datatypes-debug") << "merge(): Done" << endl;
+void TheoryDatatypes::presolve() {
+ Debug("datatypes") << "TheoryDatatypes::presolve()" << endl;
}
-void TheoryDatatypes::addTermToLabels( Node t ) {
- if( t.getType().isDatatype() ) {
- Debug("datatypes-debug") << "Add term to labels " << t << std::endl;
- Node tmp = find( t );
- if( tmp == t ) {
- //add to labels
- EqLists::iterator lbl_i = d_labels.find(t);
- if(lbl_i == d_labels.end()) {
- EqList* lbl = new(getSatContext()->getCMM()) EqList(true, getSatContext(), false,
- ContextMemoryAllocator<TNode>(getSatContext()->getCMM()));
- //if there is only one constructor, then it must be
- const Datatype& dt = ((DatatypeType)(t.getType()).toType()).getDatatype();
- if( dt.getNumConstructors()==1 ){
- Node tester = NodeManager::currentNM()->mkNode( APPLY_TESTER, Node::fromExpr( dt[0].getTester() ), t );
- lbl->push_back( tester );
- d_checkMap[ t ] = true;
- d_em.addNodeAxiom( tester, Reason::idt_texhaust );
- }
- d_labels.insertDataFromContextMemory(tmp, lbl);
- }
- }
- }
+void TheoryDatatypes::addSharedTerm(TNode t) {
+ Debug("datatypes") << "TheoryDatatypes::addSharedTerm(): "
+ << t << endl;
}
-void TheoryDatatypes::initializeEqClass( Node t ) {
- EqListsN::iterator eqc_i = d_equivalence_class.find( t );
- if( eqc_i == d_equivalence_class.end() ) {
- EqListN* eqc = new(getSatContext()->getCMM()) EqListN(true, getSatContext(), false,
- ContextMemoryAllocator<Node>(getSatContext()->getCMM()));
- eqc->push_back( t );
- d_equivalence_class.insertDataFromContextMemory(t, eqc);
- }
+void TheoryDatatypes::collectModelInfo( TheoryModel* m ){
+ printModelDebug();
+ m->assertEqualityEngine( &d_equalityEngine );
}
-void TheoryDatatypes::collectTerms( Node n, bool recurse ) {
- if( recurse ){
- for( int i=0; i<(int)n.getNumChildren(); i++ ) {
- collectTerms( n[i] );
- }
+
+void TheoryDatatypes::collectTerms( Node n ) {
+ for( int i=0; i<(int)n.getNumChildren(); i++ ) {
+ collectTerms( n[i] );
}
if( n.getKind() == APPLY_CONSTRUCTOR ){
for( int i=0; i<(int)n.getNumChildren(); i++ ) {
- Debug("datatypes-cycles") << "Subterm " << n << " -> " << n[i] << endl;
- bool result CVC4_UNUSED = d_cycle_check.addEdgeNode( n, n[i] );
- Assert( !result ); //this should not create any new cycles (relevant terms should have been recorded before)
+ Debug("datatypes-cycles") << "DtCyc: Subterm " << n << " -> " << n[i] << endl;
+ bool result = d_cycle_check.addEdgeNode( n, n[i] );
+ d_hasSeenCycle.set( d_hasSeenCycle.get() || result );
+ }
+ }else if( n.getKind() == APPLY_SELECTOR ){
+ Debug("datatypes") << " Found selector " << n << endl;
+ if (n.getType().isBoolean()) {
+ d_equalityEngine.addTriggerPredicate( n );
+ }else{
+ d_equalityEngine.addTerm( n );
}
- }else{
- if( n.getKind() == APPLY_SELECTOR && d_selectors.find( n ) == d_selectors.end() ) {
- Debug("datatypes") << " Found selector " << n << endl;
- d_selectors[ n ] = false;
- d_cc.addTerm( n );
- Node tmp = find( n[0] );
- d_checkMap[ tmp ] = true;
-
- //add selector to selector eq list
- Debug("datatypes") << " Add selector to list " << tmp << " " << n << endl;
- EqListsN::iterator sel_i = d_selector_eq.find( tmp );
- EqListN* sel;
- if( sel_i == d_selector_eq.end() ) {
- sel = new(getSatContext()->getCMM()) EqListN(true, getSatContext(), false,
- ContextMemoryAllocator<Node>(getSatContext()->getCMM()));
- d_selector_eq.insertDataFromContextMemory(tmp, sel);
- } else {
- sel = (*sel_i).second;
- }
- sel->push_back( n );
+ Node rep = getRepresentative( n[0] );
+ EqcInfo* eqc = getOrMakeEqcInfo( rep, true );
+ if( !eqc->d_selectors ){
+ eqc->d_selectors = true;
+ checkInstantiate( eqc, rep );
}
- addTermToLabels( n );
}
}
-void TheoryDatatypes::appendToDiseqList(TNode of, TNode eq) {
- Debug("datatypes") << "appending " << eq << endl
- << " to diseq list of " << of << endl;
- Assert(eq.getKind() == kind::EQUAL ||
- eq.getKind() == kind::IFF);
- Assert(of == debugFind(of));
- EqLists::iterator deq_i = d_disequalities.find(of);
- EqList* deq;
- if(deq_i == d_disequalities.end()) {
- deq = new(getSatContext()->getCMM()) EqList(true, getSatContext(), false,
- ContextMemoryAllocator<TNode>(getSatContext()->getCMM()));
- d_disequalities.insertDataFromContextMemory(of, deq);
- } else {
- deq = (*deq_i).second;
- }
- deq->push_back(eq);
- //if(Debug.isOn("uf")) {
- // Debug("uf") << " size is now " << deq->size() << endl;
- //}
+Node TheoryDatatypes::getInstantiateCons( Node n, const Datatype& dt, int index ){
+ //add constructor to equivalence class
+ std::vector< Node > children;
+ children.push_back( Node::fromExpr( dt[index].getConstructor() ) );
+ for( int i=0; i<(int)dt[index].getNumArgs(); i++ ){
+ children.push_back( NodeManager::currentNM()->mkNode( APPLY_SELECTOR, Node::fromExpr( dt[index][i].getSelector() ), n ) );
+ }
+ Node n_ic = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
+ collectTerms( n_ic );
+ //add type ascription for ambiguous constructor types
+ if( n_ic.getType()!=n.getType() ){
+ Assert( dt.isParametric() );
+ Debug("datatypes-parametric") << "DtInstantiate: ambiguous type for " << n_ic << ", ascribe to " << n.getType() << std::endl;
+ Debug("datatypes-parametric") << "Constructor is " << dt[index] << std::endl;
+ Type tspec = dt[index].getSpecializedConstructorType(n.getType().toType());
+ Debug("datatypes-parametric") << "Type specification is " << tspec << std::endl;
+ children[0] = NodeManager::currentNM()->mkNode(kind::APPLY_TYPE_ASCRIPTION,
+ NodeManager::currentNM()->mkConst(AscriptionType(tspec)), children[0] );
+ n_ic = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );
+ Assert( n_ic.getType()==n.getType() );
+ }
+ return n_ic;
}
-void TheoryDatatypes::addEquality(TNode eq) {
- Assert(eq.getKind() == kind::EQUAL ||
- eq.getKind() == kind::IFF);
- if( !hasConflict() && find( eq[0] ) != find( eq[1] ) ) {
- Debug("datatypes") << "Add equality " << eq << "." << endl;
- Debug("datatypes-debug-pf") << "Add equality " << eq << "." << endl;
-#if 1 //for delayed merging
- //setup merge pending list
- d_merge_pending.push_back( vector< pair< Node, Node > >() );
-
- d_cce.assertTrue(eq);
- d_cc.addTerm(eq[0]);
- d_cc.addTerm(eq[1]);
-
- //record which nodes are waiting to be merged
- vector< pair< Node, Node > > mp;
- mp.insert( mp.begin(),
- d_merge_pending[d_merge_pending.size()-1].begin(),
- d_merge_pending[d_merge_pending.size()-1].end() );
- d_merge_pending.pop_back();
-
- //merge original nodes
- if( !hasConflict() ) {
- merge( eq[0], eq[1] );
+void TheoryDatatypes::checkInstantiate( EqcInfo* eqc, Node n ){
+ //add constructor to equivalence class if not done so already
+ if( hasLabel( eqc, n ) && eqc->d_inst.get().isNull() ){
+ Node exp;
+ Node tt;
+ if( !eqc->d_constructor.get().isNull() ){
+ exp = NodeManager::currentNM()->mkConst( true );
+ tt = eqc->d_constructor;
}else{
- Debug("datatypes-debug-pf") << "Forget merge " << eq << std::endl;
- }
- //merge nodes waiting to be merged
- for( int i=0; i<(int)mp.size(); i++ ) {
- if( !hasConflict() ) {
- merge( mp[i].first, mp[i].second );
- }else{
- Debug("datatypes-debug-pf") << "Forget merge " << mp[i].first << " " << mp[i].second << std::endl;
+ exp = getLabel( n );
+ tt = exp[0];
+ }
+ int index = getLabelIndex( eqc, n );
+ const Datatype& dt = ((DatatypeType)(tt.getType()).toType()).getDatatype();
+ //must be finite or have a selector
+ if( eqc->d_selectors || dt[ index ].isFinite() ){
+ eqc->d_inst.set( NodeManager::currentNM()->mkConst( true ) );
+ Node tt_cons = getInstantiateCons( tt, dt, index );
+ Node eq;
+ if( tt!=tt_cons ){
+ eq = tt.eqNode( tt_cons );
+ Debug("datatypes-inst") << "DtInstantiate : " << eqc << " " << eq << std::endl;
+ d_pending.push_back( eq );
+ d_pending_exp[ eq ] = exp;
+ Debug("datatypes-infer") << "DtInfer : " << eq << " by " << exp << std::endl;
+ //eqc->d_inst.set( eq );
+ d_infer.push_back( eq );
+ d_infer_exp.push_back( exp );
}
}
-#elif 0
- Debug("datatypes-ae") << "Add equality " << eq << "." << endl;
- Debug("datatypes-ae") << " Find is " << find( eq[0] ) << " = " << find( eq[1] ) << std::endl;
- //merge original nodes
- merge( eq[0], eq[1] );
- d_cce.assertTrue(eq);
- d_cc.addTerm(eq[0]);
- d_cc.addTerm(eq[1]);
-#else
- Debug("datatypes-ae") << "Add equality " << eq << "." << endl;
- Debug("datatypes-ae") << " Find is " << find( eq[0] ) << " = " << find( eq[1] ) << std::endl;
- merge( eq[0], eq[1] );
- if( !hasConflict() ){
- d_cce.assertTrue(eq);
- d_cc.addTerm(eq[0]);
- d_cc.addTerm(eq[1]);
- }
-#endif
- if( Debug.isOn("datatypes") || Debug.isOn("datatypes-cycles") ){
- d_currEqualities.push_back(eq);
- }
}
}
-void TheoryDatatypes::addDisequality(TNode eq) {
- Assert(eq.getKind() == kind::EQUAL ||
- eq.getKind() == kind::IFF);
-
- TNode a = eq[0];
- TNode b = eq[1];
-
- appendToDiseqList(find(a), eq);
- appendToDiseqList(find(b), eq);
-}
-
void TheoryDatatypes::checkCycles() {
- for( BoolMap::iterator i = d_reps.begin(); i != d_reps.end(); i++ ) {
- if( (*i).second ) {
- map< Node, bool > visited;
- NodeBuilder<> explanation(kind::AND);
- if( searchForCycle( (*i).first, (*i).first, visited, explanation ) ) {
- Node cCycle = explanation.getNumChildren() == 1 ? explanation.getChild( 0 ) : explanation;
- d_em.addNodeConflict( cCycle, Reason::idt_cycle_coarse );
- Debug("datatypes") << "Detected cycle for " << (*i).first << endl;
- Debug("datatypes") << "Conflict is " << cCycle << endl;
- return;
- }
+ Debug("datatypes-cycle-check") << "Check cycles" << std::endl;
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node eqc = (*eqcs_i);
+ map< Node, bool > visited;
+ NodeBuilder<> explanation(kind::AND);
+ if( searchForCycle( eqc, eqc, visited, explanation ) ) {
+ d_conflictNode = explanation.getNumChildren() == 1 ? explanation.getChild( 0 ) : explanation;
+ Debug("datatypes-conflict") << "CONFLICT: Cycle conflict : " << d_conflictNode << std::endl;
+ d_out->conflict( d_conflictNode );
+ d_conflict = true;
+ return;
}
+ ++eqcs_i;
}
}
bool TheoryDatatypes::searchForCycle( Node n, Node on,
map< Node, bool >& visited,
NodeBuilder<>& explanation ) {
- //Debug("datatypes") << "Search for cycle " << n << " " << on << endl;
- if( n.getKind() == APPLY_CONSTRUCTOR ) {
- for( int i=0; i<(int)n.getNumChildren(); i++ ) {
- Node nn = find( n[i] );
- if( visited.find( nn ) == visited.end() ) {
- visited[nn] = true;
- if( nn == on || searchForCycle( nn, on, visited, explanation ) ) {
- if( Debug.isOn("datatypes-cycles") && !d_cycle_check.isConnectedNode( n, n[i] ) ){
- Debug("datatypes-cycles") << "Cycle subterm: " << n << " is not -> " << n[i] << "!!!!" << std::endl;
- }
- if( nn != n[i] ) {
- if( Debug.isOn("datatypes-cycles") && !d_cycle_check.isConnectedNode( n[i], nn ) ){
- Debug("datatypes-cycles") << "Cycle equality: " << n[i] << " is not -> " << nn << "!!!!" << std::endl;
+ Debug("datatypes-cycle-check") << "Search for cycle " << n << " " << on << endl;
+ Node ncons;
+ EqcInfo* eqc = getOrMakeEqcInfo( n );
+ if( eqc ){
+ Node ncons = eqc->d_constructor.get();
+ if( !ncons.isNull() ) {
+ for( int i=0; i<(int)ncons.getNumChildren(); i++ ) {
+ Node nn = getRepresentative( ncons[i] );
+ if( visited.find( nn ) == visited.end() ) {
+ visited[nn] = true;
+ if( nn == on || searchForCycle( nn, on, visited, explanation ) ) {
+ if( Debug.isOn("datatypes-cycles") && !d_cycle_check.isConnectedNode( n, ncons[i] ) ){
+ Debug("datatypes-cycles") << "Cycle subterm: " << n << " is not -> " << ncons[i] << "!!!!" << std::endl;
+ }
+ if( nn != ncons[i] ) {
+ if( Debug.isOn("datatypes-cycles") && !d_cycle_check.isConnectedNode( ncons[i], nn ) ){
+ Debug("datatypes-cycles") << "Cycle equality: " << ncons[i] << " is not -> " << nn << "!!!!" << std::endl;
+ }
+ explanation << NodeManager::currentNM()->mkNode( EQUAL, nn, ncons[i] );
}
- Node ccEq = NodeManager::currentNM()->mkNode( EQUAL, nn, n[i] );
- d_em.addNode( ccEq, &d_cce );
- explanation << ccEq;
+ return true;
}
- return true;
}
}
}
}
bool TheoryDatatypes::hasTerm( Node a ){
- return false;
+ return d_equalityEngine.hasTerm( a );
}
bool TheoryDatatypes::areEqual( Node a, Node b ){
- Node ar = find( a );
- Node br = find( b );
- if( ar==br ){
+ if( a==b ){
return true;
- }else if( ar.getKind()==APPLY_CONSTRUCTOR && br.getKind()==APPLY_CONSTRUCTOR &&
- ar.getOperator()==br.getOperator() ){
- //for( int i=0; i<(int)ar.getNumChildren(); i++ ){
- // if( !areEqual( ar[0], br[0] ) ){
- // return false;
- // }
- //}
- //return true;
- return false;
+ }else if( hasTerm( a ) && hasTerm( b ) ){
+ return d_equalityEngine.areEqual( a, b );
}else{
return false;
}
}
bool TheoryDatatypes::areDisequal( Node a, Node b ){
- Node ar = find( a );
- Node br = find( b );
- if( ar==br ){
+ if( a==b ){
return false;
- }else if( ar.getKind()==APPLY_CONSTRUCTOR && br.getKind()==APPLY_CONSTRUCTOR &&
- ar.getOperator()!=br.getOperator() ){
- return true;
+ }else if( hasTerm( a ) && hasTerm( b ) ){
+ return d_equalityEngine.areDisequal( a, b, false );
}else{
- EqLists::iterator deq_ia = d_disequalities.find( ar );
- EqLists::iterator deq_ib = d_disequalities.find( br );
- if( deq_ia!=d_disequalities.end() && deq_ib!=d_disequalities.end() ){
- EqList* deq;
- if( (*deq_ib).second->size()<(*deq_ia).second->size() ){
- deq = (*deq_ib).second;
- }else{
- deq = (*deq_ia).second;
- }
- for(EqList::const_iterator i = deq->begin(); i != deq->end(); i++) {
- TNode deqn = (*i);
- TNode sp = find(deqn[0]);
- TNode tp = find(deqn[1]);
- if( sp==a && tp==b ){
- return true;
- }else if( sp==b && tp==a ){
- return true;
- }
- }
- }
return false;
}
}
Node TheoryDatatypes::getRepresentative( Node a ){
- return find( a );
+ if( hasTerm( a ) ){
+ return d_equalityEngine.getRepresentative( a );
+ }else{
+ return a;
+ }
}
-
#include "util/hash.h"
#include "util/trans_closure.h"
#include "theory/datatypes/explanation_manager.h"
+#include "theory/uf/equality_engine.h"
#include <ext/hash_set>
#include <iostream>
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;
- typedef context::CDChunkList<Node> EqListN;
- typedef context::CDHashMap<Node, EqListN*, NodeHashFunction> EqListsN;
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashMap<Node, NodeList*, NodeHashFunction> NodeListMap;
typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
- /** for debugging */
- context::CDList<Node> d_currAsserts;
- context::CDList<Node> d_currEqualities;
-
- /** keeps track of all selectors we care about, value is whether they have been collapsed */
- BoolMap d_selectors;
- /** keeps track of which nodes are representatives */
- BoolMap d_reps;
- /** map from (representative) nodes to a list of selectors whose arguments are
- in the equivalence class of that node */
- EqListsN d_selector_eq;
- /** map from (representative) nodes to list of nodes in their eq class */
- EqListsN d_equivalence_class;
- /** map from nodes to whether they have been instantiated */
- BoolMap d_inst_map;
/** transitive closure to record equivalence/subterm relation. */
TransitiveClosureNode d_cycle_check;
/** has seen cycle */
context::CDO< bool > d_hasSeenCycle;
- /** get the constructor for the node */
- const DatatypeConstructor& getConstructor( Node cons );
- /** get the constructor for the selector */
- Node getConstructorForSelector( Node sel );
-
- /**
- * map from (representative) nodes to testers that hold for that node
- * for each t, this is either a list of equations of the form
+ /** inferences */
+ NodeList d_infer;
+ NodeList d_infer_exp;
+private:
+ //notification class for equality engine
+ class NotifyClass : public eq::EqualityEngineNotify {
+ TheoryDatatypes& d_dt;
+ public:
+ NotifyClass(TheoryDatatypes& dt): d_dt(dt) {}
+ bool eqNotifyTriggerEquality(TNode equality, bool value) {
+ Debug("dt") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false" )<< ")" << std::endl;
+ if (value) {
+ return d_dt.propagate(equality);
+ } else {
+ // We use only literal triggers so taking not is safe
+ return d_dt.propagate(equality.notNode());
+ }
+ }
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value) {
+ Debug("dt") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false") << ")" << std::endl;
+ if (value) {
+ return d_dt.propagate(predicate);
+ } else {
+ return d_dt.propagate(predicate.notNode());
+ }
+ }
+ bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
+ Debug("dt") << "NotifyClass::eqNotifyTriggerTermMerge(" << tag << ", " << t1 << ", " << t2 << ")" << std::endl;
+ if (value) {
+ return d_dt.propagate(t1.eqNode(t2));
+ } else {
+ return d_dt.propagate(t1.eqNode(t2).notNode());
+ }
+ }
+ void eqNotifyConstantTermMerge(TNode t1, TNode t2) {
+ Debug("dt") << "NotifyClass::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << ")" << std::endl;
+ d_dt.conflict(t1, t2);
+ }
+ void eqNotifyNewClass(TNode t) {
+ Debug("dt") << "NotifyClass::eqNotifyNewClass(" << t << std::endl;
+ d_dt.eqNotifyNewClass(t);
+ }
+ void eqNotifyPreMerge(TNode t1, TNode t2) {
+ Debug("dt") << "NotifyClass::eqNotifyPreMerge(" << t1 << ", " << t2 << std::endl;
+ d_dt.eqNotifyPreMerge(t1, t2);
+ }
+ void eqNotifyPostMerge(TNode t1, TNode t2) {
+ Debug("dt") << "NotifyClass::eqNotifyPostMerge(" << t1 << ", " << t2 << std::endl;
+ d_dt.eqNotifyPostMerge(t1, t2);
+ }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+ Debug("dt") << "NotifyClass::eqNotifyDisequal(" << t1 << ", " << t2 << ", " << reason << std::endl;
+ d_dt.eqNotifyDisequal(t1, t2, reason);
+ }
+ };/* class TheoryDatatypes::NotifyClass */
+private:
+ /** equivalence class info
+ * d_inst is whether the instantiate rule has been applied,
+ * d_constructor is a node of kind APPLY_CONSTRUCTOR (if any) in this equivalence class,
+ * d_selectors is whether a selector has been applied to this equivalence class.
+ */
+ class EqcInfo
+ {
+ public:
+ EqcInfo( context::Context* c );
+ ~EqcInfo(){}
+ //whether we have instantiatied this eqc
+ context::CDO< Node > d_inst;
+ //constructor equal to this eqc
+ context::CDO< Node > d_constructor;
+ //all selectors whose argument is this eqc
+ context::CDO< bool > d_selectors;
+ };
+ /** does eqc of n have a label? */
+ bool hasLabel( EqcInfo* eqc, Node n );
+ /** get the label associated to n */
+ Node getLabel( Node n );
+ /** get the index of the label associated to n */
+ int getLabelIndex( EqcInfo* eqc, Node n );
+ /** get the possible constructors for n */
+ void getPossibleCons( EqcInfo* eqc, Node n, std::vector< bool >& cons );
+private:
+ /** The notify class */
+ NotifyClass d_notify;
+ /** Equaltity engine */
+ eq::EqualityEngine d_equalityEngine;
+ /** information necessary for equivalence classes */
+ std::map< Node, EqcInfo* > d_eqc_info;
+ /** labels for each equivalence class
+ * for each eqc n, d_labels[n] is testers that hold for this equivalence class, either:
+ * a list of equations of the form
* NOT is_[constructor_1]( t )...NOT is_[constructor_n]( t ), each of which are unique testers
* and n is less than the number of possible constructors for t minus one,
* or a list of equations of the form
* NOT is_[constructor_1]( t )...NOT is_[constructor_n]( t ) followed by
* is_[constructor_(n+1)]( t ), each of which is a unique tester.
- */
- EqLists d_labels;
-
- class CongruenceChannel {
- TheoryDatatypes* d_datatypes;
-
- public:
- CongruenceChannel(TheoryDatatypes* datatypes) : d_datatypes(datatypes) {}
- void notifyCongruent(TNode a, TNode b) {
- d_datatypes->notifyCongruent(a, b);
- }
- };/* class CongruenceChannel */
- friend class CongruenceChannel;
-
- /**
- * Output channel connected to the congruence closure module.
- */
- CongruenceChannel d_ccChannel;
-
- /**
- * Instance of the congruence closure module.
- */
- CongruenceClosure<CongruenceChannel, CONGRUENCE_OPERATORS_2 (kind::APPLY_CONSTRUCTOR, kind::APPLY_SELECTOR)> d_cc;
-
- /**
- * Union find for storing the equalities.
- */
- UnionFind<Node, NodeHashFunction> d_unionFind;
-
- /**
- * Received a notification from the congruence closure algorithm that the two nodes
- * a and b have been merged.
- */
- void notifyCongruent(TNode a, TNode b);
-
- /**
- * List of all disequalities this theory has seen.
- * Maintaints the invariant that if a is in the
- * disequality list of b, then b is in that of a.
- * */
- EqLists d_disequalities;
-
- /**
- * information for delayed merging (is this necessary?)
- */
- std::vector< std::vector< std::pair< Node, Node > > > d_merge_pending;
-
- /**
- * Terms that currently need to be checked for collapse/instantiation rules
- */
- std::map< Node, bool > d_checkMap;
-
- /**
- * explanation manager
- */
- ExplanationManager d_em;
-
- /**
- * explanation manager for the congruence closure module
- */
- CongruenceClosureExplainer<CongruenceChannel, CONGRUENCE_OPERATORS_2 (kind::APPLY_CONSTRUCTOR, kind::APPLY_SELECTOR)> d_cce;
-
- //temporary
- std::vector< Node > d_preRegTerms;
+ */
+ NodeListMap d_labels;
+ /** Are we in conflict */
+ context::CDO<bool> d_conflict;
+ /** The conflict node */
+ Node d_conflictNode;
+ /** pending assertions/merges */
+ std::vector< Node > d_pending;
+ std::map< Node, Node > d_pending_exp;
+ std::vector< Node > d_pending_merge;
+private:
+ /** assert fact */
+ void assertFact( Node fact, Node exp );
+ /** flush pending facts */
+ void flushPendingFacts();
+ /** get or make eqc info */
+ EqcInfo* getOrMakeEqcInfo( Node n, bool doMake = false );
+ /** has eqc info */
+ bool hasEqcInfo( Node n ) { return d_labels.find( n )!=d_labels.end(); }
public:
- TheoryDatatypes(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo, QuantifiersEngine* qe);
+ TheoryDatatypes(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation,
+ const LogicInfo& logicInfo, QuantifiersEngine* qe);
~TheoryDatatypes();
+ /** propagate */
+ void propagate(Effort effort);
+ /** propagate */
+ bool propagate(TNode literal);
+ /** explain */
+ void explain( TNode literal, std::vector<TNode>& assumptions );
+ Node explain( TNode literal );
+ /** Conflict when merging two constants */
+ void conflict(TNode a, TNode b);
+ /** called when a new equivalance class is created */
+ void eqNotifyNewClass(TNode t);
+ /** called when two equivalance classes will merge */
+ void eqNotifyPreMerge(TNode t1, TNode t2);
+ /** called when two equivalance classes have merged */
+ void eqNotifyPostMerge(TNode t1, TNode t2);
+ /** called when two equivalence classes are made disequal */
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
+
+ void check(Effort e);
void preRegisterTerm(TNode n);
void presolve();
-
void addSharedTerm(TNode t);
- void check(Effort e);
void collectModelInfo( TheoryModel* m );
void shutdown() { }
std::string identify() const { return std::string("TheoryDatatypes"); }
-
private:
- /* Helper methods */
- bool checkTester( Node assertion, Node& conflict, unsigned& r );
- void addTester( Node assertion );
- Node getInstantiateCons( Node t );
- void checkInstantiateEqClass( Node t );
- bool checkInstantiate( Node te, Node cons );
- bool collapseSelector( Node t );
- void updateSelectors( Node a );
- void addTermToLabels( Node t );
- void initializeEqClass( Node t );
- void collectTerms( Node n, bool recurse = true );
- bool hasConflict();
-
- /* from uf_morgan */
- void merge(TNode a, TNode b);
- inline TNode find(TNode a);
- inline TNode debugFind(TNode a) const;
- void appendToDiseqList(TNode of, TNode eq);
- void addDisequality(TNode eq);
- void addEquality(TNode eq);
-
+ /** add tester to equivalence class info */
+ void addTester( Node t, EqcInfo* eqc, Node n );
+ /** merge the equivalence class info of t1 and t2 */
+ void merge( Node t1, Node t2 );
+ /** for checking if cycles exist */
void checkCycles();
bool searchForCycle( Node n, Node on,
std::map< Node, bool >& visited,
NodeBuilder<>& explanation );
-public:
+ /** collect terms */
+ void collectTerms( Node n );
+ /** get instantiate cons */
+ Node getInstantiateCons( Node n, const Datatype& dt, int index );
+ /** check instantiate */
+ void checkInstantiate( EqcInfo* eqc, Node n );
+ /** debug print */
+ void printModelDebug();
+
+private:
//equality queries
bool hasTerm( Node a );
bool areEqual( Node a, Node b );
bool areDisequal( Node a, Node b );
Node getRepresentative( Node a );
+public:
+ /** get equality engine */
+ eq::EqualityEngine* getEqualityEngine() { return &d_equalityEngine; }
};/* class TheoryDatatypes */
-inline bool TheoryDatatypes::hasConflict() {
- return d_em.hasConflict();
-}
-
-inline TNode TheoryDatatypes::find(TNode a) {
- return d_unionFind.find(a);
-}
-
-inline TNode TheoryDatatypes::debugFind(TNode a) const {
- return d_unionFind.debugFind(a);
-}
-
-
}/* CVC4::theory::datatypes namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
**/
#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"
+#include "theory/rr_candidate_generator.h"
using namespace std;
using namespace CVC4;
if( e<2 ){
return InstStrategy::STATUS_UNFINISHED;
}else if( e==2 ){
+ /*
InstMatch m;
for( int j = 0; j<(int)d_quantEngine->getTermDatabase()->getNumInstantiationConstants( f ); j++ ){
Node i = d_quantEngine->getTermDatabase()->getInstantiationConstant( f, j );
}
}
d_quantEngine->addInstantiation( f, m );
+ */
}
}
return InstStrategy::STATUS_UNKNOWN;
}
Node InstantiatorTheoryDatatypes::getValueFor( Node n ){
+ return n;
+ /* FIXME
//simply get the ground value for n in the current model, if it exists,
// or return an arbitrary ground term otherwise
Debug("quant-datatypes-debug") << "get value for " << n << std::endl;
}
}
}
+ */
}
InstantiatorTheoryDatatypes::Statistics::Statistics():
}
bool InstantiatorTheoryDatatypes::hasTerm( Node a ){
- return ((TheoryDatatypes*)d_th)->hasTerm( a );
+ return ((TheoryDatatypes*)d_th)->getEqualityEngine()->hasTerm( a );
}
bool InstantiatorTheoryDatatypes::areEqual( Node a, Node b ){
- return ((TheoryDatatypes*)d_th)->areEqual( a, b );
+ if( a==b ){
+ return true;
+ }else if( hasTerm( a ) && hasTerm( b ) ){
+ return ((TheoryDatatypes*)d_th)->getEqualityEngine()->areEqual( a, b );
+ }else{
+ return false;
+ }
}
bool InstantiatorTheoryDatatypes::areDisequal( Node a, Node b ){
- return ((TheoryDatatypes*)d_th)->areDisequal( a, b );
+ if( a==b ){
+ return false;
+ }else if( hasTerm( a ) && hasTerm( b ) ){
+ return ((TheoryDatatypes*)d_th)->getEqualityEngine()->areDisequal( a, b, false );
+ }else{
+ return false;
+ }
}
Node InstantiatorTheoryDatatypes::getRepresentative( Node a ){
- return ((TheoryDatatypes*)d_th)->getRepresentative( a );
+ if( hasTerm( a ) ){
+ return ((TheoryDatatypes*)d_th)->getEqualityEngine()->getRepresentative( a );
+ }else{
+ return a;
+ }
+}
+
+eq::EqualityEngine* InstantiatorTheoryDatatypes::getEqualityEngine(){
+ return &((TheoryDatatypes*)d_th)->d_equalityEngine;
+}
+
+void InstantiatorTheoryDatatypes::getEquivalenceClass( Node a, std::vector< Node >& eqc ){
+ if( hasTerm( a ) ){
+ a = getEqualityEngine()->getRepresentative( a );
+ eq::EqClassIterator eqc_iter( a, getEqualityEngine() );
+ while( !eqc_iter.isFinished() ){
+ if( std::find( eqc.begin(), eqc.end(), *eqc_iter )==eqc.end() ){
+ eqc.push_back( *eqc_iter );
+ }
+ eqc_iter++;
+ }
+ }
}
CVC4::theory::rrinst::CandidateGenerator* InstantiatorTheoryDatatypes::getRRCanGenClass(){
- TheoryDatatypes* th = static_cast<TheoryDatatypes *>(getTheory());
- return new datatypes::rrinst::CandidateGeneratorTheoryClass(th);
+ datatypes::TheoryDatatypes* dt = static_cast<datatypes::TheoryDatatypes*>(getTheory());
+ eq::EqualityEngine* ee =
+ static_cast<eq::EqualityEngine*>(dt->getEqualityEngine());
+ return new eq::rrinst::CandidateGeneratorTheoryEeClass(ee);
}
bool areEqual( Node a, Node b );
bool areDisequal( Node a, Node b );
Node getRepresentative( Node a );
+ eq::EqualityEngine* getEqualityEngine();
+ void getEquivalenceClass( Node a, std::vector< Node >& eqc );
/** general creators of candidate generators */
CVC4::theory::rrinst::CandidateGenerator* getRRCanGenClass();
};/* class InstantiatiorTheoryDatatypes */
#include "theory/inst_match.h"
#include "theory/theory_engine.h"
#include "theory/quantifiers_engine.h"
+#include "theory/candidate_generator.h"
#include "theory/uf/theory_uf_instantiator.h"
-#include "theory/uf/theory_uf_candidate_generator.h"
#include "theory/uf/equality_engine.h"
#include "theory/quantifiers/model_engine.h"
#include "theory/quantifiers/term_database.h"
using namespace CVC4::theory::inst;
-bool CandidateGenerator::isLegalCandidate( Node n ){
- return ( !n.getAttribute(NoMatchAttribute()) && ( !Options::current()->cbqi || !n.hasAttribute(InstConstantAttribute()) ) ) ||
- ( Options::current()->finiteModelFind && n.hasAttribute(ModelBasisArgAttribute()) && n.getAttribute(ModelBasisArgAttribute())==1 );
-}
-
-void CandidateGeneratorQueue::addCandidate( Node n ) {
- if( isLegalCandidate( n ) ){
- d_candidates.push_back( n );
- }
-}
-
-void CandidateGeneratorQueue::reset( Node eqc ){
- if( d_candidate_index>0 ){
- d_candidates.erase( d_candidates.begin(), d_candidates.begin() + d_candidate_index );
- d_candidate_index = 0;
- }
- if( !eqc.isNull() ){
- d_candidates.push_back( eqc );
- }
-}
-Node CandidateGeneratorQueue::getNextCandidate(){
- if( d_candidate_index<(int)d_candidates.size() ){
- Node n = d_candidates[d_candidate_index];
- d_candidate_index++;
- return n;
- }else{
- d_candidate_index = 0;
- d_candidates.clear();
- return Node::null();
- }
-}
-
InstMatch::InstMatch() {
}
void InstMatch::makeComplete( Node f, QuantifiersEngine* qe ){
for( int i=0; i<(int)qe->getTermDatabase()->d_inst_constants[f].size(); i++ ){
- if( d_map.find( qe->getTermDatabase()->d_inst_constants[f][i] )==d_map.end() ){
- d_map[ qe->getTermDatabase()->d_inst_constants[f][i] ] = qe->getTermDatabase()->getFreeVariableForInstConstant( qe->getTermDatabase()->d_inst_constants[f][i] );
+ Node ic = qe->getTermDatabase()->d_inst_constants[f][i];
+ if( d_map.find( ic )==d_map.end() ){
+ d_map[ ic ] = qe->getTermDatabase()->getFreeVariableForInstConstant( ic );
}
}
}
void InstMatch::makeInternal( QuantifiersEngine* qe ){
- for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){
- if( Options::current()->cbqi && it->second.hasAttribute(InstConstantAttribute()) ){
- d_map[ it->first ] = qe->getEqualityQuery()->getInternalRepresentative( it->second );
- if( Options::current()->cbqi && it->second.hasAttribute(InstConstantAttribute()) ){
- d_map[ it->first ] = qe->getTermDatabase()->getFreeVariableForInstConstant( it->first );
+ if( Options::current()->cbqi ){
+ for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){
+ if( it->second.hasAttribute(InstConstantAttribute()) ){
+ d_map[ it->first ] = qe->getEqualityQuery()->getInternalRepresentative( it->second );
+ if( it->second.hasAttribute(InstConstantAttribute()) ){
+ d_map[ it->first ] = qe->getTermDatabase()->getFreeVariableForInstConstant( it->first );
+ }
}
}
}
}
if( modEq ){
//check modulo equality if any other instantiation match exists
- if( ((uf::TheoryUF*)qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine()->hasTerm( n ) ){
- eq::EqClassIterator eqc( ((uf::TheoryUF*)qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine()->getRepresentative( n ),
- ((uf::TheoryUF*)qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine() );
+ if( qe->getEqualityQuery()->getEngine()->hasTerm( n ) ){
+ eq::EqClassIterator eqc( qe->getEqualityQuery()->getEngine()->getRepresentative( n ),
+ qe->getEqualityQuery()->getEngine() );
while( !eqc.isFinished() ){
Node en = (*eqc);
if( en!=n ){
//we will be producing candidates via literal matching heuristics
if( d_pattern.getKind()!=NOT ){
//candidates will be all equalities
- d_cg = new uf::inst::CandidateGeneratorTheoryUfLitEq( ith, d_match_pattern );
+ d_cg = new inst::CandidateGeneratorQELitEq( qe, d_match_pattern );
}else{
//candidates will be all disequalities
- d_cg = new uf::inst::CandidateGeneratorTheoryUfLitDeq( ith, d_match_pattern );
+ d_cg = new inst::CandidateGeneratorQELitDeq( qe, d_match_pattern );
}
}else if( d_pattern.getKind()==EQUAL || d_pattern.getKind()==IFF || d_pattern.getKind()==NOT ){
Assert( d_matchPolicy==MATCH_GEN_DEFAULT );
}else{
Assert( Trigger::isAtomicTrigger( d_match_pattern ) );
//we are matching only in a particular equivalence class
- d_cg = new uf::inst::CandidateGeneratorTheoryUf( ith, d_match_pattern.getOperator() );
+ d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() );
//store the equivalence class that we will call d_cg->reset( ... ) on
d_eq_class = d_pattern[1];
}
//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() );
+ d_cg = new inst::CandidateGeneratorQE( qe, d_match_pattern.getOperator() );
}else{
d_cg = new CandidateGeneratorQueue;
if( !Trigger::getPatternArithmetic( d_match_pattern.getAttribute(InstConstantAttribute()), d_match_pattern, d_arith_coeffs ) ){
}
if( modEq ){
//check modulo equality for other possible instantiations
- if( ((uf::TheoryUF*)qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine()->hasTerm( n ) ){
- eq::EqClassIterator eqc( qe->getEqualityQuery()->getRepresentative( n ),
- ((uf::TheoryUF*)qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine() );
+ if( qe->getEqualityQuery()->getEngine()->hasTerm( n ) ){
+ eq::EqClassIterator eqc( qe->getEqualityQuery()->getEngine()->getRepresentative( n ),
+ qe->getEqualityQuery()->getEngine() );
while( !eqc.isFinished() ){
Node en = (*eqc);
if( en!=n ){
#ifndef __CVC4__INST_MATCH_H
#define __CVC4__INST_MATCH_H
-#include "theory/theory.h"
#include "util/hash.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/candidate_generator.h"
//#define USE_EFFICIENT_E_MATCHING
namespace inst {
-class CandidateGenerator
-{
-public:
- CandidateGenerator(){}
- ~CandidateGenerator(){}
-
- /** Get candidates functions. These set up a context to get all match candidates.
- cg->reset( eqc );
- do{
- Node cand = cg->getNextCandidate();
- //.......
- }while( !cand.isNull() );
-
- eqc is the equivalence class you are searching in
- */
- virtual void reset( Node eqc ) = 0;
- virtual Node getNextCandidate() = 0;
- /** add candidate to list of nodes returned by this generator */
- virtual void addCandidate( Node n ) {}
- /** call this at the beginning of each instantiation round */
- virtual void resetInstantiationRound() = 0;
-public:
- /** legal candidate */
- static bool isLegalCandidate( Node n );
-};/* class CandidateGenerator */
-
-/** candidate generator queue (for manual candidate generation) */
-class CandidateGeneratorQueue : public CandidateGenerator {
-private:
- std::vector< Node > d_candidates;
- int d_candidate_index;
-public:
- CandidateGeneratorQueue() : d_candidate_index( 0 ){}
- ~CandidateGeneratorQueue(){}
-
- void addCandidate( Node n );
-
- void resetInstantiationRound(){}
- void reset( Node eqc );
- Node getNextCandidate();
-};/* class CandidateGeneratorQueue */
-
class EqualityQuery {
public:
EqualityQuery(){}
not contain instantiation constants, if such a term exists.
*/
virtual Node getInternalRepresentative( Node a ) = 0;
+ /** get the equality engine associated with this query */
+ virtual eq::EqualityEngine* getEngine() = 0;
+ /** get the equivalence class of a */
+ virtual void getEquivalenceClass( Node a, std::vector< Node >& eqc ) = 0;
};/* class EqualityQuery */
/** basic class defining an instantiation */
+++ /dev/null
-/********************* */
-/*! \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__INST_MATCH_IMPL_H
-#define __CVC4__INST_MATCH_IMPL_H
-
-#include "theory/inst_match.h"
-#include "theory/theory_engine.h"
-#include "theory/quantifiers_engine.h"
-#include "theory/uf/theory_uf_instantiator.h"
-#include "theory/uf/theory_uf_candidate_generator.h"
-#include "theory/uf/equality_engine.h"
-
-namespace CVC4 {
-namespace theory {
-
-template<bool modEq>
-InstMatchTrie2<modEq>::InstMatchTrie2(context::Context* c, QuantifiersEngine* qe):
- d_data(c->getLevel()), d_context(c), d_mods(c) {
- d_eQ = qe->getEqualityQuery();
- d_eE = ((uf::TheoryUF*)qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine();
-};
-
-/** add match m for quantifier f starting at index, take into account equalities q, return true if successful */
-template<bool modEq>
-void InstMatchTrie2<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 InstMatchTrie2<modEq>::existsInstMatch(InstMatchTrie2<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 InstMatchTrie2<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_eE->hasTerm( n ) ){
- //check modulo equality if any other instantiation match exists
- eq::EqClassIterator eqc( d_eQ->getRepresentative( n ), d_eE );
- for( ;!eqc.isFinished();++eqc ){
- TNode en = (*eqc);
- if( en == n ) continue; // already tested
- typename InstMatchTrie2<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 InstMatchTrie2<modEq>::addInstMatch( InstMatch& m ) {
- mapIter begin = m.d_map.begin();
- mapIter end = m.d_map.end();
- typename InstMatchTrie2<modEq>::Tree * e = &d_data;
- 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 namespace */
-
-}/* CVC4 namespace */
-
-#endif /* __CVC4__INST_MATCH_IMPL_H */
#include "theory/model.h"\r
#include "theory/quantifiers_engine.h"\r
#include "theory/theory_engine.h"\r
+#include "util/datatype.h"\r
+#include "theory/uf/theory_uf_model.h"\r
\r
using namespace std;\r
using namespace CVC4;\r
d_false = NodeManager::currentNM()->mkConst( false );\r
}\r
\r
+void TheoryModel::reset(){\r
+ d_reps.clear();\r
+ d_rep_set.clear();\r
+}\r
+\r
void TheoryModel::addDefineFunction( Node n ){\r
d_define_funcs.push_back( n );\r
d_defines.push_back( 0 );\r
\r
void TheoryModel::toStreamFunction( Node n, std::ostream& out ){\r
out << "(" << n;\r
- //out << " : " << n.getType();\r
+ out << " : " << n.getType();\r
out << " ";\r
Node value = getValue( n );\r
+ /*\r
if( n.getType().isSort() ){\r
- int index = d_ra.getIndexFor( value );\r
+ int index = d_rep_set.getIndexFor( value );\r
if( index!=-1 ){\r
out << value.getType() << "_" << index;\r
}else{\r
out << value;\r
}\r
}else{\r
- out << value;\r
- }\r
+ */\r
+ out << value;\r
out << ")" << std::endl;\r
}\r
\r
void TheoryModel::toStreamType( TypeNode tn, std::ostream& out ){\r
out << "(" << tn;\r
if( tn.isSort() ){\r
- if( d_ra.d_type_reps.find( tn )!=d_ra.d_type_reps.end() ){\r
- out << " " << d_ra.d_type_reps[tn].size();\r
+ if( d_rep_set.d_type_reps.find( tn )!=d_rep_set.d_type_reps.end() ){\r
+ out << " " << d_rep_set.d_type_reps[tn].size();\r
//out << " (";\r
- //for( size_t i=0; i<d_ra.d_type_reps[tn].size(); i++ ){\r
+ //for( size_t i=0; i<d_rep_set.d_type_reps[tn].size(); i++ ){\r
// if( i>0 ){ out << " "; }\r
- // out << d_ra.d_type_reps[tn][i];\r
+ // out << d_rep_set.d_type_reps[tn][i];\r
//}\r
//out << ")";\r
}\r
}\r
\r
void TheoryModel::toStream( std::ostream& out ){\r
+ /*//for debugging\r
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );\r
+ while( !eqcs_i.isFinished() ){\r
+ Node eqc = (*eqcs_i);\r
+ Debug("get-model-debug") << eqc << " : " << eqc.getType() << " : " << std::endl;\r
+ out << " ";\r
+ //add terms to model\r
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );\r
+ while( !eqc_i.isFinished() ){\r
+ out << (*eqc_i) << " ";\r
+ ++eqc_i;\r
+ }\r
+ out << std::endl;\r
+ ++eqcs_i;\r
+ }\r
+ */\r
int funcIndex = 0;\r
int typeIndex = 0;\r
for( size_t i=0; i<d_defines.size(); i++ ){\r
//otherwise, get the interpreted value in the model\r
return getInterpretedValue( nn );\r
}\r
-\r
- ////case for equality\r
- //if( n.getKind()==EQUAL ){\r
- // Debug("model") << "-> Equality." << std::endl;\r
- // Node n1 = getValue( n[0] );\r
- // Node n2 = getValue( n[1] );\r
- // return NodeManager::currentNM()->mkConst( n1==n2 );\r
- //}\r
}\r
\r
Node TheoryModel::getDomainValue( TypeNode tn, std::vector< Node >& exclude ){\r
- if( d_ra.d_type_reps.find( tn )!=d_ra.d_type_reps.end() ){\r
+ if( d_rep_set.d_type_reps.find( tn )!=d_rep_set.d_type_reps.end() ){\r
//try to find a pre-existing arbitrary element\r
- for( size_t i=0; i<d_ra.d_type_reps[tn].size(); i++ ){\r
- if( std::find( exclude.begin(), exclude.end(), d_ra.d_type_reps[tn][i] )==exclude.end() ){\r
- return d_ra.d_type_reps[tn][i];\r
+ for( size_t i=0; i<d_rep_set.d_type_reps[tn].size(); i++ ){\r
+ if( std::find( exclude.begin(), exclude.end(), d_rep_set.d_type_reps[tn][i] )==exclude.end() ){\r
+ return d_rep_set.d_type_reps[tn][i];\r
}\r
}\r
}\r
//FIXME: use the theory enumerator to generate constants here\r
Node TheoryModel::getNewDomainValue( TypeNode tn ){\r
if( tn==NodeManager::currentNM()->booleanType() ){\r
- if( d_ra.d_type_reps[tn].empty() ){\r
+ if( d_rep_set.d_type_reps[tn].empty() ){\r
return d_false;\r
- }else if( d_ra.d_type_reps[tn].size()==1 ){\r
- return NodeManager::currentNM()->mkConst( areEqual( d_ra.d_type_reps[tn][0], d_false ) );\r
+ }else if( d_rep_set.d_type_reps[tn].size()==1 ){\r
+ return NodeManager::currentNM()->mkConst( areEqual( d_rep_set.d_type_reps[tn][0], d_false ) );\r
}else{\r
return Node::null();\r
}\r
int val = 0;\r
do{\r
Node r = NodeManager::currentNM()->mkConst( Rational(val) );\r
- if( std::find( d_ra.d_type_reps[tn].begin(), d_ra.d_type_reps[tn].end(), r )==d_ra.d_type_reps[tn].end() &&\r
+ if( std::find( d_rep_set.d_type_reps[tn].begin(), d_rep_set.d_type_reps[tn].end(), r )==d_rep_set.d_type_reps[tn].end() &&\r
!d_equalityEngine.hasTerm( r ) ){\r
return r;\r
}\r
\r
Node TheoryModel::getRepresentative( Node a ){\r
if( d_equalityEngine.hasTerm( a ) ){\r
- return d_reps[ d_equalityEngine.getRepresentative( a ) ];\r
+ Node r = d_equalityEngine.getRepresentative( a );\r
+ return d_reps[ r ];\r
}else{\r
return a;\r
}\r
}\r
}\r
\r
-DefaultModel::DefaultModel( context::Context* c, std::string name ) : TheoryModel( c, name ){\r
+DefaultModel::DefaultModel( context::Context* c, std::string name, bool enableFuncModels ) :\r
+TheoryModel( c, name ), d_enableFuncModels( enableFuncModels ){\r
+\r
+}\r
+\r
+void DefaultModel::addTerm( Node n ){\r
+ //must collect UF terms\r
+ if( d_enableFuncModels && n.getKind()==APPLY_UF ){\r
+ d_uf_terms[ n.getOperator() ].push_back( n );\r
+ }\r
+}\r
\r
+void DefaultModel::reset(){\r
+ d_uf_terms.clear();\r
+ d_uf_models.clear();\r
+ TheoryModel::reset();\r
}\r
\r
Node DefaultModel::getInterpretedValue( TNode n ){\r
TypeNode type = n.getType();\r
if( type.isFunction() || type.isPredicate() ){\r
- //DO_THIS?\r
- return n;\r
+ //for function models\r
+ if( d_enableFuncModels ){\r
+ if( d_uf_models.find( n )==d_uf_models.end() ){\r
+ uf::UfModelTree ufmt( n );\r
+ Node default_v;\r
+ for( size_t i=0; i<d_uf_terms[n].size(); i++ ){\r
+ Node un = d_uf_terms[n][i];\r
+ Node v = getRepresentative( un );\r
+ ufmt.setValue( this, un, v );\r
+ default_v = v;\r
+ }\r
+ if( default_v.isNull() ){\r
+ default_v = getInterpretedValue( NodeManager::currentNM()->mkVar( type.getRangeType() ) );\r
+ }\r
+ ufmt.setDefaultValue( this, default_v );\r
+ ufmt.simplify();\r
+ d_uf_models[n] = ufmt.getFunctionValue();\r
+ }\r
+ return d_uf_models[n];\r
+ }else{\r
+ return n;\r
+ }\r
}else{\r
//first, see if the representative is defined\r
if( d_equalityEngine.hasTerm( n ) ){\r
void TheoryEngineModelBuilder::buildModel( Model* m ){\r
TheoryModel* tm = (TheoryModel*)m;\r
//reset representative information\r
- tm->d_reps.clear();\r
- tm->d_ra.clear();\r
- Debug( "model-builder" ) << "TheoryEngineModelBuilder: Collect model info..." << std::endl;\r
+ tm->reset();\r
//collect model info from the theory engine\r
+ Debug( "model-builder" ) << "TheoryEngineModelBuilder: Collect model info..." << std::endl;\r
d_te->collectModelInfo( tm );\r
+ //unresolved equivalence classes\r
+ std::map< Node, bool > unresolved_eqc;\r
+ std::map< TypeNode, bool > unresolved_types;\r
+ std::map< Node, std::vector< Node > > selects;\r
+ std::map< Node, Node > apply_constructors;\r
Debug( "model-builder" ) << "TheoryEngineModelBuilder: Build representatives..." << std::endl;\r
- //populate term database, store representatives\r
+ //populate term database, store constant representatives\r
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &tm->d_equalityEngine );\r
while( !eqcs_i.isFinished() ){\r
Node eqc = (*eqcs_i);\r
- //add terms to model\r
+ TypeNode eqct = eqc.getType();\r
+ //initialize unresolved type information\r
+ initializeType( eqct, unresolved_types );\r
+ //add terms to model, get constant rep if possible\r
+ Node const_rep;\r
eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &tm->d_equalityEngine );\r
while( !eqc_i.isFinished() ){\r
- tm->addTerm( *eqc_i );\r
+ Node n = *eqc_i;\r
+ //check if this is constant, if so, we will use it as representative\r
+ if( n.getMetaKind()==kind::metakind::CONSTANT ){\r
+ const_rep = n;\r
+ }\r
+ //theory-specific information needed\r
+ if( n.getKind()==SELECT ){\r
+ selects[ n[0] ].push_back( n );\r
+ }else if( n.getKind()==APPLY_CONSTRUCTOR ){\r
+ apply_constructors[ eqc ] = n;\r
+ }\r
+ //model-specific processing of the term, this will include\r
+ tm->addTerm( n );\r
++eqc_i;\r
}\r
- //choose representative for this equivalence class\r
- Node rep = chooseRepresentative( tm, eqc );\r
//store representative in representative set\r
- if( !rep.isNull() ){\r
- tm->d_reps[ eqc ] = rep;\r
- tm->d_ra.add( rep );\r
+ if( !const_rep.isNull() ){\r
+ //Message() << "Constant rep " << const_rep << " for " << eqc << std::endl;\r
+ tm->d_reps[ eqc ] = const_rep;\r
+ tm->d_rep_set.add( const_rep );\r
+ }else{\r
+ //Message() << "** unresolved eqc " << eqc << std::endl;\r
+ unresolved_eqc[ eqc ] = true;\r
+ unresolved_types[ eqct ] = true;\r
}\r
++eqcs_i;\r
}\r
- //do model-builder specific initialization\r
- // this should include choosing representatives for equivalence classes that have not yet been\r
- // assigned representatives\r
+ //choose representatives for unresolved equivalence classes\r
+ Debug( "model-builder" ) << "TheoryEngineModelBuilder: Complete model..." << std::endl;\r
+ bool fixedPoint;\r
+ do{\r
+ fixedPoint = true;\r
+ //for calculating unresolved types\r
+ std::map< TypeNode, bool > unresolved_types_next;\r
+ for( std::map< TypeNode, bool >::iterator it = unresolved_types.begin(); it != unresolved_types.end(); ++it ){\r
+ unresolved_types_next[ it->first ] = false;\r
+ }\r
+ //try to resolve each unresolved equivalence class\r
+ for( std::map< Node, bool >::iterator it = unresolved_eqc.begin(); it != unresolved_eqc.end(); ++it ){\r
+ if( it->second ){\r
+ Node n = it->first;\r
+ TypeNode tn = n.getType();\r
+ Node rep;\r
+ bool mkRep = true;\r
+ if( tn.isArray() ){\r
+ TypeNode index_t = tn.getArrayIndexType();\r
+ TypeNode elem_t = tn.getArrayConstituentType();\r
+ if( !unresolved_types[ index_t ] && !unresolved_types[ elem_t ] ){\r
+ //collect all relevant set values of n\r
+ std::vector< Node > arr_selects;\r
+ std::vector< Node > arr_select_values;\r
+ Node nbase = n;\r
+ while( nbase.getKind()==STORE ){\r
+ arr_selects.push_back( tm->getRepresentative( nbase[1] ) );\r
+ arr_select_values.push_back( tm->getRepresentative( nbase[2] ) );\r
+ nbase = nbase[0];\r
+ }\r
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( n, &tm->d_equalityEngine );\r
+ while( !eqc_i.isFinished() ){\r
+ for( int i=0; i<(int)selects[ *eqc_i ].size(); i++ ){\r
+ Node r = tm->getRepresentative( selects[ *eqc_i ][i][1] );\r
+ if( std::find( arr_selects.begin(), arr_selects.end(), r )==arr_selects.end() ){\r
+ arr_selects.push_back( r );\r
+ arr_select_values.push_back( tm->getRepresentative( selects[ *eqc_i ][i] ) );\r
+ }\r
+ }\r
+ ++eqc_i;\r
+ }\r
+ //now, construct based on select/value pairs\r
+ //TODO: make this a constant\r
+ rep = chooseRepresentative( tm, nbase );\r
+ for( int i=0; i<(int)arr_selects.size(); i++ ){\r
+ rep = NodeManager::currentNM()->mkNode( STORE, rep, arr_selects[i], arr_select_values[i] );\r
+ }\r
+ }\r
+ mkRep = false;\r
+ }else if( tn.isDatatype() ){\r
+ if( apply_constructors.find( n )!=apply_constructors.end() ){\r
+ Node ac = apply_constructors[n];\r
+ std::vector< Node > children;\r
+ children.push_back( ac.getOperator() );\r
+ for( size_t i = 0; i<ac.getNumChildren(); i++ ){\r
+ Node acir = ac[i];\r
+ if( tm->d_equalityEngine.hasTerm( acir ) ){\r
+ acir = tm->d_equalityEngine.getRepresentative( acir );\r
+ }\r
+ if( unresolved_eqc.find( acir )==unresolved_eqc.end() ){\r
+ Message() << "TheoryEngineModelBuilder::buildModel : Datatype argument does not exist in the model " << acir << std::endl;\r
+ acir = Node::null();\r
+ }\r
+ if( acir.isNull() || unresolved_eqc[ acir ] ){\r
+ mkRep = false;\r
+ break;\r
+ }else{\r
+ children.push_back( tm->getRepresentative( acir ) );\r
+ }\r
+ }\r
+ if( mkRep ){\r
+ rep = NodeManager::currentNM()->mkNode( APPLY_CONSTRUCTOR, children );\r
+ }\r
+ }else{\r
+ Message() << "TheoryEngineModelBuilder::buildModel : Do not know how to resolve datatype equivalence class " << n << std::endl;\r
+ }\r
+ mkRep = false;\r
+ }\r
+ if( mkRep ){\r
+ rep = chooseRepresentative( tm, n );\r
+ }\r
+ if( !rep.isNull() ){\r
+ tm->assertEquality( n, rep, true );\r
+ tm->d_reps[ n ] = rep;\r
+ tm->d_rep_set.add( rep );\r
+ unresolved_eqc[ n ] = false;\r
+ fixedPoint = false;\r
+ }else{\r
+ unresolved_types_next[ tn ] = true;\r
+ }\r
+ }\r
+ }\r
+ //for calculating unresolved types\r
+ for( std::map< TypeNode, bool >::iterator it = unresolved_types.begin(); it != unresolved_types.end(); ++it ){\r
+ unresolved_types[ it->first ] = unresolved_types_next[ it->first ];\r
+ }\r
+ }while( !fixedPoint );\r
+\r
+ //for all unresolved equivalence classes, just get new domain value\r
+ // this should typically never happen (all equivalence classes should be resolved at this point)\r
+ for( std::map< Node, bool >::iterator it = unresolved_eqc.begin(); it != unresolved_eqc.end(); ++it ){\r
+ if( it->second ){\r
+ Node n = it->first;\r
+ Node rep = chooseRepresentative( tm, n );\r
+ tm->assertEquality( n, rep, true );\r
+ tm->d_reps[ n ] = rep;\r
+ tm->d_rep_set.add( rep );\r
+ //FIXME: Assertion failure here?\r
+ Message() << "Warning : Unresolved eqc, assigning " << rep << " for eqc( " << n << " ), type = " << n.getType() << std::endl;\r
+ }\r
+ }\r
+\r
+ //model-specific initialization\r
processBuildModel( tm );\r
}\r
\r
-Node TheoryEngineModelBuilder::chooseRepresentative( TheoryModel* tm, Node eqc ){\r
- eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &tm->d_equalityEngine );\r
- while( !eqc_i.isFinished() ){\r
- //if constant, use this as representative\r
- if( (*eqc_i).getMetaKind()==kind::metakind::CONSTANT ){\r
- return *eqc_i;\r
+void TheoryEngineModelBuilder::initializeType( TypeNode tn, std::map< TypeNode, bool >& unresolved_types ){\r
+ if( unresolved_types.find( tn )==unresolved_types.end() ){\r
+ unresolved_types[tn] = false;\r
+ if( tn.isArray() ){\r
+ initializeType( tn.getArrayIndexType(), unresolved_types );\r
+ initializeType( tn.getArrayConstituentType(), unresolved_types );\r
+ }else if( tn.isDatatype() ){\r
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();\r
+ for( size_t i = 0; i<dt.getNumConstructors(); i++ ){\r
+ for( size_t j = 0; j<dt[i].getNumArgs(); j++ ){\r
+ initializeType( TypeNode::fromType( dt[i][j].getType() ), unresolved_types );\r
+ }\r
+ }\r
}\r
- ++eqc_i;\r
}\r
- return Node::null();\r
}\r
\r
-void TheoryEngineModelBuilder::processBuildModel( TheoryModel* tm ){\r
- Debug( "model-builder" ) << "TheoryEngineModelBuilder: Complete model..." << std::endl;\r
- //create constants for all unresolved equivalence classes\r
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &tm->d_equalityEngine );\r
- while( !eqcs_i.isFinished() ){\r
- Node n = *eqcs_i;\r
- if( tm->d_reps.find( n )!=tm->d_reps.end() ){\r
- TypeNode tn = n.getType();\r
- //add new constant to equivalence class\r
- Node rep = tm->getNewDomainValue( tn );\r
- if( !rep.isNull() ){\r
- tm->assertEquality( n, rep, true );\r
- }else{\r
- rep = n;\r
- }\r
- tm->d_reps[ n ] = rep;\r
- tm->d_ra.add( rep );\r
- }\r
- ++eqcs_i;\r
+Node TheoryEngineModelBuilder::chooseRepresentative( TheoryModel* m, Node eqc ){\r
+ //try to get a new domain value\r
+ Node rep = m->getNewDomainValue( eqc.getType() );\r
+ if( !rep.isNull() ){\r
+ return rep;\r
+ }else{\r
+ //if we can't get new domain value, just return eqc itself (this typically should not happen)\r
+ //FIXME: Assertion failure here?\r
+ return eqc;\r
}\r
}\r
{\r
friend class TheoryEngineModelBuilder;\r
protected:\r
- /** add term */\r
+ /** add term function\r
+ * This should be called on all terms that exist in the model.\r
+ * addTerm( n ) will do any model-specific processing necessary for n,\r
+ * such as contraining the interpretation of uninterpretted functions.\r
+ */\r
virtual void addTerm( Node n ) {}\r
private:\r
- /** definitions */\r
+ /** List of definitions that the user has given\r
+ * This is necessary for supporting the get-model command.\r
+ */\r
std::vector< Node > d_define_funcs;\r
std::vector< TypeNode > d_define_types;\r
std::vector< int > d_defines;\r
protected:\r
- /** to stream functions */\r
+ /** print the value of the function n to stream */\r
virtual void toStreamFunction( Node n, std::ostream& out );\r
+ /** print the value of the type tn to stream */\r
virtual void toStreamType( TypeNode tn, std::ostream& out );\r
public:\r
TheoryModel( context::Context* c, std::string name );\r
eq::EqualityEngine d_equalityEngine;\r
/** map of representatives of equality engine to used representatives in representative set */\r
std::map< Node, Node > d_reps;\r
- /** representative alphabet */\r
- RepSet d_ra;\r
- //true/false nodes\r
+ /** stores set of representatives for each type */\r
+ RepSet d_rep_set;\r
+ /** true/false nodes */\r
Node d_true;\r
Node d_false;\r
public:\r
- /** add defined function */\r
+ /** reset the model */\r
+ virtual void reset();\r
+ /** get interpreted value\r
+ * This function is called when the value of the node cannot be determined by the theory rewriter\r
+ * This should function should return a representative in d_reps\r
+ */\r
+ virtual Node getInterpretedValue( TNode n ) = 0;\r
+public:\r
+ /** add defined function (for get-model) */\r
void addDefineFunction( Node n );\r
- /** add defined type */\r
+ /** add defined type (for get-model) */\r
void addDefineType( TypeNode tn );\r
/**\r
* Get value function. This should be called only after a ModelBuilder has called buildModel(...)\r
* on this model.\r
*/\r
Node getValue( TNode n );\r
- /** get interpreted value, should be a representative in d_reps */\r
- virtual Node getInterpretedValue( TNode n ) = 0;\r
- /** get existing domain value, with possible exclusions */\r
+ /** get existing domain value, with possible exclusions\r
+ * This function returns a term in d_rep_set.d_type_reps[tn] but not in exclude\r
+ */\r
Node getDomainValue( TypeNode tn, std::vector< Node >& exclude );\r
- /** get new domain value */\r
+ /** get new domain value\r
+ * This function returns a constant term of type tn that is not in d_rep_set.d_type_reps[tn]\r
+ * If it cannot find such a node, it returns null.\r
+ */\r
Node getNewDomainValue( TypeNode tn );\r
public:\r
- /** assert equality */\r
+ /** assert equality holds in the model */\r
void assertEquality( Node a, Node b, bool polarity );\r
- /** assert predicate */\r
+ /** assert predicate holds in the model */\r
void assertPredicate( Node a, bool polarity );\r
- /** assert equality engine */\r
+ /** assert all equalities/predicates in equality engine hold in the model */\r
void assertEqualityEngine( eq::EqualityEngine* ee );\r
public:\r
- //queries about equality\r
+ /** general queries */\r
bool hasTerm( Node a );\r
Node getRepresentative( Node a );\r
bool areEqual( Node a, Node b );\r
bool areDisequal( Node a, Node b );\r
public:\r
- /** print representative function */\r
+ /** print representative debug function */\r
void printRepresentativeDebug( const char* c, Node r );\r
+ /** print representative function */\r
void printRepresentative( std::ostream& out, Node r );\r
/** to stream function */\r
void toStream( std::ostream& out );\r
};\r
\r
-//default model class: extends model arbitrarily\r
+/** Default model class\r
+ * The getInterpretedValue function will choose an existing value arbitrarily.\r
+ * If none are found, then it will create a new value.\r
+ */\r
class DefaultModel : public TheoryModel\r
{\r
+protected:\r
+ /** whether function models are enabled */\r
+ bool d_enableFuncModels;\r
+ /** add term */\r
+ void addTerm( Node n );\r
public:\r
- DefaultModel( context::Context* c, std::string name );\r
+ DefaultModel( context::Context* c, std::string name, bool enableFuncModels );\r
virtual ~DefaultModel(){}\r
+ //necessary information for function models\r
+ std::map< Node, std::vector< Node > > d_uf_terms;\r
+ std::map< Node, Node > d_uf_models;\r
public:\r
+ void reset();\r
Node getInterpretedValue( TNode n );\r
};\r
\r
-//incomplete model class: does not extend model\r
-class IncompleteModel : public TheoryModel\r
-{\r
-public:\r
- IncompleteModel( context::Context* c, std::string name ) : TheoryModel( c, name ){}\r
- virtual ~IncompleteModel(){}\r
-public:\r
- Node getInterpretedValue( TNode n ) { return Node::null(); }\r
-};\r
-\r
-\r
+/** TheoryEngineModelBuilder class\r
+ * This model builder will consult all theories in a theory engine for\r
+ * collectModelInfo( ... ) when building a model.\r
+ */\r
class TheoryEngineModelBuilder : public ModelBuilder\r
{\r
protected:\r
/** pointer to theory engine */\r
TheoryEngine* d_te;\r
- /** choose representative */\r
- virtual Node chooseRepresentative( TheoryModel* tm, Node eqc );\r
- /** representatives that are current not set */\r
- virtual void processBuildModel( TheoryModel* tm );\r
+ /** choose representative for unresolved equivalence class */\r
+ void initializeType( TypeNode tn, std::map< TypeNode, bool >& unresolved_types );\r
+ /** process build model */\r
+ virtual void processBuildModel( TheoryModel* m ){}\r
+ /** choose representative for unconstrained equivalence class */\r
+ virtual Node chooseRepresentative( TheoryModel* m, Node eqc );\r
public:\r
TheoryEngineModelBuilder( TheoryEngine* te );\r
virtual ~TheoryEngineModelBuilder(){}\r
- /**\r
- * Build model function.\r
+ /** Build model function.\r
+ * Should be called only on TheoryModels m\r
*/\r
void buildModel( Model* m );\r
};\r
term_database.h \
term_database.cpp \
first_order_model.h \
- first_order_model.cpp
+ first_order_model.cpp \
+ model_builder.h \
+ model_builder.cpp
EXTRA_DIST = kinds
\ No newline at end of file
#include "theory/quantifiers/first_order_model.h"\r
#include "theory/quantifiers/rep_set_iterator.h"\r
#include "theory/quantifiers/model_engine.h"\r
-#include "theory/uf/theory_uf_strong_solver.h"\r
+#include "theory/quantifiers/term_database.h"\r
\r
using namespace std;\r
using namespace CVC4;\r
using namespace CVC4::theory;\r
using namespace CVC4::theory::quantifiers;\r
\r
-FirstOrderModel::FirstOrderModel( QuantifiersEngine* qe, context::Context* c, std::string name ) : DefaultModel( c, name ),\r
+FirstOrderModel::FirstOrderModel( QuantifiersEngine* qe, context::Context* c, std::string name ) : DefaultModel( c, name, true ),\r
d_term_db( qe->getTermDatabase() ), d_forall_asserts( c ){\r
\r
}\r
\r
-void FirstOrderModel::initialize(){\r
+void FirstOrderModel::reset(){\r
//rebuild models\r
- d_uf_model.clear();\r
+ d_uf_model_tree.clear();\r
+ d_uf_model_gen.clear();\r
d_array_model.clear();\r
+ DefaultModel::reset();\r
+}\r
+\r
+void FirstOrderModel::addTerm( Node n ){\r
+ //std::vector< Node > added;\r
+ //d_term_db->addTerm( n, added, false );\r
+ DefaultModel::addTerm( n );\r
+}\r
+\r
+void FirstOrderModel::initialize(){\r
+ //this is called after representatives have been chosen and the equality engine has been built\r
//for each quantifier, collect all operators we care about\r
for( int i=0; i<getNumAssertedQuantifiers(); i++ ){\r
Node f = getAssertedQuantifier( i );\r
- //initialize model for term\r
+ //initialize relevant models within bodies of all quantifiers\r
initializeModelForTerm( f[1] );\r
}\r
-\r
+ //for debugging\r
if( Options::current()->printModelEngine ){\r
- for( std::map< TypeNode, std::vector< Node > >::iterator it = d_ra.d_type_reps.begin(); it != d_ra.d_type_reps.end(); ++it ){\r
- if( uf::StrongSolverTheoryUf::isRelevantType( it->first ) ){\r
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = d_rep_set.d_type_reps.begin(); it != d_rep_set.d_type_reps.end(); ++it ){\r
+ if( it->first.isSort() ){\r
Message() << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;\r
}\r
}\r
void FirstOrderModel::initializeModelForTerm( Node n ){\r
if( n.getKind()==APPLY_UF ){\r
Node op = n.getOperator();\r
- if( d_uf_model.find( op )==d_uf_model.end() ){\r
+ if( d_uf_model_tree.find( op )==d_uf_model_tree.end() ){\r
TypeNode tn = op.getType();\r
tn = tn[ (int)tn.getNumChildren()-1 ];\r
- if( tn==NodeManager::currentNM()->booleanType() || uf::StrongSolverTheoryUf::isRelevantType( tn ) ){\r
- d_uf_model[ op ] = uf::UfModel( op, this );\r
+ //only generate models for predicates and functions with uninterpreted range types\r
+ if( tn==NodeManager::currentNM()->booleanType() || tn.isSort() ){\r
+ d_uf_model_tree[ op ] = uf::UfModelTree( op );\r
+ d_uf_model_gen[ op ].clear();\r
}\r
}\r
}\r
- if( n.getKind()!=STORE && n.getType().isArray() ){\r
- d_array_model[n] = Node::null();\r
+ /*\r
+ if( n.getType().isArray() ){\r
+ while( n.getKind()==STORE ){\r
+ n = n[0];\r
+ }\r
+ Node nn = getRepresentative( n );\r
+ if( d_array_model.find( nn )==d_array_model.end() ){\r
+ d_array_model[nn] = arrays::ArrayModel( nn, this );\r
+ }\r
}\r
+ */\r
for( int i=0; i<(int)n.getNumChildren(); i++ ){\r
initializeModelForTerm( n[i] );\r
}\r
}\r
\r
void FirstOrderModel::toStreamFunction( Node n, std::ostream& out ){\r
+ /*\r
if( d_uf_model.find( n )!=d_uf_model.end() ){\r
//d_uf_model[n].toStream( out );\r
Node value = d_uf_model[n].getFunctionValue();\r
out << "(" << n << " " << value << ")";\r
- //}else if( d_array_model.find( n )!=d_array_model.end() ){\r
- //out << "(" << n << " " << d_array_model[n] << ")" << std::endl;\r
- // out << "(" << n << " Array)" << std::endl;\r
- }else{\r
- DefaultModel::toStreamFunction( n, out );\r
+ }else if( d_array_model.find( n )!=d_array_model.end() ){\r
+ Node value = d_array_model[n].getArrayValue();\r
+ out << "(" << n << " " << value << ")" << std::endl;\r
}\r
+ */\r
+ DefaultModel::toStreamFunction( n, out );\r
}\r
\r
void FirstOrderModel::toStreamType( TypeNode tn, std::ostream& out ){\r
Debug("fo-model") << "get interpreted value " << n << std::endl;\r
TypeNode type = n.getType();\r
if( type.isFunction() || type.isPredicate() ){\r
- if( d_uf_model.find( n )!=d_uf_model.end() ){\r
- return d_uf_model[n].getFunctionValue();\r
+ if( d_uf_models.find( n )==d_uf_models.end() ){\r
+ //use the model tree to generate the model\r
+ Node fn = d_uf_model_tree[n].getFunctionValue();\r
+ d_uf_models[n] = fn;\r
+ return fn;\r
+ }\r
+ /*\r
+ }else if( type.isArray() ){\r
+ if( d_array_model.find( n )!=d_array_model.end() ){\r
+ return d_array_model[n].getArrayValue();\r
}else{\r
- return n;\r
+ //std::cout << "no array model generated for " << n << std::endl;\r
}\r
+ */\r
}else if( n.getKind()==APPLY_UF ){\r
- int depIndex;\r
- return d_uf_model[ n.getOperator() ].getValue( n, depIndex );\r
+ Node op = n.getOperator();\r
+ if( d_uf_model_tree.find( op )!=d_uf_model_tree.end() ){\r
+ //consult the uf model\r
+ int depIndex;\r
+ return d_uf_model_tree[ op ].getValue( this, n, depIndex );\r
+ }\r
+ }else if( n.getKind()==SELECT ){\r
+\r
}\r
return DefaultModel::getInterpretedValue( n );\r
}\r
#if 0\r
out << "---Current Model---" << std::endl;\r
out << "Representatives: " << std::endl;\r
- d_ra.toStream( out );\r
+ d_rep_set.toStream( out );\r
out << "Functions: " << std::endl;\r
for( std::map< Node, uf::UfModel >::iterator it = d_uf_model.begin(); it != d_uf_model.end(); ++it ){\r
it->second.toStream( out );\r
out << std::endl;\r
}\r
#elif 0\r
- d_ra.toStream( out );\r
+ d_rep_set.toStream( out );\r
//print everything not related to UF in equality engine\r
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );\r
while( !eqcs_i.isFinished() ){\r
\r
#include "theory/model.h"\r
#include "theory/uf/theory_uf_model.h"\r
+#include "theory/arrays/theory_arrays_model.h"\r
\r
namespace CVC4 {\r
namespace theory {\r
private:\r
//pointer to term database\r
TermDb* d_term_db;\r
+ //add term function\r
+ void addTerm( Node n );\r
//for initialize model\r
void initializeModelForTerm( Node n );\r
/** to stream functions */\r
void toStreamType( TypeNode tn, std::ostream& out );\r
public: //for Theory UF:\r
//models for each UF operator\r
- std::map< Node, uf::UfModel > d_uf_model;\r
+ std::map< Node, uf::UfModelTree > d_uf_model_tree;\r
+ //model generators\r
+ std::map< Node, uf::UfModelTreeGenerator > d_uf_model_gen;\r
public: //for Theory Arrays:\r
//default value for each non-store array\r
- std::map< Node, Node > d_array_model;\r
+ std::map< Node, arrays::ArrayModel > d_array_model;\r
public: //for Theory Quantifiers:\r
/** list of quantifiers asserted in the current context */\r
context::CDList<Node> d_forall_asserts;\r
public:\r
FirstOrderModel( QuantifiersEngine* qe, context::Context* c, std::string name );\r
virtual ~FirstOrderModel(){}\r
- // initialize the model\r
- void initialize();\r
+ // reset the model\r
+ void reset();\r
/** get interpreted value */\r
Node getInterpretedValue( TNode n );\r
public:\r
+ // initialize the model\r
+ void initialize();\r
/** get term database */\r
TermDb* getTermDatabase();\r
/** to stream function */\r
--- /dev/null
+/********************* */
+/*! \file model_builder.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 model builder class
+ **/
+
+#include "theory/quantifiers/model_engine.h"
+#include "theory/theory_engine.h"
+#include "theory/uf/equality_engine.h"
+#include "theory/uf/theory_uf.h"
+#include "theory/uf/theory_uf_model.h"
+#include "theory/uf/theory_uf_instantiator.h"
+#include "theory/arrays/theory_arrays_model.h"
+#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/model_builder.h"
+
+//#define ME_PRINT_WARNINGS
+
+#define RECONSIDER_FUNC_CONSTANT
+//#define ONE_QUANT_PER_ROUND_INST_GEN
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+
+ModelEngineBuilder::ModelEngineBuilder( QuantifiersEngine* qe ) :
+TheoryEngineModelBuilder( qe->getTheoryEngine() ),
+d_qe( qe ){
+
+}
+
+Node ModelEngineBuilder::chooseRepresentative( TheoryModel* m, Node eqc ){
+ Assert( m->d_equalityEngine.hasTerm( eqc ) );
+ Assert( m->d_equalityEngine.getRepresentative( eqc )==eqc );
+ //avoid interpreted symbols
+ if( isBadRepresentative( eqc ) ){
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &m->d_equalityEngine );
+ while( !eqc_i.isFinished() ){
+ if( !isBadRepresentative( *eqc_i ) ){
+ return *eqc_i;
+ }
+ ++eqc_i;
+ }
+ //otherwise, make new value?
+ //Message() << "Warning: Bad rep " << eqc << std::endl;
+ }
+ return eqc;
+}
+
+bool ModelEngineBuilder::isBadRepresentative( Node n ){
+ return n.getKind()==SELECT || n.getKind()==APPLY_SELECTOR;
+}
+
+void ModelEngineBuilder::processBuildModel( TheoryModel* m ) {
+ d_addedLemmas = 0;
+ //only construct first order model if optUseModel() is true
+ if( optUseModel() ){
+ FirstOrderModel* fm = (FirstOrderModel*)m;
+ //initialize model
+ fm->initialize();
+ //analyze the functions
+ analyzeModel( fm );
+ //analyze the quantifiers
+ Debug("fmf-model-debug") << "Analyzing quantifiers..." << std::endl;
+ analyzeQuantifiers( fm );
+ //if applicable, find exceptions
+ if( optInstGen() ){
+ //now, see if we know that any exceptions via InstGen exist
+ Debug("fmf-model-debug") << "Perform InstGen techniques for quantifiers..." << std::endl;
+ for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
+ Node f = fm->getAssertedQuantifier( i );
+ if( d_quant_sat.find( f )==d_quant_sat.end() ){
+ d_addedLemmas += doInstGen( fm, f );
+ if( optOneQuantPerRoundInstGen() && d_addedLemmas>0 ){
+ break;
+ }
+ }
+ }
+ if( Options::current()->printModelEngine ){
+ if( d_addedLemmas>0 ){
+ Message() << "InstGen, added lemmas = " << d_addedLemmas << std::endl;
+ }else{
+ Message() << "No InstGen lemmas..." << std::endl;
+ }
+ }
+ Debug("fmf-model-debug") << "---> Added lemmas = " << d_addedLemmas << std::endl;
+ }
+ if( d_addedLemmas==0 ){
+ //if no immediate exceptions, build the model
+ // this model will be an approximation that will need to be tested via exhaustive instantiation
+ Debug("fmf-model-debug") << "Building model..." << std::endl;
+ finishBuildModel( fm );
+ }
+ }
+}
+
+void ModelEngineBuilder::analyzeModel( FirstOrderModel* fm ){
+ //determine if any functions are constant
+ for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
+ Node op = it->first;
+ for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
+ Node n = fm->d_uf_terms[op][i];
+ if( !n.getAttribute(NoMatchAttribute()) ){
+ Node v = fm->getRepresentative( n );
+ if( i==0 ){
+ d_uf_prefs[op].d_const_val = v;
+ }else if( v!=d_uf_prefs[op].d_const_val ){
+ d_uf_prefs[op].d_const_val = Node::null();
+ break;
+ }
+ }
+ }
+ if( !d_uf_prefs[op].d_const_val.isNull() ){
+ fm->d_uf_model_gen[op].setDefaultValue( d_uf_prefs[op].d_const_val );
+ fm->d_uf_model_gen[op].makeModel( fm, it->second );
+ Debug("fmf-model-cons") << "Function " << op << " is the constant function ";
+ fm->printRepresentativeDebug( "fmf-model-cons", d_uf_prefs[op].d_const_val );
+ Debug("fmf-model-cons") << std::endl;
+ d_uf_model_constructed[op] = true;
+ }else{
+ d_uf_model_constructed[op] = false;
+ }
+ }
+}
+
+void ModelEngineBuilder::analyzeQuantifiers( FirstOrderModel* fm ){
+ d_quant_selection_lits.clear();
+ d_quant_sat.clear();
+ d_uf_prefs.clear();
+ int quantSatInit = 0;
+ int nquantSatInit = 0;
+ //analyze the preferences of each quantifier
+ for( int i=0; i<(int)fm->getNumAssertedQuantifiers(); i++ ){
+ Node f = fm->getAssertedQuantifier( i );
+ Debug("fmf-model-prefs") << "Analyze quantifier " << f << std::endl;
+ std::vector< Node > pro_con[2];
+ std::vector< Node > constantSatOps;
+ bool constantSatReconsider;
+ //for each asserted quantifier f,
+ // - determine which literals form model basis for each quantifier
+ // - check which function/predicates have good and bad definitions according to f
+ for( std::map< Node, bool >::iterator it = d_qe->d_phase_reqs[f].begin();
+ it != d_qe->d_phase_reqs[f].end(); ++it ){
+ Node n = it->first;
+ Node gn = d_qe->getTermDatabase()->getModelBasis( n );
+ Debug("fmf-model-req") << " Req: " << n << " -> " << it->second << std::endl;
+ //calculate preference
+ int pref = 0;
+ bool value;
+ if( d_qe->getValuation().hasSatValue( gn, value ) ){
+ if( value!=it->second ){
+ //store this literal as a model basis literal
+ // this literal will force a default values in model that (modulo exceptions) shows
+ // that f is satisfied by the model
+ d_quant_selection_lits[f].push_back( value ? n : n.notNode() );
+ pref = 1;
+ }else{
+ pref = -1;
+ }
+ }
+ if( pref!=0 ){
+ //Store preferences for UF
+ bool isConst = !n.hasAttribute(InstConstantAttribute());
+ std::vector< Node > uf_terms;
+ if( gn.getKind()==APPLY_UF ){
+ uf_terms.push_back( gn );
+ isConst = !d_uf_prefs[gn.getOperator()].d_const_val.isNull();
+ }else if( gn.getKind()==EQUAL ){
+ isConst = true;
+ for( int j=0; j<2; j++ ){
+ if( n[j].hasAttribute(InstConstantAttribute()) ){
+ if( n[j].getKind()==APPLY_UF ){
+ Node op = gn[j].getOperator();
+ if( fm->d_uf_model_tree.find( op )!=fm->d_uf_model_tree.end() ){
+ uf_terms.push_back( gn[j] );
+ isConst = isConst && !d_uf_prefs[op].d_const_val.isNull();
+ }else{
+ isConst = false;
+ }
+ }else{
+ isConst = false;
+ }
+ }
+ }
+ }
+ Debug("fmf-model-prefs") << " It is " << ( pref==1 ? "pro" : "con" );
+ Debug("fmf-model-prefs") << " the definition of " << n << std::endl;
+ if( pref==1 && isConst ){
+ d_quant_sat[f] = true;
+ //instead, just note to the model for each uf term that f is pro its definition
+ constantSatReconsider = false;
+ constantSatOps.clear();
+ for( int j=0; j<(int)uf_terms.size(); j++ ){
+ Node op = uf_terms[j].getOperator();
+ constantSatOps.push_back( op );
+ if( d_uf_prefs[op].d_reconsiderModel ){
+ constantSatReconsider = true;
+ }
+ }
+ if( !constantSatReconsider ){
+ break;
+ }
+ }else{
+ int pcIndex = pref==1 ? 0 : 1;
+ for( int j=0; j<(int)uf_terms.size(); j++ ){
+ pro_con[pcIndex].push_back( uf_terms[j] );
+ }
+ }
+ }
+ }
+ if( d_quant_sat.find( f )!=d_quant_sat.end() ){
+ Debug("fmf-model-prefs") << " * Constant SAT due to definition of ops: ";
+ for( int i=0; i<(int)constantSatOps.size(); i++ ){
+ Debug("fmf-model-prefs") << constantSatOps[i] << " ";
+ d_uf_prefs[constantSatOps[i]].d_reconsiderModel = false;
+ }
+ Debug("fmf-model-prefs") << std::endl;
+ quantSatInit++;
+ d_statistics.d_pre_sat_quant += quantSatInit;
+ }else{
+ nquantSatInit++;
+ d_statistics.d_pre_nsat_quant += quantSatInit;
+ //note quantifier's value preferences to models
+ for( int k=0; k<2; k++ ){
+ for( int j=0; j<(int)pro_con[k].size(); j++ ){
+ Node op = pro_con[k][j].getOperator();
+ Node r = fm->getRepresentative( pro_con[k][j] );
+ d_uf_prefs[op].setValuePreference( f, pro_con[k][j], r, k==0 );
+ }
+ }
+ }
+ }
+ Debug("fmf-model-prefs") << "Pre-Model Completion: Quantifiers SAT: " << quantSatInit << " / " << (quantSatInit+nquantSatInit) << std::endl;
+}
+
+int ModelEngineBuilder::doInstGen( FirstOrderModel* fm, Node f ){
+ //we wish to add all known exceptions to our model basis literal(s)
+ // this will help to refine our current model.
+ //This step is advantageous over exhaustive instantiation, since we are adding instantiations that involve model basis terms,
+ // effectively acting as partial instantiations instead of pointwise instantiations.
+ int addedLemmas = 0;
+ for( int i=0; i<(int)d_quant_selection_lits[f].size(); i++ ){
+ bool phase = d_quant_selection_lits[f][i].getKind()!=NOT;
+ Node lit = d_quant_selection_lits[f][i].getKind()==NOT ? d_quant_selection_lits[f][i][0] : d_quant_selection_lits[f][i];
+ Assert( lit.hasAttribute(InstConstantAttribute()) );
+ std::vector< Node > tr_terms;
+ if( lit.getKind()==APPLY_UF ){
+ //only match predicates that are contrary to this one, use literal matching
+ Node eq = NodeManager::currentNM()->mkNode( IFF, lit, !phase ? fm->d_true : fm->d_false );
+ fm->getTermDatabase()->setInstantiationConstantAttr( eq, f );
+ tr_terms.push_back( eq );
+ }else if( lit.getKind()==EQUAL ){
+ //collect trigger terms
+ for( int j=0; j<2; j++ ){
+ if( lit[j].hasAttribute(InstConstantAttribute()) ){
+ if( lit[j].getKind()==APPLY_UF ){
+ tr_terms.push_back( lit[j] );
+ }else{
+ tr_terms.clear();
+ break;
+ }
+ }
+ }
+ if( tr_terms.size()==1 && !phase ){
+ //equality between a function and a ground term, use literal matching
+ tr_terms.clear();
+ tr_terms.push_back( lit );
+ }
+ }
+ //if applicable, try to add exceptions here
+ if( !tr_terms.empty() ){
+ //make a trigger for these terms, add instantiations
+ inst::Trigger* tr = inst::Trigger::mkTrigger( d_qe, f, tr_terms );
+ //Notice() << "Trigger = " << (*tr) << std::endl;
+ tr->resetInstantiationRound();
+ tr->reset( Node::null() );
+ //d_qe->d_optInstMakeRepresentative = false;
+ //d_qe->d_optMatchIgnoreModelBasis = true;
+ addedLemmas += tr->addInstantiations( d_quant_basis_match[f] );
+ }
+ }
+ return addedLemmas;
+}
+
+void ModelEngineBuilder::finishBuildModel( FirstOrderModel* fm ){
+ //build model for UF
+ for( std::map< Node, uf::UfModelTree >::iterator it = fm->d_uf_model_tree.begin(); it != fm->d_uf_model_tree.end(); ++it ){
+ finishBuildModelUf( fm, it->first );
+ }
+ /*
+ //build model for arrays
+ for( std::map< Node, arrays::ArrayModel >::iterator it = fm->d_array_model.begin(); it != fm->d_array_model.end(); ++it ){
+ //consult the model basis select term
+ // i.e. the default value for array A is the value of select( A, e ), where e is the model basis term
+ TypeNode tn = it->first.getType();
+ Node selModelBasis = NodeManager::currentNM()->mkNode( SELECT, it->first, fm->getTermDatabase()->getModelBasisTerm( tn[0] ) );
+ it->second.setDefaultValue( fm->getRepresentative( selModelBasis ) );
+ }
+ */
+ Debug("fmf-model-debug") << "Done building models." << std::endl;
+}
+
+void ModelEngineBuilder::finishBuildModelUf( FirstOrderModel* fm, Node op ){
+#ifdef RECONSIDER_FUNC_CONSTANT
+ if( d_uf_model_constructed[op] ){
+ if( d_uf_prefs[op].d_reconsiderModel ){
+ //if we are allowed to reconsider default value, then see if the default value can be improved
+ Node v = d_uf_prefs[op].d_const_val;
+ if( d_uf_prefs[op].d_value_pro_con[0][v].empty() ){
+ Debug("fmf-model-cons-debug") << "Consider changing the default value for " << op << std::endl;
+ fm->d_uf_model_tree[op].clear();
+ fm->d_uf_model_gen[op].clear();
+ d_uf_model_constructed[op] = false;
+ }
+ }
+ }
+#endif
+ if( !d_uf_model_constructed[op] ){
+ //construct the model for the uninterpretted function/predicate
+ bool setDefaultVal = true;
+ Node defaultTerm = d_qe->getTermDatabase()->getModelBasisOpTerm( op );
+ Debug("fmf-model-cons") << "Construct model for " << op << "..." << std::endl;
+ //set the values in the model
+ for( size_t i=0; i<fm->d_uf_terms[op].size(); i++ ){
+ Node n = fm->d_uf_terms[op][i];
+ fm->getTermDatabase()->computeModelBasisArgAttribute( n );
+ if( !n.getAttribute(NoMatchAttribute()) || n.getAttribute(ModelBasisArgAttribute())==1 ){
+ Node v = fm->getRepresentative( n );
+ //if this assertion did not help the model, just consider it ground
+ //set n = v in the model tree
+ Debug("fmf-model-cons") << " Set " << n << " = ";
+ fm->printRepresentativeDebug( "fmf-model-cons", v );
+ Debug("fmf-model-cons") << std::endl;
+ //set it as ground value
+ fm->d_uf_model_gen[op].setValue( fm, n, v );
+ if( fm->d_uf_model_gen[op].optUsePartialDefaults() ){
+ //also set as default value if necessary
+ //if( n.getAttribute(ModelBasisArgAttribute())==1 && !d_term_pro_con[0][n].empty() ){
+ if( n.hasAttribute(ModelBasisArgAttribute()) && n.getAttribute(ModelBasisArgAttribute())==1 ){
+ fm->d_uf_model_gen[op].setValue( fm, n, v, false );
+ if( n==defaultTerm ){
+ //incidentally already set, we will not need to find a default value
+ setDefaultVal = false;
+ }
+ }
+ }else{
+ if( n==defaultTerm ){
+ fm->d_uf_model_gen[op].setValue( fm, n, v, false );
+ //incidentally already set, we will not need to find a default value
+ setDefaultVal = false;
+ }
+ }
+ }
+ }
+ //set the overall default value if not set already (is this necessary??)
+ if( setDefaultVal ){
+ Debug("fmf-model-cons") << " Choose default value..." << std::endl;
+ //chose defaultVal based on heuristic, currently the best ratio of "pro" responses
+ Node defaultVal = d_uf_prefs[op].getBestDefaultValue( defaultTerm, fm );
+ Assert( !defaultVal.isNull() );
+ fm->d_uf_model_gen[op].setValue( fm, defaultTerm, defaultVal, false );
+ }
+ Debug("fmf-model-cons") << " Making model...";
+ fm->d_uf_model_gen[op].makeModel( fm, fm->d_uf_model_tree[op] );
+ d_uf_model_constructed[op] = true;
+ Debug("fmf-model-cons") << " Finished constructing model for " << op << "." << std::endl;
+ }
+}
+
+void ModelEngineBuilder::finishProcessBuildModel( TheoryModel* m ){
+ for( std::map< Node, Node >::iterator it = m->d_reps.begin(); it != m->d_reps.end(); ++it ){
+ //build proper representatives (TODO)
+ }
+}
+
+bool ModelEngineBuilder::optUseModel() {
+ return Options::current()->fmfModelBasedInst;
+}
+
+bool ModelEngineBuilder::optInstGen(){
+ return Options::current()->fmfInstGen;
+}
+
+bool ModelEngineBuilder::optOneQuantPerRoundInstGen(){
+#ifdef ONE_QUANT_PER_ROUND_INST_GEN
+ return true;
+#else
+ return false;
+#endif
+}
+
+ModelEngineBuilder::Statistics::Statistics():
+ d_pre_sat_quant("ModelEngineBuilder::Status_quant_pre_sat", 0),
+ d_pre_nsat_quant("ModelEngineBuilder::Status_quant_pre_non_sat", 0)
+{
+ StatisticsRegistry::registerStat(&d_pre_sat_quant);
+ StatisticsRegistry::registerStat(&d_pre_nsat_quant);
+}
+
+ModelEngineBuilder::Statistics::~Statistics(){
+ StatisticsRegistry::unregisterStat(&d_pre_sat_quant);
+ StatisticsRegistry::unregisterStat(&d_pre_nsat_quant);
+}
--- /dev/null
+/********************* */\r
+/*! \file model_builder.h\r
+ ** \verbatim\r
+ ** Original author: ajreynol\r
+ ** Major contributors: mdeters\r
+ ** Minor contributors (to current version): none\r
+ ** This file is part of the CVC4 prototype.\r
+ ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys)\r
+ ** Courant Institute of Mathematical Sciences\r
+ ** New York University\r
+ ** See the file COPYING in the top-level source directory for licensing\r
+ ** information.\endverbatim\r
+ **\r
+ ** \brief Model Builder class\r
+ **/\r
+\r
+#include "cvc4_private.h"\r
+\r
+#ifndef __CVC4__QUANTIFIERS_MODEL_BUILDER_H\r
+#define __CVC4__QUANTIFIERS_MODEL_BUILDER_H\r
+\r
+#include "theory/quantifiers_engine.h"\r
+#include "theory/model.h"\r
+#include "theory/uf/theory_uf_model.h"\r
+\r
+namespace CVC4 {\r
+namespace theory {\r
+namespace quantifiers {\r
+\r
+//the model builder\r
+class ModelEngineBuilder : public TheoryEngineModelBuilder\r
+{\r
+protected:\r
+ //quantifiers engine\r
+ QuantifiersEngine* d_qe;\r
+ //map from operators to model preference data\r
+ std::map< Node, uf::UfModelPreferenceData > d_uf_prefs;\r
+ //built model uf\r
+ std::map< Node, bool > d_uf_model_constructed;\r
+ /** process build model */\r
+ void processBuildModel( TheoryModel* m );\r
+ /** choose representative for unconstrained equivalence class */\r
+ Node chooseRepresentative( TheoryModel* m, Node eqc );\r
+ /** bad representative */\r
+ bool isBadRepresentative( Node n );\r
+protected:\r
+ //analyze model\r
+ void analyzeModel( FirstOrderModel* fm );\r
+ //analyze quantifiers\r
+ void analyzeQuantifiers( FirstOrderModel* fm );\r
+ //build model\r
+ void finishBuildModel( FirstOrderModel* fm );\r
+ //theory-specific build models\r
+ void finishBuildModelUf( FirstOrderModel* fm, Node op );\r
+ //do InstGen techniques for quantifier, return number of lemmas produced\r
+ int doInstGen( FirstOrderModel* fm, Node f );\r
+public:\r
+ ModelEngineBuilder( QuantifiersEngine* qe );\r
+ virtual ~ModelEngineBuilder(){}\r
+ /** finish model */\r
+ void finishProcessBuildModel( TheoryModel* m );\r
+public:\r
+ /** number of lemmas generated while building model */\r
+ int d_addedLemmas;\r
+ //map from quantifiers to if are constant SAT\r
+ std::map< Node, bool > d_quant_sat;\r
+ //map from quantifiers to the instantiation literals that their model is dependent upon\r
+ std::map< Node, std::vector< Node > > d_quant_selection_lits;\r
+public:\r
+ //map from quantifiers to model basis match\r
+ std::map< Node, InstMatch > d_quant_basis_match;\r
+ //options\r
+ bool optUseModel();\r
+ bool optInstGen();\r
+ bool optOneQuantPerRoundInstGen();\r
+ /** statistics class */\r
+ class Statistics {\r
+ public:\r
+ IntStat d_pre_sat_quant;\r
+ IntStat d_pre_nsat_quant;\r
+ Statistics();\r
+ ~Statistics();\r
+ };\r
+ Statistics d_statistics;\r
+};\r
+\r
+}\r
+}\r
+}\r
+\r
+#endif\r
#include "theory/uf/theory_uf.h"
#include "theory/uf/theory_uf_strong_solver.h"
#include "theory/uf/theory_uf_instantiator.h"
+#include "theory/arrays/theory_arrays_model.h"
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/term_database.h"
//#define ME_PRINT_WARNINGS
-//#define DISABLE_EVAL_SKIP_MULTIPLE
-
-#define RECONSIDER_FUNC_CONSTANT
#define EVAL_FAIL_SKIP_MULTIPLE
-//#define ONE_QUANT_PER_ROUND_INST_GEN
//#define ONE_QUANT_PER_ROUND
using namespace std;
using namespace CVC4::theory::quantifiers;
using namespace CVC4::theory::inst;
-ModelEngineBuilder::ModelEngineBuilder( QuantifiersEngine* qe ) :
-TheoryEngineModelBuilder( qe->getTheoryEngine() ),
-d_qe( qe ){
-
-}
-
-Node ModelEngineBuilder::chooseRepresentative( TheoryModel* tm, Node eqc ){
- return eqc;
-}
-
-void ModelEngineBuilder::processBuildModel( TheoryModel* m ) {
- d_addedLemmas = 0;
- //only construct first order model if optUseModel() is true
- if( optUseModel() ){
- FirstOrderModel* fm = (FirstOrderModel*)m;
- //initialize model
- fm->initialize();
- //analyze the quantifiers
- Debug("fmf-model-debug") << "Analyzing quantifiers..." << std::endl;
- analyzeQuantifiers( fm );
- //if applicable, find exceptions
- if( optInstGen() ){
- //now, see if we know that any exceptions via InstGen exist
- Debug("fmf-model-debug") << "Perform InstGen techniques for quantifiers..." << std::endl;
- for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
- Node f = fm->getAssertedQuantifier( i );
- if( d_quant_sat.find( f )==d_quant_sat.end() ){
- d_addedLemmas += doInstGen( fm, f );
- if( optOneQuantPerRoundInstGen() && d_addedLemmas>0 ){
- break;
- }
- }
- }
- if( Options::current()->printModelEngine ){
- if( d_addedLemmas>0 ){
- Message() << "InstGen, added lemmas = " << d_addedLemmas << std::endl;
- }else{
- Message() << "No InstGen lemmas..." << std::endl;
- }
- }
- Debug("fmf-model-debug") << "---> Added lemmas = " << d_addedLemmas << std::endl;
- }
- if( d_addedLemmas==0 ){
- //if no immediate exceptions, build the model
- // this model will be an approximation that will need to be tested via exhaustive instantiation
- Debug("fmf-model-debug") << "Building model..." << std::endl;
- finishBuildModel( fm );
- }
- }
-}
-
-void ModelEngineBuilder::analyzeQuantifiers( FirstOrderModel* fm ){
- d_quant_selection_lits.clear();
- d_quant_sat.clear();
- d_uf_prefs.clear();
- int quantSatInit = 0;
- int nquantSatInit = 0;
- //analyze the preferences of each quantifier
- for( int i=0; i<(int)fm->getNumAssertedQuantifiers(); i++ ){
- Node f = fm->getAssertedQuantifier( i );
- Debug("fmf-model-prefs") << "Analyze quantifier " << f << std::endl;
- std::vector< Node > pro_con[2];
- std::vector< Node > constantSatOps;
- bool constantSatReconsider;
- //for each asserted quantifier f,
- // - determine which literals form model basis for each quantifier
- // - check which function/predicates have good and bad definitions according to f
- for( std::map< Node, bool >::iterator it = d_qe->d_phase_reqs[f].begin();
- it != d_qe->d_phase_reqs[f].end(); ++it ){
- Node n = it->first;
- Node gn = d_qe->getTermDatabase()->getModelBasis( n );
- Debug("fmf-model-req") << " Req: " << n << " -> " << it->second << std::endl;
- //calculate preference
- int pref = 0;
- bool value;
- if( d_qe->getValuation().hasSatValue( gn, value ) ){
- if( value!=it->second ){
- //store this literal as a model basis literal
- // this literal will force a default values in model that (modulo exceptions) shows
- // that f is satisfied by the model
- d_quant_selection_lits[f].push_back( value ? n : n.notNode() );
- pref = 1;
- }else{
- pref = -1;
- }
- }
- if( pref!=0 ){
- //Store preferences for UF
- bool isConst = !n.hasAttribute(InstConstantAttribute());
- std::vector< Node > uf_terms;
- if( gn.getKind()==APPLY_UF ){
- uf_terms.push_back( gn );
- isConst = fm->d_uf_model[gn.getOperator()].isConstant();
- }else if( gn.getKind()==EQUAL ){
- isConst = true;
- for( int j=0; j<2; j++ ){
- if( n[j].hasAttribute(InstConstantAttribute()) ){
- if( n[j].getKind()==APPLY_UF ){
- Node op = gn[j].getOperator();
- if( fm->d_uf_model.find( op )!=fm->d_uf_model.end() ){
- uf_terms.push_back( gn[j] );
- isConst = isConst && fm->d_uf_model[op].isConstant();
- }else{
- isConst = false;
- }
- }else{
- isConst = false;
- }
- }
- }
- }
- Debug("fmf-model-prefs") << " It is " << ( pref==1 ? "pro" : "con" );
- Debug("fmf-model-prefs") << " the definition of " << n << std::endl;
- if( pref==1 && isConst ){
- d_quant_sat[f] = true;
- //instead, just note to the model for each uf term that f is pro its definition
- constantSatReconsider = false;
- constantSatOps.clear();
- for( int j=0; j<(int)uf_terms.size(); j++ ){
- Node op = uf_terms[j].getOperator();
- constantSatOps.push_back( op );
- if( d_uf_prefs[op].d_reconsiderModel ){
- constantSatReconsider = true;
- }
- }
- if( !constantSatReconsider ){
- break;
- }
- }else{
- int pcIndex = pref==1 ? 0 : 1;
- for( int j=0; j<(int)uf_terms.size(); j++ ){
- pro_con[pcIndex].push_back( uf_terms[j] );
- }
- }
- }
- }
- if( d_quant_sat.find( f )!=d_quant_sat.end() ){
- Debug("fmf-model-prefs") << " * Constant SAT due to definition of ops: ";
- for( int i=0; i<(int)constantSatOps.size(); i++ ){
- Debug("fmf-model-prefs") << constantSatOps[i] << " ";
- d_uf_prefs[constantSatOps[i]].d_reconsiderModel = false;
- }
- Debug("fmf-model-prefs") << std::endl;
- quantSatInit++;
- d_statistics.d_pre_sat_quant += quantSatInit;
- }else{
- nquantSatInit++;
- d_statistics.d_pre_nsat_quant += quantSatInit;
- //note quantifier's value preferences to models
- for( int k=0; k<2; k++ ){
- for( int j=0; j<(int)pro_con[k].size(); j++ ){
- Node op = pro_con[k][j].getOperator();
- Node r = fm->getRepresentative( pro_con[k][j] );
- d_uf_prefs[op].setValuePreference( f, pro_con[k][j], r, k==0 );
- }
- }
- }
- }
- Debug("fmf-model-prefs") << "Pre-Model Completion: Quantifiers SAT: " << quantSatInit << " / " << (quantSatInit+nquantSatInit) << std::endl;
-}
-
-int ModelEngineBuilder::doInstGen( FirstOrderModel* fm, Node f ){
- //we wish to add all known exceptions to our model basis literal(s)
- // this will help to refine our current model.
- //This step is advantageous over exhaustive instantiation, since we are adding instantiations that involve model basis terms,
- // effectively acting as partial instantiations instead of pointwise instantiations.
- int addedLemmas = 0;
- for( int i=0; i<(int)d_quant_selection_lits[f].size(); i++ ){
- bool phase = d_quant_selection_lits[f][i].getKind()!=NOT;
- Node lit = d_quant_selection_lits[f][i].getKind()==NOT ? d_quant_selection_lits[f][i][0] : d_quant_selection_lits[f][i];
- Assert( lit.hasAttribute(InstConstantAttribute()) );
- std::vector< Node > tr_terms;
- if( lit.getKind()==APPLY_UF ){
- //only match predicates that are contrary to this one, use literal matching
- Node eq = NodeManager::currentNM()->mkNode( IFF, lit, !phase ? fm->d_true : fm->d_false );
- fm->getTermDatabase()->setInstantiationConstantAttr( eq, f );
- tr_terms.push_back( eq );
- }else if( lit.getKind()==EQUAL ){
- //collect trigger terms
- for( int j=0; j<2; j++ ){
- if( lit[j].hasAttribute(InstConstantAttribute()) ){
- if( lit[j].getKind()==APPLY_UF ){
- tr_terms.push_back( lit[j] );
- }else{
- tr_terms.clear();
- break;
- }
- }
- }
- if( tr_terms.size()==1 && !phase ){
- //equality between a function and a ground term, use literal matching
- tr_terms.clear();
- tr_terms.push_back( lit );
- }
- }
- //if applicable, try to add exceptions here
- if( !tr_terms.empty() ){
- //make a trigger for these terms, add instantiations
- Trigger* tr = Trigger::mkTrigger( d_qe, f, tr_terms );
- //Notice() << "Trigger = " << (*tr) << std::endl;
- tr->resetInstantiationRound();
- tr->reset( Node::null() );
- //d_qe->d_optInstMakeRepresentative = false;
- //d_qe->d_optMatchIgnoreModelBasis = true;
- addedLemmas += tr->addInstantiations( d_quant_basis_match[f] );
- }
- }
- return addedLemmas;
-}
-
-void ModelEngineBuilder::finishBuildModel( FirstOrderModel* fm ){
- //build model for UF
- for( std::map< Node, uf::UfModel >::iterator it = fm->d_uf_model.begin(); it != fm->d_uf_model.end(); ++it ){
- finishBuildModelUf( fm, it->second );
- }
- //build model for arrays
- for( std::map< Node, Node >::iterator it = fm->d_array_model.begin(); it != fm->d_array_model.end(); ++it ){
- //consult the model basis select term
- // i.e. the default value for array A is the value of select( A, e ), where e is the model basis term
- TypeNode tn = it->first.getType();
- Node selModelBasis = NodeManager::currentNM()->mkNode( SELECT, it->first, fm->getTermDatabase()->getModelBasisTerm( tn[0] ) );
- it->second = fm->getRepresentative( selModelBasis );
- }
- Debug("fmf-model-debug") << "Done building models." << std::endl;
-}
-
-void ModelEngineBuilder::finishBuildModelUf( FirstOrderModel* fm, uf::UfModel& model ){
- Node op = model.getOperator();
-#ifdef RECONSIDER_FUNC_CONSTANT
- if( model.isModelConstructed() && model.isConstant() ){
- if( d_uf_prefs[op].d_reconsiderModel ){
- //if we are allowed to reconsider default value, then see if the default value can be improved
- Node t = d_qe->getTermDatabase()->getModelBasisOpTerm( op );
- Node v = model.getConstantValue( t );
- if( d_uf_prefs[op].d_value_pro_con[0][v].empty() ){
- Debug("fmf-model-cons-debug") << "Consider changing the default value for " << op << std::endl;
- model.clearModel();
- }
- }
- }
-#endif
- if( !model.isModelConstructed() ){
- //construct the model for the uninterpretted function/predicate
- bool setDefaultVal = true;
- Node defaultTerm = d_qe->getTermDatabase()->getModelBasisOpTerm( op );
- Debug("fmf-model-cons") << "Construct model for " << op << "..." << std::endl;
- //set the values in the model
- for( size_t i=0; i<model.d_ground_asserts.size(); i++ ){
- Node n = model.d_ground_asserts[i];
- Node v = model.d_ground_asserts_reps[i];
- //if this assertion did not help the model, just consider it ground
- //set n = v in the model tree
- Debug("fmf-model-cons") << " Set " << n << " = ";
- fm->printRepresentativeDebug( "fmf-model-cons", v );
- Debug("fmf-model-cons") << std::endl;
- //set it as ground value
- model.setValue( n, v );
- if( model.optUsePartialDefaults() ){
- //also set as default value if necessary
- //if( n.getAttribute(ModelBasisArgAttribute())==1 && !d_term_pro_con[0][n].empty() ){
- if( n.hasAttribute(ModelBasisArgAttribute()) && n.getAttribute(ModelBasisArgAttribute())==1 ){
- model.setValue( n, v, false );
- if( n==defaultTerm ){
- //incidentally already set, we will not need to find a default value
- setDefaultVal = false;
- }
- }
- }else{
- if( n==defaultTerm ){
- model.setValue( n, v, false );
- //incidentally already set, we will not need to find a default value
- setDefaultVal = false;
- }
- }
- }
- //set the overall default value if not set already (is this necessary??)
- if( setDefaultVal ){
- Debug("fmf-model-cons") << " Choose default value..." << std::endl;
- //chose defaultVal based on heuristic, currently the best ratio of "pro" responses
- Node defaultVal = d_uf_prefs[op].getBestDefaultValue( defaultTerm, fm );
- Assert( !defaultVal.isNull() );
- model.setValue( defaultTerm, defaultVal, false );
- }
- Debug("fmf-model-cons") << " Making model...";
- model.setModel();
- Debug("fmf-model-cons") << " Finished constructing model for " << op << "." << std::endl;
- }
-}
-
-bool ModelEngineBuilder::optUseModel() {
- return Options::current()->fmfModelBasedInst;
-}
-
-bool ModelEngineBuilder::optInstGen(){
- return Options::current()->fmfInstGen;
-}
-
-bool ModelEngineBuilder::optOneQuantPerRoundInstGen(){
-#ifdef ONE_QUANT_PER_ROUND_INST_GEN
- return true;
-#else
- return false;
-#endif
-}
-
-ModelEngineBuilder::Statistics::Statistics():
- d_pre_sat_quant("ModelEngineBuilder::Status_quant_pre_sat", 0),
- d_pre_nsat_quant("ModelEngineBuilder::Status_quant_pre_non_sat", 0)
-{
- StatisticsRegistry::registerStat(&d_pre_sat_quant);
- StatisticsRegistry::registerStat(&d_pre_nsat_quant);
-}
-
-ModelEngineBuilder::Statistics::~Statistics(){
- StatisticsRegistry::unregisterStat(&d_pre_sat_quant);
- StatisticsRegistry::unregisterStat(&d_pre_nsat_quant);
-}
-
//Model Engine constructor
ModelEngine::ModelEngine( QuantifiersEngine* qe ) :
QuantifiersModule( qe ),
//CVC4 will answer SAT
Debug("fmf-consistent") << std::endl;
debugPrint("fmf-consistent");
+ // finish building the model in the standard way
+ d_builder.finishProcessBuildModel( d_quantEngine->getModel() );
}else{
//otherwise, the search will continue
d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
}
}
d_statistics.d_eval_formulas += reval.d_eval_formulas;
- d_statistics.d_eval_eqs += reval.d_eval_eqs;
d_statistics.d_eval_uf_terms += reval.d_eval_uf_terms;
+ d_statistics.d_eval_lits += reval.d_eval_lits;
+ d_statistics.d_eval_lits_unknown += reval.d_eval_lits_unknown;
int totalInst = 1;
int relevantInst = 1;
for( size_t i=0; i<f[0].getNumChildren(); i++ ){
- totalInst = totalInst * (int)d_quantEngine->getModel()->d_ra.d_type_reps[ f[0][i].getType() ].size();
+ totalInst = totalInst * (int)d_quantEngine->getModel()->d_rep_set.d_type_reps[ f[0][i].getType() ].size();
relevantInst = relevantInst * (int)riter.d_domain[i].size();
}
d_totalLemmas += totalInst;
ModelEngine::Statistics::Statistics():
d_inst_rounds("ModelEngine::Inst_Rounds", 0),
d_eval_formulas("ModelEngine::Eval_Formulas", 0 ),
- d_eval_eqs("ModelEngine::Eval_Equalities", 0 ),
d_eval_uf_terms("ModelEngine::Eval_Uf_Terms", 0 ),
+ d_eval_lits("ModelEngine::Eval_Lits", 0 ),
+ d_eval_lits_unknown("ModelEngine::Eval_Lits_Unknown", 0 ),
d_num_quants_init("ModelEngine::Num_Quants", 0 ),
d_num_quants_init_fail("ModelEngine::Num_Quants_No_Basis", 0 )
{
StatisticsRegistry::registerStat(&d_inst_rounds);
StatisticsRegistry::registerStat(&d_eval_formulas);
- StatisticsRegistry::registerStat(&d_eval_eqs);
StatisticsRegistry::registerStat(&d_eval_uf_terms);
+ StatisticsRegistry::registerStat(&d_eval_lits);
+ StatisticsRegistry::registerStat(&d_eval_lits_unknown);
StatisticsRegistry::registerStat(&d_num_quants_init);
StatisticsRegistry::registerStat(&d_num_quants_init_fail);
}
ModelEngine::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_inst_rounds);
StatisticsRegistry::unregisterStat(&d_eval_formulas);
- StatisticsRegistry::unregisterStat(&d_eval_eqs);
StatisticsRegistry::unregisterStat(&d_eval_uf_terms);
+ StatisticsRegistry::unregisterStat(&d_eval_lits);
+ StatisticsRegistry::unregisterStat(&d_eval_lits_unknown);
StatisticsRegistry::unregisterStat(&d_num_quants_init);
StatisticsRegistry::unregisterStat(&d_num_quants_init_fail);
}
** See the file COPYING in the top-level source directory for licensing
** information.\endverbatim
**
- ** \brief Model Engine classes
+ ** \brief Model Engine class
**/
#include "cvc4_private.h"
-#ifndef __CVC4__MODEL_ENGINE_H
-#define __CVC4__MODEL_ENGINE_H
+#ifndef __CVC4__QUANTIFIERS_MODEL_ENGINE_H
+#define __CVC4__QUANTIFIERS_MODEL_ENGINE_H
#include "theory/quantifiers_engine.h"
-#include "theory/quantifiers/theory_quantifiers.h"
+#include "theory/quantifiers/model_builder.h"
#include "theory/model.h"
-#include "theory/uf/theory_uf_model.h"
#include "theory/quantifiers/relevant_domain.h"
namespace CVC4 {
namespace theory {
-
-namespace uf{
- class StrongSolverTheoryUf;
-}
-
namespace quantifiers {
-
-//the model builder
-class ModelEngineBuilder : public TheoryEngineModelBuilder
-{
-protected:
- //quantifiers engine
- QuantifiersEngine* d_qe;
- //map from operators to model preference data
- std::map< Node, uf::UfModelPreferenceData > d_uf_prefs;
- /** choose representative */
- Node chooseRepresentative( TheoryModel* tm, Node eqc );
- /** use constants for representatives */
- void processBuildModel( TheoryModel* m );
- //analyze quantifiers
- void analyzeQuantifiers( FirstOrderModel* fm );
- //build model
- void finishBuildModel( FirstOrderModel* fm );
- //theory-specific build models
- void finishBuildModelUf( FirstOrderModel* fm, uf::UfModel& model );
- //do InstGen techniques for quantifier, return number of lemmas produced
- int doInstGen( FirstOrderModel* fm, Node f );
-public:
- ModelEngineBuilder( QuantifiersEngine* qe );
- virtual ~ModelEngineBuilder(){}
-public:
- /** number of lemmas generated while building model */
- int d_addedLemmas;
- //map from quantifiers to if are constant SAT
- std::map< Node, bool > d_quant_sat;
- //map from quantifiers to the instantiation literals that their model is dependent upon
- std::map< Node, std::vector< Node > > d_quant_selection_lits;
-public:
- //map from quantifiers to model basis match
- std::map< Node, InstMatch > d_quant_basis_match;
- //options
- bool optUseModel();
- bool optInstGen();
- bool optOneQuantPerRoundInstGen();
- /** statistics class */
- class Statistics {
- public:
- IntStat d_pre_sat_quant;
- IntStat d_pre_nsat_quant;
- Statistics();
- ~Statistics();
- };
- Statistics d_statistics;
-};
-
class ModelEngine : public QuantifiersModule
{
- friend class uf::UfModel;
friend class RepSetIterator;
private:
/** builder class */
public:
IntStat d_inst_rounds;
IntStat d_eval_formulas;
- IntStat d_eval_eqs;
IntStat d_eval_uf_terms;
+ IntStat d_eval_lits;
+ IntStat d_eval_lits_unknown;
IntStat d_num_quants_init;
IntStat d_num_quants_init_fail;
Statistics();
d_quant_inst_domain[f].resize( f[0].getNumChildren() );\r
}\r
//add ground terms to domain (rule 1 of complete instantiation essentially uf fragment)\r
- for( std::map< Node, uf::UfModel >::iterator it = d_model->d_uf_model.begin();\r
- it != d_model->d_uf_model.end(); ++it ){\r
+ for( std::map< Node, uf::UfModelTree >::iterator it = d_model->d_uf_model_tree.begin();\r
+ it != d_model->d_uf_model_tree.end(); ++it ){\r
Node op = it->first;\r
- for( int i=0; i<(int)it->second.d_ground_asserts.size(); i++ ){\r
- Node n = it->second.d_ground_asserts[i];\r
+ for( size_t i=0; i<d_model->d_uf_terms[op].size(); i++ ){\r
+ Node n = d_model->d_uf_terms[op][i];\r
//add arguments to domain\r
for( int j=0; j<(int)n.getNumChildren(); j++ ){\r
- if( d_model->d_ra.hasType( n[j].getType() ) ){\r
+ if( d_model->d_rep_set.hasType( n[j].getType() ) ){\r
Node ra = d_model->getRepresentative( n[j] );\r
- int raIndex = d_model->d_ra.getIndexFor( ra );\r
+ int raIndex = d_model->d_rep_set.getIndexFor( ra );\r
Assert( raIndex!=-1 );\r
if( std::find( d_active_domain[op][j].begin(), d_active_domain[op][j].end(), raIndex )==d_active_domain[op][j].end() ){\r
d_active_domain[op][j].push_back( raIndex );\r
}\r
}\r
//add to range\r
- Node r = it->second.d_ground_asserts_reps[i];\r
- int raIndex = d_model->d_ra.getIndexFor( r );\r
+ Node r = d_model->getRepresentative( n );\r
+ int raIndex = d_model->d_rep_set.getIndexFor( r );\r
Assert( raIndex!=-1 );\r
if( std::find( d_active_range[op].begin(), d_active_range[op].end(), raIndex )==d_active_range[op].end() ){\r
d_active_range[op].push_back( raIndex );\r
if( !domainSet ){\r
//otherwise, we must consider the entire domain\r
TypeNode tn = n.getType();\r
- if( d_model->d_ra.hasType( tn ) ){\r
- if( rd[vi].size()!=d_model->d_ra.d_type_reps[tn].size() ){\r
+ if( d_model->d_rep_set.hasType( tn ) ){\r
+ if( rd[vi].size()!=d_model->d_rep_set.d_type_reps[tn].size() ){\r
rd[vi].clear();\r
- for( size_t i=0; i<d_model->d_ra.d_type_reps[tn].size(); i++ ){\r
+ for( size_t i=0; i<d_model->d_rep_set.d_type_reps[tn].size(); i++ ){\r
rd[vi].push_back( i );\r
domainChanged = true;\r
}\r
}\r
}else{\r
Node r = d_model->getRepresentative( n );\r
- range.push_back( d_model->d_ra.getIndexFor( r ) );\r
+ range.push_back( d_model->d_rep_set.getIndexFor( r ) );\r
}\r
return domainChanged;\r
}\r
d_var_order[i] = i;\r
//store default domain\r
d_domain.push_back( RepDomain() );\r
- for( int j=0; j<(int)d_model->d_ra.d_type_reps[d_f[0][i].getType()].size(); j++ ){\r
- d_domain[i].push_back( j );\r
+ TypeNode tn = d_f[0][i].getType();\r
+ if( tn.isSort() ){\r
+ if( d_model->d_rep_set.hasType( tn ) ){\r
+ for( int j=0; j<(int)d_model->d_rep_set.d_type_reps[d_f[0][i].getType()].size(); j++ ){\r
+ d_domain[i].push_back( j );\r
+ }\r
+ }else{\r
+ Unimplemented("Cannot create instantiation iterator for unknown uninterpretted sort");\r
+ }\r
+ }else if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){\r
+ Unimplemented("Cannot create instantiation iterator for arithmetic quantifier");\r
+ }else if( tn.isDatatype() ){\r
+ const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();\r
+ //if finite, then use type enumerator\r
+ if( dt.isFinite() ){\r
+ //DO_THIS: use type enumerator\r
+ Unimplemented("Not yet implemented: instantiation iterator for finite datatype quantifier");\r
+ }else{\r
+ Unimplemented("Cannot create instantiation iterator for infinite datatype quantifier");\r
+ }\r
+ }else{\r
+ Unimplemented("Cannot create instantiation iterator for quantifier");\r
}\r
}\r
}\r
\r
Node RepSetIterator::getTerm( int i ){\r
TypeNode tn = d_f[0][d_index_order[i]].getType();\r
- Assert( d_model->d_ra.d_type_reps.find( tn )!=d_model->d_ra.d_type_reps.end() );\r
+ Assert( d_model->d_rep_set.d_type_reps.find( tn )!=d_model->d_rep_set.d_type_reps.end() );\r
int index = d_index_order[i];\r
- return d_model->d_ra.d_type_reps[tn][d_domain[index][d_index[index]]];\r
+ return d_model->d_rep_set.d_type_reps[tn][d_domain[index][d_index[index]]];\r
}\r
\r
void RepSetIterator::debugPrint( const char* c ){\r
}\r
\r
RepSetEvaluator::RepSetEvaluator( FirstOrderModel* m, RepSetIterator* ri ) : d_model( m ), d_riter( ri ){\r
-\r
+ d_eval_formulas = 0;\r
+ d_eval_uf_terms = 0;\r
+ d_eval_lits = 0;\r
+ d_eval_lits_unknown = 0;\r
}\r
\r
-//if evaluate( n, phaseReq ) = eVal,\r
-// if eVal = d_riter->d_index.size()\r
-// then the formula n instantiated with d_riter cannot be proven to be equal to phaseReq\r
-// otherwise,\r
-// each n{d_riter->d_index[0]/x_0...d_riter->d_index[eVal]/x_eVal, */x_(eVal+1) ... */x_n } is equal to phaseReq in the current model\r
+//if evaluate( n ) = eVal,\r
+// let n' = d_riter * n be the formula n instantiated with the current values in r_iter\r
+// if eVal = 1, then n' is true, if eVal = -1, then n' is false,\r
+// if eVal = 0, then n' cannot be proven to be equal to phaseReq\r
+// if eVal is not 0, then\r
+// each n{d_riter->d_index[0]/x_0...d_riter->d_index[depIndex]/x_depIndex, */x_(depIndex+1) ... */x_n } is equivalent in the current model\r
int RepSetEvaluator::evaluate( Node n, int& depIndex ){\r
++d_eval_formulas;\r
//Debug("fmf-eval-debug") << "Evaluate " << n << " " << phaseReq << std::endl;\r
}else if( n.getKind()==FORALL ){\r
return 0;\r
}else{\r
+ ++d_eval_lits;\r
////if we know we will fail again, immediately return\r
//if( d_eval_failed.find( n )!=d_eval_failed.end() ){\r
// if( d_eval_failed[n] ){\r
// }\r
//}\r
//Debug("fmf-eval-debug") << "Evaluate literal " << n << std::endl;\r
- //this should be a literal\r
- //Node gn = n.substitute( d_riter->d_ic.begin(), d_riter->d_ic.end(), d_riter->d_terms.begin(), d_riter->d_terms.end() );\r
- //Debug("fmf-eval-debug") << " Ground version = " << gn << std::endl;\r
int retVal = 0;\r
depIndex = d_riter->getNumTerms()-1;\r
- if( n.getKind()==APPLY_UF ){\r
- //case for boolean predicates\r
- Node val = evaluateTerm( n, depIndex );\r
- if( d_model->hasTerm( val ) ){\r
- if( d_model->areEqual( val, d_model->d_true ) ){\r
- retVal = 1;\r
- }else{\r
- retVal = -1;\r
- }\r
- }\r
- }else if( n.getKind()==EQUAL ){\r
- //case for equality\r
- retVal = evaluateEquality( n[0], n[1], depIndex );\r
- }else{\r
- std::vector< int > cdi;\r
- Node val = evaluateTermDefault( n, depIndex, cdi );\r
- if( !val.isNull() ){\r
- val = Rewriter::rewrite( val );\r
- if( val==d_model->d_true ){\r
- retVal = 1;\r
- }else if( val==d_model->d_false ){\r
- retVal = -1;\r
+ Node val = evaluateTerm( n, depIndex );\r
+ if( !val.isNull() ){\r
+ if( d_model->areEqual( val, d_model->d_true ) ){\r
+ retVal = 1;\r
+ }else if( d_model->areEqual( val, d_model->d_false ) ){\r
+ retVal = -1;\r
+ }else{\r
+ if( val.getKind()==EQUAL ){\r
+ if( d_model->areEqual( val[0], val[1] ) ){\r
+ retVal = 1;\r
+ }else if( d_model->areDisequal( val[0], val[1] ) ){\r
+ retVal = -1;\r
+ }\r
}\r
}\r
}\r
if( retVal!=0 ){\r
- Debug("fmf-eval-debug") << "Evaluate literal: return " << retVal << ", depends = " << depIndex << std::endl;\r
+ Debug("fmf-eval-debug") << "Evaluate literal: return " << retVal << ", depIndex = " << depIndex << std::endl;\r
}else{\r
+ ++d_eval_lits_unknown;\r
Debug("fmf-eval-amb") << "Neither true nor false : " << n << std::endl;\r
//std::cout << "Neither true nor false : " << n << std::endl;\r
+ //std::cout << " Value : " << val << std::endl;\r
+ //for( int i=0; i<(int)n.getNumChildren(); i++ ){\r
+ // std::cout << " " << i << " : " << n[i].getType() << std::endl;\r
+ //}\r
}\r
return retVal;\r
}\r
}\r
\r
-int RepSetEvaluator::evaluateEquality( Node n1, Node n2, int& depIndex ){\r
- ++d_eval_eqs;\r
- //Notice() << "Eval eq " << n1 << " " << n2 << std::endl;\r
- Debug("fmf-eval-debug") << "Evaluate equality: " << std::endl;\r
- Debug("fmf-eval-debug") << " " << n1 << " = " << n2 << std::endl;\r
- int depIndex1, depIndex2;\r
- Node val1 = evaluateTerm( n1, depIndex1 );\r
- Node val2 = evaluateTerm( n2, depIndex2 );\r
- Debug("fmf-eval-debug") << " Values : ";\r
- d_model->printRepresentativeDebug( "fmf-eval-debug", val1 );\r
- Debug("fmf-eval-debug") << " = ";\r
- d_model->printRepresentativeDebug( "fmf-eval-debug", val2 );\r
- Debug("fmf-eval-debug") << std::endl;\r
- int retVal = 0;\r
- if( !val1.isNull() && !val2.isNull() ){\r
- if( d_model->areEqual( val1, val2 ) ){\r
- retVal = 1;\r
- }else if( d_model->areDisequal( val1, val2 ) ){\r
- retVal = -1;\r
- }else{\r
- Node eq = val1.eqNode( val2 );\r
- eq = Rewriter::rewrite( eq );\r
- if( eq==d_model->d_true ){\r
- retVal = 1;\r
- }else if( eq==d_model->d_false ){\r
- retVal = -1;\r
- }\r
- }\r
- }\r
- if( retVal!=0 ){\r
- depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;\r
- Debug("fmf-eval-debug") << " value = " << (retVal==1) << ", depIndex = " << depIndex << std::endl;\r
- }else{\r
- depIndex = d_riter->getNumTerms()-1;\r
- Debug("fmf-eval-amb") << "Neither equal nor disequal : " << n1 << " , " << n2 << std::endl;\r
- //std::cout << "Neither equal nor disequal : " << n1 << " , " << n2 << std::endl;\r
- }\r
- return retVal;\r
-}\r
-\r
Node RepSetEvaluator::evaluateTerm( Node n, int& depIndex ){\r
- //Notice() << "Eval term " << n << std::endl;\r
- if( n.hasAttribute(InstConstantAttribute()) ){\r
+ //Message() << "Eval term " << n << std::endl;\r
+ if( !n.hasAttribute(InstConstantAttribute()) ){\r
+ //if evaluating a ground term, just consult the standard getValue functionality\r
+ depIndex = -1;\r
+ return d_model->getValue( n );\r
+ }else{\r
Node val;\r
depIndex = d_riter->getNumTerms()-1;\r
//check the type of n\r
if( eval==0 ){\r
//evaluate children to see if they are the same\r
Node val1 = evaluateTerm( n[ 1 ], depIndex1 );\r
- Node val2 = evaluateTerm( n[ 1 ], depIndex1 );\r
+ Node val2 = evaluateTerm( n[ 2 ], depIndex2 );\r
if( val1==val2 ){\r
val = val1;\r
depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;\r
depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;\r
}\r
}else{\r
-#if 0\r
+ std::vector< int > children_depIndex;\r
//for select, pre-process read over writes\r
if( n.getKind()==SELECT ){\r
- Node selIndex = evaluateTerm( n[1], depIndex );\r
- if( selIndex.isNull() ){\r
+#if 1\r
+ //std::cout << "Evaluate " << n << std::endl;\r
+ Node sel = evaluateTerm( n[1], depIndex );\r
+ if( sel.isNull() ){\r
depIndex = d_riter->getNumTerms()-1;\r
return Node::null();\r
}\r
- Node arr = n[0];\r
+ Node arr = d_model->getRepresentative( n[0] );\r
+ //if( n[0]!=d_model->getRepresentative( n[0] ) ){\r
+ // std::cout << n[0] << " is " << d_model->getRepresentative( n[0] ) << std::endl;\r
+ //}\r
+ int tempIndex;\r
int eval = 1;\r
while( arr.getKind()==STORE && eval!=0 ){\r
- int tempIndex;\r
- eval = evaluateEquality( selIndex, arr[1], tempIndex );\r
+ eval = evaluate( sel.eqNode( arr[1] ), tempIndex );\r
depIndex = tempIndex > depIndex ? tempIndex : depIndex;\r
if( eval==1 ){\r
val = evaluateTerm( arr[2], tempIndex );\r
arr = arr[0];\r
}\r
}\r
- n = NodeManager::currentNM()->mkNode( SELECT, arr, selIndex );\r
- }\r
+ arr = evaluateTerm( arr, tempIndex );\r
+ depIndex = tempIndex > depIndex ? tempIndex : depIndex;\r
+ val = NodeManager::currentNM()->mkNode( SELECT, arr, sel );\r
+#else\r
+ val = evaluateTermDefault( n, depIndex, children_depIndex );\r
#endif\r
- //default term evaluate : evaluate all children, recreate the value\r
- std::vector< int > children_depIndex;\r
- val = evaluateTermDefault( n, depIndex, children_depIndex );\r
- //case split on the type of term\r
- if( n.getKind()==APPLY_UF ){\r
- Node op = n.getOperator();\r
- //Debug("fmf-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl;\r
- //if it is a defined UF, then consult the interpretation\r
- ++d_eval_uf_terms;\r
- int argDepIndex = 0;\r
- if( d_model->d_uf_model.find( op )!=d_model->d_uf_model.end() ){\r
- //make the term model specifically for n\r
- makeEvalUfModel( n );\r
- //now, consult the model\r
- if( d_eval_uf_use_default[n] ){\r
- val = d_model->d_uf_model[op].d_tree.getValue( d_model, val, argDepIndex );\r
- }else{\r
- val = d_eval_uf_model[ n ].getValue( d_model, val, argDepIndex );\r
- }\r
+ }else{\r
+ //default term evaluate : evaluate all children, recreate the value\r
+ val = evaluateTermDefault( n, depIndex, children_depIndex );\r
+ }\r
+ if( !val.isNull() ){\r
+ bool setVal = false;\r
+ //custom ways of evaluating terms\r
+ if( n.getKind()==APPLY_UF ){\r
+ Node op = n.getOperator();\r
//Debug("fmf-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl;\r
- //d_eval_uf_model[ n ].debugPrint("fmf-eval-debug", d_qe );\r
- Assert( !val.isNull() );\r
- }else{\r
- d_eval_uf_use_default[n] = true;\r
- argDepIndex = (int)n.getNumChildren();\r
+ //if it is a defined UF, then consult the interpretation\r
+ if( d_model->d_uf_model_tree.find( op )!=d_model->d_uf_model_tree.end() ){\r
+ ++d_eval_uf_terms;\r
+ int argDepIndex = 0;\r
+ //make the term model specifically for n\r
+ makeEvalUfModel( n );\r
+ //now, consult the model\r
+ if( d_eval_uf_use_default[n] ){\r
+ val = d_model->d_uf_model_tree[op].getValue( d_model, val, argDepIndex );\r
+ }else{\r
+ val = d_eval_uf_model[ n ].getValue( d_model, val, argDepIndex );\r
+ }\r
+ //Debug("fmf-eval-debug") << "Evaluate term " << n << " (" << gn << ")" << std::endl;\r
+ //d_eval_uf_model[ n ].debugPrint("fmf-eval-debug", d_qe );\r
+ Assert( !val.isNull() );\r
+ //recalculate the depIndex\r
+ depIndex = -1;\r
+ for( int i=0; i<argDepIndex; i++ ){\r
+ int index = d_eval_uf_use_default[n] ? i : d_eval_term_index_order[n][i];\r
+ Debug("fmf-eval-debug") << "Add variables from " << index << "..." << std::endl;\r
+ if( children_depIndex[index]>depIndex ){\r
+ depIndex = children_depIndex[index];\r
+ }\r
+ }\r
+ setVal = true;\r
+ }\r
+ }else if( n.getKind()==SELECT ){\r
+ //we are free to interpret this term however we want\r
}\r
- //recalculate the depIndex\r
- depIndex = -1;\r
- for( int i=0; i<argDepIndex; i++ ){\r
- int index = d_eval_uf_use_default[n] ? i : d_eval_term_index_order[n][i];\r
- Debug("fmf-eval-debug") << "Add variables from " << index << "..." << std::endl;\r
- if( children_depIndex[index]>depIndex ){\r
- depIndex = children_depIndex[index];\r
+ //if not set already, rewrite and consult model for interpretation\r
+ if( !setVal ){\r
+ val = Rewriter::rewrite( val );\r
+ if( val.getMetaKind()!=kind::metakind::CONSTANT ){\r
+ //FIXME: we cannot do this until we trust all theories collectModelInfo!\r
+ //val = d_model->getInterpretedValue( val );\r
+ //val = d_model->getRepresentative( val );\r
}\r
}\r
Debug("fmf-eval-debug") << "Evaluate term " << n << " = ";\r
d_model->printRepresentativeDebug( "fmf-eval-debug", val );\r
Debug("fmf-eval-debug") << ", depIndex = " << depIndex << std::endl;\r
- }else if( n.getKind()==SELECT ){\r
- if( d_model->d_array_model.find( n[0] )!=d_model->d_array_model.end() ){\r
- //consult the default value for the array DO_THIS\r
- //val = Rewriter::rewrite( val );\r
- //val = d_model->d_array_model[ n[0] ];\r
- val = Rewriter::rewrite( val );\r
- }else{\r
- val = Rewriter::rewrite( val );\r
- }\r
- }else{\r
- val = Rewriter::rewrite( val );\r
}\r
}\r
return val;\r
- }else{\r
- depIndex = -1;\r
- return n;\r
}\r
}\r
\r
Node RepSetEvaluator::evaluateTermDefault( Node n, int& depIndex, std::vector< int >& childDepIndex ){\r
- //first we must evaluate the arguments\r
- std::vector< Node > children;\r
- if( n.getMetaKind()==kind::metakind::PARAMETERIZED ){\r
- children.push_back( n.getOperator() );\r
- }\r
depIndex = -1;\r
- //for each argument, calculate its value, and the variables its value depends upon\r
- for( int i=0; i<(int)n.getNumChildren(); i++ ){\r
- childDepIndex.push_back( -1 );\r
- Node nn = evaluateTerm( n[i], childDepIndex[i] );\r
- if( nn.isNull() ){\r
- depIndex = d_riter->getNumTerms()-1;\r
- return nn;\r
- }else{\r
- children.push_back( nn );\r
- if( childDepIndex[i]>depIndex ){\r
- depIndex = childDepIndex[i];\r
+ if( n.getNumChildren()==0 ){\r
+ return n;\r
+ }else{\r
+ //first we must evaluate the arguments\r
+ std::vector< Node > children;\r
+ if( n.getMetaKind()==kind::metakind::PARAMETERIZED ){\r
+ children.push_back( n.getOperator() );\r
+ }\r
+ //for each argument, calculate its value, and the variables its value depends upon\r
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){\r
+ childDepIndex.push_back( -1 );\r
+ Node nn = evaluateTerm( n[i], childDepIndex[i] );\r
+ if( nn.isNull() ){\r
+ depIndex = d_riter->getNumTerms()-1;\r
+ return nn;\r
+ }else{\r
+ children.push_back( nn );\r
+ if( childDepIndex[i]>depIndex ){\r
+ depIndex = childDepIndex[i];\r
+ }\r
}\r
}\r
+ //recreate the value\r
+ Node val = NodeManager::currentNM()->mkNode( n.getKind(), children );\r
+ return val;\r
}\r
- //recreate the value\r
- return NodeManager::currentNM()->mkNode( n.getKind(), children );\r
}\r
\r
void RepSetEvaluator::clearEvalFailed( int index ){\r
makeEvalUfIndexOrder( n );\r
if( !d_eval_uf_use_default[n] ){\r
Node op = n.getOperator();\r
- d_eval_uf_model[n] = uf::UfModelTreeOrdered( op, d_eval_term_index_order[n] );\r
- d_model->d_uf_model[op].makeModel( d_eval_uf_model[n] );\r
+ d_eval_uf_model[n] = uf::UfModelTree( op, d_eval_term_index_order[n] );\r
+ d_model->d_uf_model_gen[op].makeModel( d_model, d_eval_uf_model[n] );\r
//Debug("fmf-index-order") << "Make model for " << n << " : " << std::endl;\r
//d_eval_uf_model[n].debugPrint( "fmf-index-order", d_qe, 2 );\r
}\r
private: //for Theory UF:\r
//map from terms to the models used to calculate their value\r
std::map< Node, bool > d_eval_uf_use_default;\r
- std::map< Node, uf::UfModelTreeOrdered > d_eval_uf_model;\r
+ std::map< Node, uf::UfModelTree > d_eval_uf_model;\r
void makeEvalUfModel( Node n );\r
//index ordering to use for each term\r
std::map< Node, std::vector< int > > d_eval_term_index_order;\r
virtual ~RepSetEvaluator(){}\r
/** evaluate functions */\r
int evaluate( Node n, int& depIndex );\r
- int evaluateEquality( Node n1, Node n2, int& depIndex );\r
Node evaluateTerm( Node n, int& depIndex );\r
public:\r
//statistics\r
int d_eval_formulas;\r
- int d_eval_eqs;\r
int d_eval_uf_terms;\r
+ int d_eval_lits;\r
+ int d_eval_lits_unknown;\r
};\r
\r
\r
}
}
-void addTermEfficient( Node n, std::set< Node >& added){
+void TermDb::addTermEfficient( Node n, std::set< Node >& added){
static AvailableInTermDb aitdi;
if (Trigger::isAtomicTrigger( n ) && !n.getAttribute(aitdi)){
//Already processed but new in this branch
void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
- //don't add terms in quantifier bodies
+ //don't add terms in quantifier bodies
if( withinQuant && !Options::current()->registerQuantBodyTerms ){
return;
}
- if( d_processed.find( n )==d_processed.end() ){
+ if( d_processed.find( n )==d_processed.end() ){
++(d_quantEngine->d_statistics.d_term_in_termdb);
d_processed.insert(n);
+ d_type_map[ n.getType() ].push_back( n );
n.setAttribute(AvailableInTermDb(),true);
- //if this is an atomic trigger, consider adding it
+ //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;
+ if( Trigger::isAtomicTrigger( n ) ){
+ 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 );
+ Node op = n.getOperator();
+ d_op_map[op].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 );
+ 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() );
- }
- }
- }
- }
+ }
+ }
+ 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 );
- }
- }
+ 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);
- }
- }
-};
+ 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;
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() );
+ d_quantEngine->getEqualityQuery()->getEngine() );
while( !eqc.isFinished() ){
Node en = (*eqc);
if( en.getKind()==APPLY_UF && !en.hasAttribute(InstConstantAttribute()) ){
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 );
+ Node mbt;
+ if( d_type_map[ tn ].empty() ){
+ std::stringstream ss;
+ ss << Expr::setlanguage(Options::current()->outputLanguage);
+ ss << "e_" << tn;
+ mbt = NodeManager::currentNM()->mkVar( ss.str(), tn );
+ }else{
+ mbt = d_type_map[ tn ][ 0 ];
+ }
ModelBasisAttribute mba;
- d_model_basis_term[tn].setAttribute(mba,true);
+ mbt.setAttribute(mba,true);
+ d_model_basis_term[tn] = mbt;
}
return d_model_basis_term[tn];
}
void setMatchingActive( bool a ) { d_matching_active = a; }\r
/** get active */\r
bool getMatchingActive() { return d_matching_active; }\r
+private:\r
+ /** for efficient e-matching */\r
+ void addTermEfficient( Node n, std::set< Node >& added);\r
public:\r
/** parent structure (for efficient E-matching):\r
n -> op -> index -> L\r
#include "theory/quantifiers/instantiation_engine.h"
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/term_database.h"
+#include "theory/rr_candidate_generator.h"
using namespace std;
using namespace CVC4;
return d_qe->getInstantiator( THEORY_UF )->getInternalRepresentative( a );
}
+eq::EqualityEngine* EqualityQueryQuantifiersEngine::getEngine(){
+ return ((uf::TheoryUF*)d_qe->getTheoryEngine()->getTheory( THEORY_UF ))->getEqualityEngine();
+}
+
+void EqualityQueryQuantifiersEngine::getEquivalenceClass( Node a, std::vector< Node >& eqc ){
+ eq::EqualityEngine* ee = d_qe->getTheoryEngine()->getSharedTermsDatabase()->getEqualityEngine();
+ if( ee->hasTerm( a ) ){
+ Node rep = ee->getRepresentative( a );
+ eq::EqClassIterator eqc_iter( rep, ee );
+ while( !eqc_iter.isFinished() ){
+ eqc.push_back( *eqc_iter );
+ eqc_iter++;
+ }
+ }
+ for( theory::TheoryId i=theory::THEORY_FIRST; i<theory::THEORY_LAST; ++i ){
+ if( d_qe->getInstantiator( i ) ){
+ d_qe->getInstantiator( i )->getEquivalenceClass( a, eqc );
+ }
+ }
+ if( eqc.empty() ){
+ eqc.push_back( 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 */
}
-// // 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);
}
// if(eq == NULL) return getInstantiator(id)->getRRCanGenClass();
// else return eq;
return getRRCanGenClass();
-}
+}
\ No newline at end of file
bool areEqual( Node a, Node b );
bool areDisequal( Node a, Node b );
Node getInternalRepresentative( Node a );
+ eq::EqualityEngine* getEngine();
+ void getEquivalenceClass( Node a, std::vector< Node >& eqc );
}; /* EqualityQueryQuantifiersEngine */
}/* CVC4::theory namespace */
--- /dev/null
+/********************* */
+/*! \file rr_candidate_generator.cpp
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: bobot
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of rr candidate generator class
+ **/
+
+#include "theory/rr_candidate_generator.h"
+#include "theory/theory_engine.h"
+#include "theory/uf/theory_uf.h"
+#include "theory/quantifiers/term_database.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::rrinst;
+
+GenericCandidateGeneratorClasses::GenericCandidateGeneratorClasses(QuantifiersEngine * qe){
+ for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){
+ if(qe->getInstantiator(i) != NULL)
+ d_can_gen[i] = qe->getInstantiator(i)->getRRCanGenClasses();
+ else d_can_gen[i] = NULL;
+ }
+}
+
+GenericCandidateGeneratorClasses::~GenericCandidateGeneratorClasses(){
+ for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){
+ delete(d_can_gen[i]);
+ }
+}
+
+void GenericCandidateGeneratorClasses::resetInstantiationRound(){
+ for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){
+ if(d_can_gen[i] != NULL) d_can_gen[i]->resetInstantiationRound();
+ }
+ d_can_gen_id=THEORY_FIRST;
+}
+
+void GenericCandidateGeneratorClasses::reset(TNode eqc){
+ Assert(eqc.isNull());
+ for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){
+ if(d_can_gen[i] != NULL) d_can_gen[i]->reset(eqc);
+ }
+ d_can_gen_id=THEORY_FIRST;
+ lookForNextTheory();
+}
+
+TNode GenericCandidateGeneratorClasses::getNextCandidate(){
+ Assert(THEORY_FIRST <= d_can_gen_id && d_can_gen_id <= THEORY_LAST);
+ /** No more */
+ if(d_can_gen_id == THEORY_LAST) return TNode::null();
+ /** Try with this theory */
+ TNode cand = d_can_gen[d_can_gen_id]->getNextCandidate();
+ if( !cand.isNull() ) return cand;
+ lookForNextTheory();
+ return getNextCandidate();
+}
+
+void GenericCandidateGeneratorClasses::lookForNextTheory(){
+ do{ /* look for the next available generator */
+ ++d_can_gen_id;
+ } while( d_can_gen_id < THEORY_LAST && d_can_gen[d_can_gen_id] == NULL);
+}
+
+GenericCandidateGeneratorClass::GenericCandidateGeneratorClass(QuantifiersEngine * qe): d_qe(qe) {
+ for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){
+ if(d_qe->getInstantiator(i) != NULL)
+ d_can_gen[i] = d_qe->getInstantiator(i)->getRRCanGenClass();
+ else d_can_gen[i] = NULL;
+ }
+}
+
+GenericCandidateGeneratorClass::~GenericCandidateGeneratorClass(){
+ for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){
+ delete(d_can_gen[i]);
+ }
+}
+
+void GenericCandidateGeneratorClass::resetInstantiationRound(){
+ for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){
+ if(d_can_gen[i] != NULL) d_can_gen[i]->resetInstantiationRound();
+ }
+ d_can_gen_id=THEORY_FIRST;
+}
+
+void GenericCandidateGeneratorClass::reset(TNode eqc){
+ for(TheoryId i = THEORY_FIRST; i < theory::THEORY_LAST; ++i){
+ if(d_can_gen[i] != NULL) d_can_gen[i]->reset(eqc);
+ }
+ d_can_gen_id=THEORY_FIRST;
+ d_node = eqc;
+ lookForNextTheory();
+}
+
+TNode GenericCandidateGeneratorClass::getNextCandidate(){
+ Assert(THEORY_FIRST <= d_can_gen_id && d_can_gen_id <= THEORY_LAST);
+ /** No more */
+ if(d_can_gen_id == THEORY_LAST) return TNode::null();
+ /** Try with this theory */
+ TNode cand = d_can_gen[d_can_gen_id]->getNextCandidate();
+ if( !cand.isNull() ) return cand;
+ lookForNextTheory();
+ return getNextCandidate();
+}
+
+void GenericCandidateGeneratorClass::lookForNextTheory(){
+ do{ /* look for the next available generator, where the element is */
+ ++d_can_gen_id;
+ } while(
+ d_can_gen_id < THEORY_LAST &&
+ (d_can_gen[d_can_gen_id] == NULL ||
+ !d_qe->getInstantiator( d_can_gen_id )->hasTerm( d_node ))
+ );
+}
--- /dev/null
+/********************* */
+/*! \file rr_candidate_generator.h
+ ** \verbatim
+ ** Original author: ajreynol
+ ** Major contributors: bobot
+ ** Minor contributors (to current version): mdeters
+ ** This file is part of the CVC4 prototype.
+ ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys)
+ ** Courant Institute of Mathematical Sciences
+ ** New York University
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief rr candidate generator
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY_UF_CANDIDATE_GENERATOR_H
+#define __CVC4__THEORY_UF_CANDIDATE_GENERATOR_H
+
+#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/rr_inst_match.h"
+
+using namespace CVC4::theory::quantifiers;
+
+namespace CVC4 {
+namespace theory {
+namespace eq {
+
+namespace rrinst{
+typedef CVC4::theory::rrinst::CandidateGenerator CandidateGenerator;
+
+//New CandidateGenerator. They have a simpler semantic than the old one
+
+// Just iterate amoung the equivalence classes
+// node::Null() must be given to reset
+class CandidateGeneratorTheoryEeClasses : public CandidateGenerator{
+private:
+ //the equality classes iterator
+ eq::EqClassesIterator d_eq;
+ //equalityengine pointer
+ EqualityEngine* d_ee;
+public:
+ CandidateGeneratorTheoryEeClasses( EqualityEngine * ee): d_ee( ee ){}
+ ~CandidateGeneratorTheoryEeClasses(){}
+ void resetInstantiationRound(){};
+ void reset( TNode eqc ){
+ Assert(eqc.isNull());
+ d_eq = eq::EqClassesIterator( d_ee );
+ }; //* the argument is not used
+ TNode getNextCandidate(){
+ if( !d_eq.isFinished() ) return (*(d_eq++));
+ else return Node::null();
+ };
+};
+
+// Just iterate amoung the equivalence class of the given node
+// node::Null() *can't* be given to reset
+class CandidateGeneratorTheoryEeClass : public CandidateGenerator{
+private:
+ //instantiator pointer
+ EqualityEngine* d_ee;
+ //the equality class iterator
+ eq::EqClassIterator d_eqc;
+ /* For the case where the given term doesn't exists in uf */
+ Node d_retNode;
+public:
+ CandidateGeneratorTheoryEeClass( EqualityEngine* ee): d_ee( ee ){}
+ ~CandidateGeneratorTheoryEeClass(){}
+ void resetInstantiationRound(){};
+ void reset( TNode eqc ){
+ Assert(!eqc.isNull());
+ if( d_ee->hasTerm( eqc ) ){
+ /* eqc is in uf */
+ eqc = d_ee->getRepresentative( eqc );
+ d_eqc = eq::EqClassIterator( eqc, d_ee );
+ d_retNode = Node::null();
+ }else{
+ /* If eqc if not a term known by uf, it is the only one in its
+ equivalence class. So we will return only it */
+ d_retNode = eqc;
+ d_eqc = eq::EqClassIterator();
+ }
+ }; //* the argument is not used
+ TNode getNextCandidate(){
+ if(d_retNode.isNull()){
+ if( !d_eqc.isFinished() ) return (*(d_eqc++));
+ else return Node::null();
+ }else{
+ /* the case where eqc not in uf */
+ Node ret = d_retNode;
+ d_retNode = Node::null(); /* d_eqc.isFinished() must be true */
+ return ret;
+ }
+ };
+};
+
+
+} /* namespace rrinst */
+} /* namespace eq */
+
+namespace uf{
+namespace rrinst {
+
+typedef CVC4::theory::rrinst::CandidateGenerator CandidateGenerator;
+
+class CandidateGeneratorTheoryUfOp : public CandidateGenerator{
+private:
+ Node d_op;
+ //instantiator pointer
+ TermDb* d_tdb;
+ // Since new term can appears we restrict ourself to the one that
+ // exists at resetInstantiationRound
+ size_t d_term_iter_limit;
+ size_t d_term_iter;
+public:
+ CandidateGeneratorTheoryUfOp(Node op, TermDb* tdb): d_op(op), d_tdb( tdb ){}
+ ~CandidateGeneratorTheoryUfOp(){}
+ void resetInstantiationRound(){
+ d_term_iter_limit = d_tdb->d_op_map[d_op].size();
+ };
+ void reset( TNode eqc ){
+ Assert(eqc.isNull());
+ d_term_iter = 0;
+ }; //* the argument is not used
+ TNode getNextCandidate(){
+ if( d_term_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 uf */
+
+class GenericCandidateGeneratorClasses: public rrinst::CandidateGenerator{
+
+ /** The candidate generators */
+ rrinst::CandidateGenerator* d_can_gen[theory::THEORY_LAST];
+ /** The current theory which candidategenerator is used */
+ TheoryId d_can_gen_id;
+
+public:
+ GenericCandidateGeneratorClasses(QuantifiersEngine * qe);
+ ~GenericCandidateGeneratorClasses();
+
+ void resetInstantiationRound();
+ void reset(TNode eqc);
+ TNode getNextCandidate();
+ void lookForNextTheory();
+};
+
+class GenericCandidateGeneratorClass: public rrinst::CandidateGenerator{
+
+ /** The candidate generators */
+ rrinst::CandidateGenerator* d_can_gen[theory::THEORY_LAST];
+ /** The current theory which candidategenerator is used */
+ TheoryId d_can_gen_id;
+ /** current node to look for equivalence class */
+ Node d_node;
+ /** QuantifierEngine */
+ QuantifiersEngine* d_qe;
+
+public:
+ GenericCandidateGeneratorClass(QuantifiersEngine * qe);
+ ~GenericCandidateGeneratorClass();
+ void resetInstantiationRound();
+
+ void reset(TNode eqc);
+ TNode getNextCandidate();
+ void lookForNextTheory();
+};
+
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY_UF_INSTANTIATOR_H */
**/
#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"
+#include "theory/datatypes/theory_datatypes.h"
+#include "theory/rr_inst_match.h"
+#include "theory/rr_trigger.h"
+#include "theory/rr_inst_match_impl.h"
+#include "theory/rr_candidate_generator.h"
using namespace CVC4;
using namespace CVC4::kind;
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());
+ eq::EqualityEngine* ee = static_cast<eq::EqualityEngine*>(uf->getEqualityEngine());
CandidateGeneratorTheoryEeClass cdtUfEq(ee);
/* Create a matcher from the candidate generator */
AuxMatcher1 am1(cdtUfEq,am2);
/* The matcher */
typedef ApplyMatcher AuxMatcher3;
typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2;
- typedef CandidateGeneratorMatcher< datatypes::rrinst::CandidateGeneratorTheoryClass, AuxMatcher2> AuxMatcher1;
+ typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2> AuxMatcher1;
AuxMatcher1 d_cgm;
static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){
Assert( pat.getKind() == kind::APPLY_CONSTRUCTOR,
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);
+ eq::EqualityEngine* ee = static_cast<eq::EqualityEngine*>(dt->getEqualityEngine());
+ CandidateGeneratorTheoryEeClass cdtDtEq(ee);
/* Create a matcher from the candidate generator */
AuxMatcher1 am1(cdtDtEq,am2);
return am1;
#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/rr_candidate_generator.h"
#include "theory/uf/equality_engine.h"
namespace CVC4 {
#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/rr_candidate_generator.h"
#include "theory/uf/equality_engine.h"
using namespace std;
std::ostream& operator<<(std::ostream& os, Theory::Effort level);
+namespace eq{
+ class EqualityEngine;
+}
+
class Instantiator {
friend class QuantifiersEngine;
protected:
virtual bool areDisequal( Node a, Node b ) { return false; }
virtual Node getRepresentative( Node a ) { return a; }
virtual Node getInternalRepresentative( Node a ) { return getRepresentative( a ); }
+ virtual eq::EqualityEngine* getEqualityEngine() { return NULL; }
+ virtual void getEquivalenceClass( Node a, std::vector< Node >& eqc ) {}
public:
/** A Creator of CandidateGenerator for classes (one element in each
equivalence class) and class (every element of one equivalence
d_quantEngine = new QuantifiersEngine(context, this);
//build model information if applicable
- d_curr_model = new theory::DefaultModel( context, "DefaultModel" );
+ d_curr_model = new theory::DefaultModel( context, "DefaultModel", false );
d_curr_model_builder = new theory::TheoryEngineModelBuilder( this );
Rewriter::init();
Assert(d_sharedTerms.isShared(carePair.a) || carePair.a.isConst());
Assert(d_sharedTerms.isShared(carePair.b) || carePair.b.isConst());
- Assert(!d_sharedTerms.areEqual(carePair.a, carePair.b), "Please don't care about stuff you were notified about");
- Assert(!d_sharedTerms.areDisequal(carePair.a, carePair.b), "Please don't care about stuff you were notified about");
+ //AJR-temp Assert(!d_sharedTerms.areEqual(carePair.a, carePair.b), "Please don't care about stuff you were notified about");
+ //AJR-temp Assert(!d_sharedTerms.areDisequal(carePair.a, carePair.b), "Please don't care about stuff you were notified about");
// The equality in question
Node equality = carePair.a < carePair.b ?
#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/candidate_generator.h"
#include "theory/uf/equality_engine.h"
using namespace std;
}
bool Trigger::isAtomicTrigger( Node n ){
- return n.getKind()==APPLY_UF || n.getKind()==SELECT || n.getKind()==STORE;
+ return n.getKind()==APPLY_UF || n.getKind()==SELECT || n.getKind()==STORE ||
+ n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR || n.getKind()==APPLY_TESTER;
}
bool Trigger::isSimpleTrigger( Node n ){
if( isAtomicTrigger( n ) ){
theory_uf_instantiator.cpp \
theory_uf_strong_solver.h \
theory_uf_strong_solver.cpp \
- theory_uf_candidate_generator.h \
- theory_uf_candidate_generator.cpp \
inst_strategy.h \
inst_strategy.cpp \
theory_uf_model.h \
- theory_uf_model.cpp
+ theory_uf_model.cpp
EXTRA_DIST = kinds
+++ /dev/null
-/********************* */
-/*! \file theory_uf_candidate_generator.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 theory uf candidate generator class
- **/
-
-#include "theory/uf/theory_uf_candidate_generator.h"
-#include "theory/theory_engine.h"
-#include "theory/uf/theory_uf.h"
-#include "theory/quantifiers/term_database.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::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() );
-}
-void CandidateGeneratorTheoryUf::resetInstantiationRound(){
- d_term_iter_limit = d_ith->getQuantifiersEngine()->getTermDatabase()->d_op_map[d_op].size();
-}
-
-void CandidateGeneratorTheoryUf::reset( Node eqc ){
- if( eqc.isNull() ){
- d_term_iter = 0;
- }else{
- //create an equivalence class iterator in eq class eqc
- if( ((TheoryUF*)d_ith->getTheory())->getEqualityEngine()->hasTerm( eqc ) ){
- eqc = ((TheoryUF*)d_ith->getTheory())->getEqualityEngine()->getRepresentative( eqc );
- d_eqc = eq::EqClassIterator( eqc, ((TheoryUF*)d_ith->getTheory())->getEqualityEngine() );
- d_retNode = Node::null();
- }else{
- d_retNode = eqc;
-
- }
- d_term_iter = -1;
- }
-}
-
-Node CandidateGeneratorTheoryUf::getNextCandidate(){
- if( d_term_iter>=0 ){
- //get next candidate term in the uf term database
- while( d_term_iter<d_term_iter_limit ){
- Node n = d_ith->getQuantifiersEngine()->getTermDatabase()->d_op_map[d_op][d_term_iter];
- d_term_iter++;
- if( isLegalCandidate( n ) ){
- return n;
- }
- }
- }else if( d_term_iter==-1 ){
- if( d_retNode.isNull() ){
- //get next candidate term in equivalence class
- while( !d_eqc.isFinished() ){
- Node n = (*d_eqc);
- ++d_eqc;
- if( n.getKind()==APPLY_UF && n.getOperator()==d_op ){
- if( isLegalCandidate( n ) ){
- return n;
- }
- }
- }
- }else{
- Node ret;
- if( d_retNode.hasOperator() && d_retNode.getOperator()==d_op ){
- ret = d_retNode;
- }
- d_term_iter = -2; //done returning matches
- return ret;
- }
- }
- return Node::null();
-}
-
-
-//CandidateGeneratorTheoryUfDisequal::CandidateGeneratorTheoryUfDisequal( InstantiatorTheoryUf* ith, Node eqc ) :
-// d_ith( ith ), d_eq_class( eqc ){
-// d_eci = NULL;
-//}
-//void CandidateGeneratorTheoryUfDisequal::resetInstantiationRound(){
-//
-//}
-////we will iterate over all terms that are disequal from eqc
-//void CandidateGeneratorTheoryUfDisequal::reset( Node eqc ){
-// //Assert( !eqc.isNull() );
-// ////begin iterating over equivalence classes that are disequal from eqc
-// //d_eci = d_ith->getEquivalenceClassInfo( eqc );
-// //if( d_eci ){
-// // d_eqci_iter = d_eci->d_disequal.begin();
-// //}
-//}
-//Node CandidateGeneratorTheoryUfDisequal::getNextCandidate(){
-// //if( d_eci ){
-// // while( d_eqci_iter != d_eci->d_disequal.end() ){
-// // if( (*d_eqci_iter).second ){
-// // //we have an equivalence class that is disequal from eqc
-// // d_cg->reset( (*d_eqci_iter).first );
-// // Node n = d_cg->getNextCandidate();
-// // //if there is a candidate in this equivalence class, return it
-// // if( !n.isNull() ){
-// // return n;
-// // }
-// // }
-// // ++d_eqci_iter;
-// // }
-// //}
-// return Node::null();
-//}
-
-
-CandidateGeneratorTheoryUfLitEq::CandidateGeneratorTheoryUfLitEq( InstantiatorTheoryUf* ith, Node mpat ) :
- d_match_pattern( mpat ), d_ith( ith ){
-
-}
-void CandidateGeneratorTheoryUfLitEq::resetInstantiationRound(){
-
-}
-void CandidateGeneratorTheoryUfLitEq::reset( Node eqc ){
- d_eq = eq::EqClassesIterator( ((TheoryUF*)d_ith->getTheory())->getEqualityEngine() );
-}
-Node CandidateGeneratorTheoryUfLitEq::getNextCandidate(){
- while( d_eq.isFinished() ){
- Node n = (*d_eq);
- ++d_eq;
- if( n.getType()==d_match_pattern[0].getType() ){
- //an equivalence class with the same type as the pattern, return reflexive equality
- return NodeManager::currentNM()->mkNode( d_match_pattern.getKind(), n, n );
- }
- }
- return Node::null();
-}
-
-
-CandidateGeneratorTheoryUfLitDeq::CandidateGeneratorTheoryUfLitDeq( InstantiatorTheoryUf* ith, Node mpat ) :
- d_match_pattern( mpat ), d_ith( ith ){
-
-}
-void CandidateGeneratorTheoryUfLitDeq::resetInstantiationRound(){
-
-}
-void CandidateGeneratorTheoryUfLitDeq::reset( Node eqc ){
- Node false_term = ((TheoryUF*)d_ith->getTheory())->getEqualityEngine()->getRepresentative(
- NodeManager::currentNM()->mkConst<bool>(false) );
- d_eqc_false = eq::EqClassIterator( false_term, ((TheoryUF*)d_ith->getTheory())->getEqualityEngine() );
-}
-Node CandidateGeneratorTheoryUfLitDeq::getNextCandidate(){
- //get next candidate term in equivalence class
- while( !d_eqc_false.isFinished() ){
- Node n = (*d_eqc_false);
- ++d_eqc_false;
- if( n.getKind()==d_match_pattern.getKind() ){
- //found an iff or equality, try to match it
- //DO_THIS: cache to avoid redundancies?
- //DO_THIS: do we need to try the symmetric equality for n? or will it also exist in the eq class of false?
- return n;
- }
- }
- return Node::null();
-}
-
-}
-}
-}
-}
+++ /dev/null
-/********************* */
-/*! \file theory_uf_candidate_generator.h
- ** \verbatim
- ** Original author: ajreynol
- ** Major contributors: none
- ** Minor contributors (to current version): mdeters
- ** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009-2012 The Analysis of Computer Systems Group (ACSys)
- ** Courant Institute of Mathematical Sciences
- ** New York University
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Theory uf candidate generator
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY_UF_CANDIDATE_GENERATOR_H
-#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;
-
-class CandidateGeneratorTheoryUf : public CandidateGenerator
-{
- friend class CandidateGeneratorTheoryUfDisequal;
-private:
- //operator you are looking for
- Node d_op;
- //instantiator pointer
- InstantiatorTheoryUf* d_ith;
- //the equality class iterator
- eq::EqClassIterator d_eqc;
- int d_term_iter;
- int d_term_iter_limit;
-private:
- Node d_retNode;
-public:
- CandidateGeneratorTheoryUf( InstantiatorTheoryUf* ith, Node op );
- ~CandidateGeneratorTheoryUf(){}
-
- void resetInstantiationRound();
- void reset( Node eqc );
- Node getNextCandidate();
-};
-
-//class CandidateGeneratorTheoryUfDisequal : public CandidateGenerator
-//{
-//private:
-// //equivalence class
-// Node d_eq_class;
-// //equivalence class info
-// EqClassInfo* d_eci;
-// //equivalence class iterator
-// EqClassInfo::BoolMap::const_iterator d_eqci_iter;
-// //instantiator pointer
-// InstantiatorTheoryUf* d_ith;
-//public:
-// CandidateGeneratorTheoryUfDisequal( InstantiatorTheoryUf* ith, Node eqc );
-// ~CandidateGeneratorTheoryUfDisequal(){}
-//
-// void resetInstantiationRound();
-// void reset( Node eqc ); //should be what you want to be disequal from
-// Node getNextCandidate();
-//};
-
-class CandidateGeneratorTheoryUfLitEq : public CandidateGenerator
-{
-private:
- //the equality classes iterator
- eq::EqClassesIterator d_eq;
- //equality you are trying to match equalities for
- Node d_match_pattern;
- //einstantiator pointer
- InstantiatorTheoryUf* d_ith;
-public:
- CandidateGeneratorTheoryUfLitEq( InstantiatorTheoryUf* ith, Node mpat );
- ~CandidateGeneratorTheoryUfLitEq(){}
-
- void resetInstantiationRound();
- void reset( Node eqc );
- Node getNextCandidate();
-};
-
-class CandidateGeneratorTheoryUfLitDeq : public CandidateGenerator
-{
-private:
- //the equality class iterator for false
- eq::EqClassIterator d_eqc_false;
- //equality you are trying to match disequalities for
- Node d_match_pattern;
- //einstantiator pointer
- InstantiatorTheoryUf* d_ith;
-public:
- CandidateGeneratorTheoryUfLitDeq( InstantiatorTheoryUf* ith, Node mpat );
- ~CandidateGeneratorTheoryUfLitDeq(){}
-
- void resetInstantiationRound();
- void reset( Node eqc );
- Node getNextCandidate();
-};
-
-
-}/* CVC4::theory::uf::inst namespace */
-}/* CVC4::theory::uf namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY_UF_INSTANTIATOR_H */
#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/rr_candidate_generator.h"
#include "theory/uf/equality_engine.h"
#include "theory/quantifiers/term_database.h"
}
bool InstantiatorTheoryUf::areEqual( Node a, Node b ){
- if( hasTerm( a ) && hasTerm( b ) ){
+ if( a==b ){
+ return true;
+ }else if( hasTerm( a ) && hasTerm( b ) ){
return ((TheoryUF*)d_th)->d_equalityEngine.areEqual( a, b );
}else{
- return a==b;
+ return false;
}
}
bool InstantiatorTheoryUf::areDisequal( Node a, Node b ){
- if( hasTerm( a ) && hasTerm( b ) ){
+ if( a==b ){
+ return false;
+ }else if( hasTerm( a ) && hasTerm( b ) ){
return ((TheoryUF*)d_th)->d_equalityEngine.areDisequal( a, b, false );
}else{
return false;
return rep;
}else{
//otherwise, must search eq class
- eq::EqClassIterator eqc_iter( rep, &((TheoryUF*)d_th)->d_equalityEngine );
+ eq::EqClassIterator eqc_iter( rep, getEqualityEngine() );
rep = Node::null();
while( !eqc_iter.isFinished() ){
if( !(*eqc_iter).hasAttribute(InstConstantAttribute()) ){
return d_ground_reps[a];
}
+eq::EqualityEngine* InstantiatorTheoryUf::getEqualityEngine(){
+ return &((TheoryUF*)d_th)->d_equalityEngine;
+}
+
+void InstantiatorTheoryUf::getEquivalenceClass( Node a, std::vector< Node >& eqc ){
+ if( hasTerm( a ) ){
+ a = getEqualityEngine()->getRepresentative( a );
+ eq::EqClassIterator eqc_iter( a, getEqualityEngine() );
+ while( !eqc_iter.isFinished() ){
+ if( std::find( eqc.begin(), eqc.end(), *eqc_iter )==eqc.end() ){
+ eqc.push_back( *eqc_iter );
+ }
+ eqc_iter++;
+ }
+ }
+}
+
InstantiatorTheoryUf::Statistics::Statistics():
//d_instantiations("InstantiatorTheoryUf::Total_Instantiations", 0),
d_instantiations_ce_solved("InstantiatorTheoryUf::Instantiations_CE-Solved", 0),
bool InstantiatorTheoryUf::collectParentsTermsIps( Node n, Node f, int arg, SetNode & terms, bool addRep, bool modEq ){ //modEq default true
bool addedTerm = false;
-
+
if( modEq && ((TheoryUF*)d_th)->d_equalityEngine.hasTerm( n )){
Assert( getRepresentative( n )==n );
//collect modulo equality
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();
bool areDisequal( Node a, Node b );
Node getRepresentative( Node a );
Node getInternalRepresentative( Node a );
+ eq::EqualityEngine* getEqualityEngine();
+ void getEquivalenceClass( Node a, std::vector< Node >& eqc );
/** general creators of candidate generators */
rrinst::CandidateGenerator* getRRCanGenClasses();
rrinst::CandidateGenerator* getRRCanGenClass();
bool areEqual( Node a, Node b ) { return d_ith->areEqual( a, b ); }
bool areDisequal( Node a, Node b ) { return d_ith->areDisequal( a, b ); }
Node getInternalRepresentative( Node a ) { return d_ith->getInternalRepresentative( a ); }
+ eq::EqualityEngine* getEngine() { return d_ith->getEqualityEngine(); }
+ void getEquivalenceClass( Node a, std::vector< Node >& eqc ) { d_ith->getEquivalenceClass( a, eqc ); }
}; /* EqualityQueryInstantiatorTheoryUf */
}
using namespace CVC4::theory::uf;\r
\r
//clear\r
-void UfModelTree::clear(){\r
+void UfModelTreeNode::clear(){\r
d_data.clear();\r
d_value = Node::null();\r
}\r
\r
-bool UfModelTree::hasConcreteArgumentDefinition(){\r
+bool UfModelTreeNode::hasConcreteArgumentDefinition(){\r
if( d_data.size()>1 ){\r
return true;\r
}else if( d_data.empty() ){\r
}\r
\r
//set value function\r
-void UfModelTree::setValue( TheoryModel* m, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex ){\r
+void UfModelTreeNode::setValue( TheoryModel* m, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex ){\r
if( d_data.empty() ){\r
d_value = v;\r
}else if( !d_value.isNull() && d_value!=v ){\r
d_value = Node::null();\r
}\r
- if( argIndex<(int)n.getNumChildren() ){\r
+ if( argIndex<(int)indexOrder.size() ){\r
//take r = null when argument is the model basis\r
Node r;\r
- if( ground || !n[ indexOrder[argIndex] ].getAttribute(ModelBasisAttribute()) ){\r
+ if( ground || ( !n.isNull() && !n[ indexOrder[argIndex] ].getAttribute(ModelBasisAttribute()) ) ){\r
r = m->getRepresentative( n[ indexOrder[argIndex] ] );\r
}\r
d_data[ r ].setValue( m, n, v, indexOrder, ground, argIndex+1 );\r
}\r
\r
//get value function\r
-Node UfModelTree::getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int& depIndex, int argIndex ){\r
+Node UfModelTreeNode::getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int& depIndex, int argIndex ){\r
if( !d_value.isNull() && isTotal( n.getOperator(), argIndex ) ){\r
//Notice() << "Constant, return " << d_value << ", depIndex = " << argIndex << std::endl;\r
depIndex = argIndex;\r
if( i==0 ){\r
r = m->getRepresentative( n[ indexOrder[argIndex] ] );\r
}\r
- std::map< Node, UfModelTree >::iterator it = d_data.find( r );\r
+ std::map< Node, UfModelTreeNode >::iterator it = d_data.find( r );\r
if( it!=d_data.end() ){\r
val = it->second.getValue( m, n, indexOrder, childDepIndex[i], argIndex+1 );\r
if( !val.isNull() ){\r
}\r
}\r
\r
-Node UfModelTree::getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, std::vector< int >& depIndex, int argIndex ){\r
+Node UfModelTreeNode::getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, std::vector< int >& depIndex, int argIndex ){\r
if( argIndex==(int)indexOrder.size() ){\r
return d_value;\r
}else{\r
if( i==0 ){\r
r = m->getRepresentative( n[ indexOrder[argIndex] ] );\r
}\r
- std::map< Node, UfModelTree >::iterator it = d_data.find( r );\r
+ std::map< Node, UfModelTreeNode >::iterator it = d_data.find( r );\r
if( it!=d_data.end() ){\r
val = it->second.getValue( m, n, indexOrder, depIndex, argIndex+1 );\r
//we have found a value\r
}\r
}\r
\r
-Node UfModelTree::getFunctionValue(){\r
+Node UfModelTreeNode::getFunctionValue(){\r
if( !d_data.empty() ){\r
Node defaultValue;\r
std::vector< Node > caseValues;\r
- for( std::map< Node, UfModelTree >::iterator it = d_data.begin(); it != d_data.end(); ++it ){\r
+ for( std::map< Node, UfModelTreeNode >::iterator it = d_data.begin(); it != d_data.end(); ++it ){\r
if( it->first.isNull() ){\r
defaultValue = it->second.getFunctionValue();\r
}else{\r
}\r
\r
//simplify function\r
-void UfModelTree::simplify( Node op, Node defaultVal, int argIndex ){\r
+void UfModelTreeNode::simplify( Node op, Node defaultVal, int argIndex ){\r
if( argIndex<(int)op.getType().getNumChildren()-1 ){\r
std::vector< Node > eraseData;\r
//first process the default argument\r
Node r;\r
- std::map< Node, UfModelTree >::iterator it = d_data.find( r );\r
+ std::map< Node, UfModelTreeNode >::iterator it = d_data.find( r );\r
if( it!=d_data.end() ){\r
if( !defaultVal.isNull() && it->second.d_value==defaultVal ){\r
eraseData.push_back( r );\r
}\r
}\r
//now see if any children can be removed, and simplify the ones that cannot\r
- for( std::map< Node, UfModelTree >::iterator it = d_data.begin(); it != d_data.end(); ++it ){\r
+ for( std::map< Node, UfModelTreeNode >::iterator it = d_data.begin(); it != d_data.end(); ++it ){\r
if( !it->first.isNull() ){\r
if( !defaultVal.isNull() && it->second.d_value==defaultVal ){\r
eraseData.push_back( it->first );\r
}\r
\r
//is total function\r
-bool UfModelTree::isTotal( Node op, int argIndex ){\r
+bool UfModelTreeNode::isTotal( Node op, int argIndex ){\r
if( argIndex==(int)(op.getType().getNumChildren()-1) ){\r
return !d_value.isNull();\r
}else{\r
Node r;\r
- std::map< Node, UfModelTree >::iterator it = d_data.find( r );\r
+ std::map< Node, UfModelTreeNode >::iterator it = d_data.find( r );\r
if( it!=d_data.end() ){\r
return it->second.isTotal( op, argIndex+1 );\r
}else{\r
}\r
}\r
\r
-Node UfModelTree::getConstantValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int argIndex ){\r
+Node UfModelTreeNode::getConstantValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int argIndex ){\r
return d_value;\r
}\r
\r
}\r
}\r
\r
-void UfModelTree::debugPrint( std::ostream& out, TheoryModel* m, std::vector< int >& indexOrder, int ind, int arg ){\r
+void UfModelTreeNode::debugPrint( std::ostream& out, TheoryModel* m, std::vector< int >& indexOrder, int ind, int arg ){\r
if( !d_data.empty() ){\r
- for( std::map< Node, UfModelTree >::iterator it = d_data.begin(); it != d_data.end(); ++it ){\r
+ for( std::map< Node, UfModelTreeNode >::iterator it = d_data.begin(); it != d_data.end(); ++it ){\r
if( !it->first.isNull() ){\r
indent( out, ind );\r
out << "if x_" << indexOrder[arg] << " == " << it->first << std::endl;\r
indent( out, ind );\r
out << "return ";\r
m->printRepresentative( out, d_value );\r
- //out << " { ";\r
- //for( int i=0; i<(int)d_explicit.size(); i++ ){\r
- // out << d_explicit[i] << " ";\r
- //}\r
- //out << "}";\r
out << std::endl;\r
}\r
}\r
\r
-UfModel::UfModel( Node op, quantifiers::FirstOrderModel* m ) : d_model( m ), d_op( op ),\r
-d_model_constructed( false ){\r
- d_tree = UfModelTreeOrdered( op );\r
- TypeNode tn = d_op.getType();\r
- tn = tn[(int)tn.getNumChildren()-1];\r
- Assert( tn==NodeManager::currentNM()->booleanType() || tn.isDatatype() || uf::StrongSolverTheoryUf::isRelevantType( tn ) );\r
- //look at ground assertions\r
- for( size_t i=0; i<d_model->getTermDatabase()->d_op_map[ d_op ].size(); i++ ){\r
- Node n = d_model->getTermDatabase()->d_op_map[ d_op ][i];\r
- d_model->getTermDatabase()->computeModelBasisArgAttribute( n );\r
- if( !n.getAttribute(NoMatchAttribute()) || n.getAttribute(ModelBasisArgAttribute())==1 ){\r
- Node r = d_model->getRepresentative( n );\r
- d_ground_asserts_reps.push_back( r );\r
- d_ground_asserts.push_back( n );\r
- }\r
- }\r
- //determine if it is constant\r
- if( !d_ground_asserts.empty() ){\r
- bool isConstant = true;\r
- for( int i=1; i<(int)d_ground_asserts.size(); i++ ){\r
- if( d_ground_asserts_reps[0]!=d_ground_asserts_reps[i] ){\r
- isConstant = false;\r
- break;\r
+\r
+Node UfModelTree::toIte2( Node fm_node, std::vector< Node >& args, int index, Node defaultNode ){\r
+ if( fm_node.getKind()==FUNCTION_MODEL ){\r
+ if( fm_node[0].getKind()==FUNCTION_CASE_SPLIT ){\r
+ Node retNode;\r
+ Node childDefaultNode = defaultNode;\r
+ //get new default\r
+ if( fm_node.getNumChildren()==2 ){\r
+ childDefaultNode = toIte2( fm_node[1], args, index+1, defaultNode );\r
}\r
+ retNode = childDefaultNode;\r
+ for( int i=(int)fm_node[0].getNumChildren()-1; i>=0; i-- ){\r
+ Node childNode = toIte2( fm_node[0][1], args, index+1, childDefaultNode );\r
+ retNode = NodeManager::currentNM()->mkNode( ITE, args[index].eqNode( fm_node[0][0] ), childNode, retNode );\r
+ }\r
+ return retNode;\r
+ }else{\r
+ return toIte2( fm_node[0], args, index+1, defaultNode );\r
}\r
- if( isConstant ){\r
- //set constant value\r
- Node t = d_model->getTermDatabase()->getModelBasisOpTerm( d_op );\r
- Node r = d_ground_asserts_reps[0];\r
- setValue( t, r, false );\r
- setModel();\r
- Debug("fmf-model-cons") << "Function " << d_op << " is the constant function ";\r
- d_model->printRepresentativeDebug( "fmf-model-cons", r );\r
- Debug("fmf-model-cons") << std::endl;\r
- }\r
+ }else{\r
+ return fm_node;\r
}\r
}\r
\r
-Node UfModel::getIntersection( Node n1, Node n2, bool& isGround ){\r
+\r
+Node UfModelTreeGenerator::getIntersection( TheoryModel* m, Node n1, Node n2, bool& isGround ){\r
//Notice() << "Get intersection " << n1 << " " << n2 << std::endl;\r
isGround = true;\r
std::vector< Node > children;\r
children.push_back( n2[i] );\r
}else if( n2[i].getAttribute(ModelBasisAttribute()) ){\r
children.push_back( n1[i] );\r
- }else if( d_model->areEqual( n1[i], n2[i] ) ){\r
+ }else if( m->areEqual( n1[i], n2[i] ) ){\r
children.push_back( n1[i] );\r
}else{\r
return Node::null();\r
return NodeManager::currentNM()->mkNode( APPLY_UF, children );\r
}\r
\r
-void UfModel::setValue( Node n, Node v, bool ground, bool isReq ){\r
+void UfModelTreeGenerator::setValue( TheoryModel* m, Node n, Node v, bool ground, bool isReq ){\r
Assert( !n.isNull() );\r
Assert( !v.isNull() );\r
d_set_values[ isReq ? 1 : 0 ][ ground ? 1 : 0 ][n] = v;\r
// is also defined.\r
//for example, if we have that f( e, a ) = ..., and f( b, e ) = ...,\r
// then we must define f( b, a ).\r
- Node ni = getIntersection( n, d_defaults[i], isGround );\r
+ Node ni = getIntersection( m, n, d_defaults[i], isGround );\r
if( !ni.isNull() ){\r
//if the intersection exists, and is not already defined\r
if( d_set_values[0][ isGround ? 1 : 0 ].find( ni )==d_set_values[0][ isGround ? 1 : 0 ].end() &&\r
d_set_values[1][ isGround ? 1 : 0 ].find( ni )==d_set_values[1][ isGround ? 1 : 0 ].end() ){\r
//use the current value\r
- setValue( ni, v, isGround, false );\r
+ setValue( m, ni, v, isGround, false );\r
}\r
}\r
}\r
}\r
}\r
\r
-Node UfModel::getValue( Node n, int& depIndex ){\r
- return d_tree.getValue( d_model, n, depIndex );\r
-}\r
-\r
-Node UfModel::getValue( Node n, std::vector< int >& depIndex ){\r
- return d_tree.getValue( d_model, n, depIndex );\r
-}\r
-\r
-Node UfModel::getConstantValue( Node n ){\r
- if( d_model_constructed ){\r
- return d_tree.getConstantValue( d_model, n );\r
- }else{\r
- return Node::null();\r
+void UfModelTreeGenerator::makeModel( TheoryModel* m, UfModelTree& tree ){\r
+ for( int j=0; j<2; j++ ){\r
+ for( int k=0; k<2; k++ ){\r
+ for( std::map< Node, Node >::iterator it = d_set_values[j][k].begin(); it != d_set_values[j][k].end(); ++it ){\r
+ tree.setValue( m, it->first, it->second, k==1 );\r
+ }\r
+ }\r
}\r
-}\r
-\r
-Node UfModel::getFunctionValue(){\r
- if( d_func_value.isNull() && d_model_constructed ){\r
- d_func_value = d_tree.getFunctionValue();\r
+ if( !d_default_value.isNull() ){\r
+ tree.setDefaultValue( m, d_default_value );\r
}\r
- return d_func_value;\r
-}\r
-\r
-bool UfModel::isConstant(){\r
- Node gn = d_model->getTermDatabase()->getModelBasisOpTerm( d_op );\r
- Node n = getConstantValue( gn );\r
- return !n.isNull();\r
+ tree.simplify();\r
}\r
\r
-bool UfModel::optUsePartialDefaults(){\r
+bool UfModelTreeGenerator::optUsePartialDefaults(){\r
#ifdef USE_PARTIAL_DEFAULT_VALUES\r
return true;\r
#else\r
#endif\r
}\r
\r
-void UfModel::setModel(){\r
- makeModel( d_tree );\r
- d_model_constructed = true;\r
- d_func_value = Node::null();\r
-\r
- //for debugging, make sure model satisfies all ground assertions\r
- for( size_t i=0; i<d_ground_asserts.size(); i++ ){\r
- int depIndex;\r
- Node n = d_tree.getValue( d_model, d_ground_asserts[i], depIndex );\r
- if( n!=d_ground_asserts_reps[i] ){\r
- Debug("fmf-bad") << "Bad model : " << d_ground_asserts[i] << " := ";\r
- d_model->printRepresentativeDebug("fmf-bad", n );\r
- Debug("fmf-bad") << " != ";\r
- d_model->printRepresentativeDebug("fmf-bad", d_ground_asserts_reps[i] );\r
- Debug("fmf-bad") << std::endl;\r
- }\r
- }\r
-}\r
-\r
-void UfModel::clearModel(){\r
+void UfModelTreeGenerator::clear(){\r
+ d_default_value = Node::null();\r
for( int j=0; j<2; j++ ){\r
for( int k=0; k<2; k++ ){\r
d_set_values[j][k].clear();\r
}\r
}\r
- d_tree.clear();\r
- d_model_constructed = false;\r
-}\r
-\r
-void UfModel::makeModel( UfModelTreeOrdered& tree ){\r
- for( int j=0; j<2; j++ ){\r
- for( int k=0; k<2; k++ ){\r
- for( std::map< Node, Node >::iterator it = d_set_values[j][k].begin(); it != d_set_values[j][k].end(); ++it ){\r
- tree.setValue( d_model, it->first, it->second, k==1 );\r
- }\r
- }\r
- }\r
- tree.simplify();\r
-}\r
-\r
-void UfModel::toStream(std::ostream& out){\r
- //out << "Function " << d_op << std::endl;\r
- //out << " Type: " << d_op.getType() << std::endl;\r
- //out << " Ground asserts:" << std::endl;\r
- //for( int i=0; i<(int)d_ground_asserts.size(); i++ ){\r
- // out << " " << d_ground_asserts[i] << " = ";\r
- // d_model->printRepresentative( out, d_ground_asserts[i] );\r
- // out << std::endl;\r
- //}\r
- //out << " Model:" << std::endl;\r
-\r
- TypeNode t = d_op.getType();\r
- out << d_op << "( ";\r
- for( int i=0; i<(int)(t.getNumChildren()-1); i++ ){\r
- out << "x_" << i << " : " << t[i];\r
- if( i<(int)(t.getNumChildren()-2) ){\r
- out << ", ";\r
- }\r
- }\r
- out << " ) : " << t[(int)t.getNumChildren()-1] << std::endl;\r
- if( d_tree.isEmpty() ){\r
- out << " [undefined]" << std::endl;\r
- }else{\r
- d_tree.debugPrint( out, d_model, 3 );\r
- out << std::endl;\r
- }\r
- //out << " Phase reqs:" << std::endl; //for( int i=0; i<2; i++ ){\r
- // for( std::map< Node, std::vector< Node > >::iterator it = d_reqs[i].begin(); it != d_reqs[i].end(); ++it ){\r
- // out << " " << it->first << std::endl;\r
- // for( int j=0; j<(int)it->second.size(); j++ ){\r
- // out << " " << it->second[j] << " -> " << (i==1) << std::endl;\r
- // }\r
- // }\r
- //}\r
- //out << std::endl;\r
- //for( int i=0; i<2; i++ ){\r
- // for( std::map< Node, std::map< Node, std::vector< Node > > >::iterator it = d_eq_reqs[i].begin(); it != d_eq_reqs[i].end(); ++it ){\r
- // out << " " << "For " << it->first << ":" << std::endl;\r
- // for( std::map< Node, std::vector< Node > >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){\r
- // for( int j=0; j<(int)it2->second.size(); j++ ){\r
- // out << " " << it2->first << ( i==1 ? "==" : "!=" ) << it2->second[j] << std::endl;\r
- // }\r
- // }\r
- // }\r
- //}\r
-}\r
-\r
-Node UfModel::toIte2( Node fm_node, std::vector< Node >& args, int index, Node defaultNode ){\r
- if( fm_node.getKind()==FUNCTION_MODEL ){\r
- if( fm_node[0].getKind()==FUNCTION_CASE_SPLIT ){\r
- Node retNode;\r
- Node childDefaultNode = defaultNode;\r
- //get new default\r
- if( fm_node.getNumChildren()==2 ){\r
- childDefaultNode = toIte2( fm_node[1], args, index+1, defaultNode );\r
- }\r
- retNode = childDefaultNode;\r
- for( int i=(int)fm_node[0].getNumChildren()-1; i>=0; i-- ){\r
- Node childNode = toIte2( fm_node[0][1], args, index+1, childDefaultNode );\r
- retNode = NodeManager::currentNM()->mkNode( ITE, args[index].eqNode( fm_node[0][0] ), childNode, retNode );\r
- }\r
- return retNode;\r
- }else{\r
- return toIte2( fm_node[0], args, index+1, defaultNode );\r
- }\r
- }else{\r
- return fm_node;\r
- }\r
+ d_defaults.clear();\r
}\r
\r
\r
\r
namespace CVC4 {\r
namespace theory {\r
-\r
-namespace quantifiers{\r
- class FirstOrderModel;\r
-}\r
-\r
namespace uf {\r
\r
-class UfModelTree\r
+class UfModelTreeNode\r
{\r
public:\r
- UfModelTree(){}\r
+ UfModelTreeNode(){}\r
/** the data */\r
- std::map< Node, UfModelTree > d_data;\r
+ std::map< Node, UfModelTreeNode > d_data;\r
/** the value of this tree node (if all paths lead to same value) */\r
Node d_value;\r
/** has concrete argument defintion */\r
bool isEmpty() { return d_data.empty() && d_value.isNull(); }\r
//clear\r
void clear();\r
- /** setValue function\r
- *\r
- * For each argument of n with ModelBasisAttribute() set to true will be considered default arguments if ground=false\r
- *\r
- */\r
+ /** setValue function */\r
void setValue( TheoryModel* m, Node n, Node v, std::vector< int >& indexOrder, bool ground, int argIndex );\r
- /** getValue function\r
- *\r
- * returns $val, the value of ground term n\r
- * Say n is f( t_0...t_n )\r
- * depIndex is the index for which every term of the form f( t_0 ... t_depIndex, *,... * ) is equal to $val\r
- * for example, if g( x_0, x_1, x_2 ) := lambda x_0 x_1 x_2. if( x_1==a ) b else c,\r
- * then g( a, a, a ) would return b with depIndex = 1\r
- * If ground = true, we are asking whether the term n is constant (assumes that all non-model basis arguments are ground)\r
- *\r
- */\r
+ /** getValue function */\r
Node getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int& depIndex, int argIndex );\r
Node getValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, std::vector< int >& depIndex, int argIndex );\r
- ///** getConstant Value function\r
- // *\r
- // * given term n, where n may contain model basis arguments\r
- // * if n is constant for its entire domain, then this function returns the value of its domain\r
- // * otherwise, it returns null\r
- // * for example, if f( x_0, x_1 ) := if( x_0 = a ) b else if( x_1 = a ) a else b,\r
- // * then f( a, e ) would return b, while f( e, a ) would return null\r
- // *\r
- // */\r
+ /** getConstant Value function */\r
Node getConstantValue( TheoryModel* m, Node n, std::vector< int >& indexOrder, int argIndex );\r
/** getFunctionValue */\r
Node getFunctionValue();\r
/** simplify function */\r
void simplify( Node op, Node defaultVal, int argIndex );\r
- // is total ?\r
+ /** is total ? */\r
bool isTotal( Node op, int argIndex );\r
public:\r
void debugPrint( std::ostream& out, TheoryModel* m, std::vector< int >& indexOrder, int ind = 0, int arg = 0 );\r
};\r
\r
-class UfModelTreeOrdered\r
+class UfModelTree\r
{\r
private:\r
+ //the op this model is for\r
Node d_op;\r
+ //the order we will treat the arguments\r
std::vector< int > d_index_order;\r
- UfModelTree d_tree;\r
+ //the data\r
+ UfModelTreeNode d_tree;\r
public:\r
- UfModelTreeOrdered(){}\r
- UfModelTreeOrdered( Node op ) : d_op( op ){\r
+ //constructors\r
+ UfModelTree(){}\r
+ UfModelTree( Node op ) : d_op( op ){\r
TypeNode tn = d_op.getType();\r
for( int i=0; i<(int)(tn.getNumChildren()-1); i++ ){\r
d_index_order.push_back( i );\r
}\r
}\r
- UfModelTreeOrdered( Node op, std::vector< int >& indexOrder ) : d_op( op ){\r
+ UfModelTree( Node op, std::vector< int >& indexOrder ) : d_op( op ){\r
d_index_order.insert( d_index_order.end(), indexOrder.begin(), indexOrder.end() );\r
}\r
- bool isEmpty() { return d_tree.isEmpty(); }\r
+ /** clear/reset the function */\r
void clear() { d_tree.clear(); }\r
+ /** setValue function\r
+ *\r
+ * For each argument of n with ModelBasisAttribute() set to true will be considered default arguments if ground=false\r
+ *\r
+ */\r
void setValue( TheoryModel* m, Node n, Node v, bool ground = true ){\r
d_tree.setValue( m, n, v, d_index_order, ground, 0 );\r
}\r
+ /** setDefaultValue function */\r
+ void setDefaultValue( TheoryModel* m, Node v ){\r
+ d_tree.setValue( m, Node::null(), v, d_index_order, false, 0 );\r
+ }\r
+ /** getValue function\r
+ *\r
+ * returns val, the value of ground term n\r
+ * Say n is f( t_0...t_n )\r
+ * depIndex is the index for which every term of the form f( t_0 ... t_depIndex, *,... * ) is equal to val\r
+ * for example, if g( x_0, x_1, x_2 ) := lambda x_0 x_1 x_2. if( x_1==a ) b else c,\r
+ * then g( a, a, a ) would return b with depIndex = 1\r
+ *\r
+ */\r
Node getValue( TheoryModel* m, Node n, int& depIndex ){\r
return d_tree.getValue( m, n, d_index_order, depIndex, 0 );\r
}\r
+ /** -> implementation incomplete */\r
Node getValue( TheoryModel* m, Node n, std::vector< int >& depIndex ){\r
return d_tree.getValue( m, n, d_index_order, depIndex, 0 );\r
}\r
+ /** getConstantValue function\r
+ *\r
+ * given term n, where n may contain "all value" arguments, aka model basis arguments\r
+ * if n is null, then every argument of n is considered "all value"\r
+ * if n is constant for the entire domain specified by n, then this function returns the value of its domain\r
+ * otherwise, it returns null\r
+ * for example, say the term e represents "all values"\r
+ * if f( x_0, x_1 ) := if( x_0 = a ) b else if( x_1 = a ) a else b,\r
+ * then f( a, e ) would return b, while f( e, a ) would return null\r
+ * -> implementation incomplete\r
+ */\r
Node getConstantValue( TheoryModel* m, Node n ) {\r
return d_tree.getConstantValue( m, n, d_index_order, 0 );\r
}\r
+ /** getFunctionValue\r
+ * Returns a compact representation of this function, of kind FUNCTION_MODEL.\r
+ * See documentation in theory/uf/kinds\r
+ */\r
Node getFunctionValue(){\r
return d_tree.getFunctionValue();\r
}\r
+ /** simplify the tree */\r
void simplify() { d_tree.simplify( d_op, Node::null(), 0 ); }\r
+ /** is this tree total? */\r
bool isTotal() { return d_tree.isTotal( d_op, 0 ); }\r
+ /** is this function constant? */\r
+ bool isConstant( TheoryModel* m ) { return !getConstantValue( m, Node::null() ).isNull(); }\r
+ /** is this tree empty? */\r
+ bool isEmpty() { return d_tree.isEmpty(); }\r
public:\r
void debugPrint( std::ostream& out, TheoryModel* m, int ind = 0 ){\r
d_tree.debugPrint( out, m, d_index_order, ind );\r
}\r
+private:\r
+ //helper for to ITE function.\r
+ static Node toIte2( Node fm_node, std::vector< Node >& args, int index, Node defaultNode );\r
+public:\r
+ /** to ITE function for function model nodes */\r
+ static Node toIte( Node fm_node, std::vector< Node >& args ) { return toIte2( fm_node, args, 0, Node::null() ); }\r
};\r
\r
-class UfModel\r
+class UfModelTreeGenerator\r
{\r
private:\r
- quantifiers::FirstOrderModel* d_model;\r
- //the operator this model is for\r
- Node d_op;\r
- //is model constructed\r
- bool d_model_constructed;\r
//store for set values\r
+ Node d_default_value;\r
std::map< Node, Node > d_set_values[2][2];\r
-private:\r
// defaults\r
std::vector< Node > d_defaults;\r
- Node getIntersection( Node n1, Node n2, bool& isGround );\r
+ Node getIntersection( TheoryModel* m, Node n1, Node n2, bool& isGround );\r
public:\r
- UfModel(){}\r
- UfModel( Node op, quantifiers::FirstOrderModel* m );\r
- ~UfModel(){}\r
- //ground terms for this operator\r
- std::vector< Node > d_ground_asserts;\r
- //the representatives they are equal to\r
- std::vector< Node > d_ground_asserts_reps;\r
- //data structure that stores the model\r
- UfModelTreeOrdered d_tree;\r
- //node equivalent of this model\r
- Node d_func_value;\r
-public:\r
- /** get operator */\r
- Node getOperator() { return d_op; }\r
- /** debug print */\r
- void toStream( std::ostream& out );\r
+ UfModelTreeGenerator(){}\r
+ ~UfModelTreeGenerator(){}\r
+ /** set default value */\r
+ void setDefaultValue( Node v ) { d_default_value = v; }\r
/** set value */\r
- void setValue( Node n, Node v, bool ground = true, bool isReq = true );\r
- /** get value, return arguments that the value depends on */\r
- Node getValue( Node n, int& depIndex );\r
- Node getValue( Node n, std::vector< int >& depIndex );\r
- /** get constant value */\r
- Node getConstantValue( Node n );\r
- /** get function value for this function */\r
- Node getFunctionValue();\r
- /** is model constructed */\r
- bool isModelConstructed() { return d_model_constructed; }\r
- /** is empty */\r
- bool isEmpty() { return d_ground_asserts.empty(); }\r
- /** is constant */\r
- bool isConstant();\r
+ void setValue( TheoryModel* m, Node n, Node v, bool ground = true, bool isReq = true );\r
+ /** make model */\r
+ void makeModel( TheoryModel* m, UfModelTree& tree );\r
/** uses partial default values */\r
bool optUsePartialDefaults();\r
-public:\r
- /** set model */\r
- void setModel();\r
- /** clear model */\r
- void clearModel();\r
- /** make model */\r
- void makeModel( UfModelTreeOrdered& tree );\r
-public:\r
- /** set value preference */\r
- void setValuePreference( Node f, Node n, bool isPro );\r
-private:\r
- //helper for to ITE function.\r
- static Node toIte2( Node fm_node, std::vector< Node >& args, int index, Node defaultNode );\r
-public:\r
- /** to ITE function for function model nodes */\r
- static Node toIte( Node fm_node, std::vector< Node >& args ) { return toIte2( fm_node, args, 0, Node::null() ); }\r
+ /** reset */\r
+ void clear();\r
};\r
\r
//this class stores temporary information useful to model engine for constructing model\r
public:\r
UfModelPreferenceData() : d_reconsiderModel( false ){}\r
virtual ~UfModelPreferenceData(){}\r
+ Node d_const_val;\r
// preferences for default values\r
std::vector< Node > d_values;\r
std::map< Node, std::vector< Node > > d_value_pro_con[2];\r
Debug("uf-ss-solver") << "StrongSolverTheoryUf: New eq class " << n << " " << tn << std::endl;
c->newEqClass( n );
}
- //else if( isRelevantType( tn ) ){
+ //else if( tn.isSort() ){
// //Debug("uf-ss-solver") << "WAIT: StrongSolverTheoryUf: New eq class " << n << " " << tn << std::endl;
// //d_new_eq_class_waiting[tn].push_back( n );
//}
if( n.getKind()==CARDINALITY_CONSTRAINT ){
TypeNode tn = n[0].getType();
Assert( d_conf_find[tn]->getCardinality()>0 );
- Assert( isRelevantType( tn ) );
+ Assert( tn.isSort() );
Assert( d_conf_find[tn] );
long nCard = n[1].getConst<Rational>().getNumerator().getLong();
d_conf_find[tn]->assertCardinality( nCard, true );
//must add new lemma
Node nn = n[0];
TypeNode tn = nn[0].getType();
- Assert( isRelevantType( tn ) );
+ Assert( tn.isSort() );
Assert( d_conf_find[tn] );
long nCard = nn[1].getConst<Rational>().getNumerator().getLong();
d_conf_find[tn]->assertCardinality( nCard, false );
void StrongSolverTheoryUf::preRegisterTerm( TNode n ){
//shouldn't have to preregister this type (it may be that there are no quantifiers over tn) FIXME
TypeNode tn = n.getType();
- if( isRelevantType( tn ) ){
+ if( tn.isSort() ){
preRegisterType( tn );
}
}
//must ensure the quantifier does not quantify over arithmetic
for( int i=0; i<(int)f[0].getNumChildren(); i++ ){
TypeNode tn = f[0][i].getType();
- if( isRelevantType( tn ) ){
+ if( tn.isSort() ){
preRegisterType( tn );
}else{
+ /*
if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){
Debug("uf-ss-na") << "Error: Cannot perform finite model finding on arithmetic quantifier";
Debug("uf-ss-na") << " (" << f << ")";
Debug("uf-ss-na") << std::endl;
Unimplemented("Cannot perform finite model finding on datatype quantifier");
}
+ */
}
}
}
std::map< TypeNode, ConflictFind* >::iterator it = d_conf_find.find( tn );
//pre-register the type if not done already
if( it==d_conf_find.end() ){
- if( isRelevantType( tn ) ){
+ if( tn.isSort() ){
preRegisterType( tn );
it = d_conf_find.find( tn );
}
StatisticsRegistry::unregisterStat(&d_max_model_size);
}
-bool StrongSolverTheoryUf::isRelevantType( TypeNode t ){
- return t!=NodeManager::currentNM()->booleanType() &&
- t!=NodeManager::currentNM()->integerType() &&
- t!=NodeManager::currentNM()->realType() &&
- t!=NodeManager::currentNM()->builtinOperatorType() &&
- !t.isFunction() &&
- !t.isDatatype() &&
- !t.isArray();
-}
-
bool StrongSolverTheoryUf::involvesRelevantType( Node n ){
if( n.getKind()==APPLY_UF ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( isRelevantType( n[i].getType() ) ){
+ if( n[i].getType().isSort() ){
return true;
}
}
/** statistics class */
Statistics d_statistics;
- /** is relevant type */
- static bool isRelevantType( TypeNode t );
/** involves relevant type */
static bool involvesRelevantType( Node n );
};/* class StrongSolverTheoryUf */
v2l40025.cvc \
v3l60006.cvc \
v5l30058.cvc \
- bug286.cvc
+ bug286.cvc \
+ wrong-sel-simp.cvc
FAILING_TESTS = rec5.cvc
-% EXPECT: valid
-% EXIT: 20
+% EXPECT: invalid
+% EXIT: 10
DATATYPE
nat = succ(pred : nat) | zero,
list = cons(car : tree, cdr : list) | null,
--- /dev/null
+% EXPECT: invalid
+% EXIT: 10
+DATATYPE
+ nat = succ(pred : nat) | zero
+END;
+
+QUERY pred(zero) = zero;