summaryrefslogtreecommitdiff
path: root/src/theory
diff options
context:
space:
mode:
Diffstat (limited to 'src/theory')
-rw-r--r--src/theory/quantifiers/bounded_integers.cpp5
-rw-r--r--src/theory/quantifiers/first_order_model.cpp257
-rw-r--r--src/theory/quantifiers/first_order_model.h73
-rw-r--r--src/theory/quantifiers/full_model_check.cpp33
-rw-r--r--src/theory/quantifiers/full_model_check.h2
-rw-r--r--src/theory/quantifiers/macros.cpp2
-rw-r--r--src/theory/quantifiers/model_builder.cpp39
-rw-r--r--src/theory/quantifiers/model_engine.cpp46
-rw-r--r--src/theory/quantifiers/model_engine.h2
-rw-r--r--src/theory/quantifiers/modes.cpp23
-rw-r--r--src/theory/quantifiers/modes.h23
-rw-r--r--src/theory/quantifiers/options43
-rw-r--r--src/theory/quantifiers/options_handlers.h80
-rwxr-xr-xsrc/theory/quantifiers/qinterval_builder.cpp1111
-rwxr-xr-xsrc/theory/quantifiers/qinterval_builder.h155
-rwxr-xr-xsrc/theory/quantifiers/quant_conflict_find.cpp1907
-rwxr-xr-xsrc/theory/quantifiers/quant_conflict_find.h258
-rw-r--r--src/theory/quantifiers/quant_util.cpp14
-rw-r--r--src/theory/quantifiers/quant_util.h2
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.cpp56
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.h4
-rw-r--r--src/theory/quantifiers/term_database.cpp10
-rw-r--r--src/theory/quantifiers/trigger.cpp8
-rw-r--r--src/theory/quantifiers_engine.cpp26
-rw-r--r--src/theory/quantifiers_engine.h11
-rw-r--r--src/theory/strings/kinds17
-rw-r--r--src/theory/strings/theory_strings.cpp258
-rw-r--r--src/theory/strings/theory_strings.h11
-rw-r--r--src/theory/strings/theory_strings_preprocess.cpp130
-rw-r--r--src/theory/strings/theory_strings_preprocess.h1
-rw-r--r--src/theory/strings/theory_strings_rewriter.cpp71
-rw-r--r--src/theory/strings/theory_strings_type_rules.h86
-rw-r--r--src/theory/theory.h7
-rw-r--r--src/theory/theory_engine.cpp15
-rw-r--r--src/theory/theory_engine.h7
-rw-r--r--src/theory/uf/equality_engine.cpp217
-rw-r--r--src/theory/uf/equality_engine.h38
-rw-r--r--src/theory/uf/equality_engine_types.h29
-rw-r--r--src/theory/uf/options6
-rw-r--r--src/theory/uf/theory_uf.cpp11
-rw-r--r--src/theory/uf/theory_uf_model.cpp32
-rw-r--r--src/theory/uf/theory_uf_strong_solver.cpp159
-rw-r--r--src/theory/uf/theory_uf_strong_solver.h24
43 files changed, 4769 insertions, 540 deletions
diff --git a/src/theory/quantifiers/bounded_integers.cpp b/src/theory/quantifiers/bounded_integers.cpp
index 28485a979..d4faf41fe 100644
--- a/src/theory/quantifiers/bounded_integers.cpp
+++ b/src/theory/quantifiers/bounded_integers.cpp
@@ -198,10 +198,9 @@ void BoundedIntegers::processLiteral( Node f, Node lit, bool pol,
void BoundedIntegers::process( Node f, Node n, bool pol,
std::map< int, std::map< Node, Node > >& bound_lit_map,
std::map< int, std::map< Node, bool > >& bound_lit_pol_map ){
- if( (( n.getKind()==IMPLIES || n.getKind()==OR) && pol) || (n.getKind()==AND && !pol) ){
+ if( (n.getKind()==OR && pol) || (n.getKind()==AND && !pol) ){
for( unsigned i=0; i<n.getNumChildren(); i++) {
- bool newPol = n.getKind()==IMPLIES && i==0 ? !pol : pol;
- process( f, n[i], newPol, bound_lit_map, bound_lit_pol_map );
+ process( f, n[i], pol, bound_lit_map, bound_lit_pol_map );
}
}else if( n.getKind()==NOT ){
process( f, n[0], !pol, bound_lit_map, bound_lit_pol_map );
diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp
index bda124e96..a05abfa29 100644
--- a/src/theory/quantifiers/first_order_model.cpp
+++ b/src/theory/quantifiers/first_order_model.cpp
@@ -16,6 +16,8 @@
#include "theory/quantifiers/model_engine.h"
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/full_model_check.h"
+#include "theory/quantifiers/qinterval_builder.h"
#define USE_INDEX_ORDERING
@@ -27,8 +29,9 @@ using namespace CVC4::theory;
using namespace CVC4::theory::quantifiers;
using namespace CVC4::theory::quantifiers::fmcheck;
-FirstOrderModel::FirstOrderModel( context::Context* c, std::string name ) : TheoryModel( c, name, true ),
-d_axiom_asserted( c, false ), d_forall_asserts( c ), d_isModelSet( c, false ){
+FirstOrderModel::FirstOrderModel(QuantifiersEngine * qe, context::Context* c, std::string name ) :
+TheoryModel( c, name, true ),
+d_qe( qe ), d_axiom_asserted( c, false ), d_forall_asserts( c ), d_isModelSet( c, false ){
}
@@ -66,16 +69,23 @@ Node FirstOrderModel::getCurrentModelValue( Node n, bool partial ) {
}
void FirstOrderModel::initialize( bool considerAxioms ) {
- processInitialize();
+ processInitialize( true );
//this is called after representatives have been chosen and the equality engine has been built
//for each quantifier, collect all operators we care about
for( int i=0; i<getNumAssertedQuantifiers(); i++ ){
Node f = getAssertedQuantifier( i );
+ processInitializeQuantifier( f );
+ if( d_quant_var_id.find( f )==d_quant_var_id.end() ){
+ for(unsigned i=0; i<f[0].getNumChildren(); i++){
+ d_quant_var_id[f][f[0][i]] = i;
+ }
+ }
if( considerAxioms || !f.hasAttribute(AxiomAttribute()) ){
//initialize relevant models within bodies of all quantifiers
initializeModelForTerm( f[1] );
}
}
+ processInitialize( false );
}
void FirstOrderModel::initializeModelForTerm( Node n ){
@@ -85,14 +95,30 @@ void FirstOrderModel::initializeModelForTerm( Node n ){
}
}
-FirstOrderModelIG::FirstOrderModelIG(context::Context* c, std::string name) : FirstOrderModel(c,name) {
+Node FirstOrderModel::getSomeDomainElement(TypeNode tn){
+ //check if there is even any domain elements at all
+ if (!d_rep_set.hasType(tn)) {
+ Trace("fmc-model-debug") << "Must create domain element for " << tn << "..." << std::endl;
+ Node mbt = d_qe->getTermDatabase()->getModelBasisTerm(tn);
+ d_rep_set.add(mbt);
+ }else if( d_rep_set.d_type_reps[tn].size()==0 ){
+ Message() << "empty reps" << std::endl;
+ exit(0);
+ }
+ return d_rep_set.d_type_reps[tn][0];
+}
+
+FirstOrderModelIG::FirstOrderModelIG(QuantifiersEngine * qe, context::Context* c, std::string name) :
+FirstOrderModel(qe, c,name) {
}
-void FirstOrderModelIG::processInitialize(){
- //rebuild models
- d_uf_model_tree.clear();
- d_uf_model_gen.clear();
+void FirstOrderModelIG::processInitialize( bool ispre ){
+ if( ispre ){
+ //rebuild models
+ d_uf_model_tree.clear();
+ d_uf_model_gen.clear();
+ }
}
void FirstOrderModelIG::processInitializeModelForTerm( Node n ){
@@ -143,12 +169,12 @@ void FirstOrderModelIG::resetEvaluate(){
// each n{ri->d_index[0]/x_0...ri->d_index[depIndex]/x_depIndex, */x_(depIndex+1) ... */x_n } is equivalent in the current model
int FirstOrderModelIG::evaluate( Node n, int& depIndex, RepSetIterator* ri ){
++d_eval_formulas;
- //Debug("fmf-eval-debug") << "Evaluate " << n << " " << phaseReq << std::endl;
+ Debug("fmf-eval-debug2") << "Evaluate " << n << std::endl;
//Notice() << "Eval " << n << std::endl;
if( n.getKind()==NOT ){
int val = evaluate( n[0], depIndex, ri );
return val==1 ? -1 : ( val==-1 ? 1 : 0 );
- }else if( n.getKind()==OR || n.getKind()==AND || n.getKind()==IMPLIES ){
+ }else if( n.getKind()==OR || n.getKind()==AND ){
int baseVal = n.getKind()==AND ? 1 : -1;
int eVal = baseVal;
int posDepIndex = ri->getNumTerms();
@@ -156,7 +182,7 @@ int FirstOrderModelIG::evaluate( Node n, int& depIndex, RepSetIterator* ri ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
//evaluate subterm
int childDepIndex;
- Node nn = ( i==0 && n.getKind()==IMPLIES ) ? n[i].notNode() : n[i];
+ Node nn = n[i];
int eValT = evaluate( nn, childDepIndex, ri );
if( eValT==baseVal ){
if( eVal==baseVal ){
@@ -184,12 +210,12 @@ int FirstOrderModelIG::evaluate( Node n, int& depIndex, RepSetIterator* ri ){
}else{
return 0;
}
- }else if( n.getKind()==IFF || n.getKind()==XOR ){
+ }else if( n.getKind()==IFF ){
int depIndex1;
int eVal = evaluate( n[0], depIndex1, ri );
if( eVal!=0 ){
int depIndex2;
- int eVal2 = evaluate( n.getKind()==XOR ? n[1].notNode() : n[1], depIndex2, ri );
+ int eVal2 = evaluate( n[1], depIndex2, ri );
if( eVal2!=0 ){
depIndex = depIndex1>depIndex2 ? depIndex1 : depIndex2;
return eVal==eVal2 ? 1 : -1;
@@ -421,7 +447,7 @@ void FirstOrderModelIG::makeEvalUfModel( Node n ){
d_eval_uf_model[n] = uf::UfModelTree( op, d_eval_term_index_order[n] );
d_uf_model_gen[op].makeModel( this, d_eval_uf_model[n] );
//Debug("fmf-index-order") << "Make model for " << n << " : " << std::endl;
- //d_eval_uf_model[n].debugPrint( "fmf-index-order", d_qe, 2 );
+ //d_eval_uf_model[n].debugPrint( std::cout, d_qe->getModel(), 2 );
}
}
}
@@ -513,10 +539,8 @@ Node FirstOrderModelIG::getCurrentUfModelValue( Node n, std::vector< Node > & ar
-
-
FirstOrderModelFmc::FirstOrderModelFmc(QuantifiersEngine * qe, context::Context* c, std::string name) :
-FirstOrderModel(c, name), d_qe(qe){
+FirstOrderModel(qe, c, name){
}
@@ -552,19 +576,21 @@ Node FirstOrderModelFmc::getCurrentUfModelValue( Node n, std::vector< Node > & a
return d_models[n.getOperator()]->evaluate(this, args);
}
-void FirstOrderModelFmc::processInitialize() {
- if( options::fmfFmcInterval() && intervalOp.isNull() ){
- std::vector< TypeNode > types;
- for(unsigned i=0; i<2; i++){
- types.push_back(NodeManager::currentNM()->integerType());
+void FirstOrderModelFmc::processInitialize( bool ispre ) {
+ if( ispre ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && intervalOp.isNull() ){
+ std::vector< TypeNode > types;
+ for(unsigned i=0; i<2; i++){
+ types.push_back(NodeManager::currentNM()->integerType());
+ }
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( types, NodeManager::currentNM()->integerType() );
+ intervalOp = NodeManager::currentNM()->mkSkolem( "interval_$$", typ, "op representing interval" );
}
- TypeNode typ = NodeManager::currentNM()->mkFunctionType( types, NodeManager::currentNM()->integerType() );
- intervalOp = NodeManager::currentNM()->mkSkolem( "interval_$$", typ, "op representing interval" );
- }
- for( std::map<Node, Def * >::iterator it = d_models.begin(); it != d_models.end(); ++it ){
- it->second->reset();
+ for( std::map<Node, Def * >::iterator it = d_models.begin(); it != d_models.end(); ++it ){
+ it->second->reset();
+ }
+ d_model_basis_rep.clear();
}
- d_model_basis_rep.clear();
}
void FirstOrderModelFmc::processInitializeModelForTerm(Node n) {
@@ -575,19 +601,6 @@ void FirstOrderModelFmc::processInitializeModelForTerm(Node n) {
}
}
-Node FirstOrderModelFmc::getSomeDomainElement(TypeNode tn){
- //check if there is even any domain elements at all
- if (!d_rep_set.hasType(tn)) {
- Trace("fmc-model-debug") << "Must create domain element for " << tn << "..." << std::endl;
- Node mbt = d_qe->getTermDatabase()->getModelBasisTerm(tn);
- d_rep_set.d_type_reps[tn].push_back(mbt);
- }else if( d_rep_set.d_type_reps[tn].size()==0 ){
- Message() << "empty reps" << std::endl;
- exit(0);
- }
- return d_rep_set.d_type_reps[tn][0];
-}
-
bool FirstOrderModelFmc::isStar(Node n) {
return n==getStar(n.getType());
@@ -603,7 +616,7 @@ Node FirstOrderModelFmc::getStar(TypeNode tn) {
Node FirstOrderModelFmc::getStarElement(TypeNode tn) {
Node st = getStar(tn);
- if( options::fmfFmcInterval() && tn.isInteger() ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && tn.isInteger() ){
st = getInterval( st, st );
}
return st;
@@ -684,3 +697,163 @@ bool FirstOrderModelFmc::isInRange( Node v, Node i ) {
return v==i;
}
}
+
+
+FirstOrderModelQInt::FirstOrderModelQInt(QuantifiersEngine * qe, context::Context* c, std::string name) :
+FirstOrderModel(qe, c, name) {
+
+}
+
+void FirstOrderModelQInt::processInitialize( bool ispre ) {
+ if( !ispre ){
+ Trace("qint-debug") << "Process initialize" << std::endl;
+ for( std::map<Node, QIntDef * >::iterator it = d_models.begin(); it != d_models.end(); ++it ) {
+ Node op = it->first;
+ TypeNode tno = op.getType();
+ Trace("qint-debug") << " Init " << op << " " << tno << std::endl;
+ for( unsigned i=0; i<tno.getNumChildren(); i++) {
+ //make sure a representative of the type exists
+ if( !d_rep_set.hasType( tno[i] ) ){
+ Node e = getSomeDomainElement( tno[i] );
+ Trace("qint-debug") << " * Initialize type " << tno[i] << ", add ";
+ Trace("qint-debug") << e << " " << e.getType() << std::endl;
+ //d_rep_set.add( e );
+ }
+ }
+ }
+ }
+}
+
+Node FirstOrderModelQInt::getFunctionValue(Node op, const char* argPrefix ) {
+ Trace("qint-debug") << "Get function value for " << op << std::endl;
+ TypeNode type = op.getType();
+ std::vector< Node > vars;
+ for( size_t i=0; i<type.getNumChildren()-1; i++ ){
+ std::stringstream ss;
+ ss << argPrefix << (i+1);
+ Node b = NodeManager::currentNM()->mkBoundVar( ss.str(), type[i] );
+ vars.push_back( b );
+ }
+ Node boundVarList = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, vars);
+ Node curr = d_models[op]->getFunctionValue( this, vars );
+ Node fv = NodeManager::currentNM()->mkNode(kind::LAMBDA, boundVarList, curr);
+ Trace("qint-debug") << "Return " << fv << std::endl;
+ return fv;
+}
+
+Node FirstOrderModelQInt::getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial ) {
+ Debug("qint-debug") << "get curr uf value " << n << std::endl;
+ return d_models[n]->evaluate( this, args );
+}
+
+void FirstOrderModelQInt::processInitializeModelForTerm(Node n) {
+ Debug("qint-debug") << "process init " << n << " " << n.getKind() << std::endl;
+
+ if( n.getKind()==APPLY_UF || n.getKind()==VARIABLE || n.getKind()==SKOLEM ){
+ Node op = n.getKind()==APPLY_UF ? n.getOperator() : n;
+ if( d_models.find(op)==d_models.end()) {
+ Debug("qint-debug") << "init model for " << op << std::endl;
+ d_models[op] = new QIntDef;
+ }
+ }
+}
+
+Node FirstOrderModelQInt::getUsedRepresentative( Node n ) {
+ if( hasTerm( n ) ){
+ if( n.getType().isBoolean() ){
+ return areEqual(n, d_true) ? d_true : d_false;
+ }else{
+ return getRepresentative( n );
+ }
+ }else{
+ Trace("qint-debug") << "Get rep " << n << " " << n.getType() << std::endl;
+ Assert( d_rep_set.hasType( n.getType() ) && !d_rep_set.d_type_reps[n.getType()].empty() );
+ return d_rep_set.d_type_reps[n.getType()][0];
+ }
+}
+
+void FirstOrderModelQInt::processInitializeQuantifier( Node q ) {
+ if( d_var_order.find( q )==d_var_order.end() ){
+ d_var_order[q] = new QuantVarOrder( q );
+ d_var_order[q]->debugPrint("qint-var-order");
+ Trace("qint-var-order") << std::endl;
+ }
+}
+unsigned FirstOrderModelQInt::getOrderedNumVars( Node q ) {
+ //return q[0].getNumChildren();
+ return d_var_order[q]->getNumVars();
+}
+
+TypeNode FirstOrderModelQInt::getOrderedVarType( Node q, int i ) {
+ //return q[0][i].getType();
+ return d_var_order[q]->getVar( i ).getType();
+}
+
+int FirstOrderModelQInt::getOrderedVarNumToVarNum( Node q, int i ) {
+ return getVariableId( q, d_var_order[q]->getVar( i ) );
+}
+
+bool FirstOrderModelQInt::isLessThan( Node v1, Node v2 ) {
+ Assert( !v1.isNull() );
+ Assert( !v2.isNull() );
+ if( v1.getType().isSort() ){
+ Assert( getRepId( v1 )!=-1 );
+ Assert( getRepId( v2 )!=-1 );
+ int rid1 = d_rep_id[v1];
+ int rid2 = d_rep_id[v2];
+ return rid1<rid2;
+ }else{
+ return false;
+ }
+}
+
+Node FirstOrderModelQInt::getMin( Node v1, Node v2 ) {
+ return isLessThan( v1, v2 ) ? v1 : v2;
+}
+
+Node FirstOrderModelQInt::getMax( Node v1, Node v2 ) {
+ return isLessThan( v1, v2 ) ? v2 : v1;
+}
+
+Node FirstOrderModelQInt::getMaximum( TypeNode tn ) {
+ return d_max[tn];
+}
+
+Node FirstOrderModelQInt::getNext( TypeNode tn, Node v ) {
+ if( v.isNull() ){
+ return d_min[tn];
+ }else{
+ Assert( getRepId( v )!=-1 );
+ int rid = d_rep_id[v];
+ if( rid==(int)(d_rep_set.d_type_reps[tn].size()-1) ){
+ Assert( false );
+ return Node::null();
+ }else{
+ return d_rep_set.d_type_reps[tn][ rid+1 ];
+ }
+ }
+}
+Node FirstOrderModelQInt::getPrev( TypeNode tn, Node v ) {
+ if( v.isNull() ){
+ Assert( false );
+ return Node::null();
+ }else{
+ Assert( getRepId( v )!=-1 );
+ int rid = d_rep_id[v];
+ if( rid==0 ){
+ return Node::null();
+ }else{
+ return d_rep_set.d_type_reps[tn][ rid-1 ];
+ }
+ }
+}
+
+bool FirstOrderModelQInt::doMeet( Node l1, Node u1, Node l2, Node u2, Node& lr, Node& ur ) {
+ Trace("qint-debug2") << "doMeet " << l1 << "..." << u1 << " with " << l2 << "..." << u2 << std::endl;
+ Assert( !u1.isNull() );
+ Assert( !u2.isNull() );
+ lr = l1.isNull() ? l2 : ( l2.isNull() ? l1 : getMax( l1, l2 ) );
+ ur = getMin( u1, u2 );
+ //return lr==ur || lr.isNull() || isLessThan( lr, ur );
+ return lr.isNull() || isLessThan( lr, ur );
+}
diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h
index b5bdff9ee..ab3a1aa52 100644
--- a/src/theory/quantifiers/first_order_model.h
+++ b/src/theory/quantifiers/first_order_model.h
@@ -33,16 +33,21 @@ class FirstOrderModelIG;
namespace fmcheck {
class FirstOrderModelFmc;
}
+class FirstOrderModelQInt;
class FirstOrderModel : public TheoryModel
{
-private:
+protected:
+ /** quant engine */
+ QuantifiersEngine * d_qe;
/** whether an axiom is asserted */
context::CDO< bool > d_axiom_asserted;
/** list of quantifiers asserted in the current context */
context::CDList<Node> d_forall_asserts;
/** is model set */
context::CDO< bool > d_isModelSet;
+ /** get variable id */
+ std::map< Node, std::map< Node, int > > d_quant_var_id;
/** get current model value */
virtual Node getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial ) = 0;
public: //for Theory Quantifiers:
@@ -57,20 +62,28 @@ public: //for Theory Quantifiers:
/** initialize model for term */
void initializeModelForTerm( Node n );
virtual void processInitializeModelForTerm( Node n ) = 0;
+ virtual void processInitializeQuantifier( Node q ) {}
public:
- FirstOrderModel( context::Context* c, std::string name );
+ FirstOrderModel(QuantifiersEngine * qe, context::Context* c, std::string name );
virtual ~FirstOrderModel(){}
virtual FirstOrderModelIG * asFirstOrderModelIG() { return NULL; }
virtual fmcheck::FirstOrderModelFmc * asFirstOrderModelFmc() { return NULL; }
+ virtual FirstOrderModelQInt * asFirstOrderModelQInt() { return NULL; }
// initialize the model
void initialize( bool considerAxioms = true );
- virtual void processInitialize() = 0;
+ virtual void processInitialize( bool ispre ) = 0;
/** mark model set */
void markModelSet() { d_isModelSet = true; }
/** is model set */
bool isModelSet() { return d_isModelSet; }
/** get current model value */
Node getCurrentModelValue( Node n, bool partial = false );
+ /** get variable id */
+ int getVariableId(Node f, Node n) {
+ return d_quant_var_id.find( f )!=d_quant_var_id.end() ? d_quant_var_id[f][n] : -1;
+ }
+ /** get some domain element */
+ Node getSomeDomainElement(TypeNode tn);
};/* class FirstOrderModel */
@@ -93,10 +106,10 @@ private:
Node getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial );
//the following functions are for evaluating quantifier bodies
public:
- FirstOrderModelIG(context::Context* c, std::string name);
+ FirstOrderModelIG(QuantifiersEngine * qe, context::Context* c, std::string name);
FirstOrderModelIG * asFirstOrderModelIG() { return this; }
// initialize the model
- void processInitialize();
+ void processInitialize( bool ispre );
//for initialize model
void processInitializeModelForTerm( Node n );
/** reset evaluation */
@@ -128,8 +141,6 @@ class FirstOrderModelFmc : public FirstOrderModel
{
friend class FullModelChecker;
private:
- /** quant engine */
- QuantifiersEngine * d_qe;
/** models for UF */
std::map<Node, Def * > d_models;
std::map<TypeNode, Node > d_model_basis_rep;
@@ -143,8 +154,7 @@ public:
FirstOrderModelFmc(QuantifiersEngine * qe, context::Context* c, std::string name);
FirstOrderModelFmc * asFirstOrderModelFmc() { return this; }
// initialize the model
- void processInitialize();
-
+ void processInitialize( bool ispre );
Node getFunctionValue(Node op, const char* argPrefix );
bool isStar(Node n);
@@ -152,7 +162,6 @@ public:
Node getStarElement(TypeNode tn);
bool isModelBasisTerm(Node n);
Node getModelBasisTerm(TypeNode tn);
- Node getSomeDomainElement(TypeNode tn);
bool isInterval(Node n);
Node getInterval( Node lb, Node ub );
bool isInRange( Node v, Node i );
@@ -161,6 +170,50 @@ public:
}
+class QIntDef;
+class QuantVarOrder;
+class FirstOrderModelQInt : public FirstOrderModel
+{
+ friend class QIntervalBuilder;
+private:
+ /** uf op to some representation */
+ std::map<Node, QIntDef * > d_models;
+ /** representatives to ids */
+ std::map< Node, int > d_rep_id;
+ std::map< TypeNode, Node > d_min;
+ std::map< TypeNode, Node > d_max;
+ /** quantifiers to information regarding variable ordering */
+ std::map<Node, QuantVarOrder * > d_var_order;
+ /** get current model value */
+ Node getCurrentUfModelValue( Node n, std::vector< Node > & args, bool partial );
+ void processInitializeModelForTerm(Node n);
+public:
+ FirstOrderModelQInt(QuantifiersEngine * qe, context::Context* c, std::string name);
+ FirstOrderModelQInt * asFirstOrderModelQInt() { return this; }
+ void processInitialize( bool ispre );
+ Node getFunctionValue(Node op, const char* argPrefix );
+
+ Node getUsedRepresentative( Node n );
+ int getRepId( Node n ) { return d_rep_id.find( n )==d_rep_id.end() ? -1 : d_rep_id[n]; }
+ bool isLessThan( Node v1, Node v2 );
+ Node getMin( Node v1, Node v2 );
+ Node getMax( Node v1, Node v2 );
+ Node getMinimum( TypeNode tn ) { return getNext( tn, Node::null() ); }
+ Node getMaximum( TypeNode tn );
+ bool isMinimum( Node n ) { return n==getMinimum( n.getType() ); }
+ bool isMaximum( Node n ) { return n==getMaximum( n.getType() ); }
+ Node getNext( TypeNode tn, Node v );
+ Node getPrev( TypeNode tn, Node v );
+ bool doMeet( Node l1, Node u1, Node l2, Node u2, Node& lr, Node& ur );
+ QuantVarOrder * getVarOrder( Node q ) { return d_var_order[q]; }
+
+ void processInitializeQuantifier( Node q ) ;
+ unsigned getOrderedNumVars( Node q );
+ TypeNode getOrderedVarType( Node q, int i );
+ int getOrderedVarNumToVarNum( Node q, int i );
+};
+
+
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp
index 2f32ec5e6..c7d7b7415 100644
--- a/src/theory/quantifiers/full_model_check.cpp
+++ b/src/theory/quantifiers/full_model_check.cpp
@@ -60,9 +60,9 @@ bool EntryTrie::hasGeneralization( FirstOrderModelFmc * m, Node c, int index ) {
return true;
}
}
- if( !options::fmfFmcInterval() || !c[index].getType().isInteger() ){
+ if( options::mbqiMode()!=quantifiers::MBQI_FMC_INTERVAL || !c[index].getType().isInteger() ){
//for star: check if all children are defined and have generalizations
- if( options::fmfFmcCoverSimplify() && c[index]==st ){
+ if( c[index]==st ){ ///options::fmfFmcCoverSimplify()
//check if all children exist and are complete
int num_child_def = d_child.size() - (d_child.find(st)!=d_child.end() ? 1 : 0);
if( num_child_def==m->d_rep_set.getNumRepresentatives(tn) ){
@@ -92,7 +92,7 @@ int EntryTrie::getGeneralizationIndex( FirstOrderModelFmc * m, std::vector<Node>
return d_data;
}else{
int minIndex = -1;
- if( options::fmfFmcInterval() && inst[index].getType().isInteger() ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && inst[index].getType().isInteger() ){
for( std::map<Node,EntryTrie>::iterator it = d_child.begin(); it != d_child.end(); ++it ){
//if( !m->isInterval( it->first ) ){
// std::cout << "Not an interval during getGenIndex " << it->first << std::endl;
@@ -327,7 +327,7 @@ QModelBuilder( c, qe ){
bool FullModelChecker::optBuildAtFullModel() {
//need to build after full model has taken effect if we are constructing interval models
// this is because we need to have a constant in all integer equivalence classes
- return options::fmfFmcInterval();
+ return options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL;
}
void FullModelChecker::processBuildModel(TheoryModel* m, bool fullModel){
@@ -443,7 +443,7 @@ void FullModelChecker::processBuildModel(TheoryModel* m, bool fullModel){
Trace("fmc-warn") << "Warning : model has non-constant argument in model " << ri << std::endl;
}
children.push_back(ri);
- if( !options::fmfFmcInterval() || !ri.getType().isInteger() ){
+ if( options::mbqiMode()!=quantifiers::MBQI_FMC_INTERVAL || !ri.getType().isInteger() ){
if (fm->isModelBasisTerm(ri) ) {
ri = fm->getStar( ri.getType() );
}else{
@@ -485,7 +485,7 @@ void FullModelChecker::processBuildModel(TheoryModel* m, bool fullModel){
}
- if( options::fmfFmcInterval() ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL ){
convertIntervalModel( fm, op );
}
@@ -588,7 +588,6 @@ bool FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f,
std::vector< TypeNode > types;
for(unsigned i=0; i<f[0].getNumChildren(); i++){
types.push_back(f[0][i].getType());
- d_quant_var_id[f][f[0][i]] = i;
}
TypeNode typ = NodeManager::currentNM()->mkFunctionType( types, NodeManager::currentNM()->booleanType() );
Node op = NodeManager::currentNM()->mkSkolem( "fmc_$$", typ, "op created for full-model checking" );
@@ -599,7 +598,7 @@ bool FullModelChecker::doExhaustiveInstantiation( FirstOrderModel * fm, Node f,
initializeType( fmfmc, f[0][i].getType() );
}
- if( !options::fmfModelBasedInst() ){
+ if( options::mbqiMode()==MBQI_NONE ){
//just exhaustive instantiate
Node c = mkCondDefault( fmfmc, f );
d_quant_models[f].addEntry( fmfmc, c, d_false );
@@ -958,8 +957,8 @@ void FullModelChecker::doVariableEquality( FirstOrderModelFmc * fm, Node f, Def
}else{
TypeNode tn = eq[0].getType();
if( tn.isSort() ){
- int j = getVariableId(f, eq[0]);
- int k = getVariableId(f, eq[1]);
+ int j = fm->getVariableId(f, eq[0]);
+ int k = fm->getVariableId(f, eq[1]);
if( !fm->d_rep_set.hasType( tn ) ){
getSomeDomainElement( fm, tn ); //to verify the type is initialized
}
@@ -977,7 +976,7 @@ void FullModelChecker::doVariableEquality( FirstOrderModelFmc * fm, Node f, Def
}
void FullModelChecker::doVariableRelation( FirstOrderModelFmc * fm, Node f, Def & d, Def & dc, Node v) {
- int j = getVariableId(f, v);
+ int j = fm->getVariableId(f, v);
for (unsigned i=0; i<dc.d_cond.size(); i++) {
Node val = dc.d_value[i];
if( val.isNull() ){
@@ -1074,7 +1073,7 @@ void FullModelChecker::doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
Trace("fmc-uf-process") << "Process " << v << std::endl;
bool bind_var = false;
if( !v.isNull() && v.getKind()==kind::BOUND_VARIABLE ){
- int j = getVariableId(f, v);
+ int j = fm->getVariableId(f, v);
Trace("fmc-uf-process") << v << " is variable #" << j << std::endl;
if (!fm->isStar(cond[j+1]) && !fm->isInterval(cond[j+1])) {
v = cond[j+1];
@@ -1084,7 +1083,7 @@ void FullModelChecker::doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
}
if (bind_var) {
Trace("fmc-uf-process") << "bind variable..." << std::endl;
- int j = getVariableId(f, v);
+ int j = fm->getVariableId(f, v);
if( fm->isStar(cond[j+1]) ){
for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
cond[j+1] = it->first;
@@ -1104,7 +1103,7 @@ void FullModelChecker::doUninterpretedCompose2( FirstOrderModelFmc * fm, Node f,
}
}else{
if( !v.isNull() ){
- if( options::fmfFmcInterval() && v.getType().isInteger() ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && v.getType().isInteger() ){
for (std::map<Node, EntryTrie>::iterator it = curr.d_child.begin(); it != curr.d_child.end(); ++it) {
if( fm->isInRange( v, it->first ) ){
doUninterpretedCompose2(fm, f, entries, index+1, cond, val, it->second);
@@ -1166,7 +1165,7 @@ int FullModelChecker::isCompat( FirstOrderModelFmc * fm, std::vector< Node > & c
Trace("fmc-debug3") << "isCompat " << c << std::endl;
Assert(cond.size()==c.getNumChildren()+1);
for (unsigned i=1; i<cond.size(); i++) {
- if( options::fmfFmcInterval() && cond[i].getType().isInteger() ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && cond[i].getType().isInteger() ){
Node iv = doIntervalMeet( fm, cond[i], c[i-1], false );
if( iv.isNull() ){
return 0;
@@ -1185,7 +1184,7 @@ bool FullModelChecker::doMeet( FirstOrderModelFmc * fm, std::vector< Node > & co
Assert(cond.size()==c.getNumChildren()+1);
for (unsigned i=1; i<cond.size(); i++) {
if( cond[i]!=c[i-1] ) {
- if( options::fmfFmcInterval() && cond[i].getType().isInteger() ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL && cond[i].getType().isInteger() ){
Node iv = doIntervalMeet( fm, cond[i], c[i-1] );
if( !iv.isNull() ){
cond[i] = iv;
@@ -1255,7 +1254,7 @@ Node FullModelChecker::mkCondDefault( FirstOrderModelFmc * fm, Node f) {
}
void FullModelChecker::mkCondDefaultVec( FirstOrderModelFmc * fm, Node f, std::vector< Node > & cond ) {
- Trace("fmc-debug") << "Make default vec, intervals = " << options::fmfFmcInterval() << std::endl;
+ Trace("fmc-debug") << "Make default vec, intervals = " << (options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL) << std::endl;
//get function symbol for f
cond.push_back(d_quant_cond[f]);
for (unsigned i=0; i<f[0].getNumChildren(); i++) {
diff --git a/src/theory/quantifiers/full_model_check.h b/src/theory/quantifiers/full_model_check.h
index 606392831..db5abb01e 100644
--- a/src/theory/quantifiers/full_model_check.h
+++ b/src/theory/quantifiers/full_model_check.h
@@ -92,7 +92,6 @@ protected:
std::map<Node, Node > d_quant_cond;
std::map< TypeNode, Node > d_array_cond;
std::map< Node, Node > d_array_term_cond;
- std::map<Node, std::map< Node, int > > d_quant_var_id;
std::map<Node, std::vector< int > > d_star_insts;
void initializeType( FirstOrderModelFmc * fm, TypeNode tn );
Node normalizeArgReps(FirstOrderModelFmc * fm, Node op, Node n);
@@ -138,7 +137,6 @@ public:
bool optBuildAtFullModel();
- int getVariableId(Node f, Node n) { return d_quant_var_id[f][n]; }
void debugPrintCond(const char * tr, Node n, bool dispStar = false);
void debugPrint(const char * tr, Node n, bool dispStar = false);
diff --git a/src/theory/quantifiers/macros.cpp b/src/theory/quantifiers/macros.cpp
index 9cd12fbfb..600f8c0b9 100644
--- a/src/theory/quantifiers/macros.cpp
+++ b/src/theory/quantifiers/macros.cpp
@@ -233,7 +233,7 @@ bool QuantifierMacros::getSubstitution( std::vector< Node >& v_quant, std::map<
void QuantifierMacros::process( Node n, bool pol, std::vector< Node >& args, Node f ){
if( n.getKind()==NOT ){
process( n[0], !pol, args, f );
- }else if( n.getKind()==AND || n.getKind()==OR || n.getKind()==IMPLIES ){
+ }else if( n.getKind()==AND || n.getKind()==OR ){
//bool favorPol = (n.getKind()==AND)==pol;
//conditional?
}else if( n.getKind()==ITE ){
diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp
index ea6f2d775..493d54b53 100644
--- a/src/theory/quantifiers/model_builder.cpp
+++ b/src/theory/quantifiers/model_builder.cpp
@@ -44,7 +44,7 @@ bool QModelBuilder::isQuantifierActive( Node f ) {
bool QModelBuilder::optUseModel() {
- return options::fmfModelBasedInst() || options::fmfBoundInt();
+ return options::mbqiMode()!=MBQI_NONE || options::fmfBoundInt();
}
void QModelBuilder::debugModel( FirstOrderModel* fm ){
@@ -124,6 +124,7 @@ Node QModelBuilderIG::getCurrentUfModelValue( FirstOrderModel* fm, Node n, std::
void QModelBuilderIG::processBuildModel( TheoryModel* m, bool fullModel ) {
FirstOrderModel* f = (FirstOrderModel*)m;
FirstOrderModelIG* fm = f->asFirstOrderModelIG();
+ Trace("model-engine-debug") << "Process build model, fullModel = " << fullModel << " " << optUseModel() << std::endl;
if( fullModel ){
Assert( d_curr_model==fm );
//update models
@@ -145,7 +146,7 @@ void QModelBuilderIG::processBuildModel( TheoryModel* m, bool fullModel ) {
reset( fm );
//only construct first order model if optUseModel() is true
if( optUseModel() ){
- Trace("model-engine-debug") << "Initializing quantifiers..." << std::endl;
+ Trace("model-engine-debug") << "Initializing " << fm->getNumAssertedQuantifiers() << " quantifiers..." << std::endl;
//check if any quantifiers are un-initialized
for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
Node f = fm->getAssertedQuantifier( i );
@@ -272,17 +273,15 @@ int QModelBuilderIG::initializeQuantifier( Node f, Node fp ){
++(d_statistics.d_num_quants_init);
}
//try to add it
- if( optInstGen() ){
- Trace("inst-fmf-init") << "Init: try to add match " << d_quant_basis_match[f] << std::endl;
- //add model basis instantiation
- if( d_qe->addInstantiation( fp, d_quant_basis_match[f], false, false, false ) ){
- d_quant_basis_match_added[f] = true;
- return 1;
- }else{
- //shouldn't happen usually, but will occur if x != y is a required literal for f.
- //Notice() << "No model basis for " << f << std::endl;
- d_quant_basis_match_added[f] = false;
- }
+ Trace("inst-fmf-init") << "Init: try to add match " << d_quant_basis_match[f] << std::endl;
+ //add model basis instantiation
+ if( d_qe->addInstantiation( fp, d_quant_basis_match[f], false, false, false ) ){
+ d_quant_basis_match_added[f] = true;
+ return 1;
+ }else{
+ //shouldn't happen usually, but will occur if x != y is a required literal for f.
+ //Notice() << "No model basis for " << f << std::endl;
+ d_quant_basis_match_added[f] = false;
}
}
return 0;
@@ -397,7 +396,6 @@ bool QModelBuilderIG::isTermActive( Node n ){
//do exhaustive instantiation
bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, int effort ) {
if( optUseModel() ){
-
RepSetIterator riter( d_qe, &(d_qe->getModel()->d_rep_set) );
if( riter.setQuantifier( f ) ){
FirstOrderModelIG * fmig = (FirstOrderModelIG*)d_qe->getModel();
@@ -418,6 +416,7 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i
//if evaluate(...)==1, then the instantiation is already true in the model
// depIndex is the index of the least significant variable that this evaluation relies upon
depIndex = riter.getNumTerms()-1;
+ Debug("fmf-model-eval") << "We will evaluate " << d_qe->getTermDatabase()->getInstConstantBody( f ) << std::endl;
eval = fmig->evaluate( d_qe->getTermDatabase()->getInstConstantBody( f ), depIndex, &riter );
if( eval==1 ){
Debug("fmf-model-eval") << " Returned success with depIndex = " << depIndex << std::endl;
@@ -456,7 +455,7 @@ bool QModelBuilderIG::doExhaustiveInstantiation( FirstOrderModel * fm, Node f, i
d_statistics.d_eval_lits += fmig->d_eval_lits;
d_statistics.d_eval_lits_unknown += fmig->d_eval_lits_unknown;
}
- Trace("inst-fmf-ei") << "Finished: " << std::endl;
+ Trace("inst-fmf-ei") << "For " << f << ", finished: " << std::endl;
Trace("inst-fmf-ei") << " Inst Tried: " << d_triedLemmas << std::endl;
Trace("inst-fmf-ei") << " Inst Added: " << d_addedLemmas << std::endl;
if( d_addedLemmas>1000 ){
@@ -930,13 +929,13 @@ Node QModelBuilderInstGen::getSelectionFormula( Node fn, Node n, bool polarity,
Node ret;
if( n.getKind()==NOT ){
ret = getSelectionFormula( fn[0], n[0], !polarity, useOption );
- }else if( n.getKind()==OR || n.getKind()==IMPLIES || n.getKind()==AND ){
+ }else if( n.getKind()==OR || n.getKind()==AND ){
//whether we only need to find one or all
bool favorPol = ( n.getKind()!=AND && polarity ) || ( n.getKind()==AND && !polarity );
std::vector< Node > children;
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- Node fnc = ( i==0 && fn.getKind()==IMPLIES ) ? fn[i].negate() : fn[i];
- Node nc = ( i==0 && n.getKind()==IMPLIES ) ? n[i].negate() : n[i];
+ Node fnc = fn[i];
+ Node nc = n[i];
Node nn = getSelectionFormula( fnc, nc, polarity, useOption );
if( nn.isNull() && !favorPol ){
//cannot make selection formula
@@ -994,8 +993,8 @@ Node QModelBuilderInstGen::getSelectionFormula( Node fn, Node n, bool polarity,
if( ret.isNull() && !nc[0].isNull() && !nc[1].isNull() ){
ret = mkAndSelectionFormula( nc[0], nc[1] );
}
- }else if( n.getKind()==IFF || n.getKind()==XOR ){
- bool opPol = polarity ? n.getKind()==XOR : n.getKind()==IFF;
+ }else if( n.getKind()==IFF ){
+ bool opPol = !polarity;
for( int p=0; p<2; p++ ){
Node nn[2];
for( int i=0; i<2; i++ ){
diff --git a/src/theory/quantifiers/model_engine.cpp b/src/theory/quantifiers/model_engine.cpp
index 99f5e8df6..9e3e77c8e 100644
--- a/src/theory/quantifiers/model_engine.cpp
+++ b/src/theory/quantifiers/model_engine.cpp
@@ -21,6 +21,8 @@
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/full_model_check.h"
+#include "theory/quantifiers/qinterval_builder.h"
using namespace std;
using namespace CVC4;
@@ -34,11 +36,18 @@ using namespace CVC4::theory::inst;
ModelEngine::ModelEngine( context::Context* c, QuantifiersEngine* qe ) :
QuantifiersModule( qe ){
- if( options::fmfFullModelCheck() || options::fmfBoundInt() ){
+ Trace("model-engine-debug") << "Initialize model engine, mbqi : " << options::mbqiMode() << " " << options::fmfBoundInt() << std::endl;
+ if( options::mbqiMode()==MBQI_FMC || options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL || options::fmfBoundInt() ){
+ Trace("model-engine-debug") << "...make fmc builder." << std::endl;
d_builder = new fmcheck::FullModelChecker( c, qe );
- }else if( options::fmfNewInstGen() ){
+ }else if( options::mbqiMode()==MBQI_INTERVAL ){
+ Trace("model-engine-debug") << "...make interval builder." << std::endl;
+ d_builder = new QIntervalBuilder( c, qe );
+ }else if( options::mbqiMode()==MBQI_INST_GEN ){
+ Trace("model-engine-debug") << "...make inst-gen builder." << std::endl;
d_builder = new QModelBuilderInstGen( c, qe );
}else{
+ Trace("model-engine-debug") << "...make default model builder." << std::endl;
d_builder = new QModelBuilderDefault( c, qe );
}
@@ -169,15 +178,17 @@ int ModelEngine::checkModel(){
it != fm->d_rep_set.d_type_reps.end(); ++it ){
if( it->first.isSort() ){
Trace("model-engine") << "Cardinality( " << it->first << " )" << " = " << it->second.size() << std::endl;
- Trace("model-engine-debug") << " ";
- Node mbt = d_quantEngine->getTermDatabase()->getModelBasisTerm(it->first);
- for( size_t i=0; i<it->second.size(); i++ ){
- //Trace("model-engine-debug") << it->second[i] << " ";
- Node r = d_quantEngine->getEqualityQuery()->getInternalRepresentative( it->second[i], Node::null(), 0 );
- Trace("model-engine-debug") << r << " ";
+ if( Trace.isOn("model-engine-debug") ){
+ Trace("model-engine-debug") << " ";
+ Node mbt = d_quantEngine->getTermDatabase()->getModelBasisTerm(it->first);
+ for( size_t i=0; i<it->second.size(); i++ ){
+ //Trace("model-engine-debug") << it->second[i] << " ";
+ Node r = d_quantEngine->getEqualityQuery()->getInternalRepresentative( it->second[i], Node::null(), 0 );
+ Trace("model-engine-debug") << r << " ";
+ }
+ Trace("model-engine-debug") << std::endl;
+ Trace("model-engine-debug") << " Model basis term : " << mbt << std::endl;
}
- Trace("model-engine-debug") << std::endl;
- Trace("model-engine-debug") << " Model basis term : " << mbt << std::endl;
}
}
}
@@ -203,7 +214,7 @@ int ModelEngine::checkModel(){
}
Trace("model-engine-debug") << "Do exhaustive instantiation..." << std::endl;
- int e_max = options::fmfFullModelCheck() && options::fmfModelBasedInst() ? 2 : 1;
+ int e_max = options::mbqiMode()==MBQI_FMC || options::mbqiMode()==MBQI_FMC_INTERVAL ? 2 : 1;
for( int e=0; e<e_max; e++) {
if (d_addedLemmas==0) {
for( int i=0; i<fm->getNumAssertedQuantifiers(); i++ ){
@@ -221,6 +232,8 @@ int ModelEngine::checkModel(){
if( optOneQuantPerRound() && d_addedLemmas>0 ){
break;
}
+ }else{
+ Trace("inst-fmf-ei") << "-> Inactive : " << f << std::endl;
}
}
}
@@ -229,7 +242,6 @@ int ModelEngine::checkModel(){
Trace("model-engine-debug") << "Instantiate axioms : " << ( d_builder->d_considerAxioms ? "yes" : "no" ) << std::endl;
Trace("model-engine") << "Added Lemmas = " << d_addedLemmas << " / " << d_triedLemmas << " / ";
Trace("model-engine") << d_totalLemmas << std::endl;
- d_statistics.d_exh_inst_lemmas += d_addedLemmas;
return d_addedLemmas;
}
@@ -239,11 +251,13 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){
d_builder->d_addedLemmas = 0;
d_builder->d_incomplete_check = false;
if( d_builder->doExhaustiveInstantiation( d_quantEngine->getModel(), f, effort ) ){
+ Trace("inst-fmf-ei") << "-> Builder determined instantiation(s)." << std::endl;
d_triedLemmas += d_builder->d_triedLemmas;
d_addedLemmas += d_builder->d_addedLemmas;
d_incomplete_check = d_incomplete_check || d_builder->d_incomplete_check;
+ d_statistics.d_mbqi_inst_lemmas += d_builder->d_addedLemmas;
}else{
- Trace("inst-fmf-ei") << "Exhaustive instantiate " << f << ", effort = " << effort << "..." << std::endl;
+ Trace("inst-fmf-ei") << "-> Exhaustive instantiate " << f << ", effort = " << effort << "..." << std::endl;
Debug("inst-fmf-ei") << " Instantiation Constants: ";
for( size_t i=0; i<f[0].getNumChildren(); i++ ){
Debug("inst-fmf-ei") << d_quantEngine->getTermDatabase()->getInstantiationConstant( f, i ) << " ";
@@ -273,6 +287,7 @@ void ModelEngine::exhaustiveInstantiate( Node f, int effort ){
}
d_addedLemmas += addedLemmas;
d_triedLemmas += triedLemmas;
+ d_statistics.d_exh_inst_lemmas += addedLemmas;
}
//if the iterator is incomplete, we will return unknown instead of sat if no instantiations are added this round
d_incomplete_check = d_incomplete_check || riter.d_incomplete;
@@ -296,15 +311,18 @@ void ModelEngine::debugPrint( const char* c ){
ModelEngine::Statistics::Statistics():
d_inst_rounds("ModelEngine::Inst_Rounds", 0),
- d_exh_inst_lemmas("ModelEngine::Exhaustive_Instantiation_Lemmas", 0 )
+ d_exh_inst_lemmas("ModelEngine::Instantiations_Exhaustive", 0 ),
+ d_mbqi_inst_lemmas("ModelEngine::Instantiations_Mbqi", 0 )
{
StatisticsRegistry::registerStat(&d_inst_rounds);
StatisticsRegistry::registerStat(&d_exh_inst_lemmas);
+ StatisticsRegistry::registerStat(&d_mbqi_inst_lemmas);
}
ModelEngine::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_inst_rounds);
StatisticsRegistry::unregisterStat(&d_exh_inst_lemmas);
+ StatisticsRegistry::unregisterStat(&d_mbqi_inst_lemmas);
}
diff --git a/src/theory/quantifiers/model_engine.h b/src/theory/quantifiers/model_engine.h
index 0c3c74b5f..ba54d7ba4 100644
--- a/src/theory/quantifiers/model_engine.h
+++ b/src/theory/quantifiers/model_engine.h
@@ -20,7 +20,6 @@
#include "theory/quantifiers_engine.h"
#include "theory/quantifiers/model_builder.h"
#include "theory/theory_model.h"
-#include "theory/quantifiers/full_model_check.h"
#include "theory/quantifiers/relevant_domain.h"
namespace CVC4 {
@@ -69,6 +68,7 @@ public:
public:
IntStat d_inst_rounds;
IntStat d_exh_inst_lemmas;
+ IntStat d_mbqi_inst_lemmas;
Statistics();
~Statistics();
};
diff --git a/src/theory/quantifiers/modes.cpp b/src/theory/quantifiers/modes.cpp
index 7da3b150f..10185914e 100644
--- a/src/theory/quantifiers/modes.cpp
+++ b/src/theory/quantifiers/modes.cpp
@@ -77,5 +77,28 @@ std::ostream& operator<<(std::ostream& out, theory::quantifiers::AxiomInstMode m
return out;
}
+std::ostream& operator<<(std::ostream& out, theory::quantifiers::MbqiMode mode) {
+ switch(mode) {
+ case theory::quantifiers::MBQI_DEFAULT:
+ out << "MBQI_DEFAULT";
+ break;
+ case theory::quantifiers::MBQI_NONE:
+ out << "MBQI_NONE";
+ break;
+ case theory::quantifiers::MBQI_INST_GEN:
+ out << "MBQI_INST_GEN";
+ break;
+ case theory::quantifiers::MBQI_FMC:
+ out << "MBQI_FMC";
+ break;
+ case theory::quantifiers::MBQI_INTERVAL:
+ out << "MBQI_INTERVAL";
+ break;
+ default:
+ out << "MbqiMode!UNKNOWN";
+ }
+ return out;
+}
+
}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/modes.h b/src/theory/quantifiers/modes.h
index edf9c78fe..7a7ce9b54 100644
--- a/src/theory/quantifiers/modes.h
+++ b/src/theory/quantifiers/modes.h
@@ -55,6 +55,29 @@ typedef enum {
AXIOM_INST_MODE_PRIORITY,
} AxiomInstMode;
+typedef enum {
+ /** default, mbqi from CADE 24 paper */
+ MBQI_DEFAULT,
+ /** no mbqi */
+ MBQI_NONE,
+ /** implementation that mimics inst-gen */
+ MBQI_INST_GEN,
+ /** mbqi from Section 5.4.2 of AJR thesis */
+ MBQI_FMC,
+ /** mbqi with integer intervals */
+ MBQI_FMC_INTERVAL,
+ /** mbqi with interval abstraction of uninterpreted sorts */
+ MBQI_INTERVAL,
+} MbqiMode;
+
+typedef enum {
+ /** default, apply at full effort */
+ QCF_WHEN_MODE_DEFAULT,
+ /** apply at standard effort */
+ QCF_WHEN_MODE_STD,
+ /** default */
+ QCF_WHEN_MODE_STD_H,
+} QcfWhenMode;
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
diff --git a/src/theory/quantifiers/options b/src/theory/quantifiers/options
index 1eb98e7b7..dc016be3f 100644
--- a/src/theory/quantifiers/options
+++ b/src/theory/quantifiers/options
@@ -40,7 +40,7 @@ option clauseSplit --clause-split bool :default false
# Whether to pre-skolemize quantifier bodies.
# For example, forall x. ( P( x ) => (exists y. f( y ) = x) ) will be rewritten to
# forall x. P( x ) => f( S( x ) ) = x
-option preSkolemQuant --pre-skolem-quant bool :default false
+option preSkolemQuant --pre-skolem-quant bool :read-write :default false
apply skolemization eagerly to bodies of quantified formulas
option iteRemoveQuant --ite-remove-quant bool :default false
apply ite removal to bodies of quantifiers
@@ -76,9 +76,8 @@ option eagerInstQuant --eager-inst-quant bool :default false
option literalMatchMode --literal-matching=MODE CVC4::theory::quantifiers::LiteralMatchMode :default CVC4::theory::quantifiers::LITERAL_MATCH_NONE :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToLiteralMatchMode :handler-include "theory/quantifiers/options_handlers.h" :predicate CVC4::theory::quantifiers::checkLiteralMatchMode :predicate-include "theory/quantifiers/options_handlers.h"
choose literal matching mode
-option cbqi --enable-cbqi/--disable-cbqi bool :default false
- turns on counterexample-based quantifier instantiation [off by default]
-/turns off counterexample-based quantifier instantiation
+option cbqi --enable-cbqi bool :default false
+ turns on counterexample-based quantifier instantiation
option recurseCbqi --cbqi-recurse bool :default false
turns on recursive counterexample-based quantifier instantiation
@@ -95,41 +94,35 @@ option internalReps /--disable-quant-internal-reps bool :default true
option finiteModelFind --finite-model-find bool :default false
use finite model finding heuristic for quantifier instantiation
-option fmfModelBasedInst /--disable-fmf-mbqi bool :default true
- disable model-based quantifier instantiation for finite model finding
+option mbqiMode --mbqi=MODE CVC4::theory::quantifiers::MbqiMode :read-write :default CVC4::theory::quantifiers::MBQI_DEFAULT :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToMbqiMode :handler-include "theory/quantifiers/options_handlers.h" :predicate CVC4::theory::quantifiers::checkMbqiMode :predicate-include "theory/quantifiers/options_handlers.h"
+ choose mode for model-based quantifier instantiation
+option fmfOneInstPerRound --mbqi-one-inst-per-round bool :default false
+ only add one instantiation per quantifier per round for mbqi
+option fmfOneQuantPerRound --mbqi-one-quant-per-round bool :default false
+ only add instantiations for one quantifier per round for mbqi
-option fmfFullModelCheck --fmf-fmc bool :default false :read-write
- enable full model check for finite model finding
-option fmfFmcSimple /--disable-fmf-fmc-simple bool :default true
- disable simple models in full model check for finite model finding
-option fmfFmcCoverSimplify /--disable-fmf-fmc-cover-simplify bool :default true
- disable covering simplification of fmc models
-option fmfFmcInterval --fmf-fmc-interval bool :default false
- construct interval models for fmc models
-
-option fmfOneInstPerRound --fmf-one-inst-per-round bool :default false
- only add one instantiation per quantifier per round for fmf
-option fmfOneQuantPerRound --fmf-one-quant-per-round bool :default false
- only add instantiations for one quantifier per round for fmf
option fmfInstEngine --fmf-inst-engine bool :default false
use instantiation engine in conjunction with finite model finding
option fmfRelevantDomain --fmf-relevant-domain bool :default false
use relevant domain computation, similar to complete instantiation (Ge, deMoura 09)
-option fmfNewInstGen --fmf-new-inst-gen bool :default false
- use new inst gen technique for answering sat without exhaustive instantiation
-option fmfInstGen --fmf-inst-gen/--disable-fmf-inst-gen bool :read-write :default true
- enable Inst-Gen instantiation techniques for finite model finding (default)
-/disable Inst-Gen instantiation techniques for finite model finding
+option fmfInstGen /--disable-fmf-inst-gen bool :default true
+ disable Inst-Gen instantiation techniques for finite model finding
option fmfInstGenOneQuantPerRound --fmf-inst-gen-one-quant-per-round bool :default false
only perform Inst-Gen instantiation techniques on one quantifier per round
option fmfFreshDistConst --fmf-fresh-dc bool :default false
use fresh distinguished representative when applying Inst-Gen techniques
-
+option fmfFmcSimple /--disable-fmf-fmc-simple bool :default true
+ disable simple models in full model check for finite model finding
option fmfBoundInt --fmf-bound-int bool :default false
finite model finding on bounded integer quantification
option axiomInstMode --axiom-inst=MODE CVC4::theory::quantifiers::AxiomInstMode :default CVC4::theory::quantifiers::AXIOM_INST_MODE_DEFAULT :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToAxiomInstMode :handler-include "theory/quantifiers/options_handlers.h"
policy for instantiating axioms
+option quantConflictFind --quant-cf bool :default false
+ enable conflict find mechanism for quantifiers
+option qcfWhenMode --quant-cf-when=MODE CVC4::theory::quantifiers::QcfWhenMode :default CVC4::theory::quantifiers::QCF_WHEN_MODE_DEFAULT :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToQcfWhenMode :handler-include "theory/quantifiers/options_handlers.h"
+ when to invoke conflict find mechanism for quantifiers
+
endmodule
diff --git a/src/theory/quantifiers/options_handlers.h b/src/theory/quantifiers/options_handlers.h
index 410578af0..e0b1e30e8 100644
--- a/src/theory/quantifiers/options_handlers.h
+++ b/src/theory/quantifiers/options_handlers.h
@@ -73,6 +73,44 @@ priority \n\
\n\
";
+static const std::string mbqiModeHelp = "\
+Model-based quantifier instantiation modes currently supported by the --mbqi option:\n\
+\n\
+default \n\
++ Default, use model-based quantifier instantiation algorithm from CADE 24 finite\n\
+ model finding paper.\n\
+\n\
+none \n\
++ Disable model-based quantifier instantiation.\n\
+\n\
+instgen \n\
++ Use instantiation algorithm that mimics Inst-Gen calculus. \n\
+\n\
+fmc \n\
++ Use algorithm from Section 5.4.2 of thesis Finite Model Finding in Satisfiability \n\
+ Modulo Theories.\n\
+\n\
+fmc-interval \n\
++ Same as fmc, but with intervals for models of integer functions.\n\
+\n\
+interval \n\
++ Use algorithm that abstracts domain elements as intervals. \n\
+\n\
+";
+static const std::string qcfWhenModeHelp = "\
+Quantifier conflict find modes currently supported by the --quant-cf-when option:\n\
+\n\
+default \n\
++ Default, apply conflict finding at full effort.\n\
+\n\
+std \n\
++ Apply conflict finding at standard effort.\n\
+\n\
+std-h \n\
++ Apply conflict finding at standard effort when heuristic says to. \n\
+\n\
+";
+
inline InstWhenMode stringToInstWhenMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
if(optarg == "pre-full") {
return INST_WHEN_PRE_FULL;
@@ -135,6 +173,48 @@ inline AxiomInstMode stringToAxiomInstMode(std::string option, std::string optar
}
}
+inline MbqiMode stringToMbqiMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+ if(optarg == "default") {
+ return MBQI_DEFAULT;
+ } else if(optarg == "none") {
+ return MBQI_NONE;
+ } else if(optarg == "instgen") {
+ return MBQI_INST_GEN;
+ } else if(optarg == "fmc") {
+ return MBQI_FMC;
+ } else if(optarg == "fmc-interval") {
+ return MBQI_FMC_INTERVAL;
+ } else if(optarg == "interval") {
+ return MBQI_INTERVAL;
+ } else if(optarg == "help") {
+ puts(mbqiModeHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(std::string("unknown option for --mbqi: `") +
+ optarg + "'. Try --mbqi help.");
+ }
+}
+
+inline void checkMbqiMode(std::string option, MbqiMode mode, SmtEngine* smt) throw(OptionException) {
+
+}
+
+inline QcfWhenMode stringToQcfWhenMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+ if(optarg == "default") {
+ return QCF_WHEN_MODE_DEFAULT;
+ } else if(optarg == "std") {
+ return QCF_WHEN_MODE_STD;
+ } else if(optarg == "std-h") {
+ return QCF_WHEN_MODE_STD_H;
+ } else if(optarg == "help") {
+ puts(qcfWhenModeHelp.c_str());
+ exit(1);
+ } else {
+ throw OptionException(std::string("unknown option for --quant-cf-when: `") +
+ optarg + "'. Try --quant-cf-when help.");
+ }
+}
+
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/quantifiers/qinterval_builder.cpp b/src/theory/quantifiers/qinterval_builder.cpp
new file mode 100755
index 000000000..ce85cecc0
--- /dev/null
+++ b/src/theory/quantifiers/qinterval_builder.cpp
@@ -0,0 +1,1111 @@
+/********************* */
+/*! \file qinterval_builder.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Implementation of qinterval builder
+ **/
+
+
+#include "theory/quantifiers/qinterval_builder.h"
+
+using namespace std;
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::context;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+
+//lower bound is exclusive
+//upper bound is inclusive
+
+struct QIntSort
+{
+ FirstOrderModelQInt * m;
+ bool operator() (Node i, Node j) {
+ return m->isLessThan( i, j );
+ }
+};
+
+void QIntDef::init_vec( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u ) {
+ for( unsigned i=0; i<m->getOrderedNumVars( q ); i++ ){
+ l.push_back( Node::null() );
+ u.push_back( m->getMaximum( m->getOrderedVarType( q, i ) ) );
+ }
+}
+
+void QIntDef::debugPrint( const char * c, FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u )
+{
+ Trace(c) << "( ";
+ for( unsigned i=0; i<l.size(); i++ ){
+ if( i>0 ) Trace(c) << ", ";
+ //Trace(c) << l[i] << "..." << u[i];
+ int lindex = l[i].isNull() ? 0 : m->getRepId( l[i] ) + 1;
+ int uindex = m->getRepId( u[i] );
+ Trace(c) << lindex << "..." << uindex;
+ }
+ Trace(c) << " )";
+}
+
+
+int QIntDef::getEvIndex( FirstOrderModelQInt * m, Node n, bool exc ) {
+ if( n.isNull() ){
+ Assert( exc );
+ return 0;
+ }else{
+ int min = 0;
+ int max = (int)(d_def_order.size()-1);
+ while( min!=max ){
+ int index = (min+max)/2;
+ Assert( index>=0 && index<(int)d_def_order.size() );
+ if( n==d_def_order[index] ){
+ max = index;
+ min = index;
+ }else if( m->isLessThan( n, d_def_order[index] ) ){
+ max = index;
+ }else{
+ min = index+1;
+ }
+ }
+ if( n==d_def_order[min] && exc ){
+ min++;
+ }
+ Assert( min>=0 && min<(int)d_def_order.size() );
+ if( ( min!=0 && !m->isLessThan( d_def_order[min-1], n ) && ( !exc || d_def_order[min-1]!=n ) ) ||
+ ( ( exc || d_def_order[min]!=n ) && !m->isLessThan( n, d_def_order[min] ) ) ){
+ Debug("qint-error") << "ERR size : " << d_def_order.size() << ", exc : " << exc << std::endl;
+ for( unsigned i=0; i<d_def_order.size(); i++ ){
+ Debug("qint-error") << "ERR ch #" << i << " : " << d_def_order[i];
+ Debug("qint-error") << " " << m->getRepId( d_def_order[i] ) << std::endl;
+ }
+ Debug("qint-error") << " : " << n << " " << min << " " << m->getRepId( n ) << std::endl;
+ }
+
+ Assert( min==0 || m->isLessThan( d_def_order[min-1], n ) || ( exc && d_def_order[min-1]==n ) );
+ Assert( ( !exc && n==d_def_order[min] ) || m->isLessThan( n, d_def_order[min] ) );
+ return min;
+ }
+}
+
+void QIntDef::addEntry( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u,
+ Node v, unsigned depth ) {
+ if( depth==0 ){
+ Trace("qint-compose-debug") << "Add entry ";
+ debugPrint( "qint-compose-debug", m, q, l, u );
+ Trace("qint-compose-debug") << " -> " << v << "..." << std::endl;
+ }
+ //Assert( false );
+ if( depth==u.size() ){
+ Assert( d_def_order.empty() );
+ Assert( v.isNull() || v.isConst() || ( v.getType().isSort() && m->getRepId( v )!=-1 ) );
+ d_def_order.push_back( v );
+ }else{
+ /*
+ if( !d_def_order.empty() &&
+ ( l[depth].isNull() || m->isLessThan( l[depth], d_def_order[d_def_order.size()-1] ) ) ){
+ int startEvIndex = getEvIndex( m, l[depth], true );
+ int endEvIndex;
+ if( m->isLessThan( u[depth], d_def_order[d_def_order.size()-1] ) ){
+ endEvIndex = getEvIndex( m, u[depth] );
+ }else{
+ endEvIndex = d_def_order.size()-1;
+ }
+ Trace("qint-compose-debug2") << this << " adding for bounds " << l[depth] << "..." << u[depth] << std::endl;
+ for( int i=startEvIndex; i<=endEvIndex; i++ ){
+ Trace("qint-compose-debug2") << this << " add entry " << d_def_order[i] << std::endl;
+ d_def[d_def_order[i]].addEntry( m, q, l, u, v, depth+1 );
+ }
+ }
+ if( !d_def_order.empty() &&
+ d_def.find(u[depth])==d_def.end() &&
+ !m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) ){
+ Trace("qint-compose-debug2") << "Bad : depth : " << depth << std::endl;
+ }
+ Assert( d_def_order.empty() ||
+ d_def.find(u[depth])!=d_def.end() ||
+ m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) );
+
+ if( d_def_order.empty() || m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) ){
+ Trace("qint-compose-debug2") << this << " add entry new : " << u[depth] << std::endl;
+ d_def_order.push_back( u[depth] );
+ d_def[u[depth]].addEntry( m, q, l, u, v, depth+1 );
+ }
+ */
+ //%%%%%%
+ bool success = true;
+ int nnum = m->getVarOrder( q )->getNextNum( depth );
+ Node pl;
+ Node pu;
+ if( nnum!=-1 ){
+ Trace("qint-compose-debug2") << "...adding entry #" << depth << " is #" << nnum << std::endl;
+ //Assert( l[nnum].isNull() || l[nnum]==l[depth] || m->isLessThan( l[nnum], l[depth] ) );
+ //Assert( u[nnum]==u[depth] || m->isLessThan( u[depth], u[nnum] ) );
+ pl = l[nnum];
+ pu = u[nnum];
+ if( !m->doMeet( l[nnum], u[nnum], l[depth], u[depth], l[nnum], u[nnum] ) ){
+ success = false;
+ }
+ }
+ //%%%%%%
+ if( success ){
+ Node r = u[depth];
+ if( d_def.find( r )!=d_def.end() ){
+ d_def[r].addEntry( m, q, l, u, v, depth+1 );
+ }else{
+ if( !d_def_order.empty() &&
+ !m->isLessThan( d_def_order[d_def_order.size()-1], u[depth] ) ){
+ Trace("qint-compose-debug2") << "Bad : depth : " << depth << " ";
+ Trace("qint-compose-debug2") << d_def_order[d_def_order.size()-1] << " " << u[depth] << std::endl;
+ }
+ Assert( d_def_order.empty() || m->isLessThan( d_def_order[d_def_order.size()-1], r ) );
+ d_def_order.push_back( r );
+ d_def[r].addEntry( m, q, l, u, v, depth+1 );
+ }
+ }
+ if( nnum!=-1 ){
+ l[nnum] = pl;
+ u[nnum] = pu;
+ }
+ }
+}
+
+Node QIntDef::simplify_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& il, std::vector< Node >& iu,
+ unsigned depth ) {
+ if( d_def.empty() ){
+ if( d_def_order.size()!=0 ){
+ Debug("qint-error") << "Simplify, size = " << d_def_order.size() << std::endl;
+ }
+ Assert( d_def_order.size()==1 );
+ return d_def_order[0];
+ }else{
+ Assert( !d_def_order.empty() );
+ std::vector< Node > newDefs;
+ Node curr;
+ for( unsigned i=0; i<d_def_order.size(); i++ ){
+ Node n = d_def[d_def_order[i]].simplify_r( m, q, il, iu, depth+1 );
+ if( i>0 ){
+ if( n==curr && !n.isNull() ){
+ d_def.erase( d_def_order[i-1] );
+ }else{
+ newDefs.push_back( d_def_order[i-1] );
+ }
+ }
+ curr = n;
+ }
+ newDefs.push_back( d_def_order[d_def_order.size()-1] );
+ d_def_order.clear();
+ d_def_order.insert( d_def_order.end(), newDefs.begin(), newDefs.end() );
+ return d_def_order.size()==1 ? curr : Node::null();
+ }
+}
+
+Node QIntDef::simplify( FirstOrderModelQInt * m, Node q ) {
+ std::vector< Node > l;
+ std::vector< Node > u;
+ if( !q.isNull() ){
+ //init_vec( m, q, l, u );
+ }
+ return simplify_r( m, q, l, u, 0 );
+}
+
+bool QIntDef::isTotal_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u,
+ unsigned depth ) {
+ if( d_def_order.empty() ){
+ return false;
+ }else if( d_def.empty() ){
+ return true;
+ }else{
+ //get the current maximum
+ Node mx;
+ if( !q.isNull() ){
+ int pnum = m->getVarOrder( q )->getPrevNum( depth );
+ if( pnum!=-1 ){
+ mx = u[pnum];
+ }
+ }
+ if( mx.isNull() ){
+ mx = m->getMaximum( d_def_order[d_def_order.size()-1].getType() );
+ }
+ //if not current maximum
+ if( d_def_order[d_def_order.size()-1]!=mx ){
+ return false;
+ }else{
+ Node pu = u[depth];
+ for( unsigned i=0; i<d_def_order.size(); i++ ){
+ u[depth] = d_def_order[i];
+ if( !d_def[d_def_order[i]].isTotal_r( m, q, l, u, depth+1 ) ){
+ return false;
+ }
+ }
+ u[depth] = pu;
+ return true;
+ }
+ }
+}
+
+bool QIntDef::isTotal( FirstOrderModelQInt * m, Node q ) {
+ std::vector< Node > l;
+ std::vector< Node > u;
+ if( !q.isNull() ){
+ init_vec( m, q, l, u );
+ }
+ return isTotal_r( m, q, l, u, 0 );
+}
+
+void QIntDef::construct_compose_r( FirstOrderModelQInt * m, Node q,
+ std::vector< Node >& l, std::vector< Node >& u,
+ Node n, QIntDef * f,
+ std::vector< Node >& args,
+ std::map< unsigned, QIntDef >& children,
+ std::map< unsigned, Node >& bchildren,
+ QIntVarNumIndex& vindex, unsigned depth ) {
+ //check for short circuit
+ if( !f ){
+ if( !args.empty() ){
+ if( ( n.getKind()==OR && args[args.size()-1]==m->d_true ) ||
+ ( n.getKind()==AND && args[args.size()-1]==m->d_false ) ){
+ addEntry( m, q, l, u, args[args.size()-1] );
+ return;
+ }
+ }
+ }
+
+ for( unsigned i=0; i<depth; i++ ) { Trace("qint-compose") << " "; }
+ Trace("qint-compose") << (f ? "U" : "I" ) << "C( ";
+ for( unsigned i=0; i<l.size(); i++ ){
+ if( i>0 ) Trace("qint-compose") << ", ";
+ //Trace("qint-compose") << l[i] << "..." << u[i];
+ int lindex = l[i].isNull() ? 0 : m->getRepId( l[i] ) + 1;
+ int uindex = m->getRepId( u[i] );
+ Trace( "qint-compose" ) << lindex << "..." << uindex;
+ }
+ Trace("qint-compose") << " )...";
+
+ //finished?
+ if( ( f && f->d_def.empty() ) || args.size()==n.getNumChildren() ){
+ if( f ){
+ Assert( f->d_def_order.size()==1 );
+ Trace("qint-compose") << "UVALUE(" << f->d_def_order[0] << ")" << std::endl;
+ addEntry( m, q, l, u, f->d_def_order[0] );
+ }else{
+ Node nn;
+ bool nnSet = false;
+ for( unsigned i=0; i<args.size(); i++ ){
+ if( args[i].isNull() ){
+ nnSet = true;
+ break;
+ }
+ }
+ if( !nnSet ){
+ if( n.getKind()==EQUAL ){
+ nn = NodeManager::currentNM()->mkConst( args[0]==args[1] );
+ }else{
+ //apply the operator to args
+ nn = NodeManager::currentNM()->mkNode( n.getKind(), args );
+ nn = Rewriter::rewrite( nn );
+ }
+ }
+ Trace("qint-compose") << "IVALUE(" << nn << ")" << std::endl;
+ addEntry( m, q, l, u, nn );
+ Trace("qint-compose-debug2") << "...added entry." << std::endl;
+ }
+ }else{
+ //if a non-simple child
+ if( children.find( depth )!=children.end() ){
+ //***************************
+ Trace("qint-compose") << "compound child, recurse" << std::endl;
+ std::vector< int > currIndex;
+ std::vector< int > endIndex;
+ std::vector< Node > prevL;
+ std::vector< Node > prevU;
+ std::vector< QIntDef * > visited;
+ do{
+ Assert( currIndex.size()==visited.size() );
+
+ //populate the vectors
+ while( visited.size()<m->getOrderedNumVars( q ) ){
+ unsigned i = visited.size();
+ QIntDef * qq = visited.empty() ? &children[depth] : visited[i-1]->getChild( currIndex[i-1] );
+ visited.push_back( qq );
+ Node qq_mx = qq->getMaximum();
+ Trace("qint-compose-debug2") << "...Get ev indices " << i << " " << l[i] << " " << u[i] << std::endl;
+ currIndex.push_back( qq->getEvIndex( m, l[i], true ) );
+ Trace("qint-compose-debug2") << "...Done get curr index " << currIndex[currIndex.size()-1] << std::endl;
+ if( m->isLessThan( qq_mx, u[i] ) ){
+ endIndex.push_back( qq->getNumChildren()-1 );
+ }else{
+ endIndex.push_back( qq->getEvIndex( m, u[i] ) );
+ }
+ Trace("qint-compose-debug2") << "...Done get end index " << endIndex[endIndex.size()-1] << std::endl;
+ prevL.push_back( l[i] );
+ prevU.push_back( u[i] );
+ if( !m->doMeet( prevL[i], prevU[i],
+ qq->getLower( currIndex[i] ), qq->getUpper( currIndex[i] ), l[i], u[i] ) ){
+ Assert( false );
+ }
+ }
+ for( unsigned i=0; i<depth; i++ ) { Trace("qint-compose") << " "; }
+ for( unsigned i=0; i<currIndex.size(); i++ ){
+ Trace("qint-compose") << "[" << currIndex[i] << "/" << endIndex[i] << "]";
+ }
+ Trace("qint-compose") << std::endl;
+ //consider the current
+ int activeIndex = visited.size()-1;
+ QIntDef * qa = visited.empty() ? &children[depth] : visited[activeIndex]->getChild( currIndex[activeIndex] );
+ if( f ){
+ int fIndex = f->getEvIndex( m, qa->getValue() );
+ construct_compose_r( m, q, l, u, n, f->getChild( fIndex ), args, children, bchildren, vindex, depth+1 );
+ }else{
+ args.push_back( qa->getValue() );
+ construct_compose_r( m, q, l, u, n, f, args, children, bchildren, vindex, depth+1 );
+ args.pop_back();
+ }
+
+ //increment the index (if possible)
+ while( activeIndex>=0 && currIndex[activeIndex]==endIndex[activeIndex] ){
+ currIndex.pop_back();
+ endIndex.pop_back();
+ l[activeIndex] = prevL[activeIndex];
+ u[activeIndex] = prevU[activeIndex];
+ prevL.pop_back();
+ prevU.pop_back();
+ visited.pop_back();
+ activeIndex--;
+ }
+ if( activeIndex>=0 ){
+ for( unsigned i=0; i<depth; i++ ) { Trace("qint-compose") << " "; }
+ Trace("qint-compose-debug") << "Increment at " << activeIndex << std::endl;
+ currIndex[activeIndex]++;
+ if( !m->doMeet( prevL[activeIndex], prevU[activeIndex],
+ visited[activeIndex]->getLower( currIndex[activeIndex] ),
+ visited[activeIndex]->getUpper( currIndex[activeIndex] ),
+ l[activeIndex], u[activeIndex] ) ){
+ Assert( false );
+ }
+ }
+ }while( !visited.empty() );
+ //***************************
+ }else{
+ Assert( bchildren.find( depth )!=bchildren.end() );
+ Node v = bchildren[depth];
+ if( f ){
+ if( v.getKind()==BOUND_VARIABLE ){
+ int vn = vindex.d_var_num[depth];
+ Trace("qint-compose") << "variable #" << vn << ", recurse" << std::endl;
+ //int vn = m->getOrderedVarOccurId( q, n, depth );
+ Trace("qint-compose-debug") << "-process " << v << ", which is var #" << vn << std::endl;
+ Node lprev = l[vn];
+ Node uprev = u[vn];
+ //restrict to last variable in order
+ int pnum = m->getVarOrder( q )->getPrevNum( vn );
+ if( pnum!=-1 ){
+ Trace("qint-compose-debug") << "-restrict to var #" << pnum << " " << l[pnum] << " " << u[pnum] << std::endl;
+ l[vn] = l[pnum];
+ u[vn] = u[pnum];
+ }
+ int startIndex = f->getEvIndex( m, l[vn], true );
+ int endIndex = f->getEvIndex( m, u[vn] );
+ Trace("qint-compose-debug") << "--will process " << startIndex << " " << endIndex << std::endl;
+ for( int i=startIndex; i<=endIndex; i++ ){
+ if( m->doMeet( lprev, uprev, f->getLower( i ), f->getUpper( i ), l[vn], u[vn] ) ){
+ construct_compose_r( m, q, l, u, n, f->getChild( i ), args, children, bchildren, vindex, depth+1 );
+ }else{
+ Assert( false );
+ }
+ }
+ l[vn] = lprev;
+ u[vn] = uprev;
+ }else{
+ Trace("qint-compose") << "value, recurse" << std::endl;
+ //simple
+ int ei = f->getEvIndex( m, v );
+ construct_compose_r( m, q, l, u, n, f->getChild( ei ), args, children, bchildren, vindex, depth+1 );
+ }
+ }else{
+ Trace("qint-compose") << "value, recurse" << std::endl;
+ args.push_back( v );
+ construct_compose_r( m, q, l, u, n, f, args, children, bchildren, vindex, depth+1 );
+ args.pop_back();
+ }
+ }
+ }
+}
+
+
+void QIntDef::construct_enum_r( FirstOrderModelQInt * m, Node q, unsigned vn, unsigned depth, Node v ) {
+ if( depth==m->getOrderedNumVars( q ) ){
+ Assert( !v.isNull() );
+ d_def_order.push_back( v );
+ }else{
+ TypeNode tn = m->getOrderedVarType( q, depth );
+ //int vnum = m->getVarOrder( q )->getVar( depth )==
+ if( depth==vn ){
+ for( unsigned i=0; i<m->d_rep_set.d_type_reps[tn].size(); i++ ){
+ Node vv = m->d_rep_set.d_type_reps[tn][i];
+ d_def_order.push_back( vv );
+ d_def[vv].construct_enum_r( m, q, vn, depth+1, vv );
+ }
+ }else if( m->getVarOrder( q )->getVar( depth )==m->getVarOrder( q )->getVar( vn ) && depth>vn ){
+ d_def_order.push_back( v );
+ d_def[v].construct_enum_r( m, q, vn, depth+1, v );
+ }else{
+ Node mx = m->getMaximum( tn );
+ d_def_order.push_back( mx );
+ d_def[mx].construct_enum_r( m, q, vn, depth+1, v );
+ }
+ }
+}
+
+bool QIntDef::construct_enum( FirstOrderModelQInt * m, Node q, unsigned vn ) {
+ TypeNode tn = m->getOrderedVarType( q, vn );
+ if( tn.isSort() ){
+ construct_enum_r( m, q, vn, 0, Node::null() );
+ return true;
+ }else{
+ return false;
+ }
+}
+
+bool QIntDef::construct_compose( FirstOrderModelQInt * m, Node q, Node n, QIntDef * f,
+ std::map< unsigned, QIntDef >& children,
+ std::map< unsigned, Node >& bchildren, int varChCount,
+ QIntVarNumIndex& vindex ) {
+ Trace("qint-compose") << "Do " << (f ? "uninterpreted" : "interpreted");
+ Trace("qint-compose") << " compose, var count = " << varChCount << "..." << std::endl;
+ std::vector< Node > l;
+ std::vector< Node > u;
+ init_vec( m, q, l, u );
+ if( varChCount==0 || f ){
+ //standard (no variable child) interpreted compose, or uninterpreted compose
+ std::vector< Node > args;
+ construct_compose_r( m, q, l, u, n, f, args, children, bchildren, vindex, 0 );
+ }else{
+ //special cases
+ bool success = false;
+ int varIndex = ( bchildren.find( 0 )!=bchildren.end() && bchildren[0].getKind()==BOUND_VARIABLE ) ? 0 : 1;
+ if( varChCount>1 ){
+ if( n.getKind()==EQUAL ){
+ //make it an enumeration
+ unsigned vn = vindex.d_var_num[0];
+ if( children[0].construct_enum( m, q, vn ) ){
+ bchildren.erase( 0 );
+ varIndex = 1;
+ success = true;
+ }
+ }
+ }else{
+ success = n.getKind()==EQUAL;
+ }
+ if( success ){
+ int oIndex = varIndex==0 ? 1 : 0;
+ Node v = bchildren[varIndex];
+ unsigned vn = vindex.d_var_num[varIndex];
+ if( children.find( oIndex )==children.end() ){
+ Assert( bchildren.find( oIndex )!=bchildren.end() );
+ Node at = bchildren[oIndex];
+ Trace("qint-icompose") << "Basic child, " << at << " with var " << v << std::endl;
+ Node prev = m->getPrev( bchildren[oIndex].getType(), bchildren[oIndex] );
+ Node above = u[vn];
+ if( !prev.isNull() ){
+ u[vn] = prev;
+ addEntry( m, q, l, u, NodeManager::currentNM()->mkConst( false ) );
+ }
+ l[vn] = prev;
+ u[vn] = at;
+ addEntry( m, q, l, u, NodeManager::currentNM()->mkConst( true ) );
+ if( at!=above ){
+ l[vn] = at;
+ u[vn] = above;
+ addEntry( m, q, l, u, NodeManager::currentNM()->mkConst( false ) );
+ }
+ }else{
+ QIntDef * qid = &children[oIndex];
+ qid->debugPrint("qint-icompose", m, q );
+ Trace("qint-icompose") << " against variable..." << v << ", which is var #" << vn << std::endl;
+
+ TypeNode tn = v.getType();
+ QIntDefIter qdi( m, q, qid );
+ while( !qdi.isFinished() ){
+ std::vector< Node > us;
+ qdi.getUppers( us );
+ std::vector< Node > ls;
+ qdi.getLowers( ls );
+ qdi.debugPrint( "qint-icompose" );
+
+ Node n_below = ls[vn];
+ Node n_prev = m->getPrev( tn, qdi.getValue() );
+ Node n_at = qdi.getValue();
+ Node n_above = us[vn];
+ Trace("qint-icompose") << n_below << " < " << n_prev << " < " << n_at << " < " << n_above << std::endl;
+ if( n.getKind()==EQUAL ){
+ bool atLtAbove = m->isLessThan( n_at, n_above );
+ Node currL = n_below;
+ if( n_at==n_above || atLtAbove ){
+ //add for value (at-1)
+ if( !n_prev.isNull() && ( n_below.isNull() || m->isLessThan( n_below, n_prev ) ) ){
+ ls[vn] = currL;
+ us[vn] = n_prev;
+ currL = n_prev;
+ Trace("qint-icompose") << "-add entry(-) at " << ls[vn] << "..." << us[vn] << std::endl;
+ addEntry( m, q, ls, us, NodeManager::currentNM()->mkConst( false ) );
+ }
+ //add for value (at)
+ if( ( n_below.isNull() || m->isLessThan( n_below, n_at ) ) && atLtAbove ){
+ ls[vn] = currL;
+ us[vn] = n_at;
+ currL = n_at;
+ Trace("qint-icompose") << "-add entry(=) at " << ls[vn] << "..." << us[vn] << std::endl;
+ addEntry( m, q, ls, us, NodeManager::currentNM()->mkConst( true ) );
+ }
+ }
+ ls[vn] = currL;
+ us[vn] = n_above;
+ Trace("qint-icompose") << "-add entry(+) at " << ls[vn] << "..." << us[vn] << std::endl;
+ addEntry( m, q, ls, us, NodeManager::currentNM()->mkConst( n_at==n_above ) );
+ }else{
+ return false;
+ }
+ qdi.increment();
+
+ Trace("qint-icompose-debug") << "Now : " << std::endl;
+ debugPrint("qint-icompose-debug", m, q );
+ Trace("qint-icompose-debug") << std::endl;
+ }
+ }
+
+ Trace("qint-icompose") << "Result : " << std::endl;
+ debugPrint("qint-icompose", m, q );
+ Trace("qint-icompose") << std::endl;
+
+ }else{
+ return false;
+ }
+ }
+ Trace("qint-compose") << "Done i-compose" << std::endl;
+ return true;
+}
+
+
+void QIntDef::construct( FirstOrderModelQInt * m, std::vector< Node >& fapps, unsigned depth ) {
+ d_def.clear();
+ d_def_order.clear();
+ Assert( !fapps.empty() );
+ if( depth==fapps[0].getNumChildren() ){
+ //get representative in model for this term
+ Assert( fapps.size()>=1 );
+ Node r = m->getUsedRepresentative( fapps[0] );
+ d_def_order.push_back( r );
+ }else{
+ std::map< Node, std::vector< Node > > fapp_child;
+ //partition based on evaluations of fapps[1][depth]....fapps[n][depth]
+ for( unsigned i=0; i<fapps.size(); i++ ){
+ Node r = m->getUsedRepresentative( fapps[i][depth] );
+ fapp_child[r].push_back( fapps[i] );
+ }
+ //sort by QIntSort
+ for( std::map< Node, std::vector< Node > >::iterator it = fapp_child.begin(); it != fapp_child.end(); ++it ){
+ d_def_order.push_back( it->first );
+ }
+ QIntSort qis;
+ qis.m = m;
+ std::sort( d_def_order.begin(), d_def_order.end(), qis );
+ //construct children
+ for( unsigned i=0; i<d_def_order.size(); i++ ){
+ Node n = d_def_order[i];
+ if( i==d_def_order.size()-1 ){
+ d_def_order[i] = m->getMaximum( d_def_order[i].getType() );
+ }
+ Debug("qint-model-debug2") << "Construct for " << n << ", terms = " << fapp_child[n].size() << std::endl;
+ d_def[d_def_order[i]].construct( m, fapp_child[n], depth+1 );
+ }
+ }
+}
+
+Node QIntDef::getFunctionValue( FirstOrderModelQInt * m, std::vector< Node >& vars, unsigned depth ) {
+ if( d_def.empty() ){
+ Assert( d_def_order.size()==1 );
+ //must convert to actual domain constant
+ if( d_def_order[0].getType().isSort() ){
+ return m->d_rep_set.d_type_reps[ d_def_order[0].getType() ][ m->getRepId( d_def_order[0] ) ];
+ }else{
+ return m->getUsedRepresentative( d_def_order[0] );
+ }
+ }else{
+ TypeNode tn = vars[depth].getType();
+ Node curr;
+ int rep_id = m->d_rep_set.getNumRepresentatives( tn );
+ for( int i=(int)(d_def_order.size()-1); i>=0; i-- ){
+ int curr_rep_id = i==0 ? 0 : m->getRepId( d_def_order[i-1] )+1;
+ Node ccurr = d_def[d_def_order[i]].getFunctionValue( m, vars, depth+1 );
+ if( curr.isNull() ){
+ curr = ccurr;
+ }else{
+ std::vector< Node > c;
+ Assert( curr_rep_id<rep_id );
+ for( int j=curr_rep_id; j<rep_id; j++ ){
+ c.push_back( vars[depth].eqNode( m->d_rep_set.d_type_reps[tn][j] ) );
+ }
+ Node cond = c.size()==1 ? c[0] : NodeManager::currentNM()->mkNode( OR, c );
+ curr = NodeManager::currentNM()->mkNode( ITE, cond, ccurr, curr );
+ }
+ rep_id = curr_rep_id;
+ }
+ return curr;
+ }
+}
+
+Node QIntDef::evaluate_r( FirstOrderModelQInt * m, std::vector< Node >& reps, unsigned depth ) {
+ if( depth==reps.size() ){
+ Assert( d_def_order.size()==1 );
+ return d_def_order[0];
+ }else{
+ if( d_def.find( reps[depth] )!=d_def.end() ){
+ return d_def[reps[depth]].evaluate_r( m, reps, depth+1 );
+ }else{
+ int ei = getEvIndex( m, reps[depth] );
+ return d_def[d_def_order[ei]].evaluate_r( m, reps, depth+1 );
+ }
+ }
+}
+Node QIntDef::evaluate_n_r( FirstOrderModelQInt * m, Node n, unsigned depth ) {
+ if( depth==n.getNumChildren() ){
+ Assert( d_def_order.size()==1 );
+ return d_def_order[0];
+ }else{
+ Node r = m->getUsedRepresentative( n[depth] );
+ if( d_def.find( r )!=d_def.end() ){
+ return d_def[r].evaluate_n_r( m, n, depth+1 );
+ }else{
+ int ei = getEvIndex( m, r );
+ return d_def[d_def_order[ei]].evaluate_n_r( m, n, depth+1 );
+ }
+ }
+}
+
+
+
+QIntDef * QIntDef::getChild( unsigned i ) {
+ Assert( i<d_def_order.size() );
+ Assert( d_def.find( d_def_order[i] )!=d_def.end() );
+ return &d_def[ d_def_order[i] ];
+}
+
+void QIntDef::debugPrint( const char * c, FirstOrderModelQInt * m, Node q, int t ) {
+ /*
+ for( unsigned i=0; i<d_def_order.size(); i++ ){
+ for( int j=0; j<t; j++ ) { Trace(c) << " "; }
+ //Trace(c) << this << " ";
+ Trace(c) << d_def_order[i] << " : " << std::endl;
+ if( d_def.find( d_def_order[i] )!=d_def.end() ){
+ d_def[d_def_order[i]].debugPrint( c, m, t+1 );
+ }
+ }
+ */
+ //if( t==0 ){
+ QIntDefIter qdi( m, q, this );
+ while( !qdi.isFinished() ){
+ qdi.debugPrint( c, t );
+ qdi.increment();
+ }
+ //}
+}
+
+
+QIntDefIter::QIntDefIter( FirstOrderModelQInt * m, Node q, QIntDef * qid ) : d_fm( m ), d_q( q ){
+ resetIndex( qid );
+}
+
+void QIntDefIter::debugPrint( const char * c, int t ) {
+ //Trace( c ) << getSize() << " " << d_index_visited.size() << " ";
+ for( int j=0; j<t; j++ ) { Trace(c) << " "; }
+ std::vector< Node > l;
+ std::vector< Node > u;
+ getLowers( l );
+ getUppers( u );
+ QIntDef::debugPrint( c, d_fm, d_q, l, u );
+ Trace( c ) << " -> " << getValue() << std::endl;
+}
+
+void QIntDefIter::resetIndex( QIntDef * qid ){
+ //std::cout << "check : " << qid << " " << qid->d_def_order.size() << " " << qid->d_def.size() << std::endl;
+ if( !qid->d_def.empty() ){
+ //std::cout << "add to visited " << qid << std::endl;
+ d_index.push_back( 0 );
+ d_index_visited.push_back( qid );
+ resetIndex( qid->getChild( 0 ) );
+ }
+}
+
+bool QIntDefIter::increment( int index ) {
+ if( !isFinished() ){
+ index = index==-1 ? (int)(d_index.size()-1) : index;
+ while( (int)(d_index.size()-1)>index ){
+ //std::cout << "remove from visit 1 " << std::endl;
+ d_index.pop_back();
+ d_index_visited.pop_back();
+ }
+ while( index>=0 && d_index[index]>=(int)(d_index_visited[index]->d_def_order.size()-1) ){
+ //std::cout << "remove from visit " << d_index_visited[ d_index_visited.size()-1 ] << std::endl;
+ d_index.pop_back();
+ d_index_visited.pop_back();
+ index--;
+ }
+ if( index>=0 ){
+ //std::cout << "increment at index = " << index << std::endl;
+ d_index[index]++;
+ resetIndex( d_index_visited[index]->getChild( d_index[index] ) );
+ return true;
+ }else{
+ d_index.clear();
+ return false;
+ }
+ }else{
+ return false;
+ }
+}
+
+Node QIntDefIter::getLower( int index ) {
+ if( d_index[index]==0 && !d_q.isNull() ){
+ int pnum = d_fm->getVarOrder( d_q )->getPrevNum( index );
+ if( pnum!=-1 ){
+ return getLower( pnum );
+ }
+ }
+ return d_index_visited[index]->getLower( d_index[index] );
+}
+
+Node QIntDefIter::getUpper( int index ) {
+ return d_index_visited[index]->getUpper( d_index[index] );
+}
+
+void QIntDefIter::getLowers( std::vector< Node >& reps ) {
+ for( unsigned i=0; i<getSize(); i++ ){
+ bool added = false;
+ if( d_index[i]==0 && !d_q.isNull() ){
+ int pnum = d_fm->getVarOrder( d_q )->getPrevNum( i );
+ if( pnum!=-1 ){
+ added = true;
+ reps.push_back( reps[pnum] );
+ }
+ }
+ if( !added ){
+ reps.push_back( getLower( i ) );
+ }
+ }
+}
+
+void QIntDefIter::getUppers( std::vector< Node >& reps ) {
+ for( unsigned i=0; i<getSize(); i++ ){
+ reps.push_back( getUpper( i ) );
+ }
+}
+
+Node QIntDefIter::getValue() {
+ return d_index_visited[ d_index_visited.size()-1 ]->getChild( d_index[d_index.size()-1] )->getValue();
+}
+
+
+//------------------------variable ordering----------------------------
+
+QuantVarOrder::QuantVarOrder( Node q ) : d_q( q ) {
+ d_var_count = 0;
+ initialize( q[1], 0, d_var_occur );
+}
+
+int QuantVarOrder::initialize( Node n, int minVarIndex, QIntVarNumIndex& vindex ) {
+ if( n.getKind()!=FORALL ){
+ //std::vector< Node > vars;
+ //std::vector< int > args;
+ int procVarOn = n.getKind()==APPLY_UF ? 0 : 1;
+ for( int r=0; r<=procVarOn; r++ ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( n[i].getKind()==BOUND_VARIABLE && r==procVarOn ){
+ int occ_index = -1;
+ for( unsigned j=0; j<d_var_to_num[n[i]].size(); j++ ){
+ if( d_var_to_num[n[i]][j]>=minVarIndex ){
+ occ_index = d_var_to_num[n[i]][j];
+ }
+ }
+ if( occ_index==-1 ){
+ //need to assign new
+ d_num_to_var[d_var_count] = n[i];
+ if( !d_var_to_num[n[i]].empty() ){
+ int v = d_var_to_num[n[i]][ d_var_to_num[n[i]].size()-1 ];
+ d_num_to_prev_num[ d_var_count ] = v;
+ d_num_to_next_num[ v ] = d_var_count;
+ }
+ d_var_num_index[ d_var_count ] = d_var_to_num[n[i]].size();
+ d_var_to_num[n[i]].push_back( d_var_count );
+ occ_index = d_var_count;
+ d_var_count++;
+ }
+ vindex.d_var_num[i] = occ_index;
+ minVarIndex = occ_index;
+ }else if( r==0 ){
+ minVarIndex = initialize( n[i], minVarIndex, vindex.d_var_index[i] );
+ }
+ }
+ }
+ }
+ return minVarIndex;
+}
+
+bool QuantVarOrder::getInstantiation( FirstOrderModelQInt * m, std::vector< Node >& l, std::vector< Node >& u,
+ std::vector< Node >& inst ) {
+ Debug("qint-var-order-debug2") << "Get for " << d_q << " " << l.size() << " " << u.size() << std::endl;
+ for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){
+ Debug("qint-var-order-debug2") << "Get for " << d_q[0][i] << " " << d_var_to_num[d_q[0][i]].size() << std::endl;
+ Node ll = Node::null();
+ Node uu = m->getMaximum( d_q[0][i].getType() );
+ for( unsigned j=0; j<d_var_to_num[d_q[0][i]].size(); j++ ){
+ Debug("qint-var-order-debug2") << "Go " << j << std::endl;
+ Node cl = ll;
+ Node cu = uu;
+ int index = d_var_to_num[d_q[0][i]][j];
+ Debug("qint-var-order-debug2") << "Do meet for " << index << "..." << std::endl;
+ Debug("qint-var-order-debug2") << l[index] << " " << u[index] << " " << cl << " " << cu << std::endl;
+ if( !m->doMeet( l[index], u[index], cl, cu, ll, uu ) ){
+ Debug("qint-var-order-debug2") << "FAILED" << std::endl;
+ return false;
+ }
+ Debug("qint-var-order-debug2") << "Result : " << ll << " " << uu << std::endl;
+ }
+ Debug("qint-var-order-debug2") << "Got " << uu << std::endl;
+ inst.push_back( uu );
+ }
+ return true;
+}
+
+void QuantVarOrder::debugPrint( const char * c ) {
+ Trace( c ) << "Variable order for " << d_q << " is : " << std::endl;
+ debugPrint( c, d_q[1], d_var_occur );
+ Trace( c ) << std::endl;
+ for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){
+ Trace( c ) << d_q[0][i] << " : ";
+ for( unsigned j=0; j<d_var_to_num[d_q[0][i]].size(); j++ ){
+ Trace( c ) << d_var_to_num[d_q[0][i]][j] << " ";
+ }
+ Trace( c ) << std::endl;
+ }
+}
+
+void QuantVarOrder::debugPrint( const char * c, Node n, QIntVarNumIndex& vindex ) {
+ if( n.getKind()==FORALL ){
+ Trace(c) << "NESTED_QUANT";
+ }else{
+ Trace(c) << n.getKind() << "(";
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( i>0 ) Trace( c ) << ",";
+ Trace( c ) << " ";
+ if( n[i].getKind()==BOUND_VARIABLE ){
+ Trace(c) << "VAR[" << vindex.d_var_num[i] << "]";
+ }else{
+ debugPrint( c, n[i], vindex.d_var_index[i] );
+ }
+ if( i==n.getNumChildren()-1 ) Trace( c ) << " ";
+ }
+ Trace(c) << ")";
+ }
+}
+
+QIntervalBuilder::QIntervalBuilder( context::Context* c, QuantifiersEngine* qe ) :
+QModelBuilder( c, qe ){
+ d_true = NodeManager::currentNM()->mkConst( true );
+}
+
+
+//------------------------model construction----------------------------
+
+void QIntervalBuilder::processBuildModel(TheoryModel* m, bool fullModel) {
+ Trace("fmf-qint-debug") << "process build model " << fullModel << std::endl;
+ FirstOrderModel* f = (FirstOrderModel*)m;
+ FirstOrderModelQInt* fm = f->asFirstOrderModelQInt();
+ if( fullModel ){
+ Trace("qint-model") << "Construct model representation..." << std::endl;
+ //make function values
+ for( std::map<Node, QIntDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
+ if( it->first.getType().getNumChildren()>1 ){
+ Trace("qint-model") << "Construct for " << it->first << "..." << std::endl;
+ m->d_uf_models[ it->first ] = fm->getFunctionValue( it->first, "$x" );
+ }
+ }
+ TheoryEngineModelBuilder::processBuildModel( m, fullModel );
+ //mark that the model has been set
+ fm->markModelSet();
+ //debug the model
+ debugModel( fm );
+ }else{
+ fm->initialize( d_considerAxioms );
+ //process representatives
+ fm->d_rep_id.clear();
+ fm->d_max.clear();
+ fm->d_min.clear();
+ Trace("qint-model") << std::endl << "Making representatives..." << std::endl;
+ for( std::map< TypeNode, std::vector< Node > >::iterator it = fm->d_rep_set.d_type_reps.begin();
+ it != fm->d_rep_set.d_type_reps.end(); ++it ){
+ if( it->first.isSort() ){
+ if( it->second.empty() ){
+ std::cout << "Empty rep for " << it->first << std::endl;
+ exit(0);
+ }
+ Trace("qint-model") << "Representatives for " << it->first << " : " << std::endl;
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ Trace("qint-model") << i << " : " << it->second[i] << std::endl;
+ fm->d_rep_id[it->second[i]] = i;
+ }
+ fm->d_min[it->first] = it->second[0];
+ fm->d_max[it->first] = it->second[it->second.size()-1];
+ }else{
+ //TODO: enumerate?
+ }
+ }
+ Trace("qint-model") << std::endl << "Making function definitions..." << std::endl;
+ //construct the models for functions
+ for( std::map<Node, QIntDef * >::iterator it = fm->d_models.begin(); it != fm->d_models.end(); ++it ) {
+ Node f = it->first;
+ Trace("qint-model-debug") << "Building Model for " << f << std::endl;
+ //reset the model
+ //get all (non-redundant) f-applications
+ std::vector< Node > fapps;
+ Trace("qint-model-debug") << "Initial terms: " << std::endl;
+ for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){
+ Node n = fm->d_uf_terms[f][i];
+ if( !n.getAttribute(NoMatchAttribute()) ){
+ Trace("qint-model-debug") << " " << n << std::endl;
+ fapps.push_back( n );
+ }
+ }
+ if( fapps.empty() ){
+ //choose arbitrary value
+ Node mbt = d_qe->getTermDatabase()->getModelBasisOpTerm(f);
+ Trace("qint-model-debug") << "Initial terms empty, add " << mbt << std::endl;
+ fapps.push_back( mbt );
+ }
+ //construct the interval model
+ it->second->construct( fm, fapps );
+ Trace("qint-model-debug") << "Definition for " << f << " : " << std::endl;
+ it->second->debugPrint("qint-model-debug", fm, Node::null() );
+
+ it->second->simplify( fm, Node::null() );
+ Trace("qint-model") << "(Simplified) definition for " << f << " : " << std::endl;
+ it->second->debugPrint("qint-model", fm, Node::null() );
+
+ if( Debug.isOn("qint-model-debug") ){
+ for( size_t i=0; i<fm->d_uf_terms[f].size(); i++ ){
+ Node e = it->second->evaluate_n( fm, fm->d_uf_terms[f][i] );
+ Debug("qint-model-debug") << fm->d_uf_terms[f][i] << " evaluates to " << e << std::endl;
+ Assert( fm->areEqual( e, fm->d_uf_terms[f][i] ) );
+ }
+ }
+ }
+ }
+}
+
+
+//--------------------model checking---------------------------------------
+
+//do exhaustive instantiation
+bool QIntervalBuilder::doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort ) {
+ Trace("qint-check") << "exhaustive instantiation " << q << " " << effort << std::endl;
+ if (effort==0) {
+
+ FirstOrderModelQInt * fmqint = fm->asFirstOrderModelQInt();
+ QIntDef qid;
+ doCheck( fmqint, q, qid, q[1], fmqint->d_var_order[q]->d_var_occur );
+ //now process entries
+ Trace("qint-inst") << "Interpretation for " << q << " is : " << std::endl;
+ qid.debugPrint( "qint-inst", fmqint, q );
+ Trace("qint-inst") << std::endl;
+ Debug("qint-check-debug2") << "Make iterator..." << std::endl;
+ QIntDefIter qdi( fmqint, q, &qid );
+ while( !qdi.isFinished() ){
+ if( qdi.getValue()!=d_true ){
+ Debug("qint-check-debug2") << "Set up vectors..." << std::endl;
+ std::vector< Node > l;
+ std::vector< Node > u;
+ std::vector< Node > inst;
+ qdi.getLowers( l );
+ qdi.getUppers( u );
+ Debug("qint-check-debug2") << "Get instantiation..." << std::endl;
+ if( fmqint->d_var_order[q]->getInstantiation( fmqint, l, u, inst ) ){
+ Trace("qint-inst") << "** Instantiate with ";
+ //just add the instance
+ InstMatch m;
+ for( unsigned j=0; j<inst.size(); j++) {
+ m.set( d_qe, q, j, inst[j] );
+ Trace("qint-inst") << inst[j] << " ";
+ }
+ Trace("qint-inst") << std::endl;
+ d_triedLemmas++;
+ if( d_qe->addInstantiation( q, m ) ){
+ Trace("qint-inst") << " ...added instantiation." << std::endl;
+ d_addedLemmas++;
+ }else{
+ Trace("qint-inst") << " ...duplicate instantiation" << std::endl;
+ //verify that instantiation is witness for current entry
+ if( Debug.isOn("qint-check-debug2") ){
+ Debug("qint-check-debug2") << "Check if : ";
+ std::vector< Node > exp_inst;
+ for( unsigned i=0; i<fmqint->getOrderedNumVars( q ); i++ ){
+ int index = fmqint->getOrderedVarNumToVarNum( q, i );
+ exp_inst.push_back( inst[ index ] );
+ Debug("qint-check-debug2") << inst[index] << " ";
+ }
+ Debug("qint-check-debug2") << " evaluates to " << qdi.getValue() << std::endl;
+ Assert( qid.evaluate( fmqint, exp_inst )==qdi.getValue() );
+ }
+ }
+ }else{
+ Trace("qint-inst") << "** Spurious instantiation." << std::endl;
+ }
+ }
+ qdi.increment();
+ }
+ }
+ return true;
+}
+
+bool QIntervalBuilder::doCheck( FirstOrderModelQInt * m, Node q, QIntDef & qid, Node n,
+ QIntVarNumIndex& vindex ) {
+ Assert( n.getKind()!=FORALL );
+ std::map< unsigned, QIntDef > children;
+ std::map< unsigned, Node > bchildren;
+ int varChCount = 0;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( n[i].getKind()==FORALL ){
+ bchildren[i] = Node::null();
+ }else if( n[i].getKind() == BOUND_VARIABLE ){
+ varChCount++;
+ bchildren[i] = n[i];
+ }else if( m->hasTerm( n[i] ) ){
+ bchildren[i] = m->getUsedRepresentative( n[i] );
+ }else{
+ if( !doCheck( m, q, children[i], n[i], vindex.d_var_index[i] ) ){
+ bchildren[i] = Node::null();
+ }
+ }
+ }
+ Trace("qint-check-debug") << "Compute Interpretation of " << n << " " << n.getKind() << std::endl;
+ if( n.getKind() == APPLY_UF || n.getKind() == VARIABLE || n.getKind() == SKOLEM ){
+ Node op = n.getKind() == APPLY_UF ? n.getOperator() : n;
+ //uninterpreted compose
+ qid.construct_compose( m, q, n, m->d_models[op], children, bchildren, varChCount, vindex );
+ }else if( !qid.construct_compose( m, q, n, NULL, children, bchildren, varChCount, vindex ) ){
+ Trace("qint-check-debug") << "** Cannot produce definition for " << n << std::endl;
+ return false;
+ }
+ Trace("qint-check-debug2") << "Definition for " << n << " is : " << std::endl;
+ qid.debugPrint("qint-check-debug2", m, q);
+ qid.simplify( m, q );
+ Trace("qint-check-debug") << "(Simplified) Definition for " << n << " is : " << std::endl;
+ qid.debugPrint("qint-check-debug", m, q);
+ Trace("qint-check-debug") << std::endl;
+ Assert( qid.isTotal( m, q ) );
+ return true;
+}
diff --git a/src/theory/quantifiers/qinterval_builder.h b/src/theory/quantifiers/qinterval_builder.h
new file mode 100755
index 000000000..8f48776cc
--- /dev/null
+++ b/src/theory/quantifiers/qinterval_builder.h
@@ -0,0 +1,155 @@
+/********************* */
+/*! \file qinterval_builder.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief qinterval model class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef QINTERVAL_BUILDER
+#define QINTERVAL_BUILDER
+
+#include "theory/quantifiers/model_builder.h"
+#include "theory/quantifiers/first_order_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class FirstOrderModelQInt;
+
+class QIntVarNumIndex
+{
+public:
+ std::map< int, int > d_var_num;
+ std::map< int, QIntVarNumIndex > d_var_index;
+};
+
+class QIntDef
+{
+private:
+ Node evaluate_r( FirstOrderModelQInt * m, std::vector< Node >& reps, unsigned depth );
+ Node evaluate_n_r( FirstOrderModelQInt * m, Node n, unsigned depth );
+ void construct_compose_r( FirstOrderModelQInt * m, Node q,
+ std::vector< Node >& l, std::vector< Node >& u, Node n, QIntDef * f,
+ std::vector< Node >& args,
+ std::map< unsigned, QIntDef >& children,
+ std::map< unsigned, Node >& bchildren,
+ QIntVarNumIndex& vindex,
+ unsigned depth );
+
+ void construct_enum_r( FirstOrderModelQInt * m, Node q, unsigned vn, unsigned depth, Node v );
+ int getEvIndex( FirstOrderModelQInt * m, Node n, bool exc = false );
+ void addEntry( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u,
+ Node v, unsigned depth = 0 );
+ Node simplify_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& il, std::vector< Node >& iu,
+ unsigned depth );
+ bool isTotal_r( FirstOrderModelQInt * m, Node q, std::vector< Node >& il, std::vector< Node >& iu,
+ unsigned depth );
+public:
+ QIntDef(){}
+ std::map< Node, QIntDef > d_def;
+ std::vector< Node > d_def_order;
+
+ void construct( FirstOrderModelQInt * m, std::vector< Node >& fapps, unsigned depth = 0 );
+ bool construct_compose( FirstOrderModelQInt * m, Node q, Node n, QIntDef * f,
+ std::map< unsigned, QIntDef >& children,
+ std::map< unsigned, Node >& bchildren, int varChCount,
+ QIntVarNumIndex& vindex );
+ bool construct_enum( FirstOrderModelQInt * m, Node q, unsigned vn );
+
+ Node evaluate( FirstOrderModelQInt * m, std::vector< Node >& reps ) { return evaluate_r( m, reps, 0 ); }
+ Node evaluate_n( FirstOrderModelQInt * m, Node n ) { return evaluate_n_r( m, n, 0 ); }
+
+ void debugPrint( const char * c, FirstOrderModelQInt * m, Node q, int t = 0 );
+ QIntDef * getChild( unsigned i );
+ Node getValue() { return d_def_order[0]; }
+ Node getLower( unsigned i ) { return i==0 ? Node::null() : d_def_order[i-1]; }
+ Node getUpper( unsigned i ) { return d_def_order[i]; }
+ Node getMaximum() { return d_def_order.empty() ? Node::null() : getUpper( d_def_order.size()-1 ); }
+ int getNumChildren() { return d_def_order.size(); }
+ bool isTotal( FirstOrderModelQInt * m, Node q );
+
+ Node simplify( FirstOrderModelQInt * m, Node q );
+ Node getFunctionValue( FirstOrderModelQInt * m, std::vector< Node >& vars, unsigned depth = 0 );
+
+ static void init_vec( FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u );
+ static void debugPrint( const char * c, FirstOrderModelQInt * m, Node q, std::vector< Node >& l, std::vector< Node >& u );
+};
+
+class QIntDefIter {
+private:
+ FirstOrderModelQInt * d_fm;
+ Node d_q;
+ void resetIndex( QIntDef * qid );
+public:
+ QIntDefIter( FirstOrderModelQInt * m, Node q, QIntDef * qid );
+ void debugPrint( const char * c, int t = 0 );
+ std::vector< QIntDef * > d_index_visited;
+ std::vector< int > d_index;
+ bool isFinished() { return d_index.empty(); }
+ bool increment( int index = -1 );
+ unsigned getSize() { return d_index.size(); }
+ Node getLower( int index );
+ Node getUpper( int index );
+ void getLowers( std::vector< Node >& reps );
+ void getUppers( std::vector< Node >& reps );
+ Node getValue();
+};
+
+
+class QuantVarOrder
+{
+private:
+ int initialize( Node n, int minVarIndex, QIntVarNumIndex& vindex );
+ int d_var_count;
+ Node d_q;
+ void debugPrint( const char * c, Node n, QIntVarNumIndex& vindex );
+public:
+ QuantVarOrder( Node q );
+ std::map< int, Node > d_num_to_var;
+ std::map< int, int > d_num_to_prev_num;
+ std::map< int, int > d_num_to_next_num;
+ std::map< Node, std::vector< int > > d_var_to_num;
+ std::map< int, int > d_var_num_index;
+ //std::map< Node, std::map< int, int > > d_var_occur;
+ //int getVarNum( Node n, int arg ) { return d_var_occur[n][arg]; }
+ unsigned getNumVars() { return d_var_count; }
+ Node getVar( int i ) { return d_num_to_var[i]; }
+ int getPrevNum( int i ) { return d_num_to_prev_num.find( i )!=d_num_to_prev_num.end() ? d_num_to_prev_num[i] : -1; }
+ int getNextNum( int i ) { return d_num_to_next_num.find( i )!=d_num_to_next_num.end() ? d_num_to_next_num[i] : -1; }
+ int getVarNumIndex( int i ) { return d_var_num_index[i]; }
+ bool getInstantiation( FirstOrderModelQInt * m, std::vector< Node >& l, std::vector< Node >& u,
+ std::vector< Node >& inst );
+ void debugPrint( const char * c );
+ QIntVarNumIndex d_var_occur;
+};
+
+class QIntervalBuilder : public QModelBuilder
+{
+private:
+ Node d_true;
+ bool doCheck( FirstOrderModelQInt * m, Node q, QIntDef & qid, Node n,
+ QIntVarNumIndex& vindex );
+public:
+ QIntervalBuilder( context::Context* c, QuantifiersEngine* qe );
+ //process build model
+ void processBuildModel(TheoryModel* m, bool fullModel);
+ //do exhaustive instantiation
+ bool doExhaustiveInstantiation( FirstOrderModel * fm, Node q, int effort );
+};
+
+
+}
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/theory/quantifiers/quant_conflict_find.cpp b/src/theory/quantifiers/quant_conflict_find.cpp
new file mode 100755
index 000000000..d7111ea39
--- /dev/null
+++ b/src/theory/quantifiers/quant_conflict_find.cpp
@@ -0,0 +1,1907 @@
+/********************* */
+/*! \file quant_conflict_find.cpp
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief quant conflict find class
+ **
+ **/
+
+#include <vector>
+
+#include "theory/quantifiers/quant_conflict_find.h"
+#include "theory/quantifiers/quant_util.h"
+#include "theory/theory_engine.h"
+
+using namespace CVC4;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace std;
+
+namespace CVC4 {
+
+/*
+Node QcfNodeIndex::existsTerm( QuantConflictFind * qcf, Node n, int index ) {
+ if( index==(int)n.getNumChildren() ){
+ if( d_children.empty() ){
+ return Node::null();
+ }else{
+ return d_children.begin()->first;
+ }
+ }else{
+ Node r = qcf->getRepresentative( n[index] );
+ if( d_children.find( r )==d_children.end() ){
+ return n;
+ }else{
+ return d_children[r].existsTerm( qcf, n, index+1 );
+ }
+ }
+}
+
+
+Node QcfNodeIndex::addTerm( QuantConflictFind * qcf, Node n, int index ) {
+ if( index==(int)n.getNumChildren() ){
+ if( d_children.empty() ){
+ d_children[ n ].clear();
+ return n;
+ }else{
+ return d_children.begin()->first;
+ }
+ }else{
+ Node r = qcf->getRepresentative( n[index] );
+ return d_children[r].addTerm( qcf, n, index+1 );
+ }
+}
+
+bool QcfNodeIndex::addTermEq( QuantConflictFind * qcf, Node n1, Node n2, int index ) {
+ if( index==(int)n1.getNumChildren() ){
+ Node n = addTerm( qcf, n2 );
+ return n==n2;
+ }else{
+ Node r = qcf->getRepresentative( n1[index] );
+ return d_children[r].addTermEq( qcf, n1, n2, index+1 );
+ }
+}
+*/
+
+
+
+Node QcfNodeIndex::existsTerm( Node n, std::vector< Node >& reps, int index ) {
+ if( index==(int)reps.size() ){
+ if( d_children.empty() ){
+ return Node::null();
+ }else{
+ return d_children.begin()->first;
+ }
+ }else{
+ if( d_children.find( reps[index] )==d_children.end() ){
+ return Node::null();
+ }else{
+ return d_children[reps[index]].existsTerm( n, reps, index+1 );
+ }
+ }
+}
+
+Node QcfNodeIndex::addTerm( Node n, std::vector< Node >& reps, int index ) {
+ if( index==(int)reps.size() ){
+ if( d_children.empty() ){
+ d_children[ n ].clear();
+ return n;
+ }else{
+ return d_children.begin()->first;
+ }
+ }else{
+ return d_children[reps[index]].addTerm( n, reps, index+1 );
+ }
+}
+
+bool QcfNodeIndex::addTermEq( Node n1, Node n2, std::vector< Node >& reps1, std::vector< Node >& reps2, int index ) {
+ if( index==(int)reps1.size() ){
+ Node n = addTerm( n2, reps2 );
+ return n==n2;
+ }else{
+ return d_children[reps1[index]].addTermEq( n1, n2, reps1, reps2, index+1 );
+ }
+}
+
+
+
+void QcfNodeIndex::debugPrint( const char * c, int t ) {
+ for( std::map< Node, QcfNodeIndex >::iterator it = d_children.begin(); it != d_children.end(); ++it ){
+ if( !it->first.isNull() ){
+ for( int j=0; j<t; j++ ){ Trace(c) << " "; }
+ Trace(c) << it->first << " : " << std::endl;
+ it->second.debugPrint( c, t+1 );
+ }
+ }
+}
+
+EqRegistry::EqRegistry( context::Context* c ) : d_active( c, false ){//: d_t_eqc( c ){
+
+}
+
+void EqRegistry::debugPrint( const char * c, int t ) {
+ d_qni.debugPrint( c, t );
+}
+
+//QcfNode::QcfNode( context::Context* c ) : d_parent( NULL ){
+// d_reg[0] = NULL;
+// d_reg[1] = NULL;
+//}
+
+QuantConflictFind::QuantConflictFind( QuantifiersEngine * qe, context::Context* c ) :
+QuantifiersModule( qe ),
+d_c( c ),
+d_conflict( c, false ),
+d_qassert( c ) {
+ d_fid_count = 0;
+ d_true = NodeManager::currentNM()->mkConst<bool>(true);
+ d_false = NodeManager::currentNM()->mkConst<bool>(false);
+ getFunctionId( d_true );
+ getFunctionId( d_false );
+}
+
+int QuantConflictFind::getFunctionId( Node f ) {
+ std::map< Node, int >::iterator it = d_fid.find( f );
+ if( it==d_fid.end() ){
+ d_fid[f] = d_fid_count;
+ d_fid_count++;
+ return d_fid[f];
+ }
+ return it->second;
+}
+
+bool QuantConflictFind::isLessThan( Node a, Node b ) {
+ Assert( a.getKind()==APPLY_UF );
+ Assert( b.getKind()==APPLY_UF );
+ /*
+ if( a.getOperator()==b.getOperator() ){
+ for( unsigned i=0; i<a.getNumChildren(); i++ ){
+ Node acr = getRepresentative( a[i] );
+ Node bcr = getRepresentative( b[i] );
+ if( acr<bcr ){
+ return true;
+ }else if( acr>bcr ){
+ return false;
+ }
+ }
+ return false;
+ }else{
+ */
+ return getFunctionId( a.getOperator() )<getFunctionId( b.getOperator() );
+ //}
+}
+
+Node QuantConflictFind::getFunction( Node n, bool isQuant ) {
+ if( isQuant && !quantifiers::TermDb::hasBoundVarAttr( n ) ){
+ return n;
+ }else if( n.getKind()==APPLY_UF ){
+ std::map< Node, Node >::iterator it = d_op_node.find( n.getOperator() );
+ if( it==d_op_node.end() ){
+ std::vector< Node > children;
+ children.push_back( n.getOperator() );
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ children.push_back( getFv( n[i].getType() ) );
+ }
+ Node nn = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ d_op_node[n.getOperator()] = nn;
+ return nn;
+ }else{
+ return it->second;
+ }
+ }else{
+ //should be a variable
+ return Node::null();
+ }
+}
+
+Node QuantConflictFind::getFv( TypeNode tn ) {
+ if( d_fv.find( tn )==d_fv.end() ){
+ std::stringstream ss;
+ ss << "_u";
+ d_fv[tn] = NodeManager::currentNM()->mkSkolem( ss.str(), tn, "is for QCF" );
+ }
+ return d_fv[tn];
+}
+
+Node QuantConflictFind::mkEqNode( Node a, Node b ) {
+ if( a.getType().isBoolean() ){
+ return a.iffNode( b );
+ }else{
+ return a.eqNode( b );
+ }
+}
+
+//-------------------------------------------------- registration
+
+/*
+void QuantConflictFind::registerAssertions( std::vector< Node >& assertions ) {
+ for( unsigned i=0; i<assertions.size(); i++ ){
+ registerAssertion( assertions[i] );
+ }
+}
+
+void QuantConflictFind::registerAssertion( Node n ) {
+ if( n.getKind()==FORALL ){
+ registerNode( Node::null(), n[1], NULL, true, true );
+ }else{
+ if( n.getType().isBoolean() ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ registerAssertion( n[i] );
+ }
+ }
+ }
+}
+*/
+void QuantConflictFind::registerNode( Node q, Node n, bool hasPol, bool pol ) {
+ //qcf->d_node = n;
+ bool recurse = true;
+ if( n.getKind()!=OR && n.getKind()!=AND && n.getKind()!=IFF && n.getKind()!=ITE && n.getKind()!=NOT ){
+ if( quantifiers::TermDb::hasBoundVarAttr( n ) ){
+ //literals
+ for( unsigned i=0; i<2; i++ ){
+ if( !hasPol || ( pol!=(i==0) ) ){
+ EqRegistry * eqr = getEqRegistry( i==0, n );
+ if( eqr ){
+ d_qinfo[q].d_rel_eqr[ eqr ] = true;
+ }
+ }
+ }
+ if( n.getKind()==APPLY_UF ||
+ ( n.getKind()==EQUAL && ( n[0].getKind()==BOUND_VARIABLE || n[1].getKind()==BOUND_VARIABLE ) ) ){
+ flatten( q, n );
+ }else{
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ flatten( q, n[i] );
+ }
+ }
+ }else{
+ Trace("qcf-qregister") << " RegisterGroundLit : " << n;
+ }
+ recurse = false;
+ }
+ if( recurse ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ bool newHasPol;
+ bool newPol;
+ QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol );
+ //QcfNode * qcfc = new QcfNode( d_c );
+ //qcfc->d_parent = qcf;
+ //qcf->d_child[i] = qcfc;
+ registerNode( q, n[i], newHasPol, newPol );
+ }
+ }
+}
+
+void QuantConflictFind::flatten( Node q, Node n ) {
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( quantifiers::TermDb::hasBoundVarAttr( n[i] ) && n.getKind()!=BOUND_VARIABLE ){
+ if( d_qinfo[q].d_var_num.find( n[i] )==d_qinfo[q].d_var_num.end() ){
+ //Trace("qcf-qregister") << " Flatten term " << n[i] << std::endl;
+ d_qinfo[q].d_var_num[n[i]] = d_qinfo[q].d_vars.size();
+ d_qinfo[q].d_vars.push_back( n[i] );
+ flatten( q, n[i] );
+ }
+ }
+ }
+}
+
+void QuantConflictFind::registerQuantifier( Node q ) {
+ d_quants.push_back( q );
+ d_quant_id[q] = d_quants.size();
+ Trace("qcf-qregister") << "Register ";
+ debugPrintQuant( "qcf-qregister", q );
+ Trace("qcf-qregister") << " : " << q << std::endl;
+
+ //register the variables
+ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+ d_qinfo[q].d_var_num[q[0][i]] = i;
+ d_qinfo[q].d_vars.push_back( q[0][i] );
+ }
+
+ //make QcfNode structure
+ Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl;
+ //d_qinfo[q].d_cf = new QcfNode( d_c );
+ registerNode( q, q[1], true, true );
+
+ //debug print
+ Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;
+ Trace("qcf-qregister") << " ";
+ debugPrintQuantBody( "qcf-qregister", q, q[1] );
+ Trace("qcf-qregister") << std::endl;
+ if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){
+ Trace("qcf-qregister") << " with additional constraints : " << std::endl;
+ for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){
+ Trace("qcf-qregister") << " ?x" << j << " = ";
+ debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false );
+ Trace("qcf-qregister") << std::endl;
+ }
+ }
+
+ Trace("qcf-qregister") << "- Make match gen structure..." << std::endl;
+ d_qinfo[q].d_mg = new MatchGen( this, q, q[1], true );
+
+ for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){
+ d_qinfo[q].d_var_mg[j] = new MatchGen( this, q, d_qinfo[q].d_vars[j], false, true );
+ if( !d_qinfo[q].d_var_mg[j]->isValid() ){
+ d_qinfo[q].d_mg->setInvalid();
+ break;
+ }
+ }
+
+ Trace("qcf-qregister") << "Done registering quantifier." << std::endl;
+}
+
+EqRegistry * QuantConflictFind::getEqRegistry( bool polarity, Node lit, bool doCreate ) {
+ Assert( quantifiers::TermDb::hasBoundVarAttr( lit ) );
+ int i;
+ Node f1;
+ Node f2;
+ if( lit.getKind()==EQUAL ){
+ i = polarity ? 0 : 1;
+ f1 = getFunction( lit[0], true );
+ f2 = getFunction( lit[1], true );
+ }else if( lit.getKind()==APPLY_UF ){
+ i = 0;
+ f1 = getFunction( lit, true );
+ f2 = polarity ? d_true : d_false;
+ }
+ if( !f1.isNull() && !f2.isNull() ){
+ if( d_eqr[i][f1].find( f2 )==d_eqr[i][f1].end() ){
+ if( doCreate ){
+ Trace("qcf-register") << "RegisterEqr : " << f1 << " " << f2 << ", polarity = " << (i==0) << std::endl;
+ d_eqr[i][f1][f2] = new EqRegistry( d_c );
+ d_eqr[i][f2][f1] = d_eqr[i][f1][f2];
+ }else{
+ return NULL;
+ }
+ }
+ return d_eqr[i][f1][f2];
+ }else{
+ return NULL;
+ }
+}
+
+void QuantConflictFind::getEqRegistryApps( Node lit, std::vector< Node >& terms ) {
+ Assert( quantifiers::TermDb::hasBoundVarAttr( lit ) );
+ if( lit.getKind()==EQUAL ){
+ bool allUf = false;
+ for( unsigned i=0; i<2; i++ ){
+ if( quantifiers::TermDb::hasBoundVarAttr( lit[i] ) ){
+ if( lit[i].getKind()==BOUND_VARIABLE ){
+ //do not handle variable equalities
+ terms.clear();
+ return;
+ }else{
+ allUf = allUf && lit[i].getKind()==APPLY_UF;
+ terms.push_back( lit[i] );
+ }
+ }
+ }
+ if( terms.size()==2 && allUf && isLessThan( terms[1], terms[0] ) ){
+ Node t = terms[0];
+ terms[0] = terms[1];
+ terms[1] = t;
+ }
+ }else if( lit.getKind()==APPLY_UF ){
+ terms.push_back( lit );
+ }
+}
+
+int QuantConflictFind::evaluate( Node n ) {
+ int ret = 0;
+ if( n.getKind()==EQUAL ){
+ Node n1 = getTerm( n[0] );
+ Node n2 = getTerm( n[1] );
+ Debug("qcf-eval") << "Evaluate : Normalize " << n << " to " << n1 << " = " << n2 << std::endl;
+ if( areEqual( n1, n2 ) ){
+ ret = 1;
+ }else if( areDisequal( n1, n2 ) ){
+ ret = -1;
+ }
+ }else if( n.getKind()==APPLY_UF ){
+ Node nn = getTerm( n );
+ Debug("qcf-eval") << "Evaluate : Normalize " << nn << " to " << n << std::endl;
+ if( areEqual( nn, d_true ) ){
+ ret = 1;
+ }else if( areEqual( nn, d_false ) ){
+ ret = -1;
+ }
+ }else if( n.getKind()==NOT ){
+ return -evaluate( n[0] );
+ }else if( n.getKind()==ITE ){
+ int cev1 = evaluate( n[0] );
+ int cevc[2] = { 0, 0 };
+ for( unsigned i=0; i<2; i++ ){
+ if( ( i==0 && cev1!=-1 ) || ( i==1 && cev1!=1 ) ){
+ cevc[i] = evaluate( n[i+1] );
+ if( cev1!=0 ){
+ ret = cevc[i];
+ break;
+ }else if( cevc[i]==0 ){
+ break;
+ }
+ }
+ }
+ if( ret==0 && cevc[0]!=0 && cevc[0]==cevc[1] ){
+ ret = cevc[0];
+ }
+ }else if( n.getKind()==IFF ){
+ int cev1 = evaluate( n[0] );
+ if( cev1!=0 ){
+ int cev2 = evaluate( n[1] );
+ if( cev2!=0 ){
+ ret = cev1==cev2 ? 1 : -1;
+ }
+ }
+
+ }else{
+ int ssval = 0;
+ if( n.getKind()==OR ){
+ ssval = 1;
+ }else if( n.getKind()==AND ){
+ ssval = -1;
+ }
+ bool isUnk = false;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ int cev = evaluate( n[i] );
+ if( cev==ssval ){
+ ret = ssval;
+ break;
+ }else if( cev==0 ){
+ isUnk = true;
+ }
+ }
+ if( ret==0 && !isUnk ){
+ ret = -ssval;
+ }
+ }
+ Debug("qcf-eval") << "Evaluate " << n << " to " << ret << std::endl;
+ return ret;
+}
+
+//-------------------------------------------------- handling assertions / eqc
+
+void QuantConflictFind::assertNode( Node q ) {
+ Trace("qcf-proc") << "QCF : assertQuantifier : ";
+ debugPrintQuant("qcf-proc", q);
+ Trace("qcf-proc") << std::endl;
+ d_qassert.push_back( q );
+ //set the eqRegistries that this depends on to true
+ for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){
+ it->first->d_active.set( true );
+ }
+}
+
+eq::EqualityEngine * QuantConflictFind::getEqualityEngine() {
+ //return ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( theory::THEORY_UF ))->getEqualityEngine();
+ return d_quantEngine->getTheoryEngine()->getMasterEqualityEngine();
+}
+bool QuantConflictFind::areEqual( Node n1, Node n2 ) {
+ return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areEqual( n1,n2 );
+}
+bool QuantConflictFind::areDisequal( Node n1, Node n2 ) {
+ return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areDisequal( n1,n2, false );
+}
+Node QuantConflictFind::getRepresentative( Node n ) {
+ if( getEqualityEngine()->hasTerm( n ) ){
+ return getEqualityEngine()->getRepresentative( n );
+ }else{
+ return n;
+ }
+}
+Node QuantConflictFind::getTerm( Node n ) {
+ if( n.getKind()==APPLY_UF ){
+ computeArgReps( n );
+ Node nn = d_uf_terms[n.getOperator()].existsTerm( n, d_arg_reps[n] );
+ if( !nn.isNull() ){
+ return nn;
+ }
+ }
+ return n;
+}
+
+QuantConflictFind::EqcInfo * QuantConflictFind::getEqcInfo( Node n, bool doCreate ) {
+ /*
+ NodeBoolMap::iterator it = d_eqc.find( n );
+ if( it==d_eqc.end() ){
+ if( doCreate ){
+ d_eqc[n] = true;
+ }else{
+ //equivalence class does not currently exist
+ return NULL;
+ }
+ }else{
+ //should only ask for valid equivalence classes
+ Assert( (*it).second );
+ }
+ */
+ std::map< Node, EqcInfo * >::iterator it2 = d_eqc_info.find( n );
+ if( it2==d_eqc_info.end() ){
+ if( doCreate ){
+ EqcInfo * eqci = new EqcInfo( d_c );
+ d_eqc_info[n] = eqci;
+ return eqci;
+ }else{
+ return NULL;
+ }
+ }
+ return it2->second;
+}
+
+/** new node */
+void QuantConflictFind::newEqClass( Node n ) {
+ Trace("qcf-proc-debug") << "QCF : newEqClass : " << n << std::endl;
+
+ Trace("qcf-proc2-debug") << "QCF : finished newEqClass : " << n << std::endl;
+}
+
+/** merge */
+void QuantConflictFind::merge( Node a, Node b ) {
+ if( b.getKind()==EQUAL ){
+ if( a==d_true ){
+ //will merge anyways
+ //merge( b[0], b[1] );
+ }else if( a==d_false ){
+ assertDisequal( b[0], b[1] );
+ }
+ }else{
+ Trace("qcf-proc") << "QCF : merge : " << a << " " << b << std::endl;
+ EqcInfo * eqc_b = getEqcInfo( b, false );
+ EqcInfo * eqc_a = NULL;
+ if( eqc_b ){
+ eqc_a = getEqcInfo( a );
+ //move disequalities of b into a
+ for( NodeBoolMap::iterator it = eqc_b->d_diseq.begin(); it != eqc_b->d_diseq.end(); ++it ){
+ if( (*it).second ){
+ Node n = (*it).first;
+ EqcInfo * eqc_n = getEqcInfo( n, false );
+ Assert( eqc_n );
+ if( !eqc_n->isDisequal( a ) ){
+ Assert( !eqc_a->isDisequal( n ) );
+ eqc_n->setDisequal( a );
+ eqc_a->setDisequal( n );
+ //setEqual( eqc_a, eqc_b, a, n, false );
+ }
+ eqc_n->setDisequal( b, false );
+ }
+ }
+ /*
+ //move all previous EqcRegistry's regarding equalities within b
+ for( NodeBoolMap::iterator it = eqc_b->d_rel_eqr_e.begin(); it != eqc_b->d_rel_eqr_e.end(); ++it ){
+ if( (*it).second ){
+ eqc_a->d_rel_eqr_e[(*it).first] = true;
+ }
+ }
+ */
+ }
+ //process new equalities
+ //setEqual( eqc_a, eqc_b, a, b, true );
+ Trace("qcf-proc2") << "QCF : finished merge : " << a << " " << b << std::endl;
+ }
+}
+
+/** assert disequal */
+void QuantConflictFind::assertDisequal( Node a, Node b ) {
+ a = getRepresentative( a );
+ b = getRepresentative( b );
+ Trace("qcf-proc") << "QCF : assert disequal : " << a << " " << b << std::endl;
+ EqcInfo * eqc_a = getEqcInfo( a );
+ EqcInfo * eqc_b = getEqcInfo( b );
+ if( !eqc_a->isDisequal( b ) ){
+ Assert( !eqc_b->isDisequal( a ) );
+ eqc_b->setDisequal( a );
+ eqc_a->setDisequal( b );
+ //setEqual( eqc_a, eqc_b, a, b, false );
+ }
+ Trace("qcf-proc2") << "QCF : finished assert disequal : " << a << " " << b << std::endl;
+}
+
+//-------------------------------------------------- check function
+
+/** check */
+void QuantConflictFind::check( Theory::Effort level ) {
+ Trace("qcf-check") << "QCF : check : " << level << std::endl;
+ if( d_conflict ){
+ Trace("qcf-check2") << "QCF : finished check : already in conflict." << std::endl;
+ if( level>=Theory::EFFORT_FULL ){
+ Assert( false );
+ }
+ }else{
+ bool addedLemma = false;
+ if( d_performCheck ){
+ ++(d_statistics.d_inst_rounds);
+ double clSet = 0;
+ if( Trace.isOn("qcf-engine") ){
+ clSet = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level << "---" << std::endl;
+ }
+ Trace("qcf-check") << "Compute relevant equalities..." << std::endl;
+ computeRelevantEqr();
+
+ Trace("qcf-debug") << std::endl;
+ debugPrint("qcf-debug");
+ Trace("qcf-debug") << std::endl;
+
+
+ Trace("qcf-check") << "Checking quantified formulas..." << std::endl;
+ for( unsigned j=0; j<d_qassert.size(); j++ ){
+ Node q = d_qassert[j];
+ Trace("qcf-check") << "Check quantified formula ";
+ debugPrintQuant("qcf-check", q);
+ Trace("qcf-check") << " : " << q << "..." << std::endl;
+
+ Assert( d_qinfo.find( q )!=d_qinfo.end() );
+ if( d_qinfo[q].d_mg->isValid() ){
+ d_qinfo[q].reset_round( this );
+ //try to make a matches making the body false
+ d_qinfo[q].d_mg->reset( this, false, q );
+ while( d_qinfo[q].d_mg->getNextMatch( this, q ) ){
+
+ Trace("qcf-check") << "*** Produced match : " << std::endl;
+ d_qinfo[q].debugPrintMatch("qcf-check");
+ Trace("qcf-check") << std::endl;
+
+ if( !d_qinfo[q].isMatchSpurious( this ) ){
+ std::vector< int > assigned;
+ if( d_qinfo[q].completeMatch( this, q, assigned ) ){
+ InstMatch m;
+ for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
+ Node cv = d_qinfo[q].getCurrentValue( d_qinfo[q].d_match[i] );
+ Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_qinfo[q].d_match[i] << std::endl;
+ m.set( d_quantEngine, q, i, cv );
+ }
+ if( Debug.isOn("qcf-check-inst") ){
+ Node inst = d_quantEngine->getInstantiation( q, m );
+ Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;
+ Assert( evaluate( inst )==-1 );
+ }
+ if( d_quantEngine->addInstantiation( q, m ) ){
+ Trace("qcf-check") << " ... Added instantiation" << std::endl;
+ d_quantEngine->flushLemmas();
+ d_conflict.set( true );
+ addedLemma = true;
+ ++(d_statistics.d_conflict_inst);
+ break;
+ }else{
+ Trace("qcf-check") << " ... Failed to add instantiation" << std::endl;
+ Assert( false );
+ }
+ //clean up assigned
+ for( unsigned i=0; i<assigned.size(); i++ ){
+ d_qinfo[q].d_match.erase( assigned[i] );
+ }
+ }else{
+ Trace("qcf-check") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl;
+ }
+ }else{
+ Trace("qcf-check") << " ... Spurious instantiation (does not meet variable constraints)" << std::endl;
+ }
+ }
+ }
+ if( addedLemma ){
+ break;
+ }
+ }
+ if( Trace.isOn("qcf-engine") ){
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("qcf-engine") << "Finished conflict find engine, time = " << (clSet2-clSet) << ", addedLemma = " << addedLemma << std::endl;
+ }
+ }
+ Trace("qcf-check2") << "QCF : finished check : " << level << std::endl;
+ }
+}
+
+bool QuantConflictFind::needsCheck( Theory::Effort level ) {
+ d_performCheck = false;
+ if( !d_conflict ){
+ if( level==Theory::EFFORT_FULL ){
+ d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_DEFAULT;
+ }else if( level==Theory::EFFORT_STANDARD ){
+ d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_STD;
+ }
+ }
+ return d_performCheck;
+}
+
+void QuantConflictFind::computeRelevantEqr() {
+ //first, reset information
+ for( unsigned i=0; i<2; i++ ){
+ for( std::map< Node, std::map< Node, EqRegistry * > >::iterator it = d_eqr[i].begin(); it != d_eqr[i].end(); ++it ){
+ for( std::map< Node, EqRegistry * >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ it2->second->clear();
+ }
+ }
+ }
+ d_uf_terms.clear();
+ d_eqc_uf_terms.clear();
+ d_eqcs.clear();
+ d_arg_reps.clear();
+
+ //which nodes are irrelevant for disequality matches
+ std::map< Node, bool > irrelevant_dnode;
+ //which eqc we have processed
+ std::map< Node, bool > process_eqc;
+ //now, store matches
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
+ while( !eqcs_i.isFinished() ){
+ Node r = (*eqcs_i);
+ d_eqcs[r.getType()].push_back( r );
+ EqcInfo * eqcir = getEqcInfo( r, false );
+ //get relevant nodes that we are disequal from
+ std::vector< Node > deqc;
+ if( eqcir ){
+ for( NodeBoolMap::iterator it = eqcir->d_diseq.begin(); it != eqcir->d_diseq.end(); ++it ){
+ if( (*it).second ){
+ Node rd = (*it).first;
+ //if we have processed the other direction
+ if( process_eqc.find( rd )!=process_eqc.end() ){
+ eq::EqClassIterator eqcd_i = eq::EqClassIterator( rd, getEqualityEngine() );
+ while( !eqcd_i.isFinished() ){
+ Node nd = (*eqcd_i);
+ if( irrelevant_dnode.find( nd )==irrelevant_dnode.end() ){
+ deqc.push_back( nd );
+ }
+ ++eqcd_i;
+ }
+ }
+ }
+ }
+ }
+ //the relevant nodes in this eqc
+ std::vector< Node > eqc;
+ //process disequalities
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() );
+ while( !eqc_i.isFinished() ){
+ Node n = (*eqc_i);
+ bool isRedundant;
+ if( n.getKind()==APPLY_UF ){
+ computeArgReps( n );
+ Node nadd = d_eqc_uf_terms[r][n.getOperator()].addTerm( n, d_arg_reps[n] );
+ isRedundant = (nadd!=n);
+ d_uf_terms[n.getOperator()].addTerm( n, d_arg_reps[n] );
+ }else{
+ isRedundant = false;
+ }
+ //process all relevant equalities and disequalities to n
+ for( unsigned index=0; index<2; index++ ){
+ std::map< Node, std::map< Node, EqRegistry * > >::iterator itn[2];
+ itn[0] = d_eqr[index].find( n );
+ Node fn;
+ if( n.getKind()==APPLY_UF && !isRedundant ){
+ fn = getFunction( n );
+ itn[1] = d_eqr[index].find( fn );
+ }
+ //for n, fn...
+ bool relevant = false;
+ for( unsigned j=0; j<2; j++ ){
+ //if this node is relevant as an ground term or f-application
+ if( ( j==0 || !fn.isNull() ) && itn[j]!=d_eqr[index].end() ){
+ relevant = true;
+ std::vector< Node >& rel_nodes = index==0 ? eqc : deqc;
+ for( unsigned i=0; i<rel_nodes.size(); i++ ){
+ Node m = rel_nodes[i];
+ Node fm;
+ if( m.getKind()==APPLY_UF ){
+ fm = getFunction( m );
+ }
+ //process equality/disequality
+ if( j==1 ){
+ //fn with m
+ std::map< Node, EqRegistry * >::iterator itm = itn[j]->second.find( m );
+ if( itm!=itn[j]->second.end() ){
+ if( itm->second->d_qni.addTerm( n, d_arg_reps[n] )==n ){
+ Trace("qcf-reqr") << "Add relevant : " << n << (index==0?"":"!") << "=" << m << " for ";
+ Trace("qcf-reqr") << fn << " " << m << std::endl;
+ }
+ }
+ }
+ if( !fm.isNull() ){
+ std::map< Node, EqRegistry * >::iterator itm = itn[j]->second.find( fm );
+ if( itm!=itn[j]->second.end() ){
+ Assert( d_arg_reps.find( m )!=d_arg_reps.end() );
+ if( j==0 ){
+ //n with fm
+ if( itm->second->d_qni.addTerm( m, d_arg_reps[m] )==m ){
+ Trace("qcf-reqr") << "Add relevant : " << n << (index==0?"":"!") << "=" << m << " for ";
+ Trace("qcf-reqr") << n << " " << fm << std::endl;
+ }
+ }else{
+ //fn with fm
+ bool mltn = isLessThan( m, n );
+ for( unsigned i=0; i<2; i++ ){
+ if( i==0 || m.getOperator()==n.getOperator() ){
+ Node am = ((i==0)==mltn) ? n : m;
+ Node an = ((i==0)==mltn) ? m : n;
+ if( itm->second->d_qni.addTermEq( an, am, d_arg_reps[n], d_arg_reps[m] ) ){
+ Trace("qcf-reqr") << "Add relevant (eq) : " << an << (index==0?"":"!") << "=" << am << " for ";
+ Trace("qcf-reqr") << fn << " " << fm << std::endl;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if( !relevant ){
+ //if not relevant for disequalities, store it
+ if( index==1 ){
+ irrelevant_dnode[n] = true;
+ }
+ }else{
+ //if relevant for equalities, store it
+ if( index==0 ){
+ eqc.push_back( n );
+ }
+ }
+ }
+ ++eqc_i;
+ }
+ process_eqc[r] = true;
+ ++eqcs_i;
+ }
+}
+
+void QuantConflictFind::computeArgReps( Node n ) {
+ if( d_arg_reps.find( n )==d_arg_reps.end() ){
+ for( unsigned j=0; j<n.getNumChildren(); j++ ){
+ d_arg_reps[n].push_back( getRepresentative( n[j] ) );
+ }
+ }
+}
+
+
+void QuantConflictFind::QuantInfo::reset_round( QuantConflictFind * p ) {
+ d_match.clear();
+ d_curr_var_deq.clear();
+ //add built-in variable constraints
+ for( unsigned r=0; r<2; r++ ){
+ for( std::map< int, std::vector< Node > >::iterator it = d_var_constraint[r].begin();
+ it != d_var_constraint[r].end(); ++it ){
+ for( unsigned j=0; j<it->second.size(); j++ ){
+ Node rr = it->second[j];
+ if( !isVar( rr ) ){
+ rr = p->getRepresentative( rr );
+ }
+ if( addConstraint( p, it->first, rr, r==0 )==-1 ){
+ d_var_constraint[0].clear();
+ d_var_constraint[1].clear();
+ //quantified formula is actually equivalent to true
+ Trace("qcf-qregister") << "Quantifier is equivalent to true!!!" << std::endl;
+ d_mg->d_children.clear();
+ d_mg->d_n = NodeManager::currentNM()->mkConst( true );
+ d_mg->d_type = MatchGen::typ_ground;
+ return;
+ }
+ }
+ }
+ }
+ d_mg->reset_round( p );
+ for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){
+ it->second->reset_round( p );
+ }
+}
+
+int QuantConflictFind::QuantInfo::getCurrentRepVar( int v ) {
+ std::map< int, Node >::iterator it = d_match.find( v );
+ if( it!=d_match.end() ){
+ int vn = getVarNum( it->second );
+ if( vn!=-1 ){
+ //int vr = getCurrentRepVar( vn );
+ //d_match[v] = d_vars[vr];
+ //return vr;
+ return getCurrentRepVar( vn );
+ }
+ }
+ return v;
+}
+
+Node QuantConflictFind::QuantInfo::getCurrentValue( Node n ) {
+ int v = getVarNum( n );
+ if( v==-1 ){
+ return n;
+ }else{
+ std::map< int, Node >::iterator it = d_match.find( v );
+ if( it==d_match.end() ){
+ return n;
+ }else{
+ Assert( getVarNum( it->second )!=v );
+ return getCurrentValue( it->second );
+ }
+ }
+}
+
+bool QuantConflictFind::QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, Node n ) {
+ //check disequalities
+ for( std::map< Node, int >::iterator it = d_curr_var_deq[v].begin(); it != d_curr_var_deq[v].end(); ++it ){
+ Node cv = getCurrentValue( it->first );
+ Debug("qcf-ccbe") << "compare " << cv << " " << n << std::endl;
+ if( cv==n ){
+ return false;
+ }else if( !isVar( n ) && !isVar( cv ) ){
+ //they must actually be disequal
+ if( !p->areDisequal( n, cv ) ){
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+int QuantConflictFind::QuantInfo::addConstraint( QuantConflictFind * p, int v, Node n, bool polarity ) {
+ v = getCurrentRepVar( v );
+ int vn = getVarNum( n );
+ vn = vn==-1 ? -1 : getCurrentRepVar( vn );
+ n = getCurrentValue( n );
+ return addConstraint( p, v, n, vn, polarity, false );
+}
+
+int QuantConflictFind::QuantInfo::addConstraint( QuantConflictFind * p, int v, Node n, int vn, bool polarity, bool doRemove ) {
+ //for handling equalities between variables, and disequalities involving variables
+ Debug("qcf-match-debug") << "- " << (doRemove ? "un" : "" ) << "constrain : " << v << " -> " << n << " (cv=" << getCurrentValue( n ) << ")";
+ Debug("qcf-match-debug") << ", (vn=" << vn << "), polarity = " << polarity << std::endl;
+ Assert( doRemove || n==getCurrentValue( n ) );
+ Assert( doRemove || v==getCurrentRepVar( v ) );
+ Assert( doRemove || vn==getCurrentRepVar( getVarNum( n ) ) );
+ if( polarity ){
+ if( vn!=v ){
+ if( doRemove ){
+ if( vn!=-1 ){
+ //if set to this in the opposite direction, clean up opposite instead
+ std::map< int, Node >::iterator itmn = d_match.find( vn );
+ if( itmn!=d_match.end() && itmn->second==d_vars[v] ){
+ return addConstraint( p, vn, d_vars[v], v, true, true );
+ }else{
+ //unsetting variables equal
+
+ //remove disequalities owned by this
+ std::vector< Node > remDeq;
+ for( std::map< Node, int >::iterator it = d_curr_var_deq[vn].begin(); it != d_curr_var_deq[vn].end(); ++it ){
+ if( it->second==v ){
+ remDeq.push_back( it->first );
+ }
+ }
+ for( unsigned i=0; i<remDeq.size(); i++ ){
+ d_curr_var_deq[vn].erase( remDeq[i] );
+ }
+ }
+ }
+ d_match.erase( v );
+ return 1;
+ }else{
+ std::map< int, Node >::iterator itm = d_match.find( v );
+
+ if( vn!=-1 ){
+ Debug("qcf-match-debug") << " ...Variable bound to variable" << std::endl;
+ std::map< int, Node >::iterator itmn = d_match.find( vn );
+ if( itm==d_match.end() ){
+ //setting variables equal
+ bool alreadySet = false;
+ if( itmn!=d_match.end() ){
+ alreadySet = true;
+ Assert( !itmn->second.isNull() && !isVar( itmn->second ) );
+ }
+
+ //copy or check disequalities
+ std::vector< Node > addDeq;
+ for( std::map< Node, int >::iterator it = d_curr_var_deq[v].begin(); it != d_curr_var_deq[v].end(); ++it ){
+ Node dv = getCurrentValue( it->first );
+ if( !alreadySet ){
+ if( d_curr_var_deq[vn].find( dv )==d_curr_var_deq[vn].end() ){
+ d_curr_var_deq[vn][dv] = v;
+ addDeq.push_back( dv );
+ }
+ }else{
+ if( itmn->second!=dv ){
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
+ return -1;
+ }
+ }
+ }
+ if( alreadySet ){
+ n = getCurrentValue( n );
+ }
+ }else{
+ if( itmn==d_match.end() ){
+ Debug("qcf-match-debug") << " ...Reverse direction" << std::endl;
+ //set the opposite direction
+ return addConstraint( p, vn, d_vars[v], v, true, false );
+ }else{
+ Debug("qcf-match-debug") << " -> Both variables bound, compare" << std::endl;
+ //are they currently equal
+ return itm->second==itmn->second ? 0 : -1;
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " ...Variable bound to ground" << std::endl;
+ if( itm==d_match.end() ){
+
+ }else{
+ //compare ground values
+ Debug("qcf-match-debug") << " -> Ground value, compare " << itm->second << " "<< n << std::endl;
+ return itm->second==n ? 0 : -1;
+ }
+ }
+ if( setMatch( p, v, n ) ){
+ Debug("qcf-match-debug") << " -> success" << std::endl;
+ return 1;
+ }else{
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
+ return -1;
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " -> redundant, variable identity" << std::endl;
+ return 0;
+ }
+ }else{
+ if( vn==v ){
+ Debug("qcf-match-debug") << " -> fail, variable identity" << std::endl;
+ return -1;
+ }else{
+ if( doRemove ){
+ Assert( d_curr_var_deq[v].find( n )!=d_curr_var_deq[v].end() );
+ d_curr_var_deq[v].erase( n );
+ return 1;
+ }else{
+ if( d_curr_var_deq[v].find( n )==d_curr_var_deq[v].end() ){
+ //check if it respects equality
+ std::map< int, Node >::iterator itm = d_match.find( v );
+ if( itm!=d_match.end() ){
+ if( getCurrentValue( n )==itm->second ){
+ Debug("qcf-match-debug") << " -> fail, conflicting disequality" << std::endl;
+ return -1;
+ }
+ }
+ d_curr_var_deq[v][n] = v;
+ Debug("qcf-match-debug") << " -> success" << std::endl;
+ return 1;
+ }else{
+ Debug("qcf-match-debug") << " -> redundant disequality" << std::endl;
+ return 0;
+ }
+ }
+ }
+ }
+}
+
+bool QuantConflictFind::QuantInfo::setMatch( QuantConflictFind * p, int v, Node n ) {
+ if( getCurrentCanBeEqual( p, v, n ) ){
+ Debug("qcf-match-debug") << "-- bind : " << v << " -> " << n << ", checked " << d_curr_var_deq[v].size() << " disequalities" << std::endl;
+ d_match[v] = n;
+ return true;
+ }else{
+ return false;
+ }
+}
+
+bool QuantConflictFind::QuantInfo::isMatchSpurious( QuantConflictFind * p ) {
+ for( int i=0; i<getNumVars(); i++ ){
+ std::map< int, Node >::iterator it = d_match.find( i );
+ if( it!=d_match.end() ){
+ if( !getCurrentCanBeEqual( p, i, it->second ) ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool QuantConflictFind::QuantInfo::completeMatch( QuantConflictFind * p, Node q, std::vector< int >& assigned ) {
+ //assign values for variables that were unassigned (usually not necessary, but handles corner cases)
+ Trace("qcf-check") << std::endl;
+ std::vector< int > unassigned[2];
+ std::vector< TypeNode > unassigned_tn[2];
+ for( int i=0; i<getNumVars(); i++ ){
+ if( d_match.find( i )==d_match.end() ){
+ Assert( i<(int)q[0].getNumChildren() );
+ int rindex = d_var_mg.find( i )==d_var_mg.end() ? 1 : 0;
+ unassigned[rindex].push_back( i );
+ unassigned_tn[rindex].push_back( getVar( i ).getType() );
+ assigned.push_back( i );
+ }
+ }
+ bool success = true;
+ for( unsigned r=0; r<2; r++ ){
+ if( success && !unassigned[r].empty() ){
+ Trace("qcf-check") << "Assign to unassigned, rep = " << r << "..." << std::endl;
+ int index = 0;
+ std::vector< int > eqc_count;
+ do {
+ bool invalidMatch;
+ while( ( index>=0 && (int)index<(int)unassigned[r].size() ) || invalidMatch ){
+ invalidMatch = false;
+ if( index==(int)eqc_count.size() ){
+ //check if it has now been assigned
+ if( r==0 ){
+ d_var_mg[ unassigned[r][index] ]->reset( p, true, q );
+ }
+ eqc_count.push_back( 0 );
+ }else{
+ if( r==0 ){
+ if( d_var_mg[unassigned[r][index]]->getNextMatch( p, q ) ){
+ Trace("qcf-check-unassign") << "Succeeded match with mg" << std::endl;
+ index++;
+ }else{
+ Trace("qcf-check-unassign") << "Failed match with mg" << std::endl;
+ eqc_count.pop_back();
+ index--;
+ }
+ }else{
+ Assert( index==(int)eqc_count.size()-1 );
+ if( eqc_count[index]<(int)p->d_eqcs[unassigned_tn[r][index]].size() ){
+ int currIndex = eqc_count[index];
+ eqc_count[index]++;
+ Trace("qcf-check-unassign") << unassigned[r][index] << "->" << p->d_eqcs[unassigned_tn[r][index]][currIndex] << std::endl;
+ if( setMatch( p, unassigned[r][index], p->d_eqcs[unassigned_tn[r][index]][currIndex] ) ){
+ Trace("qcf-check-unassign") << "Succeeded match" << std::endl;
+ index++;
+ }else{
+ Trace("qcf-check-unassign") << "Failed match" << std::endl;
+ invalidMatch = true;
+ }
+ }else{
+ Trace("qcf-check-unassign") << "No more matches" << std::endl;
+ eqc_count.pop_back();
+ index--;
+ }
+ }
+ }
+ }
+ success = index>=0;
+ if( success ){
+ index = (int)unassigned[r].size()-1;
+ Trace("qcf-check-unassign") << " Try: " << std::endl;
+ for( unsigned i=0; i<unassigned[r].size(); i++ ){
+ int ui = unassigned[r][i];
+ Trace("qcf-check-unassign") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
+ }
+ }
+ }while( success && isMatchSpurious( p ) );
+ }
+ }
+ if( success ){
+ return true;
+ }else{
+ for( unsigned i=0; i<assigned.size(); i++ ){
+ d_match.erase( assigned[i] );
+ }
+ assigned.clear();
+ return false;
+ }
+}
+
+void QuantConflictFind::QuantInfo::debugPrintMatch( const char * c ) {
+ for( int i=0; i<getNumVars(); i++ ){
+ Trace(c) << " " << d_vars[i] << " -> ";
+ if( d_match.find( i )!=d_match.end() ){
+ Trace(c) << d_match[i];
+ }else{
+ Trace(c) << "(unassigned) ";
+ }
+ if( !d_curr_var_deq[i].empty() ){
+ Trace(c) << ", DEQ{ ";
+ for( std::map< Node, int >::iterator it = d_curr_var_deq[i].begin(); it != d_curr_var_deq[i].end(); ++it ){
+ Trace(c) << it->first << " ";
+ }
+ Trace(c) << "}";
+ }
+ Trace(c) << std::endl;
+ }
+}
+
+
+struct MatchGenSort {
+ QuantConflictFind::MatchGen * d_mg;
+ bool operator() (int i,int j) {
+ return d_mg->d_children[i].d_type<d_mg->d_children[j].d_type;
+ }
+};
+
+QuantConflictFind::MatchGen::MatchGen( QuantConflictFind * p, Node q, Node n, bool isTop, bool isVar ){
+ Trace("qcf-qregister-debug") << "Make match gen for " << n << ", top/var = " << isTop << " " << isVar << std::endl;
+ std::vector< Node > qni_apps;
+ d_qni_size = 0;
+ if( isVar ){
+ Assert( p->d_qinfo[q].d_var_num.find( n )!=p->d_qinfo[q].d_var_num.end() );
+ if( n.getKind()==APPLY_UF ){
+ d_type = typ_var;
+ //d_type_not = true; //implicit disequality, in disjunction at top level
+ d_type_not = false;
+ d_n = n;
+ qni_apps.push_back( n );
+ }else{
+ //for now, unknown term
+ d_type = typ_invalid;
+ }
+ }else{
+ /*
+ if( isTop && n.getKind()!=OR && p->d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){
+ //conjoin extra constraints based on flattening with quantifier body
+ d_children.push_back( MatchGen( p, q, n ) );
+ if( d_children[0].d_type==typ_invalid ){
+ d_children.clear();
+ d_type = typ_invalid;
+ }else{
+ d_type = typ_top;
+ }
+ d_type_not = false;
+ }else
+ */
+ if( quantifiers::TermDb::hasBoundVarAttr( n ) ){
+ //we handle not immediately
+ d_n = n.getKind()==NOT ? n[0] : n;
+ d_type_not = n.getKind()==NOT;
+ if( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF || d_n.getKind()==ITE ){
+ //non-literals
+ d_type = typ_valid;
+ for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
+ d_children.push_back( MatchGen( p, q, d_n[i] ) );
+ if( d_children[d_children.size()-1].d_type==typ_invalid ){
+ setInvalid();
+ break;
+ }else if( isTop && n.getKind()==OR && d_children[d_children.size()-1].d_type==typ_var_eq ){
+ Trace("qcf-qregister-debug") << "Remove child, make built-in constraint" << std::endl;
+ //if variable equality/disequality at top level, remove immediately
+ bool cIsNot = d_children[d_children.size()-1].d_type_not;
+ Node cn = d_children[d_children.size()-1].d_n;
+ Assert( cn.getKind()==EQUAL );
+ Assert( p->d_qinfo[q].isVar( cn[0] ) || p->d_qinfo[q].isVar( cn[1] ) );
+ //make it a built-in constraint instead
+ for( unsigned i=0; i<2; i++ ){
+ if( p->d_qinfo[q].isVar( cn[i] ) ){
+ int v = p->d_qinfo[q].getVarNum( cn[i] );
+ Node cno = cn[i==0 ? 1 : 0];
+ p->d_qinfo[q].d_var_constraint[ cIsNot ? 0 : 1 ][v].push_back( cno );
+ break;
+ }
+ }
+ d_children.pop_back();
+ }
+ }
+ }else{
+ d_type = typ_invalid;
+ //literals
+ if( d_n.getKind()==APPLY_UF || d_n.getKind()==EQUAL ){
+ //get the applications (in order) that will be matching
+ p->getEqRegistryApps( d_n, qni_apps );
+ bool isValid = true;
+ if( qni_apps.size()>0 ){
+ for( unsigned i=0; i<qni_apps.size(); i++ ){
+ if( qni_apps[i].getKind()!=APPLY_UF ){
+ //for now, cannot handle anything besides uf
+ isValid = false;
+ qni_apps.clear();
+ break;
+ }
+ }
+ if( isValid ){
+ d_type = typ_valid_lit;
+ }
+ }else if( d_n.getKind()==EQUAL ){
+ for( unsigned i=0; i<2; i++ ){
+ if( quantifiers::TermDb::hasBoundVarAttr( d_n[i] ) && !p->d_qinfo[q].isVar( d_n[i] ) ){
+ isValid = false;
+ break;
+ }
+ }
+ if( isValid ){
+ Assert( p->d_qinfo[q].isVar( d_n[0] ) || p->d_qinfo[q].isVar( d_n[1] ) );
+ // variable equality
+ d_type = typ_var_eq;
+ }
+ }
+ }
+ }
+ }else{
+ //we will just evaluate
+ d_n = n;
+ d_type = typ_ground;
+ }
+ if( d_type!=typ_invalid ){
+ //determine an efficient children ordering
+ if( !d_children.empty() ){
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ d_children_order.push_back( i );
+ }
+ //if( !d_n.isNull() && ( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF ) ){
+ //sort based on the type of the constraint : ground comes first, then literals, then others
+ //MatchGenSort mgs;
+ //mgs.d_mg = this;
+ //std::sort( d_children_order.begin(), d_children_order.end(), mgs );
+ //}
+ }
+ /*
+ if( isTop ){
+ int base = d_children.size();
+ //add additional constraints based on flattening
+ for( unsigned j=q[0].getNumChildren(); j<p->d_qinfo[q].d_vars.size(); j++ ){
+ d_children.push_back( MatchGen( p, q, p->d_qinfo[q].d_vars[j], false, true ) );
+ }
+
+ //choose variable order for variables based on when they are bound
+ std::vector< int > varOrder;
+ varOrder.insert( varOrder.end(), d_children_order.begin(), d_children_order.end() );
+ d_children_order.clear();
+ std::map< int, bool > bound;
+ for( unsigned i=0; i<varOrder.size(); i++ ){
+ int curr = varOrder[i];
+ Trace("qcf-qregister-debug") << "Var Order : " << curr << std::endl;
+ d_children_order.push_back( curr );
+ for( std::map< int, int >::iterator it = d_children[curr].d_qni_var_num.begin();
+ it != d_children[curr].d_qni_var_num.end(); ++it ){
+ if( it->second>=(int)q[0].getNumChildren() && bound.find( it->second )==bound.end() ){
+ bound[ it->second ] = true;
+ int var = base + it->second - (int)q[0].getNumChildren();
+ d_children_order.push_back( var );
+ Trace("qcf-qregister-debug") << "Var Order, bound : " << var << std::endl;
+ }
+ }
+ }
+ for( unsigned j=q[0].getNumChildren(); j<p->d_qinfo[q].d_vars.size(); j++ ){
+ if( bound.find( j )==bound.end() ){
+ int var = base + j - (int)q[0].getNumChildren();
+ d_children_order.push_back( var );
+ Trace("qcf-qregister-debug") << "Var Order, remaining : " << j << std::endl;
+ }
+ }
+ }
+ */
+ }
+ }
+ if( d_type!=typ_invalid ){
+ if( !qni_apps.empty() ){
+ Trace("qcf-qregister-debug") << "Initialize matching..." << std::endl;
+ for( unsigned i=0; i<qni_apps.size(); i++ ){
+ for( unsigned j=0; j<qni_apps[i].getNumChildren(); j++ ){
+ Node nn = qni_apps[i][j];
+ Trace("qcf-qregister-debug") << " " << d_qni_size;
+ if( p->d_qinfo[q].isVar( nn ) ){
+ Trace("qcf-qregister-debug") << " is var #" << p->d_qinfo[q].d_var_num[nn] << std::endl;
+ d_qni_var_num[d_qni_size] = p->d_qinfo[q].d_var_num[nn];
+ }else{
+ Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl;
+ d_qni_gterm[d_qni_size] = nn;
+ }
+ d_qni_size++;
+ }
+ }
+ }
+ }
+ Trace("qcf-qregister-debug") << "Done make match gen " << n << ", type = ";
+ debugPrintType( "qcf-qregister-debug", d_type, true );
+ Trace("qcf-qregister-debug") << std::endl;
+ Assert( d_children.size()==d_children_order.size() );
+}
+
+void QuantConflictFind::MatchGen::reset_round( QuantConflictFind * p ) {
+ for( std::map< int, Node >::iterator it = d_qni_gterm.begin(); it != d_qni_gterm.end(); ++it ){
+ d_qni_gterm_rep[it->first] = p->getRepresentative( it->second );
+ }
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ d_children[i].reset_round( p );
+ }
+}
+
+void QuantConflictFind::MatchGen::reset( QuantConflictFind * p, bool tgt, Node q ) {
+ d_tgt = d_type_not ? !tgt : tgt;
+ Debug("qcf-match") << " Reset for : " << d_n << ", type : ";
+ debugPrintType( "qcf-match", d_type );
+ Debug("qcf-match") << ", tgt = " << d_tgt << ", children = " << d_children.size() << std::endl;
+ d_qn.clear();
+ d_qni.clear();
+ d_qni_bound.clear();
+ d_child_counter = -1;
+
+ //set up processing matches
+ if( d_type==typ_ground ){
+ if( p->evaluate( d_n )==( d_tgt ? 1 : -1 ) ){
+ //store dummy variable
+ d_qn.push_back( NULL );
+ }
+ }else if( d_type==typ_var ){
+ //check if variable is bound by now
+ int vi = p->d_qinfo[q].getVarNum( d_n );
+ Assert( vi!=-1 );
+ int repVar = p->d_qinfo[q].getCurrentRepVar( vi );
+ Assert( d_n.getKind()==APPLY_UF );
+ Node f = d_n.getOperator();
+ std::map< int, Node >::iterator it = p->d_qinfo[q].d_match.find( repVar );
+ if( it!=p->d_qinfo[q].d_match.end() && d_tgt ) {
+ Debug("qcf-match") << " will be matching var within eqc = " << it->second << std::endl;
+ //f-applications in the equivalence class in match[ repVar ]
+ std::map< Node, QcfNodeIndex >::iterator itut = p->d_eqc_uf_terms[ it->second ].find( f );
+ if( itut!=p->d_eqc_uf_terms[ it->second ].end() ){
+ d_qn.push_back( &itut->second );
+ }
+ }else{
+ Debug("qcf-match") << " will be matching var within any eqc." << std::endl;
+ //we are binding rep var
+ d_qni_bound_cons[repVar] = Node::null();
+ //must look at all f-applications
+ std::map< Node, QcfNodeIndex >::iterator itut = p->d_uf_terms.find( f );
+ if( itut!=p->d_uf_terms.end() ){
+ d_qn.push_back( &itut->second );
+ }
+ }
+ }else if( d_type==typ_var_eq ){
+ bool success = false;
+ for( unsigned i=0; i<2; i++ ){
+ int var = p->d_qinfo[q].getVarNum( d_n[i] );
+ if( var!=-1 ){
+ int repVar = p->d_qinfo[q].getCurrentRepVar( var );
+ Node o = d_n[ i==0 ? 1 : 0 ];
+ o = p->d_qinfo[q].getCurrentValue( o );
+ int vo = p->d_qinfo[q].getCurrentRepVar( p->d_qinfo[q].getVarNum( o ) );
+ int addCons = p->d_qinfo[q].addConstraint( p, repVar, o, vo, d_tgt, false );
+ success = addCons!=-1;
+ //if successful and non-redundant, store that we need to cleanup this
+ if( addCons==1 ){
+ d_qni_bound_cons[repVar] = o;
+ d_qni_bound[repVar] = vo;
+ }
+ break;
+ }
+ }
+ if( success ){
+ //store dummy
+ d_qn.push_back( NULL );
+ }
+ }else if( d_type==typ_valid_lit ){
+ //literal
+ EqRegistry * er = p->getEqRegistry( d_tgt, d_n, false );
+ Assert( er );
+ d_qn.push_back( &(er->d_qni) );
+ }else{
+ if( d_children.empty() ){
+ //add dummy
+ d_qn.push_back( NULL );
+ }else{
+ //reset the first child to d_tgt
+ d_child_counter = 0;
+ getChild( d_child_counter )->reset( p, d_tgt, q );
+ }
+ }
+ Debug("qcf-match") << " Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl;
+}
+
+bool QuantConflictFind::MatchGen::getNextMatch( QuantConflictFind * p, Node q ) {
+ Debug("qcf-match") << " Get next match for : " << d_n << ", type = ";
+ debugPrintType( "qcf-match", d_type );
+ Debug("qcf-match") << ", children = " << d_children.size() << std::endl;
+ if( d_children.empty() ){
+ bool success = doMatching( p, q );
+ if( success ){
+ Debug("qcf-match") << " Produce matches for bound variables..." << std::endl;
+ //also need to create match for each variable we bound
+ std::map< int, int >::iterator it = d_qni_bound.begin();
+ bool doReset = true;
+ while( success && it!=d_qni_bound.end() ){
+ std::map< int, MatchGen * >::iterator itm = p->d_qinfo[q].d_var_mg.find( it->second );
+ if( itm!=p->d_qinfo[q].d_var_mg.end() ){
+ Debug("qcf-match-debug") << " process variable " << it->second << ", reset = " << doReset << std::endl;
+ if( doReset ){
+ itm->second->reset( p, true, q );
+ }
+ if( !itm->second->getNextMatch( p, q ) ){
+ do {
+ if( it==d_qni_bound.begin() ){
+ Debug("qcf-match-debug") << " failed." << std::endl;
+ success = false;
+ }else{
+ Debug("qcf-match-debug") << " decrement..." << std::endl;
+ --it;
+ }
+ }while( success && p->d_qinfo[q].d_var_mg.find( it->second )==p->d_qinfo[q].d_var_mg.end() );
+ doReset = false;
+ }else{
+ Debug("qcf-match-debug") << " increment..." << std::endl;
+ ++it;
+ doReset = true;
+ }
+ }else{
+ Debug("qcf-match-debug") << " skip..." << std::endl;
+ ++it;
+ doReset = true;
+ }
+ }
+ }
+ if( !success ){
+ for( std::map< int, Node >::iterator it = d_qni_bound_cons.begin(); it != d_qni_bound_cons.end(); ++it ){
+ if( !it->second.isNull() ){
+ Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl;
+ std::map< int, int >::iterator itb = d_qni_bound.find( it->first );
+ int vn = itb!=d_qni_bound.end() ? itb->second : -1;
+ p->d_qinfo[q].addConstraint( p, it->first, it->second, vn, d_tgt, true );
+ if( vn!=-1 ){
+ d_qni_bound.erase( vn );
+ }
+ }
+ }
+ d_qni_bound_cons.clear();
+ //clean up the match : remove equalities/disequalities
+ for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
+ Debug("qcf-match") << " Clean up bound var " << it->second << std::endl;
+ Assert( it->second<p->d_qinfo[q].getNumVars() );
+ p->d_qinfo[q].d_match.erase( it->second );
+ }
+ d_qni_bound.clear();
+ }
+ Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl;
+ return success;
+ }else{
+ if( d_child_counter!=-1 ){
+ bool success = false;
+ while( !success && d_child_counter>=0 ){
+ //transition system based on d_child_counter
+ if( d_type==typ_top || d_n.getKind()==OR || d_n.getKind()==AND ){
+ if( (d_n.getKind()==AND)==d_tgt ){
+ //all children must match simultaneously
+ if( getChild( d_child_counter )->getNextMatch( p, q ) ){
+ if( d_child_counter<(int)(getNumChildren()-1) ){
+ d_child_counter++;
+ Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", all match " << d_children_order.size() << " " << d_children_order[d_child_counter] << std::endl;
+ getChild( d_child_counter )->reset( p, d_tgt, q );
+ }else{
+ success = true;
+ }
+ }else{
+ d_child_counter--;
+ }
+ }else{
+ //one child must match
+ if( !getChild( d_child_counter )->getNextMatch( p, q ) ){
+ if( d_child_counter<(int)(getNumChildren()-1) ){
+ d_child_counter++;
+ Debug("qcf-match-debug") << " Reset child " << d_child_counter << " of " << d_n << ", one match" << std::endl;
+ getChild( d_child_counter )->reset( p, d_tgt, q );
+ }else{
+ d_child_counter = -1;
+ }
+ }else{
+ success = true;
+ }
+ }
+ }else if( d_n.getKind()==IFF ){
+ //construct match based on both children
+ if( d_child_counter%2==0 ){
+ if( getChild( 0 )->getNextMatch( p, q ) ){
+ d_child_counter++;
+ getChild( 1 )->reset( p, d_child_counter==1, q );
+ }else{
+ if( d_child_counter==0 ){
+ d_child_counter = 2;
+ getChild( 0 )->reset( p, !d_tgt, q );
+ }else{
+ d_child_counter = -1;
+ }
+ }
+ }
+ if( d_child_counter%2==1 ){
+ if( getChild( 1 )->getNextMatch( p, q ) ){
+ success = true;
+ }else{
+ d_child_counter--;
+ }
+ }
+ }else if( d_n.getKind()==ITE ){
+ if( d_child_counter%2==0 ){
+ int index1 = d_child_counter==4 ? 1 : 0;
+ if( getChild( index1 )->getNextMatch( p, q ) ){
+ d_child_counter++;
+ getChild( d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==0) ? 1 : 2) )->reset( p, d_tgt, q );
+ }else{
+ if( d_child_counter==4 ){
+ d_child_counter = -1;
+ }else{
+ d_child_counter +=2;
+ getChild( d_child_counter==4 ? 1 : 0 )->reset( p, d_child_counter==2 ? !d_tgt : d_tgt, q );
+ }
+ }
+ }
+ if( d_child_counter%2==1 ){
+ int index2 = d_child_counter==5 ? 2 : (d_tgt==(d_child_counter==0) ? 1 : 2);
+ if( getChild( index2 )->getNextMatch( p, q ) ){
+ success = true;
+ }else{
+ d_child_counter--;
+ }
+ }
+ }
+ }
+ Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl;
+ return success;
+ }
+ }
+ Debug("qcf-match") << " ...already finished for " << d_n << std::endl;
+ return false;
+}
+
+bool QuantConflictFind::MatchGen::doMatching( QuantConflictFind * p, Node q ) {
+ if( !d_qn.empty() ){
+ if( d_qn[0]==NULL ){
+ d_qn.clear();
+ return true;
+ }else{
+ Assert( d_qni_size>0 );
+ bool invalidMatch;
+ do {
+ invalidMatch = false;
+ Debug("qcf-match-debug") << " Do matching " << d_qn.size() << " " << d_qni.size() << std::endl;
+ if( d_qn.size()==d_qni.size()+1 ) {
+ int index = (int)d_qni.size();
+ //initialize
+ Node val;
+ std::map< int, int >::iterator itv = d_qni_var_num.find( index );
+ if( itv!=d_qni_var_num.end() ){
+ //get the representative variable this variable is equal to
+ int repVar = p->d_qinfo[q].getCurrentRepVar( itv->second );
+ Debug("qcf-match-debug") << " Match " << index << " is a variable " << itv->second << ", which is repVar " << repVar << std::endl;
+ //get the value the rep variable
+ std::map< int, Node >::iterator itm = p->d_qinfo[q].d_match.find( repVar );
+ if( itm!=p->d_qinfo[q].d_match.end() ){
+ val = itm->second;
+ Assert( !val.isNull() );
+ Debug("qcf-match-debug") << " Variable is already bound to " << val << std::endl;
+ }else{
+ //binding a variable
+ d_qni_bound[index] = repVar;
+ std::map< Node, QcfNodeIndex >::iterator it = d_qn[index]->d_children.begin();
+ if( it != d_qn[index]->d_children.end() ) {
+ d_qni.push_back( it );
+ //set the match
+ if( p->d_qinfo[q].setMatch( p, d_qni_bound[index], it->first ) ){
+ Debug("qcf-match-debug") << " Binding variable" << std::endl;
+ if( d_qn.size()<d_qni_size ){
+ d_qn.push_back( &it->second );
+ }
+ }else{
+ Debug("qcf-match") << " Binding variable, currently fail." << std::endl;
+ invalidMatch = true;
+ }
+ }else{
+ Debug("qcf-match-debug") << " Binding variable, fail, no more variables to bind" << std::endl;
+ d_qn.pop_back();
+ }
+ }
+ }else{
+ Debug("qcf-match-debug") << " Match " << index << " is ground term" << std::endl;
+ Assert( d_qni_gterm.find( index )!=d_qni_gterm.end() );
+ Assert( d_qni_gterm_rep.find( index )!=d_qni_gterm_rep.end() );
+ val = d_qni_gterm_rep[index];
+ Assert( !val.isNull() );
+ }
+ if( !val.isNull() ){
+ //constrained by val
+ std::map< Node, QcfNodeIndex >::iterator it = d_qn[index]->d_children.find( val );
+ if( it!=d_qn[index]->d_children.end() ){
+ Debug("qcf-match-debug") << " Match" << std::endl;
+ d_qni.push_back( it );
+ if( d_qn.size()<d_qni_size ){
+ d_qn.push_back( &it->second );
+ }
+ }else{
+ Debug("qcf-match-debug") << " Failed to match" << std::endl;
+ d_qn.pop_back();
+ }
+ }
+ }else{
+ Assert( d_qn.size()==d_qni.size() );
+ int index = d_qni.size()-1;
+ //increment if binding this variable
+ bool success = false;
+ std::map< int, int >::iterator itb = d_qni_bound.find( index );
+ if( itb!=d_qni_bound.end() ){
+ d_qni[index]++;
+ if( d_qni[index]!=d_qn[index]->d_children.end() ){
+ success = true;
+ if( p->d_qinfo[q].setMatch( p, itb->second, d_qni[index]->first ) ){
+ Debug("qcf-match-debug") << " Bind next variable" << std::endl;
+ if( d_qn.size()<d_qni_size ){
+ d_qn.push_back( &d_qni[index]->second );
+ }
+ }else{
+ Debug("qcf-match-debug") << " Bind next variable, currently fail" << std::endl;
+ invalidMatch = true;
+ }
+ }else{
+ Debug("qcf-match-debug") << " Bind next variable, no more variables to bind" << std::endl;
+ }
+ }
+ //if not incrementing, move to next
+ if( !success ){
+ d_qn.pop_back();
+ d_qni.pop_back();
+ }
+ }
+ if( d_type==typ_var ){
+ if( !invalidMatch && d_qni.size()==d_qni_size ){
+ //if in the act of binding the variable by this term, bind the variable
+ std::map< int, Node >::iterator itb = d_qni_bound_cons.begin();
+ if( itb!=d_qni_bound_cons.end() ){
+ QcfNodeIndex * v_qni = &d_qni[d_qni.size()-1]->second;
+ Assert( v_qni->d_children.begin()!=v_qni->d_children.end() );
+ Node vb = v_qni->d_children.begin()->first;
+ Assert( !vb.isNull() );
+ vb = p->getRepresentative( vb );
+ Debug("qcf-match-debug") << " For var, require binding " << itb->first << " to " << vb << ", d_tgt = " << d_tgt << std::endl;
+ if( !itb->second.isNull() ){
+ p->d_qinfo[q].addConstraint( p, itb->first, itb->second, -1, d_tgt, true );
+ }
+ int addCons = p->d_qinfo[q].addConstraint( p, itb->first, vb, -1, d_tgt, false );
+ if( addCons==-1 ){
+ Debug("qcf-match-debug") << " Failed set for var." << std::endl;
+ invalidMatch = true;
+ d_qni_bound_cons[itb->first] = Node::null();
+ }else{
+ Debug("qcf-match-debug") << " Succeeded set for var." << std::endl;
+ if( addCons==1 ){
+ d_qni_bound_cons[itb->first] = vb;
+ }
+ }
+ }
+ }
+ }
+ }while( ( !d_qn.empty() && d_qni.size()!=d_qni_size ) || invalidMatch );
+ }
+ }
+ return !d_qn.empty();
+}
+
+void QuantConflictFind::MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) {
+ if( isTrace ){
+ switch( typ ){
+ case typ_invalid: Trace(c) << "invalid";break;
+ case typ_ground: Trace(c) << "ground";break;
+ case typ_valid_lit: Trace(c) << "valid_lit";break;
+ case typ_valid: Trace(c) << "valid";break;
+ case typ_var: Trace(c) << "var";break;
+ case typ_var_eq: Trace(c) << "var_eq";break;
+ case typ_top: Trace(c) << "top";break;
+ }
+ }else{
+ switch( typ ){
+ case typ_invalid: Debug(c) << "invalid";break;
+ case typ_ground: Debug(c) << "ground";break;
+ case typ_valid_lit: Debug(c) << "valid_lit";break;
+ case typ_valid: Debug(c) << "valid";break;
+ case typ_var: Debug(c) << "var";break;
+ case typ_var_eq: Debug(c) << "var_eq";break;
+ case typ_top: Debug(c) << "top";break;
+ }
+ }
+}
+
+void QuantConflictFind::MatchGen::setInvalid() {
+ d_type = typ_invalid;
+ d_children.clear();
+}
+
+
+//-------------------------------------------------- debugging
+
+
+void QuantConflictFind::debugPrint( const char * c ) {
+ //print the equivalance classes
+ Trace(c) << "----------EQ classes" << std::endl;
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
+ while( !eqcs_i.isFinished() ){
+ Node n = (*eqcs_i);
+ if( !n.getType().isInteger() ){
+ Trace(c) << " - " << n << " : {";
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( n, getEqualityEngine() );
+ bool pr = false;
+ while( !eqc_i.isFinished() ){
+ Node nn = (*eqc_i);
+ if( nn.getKind()!=EQUAL && nn!=n ){
+ Trace(c) << (pr ? "," : "" ) << " " << nn;
+ pr = true;
+ }
+ ++eqc_i;
+ }
+ Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
+ EqcInfo * eqcn = getEqcInfo( n, false );
+ if( eqcn ){
+ Trace(c) << " DEQ : {";
+ pr = false;
+ for( NodeBoolMap::iterator it = eqcn->d_diseq.begin(); it != eqcn->d_diseq.end(); ++it ){
+ if( (*it).second ){
+ Trace(c) << (pr ? "," : "" ) << " " << (*it).first;
+ pr = true;
+ }
+ }
+ Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
+ }
+ }
+ ++eqcs_i;
+ }
+ std::map< Node, std::map< Node, bool > > printed;
+ //print the equality registries
+ for( unsigned i=0; i<2; i++ ){
+ printed.clear();
+ Trace(c) << "----------EQR, polarity = " << (i==0) << std::endl;
+ for( std::map< Node, std::map< Node, EqRegistry * > >::iterator it = d_eqr[i].begin(); it != d_eqr[i].end(); ++it ){
+ bool prHead = false;
+ for( std::map< Node, EqRegistry * >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ bool print;
+ if( it->first.getKind()==APPLY_UF && it2->first.getKind()==APPLY_UF &&
+ it->first.getOperator()!=it2->first.getOperator() ){
+ print = isLessThan( it->first, it2->first );
+ }else{
+ print = printed[it->first].find( it2->first )==printed[it->first].end();
+ }
+ if( print ){
+ printed[it->first][it2->first] = true;
+ printed[it2->first][it->first] = true;
+ if( !prHead ){
+ Trace(c) << "- " << it->first << std::endl;
+ prHead = true;
+ }
+ Trace(c) << " " << it2->first << ", terms : " << std::endl;
+
+ /*
+ Trace(c) << " " << it2->first << " : {";
+ bool pr = false;
+ for( NodeBoolMap::iterator it3 = it2->second->d_t_eqc.begin(); it3 != it2->second->d_t_eqc.end(); ++it3 ){
+ if( (*it3).second ){
+ Trace(c) << (pr ? "," : "" ) << " " << (*it3).first;
+ pr = true;
+ }
+ }
+ Trace(c) << (pr ? " " : "" ) << "}" << std::endl;
+ */
+ //print qni structure
+ it2->second->debugPrint( c, 3 );
+ }
+ }
+ }
+ }
+}
+
+void QuantConflictFind::debugPrintQuant( const char * c, Node q ) {
+ Trace(c) << "Q" << d_quant_id[q];
+}
+
+void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum ) {
+ if( n.getNumChildren()==0 ){
+ Trace(c) << n;
+ }else if( doVarNum && d_qinfo[q].d_var_num.find( n )!=d_qinfo[q].d_var_num.end() ){
+ Trace(c) << "?x" << d_qinfo[q].d_var_num[n];
+ }else{
+ Trace(c) << "(";
+ if( n.getKind()==APPLY_UF ){
+ Trace(c) << n.getOperator();
+ }else{
+ Trace(c) << n.getKind();
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ Trace(c) << " ";
+ debugPrintQuantBody( c, q, n[i] );
+ }
+ Trace(c) << ")";
+ }
+}
+
+QuantConflictFind::Statistics::Statistics():
+ d_inst_rounds("QuantConflictFind::Inst_Rounds", 0),
+ d_conflict_inst("QuantConflictFind::Instantiations_Conflict_Find", 0 )
+{
+ StatisticsRegistry::registerStat(&d_inst_rounds);
+ StatisticsRegistry::registerStat(&d_conflict_inst);
+}
+
+QuantConflictFind::Statistics::~Statistics(){
+ StatisticsRegistry::unregisterStat(&d_inst_rounds);
+ StatisticsRegistry::unregisterStat(&d_conflict_inst);
+}
+
+} \ No newline at end of file
diff --git a/src/theory/quantifiers/quant_conflict_find.h b/src/theory/quantifiers/quant_conflict_find.h
new file mode 100755
index 000000000..0b503d49b
--- /dev/null
+++ b/src/theory/quantifiers/quant_conflict_find.h
@@ -0,0 +1,258 @@
+/********************* */
+/*! \file quant_conflict_find.h
+ ** \verbatim
+ ** Original author: Andrew Reynolds
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2013 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief quantifiers conflict find class
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef QUANT_CONFLICT_FIND
+#define QUANT_CONFLICT_FIND
+
+#include "context/cdhashmap.h"
+#include "context/cdchunk_list.h"
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class QcfNode;
+
+class QuantConflictFind;
+
+class QcfNodeIndex {
+public:
+ std::map< Node, QcfNodeIndex > d_children;
+ void clear() { d_children.clear(); }
+ //Node existsTerm( QuantConflictFind * qcf, Node n, int index = 0 );
+ //Node addTerm( QuantConflictFind * qcf, Node n, int index = 0 );
+ //bool addTermEq( QuantConflictFind * qcf, Node n1, Node n2, int index = 0 );
+ void debugPrint( const char * c, int t );
+ //optimized versions
+ Node existsTerm( Node n, std::vector< Node >& reps, int index = 0 );
+ Node addTerm( Node n, std::vector< Node >& reps, int index = 0 );
+ bool addTermEq( Node n1, Node n2, std::vector< Node >& reps1, std::vector< Node >& reps2, int index = 0 );
+};
+
+class EqRegistry {
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+public:
+ EqRegistry( context::Context* c );
+ //active
+ context::CDO< bool > d_active;
+ //NodeIndex describing pairs that meet the criteria of the EqRegistry
+ QcfNodeIndex d_qni;
+
+ //qcf nodes that this helps to 1:satisfy -1:falsify 0:both a quantifier conflict node
+ //std::map< QcfNode *, int > d_qcf;
+ //has eqc
+ //bool hasEqc( Node n ) { return d_t_eqc.find( n )!=d_t_eqc.end() && d_t_eqc[n]; }
+ //void setEqc( Node n, bool val = true ) { d_t_eqc[n] = val; }
+ void clear() { d_qni.clear(); }
+ void debugPrint( const char * c, int t );
+};
+
+/*
+class QcfNode {
+public:
+ QcfNode( context::Context* c );
+ QcfNode * d_parent;
+ std::map< int, QcfNode * > d_child;
+ Node d_node;
+ EqRegistry * d_reg[2];
+};
+*/
+
+class QuantConflictFind : public QuantifiersModule
+{
+ friend class QcfNodeIndex;
+ typedef context::CDChunkList<Node> NodeList;
+ typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
+private:
+ context::Context* d_c;
+ context::CDO< bool > d_conflict;
+ bool d_performCheck;
+ //void registerAssertion( Node n );
+ void registerNode( Node q, Node n, bool hasPol, bool pol );
+ void flatten( Node q, Node n );
+private:
+ std::map< TypeNode, Node > d_fv;
+ Node getFv( TypeNode tn );
+ std::map< Node, Node > d_op_node;
+ int getFunctionId( Node f );
+ bool isLessThan( Node a, Node b );
+ Node getFunction( Node n, bool isQuant = false );
+ int d_fid_count;
+ std::map< Node, int > d_fid;
+ Node mkEqNode( Node a, Node b );
+private: //for ground terms
+ Node d_true;
+ Node d_false;
+ std::map< Node, std::map< Node, EqRegistry * > > d_eqr[2];
+ EqRegistry * getEqRegistry( bool polarity, Node lit, bool doCreate = true );
+ void getEqRegistryApps( Node lit, std::vector< Node >& terms );
+ int evaluate( Node n );
+public: //for quantifiers
+ //match generator
+ class MatchGen {
+ private:
+ //current children information
+ int d_child_counter;
+ //children of this object
+ std::vector< int > d_children_order;
+ unsigned getNumChildren() { return d_children.size(); }
+ MatchGen * getChild( int i ) { return &d_children[d_children_order[i]]; }
+ //current matching information
+ std::vector< QcfNodeIndex * > d_qn;
+ std::vector< std::map< Node, QcfNodeIndex >::iterator > d_qni;
+ bool doMatching( QuantConflictFind * p, Node q );
+ //for matching : each index is either a variable or a ground term
+ unsigned d_qni_size;
+ std::map< int, int > d_qni_var_num;
+ std::map< int, Node > d_qni_gterm;
+ std::map< int, Node > d_qni_gterm_rep;
+ std::map< int, int > d_qni_bound;
+ std::map< int, Node > d_qni_bound_cons;
+ public:
+ //type of the match generator
+ enum {
+ typ_invalid,
+ typ_ground,
+ typ_var_eq,
+ typ_valid_lit,
+ typ_valid,
+ typ_var,
+ typ_top,
+ };
+ void debugPrintType( const char * c, short typ, bool isTrace = false );
+ public:
+ MatchGen() : d_type( typ_invalid ){}
+ MatchGen( QuantConflictFind * p, Node q, Node n, bool isTop = false, bool isVar = false );
+ bool d_tgt;
+ Node d_n;
+ std::vector< MatchGen > d_children;
+ short d_type;
+ bool d_type_not;
+ void reset_round( QuantConflictFind * p );
+ void reset( QuantConflictFind * p, bool tgt, Node q );
+ bool getNextMatch( QuantConflictFind * p, Node q );
+ bool isValid() { return d_type!=typ_invalid; }
+ void setInvalid();
+ };
+private:
+ //currently asserted quantifiers
+ NodeList d_qassert;
+ //info for quantifiers
+ class QuantInfo {
+ public:
+ QuantInfo() : d_mg( NULL ) {}
+ std::vector< Node > d_vars;
+ std::map< Node, int > d_var_num;
+ std::map< EqRegistry *, bool > d_rel_eqr;
+ std::map< int, std::vector< Node > > d_var_constraint[2];
+ int getVarNum( Node v ) { return d_var_num.find( v )!=d_var_num.end() ? d_var_num[v] : -1; }
+ bool isVar( Node v ) { return d_var_num.find( v )!=d_var_num.end(); }
+ int getNumVars() { return (int)d_vars.size(); }
+ Node getVar( int i ) { return d_vars[i]; }
+ MatchGen * d_mg;
+ std::map< int, MatchGen * > d_var_mg;
+ void reset_round( QuantConflictFind * p );
+ public:
+ //current constraints
+ std::map< int, Node > d_match;
+ std::map< int, std::map< Node, int > > d_curr_var_deq;
+ int getCurrentRepVar( int v );
+ Node getCurrentValue( Node n );
+ bool getCurrentCanBeEqual( QuantConflictFind * p, int v, Node n );
+ int addConstraint( QuantConflictFind * p, int v, Node n, bool polarity );
+ int addConstraint( QuantConflictFind * p, int v, Node n, int vn, bool polarity, bool doRemove );
+ bool setMatch( QuantConflictFind * p, int v, Node n );
+ bool isMatchSpurious( QuantConflictFind * p );
+ bool completeMatch( QuantConflictFind * p, Node q, std::vector< int >& assigned );
+ void debugPrintMatch( const char * c );
+ };
+ std::map< Node, QuantInfo > d_qinfo;
+private: //for equivalence classes
+ eq::EqualityEngine * getEqualityEngine();
+ bool areDisequal( Node n1, Node n2 );
+ bool areEqual( Node n1, Node n2 );
+ Node getRepresentative( Node n );
+ Node getTerm( Node n );
+
+ class EqcInfo {
+ public:
+ EqcInfo( context::Context* c ) : d_diseq( c ) {}
+ NodeBoolMap d_diseq;
+ bool isDisequal( Node n ) { return d_diseq.find( n )!=d_diseq.end() && d_diseq[n]; }
+ void setDisequal( Node n, bool val = true ) { d_diseq[n] = val; }
+ //NodeBoolMap& getRelEqr( int index ) { return index==0 ? d_rel_eqr_e : d_rel_eqr_d; }
+ };
+ std::map< Node, EqcInfo * > d_eqc_info;
+ EqcInfo * getEqcInfo( Node n, bool doCreate = true );
+ // operator -> index(terms)
+ std::map< Node, QcfNodeIndex > d_uf_terms;
+ // eqc x operator -> index(terms)
+ std::map< Node, std::map< Node, QcfNodeIndex > > d_eqc_uf_terms;
+ // type -> list(eqc)
+ std::map< TypeNode, std::vector< Node > > d_eqcs;
+ //mapping from UF terms to representatives of their arguments
+ std::map< Node, std::vector< Node > > d_arg_reps;
+ //compute arg reps
+ void computeArgReps( Node n );
+public:
+ QuantConflictFind( QuantifiersEngine * qe, context::Context* c );
+
+ /** register assertions */
+ //void registerAssertions( std::vector< Node >& assertions );
+ /** register quantifier */
+ void registerQuantifier( Node q );
+
+public:
+ /** assert quantifier */
+ void assertNode( Node q );
+ /** new node */
+ void newEqClass( Node n );
+ /** merge */
+ void merge( Node a, Node b );
+ /** assert disequal */
+ void assertDisequal( Node a, Node b );
+ /** check */
+ void check( Theory::Effort level );
+ /** needs check */
+ bool needsCheck( Theory::Effort level );
+private:
+ void computeRelevantEqr();
+private:
+ void debugPrint( const char * c );
+ //for debugging
+ std::vector< Node > d_quants;
+ std::map< Node, int > d_quant_id;
+ void debugPrintQuant( const char * c, Node q );
+ void debugPrintQuantBody( const char * c, Node q, Node n, bool doVarNum = true );
+public:
+ /** statistics class */
+ class Statistics {
+ public:
+ IntStat d_inst_rounds;
+ IntStat d_conflict_inst;
+ Statistics();
+ ~Statistics();
+ };
+ Statistics d_statistics;
+};
+
+}
+}
+}
+
+#endif
diff --git a/src/theory/quantifiers/quant_util.cpp b/src/theory/quantifiers/quant_util.cpp
index 59995a510..31a95fb8a 100644
--- a/src/theory/quantifiers/quant_util.cpp
+++ b/src/theory/quantifiers/quant_util.cpp
@@ -239,3 +239,17 @@ void QuantPhaseReq::computePhaseReqs( Node n, bool polarity, std::map< Node, int
}
}
}
+
+void QuantPhaseReq::getPolarity( Node n, int child, bool hasPol, bool pol, bool& newHasPol, bool& newPol ) {
+ newHasPol = hasPol;
+ newPol = pol;
+ if( n.getKind()==NOT ){
+ newPol = !pol;
+ }else if( n.getKind()==IFF ){
+ newHasPol = false;
+ }else if( n.getKind()==ITE ){
+ if( child==0 ){
+ newHasPol = false;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/theory/quantifiers/quant_util.h b/src/theory/quantifiers/quant_util.h
index 86c7bc3a0..711144e7e 100644
--- a/src/theory/quantifiers/quant_util.h
+++ b/src/theory/quantifiers/quant_util.h
@@ -82,6 +82,8 @@ public:
std::map< Node, bool > d_phase_reqs;
std::map< Node, bool > d_phase_reqs_equality;
std::map< Node, Node > d_phase_reqs_equality_term;
+
+ static void getPolarity( Node n, int child, bool hasPol, bool pol, bool& newHasPol, bool& newPol );
};
diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp
index ecc3c02bc..3a6785d00 100644
--- a/src/theory/quantifiers/quantifiers_rewriter.cpp
+++ b/src/theory/quantifiers/quantifiers_rewriter.cpp
@@ -229,6 +229,32 @@ RewriteResponse QuantifiersRewriter::postRewrite(TNode in) {
return RewriteResponse(REWRITE_DONE, in);
}
+Node QuantifiersRewriter::computeElimSymbols( Node body ) {
+ if( isLiteral( body ) ){
+ return body;
+ }else{
+ bool childrenChanged = false;
+ std::vector< Node > children;
+ for( unsigned i=0; i<body.getNumChildren(); i++ ){
+ Node c = computeElimSymbols( body[i] );
+ if( i==0 && ( body.getKind()==IMPLIES || body.getKind()==XOR ) ){
+ c = c.negate();
+ }
+ children.push_back( c );
+ childrenChanged = childrenChanged || c!=body[i];
+ }
+ if( body.getKind()==IMPLIES ){
+ return NodeManager::currentNM()->mkNode( OR, children );
+ }else if( body.getKind()==XOR ){
+ return NodeManager::currentNM()->mkNode( IFF, children );
+ }else if( childrenChanged ){
+ return NodeManager::currentNM()->mkNode( body.getKind(), children );
+ }else{
+ return body;
+ }
+ }
+}
+
Node QuantifiersRewriter::computeNNF( Node body ){
if( body.getKind()==NOT ){
if( body[0].getKind()==NOT ){
@@ -238,10 +264,9 @@ Node QuantifiersRewriter::computeNNF( Node body ){
}else{
std::vector< Node > children;
Kind k = body[0].getKind();
- if( body[0].getKind()==OR || body[0].getKind()==IMPLIES || body[0].getKind()==AND ){
+ if( body[0].getKind()==OR || body[0].getKind()==AND ){
for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
- Node nn = body[0].getKind()==IMPLIES && i==0 ? body[0][i] : body[0][i].notNode();
- children.push_back( computeNNF( nn ) );
+ children.push_back( computeNNF( body[0][i].notNode() ) );
}
k = body[0].getKind()==AND ? OR : AND;
}else if( body[0].getKind()==XOR || body[0].getKind()==IFF ){
@@ -376,8 +401,7 @@ Node QuantifiersRewriter::computeClause( Node n ){
}
}else{
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- Node nc = ( ( i==0 && n.getKind()==IMPLIES ) ? n[i].notNode() : n[i] );
- Node nn = computeClause( nc );
+ Node nn = computeClause( n[i] );
addNodeToOrBuilder( nn, t );
}
}
@@ -391,10 +415,10 @@ Node QuantifiersRewriter::computeCNF( Node n, std::vector< Node >& args, NodeBui
}else if( !forcePred && isClause( n ) ){
return computeClause( n );
}else{
- Kind k = ( n.getKind()==IMPLIES ? OR : ( n.getKind()==XOR ? IFF : n.getKind() ) );
+ Kind k = n.getKind();
NodeBuilder<> t(k);
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- Node nc = ( i==0 && ( n.getKind()==IMPLIES || n.getKind()==XOR ) ) ? n[i].notNode() : n[i];
+ Node nc = n[i];
Node ncnf = computeCNF( nc, args, defs, k!=OR );
if( k==OR ){
addNodeToOrBuilder( ncnf, t );
@@ -523,7 +547,7 @@ Node QuantifiersRewriter::computePrenex( Node body, std::vector< Node >& args, b
bool childrenChanged = false;
std::vector< Node > newChildren;
for( int i=0; i<(int)body.getNumChildren(); i++ ){
- bool newPol = ( body.getKind()==NOT || ( body.getKind()==IMPLIES && i==0 ) ) ? !pol : pol;
+ bool newPol = body.getKind()==NOT ? !pol : pol;
Node n = computePrenex( body[i], args, newPol );
newChildren.push_back( n );
if( n!=body[i] ){
@@ -661,7 +685,9 @@ Node QuantifiersRewriter::computeOperation( Node f, int computeOption ){
if( f.getNumChildren()==3 ){
ipl = f[2];
}
- if( computeOption==COMPUTE_MINISCOPING ){
+ if( computeOption==COMPUTE_ELIM_SYMBOLS ){
+ n = computeElimSymbols( n );
+ }else if( computeOption==COMPUTE_MINISCOPING ){
//return directly
return computeMiniscoping( args, n, ipl, f.hasAttribute(NestedQuantAttribute()) );
}else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){
@@ -746,11 +772,11 @@ Node QuantifiersRewriter::computeMiniscoping( std::vector< Node >& args, Node bo
}
return computeMiniscoping( args, t.constructNode(), ipl );
}
- }else if( body[0].getKind()==OR || body[0].getKind()==IMPLIES ){
+ }else if( body[0].getKind()==OR ){
if( doMiniscopingAnd() ){
NodeBuilder<> t(kind::AND);
for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
- Node trm = ( body[0].getKind()==IMPLIES && i==0 ) ? body[0][i] : ( body[0][i].getKind()==NOT ? body[0][i][0] : body[0][i].notNode() );
+ Node trm = body[0][i].negate();
t << computeMiniscoping( args, trm, ipl );
}
return t.constructNode();
@@ -766,13 +792,13 @@ Node QuantifiersRewriter::computeMiniscoping( std::vector< Node >& args, Node bo
Node retVal = t;
return retVal;
}
- }else if( body.getKind()==OR || body.getKind()==IMPLIES ){
+ }else if( body.getKind()==OR ){
if( doMiniscopingNoFreeVar() ){
Node newBody = body;
NodeBuilder<> body_split(kind::OR);
NodeBuilder<> tb(kind::OR);
for( int i=0; i<(int)body.getNumChildren(); i++ ){
- Node trm = ( body.getKind()==IMPLIES && i==0 ) ? ( body[i].getKind()==NOT ? body[i][0] : body[i].notNode() ) : body[i];
+ Node trm = body[i];
if( hasArg( args, body[i] ) ){
tb << trm;
}else{
@@ -916,7 +942,9 @@ bool QuantifiersRewriter::doMiniscopingAnd(){
}
bool QuantifiersRewriter::doOperation( Node f, bool isNested, int computeOption ){
- if( computeOption==COMPUTE_MINISCOPING ){
+ if( computeOption==COMPUTE_ELIM_SYMBOLS ){
+ return true;
+ }else if( computeOption==COMPUTE_MINISCOPING ){
return true;
}else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){
return options::aggressiveMiniscopeQuant();
diff --git a/src/theory/quantifiers/quantifiers_rewriter.h b/src/theory/quantifiers/quantifiers_rewriter.h
index 40234904f..e97d84701 100644
--- a/src/theory/quantifiers/quantifiers_rewriter.h
+++ b/src/theory/quantifiers/quantifiers_rewriter.h
@@ -44,6 +44,7 @@ private:
static void setNestedQuantifiers2( Node n, Node q, std::vector< Node >& processed );
static Node computeClause( Node n );
private:
+ static Node computeElimSymbols( Node body );
static Node computeMiniscoping( std::vector< Node >& args, Node body, Node ipl, bool isNested = false );
static Node computeAggressiveMiniscoping( std::vector< Node >& args, Node body, bool isNested = false );
static Node computeNNF( Node body );
@@ -54,7 +55,8 @@ private:
static Node computeSplit( Node f, Node body, std::vector< Node >& args );
private:
enum{
- COMPUTE_MINISCOPING = 0,
+ COMPUTE_ELIM_SYMBOLS = 0,
+ COMPUTE_MINISCOPING,
COMPUTE_AGGRESSIVE_MINISCOPING,
COMPUTE_NNF,
COMPUTE_SIMPLE_ITE_LIFT,
diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp
index e18a4e0dc..6b1368be1 100644
--- a/src/theory/quantifiers/term_database.cpp
+++ b/src/theory/quantifiers/term_database.cpp
@@ -146,6 +146,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
if( !d_func_map_trie[ it->first ].addTerm( d_quantEngine, n ) ){
NoMatchAttribute nma;
n.setAttribute(nma,true);
+ Debug("term-db-cong") << n << " is redundant." << std::endl;
congruentCount++;
}else{
nonCongruentCount++;
@@ -173,6 +174,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
if( !d_pred_map_trie[i][op].addTerm( d_quantEngine, en ) ){
NoMatchAttribute nma;
en.setAttribute(nma,true);
+ Debug("term-db-cong") << en << " is redundant." << std::endl;
congruentCount++;
}else{
nonCongruentCount++;
@@ -222,10 +224,14 @@ Node TermDb::getModelBasisOpTerm( Node op ){
TypeNode t = op.getType();
std::vector< Node > children;
children.push_back( op );
- for( size_t i=0; i<t.getNumChildren()-1; i++ ){
+ for( int i=0; i<(int)(t.getNumChildren()-1); i++ ){
children.push_back( getModelBasisTerm( t[i] ) );
}
- d_model_basis_op_term[op] = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ if( children.size()==1 ){
+ d_model_basis_op_term[op] = op;
+ }else{
+ d_model_basis_op_term[op] = NodeManager::currentNM()->mkNode( APPLY_UF, children );
+ }
}
return d_model_basis_op_term[op];
}
diff --git a/src/theory/quantifiers/trigger.cpp b/src/theory/quantifiers/trigger.cpp
index 39063942d..b13e76afb 100644
--- a/src/theory/quantifiers/trigger.cpp
+++ b/src/theory/quantifiers/trigger.cpp
@@ -342,7 +342,7 @@ bool Trigger::isSimpleTrigger( Node n ){
bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt, bool pol, bool hasPol ){
if( patMap.find( n )==patMap.end() ){
patMap[ n ] = false;
- bool newHasPol = (n.getKind()==IFF || n.getKind()==XOR) ? false : hasPol;
+ bool newHasPol = n.getKind()==IFF ? false : hasPol;
bool newPol = n.getKind()==NOT ? !pol : pol;
if( tstrt==TS_MIN_TRIGGER ){
if( n.getKind()==FORALL ){
@@ -350,9 +350,8 @@ bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map<
}else{
bool retVal = false;
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- bool newPol2 = (n.getKind()==IMPLIES && i==0) ? !newPol : newPol;
bool newHasPol2 = (n.getKind()==ITE && i==0) ? false : newHasPol;
- if( collectPatTerms2( qe, f, n[i], patMap, tstrt, newPol2, newHasPol2 ) ){
+ if( collectPatTerms2( qe, f, n[i], patMap, tstrt, newPol, newHasPol2 ) ){
retVal = true;
}
}
@@ -381,9 +380,8 @@ bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map<
}
if( n.getKind()!=FORALL ){
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- bool newPol2 = (n.getKind()==IMPLIES && i==0) ? !newPol : newPol;
bool newHasPol2 = (n.getKind()==ITE && i==0) ? false : newHasPol;
- if( collectPatTerms2( qe, f, n[i], patMap, tstrt, newPol2, newHasPol2 ) ){
+ if( collectPatTerms2( qe, f, n[i], patMap, tstrt, newPol, newHasPol2 ) ){
retVal = true;
}
}
diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp
index e9a69bd30..2ddc83a4b 100644
--- a/src/theory/quantifiers_engine.cpp
+++ b/src/theory/quantifiers_engine.cpp
@@ -29,6 +29,7 @@
#include "theory/rewriterules/rr_trigger.h"
#include "theory/quantifiers/bounded_integers.h"
#include "theory/quantifiers/rewrite_engine.h"
+#include "theory/quantifiers/quant_conflict_find.h"
#include "theory/uf/options.h"
using namespace std;
@@ -49,14 +50,24 @@ d_lemmas_produced_c(u){
d_eem = new EfficientEMatcher( this );
d_hasAddedLemma = false;
+ Trace("quant-engine-debug") << "Initialize model, mbqi : " << options::mbqiMode() << std::endl;
//the model object
- if( options::fmfFullModelCheck() || options::fmfBoundInt() ){
+ if( options::mbqiMode()==quantifiers::MBQI_FMC ||
+ options::mbqiMode()==quantifiers::MBQI_FMC_INTERVAL || options::fmfBoundInt() ){
d_model = new quantifiers::fmcheck::FirstOrderModelFmc( this, c, "FirstOrderModelFmc" );
+ }else if( options::mbqiMode()==quantifiers::MBQI_INTERVAL ){
+ d_model = new quantifiers::FirstOrderModelQInt( this, c, "FirstOrderModelQInt" );
}else{
- d_model = new quantifiers::FirstOrderModelIG( c, "FirstOrderModelIG" );
+ d_model = new quantifiers::FirstOrderModelIG( this, c, "FirstOrderModelIG" );
}
//add quantifiers modules
+ if( options::quantConflictFind() ){
+ d_qcf = new quantifiers::QuantConflictFind( this, c);
+ d_modules.push_back( d_qcf );
+ }else{
+ d_qcf = NULL;
+ }
if( !options::finiteModelFind() || options::fmfInstEngine() ){
//the instantiation must set incomplete flag unless finite model finding is turned on
d_inst_engine = new quantifiers::InstantiationEngine( this, !options::finiteModelFind() );
@@ -389,6 +400,10 @@ Node QuantifiersEngine::getInstantiation( Node f, InstMatch& m ){
return getInstantiation( f, vars, terms );
}
+Node QuantifiersEngine::getInstantiation( Node f, std::vector< Node >& terms ) {
+ return getInstantiation( f, d_term_db->d_inst_constants[f], terms );
+}
+
bool QuantifiersEngine::existsInstantiation( Node f, InstMatch& m, bool modEq, bool modInst ){
if( d_inst_match_trie.find( f )!=d_inst_match_trie.end() ){
if( d_inst_match_trie[f]->existsInstMatch( this, f, m, modEq, modInst ) ){
@@ -493,12 +508,13 @@ bool QuantifiersEngine::addSplitEquality( Node n1, Node n2, bool reqPhase, bool
void QuantifiersEngine::flushLemmas( OutputChannel* out ){
if( !d_lemmas_waiting.empty() ){
+ if( !out ){
+ out = &getOutputChannel();
+ }
//take default output channel if none is provided
d_hasAddedLemma = true;
for( int i=0; i<(int)d_lemmas_waiting.size(); i++ ){
- if( out ){
- out->lemma( d_lemmas_waiting[i] );
- }
+ out->lemma( d_lemmas_waiting[i] );
}
d_lemmas_waiting.clear();
}
diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h
index 6de13ff3c..ee7e6e6d8 100644
--- a/src/theory/quantifiers_engine.h
+++ b/src/theory/quantifiers_engine.h
@@ -52,7 +52,7 @@ public:
/* Call during quantifier engine's check */
virtual void check( Theory::Effort e ) = 0;
/* Called for new quantifiers */
- virtual void registerQuantifier( Node n ) = 0;
+ virtual void registerQuantifier( Node q ) = 0;
virtual void assertNode( Node n ) = 0;
virtual void propagate( Theory::Effort level ){}
virtual Node getNextDecisionRequest() { return TNode::null(); }
@@ -66,6 +66,7 @@ namespace quantifiers {
class InstantiationEngine;
class ModelEngine;
class BoundedIntegers;
+ class QuantConflictFind;
class RewriteEngine;
}/* CVC4::theory::quantifiers */
@@ -105,6 +106,8 @@ private:
quantifiers::ModelEngine* d_model_engine;
/** bounded integers utility */
quantifiers::BoundedIntegers * d_bint;
+ /** Conflict find mechanism for quantifiers */
+ quantifiers::QuantConflictFind* d_qcf;
/** rewrite rules utility */
quantifiers::RewriteEngine * d_rr_engine;
private:
@@ -165,6 +168,8 @@ public:
EfficientEMatcher* getEfficientEMatcher() { return d_eem; }
/** get bounded integers utility */
quantifiers::BoundedIntegers * getBoundedIntegers() { return d_bint; }
+ /** Conflict find mechanism for quantifiers */
+ quantifiers::QuantConflictFind* getConflictFind() { return d_qcf; }
public:
/** initialize */
void finishInit();
@@ -194,6 +199,8 @@ public:
Node getInstantiation( Node f, std::vector< Node >& vars, std::vector< Node >& terms );
/** get instantiation */
Node getInstantiation( Node f, InstMatch& m );
+ /** get instantiation */
+ Node getInstantiation( Node f, std::vector< Node >& terms );
/** exist instantiation ? */
bool existsInstantiation( Node f, InstMatch& m, bool modEq = true, bool modInst = false );
/** add lemma lem */
@@ -207,7 +214,7 @@ public:
/** has added lemma */
bool hasAddedLemma() { return !d_lemmas_waiting.empty() || d_hasAddedLemma; }
/** flush lemmas */
- void flushLemmas( OutputChannel* out );
+ void flushLemmas( OutputChannel* out = NULL );
/** get number of waiting lemmas */
int getNumLemmasWaiting() { return (int)d_lemmas_waiting.size(); }
public:
diff --git a/src/theory/strings/kinds b/src/theory/strings/kinds
index 20db916c9..b30bf8f36 100644
--- a/src/theory/strings/kinds
+++ b/src/theory/strings/kinds
@@ -11,12 +11,15 @@ typechecker "theory/strings/theory_strings_type_rules.h"
operator STRING_CONCAT 2: "string concat"
-
operator STRING_IN_REGEXP 2 "membership"
-
operator STRING_LENGTH 1 "string length"
-
-operator STRING_SUBSTR 3 "string substr"
+operator STRING_SUBSTR 3 "string substr (user symbol)"
+operator STRING_SUBSTR_TOTAL 3 "string substr (internal symbol)"
+operator STRING_CHARAT 2 "string charat (user symbol)"
+operator STRING_CHARAT_TOTAL 2 "string charat (internal symbol)"
+operator STRING_STRCTN 2 "string contains"
+operator STRING_STRIDOF 3 "string indexof"
+operator STRING_STRREPL 3 "string replace"
#sort CHAR_TYPE \
# Cardinality::INTEGERS \
@@ -104,6 +107,12 @@ typerule STRING_TO_REGEXP ::CVC4::theory::strings::StringToRegExpTypeRule
typerule STRING_CONCAT ::CVC4::theory::strings::StringConcatTypeRule
typerule STRING_LENGTH ::CVC4::theory::strings::StringLengthTypeRule
typerule STRING_SUBSTR ::CVC4::theory::strings::StringSubstrTypeRule
+typerule STRING_SUBSTR_TOTAL ::CVC4::theory::strings::StringSubstrTypeRule
+typerule STRING_CHARAT ::CVC4::theory::strings::StringCharAtTypeRule
+typerule STRING_CHARAT_TOTAL ::CVC4::theory::strings::StringCharAtTypeRule
+typerule STRING_STRCTN ::CVC4::theory::strings::StringContainTypeRule
+typerule STRING_STRIDOF ::CVC4::theory::strings::StringIndexOfTypeRule
+typerule STRING_STRREPL ::CVC4::theory::strings::StringReplaceTypeRule
typerule STRING_IN_REGEXP ::CVC4::theory::strings::StringInRegExpTypeRule
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp
index 62e71327e..4b479e348 100644
--- a/src/theory/strings/theory_strings.cpp
+++ b/src/theory/strings/theory_strings.cpp
@@ -43,6 +43,8 @@ TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u, Outpu
d_nf_pairs(c),
//d_var_lmin( c ),
//d_var_lmax( c ),
+ d_str_pos_ctn( c ),
+ d_str_neg_ctn( c ),
d_reg_exp_mem( c ),
d_curr_cardinality( c, 0 )
{
@@ -50,6 +52,7 @@ TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u, Outpu
//d_equalityEngine.addFunctionKind(kind::STRING_IN_REGEXP);
d_equalityEngine.addFunctionKind(kind::STRING_LENGTH);
d_equalityEngine.addFunctionKind(kind::STRING_CONCAT);
+ d_equalityEngine.addFunctionKind(kind::STRING_STRCTN);
d_zero = NodeManager::currentNM()->mkConst( Rational( 0 ) );
d_emptyString = NodeManager::currentNM()->mkConst( ::CVC4::String("") );
@@ -308,7 +311,7 @@ void TheoryStrings::collectModelInfo( TheoryModel* m, bool fullModel ) {
}
}
}
- Trace("strings-model") << "String Model : Finished." << std::endl;
+ Trace("strings-model") << "String Model : Pure Assigned." << std::endl;
//step 4 : assign constants to all other equivalence classes
for( unsigned i=0; i<nodes.size(); i++ ){
if( processed.find( nodes[i] )==processed.end() ){
@@ -336,6 +339,20 @@ void TheoryStrings::collectModelInfo( TheoryModel* m, bool fullModel ) {
m->assertEquality( nodes[i], cc, true );
}
}
+ Trace("strings-model") << "String Model : Assigned." << std::endl;
+ //check for negative contains
+ /*
+ Trace("strings-model") << "String Model : Check Neg Contains, size = " << d_str_neg_ctn.size() << std::endl;
+ for( unsigned i=0; i<d_str_neg_ctn.size(); i++ ) {
+ Node x = d_str_neg_ctn[i][0];
+ Node y = d_str_neg_ctn[i][1];
+ Trace("strings-model") << "String Model : Check Neg contains: ~contains(" << x << ", " << y << ")." << std::endl;
+ //Node xv = m->getValue(x);
+ //Node yv = m->getValue(y);
+ //Trace("strings-model") << "String Model : Check Neg contains Value: ~contains(" << xv << ", " << yv << ")." << std::endl;
+ }
+ */
+ Trace("strings-model") << "String Model : Finished." << std::endl;
}
/////////////////////////////////////////////////////////////////////////////
@@ -387,14 +404,13 @@ void TheoryStrings::check(Effort e) {
bool polarity;
TNode atom;
- if( !done() && !hasTerm( d_emptyString ) ){
+ if( !done() && !hasTerm( d_emptyString ) ) {
preRegisterTerm( d_emptyString );
}
// Trace("strings-process") << "Theory of strings, check : " << e << std::endl;
Trace("strings-check") << "Theory of strings, check : " << e << std::endl;
- while ( !done() && !d_conflict)
- {
+ while ( !done() && !d_conflict ) {
// Get all the assertions
Assertion assertion = get();
TNode fact = assertion.assertion;
@@ -406,7 +422,14 @@ void TheoryStrings::check(Effort e) {
//must record string in regular expressions
if ( atom.getKind() == kind::STRING_IN_REGEXP ) {
d_reg_exp_mem.push_back( assertion );
- }else if (atom.getKind() == kind::EQUAL) {
+ } else if (atom.getKind() == kind::STRING_STRCTN) {
+ if(polarity) {
+ d_str_pos_ctn.push_back( atom );
+ } else {
+ d_str_neg_ctn.push_back( atom );
+ }
+ d_equalityEngine.assertPredicate(atom, polarity, fact);
+ } else if (atom.getKind() == kind::EQUAL) {
d_equalityEngine.assertEquality(atom, polarity, fact);
} else {
d_equalityEngine.assertPredicate(atom, polarity, fact);
@@ -417,24 +440,28 @@ void TheoryStrings::check(Effort e) {
bool addedLemma = false;
if( e == EFFORT_FULL && !d_conflict ) {
- addedLemma = checkLengths();
- Trace("strings-process") << "Done check (constant) lengths, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if( !addedLemma ){
- addedLemma = checkNormalForms();
- Trace("strings-process") << "Done check normal forms, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if(!d_conflict && !addedLemma) {
- addedLemma = checkLengthsEqc();
- Trace("strings-process") << "Done check lengths, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if(!d_conflict && !addedLemma) {
- addedLemma = checkCardinality();
- Trace("strings-process") << "Done check cardinality, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if( !d_conflict && !addedLemma ){
+ addedLemma = checkLengths();
+ Trace("strings-process") << "Done check (constant) lengths, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if( !addedLemma ) {
+ addedLemma = checkNormalForms();
+ Trace("strings-process") << "Done check normal forms, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if(!d_conflict && !addedLemma) {
+ addedLemma = checkLengthsEqc();
+ Trace("strings-process") << "Done check lengths, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if(!d_conflict && !addedLemma) {
+ addedLemma = checkCardinality();
+ Trace("strings-process") << "Done check cardinality, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if( !d_conflict && !addedLemma ) {
addedLemma = checkMemberships();
Trace("strings-process") << "Done check membership constraints, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- }
- }
- }
- }
+ if( !d_conflict && !addedLemma ) {
+ addedLemma = checkContains();
+ Trace("strings-process") << "Done check contain constraints, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ }
+ }
+ }
+ }
+ }
}
Trace("strings-check") << "Theory of strings, done check : " << e << std::endl;
Trace("strings-process") << "Theory of strings, done check : " << e << std::endl;
@@ -713,6 +740,7 @@ bool TheoryStrings::getNormalForms(Node &eqc, std::vector< Node > & visited, std
Trace("strings-solve") << "--- Normal forms for equivlance class " << eqc << " : " << std::endl;
for( unsigned i=0; i<normal_forms.size(); i++ ) {
Trace("strings-solve") << "#" << i << " (from " << normal_form_src[i] << ") : ";
+ //mergeCstVec(normal_forms[i]);
for( unsigned j=0; j<normal_forms[i].size(); j++ ) {
if(j>0) Trace("strings-solve") << ", ";
Trace("strings-solve") << normal_forms[i][j];
@@ -733,6 +761,27 @@ bool TheoryStrings::getNormalForms(Node &eqc, std::vector< Node > & visited, std
return true;
}
+void TheoryStrings::mergeCstVec(std::vector< Node > &vec_strings) {
+ std::vector< Node >::iterator itr = vec_strings.begin();
+ while(itr != vec_strings.end()) {
+ if(itr->isConst()) {
+ std::vector< Node >::iterator itr2 = itr + 1;
+ if(itr2 == vec_strings.end()) {
+ break;
+ } else if(itr2->isConst()) {
+ CVC4::String s1 = itr->getConst<String>();
+ CVC4::String s2 = itr2->getConst<String>();
+ *itr = NodeManager::currentNM()->mkConst(s1.concat(s2));
+ vec_strings.erase(itr2);
+ } else {
+ ++itr;
+ }
+ } else {
+ ++itr;
+ }
+ }
+}
+
bool TheoryStrings::detectLoop( std::vector< std::vector< Node > > &normal_forms,
int i, int j, int index_i, int index_j,
int &loop_in_i, int &loop_in_j) {
@@ -1380,7 +1429,7 @@ bool TheoryStrings::isNormalFormPair2( Node n1, Node n2 ) {
}
void TheoryStrings::sendLemma( Node ant, Node conc, const char * c ) {
- if( conc.isNull() || conc==d_false ){
+ if( conc.isNull() ){
d_out->conflict(ant);
Trace("strings-conflict") << "Strings::Conflict : " << ant << std::endl;
d_conflict = true;
@@ -2028,33 +2077,18 @@ bool TheoryStrings::checkMemberships() {
}
} else {
//TODO: negative membership
- //Node r = Rewriter::rewrite( atom[1] );
- //r = d_regexp_opr.complement( r );
- //Trace("strings-regexp-test") << "Compl( " << d_regexp_opr.mkString( atom[1] ) << " ) is " << d_regexp_opr.mkString( r ) << std::endl;
- //Trace("strings-regexp-test") << "Delta( " << d_regexp_opr.mkString( atom[1] ) << " ) is " << d_regexp_opr.delta( atom[1] ) << std::endl;
- //Trace("strings-regexp-test") << "Delta( " << d_regexp_opr.mkString( r ) << " ) is " << d_regexp_opr.delta( r ) << std::endl;
- //Trace("strings-regexp-test") << "Deriv( " << d_regexp_opr.mkString( r ) << ", c='b' ) is " << d_regexp_opr.mkString( d_regexp_opr.derivativeSingle( r, ::CVC4::String("b") ) ) << std::endl;
- //Trace("strings-regexp-test") << "FHC( " << d_regexp_opr.mkString( r ) <<" ) is " << std::endl;
- //d_regexp_opr.firstChar( r );
- //r = NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, atom[0], r );
- /*
- std::vector< Node > vec_r;
- vec_r.push_back( r );
-
- StringsPreprocess spp;
- spp.simplify( vec_r );
- for( unsigned i=1; i<vec_r.size(); i++ ){
- if(vec_r[i].getKind() == kind::STRING_IN_REGEXP) {
- d_reg_exp_mem.push_back( vec_r[i] );
- } else if(vec_r[i].getKind() == kind::EQUAL) {
- d_equalityEngine.assertEquality(vec_r[i], true, vec_r[i]);
- } else {
- Assert(false);
- }
+ Node x = atom[0];
+ Node r = atom[1];
+ Assert( r.getKind()==kind::REGEXP_STAR );
+ if( areEqual( x, d_emptyString ) ) {
+ Node ant = NodeManager::currentNM()->mkNode( kind::AND, assertion, x.eqNode( d_emptyString ) );
+ Node conc = Node::null();
+ sendLemma( ant, conc, "RegExp Empty Conflict" );
+ addedLemma = true;
+ } else {
+ Trace("strings-regexp") << "RegEx is incomplete due to " << assertion << "." << std::endl;
+ is_unk = true;
}
- */
- Trace("strings-regexp") << "RegEx is incomplete due to " << assertion << "." << std::endl;
- is_unk = true;
}
}
if( addedLemma ){
@@ -2077,6 +2111,130 @@ bool TheoryStrings::checkMemberships() {
}
}
+bool TheoryStrings::checkContains() {
+ bool addedLemma = checkPosContains();
+ Trace("strings-process") << "Done check positive contain constraints, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if(!addedLemma) {
+ addedLemma = checkNegContains();
+ Trace("strings-process") << "Done check positive contain constraints, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ }
+ return addedLemma;
+}
+
+bool TheoryStrings::checkPosContains() {
+ bool addedLemma = false;
+ for( unsigned i=0; i<d_str_pos_ctn.size(); i++ ) {
+ Node atom = d_str_pos_ctn[i];
+ Trace("strings-ctn") << "We have positive contain assertion : " << atom << std::endl;
+ Assert( atom.getKind()==kind::STRING_STRCTN );
+ Node x = atom[0];
+ Node s = atom[1];
+ if( !areEqual( s, d_emptyString ) && !areEqual( s, x ) ) {
+ if(d_str_pos_ctn_rewritten.find(atom) == d_str_pos_ctn_rewritten.end()) {
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "sc1_$$", s.getType(), "created for contain" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "sc2_$$", s.getType(), "created for contain" );
+ Node eq = Rewriter::rewrite( x.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, s, sk2 ) ) );
+ sendLemma( atom, eq, "POS-INC" );
+ addedLemma = true;
+ d_str_pos_ctn_rewritten[ atom ] = true;
+ } else {
+ Trace("strings-ctn") << "... is already rewritten." << std::endl;
+ }
+ } else {
+ Trace("strings-ctn") << "... is satisfied." << std::endl;
+ }
+ }
+ if( addedLemma ){
+ doPendingLemmas();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool TheoryStrings::checkNegContains() {
+ bool is_unk = false;
+ bool addedLemma = false;
+ for( unsigned i=0; i<d_str_neg_ctn.size(); i++ ){
+ Node atom = d_str_neg_ctn[i];
+ Trace("strings-ctn") << "We have nagetive contain assertion : (not " << atom << " )" << std::endl;
+ if( areEqual( atom[1], d_emptyString ) ) {
+ Node ant = NodeManager::currentNM()->mkNode( kind::AND, atom.negate(), atom[1].eqNode( d_emptyString ) );
+ Node conc = Node::null();
+ sendLemma( ant, conc, "NEG-CTN Conflict 1" );
+ addedLemma = true;
+ } else if( areEqual( atom[1], atom[0] ) ) {
+ Node ant = NodeManager::currentNM()->mkNode( kind::AND, atom.negate(), atom[1].eqNode( atom[0] ) );
+ Node conc = Node::null();
+ sendLemma( ant, conc, "NEG-CTN Conflict 2" );
+ addedLemma = true;
+ } else {
+ if(options::stringExp()) {
+ Node x = atom[0];
+ Node s = atom[1];
+ Node lenx = getLength(x);
+ Node lens = getLength(s);
+ if(areEqual(lenx, lens)) {
+ if(d_str_ctn_eqlen.find(atom) == d_str_ctn_eqlen.end()) {
+ Node eq = lenx.eqNode(lens);
+ Node antc = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, atom.negate(), eq ) );
+ Node xneqs = x.eqNode(s).negate();
+ d_str_ctn_eqlen[ atom ] = true;
+ sendLemma( antc, xneqs, "NEG-CTN-EQL" );
+ addedLemma = true;
+ }
+ } else if(!areDisequal(lenx, lens)) {
+ sendSplit(lenx, lens, "NEG-CTN-SP");
+ addedLemma = true;
+ } else {
+ if(d_str_neg_ctn_rewritten.find(atom) == d_str_neg_ctn_rewritten.end()) {
+ Node e1 = NodeManager::currentNM()->mkSkolem( "nc1_$$", s.getType(), "created for contain" );
+ Node e2 = NodeManager::currentNM()->mkSkolem( "nc2_$$", s.getType(), "created for contain" );
+ Node z = NodeManager::currentNM()->mkSkolem( "ncz_$$", s.getType(), "created for contain" );
+ Node w = NodeManager::currentNM()->mkSkolem( "ncw_$$", s.getType(), "created for contain" );
+ std::vector< Node > vec_conc;
+ Node cc = Rewriter::rewrite( x.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, e1, z ) ) );
+ vec_conc.push_back(cc);
+ cc = Rewriter::rewrite( x.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, w, e2 ) ) );
+ vec_conc.push_back(cc);
+ cc = Rewriter::rewrite( z.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, s, e2 ) ).negate() );
+ vec_conc.push_back(cc);
+ cc = Rewriter::rewrite( w.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, e1, s ) ).negate() );
+ vec_conc.push_back(cc);
+ cc = Rewriter::rewrite( lenx.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, e1, s, e2 ) ) ) );
+ vec_conc.push_back(cc);
+ //Incomplete
+ //cc = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, e1, s ).negate();
+ //vec_conc.push_back(cc);
+ //cc = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, e2, s ).negate();
+ //vec_conc.push_back(cc);
+ Node conc = NodeManager::currentNM()->mkNode( kind::AND, vec_conc );
+ Node xlss = NodeManager::currentNM()->mkNode( kind::GT, lens, lenx );
+ conc = NodeManager::currentNM()->mkNode( kind::OR, xlss, conc );
+ d_str_neg_ctn_rewritten[ atom ] = true;
+ sendLemma( atom.negate(), conc, "NEG-INC-BRK" );
+ addedLemma = true;
+ }
+ }
+ } else {
+ Trace("strings-ctn") << "Strings Incomplete (due to Negative Contain) by default." << std::endl;
+ is_unk = true;
+ }
+ }
+ }
+ if( addedLemma ){
+ doPendingLemmas();
+ return true;
+ } else {
+ if( is_unk ){
+ Trace("strings-ctn") << "Strings::inc: possibly incomplete." << std::endl;
+ d_out->setIncomplete();
+ }
+ return false;
+ }
+}
+
CVC4::String TheoryStrings::getHeadConst( Node x ) {
if( x.isConst() ) {
return x.getConst< String >();
@@ -2092,8 +2250,8 @@ CVC4::String TheoryStrings::getHeadConst( Node x ) {
}
bool TheoryStrings::addMembershipLength(Node atom) {
- Node x = atom[0];
- Node r = atom[1];
+ //Node x = atom[0];
+ //Node r = atom[1];
/*std::vector< int > co;
co.push_back(0);
diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h
index 875f407c5..1d92abbd2 100644
--- a/src/theory/strings/theory_strings.h
+++ b/src/theory/strings/theory_strings.h
@@ -191,6 +191,7 @@ private:
//maintain which concat terms have the length lemma instantiated
std::map< Node, bool > d_length_inst;
private:
+ void mergeCstVec(std::vector< Node > &vec_strings);
bool getNormalForms(Node &eqc, std::vector< Node > & visited, std::vector< Node > & nf,
std::vector< std::vector< Node > > &normal_forms,
std::vector< std::vector< Node > > &normal_forms_exp,
@@ -216,6 +217,9 @@ private:
bool checkCardinality();
bool checkInductiveEquations();
bool checkMemberships();
+ bool checkContains();
+ bool checkPosContains();
+ bool checkNegContains();
public:
void preRegisterTerm(TNode n);
@@ -269,6 +273,13 @@ private:
Node mkSplitEq( const char * c, const char * info, Node lhs, Node rhs, bool lgtZero );
int getMaxPossibleLength( Node x );
+ // Special String Functions
+ NodeList d_str_pos_ctn;
+ NodeList d_str_neg_ctn;
+ std::map< Node, bool > d_str_ctn_eqlen;
+ std::map< Node, bool > d_str_pos_ctn_rewritten;
+ std::map< Node, bool > d_str_neg_ctn_rewritten;
+
// Regular Expression
private:
// regular expression memberships
diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp
index ff01b1887..11e206eeb 100644
--- a/src/theory/strings/theory_strings_preprocess.cpp
+++ b/src/theory/strings/theory_strings_preprocess.cpp
@@ -23,6 +23,9 @@ namespace CVC4 {
namespace theory {
namespace strings {
+StringsPreprocess::StringsPreprocess() {
+}
+
void StringsPreprocess::simplifyRegExp( Node s, Node r, std::vector< Node > &ret, std::vector< Node > &nn ) {
int k = r.getKind();
switch( k ) {
@@ -115,28 +118,117 @@ Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
// TODO
// return (t0 == t[0]) ? t : NodeManager::currentNM()->mkNode( kind::STRING_IN_REGEXP, t0, t[1] );
//}
- } else if( t.getKind() == kind::STRING_SUBSTR ){
+ } else if( t.getKind() == kind::STRING_SUBSTR_TOTAL ){
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "st1_$$", t.getType(), "created for substr" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "st2_$$", t.getType(), "created for substr" );
+ Node sk3 = NodeManager::currentNM()->mkSkolem( "st3_$$", t.getType(), "created for substr" );
+ Node x = simplify( t[0], new_nodes );
+ Node lenxgti = NodeManager::currentNM()->mkNode( kind::GEQ,
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, x ),
+ NodeManager::currentNM()->mkNode( kind::PLUS, t[1], t[2] ) );
+ Node x_eq_123 = NodeManager::currentNM()->mkNode( kind::EQUAL,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk2, sk3 ), x );
+ Node len_sk1_eq_i = NodeManager::currentNM()->mkNode( kind::EQUAL, t[1],
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk1 ) );
+ Node len_sk2_eq_j = NodeManager::currentNM()->mkNode( kind::EQUAL, t[2],
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk2 ) );
+
+ Node tp = NodeManager::currentNM()->mkNode( kind::AND, x_eq_123, len_sk1_eq_i, len_sk2_eq_j );
+ tp = NodeManager::currentNM()->mkNode( kind::IMPLIES, lenxgti, tp );
+ new_nodes.push_back( tp );
+
+ d_cache[t] = sk2;
+ retNode = sk2;
+ } else if( t.getKind() == kind::STRING_CHARAT_TOTAL ){
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "ca1_$$", t.getType(), "created for charat" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "ca2_$$", t.getType(), "created for charat" );
+ Node sk3 = NodeManager::currentNM()->mkSkolem( "ca3_$$", t.getType(), "created for charat" );
+ Node x = simplify( t[0], new_nodes );
+ Node lenxgti = NodeManager::currentNM()->mkNode( kind::GT,
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, x ), t[1] );
+ Node x_eq_123 = NodeManager::currentNM()->mkNode( kind::EQUAL,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk2, sk3 ), x );
+ Node len_sk1_eq_i = NodeManager::currentNM()->mkNode( kind::EQUAL, t[1],
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk1 ) );
+ Node len_sk2_eq_1 = NodeManager::currentNM()->mkNode( kind::EQUAL, NodeManager::currentNM()->mkConst( Rational( 1 ) ),
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk2 ) );
+
+ Node tp = NodeManager::currentNM()->mkNode( kind::AND, x_eq_123, len_sk1_eq_i, len_sk2_eq_1 );
+ tp = NodeManager::currentNM()->mkNode( kind::IMPLIES, lenxgti, tp );
+ new_nodes.push_back( tp );
+
+ d_cache[t] = sk2;
+ retNode = sk2;
+ } else if( t.getKind() == kind::STRING_STRIDOF ){
+ if(options::stringExp()) {
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "io1_$$", t[0].getType(), "created for indexof" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "io2_$$", t[0].getType(), "created for indexof" );
+ Node sk3 = NodeManager::currentNM()->mkSkolem( "io3_$$", t[0].getType(), "created for indexof" );
+ Node sk4 = NodeManager::currentNM()->mkSkolem( "io4_$$", t[0].getType(), "created for indexof" );
+ Node skk = NodeManager::currentNM()->mkSkolem( "iok_$$", t[2].getType(), "created for indexof" );
+ Node eq = t[0].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk2, sk3, sk4 ) );
+ new_nodes.push_back( eq );
+ Node negone = NodeManager::currentNM()->mkConst( ::CVC4::Rational(-1) );
+ Node krange = NodeManager::currentNM()->mkNode( kind::AND,
+ NodeManager::currentNM()->mkNode( kind::GEQ, skk, negone ),
+ NodeManager::currentNM()->mkNode( kind::GT,
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[0] ),
+ skk));
+ new_nodes.push_back( krange );
+
+ //str.len(s1) < y + str.len(s2)
+ Node c1 = NodeManager::currentNM()->mkNode( kind::GT, NodeManager::currentNM()->mkNode( kind::PLUS, t[2], NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[1] )),
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, t[0] ));
+ //str.len(t1) = y
+ Node c2 = t[2].eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk1 ) );
+ //~contain(t234, s2)
+ Node c3 = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk2, sk3, sk4), t[1] ).negate();
+ //left
+ Node left = NodeManager::currentNM()->mkNode( kind::OR, c1, NodeManager::currentNM()->mkNode( kind::AND, c2, c3 ) );
+ //t3 = s2
+ Node c4 = t[1].eqNode( sk3 );
+ //~contain(t2, s2)
+ Node c5 = NodeManager::currentNM()->mkNode( kind::STRING_STRCTN, sk2, t[1] ).negate();
+ //k=str.len(s1, s2)
+ Node c6 = skk.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk2 )));
+ //right
+ Node right = NodeManager::currentNM()->mkNode( kind::AND, c2, c4, c5, c6 );
+ Node cond = skk.eqNode( negone );
+ Node rr = NodeManager::currentNM()->mkNode( kind::ITE, cond, left, right );
+ new_nodes.push_back( rr );
+ d_cache[t] = skk;
+ retNode = skk;
+ } else {
+ throw LogicException("string indexof not supported in this release");
+ }
+ } else if( t.getKind() == kind::STRING_STRREPL ){
if(options::stringExp()) {
- Node sk1 = NodeManager::currentNM()->mkSkolem( "st1sym_$$", t.getType(), "created for substr" );
- Node sk2 = NodeManager::currentNM()->mkSkolem( "st2sym_$$", t.getType(), "created for substr" );
- Node sk3 = NodeManager::currentNM()->mkSkolem( "st3sym_$$", t.getType(), "created for substr" );
- Node x = simplify( t[0], new_nodes );
- Node x_eq_123 = NodeManager::currentNM()->mkNode( kind::EQUAL,
- NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk2, sk3 ), x );
- new_nodes.push_back( x_eq_123 );
- Node len_sk1_eq_i = NodeManager::currentNM()->mkNode( kind::EQUAL, t[1],
- NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk1 ) );
- new_nodes.push_back( len_sk1_eq_i );
- Node len_sk2_eq_j = NodeManager::currentNM()->mkNode( kind::EQUAL, t[2],
- NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk2 ) );
- new_nodes.push_back( len_sk2_eq_j );
-
- d_cache[t] = sk2;
- retNode = sk2;
+ Node zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
+ Node x = t[0];
+ Node y = t[1];
+ Node z = t[2];
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "rp1_$$", t[0].getType(), "created for replace" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "rp2_$$", t[0].getType(), "created for replace" );
+ Node skw = NodeManager::currentNM()->mkSkolem( "rpw_$$", t[0].getType(), "created for replace" );
+ Node iof = NodeManager::currentNM()->mkNode( kind::STRING_STRIDOF, x, y, zero );
+ Node igeq0 = NodeManager::currentNM()->mkNode( kind::GEQ, iof, zero );
+ Node c1 = x.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, y, sk2 ) );
+ Node c2 = skw.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, z, sk2 ) );
+ Node c3 = iof.eqNode( NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk1 ) );
+ Node rr = NodeManager::currentNM()->mkNode( kind::ITE, igeq0,
+ NodeManager::currentNM()->mkNode( kind::AND, c1, c2, c3 ),
+ skw.eqNode(x) );
+ new_nodes.push_back( rr );
+ d_cache[t] = skw;
+ retNode = skw;
} else {
- throw LogicException("substring not supported in this release");
+ throw LogicException("string replace not supported in this release");
}
- } else if( t.getNumChildren()>0 ){
+ } else if(t.getKind() == kind::STRING_CHARAT || t.getKind() == kind::STRING_SUBSTR) {
+ InternalError("CharAt and Substr should not be reached here.");
+ } else if( t.getNumChildren()>0 ) {
std::vector< Node > cc;
if (t.getMetaKind() == kind::metakind::PARAMETERIZED) {
cc.push_back(t.getOperator());
diff --git a/src/theory/strings/theory_strings_preprocess.h b/src/theory/strings/theory_strings_preprocess.h
index 698ef6ba1..6d278cc7a 100644
--- a/src/theory/strings/theory_strings_preprocess.h
+++ b/src/theory/strings/theory_strings_preprocess.h
@@ -36,6 +36,7 @@ private:
Node simplify( Node t, std::vector< Node > &new_nodes );
public:
void simplify(std::vector< Node > &vec_node);
+ StringsPreprocess();
};
}/* CVC4::theory::strings namespace */
diff --git a/src/theory/strings/theory_strings_rewriter.cpp b/src/theory/strings/theory_strings_rewriter.cpp
index 0e37367bf..9f278aac2 100644
--- a/src/theory/strings/theory_strings_rewriter.cpp
+++ b/src/theory/strings/theory_strings_rewriter.cpp
@@ -340,22 +340,67 @@ RewriteResponse TheoryStringsRewriter::postRewrite(TNode node) {
retNode = NodeManager::currentNM()->mkNode(kind::PLUS, node_vec);
}
}
- } else if(node.getKind() == kind::STRING_SUBSTR) {
- if(options::stringExp()) {
- if( node[0].isConst() && node[1].isConst() && node[2].isConst() ) {
- int i = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
- int j = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
- if( node[0].getConst<String>().size() >= (unsigned) (i + j) ) {
- retNode = NodeManager::currentNM()->mkConst( node[0].getConst<String>().substr(i, j) );
+ } else if(node.getKind() == kind::STRING_SUBSTR_TOTAL) {
+ if( node[0].isConst() && node[1].isConst() && node[2].isConst() ) {
+ int i = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
+ int j = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
+ if( node[0].getConst<String>().size() >= (unsigned) (i + j) ) {
+ retNode = NodeManager::currentNM()->mkConst( node[0].getConst<String>().substr(i, j) );
+ }
+ }
+ } else if(node.getKind() == kind::STRING_STRCTN) {
+ if( node[0] == node[1] ) {
+ retNode = NodeManager::currentNM()->mkConst( true );
+ } else if( node[0].isConst() && node[1].isConst() ) {
+ CVC4::String s = node[0].getConst<String>();
+ CVC4::String t = node[1].getConst<String>();
+ if( s.find(t) != std::string::npos ) {
+ retNode = NodeManager::currentNM()->mkConst( true );
+ } else {
+ retNode = NodeManager::currentNM()->mkConst( false );
+ }
+ }
+ } else if(node.getKind() == kind::STRING_CHARAT_TOTAL) {
+ if( node[0].isConst() && node[1].isConst() ) {
+ int i = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
+ if( node[0].getConst<String>().size() > (unsigned) i ) {
+ retNode = NodeManager::currentNM()->mkConst( node[0].getConst<String>().substr(i, 1) );
+ }
+ }
+ } else if(node.getKind() == kind::STRING_STRIDOF) {
+ if( node[0].isConst() && node[1].isConst() && node[2].isConst() ) {
+ CVC4::String s = node[0].getConst<String>();
+ CVC4::String t = node[1].getConst<String>();
+ int i = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
+ std::size_t ret = s.find(t, i);
+ if( ret != std::string::npos ) {
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational((int) ret) );
+ } else {
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::Rational(-1) );
+ }
+ }
+ } else if(node.getKind() == kind::STRING_STRREPL) {
+ if(node[1] != node[2]) {
+ if(node[0].isConst() && node[1].isConst()) {
+ CVC4::String s = node[0].getConst<String>();
+ CVC4::String t = node[1].getConst<String>();
+ std::size_t p = s.find(t);
+ if( p != std::string::npos ) {
+ if(node[2].isConst()) {
+ CVC4::String r = node[2].getConst<String>();
+ CVC4::String ret = s.replace(t, r);
+ retNode = NodeManager::currentNM()->mkConst( ::CVC4::String(ret) );
+ } else {
+ CVC4::String s1 = s.substr(0, (int)p);
+ CVC4::String s3 = s.substr((int)p + (int)t.size());
+ Node ns1 = NodeManager::currentNM()->mkConst( ::CVC4::String(s1) );
+ Node ns3 = NodeManager::currentNM()->mkConst( ::CVC4::String(s3) );
+ retNode = NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, ns1, node[2], ns3 );
+ }
} else {
- // TODO: some issues, must be guarded by users
- retNode = NodeManager::currentNM()->mkConst( false );
+ retNode = node[0];
}
- } else {
- //handled by preprocess
}
- } else {
- throw LogicException("substring not supported in this release");
}
} else if(node.getKind() == kind::STRING_IN_REGEXP) {
retNode = rewriteMembership(node);
diff --git a/src/theory/strings/theory_strings_type_rules.h b/src/theory/strings/theory_strings_type_rules.h
index d5019ab39..29fdf27a6 100644
--- a/src/theory/strings/theory_strings_type_rules.h
+++ b/src/theory/strings/theory_strings_type_rules.h
@@ -73,15 +73,95 @@ public:
if( check ){
TypeNode t = n[0].getType(check);
if (!t.isString()) {
- throw TypeCheckingExceptionPrivate(n, "expecting string terms in substr");
+ throw TypeCheckingExceptionPrivate(n, "expecting a string term in substr");
}
t = n[1].getType(check);
if (!t.isInteger()) {
- throw TypeCheckingExceptionPrivate(n, "expecting start int terms in substr");
+ throw TypeCheckingExceptionPrivate(n, "expecting a start int term in substr");
}
t = n[2].getType(check);
if (!t.isInteger()) {
- throw TypeCheckingExceptionPrivate(n, "expecting length int terms in substr");
+ throw TypeCheckingExceptionPrivate(n, "expecting a length int term in substr");
+ }
+ }
+ return nodeManager->stringType();
+ }
+};
+
+class StringContainTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ){
+ TypeNode t = n[0].getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting an orginal string term in string contain");
+ }
+ t = n[1].getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting a target string term in string contain");
+ }
+ }
+ return nodeManager->booleanType();
+ }
+};
+
+class StringCharAtTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ){
+ TypeNode t = n[0].getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting a string term in string char at 0");
+ }
+ t = n[1].getType(check);
+ if (!t.isInteger()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting an integer term in string char at 1");
+ }
+ }
+ return nodeManager->stringType();
+ }
+};
+
+class StringIndexOfTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ){
+ TypeNode t = n[0].getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting a string term in string indexof 0");
+ }
+ t = n[1].getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting a string term in string indexof 1");
+ }
+ t = n[2].getType(check);
+ if (!t.isInteger()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting an integer term in string indexof 2");
+ }
+ }
+ return nodeManager->integerType();
+ }
+};
+
+class StringReplaceTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ){
+ TypeNode t = n[0].getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting a string term in string replace 0");
+ }
+ t = n[1].getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting a string term in string replace 1");
+ }
+ t = n[2].getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting a string term in string replace 2");
}
}
return nodeManager->stringType();
diff --git a/src/theory/theory.h b/src/theory/theory.h
index fdd2d0518..43d35ac9d 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -254,6 +254,7 @@ protected:
, d_sharedTerms(satContext)
, d_out(&out)
, d_valuation(valuation)
+ , d_proofEnabled(false)
{
StatisticsRegistry::registerStat(&d_computeCareGraphTime);
}
@@ -299,6 +300,12 @@ protected:
void printFacts(std::ostream& os) const;
void debugPrintFacts() const;
+ /**
+ * Whether proofs are enabled
+ *
+ */
+ bool d_proofEnabled;
+
public:
/**
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index 7cf4d7ad9..e55d6a9c9 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -75,12 +75,18 @@ void TheoryEngine::finishInit() {
void TheoryEngine::eqNotifyNewClass(TNode t){
d_quantEngine->addTermToDatabase( t );
+ if( d_logicInfo.isQuantified() && options::quantConflictFind() ){
+ d_quantEngine->getConflictFind()->newEqClass( t );
+ }
}
void TheoryEngine::eqNotifyPreMerge(TNode t1, TNode t2){
//TODO: add notification to efficient E-matching
- if (d_logicInfo.isQuantified()) {
+ if( d_logicInfo.isQuantified() ){
d_quantEngine->getEfficientEMatcher()->merge( t1, t2 );
+ if( options::quantConflictFind() ){
+ d_quantEngine->getConflictFind()->merge( t1, t2 );
+ }
}
}
@@ -89,7 +95,11 @@ void TheoryEngine::eqNotifyPostMerge(TNode t1, TNode t2){
}
void TheoryEngine::eqNotifyDisequal(TNode t1, TNode t2, TNode reason){
-
+ if( d_logicInfo.isQuantified() ){
+ if( options::quantConflictFind() ){
+ d_quantEngine->getConflictFind()->assertDisequal( t1, t2 );
+ }
+ }
}
@@ -146,6 +156,7 @@ TheoryEngine::TheoryEngine(context::Context* context,
StatisticsRegistry::registerStat(&d_combineTheoriesTime);
d_true = NodeManager::currentNM()->mkConst<bool>(true);
d_false = NodeManager::currentNM()->mkConst<bool>(false);
+
PROOF (ProofManager::currentPM()->initTheoryProof(); );
d_iteUtilities = new ITEUtilities(d_iteRemover.getContainsVisitor());
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index 92469aa31..8f292e008 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -39,6 +39,7 @@
#include "util/statistics_registry.h"
#include "util/cvc4_assert.h"
#include "util/sort_inference.h"
+#include "theory/quantifiers/quant_conflict_find.h"
#include "theory/uf/equality_engine.h"
#include "theory/bv/bv_to_bool.h"
#include "theory/atom_requests.h"
@@ -778,10 +779,10 @@ private:
UnconstrainedSimplifier* d_unconstrainedSimp;
/** For preprocessing pass lifting bit-vectors of size 1 to booleans */
- theory::bv::BvToBoolPreprocessor d_bvToBoolPreprocessor;
+ theory::bv::BvToBoolPreprocessor d_bvToBoolPreprocessor;
public:
- void ppBvToBool(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
+ void ppBvToBool(const std::vector<Node>& assertions, std::vector<Node>& new_assertions);
Node ppSimpITE(TNode assertion);
/** Returns false if an assertion simplified to false. */
bool donePPSimpITE(std::vector<Node>& assertions);
@@ -790,6 +791,8 @@ public:
SharedTermsDatabase* getSharedTermsDatabase() { return &d_sharedTerms; }
+ theory::eq::EqualityEngine* getMasterEqualityEngine() { return d_masterEqualityEngine; }
+
SortInference* getSortInference() { return &d_sortInfer; }
private:
std::map< std::string, std::vector< theory::Theory* > > d_attr_handle;
diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp
index cb44b42df..df1d2ebde 100644
--- a/src/theory/uf/equality_engine.cpp
+++ b/src/theory/uf/equality_engine.cpp
@@ -71,8 +71,8 @@ void EqualityEngine::init() {
addTermInternal(d_false);
d_trueId = getNodeId(d_true);
- d_falseId = getNodeId(d_false);
-}
+ d_falseId = getNodeId(d_false);
+}
EqualityEngine::~EqualityEngine() throw(AssertionException) {
free(d_triggerDatabase);
@@ -287,7 +287,7 @@ void EqualityEngine::addTermInternal(TNode t, bool isOperator) {
d_isConstant[result] = t.isConst();
// If interpreted, set the number of non-interpreted children
if (isInterpreted) {
- // How many children are not constants yet
+ // How many children are not constants yet
d_subtermsToEvaluate[result] = t.getNumChildren();
for (unsigned i = 0; i < t.getNumChildren(); ++ i) {
if (isConstant(getNodeId(t[i]))) {
@@ -316,11 +316,11 @@ void EqualityEngine::addTermInternal(TNode t, bool isOperator) {
for (TheoryId currentTheory = THEORY_FIRST; currentTheory != THEORY_LAST; ++ currentTheory) {
d_newSetTags = Theory::setInsert(currentTheory, d_newSetTags);
d_newSetTriggers[currentTheory] = tId;
- }
+ }
// Add it to the list for backtracking
d_triggerTermSetUpdates.push_back(TriggerSetUpdate(tId, null_set_id));
d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
- // Mark the the new set as a trigger
+ // Mark the the new set as a trigger
d_nodeIndividualTrigger[tId] = newTriggerTermSet();
}
@@ -333,7 +333,7 @@ void EqualityEngine::addTermInternal(TNode t, bool isOperator) {
propagate();
Assert(hasTerm(t));
-
+
Debug("equality") << d_name << "::eq::addTermInternal(" << t << ") => " << result << std::endl;
}
@@ -419,12 +419,12 @@ void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason) {
Debug("equality::trigger") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ")" << std::endl;
assertEqualityInternal(eq, d_false, reason);
- propagate();
-
+ propagate();
+
if (d_done) {
return;
}
-
+
// If both have constant representatives, we don't notify anyone
EqualityNodeId a = getNodeId(eq[0]);
EqualityNodeId b = getNodeId(eq[1]);
@@ -432,8 +432,8 @@ void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason) {
EqualityNodeId bClassId = getEqualityNode(b).getFind();
if (d_isConstant[aClassId] && d_isConstant[bClassId]) {
return;
- }
-
+ }
+
// If we are adding a disequality, notify of the shared term representatives
EqualityNodeId eqId = getNodeId(eq);
TriggerTermSetRef aTriggerRef = d_nodeIndividualTrigger[aClassId];
@@ -443,16 +443,16 @@ void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason) {
// The sets of trigger terms
TriggerTermSet& aTriggerTerms = getTriggerTermSet(aTriggerRef);
TriggerTermSet& bTriggerTerms = getTriggerTermSet(bTriggerRef);
- // Go through and notify the shared dis-equalities
- Theory::Set aTags = aTriggerTerms.tags;
- Theory::Set bTags = bTriggerTerms.tags;
+ // Go through and notify the shared dis-equalities
+ Theory::Set aTags = aTriggerTerms.tags;
+ Theory::Set bTags = bTriggerTerms.tags;
TheoryId aTag = Theory::setPop(aTags);
TheoryId bTag = Theory::setPop(bTags);
int a_i = 0, b_i = 0;
while (aTag != THEORY_LAST && bTag != THEORY_LAST) {
if (aTag < bTag) {
aTag = Theory::setPop(aTags);
- ++ a_i;
+ ++ a_i;
} else if (aTag > bTag) {
bTag = Theory::setPop(bTags);
++ b_i;
@@ -499,7 +499,7 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << ")" << std::endl;
Assert(triggersFired.empty());
-
+
++ d_stats.mergesCount;
EqualityNodeId class1Id = class1.getFind();
@@ -539,8 +539,8 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
TaggedEqualitiesSet class1disequalitiesToNotify;
// Individual tags
- Theory::Set class1OnlyTags = Theory::setDifference(class1Tags, class2Tags);
- Theory::Set class2OnlyTags = Theory::setDifference(class2Tags, class1Tags);
+ Theory::Set class1OnlyTags = Theory::setDifference(class1Tags, class2Tags);
+ Theory::Set class2OnlyTags = Theory::setDifference(class2Tags, class1Tags);
// Only get disequalities if they are not both constant
if (!class1isConstant || !class2isConstant) {
@@ -590,9 +590,9 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): updating lookups of " << class2Id << std::endl;
do {
// Get the current node
- EqualityNode& currentNode = getEqualityNode(currentId);
+ EqualityNode& currentNode = getEqualityNode(currentId);
Debug("equality") << d_name << "::eq::merge(" << class1.getFind() << "," << class2.getFind() << "): updating lookups of node " << currentId << std::endl;
-
+
// Go through the uselist and check for congruences
UseListNodeId currentUseId = currentNode.getUseList();
while (currentUseId != null_uselist_id) {
@@ -604,7 +604,7 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
const FunctionApplication& fun = d_applications[useNode.getApplicationId()].normalized;
// If it's interpreted and we can interpret
if (fun.isInterpreted() && class1isConstant && !d_isInternal[currentId]) {
- // Get the actual term id
+ // Get the actual term id
TNode term = d_nodes[funId];
subtermEvaluates(getNodeId(term));
}
@@ -622,16 +622,16 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
// There is no representative, so we can add one, we remove this when backtracking
storeApplicationLookup(funNormalized, funId);
}
-
+
// Go to the next one in the use list
currentUseId = useNode.getNext();
}
-
+
// Move to the next node
currentId = currentNode.getNext();
} while (currentId != class2Id);
}
-
+
// Now merge the lists
class1.merge<true>(class2);
@@ -660,24 +660,24 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
// Get the triggers
TriggerTermSet& class1triggers = getTriggerTermSet(class1triggerRef);
TriggerTermSet& class2triggers = getTriggerTermSet(class2triggerRef);
-
+
// Initialize the merged set
d_newSetTags = Theory::setUnion(class1triggers.tags, class2triggers.tags);
d_newSetTriggersSize = 0;
-
+
int i1 = 0;
int i2 = 0;
Theory::Set tags1 = class1triggers.tags;
Theory::Set tags2 = class2triggers.tags;
TheoryId tag1 = Theory::setPop(tags1);
TheoryId tag2 = Theory::setPop(tags2);
-
+
// Comparing the THEORY_LAST is OK because all other theories are
// smaller, and will therefore be preferred
- while (tag1 != THEORY_LAST || tag2 != THEORY_LAST)
+ while (tag1 != THEORY_LAST || tag2 != THEORY_LAST)
{
if (tag1 < tag2) {
- // copy tag1
+ // copy tag1
d_newSetTriggers[d_newSetTriggersSize++] = class1triggers.triggers[i1++];
tag1 = Theory::setPop(tags1);
} else if (tag1 > tag2) {
@@ -685,7 +685,7 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
d_newSetTriggers[d_newSetTriggersSize++] = class2triggers.triggers[i2++];
tag2 = Theory::setPop(tags2);
} else {
- // copy tag1
+ // copy tag1
EqualityNodeId tag1id = d_newSetTriggers[d_newSetTriggersSize++] = class1triggers.triggers[i1++];
// since they are both tagged notify of merge
if (d_performNotify) {
@@ -698,17 +698,17 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
tag1 = Theory::setPop(tags1);
tag2 = Theory::setPop(tags2);
}
- }
-
+ }
+
// Add the new trigger set, if different from previous one
if (class1triggers.tags != class2triggers.tags) {
// Add it to the list for backtracking
d_triggerTermSetUpdates.push_back(TriggerSetUpdate(class1Id, class1triggerRef));
d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
- // Mark the the new set as a trigger
+ // Mark the the new set as a trigger
d_nodeIndividualTrigger[class1Id] = newTriggerTermSet();
- }
- }
+ }
+ }
}
// Everything fine
@@ -792,14 +792,14 @@ void EqualityEngine::backtrack() {
}
d_triggerTermSetUpdates.resize(d_triggerTermSetUpdatesSize);
}
-
+
if (d_equalityTriggers.size() > d_equalityTriggersCount) {
// Unlink the triggers from the lists
for (int i = d_equalityTriggers.size() - 1, i_end = d_equalityTriggersCount; i >= i_end; -- i) {
const Trigger& trigger = d_equalityTriggers[i];
d_nodeTriggers[trigger.classId] = trigger.nextTrigger;
}
- // Get rid of the triggers
+ // Get rid of the triggers
d_equalityTriggers.resize(d_equalityTriggersCount);
d_equalityTriggersOriginal.resize(d_equalityTriggersCount);
}
@@ -859,7 +859,7 @@ void EqualityEngine::backtrack() {
d_deducedDisequalityReasons.resize(d_deducedDisequalityReasonsSize);
d_deducedDisequalities.resize(d_deducedDisequalitiesSize);
}
-
+
}
void EqualityEngine::addGraphEdge(EqualityNodeId t1, EqualityNodeId t2, MergeReasonType type, TNode reason) {
@@ -892,7 +892,7 @@ std::string EqualityEngine::edgesToString(EqualityEdgeId edgeId) const {
return out.str();
}
-void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity, std::vector<TNode>& equalities) const {
+void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity, std::vector<TNode>& equalities, EqProof * eqp) const {
Debug("equality") << d_name << "::eq::explainEquality(" << t1 << ", " << t2 << ", " << (polarity ? "true" : "false") << ")" << std::endl;
// The terms must be there already
@@ -904,7 +904,7 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity, std::vec
if (polarity) {
// Get the explanation
- getExplanation(t1Id, t2Id, equalities);
+ getExplanation(t1Id, t2Id, equalities, eqp);
} else {
// Get the reason for this disequality
EqualityPair pair(t1Id, t2Id);
@@ -912,20 +912,20 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity, std::vec
DisequalityReasonRef reasonRef = d_disequalityReasonsMap.find(pair)->second;
for (unsigned i = reasonRef.mergesStart; i < reasonRef.mergesEnd; ++ i) {
EqualityPair toExplain = d_deducedDisequalityReasons[i];
- getExplanation(toExplain.first, toExplain.second, equalities);
+ getExplanation(toExplain.first, toExplain.second, equalities, eqp);
}
}
}
-void EqualityEngine::explainPredicate(TNode p, bool polarity, std::vector<TNode>& assertions) const {
+void EqualityEngine::explainPredicate(TNode p, bool polarity, std::vector<TNode>& assertions, EqProof * eqp) const {
Debug("equality") << d_name << "::eq::explainPredicate(" << p << ")" << std::endl;
// Must have the term
Assert(hasTerm(p));
// Get the explanation
- getExplanation(getNodeId(p), polarity ? d_trueId : d_falseId, assertions);
+ getExplanation(getNodeId(p), polarity ? d_trueId : d_falseId, assertions, eqp);
}
-void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, std::vector<TNode>& equalities) const {
+void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, std::vector<TNode>& equalities, EqProof * eqp) const {
Debug("equality") << d_name << "::eq::getExplanation(" << d_nodes[t1Id] << "," << d_nodes[t2Id] << ")" << std::endl;
@@ -933,17 +933,23 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
#ifdef CVC4_ASSERTIONS
bool canExplain = getEqualityNode(t1Id).getFind() == getEqualityNode(t2Id).getFind()
|| (d_done && isConstant(t1Id) && isConstant(t2Id));
-
+
if (!canExplain) {
Warning() << "Can't explain equality:" << std::endl;
Warning() << d_nodes[t1Id] << " with find " << d_nodes[getEqualityNode(t1Id).getFind()] << std::endl;
- Warning() << d_nodes[t2Id] << " with find " << d_nodes[getEqualityNode(t2Id).getFind()] << std::endl;
+ Warning() << d_nodes[t2Id] << " with find " << d_nodes[getEqualityNode(t2Id).getFind()] << std::endl;
}
Assert(canExplain);
#endif
// If the nodes are the same, we're done
- if (t1Id == t2Id) return;
+ if (t1Id == t2Id){
+ if( eqp ) {
+ eqp->d_node = d_nodes[t1Id];
+ }
+ return;
+ }
+
if (Debug.isOn("equality::internal")) {
debugPrintGraph();
@@ -986,6 +992,8 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
Debug("equality") << d_name << "::eq::getExplanation(): path found: " << std::endl;
+ std::vector< EqProof * > eqp_trans;
+
// Reconstruct the path
do {
// The current node
@@ -995,6 +1003,12 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
Debug("equality") << d_name << "::eq::getExplanation(): currentEdge = " << currentEdge << ", currentNode = " << currentNode << std::endl;
+ EqProof * eqpc = NULL;
+ //make child proof if a proof is being constructed
+ if( eqp ){
+ eqpc = new EqProof;
+ eqpc->d_id = reasonType;
+ }
// Add the actual equality to the vector
switch (reasonType) {
case MERGED_THROUGH_CONGRUENCE: {
@@ -1003,32 +1017,45 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
const FunctionApplication& f1 = d_applications[currentNode].original;
const FunctionApplication& f2 = d_applications[edgeNode].original;
Debug("equality") << push;
- getExplanation(f1.a, f2.a, equalities);
- getExplanation(f1.b, f2.b, equalities);
+ EqProof * eqpc1 = eqpc ? new EqProof : NULL;
+ getExplanation(f1.a, f2.a, equalities, eqpc1);
+ EqProof * eqpc2 = eqpc ? new EqProof : NULL;
+ getExplanation(f1.b, f2.b, equalities, eqpc2);
+ if( eqpc ){
+ eqpc->d_children.push_back( eqpc1 );
+ eqpc->d_children.push_back( eqpc2 );
+ }
Debug("equality") << pop;
break;
- }
+ }
case MERGED_THROUGH_EQUALITY:
// Construct the equality
Debug("equality") << d_name << "::eq::getExplanation(): adding: " << d_equalityEdges[currentEdge].getReason() << std::endl;
+ if( eqpc ){
+ eqpc->d_node = d_equalityEdges[currentEdge].getReason();
+ }
equalities.push_back(d_equalityEdges[currentEdge].getReason());
break;
case MERGED_THROUGH_REFLEXIVITY: {
- // x1 == x1
+ // x1 == x1
Debug("equality") << d_name << "::eq::getExplanation(): due to reflexivity, going deeper" << std::endl;
EqualityNodeId eqId = currentNode == d_trueId ? edgeNode : currentNode;
const FunctionApplication& eq = d_applications[eqId].original;
Assert(eq.isEquality(), "Must be an equality");
-
+
// Explain why a = b constant
Debug("equality") << push;
- getExplanation(eq.a, eq.b, equalities);
+ EqProof * eqpc1 = eqpc ? new EqProof : NULL;
+ getExplanation(eq.a, eq.b, equalities, eqpc1);
+ if( eqpc ){
+ eqpc->d_children.push_back( eqpc1 );
+ }
Debug("equality") << pop;
-
- break;
+
+ break;
}
case MERGED_THROUGH_CONSTANTS: {
- // f(c1, ..., cn) = c semantically, we can just ignore it
+ // f(c1, ..., cn) = c semantically, we can just ignore it
Debug("equality") << d_name << "::eq::getExplanation(): due to constants, explain the constants" << std::endl;
Debug("equality") << push;
@@ -1042,7 +1069,11 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
for (unsigned i = 0; i < interpreted.getNumChildren(); ++ i) {
EqualityNodeId childId = getNodeId(interpreted[i]);
Assert(isConstant(childId));
- getExplanation(childId, getEqualityNode(childId).getFind(), equalities);
+ EqProof * eqpcc = eqpc ? new EqProof : NULL;
+ getExplanation(childId, getEqualityNode(childId).getFind(), equalities, eqpcc);
+ if( eqpc ) {
+ eqpc->d_children.push_back( eqpcc );
+ }
}
Debug("equality") << pop;
@@ -1051,14 +1082,21 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
}
default:
Unreachable();
- }
-
+ }
+
// Go to the previous
currentEdge = bfsQueue[currentIndex].edgeId;
currentIndex = bfsQueue[currentIndex].previousIndex;
-
+
+ eqp_trans.push_back( eqpc );
+
} while (currentEdge != null_id);
+ if( eqp ){
+ eqp->d_id = MERGED_THROUGH_TRANS;
+ eqp->d_children.insert( eqp->d_children.end(), eqp_trans.begin(), eqp_trans.end() );
+ }
+
// Done
return;
}
@@ -1220,7 +1258,7 @@ void EqualityEngine::processEvaluationQueue() {
// Get the node
EqualityNodeId id = d_evaluationQueue.front();
d_evaluationQueue.pop();
-
+
// Replace the children with their representatives (must be constants)
Node nodeEvaluated = evaluateTerm(d_nodes[id]);
Debug("equality::evaluation") << d_name << "::eq::processEvaluationQueue(): " << d_nodes[id] << " evaluates to " << nodeEvaluated << std::endl;
@@ -1240,11 +1278,11 @@ void EqualityEngine::propagate() {
if (d_inPropagate) {
// We're already in propagate, go back
return;
- }
-
+ }
+
// Make sure we don't get in again
ScopedBool inPropagate(d_inPropagate, true);
-
+
Debug("equality") << d_name << "::eq::propagate()" << std::endl;
while (!d_propagationQueue.empty() || !d_evaluationQueue.empty()) {
@@ -1255,13 +1293,13 @@ void EqualityEngine::propagate() {
while (!d_evaluationQueue.empty()) d_evaluationQueue.pop();
continue;
}
-
+
// Process any evaluation requests
if (!d_evaluationQueue.empty()) {
processEvaluationQueue();
continue;
}
-
+
// The current merge candidate
const MergeCandidate current = d_propagationQueue.front();
d_propagationQueue.pop_front();
@@ -1288,7 +1326,7 @@ void EqualityEngine::propagate() {
// Add the actual equality to the equality graph
addGraphEdge(current.t1Id, current.t2Id, current.type, current.reason);
- // If constants are being merged we're done
+ // If constants are being merged we're done
if (d_isConstant[t1classId] && d_isConstant[t2classId]) {
// When merging constants we are inconsistent, hence done
d_done = true;
@@ -1462,7 +1500,7 @@ bool EqualityEngine::areDisequal(TNode t1, TNode t2, bool ensureProof) const
return true;
}
}
-
+
// Check the other equality itself if it exists
eq = t2.eqNode(t1);
if (hasTerm(eq)) {
@@ -1474,7 +1512,7 @@ bool EqualityEngine::areDisequal(TNode t1, TNode t2, bool ensureProof) const
return true;
}
}
-
+
// Create the equality
FunctionApplication eqNormalized(APP_EQUALITY, t1ClassId, t2ClassId);
ApplicationIdsMap::const_iterator find = d_applicationLookup.find(eqNormalized);
@@ -1492,7 +1530,7 @@ bool EqualityEngine::areDisequal(TNode t1, TNode t2, bool ensureProof) const
return true;
}
}
-
+
// Check the symmetric disequality
std::swap(eqNormalized.a, eqNormalized.b);
find = d_applicationLookup.find(eqNormalized);
@@ -1510,7 +1548,7 @@ bool EqualityEngine::areDisequal(TNode t1, TNode t2, bool ensureProof) const
return true;
}
}
-
+
// Couldn't deduce dis-equalityReturn whether the terms are disequal
return false;
}
@@ -1568,19 +1606,19 @@ void EqualityEngine::addTriggerTerm(TNode t, TheoryId tag)
// Initialize the new set for copy/insert
d_newSetTags = Theory::setInsert(tag, triggerSet.tags);
d_newSetTriggersSize = 0;
- // Copy into to new one, and insert the new tag/id
+ // Copy into to new one, and insert the new tag/id
unsigned i = 0;
Theory::Set tags = d_newSetTags;
- TheoryId current;
+ TheoryId current;
while ((current = Theory::setPop(tags)) != THEORY_LAST) {
// Remove from the tags
tags = Theory::setRemove(current, tags);
// Insert the id into the triggers
- d_newSetTriggers[d_newSetTriggersSize++] =
+ d_newSetTriggers[d_newSetTriggersSize++] =
current == tag ? eqNodeId : triggerSet.triggers[i++];
}
} else {
- // Setup a singleton
+ // Setup a singleton
d_newSetTags = Theory::setInsert(tag);
d_newSetTriggers[0] = eqNodeId;
d_newSetTriggersSize = 1;
@@ -1589,7 +1627,7 @@ void EqualityEngine::addTriggerTerm(TNode t, TheoryId tag)
// Add it to the list for backtracking
d_triggerTermSetUpdates.push_back(TriggerSetUpdate(classId, triggerSetRef));
d_triggerTermSetUpdatesSize = d_triggerTermSetUpdatesSize + 1;
- // Mark the the new set as a trigger
+ // Mark the the new set as a trigger
d_nodeIndividualTrigger[classId] = triggerSetRef = newTriggerTermSet();
// Propagate trigger term disequalities we remembered
@@ -1843,7 +1881,7 @@ void EqualityEngine::getDisequalities(bool allowConstants, EqualityNodeId classI
}
bool EqualityEngine::propagateTriggerTermDisequalities(Theory::Set tags, TriggerTermSetRef triggerSetRef, const TaggedEqualitiesSet& disequalitiesToNotify) {
-
+
// No tags, no food
if (!tags) {
return !d_done;
@@ -1852,14 +1890,14 @@ bool EqualityEngine::propagateTriggerTermDisequalities(Theory::Set tags, Trigger
Assert(triggerSetRef != null_set_id);
// This is the class trigger set
- const TriggerTermSet& triggerSet = getTriggerTermSet(triggerSetRef);
+ const TriggerTermSet& triggerSet = getTriggerTermSet(triggerSetRef);
// Go through the disequalities and notify
TaggedEqualitiesSet::const_iterator it = disequalitiesToNotify.begin();
TaggedEqualitiesSet::const_iterator it_end = disequalitiesToNotify.end();
for (; !d_done && it != it_end; ++ it) {
// The information about the equality that is asserted to false
const TaggedEquality& disequalityInfo = *it;
- const TriggerTermSet& disequalityTriggerSet = getTriggerTermSet(disequalityInfo.triggerSetRef);
+ const TriggerTermSet& disequalityTriggerSet = getTriggerTermSet(disequalityInfo.triggerSetRef);
Theory::Set commonTags = Theory::setIntersection(disequalityTriggerSet.tags, tags);
Assert(commonTags);
// This is the actual function
@@ -1897,7 +1935,7 @@ bool EqualityEngine::propagateTriggerTermDisequalities(Theory::Set tags, Trigger
}
}
}
-
+
return !d_done;
}
@@ -2005,6 +2043,25 @@ bool EqClassIterator::isFinished() const {
}
+void EqProof::debug_print( const char * c, unsigned tb ){
+ for( unsigned i=0; i<tb; i++ ) { Debug( c ) << " "; }
+ Debug( c ) << d_id << "(";
+ if( !d_children.empty() || !d_node.isNull() ){
+ if( !d_node.isNull() ){
+ Debug( c ) << std::endl;
+ for( unsigned i=0; i<tb+1; i++ ) { Debug( c ) << " "; }
+ Debug( c ) << d_node;
+ }
+ for( unsigned i=0; i<d_children.size(); i++ ){
+ if( i>0 || !d_node.isNull() ) Debug( c ) << ",";
+ std::cout << std::endl;
+ d_children[i]->debug_print( c, tb+1 );
+ }
+ }
+ Debug( c ) << ")";
+}
+
+
} // Namespace uf
} // Namespace theory
} // Namespace CVC4
diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h
index ab106bc8d..f8e361081 100644
--- a/src/theory/uf/equality_engine.h
+++ b/src/theory/uf/equality_engine.h
@@ -39,6 +39,8 @@ namespace CVC4 {
namespace theory {
namespace eq {
+
+class EqProof;
class EqClassesIterator;
class EqClassIterator;
@@ -421,35 +423,35 @@ private:
/**
* Map from ids of proper terms, to the number of non-constant direct subterms. If we update an interpreted
* application to a constant, we can decrease this value. If we hit 0, we can evaluate the term.
- *
+ *
*/
std::vector<unsigned> d_subtermsToEvaluate;
-
- /**
+
+ /**
* For nodes that we need to postpone evaluation.
*/
std::queue<EqualityNodeId> d_evaluationQueue;
-
+
/**
* Evaluate all terms in the evaluation queue.
*/
void processEvaluationQueue();
-
+
/** Vector of nodes that evaluate. */
std::vector<EqualityNodeId> d_subtermEvaluates;
/** Size of the nodes that evaluate vector. */
context::CDO<unsigned> d_subtermEvaluatesSize;
-
+
/** Set the node evaluate flag */
void subtermEvaluates(EqualityNodeId id);
/**
- * Returns the evaluation of the term when all (direct) children are replaced with
+ * Returns the evaluation of the term when all (direct) children are replaced with
* the constant representatives.
*/
Node evaluateTerm(TNode node);
-
+
/**
* Returns true if it's a constant
*/
@@ -487,7 +489,7 @@ private:
/** Enqueue to the propagation queue */
void enqueue(const MergeCandidate& candidate, bool back = true);
-
+
/** Do the propagation */
void propagate();
@@ -499,7 +501,7 @@ private:
* imply t1 = t2. Returns TNodes as the assertion equalities should be hashed somewhere
* else.
*/
- void getExplanation(EqualityEdgeId t1Id, EqualityNodeId t2Id, std::vector<TNode>& equalities) const;
+ void getExplanation(EqualityEdgeId t1Id, EqualityNodeId t2Id, std::vector<TNode>& equalities, EqProof * eqp) const;
/**
* Print the equality graph.
@@ -752,7 +754,7 @@ public:
void assertPredicate(TNode p, bool polarity, TNode reason);
/**
- * Adds predicate p and q and makes them equal.
+ * Adds predicate p and q and makes them equal.
*/
void mergePredicates(TNode p, TNode q, TNode reason);
@@ -782,14 +784,14 @@ public:
* Returns the reasons (added when asserting) that imply it
* in the assertions vector.
*/
- void explainEquality(TNode t1, TNode t2, bool polarity, std::vector<TNode>& assertions) const;
+ void explainEquality(TNode t1, TNode t2, bool polarity, std::vector<TNode>& assertions, EqProof * eqp = NULL) const;
/**
* Get an explanation of the predicate being true or false.
* Returns the reasons (added when asserting) that imply imply it
* in the assertions vector.
*/
- void explainPredicate(TNode p, bool polarity, std::vector<TNode>& assertions) const;
+ void explainPredicate(TNode p, bool polarity, std::vector<TNode>& assertions, EqProof * eqp = NULL) const;
/**
* Add term to the set of trigger terms with a corresponding tag. The notify class will get
@@ -890,6 +892,16 @@ public:
bool isFinished() const;
};/* class EqClassIterator */
+class EqProof
+{
+public:
+ EqProof() : d_id(MERGED_THROUGH_REFLEXIVITY){}
+ MergeReasonType d_id;
+ Node d_node;
+ std::vector< EqProof * > d_children;
+ void debug_print( const char * c, unsigned tb = 0 );
+};
+
} // Namespace eq
} // Namespace theory
} // Namespace CVC4
diff --git a/src/theory/uf/equality_engine_types.h b/src/theory/uf/equality_engine_types.h
index a36291974..435a1ece5 100644
--- a/src/theory/uf/equality_engine_types.h
+++ b/src/theory/uf/equality_engine_types.h
@@ -54,7 +54,7 @@ static const EqualityEdgeId null_edge = (EqualityEdgeId)(-1);
/**
* A reason for a merge. Either an equality x = y, a merge of two
- * function applications f(x1, x2), f(y1, y2) due to congruence,
+ * function applications f(x1, x2), f(y1, y2) due to congruence,
* or a merge of an equality to false due to both sides being
* (different) constants.
*/
@@ -67,6 +67,9 @@ enum MergeReasonType {
MERGED_THROUGH_REFLEXIVITY,
/** Equality was merged to false, due to both sides of equality being a constant */
MERGED_THROUGH_CONSTANTS,
+
+ /** (for proofs only) Equality was merged due to transitivity */
+ MERGED_THROUGH_TRANS,
};
inline std::ostream& operator << (std::ostream& out, MergeReasonType reason) {
@@ -83,6 +86,10 @@ inline std::ostream& operator << (std::ostream& out, MergeReasonType reason) {
case MERGED_THROUGH_CONSTANTS:
out << "constants disequal";
break;
+ // (for proofs only)
+ case MERGED_THROUGH_TRANS:
+ out << "transitivity";
+ break;
default:
Unreachable();
}
@@ -98,7 +105,7 @@ struct MergeCandidate {
MergeReasonType type;
TNode reason;
MergeCandidate(EqualityNodeId x, EqualityNodeId y, MergeReasonType type, TNode reason)
- : t1Id(x), t2Id(y), type(type), reason(reason)
+ : t1Id(x), t2Id(y), type(type), reason(reason)
{}
};
@@ -112,9 +119,9 @@ struct DisequalityReasonRef {
: mergesStart(mergesStart), mergesEnd(mergesEnd) {}
};
-/**
+/**
* We maintain uselist where a node appears in, and this is the node
- * of such a list.
+ * of such a list.
*/
class UseListNode {
@@ -150,12 +157,12 @@ public:
};
/**
- * Main class for representing nodes in the equivalence class. The
+ * Main class for representing nodes in the equivalence class. The
* nodes are a circular list, with the representative carrying the
* size. Each individual node carries with itself the uselist of
- * function applications it appears in and the list of asserted
+ * function applications it appears in and the list of asserted
* disequalities it belongs to. In order to get these lists one must
- * traverse the entire class and pick up all the individual lists.
+ * traverse the entire class and pick up all the individual lists.
*/
class EqualityNode {
@@ -180,7 +187,7 @@ public:
*/
EqualityNode(EqualityNodeId nodeId = null_id)
: d_size(1)
- , d_findId(nodeId)
+ , d_findId(nodeId)
, d_nextId(nodeId)
, d_useList(null_uselist_id)
{}
@@ -232,7 +239,7 @@ public:
/**
* Note that this node is used in a function application funId, or
- * a negatively asserted equality (dis-equality) with funId.
+ * a negatively asserted equality (dis-equality) with funId.
*/
template<typename memory_class>
void usedIn(EqualityNodeId funId, memory_class& memory) {
@@ -275,8 +282,8 @@ enum FunctionApplicationType {
/**
* Represents the function APPLY a b. If isEquality is true then it
- * represents the predicate (a = b). Note that since one can not
- * construct the equality over function terms, the equality and hash
+ * represents the predicate (a = b). Note that since one can not
+ * construct the equality over function terms, the equality and hash
* function below are still well defined.
*/
struct FunctionApplication {
diff --git a/src/theory/uf/options b/src/theory/uf/options
index cfa6e6c04..26f87da79 100644
--- a/src/theory/uf/options
+++ b/src/theory/uf/options
@@ -15,20 +15,14 @@ option ufssRegions /--disable-uf-ss-regions bool :default true
disable region-based method for discovering cliques and splits in uf strong solver
option ufssEagerSplits --uf-ss-eager-split bool :default false
add splits eagerly for uf strong solver
-option ufssColoringSat --uf-ss-coloring-sat bool :default false
- use coloring-based SAT heuristic for uf strong solver
option ufssTotality --uf-ss-totality bool :default false
always use totality axioms for enforcing cardinality constraints
option ufssTotalityLimited --uf-ss-totality-limited=N int :default -1
apply totality axioms, but only up to cardinality N (-1 == do not apply totality axioms, default)
-option ufssTotalityLazy --uf-ss-totality-lazy bool :default false
- apply totality axioms lazily
option ufssTotalitySymBreak --uf-ss-totality-sym-break bool :default false
apply symmetry breaking for totality axioms
option ufssAbortCardinality --uf-ss-abort-card=N int :default -1
tells the uf strong solver a cardinality to abort at (-1 == no limit, default)
-option ufssSmartSplits --uf-ss-smart-split bool :default false
- use smart splitting heuristic for uf strong solver
option ufssExplainedCliques --uf-ss-explained-cliques bool :default false
use explained clique lemmas for uf strong solver
option ufssSimpleCliques --uf-ss-simple-cliques bool :default true
diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp
index 1045c5a24..fd46ed7f4 100644
--- a/src/theory/uf/theory_uf.cpp
+++ b/src/theory/uf/theory_uf.cpp
@@ -178,10 +178,16 @@ void TheoryUF::explain(TNode literal, std::vector<TNode>& assumptions) {
// Do the work
bool polarity = literal.getKind() != kind::NOT;
TNode atom = polarity ? literal : literal[0];
+ eq::EqProof * eqp = d_proofEnabled ? new eq::EqProof : NULL;
if (atom.getKind() == kind::EQUAL || atom.getKind() == kind::IFF) {
- d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions);
+ d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions, eqp);
} else {
- d_equalityEngine.explainPredicate(atom, polarity, assumptions);
+ d_equalityEngine.explainPredicate(atom, polarity, assumptions, eqp);
+ }
+ //for now, just print debug
+ //TODO : send the proof outwards : d_out->conflict( lem, eqp );
+ if( eqp ){
+ eqp->debug_print("uf-pf");
}
}
@@ -462,6 +468,7 @@ void TheoryUF::computeCareGraph() {
}/* TheoryUF::computeCareGraph() */
void TheoryUF::conflict(TNode a, TNode b) {
+ //TODO: create EqProof at this level if d_proofEnabled = true
if (a.getKind() == kind::CONST_BOOLEAN) {
d_conflictNode = explain(a.iffNode(b));
} else {
diff --git a/src/theory/uf/theory_uf_model.cpp b/src/theory/uf/theory_uf_model.cpp
index 409b41e3f..3b59c1c58 100644
--- a/src/theory/uf/theory_uf_model.cpp
+++ b/src/theory/uf/theory_uf_model.cpp
@@ -346,23 +346,21 @@ void UfModelTreeGenerator::setValue( TheoryModel* m, Node n, Node v, bool ground
d_set_values[ isReq ? 1 : 0 ][ ground ? 1 : 0 ][n] = v;
if( optUsePartialDefaults() ){
if( !ground ){
- if (!options::fmfFullModelCheck()) {
- int defSize = (int)d_defaults.size();
- for( int i=0; i<defSize; i++ ){
- //for soundness, to allow variable order-independent function interpretations,
- // we must ensure that the intersection of all default terms
- // is also defined.
- //for example, if we have that f( e, a ) = ..., and f( b, e ) = ...,
- // then we must define f( b, a ).
- bool isGround;
- Node ni = getIntersection( m, n, d_defaults[i], isGround );
- if( !ni.isNull() ){
- //if the intersection exists, and is not already defined
- if( d_set_values[0][ isGround ? 1 : 0 ].find( ni )==d_set_values[0][ isGround ? 1 : 0 ].end() &&
- d_set_values[1][ isGround ? 1 : 0 ].find( ni )==d_set_values[1][ isGround ? 1 : 0 ].end() ){
- //use the current value
- setValue( m, ni, v, isGround, false );
- }
+ int defSize = (int)d_defaults.size();
+ for( int i=0; i<defSize; i++ ){
+ //for soundness, to allow variable order-independent function interpretations,
+ // we must ensure that the intersection of all default terms
+ // is also defined.
+ //for example, if we have that f( e, a ) = ..., and f( b, e ) = ...,
+ // then we must define f( b, a ).
+ bool isGround;
+ Node ni = getIntersection( m, n, d_defaults[i], isGround );
+ if( !ni.isNull() ){
+ //if the intersection exists, and is not already defined
+ if( d_set_values[0][ isGround ? 1 : 0 ].find( ni )==d_set_values[0][ isGround ? 1 : 0 ].end() &&
+ d_set_values[1][ isGround ? 1 : 0 ].find( ni )==d_set_values[1][ isGround ? 1 : 0 ].end() ){
+ //use the current value
+ setValue( m, ni, v, isGround, false );
}
}
}
diff --git a/src/theory/uf/theory_uf_strong_solver.cpp b/src/theory/uf/theory_uf_strong_solver.cpp
index 052b2f568..54a3075a1 100644
--- a/src/theory/uf/theory_uf_strong_solver.cpp
+++ b/src/theory/uf/theory_uf_strong_solver.cpp
@@ -428,12 +428,10 @@ void StrongSolverTheoryUF::SortModel::initialize( OutputChannel* out ){
void StrongSolverTheoryUF::SortModel::newEqClass( Node n ){
if( !d_conflict ){
if( d_regions_map.find( n )==d_regions_map.end() ){
- if( !options::ufssTotalityLazy() ){
- //must generate totality axioms for every cardinality we have allocated thus far
- for( std::map< int, Node >::iterator it = d_cardinality_literal.begin(); it != d_cardinality_literal.end(); ++it ){
- if( applyTotality( it->first ) ){
- addTotalityAxiom( n, it->first, &d_thss->getOutputChannel() );
- }
+ //must generate totality axioms for every cardinality we have allocated thus far
+ for( std::map< int, Node >::iterator it = d_cardinality_literal.begin(); it != d_cardinality_literal.end(); ++it ){
+ if( applyTotality( it->first ) ){
+ addTotalityAxiom( n, it->first, &d_thss->getOutputChannel() );
}
}
if( options::ufssTotality() ){
@@ -449,9 +447,6 @@ void StrongSolverTheoryUF::SortModel::newEqClass( Node n ){
d_regions_index = 0;
}
d_regions_map[n] = d_regions_index;
- if( options::ufssSmartSplits() ){
- setSplitScore( n, 0 );
- }
Debug("uf-ss") << "StrongSolverTheoryUF: New Eq Class " << n << std::endl;
Debug("uf-ss-debug") << d_regions_index << " " << (int)d_regions.size() << std::endl;
if( d_regions_index<d_regions.size() ){
@@ -634,18 +629,7 @@ void StrongSolverTheoryUF::SortModel::check( Theory::Effort level, OutputChannel
}
}
}
- if( applyTotality( d_cardinality ) ){
- //add totality axioms for all nodes that have not yet been equated to cardinality terms
- if( options::ufssTotalityLazy() ){ //this should always be true
- if( level==Theory::EFFORT_FULL ){
- for( NodeIntMap::iterator it = d_regions_map.begin(); it != d_regions_map.end(); ++it ){
- if( !options::ufssTotality() || d_regions_map[ (*it).first ]!=-1 ){
- addTotalityAxiom( (*it).first, d_cardinality, &d_thss->getOutputChannel() );
- }
- }
- }
- }
- }else{
+ if( !applyTotality( d_cardinality ) ){
//do splitting on demand
bool addedLemma = false;
if( level==Theory::EFFORT_FULL || options::ufssEagerSplits() ){
@@ -1073,7 +1057,7 @@ void StrongSolverTheoryUF::SortModel::allocateCardinality( OutputChannel* out ){
//out->propagateAsDecision( lem[0] );
d_thss->d_statistics.d_max_model_size.maxAssign( d_aloc_cardinality );
- if( applyTotality( d_aloc_cardinality ) && !options::ufssTotalityLazy() ){
+ if( applyTotality( d_aloc_cardinality ) ){
//must send totality axioms for each existing term
for( NodeIntMap::iterator it = d_regions_map.begin(); it != d_regions_map.end(); ++it ){
addTotalityAxiom( (*it).first, d_aloc_cardinality, &d_thss->getOutputChannel() );
@@ -1085,27 +1069,11 @@ void StrongSolverTheoryUF::SortModel::allocateCardinality( OutputChannel* out ){
int StrongSolverTheoryUF::SortModel::addSplit( Region* r, OutputChannel* out ){
Node s;
if( r->hasSplits() ){
- if( !options::ufssSmartSplits() ){
- //take the first split you find
- for( NodeBoolMap::iterator it = r->d_splits.begin(); it != r->d_splits.end(); ++it ){
- if( (*it).second ){
- s = (*it).first;
- break;
- }
- }
- }else{
- int maxScore = -1;
- std::vector< Node > splits;
- for( NodeBoolMap::iterator it = r->d_splits.begin(); it != r->d_splits.end(); ++it ){
- if( (*it).second ){
- int score1 = d_split_score[ (*it).first[0] ];
- int score2 = d_split_score[ (*it).first[1] ];
- int score = score1<score2 ? score1 : score2;
- if( score>maxScore ){
- maxScore = -1;
- s = (*it).first;
- }
- }
+ //take the first split you find
+ for( NodeBoolMap::iterator it = r->d_splits.begin(); it != r->d_splits.end(); ++it ){
+ if( (*it).second ){
+ s = (*it).first;
+ break;
}
}
Assert( s!=Node::null() );
@@ -1338,6 +1306,21 @@ void StrongSolverTheoryUF::SortModel::addTotalityAxiom( Node n, int cardinality,
d_sym_break_terms[n.getType()][sort_id].push_back( n );
d_sym_break_index[n] = use_cardinality;
Trace("uf-ss-totality") << "Allocate symmetry breaking term " << n << ", index = " << use_cardinality << std::endl;
+ if( d_sym_break_terms[n.getType()][sort_id].size()>1 ){
+ //enforce canonicity
+ for( int i=2; i<use_cardinality; i++ ){
+ //can only be assigned to domain constant d if someone has been assigned domain constant d-1
+ Node eq = n.eqNode( getTotalityLemmaTerm( cardinality, i ) );
+ std::vector< Node > eqs;
+ for( unsigned j=0; j<(d_sym_break_terms[n.getType()][sort_id].size()-1); j++ ){
+ eqs.push_back( d_sym_break_terms[n.getType()][sort_id][j].eqNode( getTotalityLemmaTerm( cardinality, i-1 ) ) );
+ }
+ Node ax = NodeManager::currentNM()->mkNode( OR, eqs );
+ Node lem = NodeManager::currentNM()->mkNode( IMPLIES, eq, ax );
+ Trace("uf-ss-lemma") << "*** Add (canonicity) totality axiom " << lem << std::endl;
+ d_thss->getOutputChannel().lemma( lem );
+ }
+ }
}
}
@@ -1459,11 +1442,6 @@ Node StrongSolverTheoryUF::SortModel::getCardinalityLiteral( int c ) {
StrongSolverTheoryUF::StrongSolverTheoryUF(context::Context* c, context::UserContext* u, OutputChannel& out, TheoryUF* th) :
d_out( &out ), d_th( th ), d_conflict( c, false ), d_rep_model(), d_aloc_com_card( u, 0 ), d_com_card_assertions( c )
{
- if( options::ufssColoringSat() ){
- d_term_amb = new TermDisambiguator( th->getQuantifiersEngine(), c );
- }else{
- d_term_amb = NULL;
- }
if( options::ufssDiseqPropagation() ){
d_deq_prop = new DisequalityPropagator( th->getQuantifiersEngine(), this );
}else{
@@ -1499,6 +1477,7 @@ void StrongSolverTheoryUF::newEqClass( Node n ){
if( options::ufssSymBreak() ){
d_sym_break->newEqClass( n );
}
+ Trace("uf-ss-solver") << "StrongSolverTheoryUF: Done New eq class." << std::endl;
}
}
@@ -1508,6 +1487,7 @@ void StrongSolverTheoryUF::merge( Node a, Node b ){
if( c ){
Trace("uf-ss-solver") << "StrongSolverTheoryUF: Merge " << a << " " << b << " : " << a.getType() << std::endl;
c->merge( a, b );
+ Trace("uf-ss-solver") << "StrongSolverTheoryUF: Done Merge." << std::endl;
}else{
if( options::ufssDiseqPropagation() ){
d_deq_prop->merge(a, b);
@@ -1523,6 +1503,7 @@ void StrongSolverTheoryUF::assertDisequal( Node a, Node b, Node reason ){
//Assert( d_th->d_equalityEngine.getRepresentative( a )==a );
//Assert( d_th->d_equalityEngine.getRepresentative( b )==b );
c->assertDisequal( a, b, reason );
+ Trace("uf-ss-solver") << "StrongSolverTheoryUF: Done Assert disequal." << std::endl;
}else{
if( options::ufssDiseqPropagation() ){
d_deq_prop->assertDisequal(a, b, reason);
@@ -1610,13 +1591,6 @@ void StrongSolverTheoryUF::check( Theory::Effort level ){
if( level==Theory::EFFORT_FULL ){
debugPrint( "uf-ss-debug" );
}
- if( !d_conflict && level==Theory::EFFORT_FULL && options::ufssColoringSat() ){
- int lemmas = d_term_amb->disambiguateTerms( d_out );
- d_statistics.d_disamb_term_lemmas += lemmas;
- if( lemmas>=0 ){
- return;
- }
- }
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
it->second->check( level, d_out );
if( it->second->isConflict() ){
@@ -1628,11 +1602,6 @@ void StrongSolverTheoryUF::check( Theory::Effort level ){
if( !d_conflict && options::ufssSymBreak() ){
d_sym_break->check( level );
}
- //disambiguate terms if necessary
- //if( !d_conflict && level==Theory::EFFORT_FULL && options::ufssColoringSat() ){
- // Assert( d_term_amb!=NULL );
- // d_statistics.d_disamb_term_lemmas += d_term_amb->disambiguateTerms( d_out );
- //}
Trace("uf-ss-solver") << "Done StrongSolverTheoryUF: check " << level << std::endl;
}
}
@@ -1900,76 +1869,6 @@ StrongSolverTheoryUF::Statistics::~Statistics(){
}
-int TermDisambiguator::disambiguateTerms( OutputChannel* out ){
- Debug("uf-ss-disamb") << "Disambiguate terms." << std::endl;
- int lemmaAdded = 0;
- //otherwise, determine ambiguous pairs of ground terms for relevant sorts
- quantifiers::TermDb* db = d_qe->getTermDatabase();
- for( std::map< Node, std::vector< Node > >::iterator it = db->d_op_map.begin(); it != db->d_op_map.end(); ++it ){
- Debug("uf-ss-disamb") << "Check " << it->first << std::endl;
- if( it->second.size()>1 ){
- if(involvesRelevantType( it->second[0] ) ){
- for( int i=0; i<(int)it->second.size(); i++ ){
- for( int j=(i+1); j<(int)it->second.size(); j++ ){
- Kind knd = it->second[i].getType()==NodeManager::currentNM()->booleanType() ? IFF : EQUAL;
- Node eq = NodeManager::currentNM()->mkNode( knd, it->second[i], it->second[j] );
- eq = Rewriter::rewrite(eq);
- //determine if they are ambiguous
- if( d_term_amb.find( eq )==d_term_amb.end() ){
- Debug("uf-ss-disamb") << "Check disambiguate " << it->second[i] << " " << it->second[j] << std::endl;
- d_term_amb[ eq ] = true;
- //if they are equal
- if( d_qe->getEqualityQuery()->areEqual( it->second[i], it->second[j] ) ){
- d_term_amb[ eq ] = false;
- }else{
- //if an argument is disequal, then they are not ambiguous
- for( int k=0; k<(int)it->second[i].getNumChildren(); k++ ){
- if( d_qe->getEqualityQuery()->areDisequal( it->second[i][k], it->second[j][k] ) ){
- d_term_amb[ eq ] = false;
- break;
- }
- }
- }
- if( d_term_amb[ eq ] ){
- Debug("uf-ss-disamb") << "Disambiguate " << it->second[i] << " " << it->second[j] << std::endl;
- //must add lemma
- std::vector< Node > children;
- children.push_back( eq );
- for( int k=0; k<(int)it->second[i].getNumChildren(); k++ ){
- Kind knd2 = it->second[i][k].getType()==NodeManager::currentNM()->booleanType() ? IFF : EQUAL;
- Node eqc = NodeManager::currentNM()->mkNode( knd2, it->second[i][k], it->second[j][k] );
- children.push_back( eqc.notNode() );
- }
- Assert( children.size()>1 );
- Node lem = NodeManager::currentNM()->mkNode( OR, children );
- Trace( "uf-ss-lemma" ) << "*** Disambiguate lemma : " << lem << std::endl;
- //Notice() << "*** Disambiguate lemma : " << lem << std::endl;
- out->lemma( lem );
- d_term_amb[ eq ] = false;
- lemmaAdded++;
- return lemmaAdded;
- }
- }
- }
- }
- }
- }
- }
- Debug("uf-ss-disamb") << "Done disambiguate terms. " << lemmaAdded << std::endl;
- return lemmaAdded;
-}
-
-bool TermDisambiguator::involvesRelevantType( Node n ){
- if( n.getKind()==APPLY_UF ){
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( n[i].getType().isSort() ){
- return true;
- }
- }
- }
- return false;
-}
-
DisequalityPropagator::DisequalityPropagator(QuantifiersEngine* qe, StrongSolverTheoryUF* ufss) :
d_qe(qe), d_ufss(ufss){
d_true = NodeManager::currentNM()->mkConst( true );
diff --git a/src/theory/uf/theory_uf_strong_solver.h b/src/theory/uf/theory_uf_strong_solver.h
index 4f41ebf2e..51783c1e3 100644
--- a/src/theory/uf/theory_uf_strong_solver.h
+++ b/src/theory/uf/theory_uf_strong_solver.h
@@ -37,7 +37,6 @@ class SubsortSymmetryBreaker;
namespace uf {
class TheoryUF;
-class TermDisambiguator;
class DisequalityPropagator;
class StrongSolverTheoryUF{
@@ -45,8 +44,6 @@ protected:
typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
- typedef context::CDChunkList<Node> NodeList;
- typedef context::CDList<bool> BoolList;
typedef context::CDHashMap<TypeNode, bool, TypeNodeHashFunction> TypeNodeBoolMap;
public:
/** information for incremental conflict/clique finding for a particular sort */
@@ -320,8 +317,6 @@ private:
/** check */
void checkCombinedCardinality();
private:
- /** term disambiguator */
- TermDisambiguator* d_term_amb;
/** disequality propagator */
DisequalityPropagator* d_deq_prop;
/** symmetry breaking techniques */
@@ -331,8 +326,6 @@ public:
~StrongSolverTheoryUF() {}
/** get theory */
TheoryUF* getTheory() { return d_th; }
- /** term disambiguator */
- TermDisambiguator* getTermDisambiguator() { return d_term_amb; }
/** disequality propagator */
DisequalityPropagator* getDisequalityPropagator() { return d_deq_prop; }
/** symmetry breaker */
@@ -401,23 +394,6 @@ public:
Statistics d_statistics;
};/* class StrongSolverTheoryUF */
-
-class TermDisambiguator
-{
-private:
- /** quantifiers engine */
- QuantifiersEngine* d_qe;
- /** whether two terms are ambiguous (indexed by equalities) */
- context::CDHashMap<Node, bool, NodeHashFunction> d_term_amb;
- /** involves relevant type */
- static bool involvesRelevantType( Node n );
-public:
- TermDisambiguator( QuantifiersEngine* qe, context::Context* c ) : d_qe( qe ), d_term_amb( c ){}
- ~TermDisambiguator(){}
- /** check ambiguous terms */
- int disambiguateTerms( OutputChannel* out );
-};
-
class DisequalityPropagator
{
private:
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback