summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am6
-rw-r--r--src/options/sets_options6
-rw-r--r--src/parser/cvc/Cvc.g47
-rw-r--r--src/printer/cvc/cvc_printer.cpp20
-rw-r--r--src/smt/smt_engine.cpp4
-rw-r--r--src/theory/sets/card_unused_implementation.cpp312
-rw-r--r--src/theory/sets/expr_patterns.h63
-rw-r--r--src/theory/sets/kinds16
-rw-r--r--src/theory/sets/normal_form.h25
-rw-r--r--src/theory/sets/rels_utils.h96
-rw-r--r--src/theory/sets/scrutinize.h73
-rw-r--r--src/theory/sets/term_info.h69
-rw-r--r--src/theory/sets/theory_sets.cpp6
-rw-r--r--src/theory/sets/theory_sets.h3
-rw-r--r--src/theory/sets/theory_sets_private.cpp3995
-rw-r--r--src/theory/sets/theory_sets_private.h298
-rw-r--r--src/theory/sets/theory_sets_rels.cpp1907
-rw-r--r--src/theory/sets/theory_sets_rels.h260
-rw-r--r--src/theory/sets/theory_sets_rewriter.cpp478
-rw-r--r--src/theory/sets/theory_sets_rewriter.h4
-rw-r--r--src/theory/sets/theory_sets_type_rules.h93
21 files changed, 4406 insertions, 3375 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index f5e3776e5..6117ca057 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -259,10 +259,7 @@ libcvc4_la_SOURCES = \
theory/datatypes/theory_datatypes.cpp \
theory/datatypes/datatypes_sygus.h \
theory/datatypes/datatypes_sygus.cpp \
- theory/sets/expr_patterns.h \
theory/sets/normal_form.h \
- theory/sets/scrutinize.h \
- theory/sets/term_info.h \
theory/sets/theory_sets.cpp \
theory/sets/theory_sets.h \
theory/sets/theory_sets_private.cpp \
@@ -271,6 +268,9 @@ libcvc4_la_SOURCES = \
theory/sets/theory_sets_rewriter.h \
theory/sets/theory_sets_type_enumerator.h \
theory/sets/theory_sets_type_rules.h \
+ theory/sets/theory_sets_rels.cpp \
+ theory/sets/theory_sets_rels.h \
+ theory/sets/rel_utils.h \
theory/strings/theory_strings.h \
theory/strings/theory_strings.cpp \
theory/strings/theory_strings_rewriter.h \
diff --git a/src/options/sets_options b/src/options/sets_options
index be945e4c9..4c019c039 100644
--- a/src/options/sets_options
+++ b/src/options/sets_options
@@ -17,12 +17,12 @@ expert-option setsCare1 --sets-care1 bool :default false
option setsPropFull --sets-prop-full bool :default true
additional propagation at full effort
-option setsAggRewrite --sets-agg-rewrite bool :default false
- aggressive sets rewriting
-
option setsGuessEmpty --sets-guess-empty int :default 0
when to guess leaf nodes being empty (0...2 : most aggressive..least aggressive)
option setsSlowLemmas --sets-slow-lemmas bool :default true
+option setsInferAsLemmas --sets-infer-as-lemmas bool :default true
+ send inferences as lemmas
+
endmodule
diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g
index 4c0516eb6..e6d7f9d86 100644
--- a/src/parser/cvc/Cvc.g
+++ b/src/parser/cvc/Cvc.g
@@ -109,6 +109,8 @@ tokens {
SUBTYPE_TOK = 'SUBTYPE';
SET_TOK = 'SET';
+
+ TUPLE_TOK = 'TUPLE';
FORALL_TOK = 'FORALL';
EXISTS_TOK = 'EXISTS';
@@ -201,6 +203,12 @@ tokens {
BVSGT_TOK = 'BVSGT';
BVSLE_TOK = 'BVSLE';
BVSGE_TOK = 'BVSGE';
+
+ // Relations
+ JOIN_TOK = 'JOIN';
+ TRANSPOSE_TOK = 'TRANSPOSE';
+ PRODUCT_TOK = 'PRODUCT';
+ TRANSCLOSURE_TOK = 'TCLOSURE';
// Strings
@@ -307,9 +315,14 @@ int getOperatorPrecedence(int type) {
case STAR_TOK:
case INTDIV_TOK:
case DIV_TOK:
+ case TUPLE_TOK:
case MOD_TOK: return 23;
case PLUS_TOK:
- case MINUS_TOK: return 24;
+ case MINUS_TOK:
+ case JOIN_TOK:
+ case TRANSPOSE_TOK:
+ case PRODUCT_TOK:
+ case TRANSCLOSURE_TOK: return 24;
case LEQ_TOK:
case LT_TOK:
case GEQ_TOK:
@@ -346,6 +359,9 @@ Kind getOperatorKind(int type, bool& negate) {
case OR_TOK: return kind::OR;
case XOR_TOK: return kind::XOR;
case AND_TOK: return kind::AND;
+
+ case PRODUCT_TOK: return kind::PRODUCT;
+ case JOIN_TOK: return kind::JOIN;
// comparisonBinop
case EQUAL_TOK: return kind::EQUAL;
@@ -1222,8 +1238,8 @@ restrictedTypePossiblyFunctionLHS[CVC4::Type& t,
| ARRAY_TOK restrictedType[t,check] OF_TOK restrictedType[t2,check]
{ t = EXPR_MANAGER->mkArrayType(t, t2); }
| SET_TOK OF_TOK restrictedType[t,check]
- { t = EXPR_MANAGER->mkSetType(t); }
-
+ { t = EXPR_MANAGER->mkSetType(t); }
+
/* subtypes */
| SUBTYPE_TOK LPAREN
/* A bit tricky: this LAMBDA expression cannot refer to constants
@@ -1472,6 +1488,8 @@ booleanBinop[unsigned& op]
| OR_TOK
| XOR_TOK
| AND_TOK
+ | JOIN_TOK
+ | PRODUCT_TOK
;
comparison[CVC4::Expr& f]
@@ -1651,6 +1669,20 @@ bvNegTerm[CVC4::Expr& f]
/* BV neg */
: BVNEG_TOK bvNegTerm[f]
{ f = MK_EXPR(CVC4::kind::BITVECTOR_NOT, f); }
+ | TRANSPOSE_TOK bvNegTerm[f]
+ { f = MK_EXPR(CVC4::kind::TRANSPOSE, f); }
+ | TRANSCLOSURE_TOK bvNegTerm[f]
+ { f = MK_EXPR(CVC4::kind::TCLOSURE, f); }
+ | TUPLE_TOK LPAREN bvNegTerm[f] RPAREN
+ { std::vector<Type> types;
+ std::vector<Expr> args;
+ args.push_back(f);
+ types.push_back(f.getType());
+ DatatypeType t = EXPR_MANAGER->mkTupleType(types);
+ const Datatype& dt = t.getDatatype();
+ args.insert( args.begin(), dt[0].getConstructor() );
+ f = MK_EXPR(kind::APPLY_CONSTRUCTOR, args);
+ }
| postfixTerm[f]
;
@@ -1969,8 +2001,8 @@ simpleTerm[CVC4::Expr& f]
Type t, t2;
}
/* if-then-else */
- : iteTerm[f]
-
+ : iteTerm[f]
+
/* parenthesized sub-formula / tuple literals */
| LPAREN formula[f] { args.push_back(f); }
( COMMA formula[f] { args.push_back(f); } )* RPAREN
@@ -1987,14 +2019,15 @@ simpleTerm[CVC4::Expr& f]
args.insert( args.begin(), dt[0].getConstructor() );
f = MK_EXPR(kind::APPLY_CONSTRUCTOR, args);
}
- }
+ }
/* empty tuple literal */
| LPAREN RPAREN
{ std::vector<Type> types;
DatatypeType t = EXPR_MANAGER->mkTupleType(types);
const Datatype& dt = t.getDatatype();
- f = MK_EXPR(kind::APPLY_CONSTRUCTOR, dt[0].getConstructor()); }
+ f = MK_EXPR(kind::APPLY_CONSTRUCTOR, dt[0].getConstructor()); }
+
/* empty record literal */
| PARENHASH HASHPAREN
{ DatatypeType t = EXPR_MANAGER->mkRecordType(std::vector< std::pair<std::string, Type> >());
diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp
index d09290db5..550f87081 100644
--- a/src/printer/cvc/cvc_printer.cpp
+++ b/src/printer/cvc/cvc_printer.cpp
@@ -355,7 +355,9 @@ void CvcPrinter::toStream(std::ostream& out, TNode n, int depth, bool types, boo
case kind::APPLY_CONSTRUCTOR: {
TypeNode t = n.getType();
if( t.isTuple() ){
- //no-op
+ if( n.getNumChildren()==1 ){
+ out << "TUPLE";
+ }
}else if( t.isRecord() ){
const Record& rec = t.getRecord();
out << "(# ";
@@ -768,6 +770,22 @@ void CvcPrinter::toStream(std::ostream& out, TNode n, int depth, bool types, boo
op << "IS_IN";
opType = INFIX;
break;
+ case kind::PRODUCT:
+ op << "PRODUCT";
+ opType = INFIX;
+ break;
+ case kind::JOIN:
+ op << "JOIN";
+ opType = INFIX;
+ break;
+ case kind::TRANSPOSE:
+ op << "TRANSPOSE";
+ opType = PREFIX;
+ break;
+ case kind::TCLOSURE:
+ op << "TCLOSURE";
+ opType = PREFIX;
+ break;
case kind::SINGLETON:
out << "{";
toStream(out, n[0], depth, types, false);
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index 19bc85e3e..f288c6c0a 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -1926,7 +1926,8 @@ void SmtEngine::setDefaults() {
//until bugs 371,431 are fixed
if( ! options::minisatUseElim.wasSetByUser()){
- if( d_logic.isQuantified() || options::produceModels() || options::produceAssignments() || options::checkModels() ){
+ //AJR: cannot use minisat elim for new implementation of sets TODO: why?
+ if( d_logic.isTheoryEnabled(THEORY_SETS) || d_logic.isQuantified() || options::produceModels() || options::produceAssignments() || options::checkModels() ){
options::minisatUseElim.set( false );
}
}
@@ -5467,3 +5468,4 @@ void SmtEngine::setReplayStream(ExprStream* replayStream) {
}
}/* CVC4 namespace */
+
diff --git a/src/theory/sets/card_unused_implementation.cpp b/src/theory/sets/card_unused_implementation.cpp
deleted file mode 100644
index 488ee1026..000000000
--- a/src/theory/sets/card_unused_implementation.cpp
+++ /dev/null
@@ -1,312 +0,0 @@
-// Removing old cardinality implementation, dumping it here.
-
-///////////////////////////////////////////////////////////////
-// Commenting out processCard, creates confusion when writing
-// processCard2
-///////////////////////////////////////////////////////////////
-
-
-// void TheorySetsPrivate::processCard(Theory::Effort level) {
-// if(level != Theory::EFFORT_FULL) return;
-
-
-// Trace("sets-card") << "[sets-card] processCard( " << level << ")" << std::endl;
-// Trace("sets-card") << "[sets-card] # processed terms = " << d_processedCardTerms.size() << std::endl;
-// Trace("sets-card") << "[sets-card] # processed pairs = " << d_processedCardPairs.size() << std::endl;
-// NodeManager* nm = NodeManager::currentNM();
-
-// bool newLemmaGenerated = false;
-
-// // Introduce lemma
-// for(typeof(d_cardTerms.begin()) it = d_cardTerms.begin();
-// it != d_cardTerms.end(); ++it) {
-
-// for(eq::EqClassIterator j(d_equalityEngine.getRepresentative((*it)[0]), &d_equalityEngine);
-// !j.isFinished(); ++j) {
-
-// Node n = nm->mkNode(kind::CARD, (*j));
-
-// if(d_processedCardTerms.find(n) != d_processedCardTerms.end()) {
-// continue;
-// }
-
-// Trace("sets-card") << "[sets-card] Processing " << n << " in eq cl of " << (*it) << std::endl;
-
-// newLemmaGenerated = true;
-// d_processedCardTerms.insert(n);
-
-// Kind k = n[0].getKind();
-
-// if(k == kind::SINGLETON) {
-// d_external.d_out->lemma(nm->mkNode(kind::EQUAL,
-// n,
-// nm->mkConst(Rational(1))));
-// continue;
-// } else {
-// d_external.d_out->lemma(nm->mkNode(kind::GEQ,
-// n,
-// nm->mkConst(Rational(0))));
-// }
-
-// // rest of the processing is for compound terms
-// if(k != kind::UNION && k != kind::INTERSECTION && k != kind::SETMINUS) {
-// continue;
-// }
-
-// Node s = min(n[0][0], n[0][1]);
-// Node t = max(n[0][0], n[0][1]);
-// bool isUnion = (k == kind::UNION);
-// Assert(Rewriter::rewrite(s) == s);
-// Assert(Rewriter::rewrite(t) == t);
-
-// typeof(d_processedCardPairs.begin()) processedInfo = d_processedCardPairs.find(make_pair(s, t));
-
-// if(processedInfo == d_processedCardPairs.end()) {
-
-// Node sNt = nm->mkNode(kind::INTERSECTION, s, t);
-// sNt = Rewriter::rewrite(sNt);
-// Node sMt = nm->mkNode(kind::SETMINUS, s, t);
-// sMt = Rewriter::rewrite(sMt);
-// Node tMs = nm->mkNode(kind::SETMINUS, t, s);
-// tMs = Rewriter::rewrite(tMs);
-
-// Node card_s = nm->mkNode(kind::CARD, s);
-// Node card_t = nm->mkNode(kind::CARD, t);
-// Node card_sNt = nm->mkNode(kind::CARD, sNt);
-// Node card_sMt = nm->mkNode(kind::CARD, sMt);
-// Node card_tMs = nm->mkNode(kind::CARD, tMs);
-
-// Node lem;
-
-// // for s
-// lem = nm->mkNode(kind::EQUAL,
-// card_s,
-// nm->mkNode(kind::PLUS, card_sNt, card_sMt));
-// d_external.d_out->lemma(lem);
-
-// // for t
-// lem = nm->mkNode(kind::EQUAL,
-// card_t,
-// nm->mkNode(kind::PLUS, card_sNt, card_tMs));
-
-// d_external.d_out->lemma(lem);
-
-// // for union
-// if(isUnion) {
-// lem = nm->mkNode(kind::EQUAL,
-// n, // card(s union t)
-// nm->mkNode(kind::PLUS, card_sNt, card_sMt, card_tMs));
-// d_external.d_out->lemma(lem);
-// }
-
-// d_processedCardPairs.insert(make_pair(make_pair(s, t), isUnion));
-
-// } else if(isUnion && processedInfo->second == false) {
-
-// Node sNt = nm->mkNode(kind::INTERSECTION, s, t);
-// sNt = Rewriter::rewrite(sNt);
-// Node sMt = nm->mkNode(kind::SETMINUS, s, t);
-// sMt = Rewriter::rewrite(sMt);
-// Node tMs = nm->mkNode(kind::SETMINUS, t, s);
-// tMs = Rewriter::rewrite(tMs);
-
-// Node card_s = nm->mkNode(kind::CARD, s);
-// Node card_t = nm->mkNode(kind::CARD, t);
-// Node card_sNt = nm->mkNode(kind::CARD, sNt);
-// Node card_sMt = nm->mkNode(kind::CARD, sMt);
-// Node card_tMs = nm->mkNode(kind::CARD, tMs);
-
-// Assert(Rewriter::rewrite(n[0]) == n[0]);
-
-// Node lem = nm->mkNode(kind::EQUAL,
-// n, // card(s union t)
-// nm->mkNode(kind::PLUS, card_sNt, card_sMt, card_tMs));
-// d_external.d_out->lemma(lem);
-
-// processedInfo->second = true;
-// }
-
-// }//equivalence class loop
-
-// }//d_cardTerms loop
-
-// if(newLemmaGenerated) {
-// Trace("sets-card") << "[sets-card] New introduce done. Returning." << std::endl;
-// return;
-// }
-
-
-
-// // Leaves disjoint lemmas
-// buildGraph();
-
-// // Leaves disjoint lemmas
-// for(typeof(leaves.begin()) it = leaves.begin(); it != leaves.end(); ++it) {
-// TNode l1 = (*it);
-// if(d_equalityEngine.getRepresentative(l1).getKind() == kind::EMPTYSET) continue;
-// for(typeof(leaves.begin()) jt = leaves.begin(); jt != leaves.end(); ++jt) {
-// TNode l2 = (*jt);
-
-// if(d_equalityEngine.getRepresentative(l2).getKind() == kind::EMPTYSET) continue;
-
-// if( l1 == l2 ) continue;
-
-// Node l1_inter_l2 = nm->mkNode(kind::INTERSECTION, min(l1, l2), max(l1, l2));
-// l1_inter_l2 = Rewriter::rewrite(l1_inter_l2);
-// Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType(l1_inter_l2.getType())));
-// if(d_equalityEngine.hasTerm(l1_inter_l2) &&
-// d_equalityEngine.hasTerm(emptySet) &&
-// d_equalityEngine.areEqual(l1_inter_l2, emptySet)) {
-// Debug("sets-card-graph") << "[sets-card-graph] Disjoint (asserted): " << l1 << " and " << l2 << std::endl;
-// continue; // known to be disjoint
-// }
-
-// std::set<TNode> l1_ancestors = getReachable(edgesBk, l1);
-// std::set<TNode> l2_ancestors = getReachable(edgesBk, l2);
-
-// // have a disjoint edge
-// bool loop = true;
-// bool equality = false;
-// for(typeof(l1_ancestors.begin()) l1_it = l1_ancestors.begin();
-// l1_it != l1_ancestors.end() && loop; ++l1_it) {
-// for(typeof(l2_ancestors.begin()) l2_it = l2_ancestors.begin();
-// l2_it != l2_ancestors.end() && loop; ++l2_it) {
-// TNode n1 = (*l1_it);
-// TNode n2 = (*l2_it);
-// if(disjoint.find(make_pair(n1, n2)) != disjoint.find(make_pair(n2, n1))) {
-// loop = false;
-// }
-// if(n1 == n2) {
-// equality = true;
-// }
-// if(d_equalityEngine.hasTerm(n1) && d_equalityEngine.hasTerm(n2) &&
-// d_equalityEngine.areEqual(n1, n2)) {
-// equality = true;
-// }
-// }
-// }
-// if(loop == false) {
-// Debug("sets-card-graph") << "[sets-card-graph] Disjoint (always): " << l1 << " and " << l2 << std::endl;
-// continue;
-// }
-// if(equality == false) {
-// Debug("sets-card-graph") << "[sets-card-graph] No equality found: " << l1 << " and " << l2 << std::endl;
-// continue;
-// }
-
-// Node lem = nm->mkNode(kind::OR,
-// nm->mkNode(kind::EQUAL, l1_inter_l2, emptySet),
-// nm->mkNode(kind::LT, nm->mkConst(Rational(0)),
-// nm->mkNode(kind::CARD, l1_inter_l2)));
-
-// d_external.d_out->lemma(lem);
-// Trace("sets-card") << "[sets-card] Guessing disjointness of : " << l1 << " and " << l2 << std::endl;
-// if(Debug.isOn("sets-card-disjoint")) {
-// Debug("sets-card-disjoint") << "[sets-card-disjoint] Lemma for " << l1 << " and " << l2 << " generated because:" << std::endl;
-// for(typeof(disjoint.begin()) it = disjoint.begin(); it != disjoint.end(); ++it) {
-// Debug("sets-card-disjoint") << "[sets-card-disjoint] " << it->first << " " << it->second << std::endl;
-// }
-// }
-// newLemmaGenerated = true;
-// Trace("sets-card") << "[sets-card] New intersection being empty lemma generated. Returning." << std::endl;
-// return;
-// }
-// }
-
-// Assert(!newLemmaGenerated);
-
-
-
-// // Elements being either equal or disequal
-
-// for(typeof(leaves.begin()) it = leaves.begin();
-// it != leaves.end(); ++it) {
-// Assert(d_equalityEngine.hasTerm(*it));
-// Node n = d_equalityEngine.getRepresentative(*it);
-// Assert(n.getKind() == kind::EMPTYSET || leaves.find(n) != leaves.end());
-// if(n != *it) continue;
-// const CDTNodeList* l = d_termInfoManager->getMembers(*it);
-// std::set<TNode> elems;
-// for(typeof(l->begin()) l_it = l->begin(); l_it != l->end(); ++l_it) {
-// elems.insert(d_equalityEngine.getRepresentative(*l_it));
-// }
-// for(typeof(elems.begin()) e1_it = elems.begin(); e1_it != elems.end(); ++e1_it) {
-// for(typeof(elems.begin()) e2_it = elems.begin(); e2_it != elems.end(); ++e2_it) {
-// if(*e1_it == *e2_it) continue;
-// if(!d_equalityEngine.areDisequal(*e1_it, *e2_it, false)) {
-// Node lem = nm->mkNode(kind::EQUAL, *e1_it, *e2_it);
-// lem = nm->mkNode(kind::OR, lem, nm->mkNode(kind::NOT, lem));
-// d_external.d_out->lemma(lem);
-// newLemmaGenerated = true;
-// }
-// }
-// }
-// }
-
-// if(newLemmaGenerated) {
-// Trace("sets-card") << "[sets-card] Members arrangments lemmas. Returning." << std::endl;
-// return;
-// }
-
-
-// // Guess leaf nodes being empty or non-empty
-// for(typeof(leaves.begin()) it = leaves.begin(); it != leaves.end(); ++it) {
-// Node n = d_equalityEngine.getRepresentative(*it);
-// if(n.getKind() == kind::EMPTYSET) continue;
-// if(d_termInfoManager->getMembers(n)->size() > 0) continue;
-// Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType(n.getType())));
-// if(!d_equalityEngine.hasTerm(emptySet)) {
-// d_equalityEngine.addTerm(emptySet);
-// }
-// if(!d_equalityEngine.areDisequal(n, emptySet, false)) {
-// Node lem = nm->mkNode(kind::EQUAL, n, emptySet);
-// lem = nm->mkNode(kind::OR, lem, nm->mkNode(kind::NOT, lem));
-// Assert(d_cardLowerLemmaCache.find(lem) == d_cardLowerLemmaCache.end());
-// d_cardLowerLemmaCache.insert(lem);
-// d_external.d_out->lemma(lem);
-// newLemmaGenerated = true;
-// break;
-// }
-// }
-
-// if(newLemmaGenerated) {
-// Trace("sets-card") << "[sets-card] New guessing leaves being empty done." << std::endl;
-// return;
-// }
-
-// // Assert Lower bound
-// for(typeof(leaves.begin()) it = leaves.begin();
-// it != leaves.end(); ++it) {
-// Assert(d_equalityEngine.hasTerm(*it));
-// Node n = d_equalityEngine.getRepresentative(*it);
-// Assert(n.getKind() == kind::EMPTYSET || leaves.find(n) != leaves.end());
-// if(n != *it) continue;
-// const CDTNodeList* l = d_termInfoManager->getMembers(n);
-// std::set<TNode> elems;
-// for(typeof(l->begin()) l_it = l->begin(); l_it != l->end(); ++l_it) {
-// elems.insert(d_equalityEngine.getRepresentative(*l_it));
-// }
-// if(elems.size() == 0) continue;
-// NodeBuilder<> nb(kind::OR);
-// nb << ( nm->mkNode(kind::LEQ, nm->mkConst(Rational(elems.size())), nm->mkNode(kind::CARD, n)) );
-// if(elems.size() > 1) {
-// for(typeof(elems.begin()) e1_it = elems.begin(); e1_it != elems.end(); ++e1_it) {
-// for(typeof(elems.begin()) e2_it = elems.begin(); e2_it != elems.end(); ++e2_it) {
-// if(*e1_it == *e2_it) continue;
-// nb << (nm->mkNode(kind::EQUAL, *e1_it, *e2_it));
-// }
-// }
-// }
-// for(typeof(elems.begin()) e_it = elems.begin(); e_it != elems.end(); ++e_it) {
-// nb << nm->mkNode(kind::NOT, nm->mkNode(kind::MEMBER, *e_it, n));
-// }
-// Node lem = Node(nb);
-// if(d_cardLowerLemmaCache.find(lem) == d_cardLowerLemmaCache.end()) {
-// Trace("sets-card") << "[sets-card] Card Lower: " << lem << std::endl;
-// d_external.d_out->lemma(lem);
-// d_cardLowerLemmaCache.insert(lem);
-// newLemmaGenerated = true;
-// }
-// }
-// }
-
diff --git a/src/theory/sets/expr_patterns.h b/src/theory/sets/expr_patterns.h
deleted file mode 100644
index 32e77d8b8..000000000
--- a/src/theory/sets/expr_patterns.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/********************* */
-/*! \file expr_patterns.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Kshitij Bansal, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Expr patterns.
- **
- ** Expr patterns.
- **/
-
-#include "cvc4_private.h"
-
-#pragma once
-
-#include "expr/node.h"
-
-namespace CVC4 {
-namespace expr {
-namespace pattern {
-
-/** Boolean operators */
-static Node AND(TNode a, TNode b) {
- return NodeManager::currentNM()->mkNode(kind::AND, a, b);
-}
-
-static Node OR(TNode a, TNode b) {
- return NodeManager::currentNM()->mkNode(kind::OR, a, b);
-}
-
-static Node OR(TNode a, TNode b, TNode c) {
- return NodeManager::currentNM()->mkNode(kind::OR, a, b, c);
-}
-
-static Node NOT(TNode a) {
- return NodeManager::currentNM()->mkNode(kind::NOT, a);
-}
-
-/** Theory operators */
-static Node MEMBER(TNode a, TNode b) {
- return NodeManager::currentNM()->mkNode(kind::MEMBER, a, b);
-}
-
-static Node SINGLETON(TNode a) {
- return NodeManager::currentNM()->mkNode(kind::SINGLETON, a);
-}
-
-static Node EQUAL(TNode a, TNode b) {
- return NodeManager::currentNM()->mkNode(kind::EQUAL, a, b);
-}
-
-static Node CARD(TNode a) {
- return NodeManager::currentNM()->mkNode(kind::CARD, a);
-}
-
-}/* CVC4::expr::pattern namespace */
-}/* CVC4::expr namespace */
-}/* CVC4 namespace */
diff --git a/src/theory/sets/kinds b/src/theory/sets/kinds
index 14c87a947..c92eab4bd 100644
--- a/src/theory/sets/kinds
+++ b/src/theory/sets/kinds
@@ -44,6 +44,11 @@ operator SINGLETON 1 "the set of the single element given as a parameter"
operator INSERT 2: "set obtained by inserting elements (first N-1 parameters) into a set (the last parameter)"
operator CARD 1 "set cardinality operator"
+operator JOIN 2 "set join"
+operator PRODUCT 2 "set cartesian product"
+operator TRANSPOSE 1 "set transpose"
+operator TCLOSURE 1 "set transitive closure"
+
typerule UNION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
typerule INTERSECTION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
typerule SETMINUS ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
@@ -54,6 +59,12 @@ typerule EMPTYSET ::CVC4::theory::sets::EmptySetTypeRule
typerule INSERT ::CVC4::theory::sets::InsertTypeRule
typerule CARD ::CVC4::theory::sets::CardTypeRule
+typerule JOIN ::CVC4::theory::sets::RelBinaryOperatorTypeRule
+typerule PRODUCT ::CVC4::theory::sets::RelBinaryOperatorTypeRule
+typerule TRANSPOSE ::CVC4::theory::sets::RelTransposeTypeRule
+typerule TCLOSURE ::CVC4::theory::sets::RelTransClosureTypeRule
+
+
construle UNION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
construle INTERSECTION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
construle SETMINUS ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
@@ -61,4 +72,9 @@ construle SINGLETON ::CVC4::theory::sets::SingletonTypeRule
construle INSERT ::CVC4::theory::sets::InsertTypeRule
construle CARD ::CVC4::theory::sets::CardTypeRule
+construle JOIN ::CVC4::theory::sets::RelBinaryOperatorTypeRule
+construle PRODUCT ::CVC4::theory::sets::RelBinaryOperatorTypeRule
+construle TRANSPOSE ::CVC4::theory::sets::RelTransposeTypeRule
+construle TCLOSURE ::CVC4::theory::sets::RelTransClosureTypeRule
+
endtheory
diff --git a/src/theory/sets/normal_form.h b/src/theory/sets/normal_form.h
index c1f05ae85..6379fb299 100644
--- a/src/theory/sets/normal_form.h
+++ b/src/theory/sets/normal_form.h
@@ -106,6 +106,31 @@ class NormalForm {
ret.insert(n[0]);
return ret;
}
+
+
+ //AJR
+
+ static void getElementsFromBop( Kind k, Node n, std::vector< Node >& els ){
+ if( n.getKind()==k ){
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ getElementsFromBop( k, n[i], els );
+ }
+ }else{
+ if( std::find( els.begin(), els.end(), n )==els.end() ){
+ els.push_back( n );
+ }
+ }
+ }
+ static Node mkBop( Kind k, std::vector< Node >& els, TypeNode tn, unsigned index = 0 ){
+ if( index>=els.size() ){
+ return NodeManager::currentNM()->mkConst(EmptySet(tn.toType()));
+ }else if( index==els.size()-1 ){
+ return els[index];
+ }else{
+ return NodeManager::currentNM()->mkNode( k, els[index], mkBop( k, els, tn, index+1 ) );
+ }
+ }
+
};
}
}
diff --git a/src/theory/sets/rels_utils.h b/src/theory/sets/rels_utils.h
new file mode 100644
index 000000000..df14bf53b
--- /dev/null
+++ b/src/theory/sets/rels_utils.h
@@ -0,0 +1,96 @@
+/********************* */
+/*! \file rels_utils.h
+ ** \verbatim
+ ** Original author: Paul Meng
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Sets theory implementation.
+ **
+ ** Extension to Sets theory.
+ **/
+
+#ifndef SRC_THEORY_SETS_RELS_UTILS_H_
+#define SRC_THEORY_SETS_RELS_UTILS_H_
+
+namespace CVC4 {
+namespace theory {
+namespace sets {
+
+class RelsUtils {
+
+public:
+
+ // Assumption: the input rel_mem contains all constant pairs
+ static std::set< Node > computeTC( std::set< Node > rel_mem, Node rel ) {
+ std::set< Node >::iterator mem_it = rel_mem.begin();
+ std::map< Node, int > ele_num_map;
+ std::set< Node > tc_rel_mem;
+
+ while( mem_it != rel_mem.end() ) {
+ Node fst = nthElementOfTuple( *mem_it, 0 );
+ Node snd = nthElementOfTuple( *mem_it, 1 );
+ std::set< Node > traversed;
+ traversed.insert(fst);
+ computeTC(rel, rel_mem, fst, snd, traversed, tc_rel_mem);
+ mem_it++;
+ }
+ return tc_rel_mem;
+ }
+
+ static void computeTC( Node rel, std::set< Node >& rel_mem, Node fst,
+ Node snd, std::set< Node >& traversed, std::set< Node >& tc_rel_mem ) {
+ tc_rel_mem.insert(constructPair(rel, fst, snd));
+ if( traversed.find(snd) == traversed.end() ) {
+ traversed.insert(snd);
+ } else {
+ return;
+ }
+
+ std::set< Node >::iterator mem_it = rel_mem.begin();
+ while( mem_it != rel_mem.end() ) {
+ Node new_fst = nthElementOfTuple( *mem_it, 0 );
+ Node new_snd = nthElementOfTuple( *mem_it, 1 );
+ if( snd == new_fst ) {
+ computeTC(rel, rel_mem, fst, new_snd, traversed, tc_rel_mem);
+ }
+ mem_it++;
+ }
+ }
+
+ static Node nthElementOfTuple( Node tuple, int n_th ) {
+ if( tuple.getKind() == kind::APPLY_CONSTRUCTOR ) {
+ return tuple[n_th];
+ }
+ Datatype dt = tuple.getType().getDatatype();
+ return NodeManager::currentNM()->mkNode(kind::APPLY_SELECTOR_TOTAL, dt[0][n_th].getSelector(), tuple);
+ }
+
+ static Node reverseTuple( Node tuple ) {
+ Assert( tuple.getType().isTuple() );
+ std::vector<Node> elements;
+ std::vector<TypeNode> tuple_types = tuple.getType().getTupleTypes();
+ std::reverse( tuple_types.begin(), tuple_types.end() );
+ TypeNode tn = NodeManager::currentNM()->mkTupleType( tuple_types );
+ Datatype dt = tn.getDatatype();
+ elements.push_back( Node::fromExpr(dt[0].getConstructor() ) );
+ for(int i = tuple_types.size() - 1; i >= 0; --i) {
+ elements.push_back( nthElementOfTuple(tuple, i) );
+ }
+ return NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, elements );
+ }
+ static Node constructPair(Node rel, Node a, Node b) {
+ Datatype dt = rel.getType().getSetElementType().getDatatype();
+ return NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, Node::fromExpr(dt[0].getConstructor()), a, b);
+ }
+
+};
+}/* CVC4::theory::sets namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif
diff --git a/src/theory/sets/scrutinize.h b/src/theory/sets/scrutinize.h
deleted file mode 100644
index 88f6001b9..000000000
--- a/src/theory/sets/scrutinize.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/********************* */
-/*! \file scrutinize.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Kshitij Bansal, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Check consistency of internal data structures.
- **
- ** Some checks are very low-level with respect to TheorySetsPrivate
- ** implementation, and hence might become outdated pretty quickly.
- **/
-
-#pragma once
-
-#include "theory/sets/theory_sets.h"
-#include "theory/sets/theory_sets_private.h"
-
-namespace CVC4 {
-namespace theory {
-namespace sets {
-
-class TheorySetsScrutinize {
- /* we don't want to accidentally modify theory data */
- const TheorySetsPrivate* d_theory;
-public:
- TheorySetsScrutinize(TheorySetsPrivate* theory): d_theory(theory) {
- Debug("sets") << "[sets] scrunitize enabled" << std::endl;
- }
- void postCheckInvariants() const {
- Debug("sets-scrutinize") << "[sets-scrutinize] postCheckInvariants()" << std::endl;
-
- // assume not in conflict, and complete:
- // - try building model
- // - check it
-
- TheorySetsPrivate::SettermElementsMap settermElementsMap;
- TNode true_atom = NodeManager::currentNM()->mkConst<bool>(true);
- std::set<Node> terms;
- (d_theory->d_external).computeRelevantTerms(terms);
- for(eq::EqClassIterator it_eqclasses(true_atom, &d_theory->d_equalityEngine);
- ! it_eqclasses.isFinished() ; ++it_eqclasses) {
- TNode n = (*it_eqclasses);
- if(n.getKind() == kind::MEMBER) {
- Assert(d_theory->d_equalityEngine.areEqual(n, true_atom));
- TNode x = d_theory->d_equalityEngine.getRepresentative(n[0]);
- TNode S = d_theory->d_equalityEngine.getRepresentative(n[1]);
- settermElementsMap[S].insert(x);
- }
- }
- bool checkPassed = true;
- for (std::set<Node>::const_iterator it = terms.begin(); it != terms.end(); it++){
- TNode term = *it;
- if( term.getType().isSet() ) {
- checkPassed &= d_theory->checkModel(settermElementsMap, term);
- }
- }
- if(Debug.isOn("sets-checkmodel-ignore")) {
- Debug("sets-checkmodel-ignore") << "[sets-checkmodel-ignore] checkPassed value was " << checkPassed << std::endl;
- } else {
- Assert( checkPassed,
- "THEORY_SETS check-model failed. Run with -d sets-model for details." );
- }
- }
-};
-
-}/* CVC4::theory::sets namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
diff --git a/src/theory/sets/term_info.h b/src/theory/sets/term_info.h
deleted file mode 100644
index c7d4b38bc..000000000
--- a/src/theory/sets/term_info.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/********************* */
-/*! \file term_info.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Kshitij Bansal, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Term info.
- **
- ** Term info.
- **/
-
-#include "cvc4_private.h"
-
-#pragma once
-
-namespace CVC4 {
-namespace theory {
-namespace sets {
-
-
-typedef context::CDList<TNode> CDTNodeList;
-typedef context::CDHashSet<Node, NodeHashFunction> CDNodeSet;
-typedef context::CDHashSet<Node, NodeHashFunction> CDNodeSet;
-
-class TheorySetsTermInfo {
-public:
- CDTNodeList* elementsInThisSet;
- CDTNodeList* elementsNotInThisSet;
- CDTNodeList* setsContainingThisElement;
- CDTNodeList* setsNotContainingThisElement;
- CDTNodeList* parents;
-
- TheorySetsTermInfo(context::Context* c)
- {
- elementsInThisSet = new(true)CDTNodeList(c);
- elementsNotInThisSet = new(true)CDTNodeList(c);
- setsContainingThisElement = new(true)CDTNodeList(c);
- setsNotContainingThisElement = new(true)CDTNodeList(c);
- parents = new(true)CDTNodeList(c);
- }
-
- void addToElementList(TNode n, bool polarity) {
- if(polarity) elementsInThisSet -> push_back(n);
- else elementsNotInThisSet -> push_back(n);
- }
-
- void addToSetList(TNode n, bool polarity) {
- if(polarity) setsContainingThisElement -> push_back(n);
- else setsNotContainingThisElement -> push_back(n);
- }
-
- ~TheorySetsTermInfo() {
- elementsInThisSet -> deleteSelf();
- elementsNotInThisSet -> deleteSelf();
- setsContainingThisElement -> deleteSelf();
- setsNotContainingThisElement -> deleteSelf();
- parents -> deleteSelf();
- }
-
-};
-
-}/* CVC4::theory::sets namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
diff --git a/src/theory/sets/theory_sets.cpp b/src/theory/sets/theory_sets.cpp
index bdbc964c6..52afe05e2 100644
--- a/src/theory/sets/theory_sets.cpp
+++ b/src/theory/sets/theory_sets.cpp
@@ -63,7 +63,7 @@ EqualityStatus TheorySets::getEqualityStatus(TNode a, TNode b) {
}
Node TheorySets::getModelValue(TNode node) {
- return d_internal->getModelValue(node);
+ return Node::null();
}
void TheorySets::preRegisterTerm(TNode node) {
@@ -82,6 +82,10 @@ void TheorySets::setMasterEqualityEngine(eq::EqualityEngine* eq) {
d_internal->setMasterEqualityEngine(eq);
}
+bool TheorySets::isEntailed( Node n, bool pol ) {
+ return d_internal->isEntailed( n, pol );
+}
+
}/* CVC4::theory::sets namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/sets/theory_sets.h b/src/theory/sets/theory_sets.h
index bbeaf4a4c..2ebb9947d 100644
--- a/src/theory/sets/theory_sets.h
+++ b/src/theory/sets/theory_sets.h
@@ -33,6 +33,7 @@ class TheorySets : public Theory {
private:
friend class TheorySetsPrivate;
friend class TheorySetsScrutinize;
+ friend class TheorySetsRels;
TheorySetsPrivate* d_internal;
public:
@@ -68,6 +69,8 @@ public:
void propagate(Effort);
void setMasterEqualityEngine(eq::EqualityEngine* eq);
+
+ bool isEntailed( Node n, bool pol );
};/* class TheorySets */
diff --git a/src/theory/sets/theory_sets_private.cpp b/src/theory/sets/theory_sets_private.cpp
index 6fb90fea3..edf250c4d 100644
--- a/src/theory/sets/theory_sets_private.cpp
+++ b/src/theory/sets/theory_sets_private.cpp
@@ -22,438 +22,1492 @@
#include "expr/emptyset.h"
#include "options/sets_options.h"
#include "smt/smt_statistics_registry.h"
-#include "theory/sets/expr_patterns.h" // ONLY included here
-#include "theory/sets/scrutinize.h"
#include "theory/sets/theory_sets.h"
+#include "theory/sets/normal_form.h"
#include "theory/theory_model.h"
#include "util/result.h"
+#include "theory/quantifiers/term_database.h"
+
+#define AJR_IMPLEMENTATION
using namespace std;
-using namespace CVC4::expr::pattern;
namespace CVC4 {
namespace theory {
namespace sets {
-const char* element_of_str = " \u2208 ";
+TheorySetsPrivate::TheorySetsPrivate(TheorySets& external,
+ context::Context* c,
+ context::UserContext* u):
+ d_rels(NULL),
+ d_members(c),
+ d_deq(c),
+ d_deq_processed(u),
+ d_keep(c),
+ d_proxy(u),
+ d_proxy_to_term(u),
+ d_lemmas_produced(u),
+ d_card_processed(u),
+ d_external(external),
+ d_notify(*this),
+ d_equalityEngine(d_notify, c, "theory::sets::TheorySetsPrivate", true),
+ d_conflict(c)
+{
-// Declaration of functions defined later in this CPP file
-const std::set<TNode> getLeaves(map<TNode, set<TNode> >& edges, TNode node);
+ d_rels = new TheorySetsRels(c, u, &d_equalityEngine, &d_conflict, external);
+
+ d_true = NodeManager::currentNM()->mkConst( true );
+ d_false = NodeManager::currentNM()->mkConst( false );
+ d_zero = NodeManager::currentNM()->mkConst( Rational(0) );
-/**************************** TheorySetsPrivate *****************************/
-/**************************** TheorySetsPrivate *****************************/
-/**************************** TheorySetsPrivate *****************************/
+ d_equalityEngine.addFunctionKind(kind::SINGLETON);
+ d_equalityEngine.addFunctionKind(kind::UNION);
+ d_equalityEngine.addFunctionKind(kind::INTERSECTION);
+ d_equalityEngine.addFunctionKind(kind::SETMINUS);
-void TheorySetsPrivate::check(Theory::Effort level) {
- d_newLemmaGenerated = false;
- while(!d_external.done() && !d_conflict) {
- // Get all the assertions
- Assertion assertion = d_external.get();
- TNode fact = assertion.assertion;
+ d_equalityEngine.addFunctionKind(kind::MEMBER);
+ d_equalityEngine.addFunctionKind(kind::SUBSET);
- Debug("sets") << "\n\n[sets] TheorySetsPrivate::check(): processing "
- << fact << std::endl;
+ // If cardinality is on.
+ d_equalityEngine.addFunctionKind(kind::CARD);
- bool polarity = fact.getKind() != kind::NOT;
- TNode atom = polarity ? fact : fact[0];
+ d_card_enabled = false;
- if (!assertion.isPreregistered) {
- if (atom.getKind() == kind::EQUAL) {
- if (!d_equalityEngine.hasTerm(atom[0])) {
- Assert(atom[0].isConst());
- d_equalityEngine.addTerm(atom[0]);
- d_termInfoManager->addTerm(atom[0]);
- }
- if (!d_equalityEngine.hasTerm(atom[1])) {
- Assert(atom[1].isConst());
- d_equalityEngine.addTerm(atom[1]);
- d_termInfoManager->addTerm(atom[1]);
+}/* TheorySetsPrivate::TheorySetsPrivate() */
+
+TheorySetsPrivate::~TheorySetsPrivate(){
+ delete d_rels;
+ for(std::map< Node, EqcInfo* >::iterator i = d_eqc_info.begin(), iend = d_eqc_info.end(); i != iend; ++i){
+ EqcInfo* current = (*i).second;
+ delete current;
+ }
+}/* TheorySetsPrivate::~TheorySetsPrivate() */
+
+
+void TheorySetsPrivate::eqNotifyNewClass(TNode t) {
+ if( t.getKind()==kind::SINGLETON || t.getKind()==kind::EMPTYSET ){
+ EqcInfo * e = getOrMakeEqcInfo( t, true );
+ e->d_singleton = t;
+ }
+ d_rels->eqNotifyNewClass( t );
+}
+
+void TheorySetsPrivate::eqNotifyPreMerge(TNode t1, TNode t2){
+
+}
+
+void TheorySetsPrivate::eqNotifyPostMerge(TNode t1, TNode t2){
+ if( !d_conflict ){
+ Trace("sets-prop-debug") << "Merge " << t1 << " and " << t2 << "..." << std::endl;
+ Node s1, s2;
+ EqcInfo * e2 = getOrMakeEqcInfo( t2 );
+ if( e2 ){
+ s2 = e2->d_singleton;
+ EqcInfo * e1 = getOrMakeEqcInfo( t1 );
+ Node s1;
+ Trace("sets-prop-debug") << "Merging singletons..." << std::endl;
+ if( e1 ){
+ s1 = e1->d_singleton;
+ if( !s1.isNull() && !s2.isNull() ){
+ if( s1.getKind()==s2.getKind() ){
+ Trace("sets-prop") << "Propagate eq inference : " << s1 << " == " << s2 << std::endl;
+ //infer equality between elements of singleton
+ Node exp = s1.eqNode( s2 );
+ Node eq = s1[0].eqNode( s2[0] );
+ d_keep.insert( exp );
+ d_keep.insert( eq );
+ assertFact( eq, exp );
+ }else{
+ //singleton equal to emptyset, conflict
+ Trace("sets-prop") << "Propagate conflict : " << s1 << " == " << s2 << std::endl;
+ conflict( s1, s2 );
+ return;
+ }
}
+ }else{
+ //copy information
+ e1 = getOrMakeEqcInfo( t1, true );
+ e1->d_singleton.set( e2->d_singleton );
}
}
-
- // Solve each
- switch(atom.getKind()) {
- case kind::EQUAL:
- Debug("sets") << atom[0] << " should " << (polarity ? "":"NOT ")
- << "be equal to " << atom[1] << std::endl;
- assertEquality(fact, fact, /* learnt = */ false);
- break;
-
- case kind::MEMBER:
- Debug("sets") << atom[0] << " should " << (polarity ? "":"NOT ")
- << "be in " << atom[1] << std::endl;
- assertMemebership(fact, fact, /* learnt = */ false);
- break;
-
- default:
- Unhandled(fact.getKind());
+ //merge membership list
+ Trace("sets-prop-debug") << "Copying membership list..." << std::endl;
+ NodeIntMap::iterator mem_i2 = d_members.find( t2 );
+ if( mem_i2 != d_members.end() ) {
+ NodeIntMap::iterator mem_i1 = d_members.find( t1 );
+ int n_members = 0;
+ if( mem_i1 != d_members.end() ) {
+ n_members = (*mem_i1).second;
+ }
+ for( int i=0; i<(*mem_i2).second; i++ ){
+ Assert( i<(int)d_members_data[t2].size() && d_members_data[t2][i].getKind()==kind::MEMBER );
+ Node m2 = d_members_data[t2][i];
+ //check if redundant
+ bool add = true;
+ for( int j=0; j<n_members; j++ ){
+ Assert( j<(int)d_members_data[t1].size() && d_members_data[t1][j].getKind()==kind::MEMBER );
+ if( ee_areEqual( m2[0], d_members_data[t1][j][0] ) ){
+ add = false;
+ break;
+ }
+ }
+ if( add ){
+ if( !s1.isNull() && s2.isNull() ){
+ Assert( m2[1].getType()==s1.getType() );
+ Assert( ee_areEqual( m2[1], s1 ) );
+ Node exp = NodeManager::currentNM()->mkNode( kind::AND, m2[1].eqNode( s1 ), m2 );
+ if( s1.getKind()==kind::SINGLETON ){
+ if( s1[0]!=m2[0] ){
+ Node eq = s1[0].eqNode( m2[0] );
+ d_keep.insert( exp );
+ d_keep.insert( eq );
+ Trace("sets-prop") << "Propagate eq-mem eq inference : " << exp << " => " << eq << std::endl;
+ assertFact( eq, exp );
+ }
+ }else{
+ //conflict
+ Trace("sets-prop") << "Propagate eq-mem conflict : " << exp << std::endl;
+ d_conflict = true;
+ d_external.d_out->conflict( exp );
+ return;
+ }
+ }
+ if( n_members<(int)d_members_data[t1].size() ){
+ d_members_data[t1][n_members] = m2;
+ }else{
+ d_members_data[t1].push_back( m2 );
+ }
+ n_members++;
+ }
+ }
+ d_members[t1] = n_members;
}
- finishPropagation();
-
- Debug("sets") << "[sets] in conflict = " << d_conflict << std::endl;
- // Assert( d_conflict ^ d_equalityEngine.consistent() );
- // ^ doesn't hold when we propagate equality/disequality between shared terms
- // and that leads to conflict (externally).
- if(d_conflict) { return; }
- Debug("sets") << "[sets] is complete = " << isComplete() << std::endl;
+ d_rels->eqNotifyPostMerge( t1, t2 );
}
+}
- if( (level == Theory::EFFORT_FULL || options::setsEagerLemmas() ) && !isComplete()) {
- lemma(getLemma(), SETS_LEMMA_OTHER);
- return;
+void TheorySetsPrivate::eqNotifyDisequal(TNode t1, TNode t2, TNode reason){
+ if( t1.getType().isSet() ){
+ Node eq = t1.eqNode( t2 );
+ if( d_deq.find( eq )==d_deq.end() ){
+ d_deq[eq] = true;
+ }
}
-
- //processCard(level);
+}
- processCard2(level);
-
- // if we are here, there is no conflict and we are complete
- if(Debug.isOn("sets-scrutinize")) { d_scrutinize->postCheckInvariants(); }
+TheorySetsPrivate::EqcInfo::EqcInfo( context::Context* c ) : d_singleton( c ){
- return;
-}/* TheorySetsPrivate::check() */
-
-
-void TheorySetsPrivate::assertEquality(TNode fact, TNode reason, bool learnt)
-{
- Debug("sets-assert") << "\n[sets-assert] adding equality: " << fact
- << ", " << reason
- << ", " << learnt << std::endl;
-
- bool polarity = fact.getKind() != kind::NOT;
- TNode atom = polarity ? fact : fact[0];
+}
- // fact already holds
- if( holds(atom, polarity) ) {
- Debug("sets-assert") << "[sets-assert] already present, skipping" << std::endl;
- return;
+TheorySetsPrivate::EqcInfo* TheorySetsPrivate::getOrMakeEqcInfo( TNode n, bool doMake ){
+ std::map< Node, EqcInfo* >::iterator eqc_i = d_eqc_info.find( n );
+ if( eqc_i==d_eqc_info.end() ){
+ EqcInfo* ei = NULL;
+ if( doMake ){
+ ei = new EqcInfo( d_external.getSatContext() );
+ d_eqc_info[n] = ei;
+ }
+ return ei;
+ }else{
+ return eqc_i->second;
}
+}
- // assert fact & check for conflict
- if(learnt) {
- registerReason(reason, /*save=*/ true);
- }
- d_equalityEngine.assertEquality(atom, polarity, reason);
- if(!d_equalityEngine.consistent()) {
- Debug("sets-assert") << "[sets-assert] running into a conflict" << std::endl;
- d_conflict = true;
- return;
+bool TheorySetsPrivate::ee_areEqual( Node a, Node b ) {
+ if( a==b ){
+ return true;
+ }else{
+ if( d_equalityEngine.hasTerm( a ) && d_equalityEngine.hasTerm( b ) ){
+ return d_equalityEngine.areEqual( a, b );
+ }else{
+ return false;
+ }
}
+}
- if(atom[0].getKind() == kind::CARD && isCardVar(atom[0])) {
- NodeManager* nm = NodeManager::currentNM();
- Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType(atom[0].getType())));
- Node newFact = nm->mkNode(kind::EQUAL, getCardVar(atom[0]), emptySet);
- if(!polarity) newFact = nm->mkNode(kind::NOT, newFact);
- learnLiteral(newFact, fact);
- }
-
- // disequality lemma
- if(!polarity && atom[0].getType().isSet()) {
- addToPending(atom);
+bool TheorySetsPrivate::ee_areDisequal( Node a, Node b ) {
+ if( a==b ){
+ return false;
+ }else{
+ if( d_equalityEngine.hasTerm( a ) && d_equalityEngine.hasTerm( b ) ){
+ return d_equalityEngine.areDisequal( a, b, false );
+ }else{
+ return a.isConst() && b.isConst();
+ }
}
+}
- // for cardinality
- if(polarity && atom[0].getType().isSet()) {
- d_graphMergesPending.push(make_pair(atom[0], atom[1]));
+bool TheorySetsPrivate::isEntailed( Node n, bool polarity ) {
+ if( n.getKind()==kind::NOT ){
+ return isEntailed( n[0], !polarity );
+ }else if( n.getKind()==kind::EQUAL ){
+ if( polarity ){
+ return ee_areEqual( n[0], n[1] );
+ }else{
+ return ee_areDisequal( n[0], n[1] );
+ }
+ }else if( n.getKind()==kind::MEMBER ){
+ if( ee_areEqual( n, polarity ? d_true : d_false ) ){
+ return true;
+ }
+ //check members cache
+ if( polarity && d_equalityEngine.hasTerm( n[1] ) ){
+ Node r = d_equalityEngine.getRepresentative( n[1] );
+ if( isMember( n[0], r ) ){
+ return true;
+ }
+ }
+ }else if( n.getKind()==kind::AND && n.getKind()==kind::OR ){
+ bool conj = (n.getKind()==kind::AND)==polarity;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ bool isEnt = isEntailed( n[i], polarity );
+ if( isEnt==conj ){
+ return conj;
+ }
+ }
+ return !conj;
+ }else if( n.isConst() ){
+ return ( polarity && n==d_true ) || ( !polarity && n==d_false );
}
-}/* TheorySetsPrivate::assertEquality() */
-
-
-void TheorySetsPrivate::assertMemebership(TNode fact, TNode reason, bool learnt)
-{
- Debug("sets-assert") << "\n[sets-assert] adding membership: " << fact
- << ", " << reason
- << ", " << learnt << std::endl;
+ return false;
+}
- bool polarity = fact.getKind() == kind::NOT ? false : true;
+bool TheorySetsPrivate::isMember( Node x, Node s ) {
+ Assert( d_equalityEngine.hasTerm( s ) && d_equalityEngine.getRepresentative( s )==s );
+ NodeIntMap::iterator mem_i = d_members.find( s );
+ if( mem_i != d_members.end() ) {
+ for( int i=0; i<(*mem_i).second; i++ ){
+ if( ee_areEqual( d_members_data[s][i][0], x ) ){
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool TheorySetsPrivate::assertFact( Node fact, Node exp ){
+ Trace("sets-assert") << "TheorySets::assertFact : " << fact << ", exp = " << exp << std::endl;
+ bool polarity = fact.getKind() != kind::NOT;
TNode atom = polarity ? fact : fact[0];
-
- // fact already holds
- if( holds(atom, polarity) ) {
- Debug("sets-assert") << "[sets-assert] already present, skipping" << std::endl;
- return;
+ if( !isEntailed( atom, polarity ) ){
+ if( atom.getKind()==kind::EQUAL ){
+ d_equalityEngine.assertEquality( atom, polarity, exp );
+ }else{
+ d_equalityEngine.assertPredicate( atom, polarity, exp );
+ }
+ if( !d_conflict ){
+ if( atom.getKind()==kind::MEMBER && polarity ){
+ //check if set has a value, if so, we can propagate
+ Node r = d_equalityEngine.getRepresentative( atom[1] );
+ EqcInfo * e = getOrMakeEqcInfo( r, true );
+ if( e ){
+ Node s = e->d_singleton;
+ if( !s.isNull() ){
+ Node exp = NodeManager::currentNM()->mkNode( kind::AND, atom, atom[1].eqNode( s ) );
+ d_keep.insert( exp );
+ if( s.getKind()==kind::SINGLETON ){
+ if( s[0]!=atom[0] ){
+ Trace("sets-prop") << "Propagate mem-eq : " << exp << std::endl;
+ Node eq = s[0].eqNode( atom[0] );
+ d_keep.insert( eq );
+ assertFact( eq, exp );
+ }
+ }else{
+ Trace("sets-prop") << "Propagate mem-eq conflict : " << exp << std::endl;
+ d_conflict = true;
+ d_external.d_out->conflict( exp );
+ }
+ }
+ }
+ //add to membership list
+ NodeIntMap::iterator mem_i = d_members.find( r );
+ int n_members = 0;
+ if( mem_i != d_members.end() ) {
+ n_members = (*mem_i).second;
+ }
+ d_members[r] = n_members + 1;
+ if( n_members<(int)d_members_data[r].size() ){
+ d_members_data[r][n_members] = atom;
+ }else{
+ d_members_data[r].push_back( atom );
+ }
+ }
+ }
+ return true;
+ }else{
+ return false;
}
+}
- // assert fact & check for conflict
- if(learnt) {
- registerReason(reason, true);
+bool TheorySetsPrivate::assertFactRec( Node fact, Node exp, std::vector< Node >& lemma, int inferType ) {
+ if( ( options::setsInferAsLemmas() && inferType!=-1 ) || inferType==1 ){
+ if( !isEntailed( fact, true ) ){
+ lemma.push_back( exp==d_true ? fact : NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, fact ) );
+ return true;
+ }
+ }else{
+ Trace("sets-fact") << "Assert fact rec : " << fact << ", exp = " << exp << std::endl;
+ if( fact.isConst() ){
+ //either trivial or a conflict
+ if( fact==d_false ){
+ Trace("sets-lemma") << "Conflict : " << exp << std::endl;
+ d_conflict = true;
+ d_external.d_out->conflict( exp );
+ return true;
+ }
+ }else if( fact.getKind()==kind::AND || ( fact.getKind()==kind::NOT && fact[0].getKind()==kind::OR ) ){
+ bool ret = false;
+ Node f = fact.getKind()==kind::NOT ? fact[0] : fact;
+ for( unsigned i=0; i<f.getNumChildren(); i++ ){
+ Node factc = fact.getKind()==kind::NOT ? f[i].negate() : f[i];
+ bool tret = assertFactRec( factc, exp, lemma, inferType );
+ ret = ret || tret;
+ if( d_conflict ){
+ return true;
+ }
+ }
+ return ret;
+ }else{
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ //things we can assert to equality engine
+ if( atom.getKind()==kind::MEMBER || ( atom.getKind()==kind::EQUAL && atom[0].getType().isSet() ) ){
+ //send to equality engine
+ if( assertFact( fact, exp ) ){
+ d_addedFact = true;
+ return true;
+ }
+ }else{
+ if( !isEntailed( fact, true ) ){
+ //must send as lemma
+ lemma.push_back( exp==d_true ? fact : NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, fact ) );
+ return true;
+ }
+ }
+ }
}
- d_equalityEngine.assertPredicate(atom, polarity, reason);
-
- if(!d_equalityEngine.consistent()) {
- Debug("sets-assert") << "[sets-assert] running into a conflict" << std::endl;
- d_conflict = true;
- return;
+ return false;
+}
+void TheorySetsPrivate::assertInference( Node fact, Node exp, std::vector< Node >& lemmas, const char * c, int inferType ) {
+ d_keep.insert( exp );
+ d_keep.insert( fact );
+ if( assertFactRec( fact, exp, lemmas, inferType ) ){
+ Trace("sets-lemma") << "Sets::Lemma : " << fact << " from " << exp << " by " << c << std::endl;
+ Trace("sets-assertion") << "(assert (=> " << exp << " " << fact << ")) ; by " << c << std::endl;
+ }
+}
+
+void TheorySetsPrivate::assertInference( Node fact, std::vector< Node >& exp, std::vector< Node >& lemmas, const char * c, int inferType ){
+ Node exp_n = exp.empty() ? d_true : ( exp.size()==1 ? exp[0] : NodeManager::currentNM()->mkNode( kind::AND, exp ) );
+ assertInference( fact, exp_n, lemmas, c, inferType );
+}
+
+void TheorySetsPrivate::assertInference( std::vector< Node >& conc, Node exp, std::vector< Node >& lemmas, const char * c, int inferType ){
+ if( !conc.empty() ){
+ Node fact = conc.size()==1 ? conc[0] : NodeManager::currentNM()->mkNode( kind::AND, conc );
+ assertInference( fact, exp, lemmas, c, inferType );
+ }
+}
+void TheorySetsPrivate::assertInference( std::vector< Node >& conc, std::vector< Node >& exp, std::vector< Node >& lemmas, const char * c, int inferType ) {
+ Node exp_n = exp.empty() ? d_true : ( exp.size()==1 ? exp[0] : NodeManager::currentNM()->mkNode( kind::AND, exp ) );
+ assertInference( conc, exp_n, lemmas, c, inferType );
+}
+
+void TheorySetsPrivate::split( Node n, int reqPol ) {
+ n = Rewriter::rewrite( n );
+ Node lem = NodeManager::currentNM()->mkNode( kind::OR, n, n.negate() );
+ std::vector< Node > lemmas;
+ lemmas.push_back( lem );
+ flushLemmas( lemmas );
+ Trace("sets-lemma") << "Sets::Lemma split : " << lem << std::endl;
+ if( reqPol!=0 ){
+ Trace("sets-lemma") << "Sets::Require phase " << n << " " << (reqPol>0) << std::endl;
+ d_external.getOutputChannel().requirePhase( n, reqPol>0 );
+ }
+}
+
+void TheorySetsPrivate::fullEffortCheck(){
+ Trace("sets") << "----- Full effort check ------" << std::endl;
+ do{
+ Trace("sets") << "...iterate full effort check..." << std::endl;
+ Assert( d_equalityEngine.consistent() );
+ d_sentLemma = false;
+ d_addedFact = false;
+ d_set_eqc.clear();
+ d_set_eqc_list.clear();
+ d_eqc_emptyset.clear();
+ d_eqc_singleton.clear();
+ d_congruent.clear();
+ d_nvar_sets.clear();
+ d_pol_mems[0].clear();
+ d_pol_mems[1].clear();
+ d_members_index.clear();
+ d_singleton_index.clear();
+ d_bop_index.clear();
+ d_op_list.clear();
+ d_card_enabled = false;
+ d_eqc_to_card_term.clear();
+
+ std::vector< Node > lemmas;
+ Trace("sets-eqc") << "Equality Engine:" << std::endl;
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ while( !eqcs_i.isFinished() ){
+ Node eqc = (*eqcs_i);
+ bool isSet = false;
+ TypeNode tn = eqc.getType();
+ if( tn.isSet() ){
+ isSet = true;
+ d_set_eqc.push_back( eqc );
+ }
+ Trace("sets-eqc") << "[" << eqc << "] : ";
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ while( !eqc_i.isFinished() ) {
+ Node n = (*eqc_i);
+ if( n!=eqc ){
+ Trace("sets-eqc") << n << " ";
+ }
+ if( n.getKind()==kind::MEMBER ){
+ Node s = d_equalityEngine.getRepresentative( n[1] );
+ Node x = d_equalityEngine.getRepresentative( n[0] );
+ int pindex = eqc==d_true ? 0 : ( eqc==d_false ? 1 : -1 );
+ if( pindex!=-1 ){
+ if( d_pol_mems[pindex][s].find( x )==d_pol_mems[pindex][s].end() ){
+ d_pol_mems[pindex][s][x] = n;
+ Trace("sets-debug2") << "Membership[" << x << "][" << s << "] : " << n << ", pindex = " << pindex << std::endl;
+ }
+ }
+ if( d_members_index[s].find( x )==d_members_index[s].end() ){
+ d_members_index[s][x] = n;
+ d_op_list[kind::MEMBER].push_back( n );
+ }
+ }else if( n.getKind()==kind::SINGLETON || n.getKind()==kind::UNION || n.getKind()==kind::INTERSECTION || n.getKind()==kind::SETMINUS || n.getKind()==kind::EMPTYSET ){
+ if( n.getKind()==kind::SINGLETON ){
+ //singleton lemma
+ getProxy( n );
+ Node r = d_equalityEngine.getRepresentative( n[0] );
+ if( d_singleton_index.find( r )==d_singleton_index.end() ){
+ d_singleton_index[r] = n;
+ d_eqc_singleton[eqc] = n;
+ d_op_list[kind::SINGLETON].push_back( n );
+ }else{
+ d_congruent[n] = d_singleton_index[r];
+ }
+ }else if( n.getKind()!=kind::EMPTYSET ){
+ Node r1 = d_equalityEngine.getRepresentative( n[0] );
+ Node r2 = d_equalityEngine.getRepresentative( n[1] );
+ if( d_bop_index[n.getKind()][r1].find( r2 )==d_bop_index[n.getKind()][r1].end() ){
+ d_bop_index[n.getKind()][r1][r2] = n;
+ d_op_list[n.getKind()].push_back( n );
+ }else{
+ d_congruent[n] = d_bop_index[n.getKind()][r1][r2];
+ }
+ }else{
+ d_eqc_emptyset[tn] = eqc;
+ }
+ d_nvar_sets[eqc].push_back( n );
+ Trace("sets-debug2") << "Non-var-set[" << eqc << "] : " << n << std::endl;
+ d_set_eqc_list[eqc].push_back( n );
+ }else if( n.getKind()==kind::CARD ){
+ d_card_enabled = true;
+ Node r = d_equalityEngine.getRepresentative( n[0] );
+ if( d_eqc_to_card_term.find( r )==d_eqc_to_card_term.end() ){
+ d_eqc_to_card_term[ r ] = n;
+ registerCardinalityTerm( n[0], lemmas );
+ }
+ }else if( isSet ){
+ d_set_eqc_list[eqc].push_back( n );
+ }
+ ++eqc_i;
+ }
+ Trace("sets-eqc") << std::endl;
+ ++eqcs_i;
+ }
+
+ flushLemmas( lemmas );
+ if( !hasProcessed() ){
+ if( Trace.isOn("sets-mem") ){
+ for( unsigned i=0; i<d_set_eqc.size(); i++ ){
+ Node s = d_set_eqc[i];
+ Trace("sets-mem") << "Eqc " << s << " : ";
+ std::map< Node, std::map< Node, Node > >::iterator it = d_pol_mems[0].find( s );
+ if( it!=d_pol_mems[0].end() ){
+ Trace("sets-mem") << "Memberships : ";
+ for( std::map< Node, Node >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ Trace("sets-mem") << it2->first << " ";
+ }
+ }
+ std::map< Node, Node >::iterator its = d_eqc_singleton.find( s );
+ if( its!=d_eqc_singleton.end() ){
+ Trace("sets-mem") << " : Singleton : " << its->second;
+ }
+ Trace("sets-mem") << std::endl;
+ }
+ }
+
+ checkDownwardsClosure( lemmas );
+ if( options::setsInferAsLemmas() ){
+ flushLemmas( lemmas );
+ }
+ if( !hasProcessed() ){
+ checkUpwardsClosure( lemmas );
+ flushLemmas( lemmas );
+ if( !hasProcessed() ){
+ if( d_card_enabled ){
+ //for cardinality
+ checkCardBuildGraph( lemmas );
+ flushLemmas( lemmas );
+ if( !hasProcessed() ){
+ checkMinCard( lemmas );
+ flushLemmas( lemmas );
+ if( !hasProcessed() ){
+ checkCardCycles( lemmas );
+ flushLemmas( lemmas );
+ if( !hasProcessed() ){
+ std::vector< Node > intro_sets;
+ checkNormalForms( lemmas, intro_sets );
+ flushLemmas( lemmas );
+ if( !hasProcessed() ){
+ checkDisequalities( lemmas );
+ flushLemmas( lemmas );
+ if( !hasProcessed() && !intro_sets.empty() ){
+ Assert( intro_sets.size()==1 );
+ Trace("sets-intro") << "Introduce term : " << intro_sets[0] << std::endl;
+ Trace("sets-intro") << " Actual Intro : ";
+ debugPrintSet( intro_sets[0], "sets-nf" );
+ Trace("sets-nf") << std::endl;
+ Node k = getProxy( intro_sets[0] );
+ d_sentLemma = true;
+ }
+ }
+ }
+ }
+ }
+ }else{
+ checkDisequalities( lemmas );
+ flushLemmas( lemmas );
+ }
+ }
+ }
+ }
+ }while( !d_sentLemma && !d_conflict && d_addedFact );
+ Trace("sets") << "----- End full effort check, conflict=" << d_conflict << ", lemma=" << d_sentLemma << std::endl;
+}
+
+
+void TheorySetsPrivate::checkDownwardsClosure( std::vector< Node >& lemmas ) {
+ Trace("sets") << "Downwards closure..." << std::endl;
+ //downwards closure
+ for( std::map< Node, std::map< Node, Node > >::iterator it = d_pol_mems[0].begin(); it != d_pol_mems[0].end(); ++it ){
+ std::map< Node, std::vector< Node > >::iterator itn = d_nvar_sets.find( it->first );
+ if( itn!=d_nvar_sets.end() ){
+ for( unsigned j=0; j<itn->second.size(); j++ ){
+ if( d_congruent.find( itn->second[j] )==d_congruent.end() ){
+ for( std::map< Node, Node >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ Node mem = it2->second;
+ Node eq_set = itn->second[j];
+ Assert( d_equalityEngine.areEqual( mem[1], eq_set ) );
+ if( mem[1]!=eq_set ){
+ Trace("sets-debug") << "Downwards closure based on " << mem << ", eq_set = " << eq_set << std::endl;
+ #if 1
+ Node nmem = NodeManager::currentNM()->mkNode( kind::MEMBER, mem[0], eq_set );
+ nmem = Rewriter::rewrite( nmem );
+ std::vector< Node > exp;
+ exp.push_back( mem );
+ exp.push_back( mem[1].eqNode( eq_set ) );
+ assertInference( nmem, exp, lemmas, "downc" );
+ if( d_conflict ){
+ return;
+ }
+ #else
+ Node k = getProxy( eq_set );
+ Node pmem = NodeManager::currentNM()->mkNode( kind::MEMBER, mem[0], k );
+ if( ee_areEqual( mem, pmem ) ){
+ Node nmem = NodeManager::currentNM()->mkNode( kind::MEMBER, mem[0], eq_set );
+ nmem = Rewriter::rewrite( nmem );
+ d_keep.insert( nmem );
+ d_keep.insert( pmem );
+ assertFactRec( nmem, pmem, lemmas );
+ }else{
+ Trace("sets-debug") << "...infer proxy membership" << std::endl;
+ Node exp = NodeManager::currentNM()->mkNode( kind::AND, mem, mem[1].eqNode( eq_set ) );
+ d_keep.insert( pmem );
+ d_keep.insert( exp );
+ assertFactRec( pmem, exp, lemmas );
+ }
+ if( d_conflict ){
+ return;
+ }
+ #endif
+ }
+ }
+ }
+ }
+ }
}
+}
- // update term info data structures
- d_termInfoManager->notifyMembership(fact);
-
- // propagation
- TNode x = d_equalityEngine.getRepresentative(atom[0]);
- eq::EqClassIterator j(d_equalityEngine.getRepresentative(atom[1]),
- &d_equalityEngine);
- TNode S = (*j);
- Node cur_atom = MEMBER(x, S);
-
- /**
- * It is sufficient to do emptyset propagation outside the loop as
- * constant term is guaranteed to be class representative.
- */
- if(polarity && S.getKind() == kind::EMPTYSET) {
- Debug("sets-prop") << "[sets-prop] something in empty set? conflict."
- << std::endl;
- learnLiteral(cur_atom, false, cur_atom);
- Assert(d_conflict);
- return;
+void TheorySetsPrivate::checkUpwardsClosure( std::vector< Node >& lemmas ) {
+ //upwards closure
+ for( std::map< Kind, std::map< Node, std::map< Node, Node > > >::iterator itb = d_bop_index.begin(); itb != d_bop_index.end(); ++itb ){
+ Kind k = itb->first;
+ Trace("sets") << "Upwards closure " << k << "..." << std::endl;
+ for( std::map< Node, std::map< Node, Node > >::iterator it = itb->second.begin(); it != itb->second.end(); ++it ){
+ Node r1 = it->first;
+ //see if there are members in first argument r1
+ std::map< Node, std::map< Node, Node > >::iterator itm1 = d_pol_mems[0].find( r1 );
+ if( itm1!=d_pol_mems[0].end() || k==kind::UNION ){
+ for( std::map< Node, Node >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+ Node r2 = it2->first;
+ //see if there are members in second argument
+ std::map< Node, std::map< Node, Node > >::iterator itm2 = d_pol_mems[0].find( r2 );
+ if( itm2!=d_pol_mems[0].end() || k!=kind::INTERSECTION ){
+ Trace("sets-debug") << "Checking " << it2->second << ", members = " << (itm1!=d_pol_mems[0].end()) << ", " << (itm2!=d_pol_mems[0].end()) << std::endl;
+ //for all members of r1
+ if( itm1!=d_pol_mems[0].end() ){
+ for( std::map< Node, Node >::iterator itm1m = itm1->second.begin(); itm1m != itm1->second.end(); ++itm1m ){
+ Node xr = itm1m->first;
+ Node x = itm1m->second[0];
+ Trace("sets-debug") << "checking membership " << xr << " " << itm1m->second << std::endl;
+ std::vector< Node > exp;
+ exp.push_back( itm1m->second );
+ addEqualityToExp( it2->second[0], itm1m->second[1], exp );
+ bool valid = false;
+ int inferType = 0;
+ if( k==kind::UNION ){
+ valid = true;
+ }else if( k==kind::INTERSECTION ){
+ //conclude x is in it2->second
+ //if also existing in members of r2
+ bool in_r2 = itm2!=d_pol_mems[0].end() && itm2->second.find( xr )!=itm2->second.end();
+ if( in_r2 ){
+ exp.push_back( itm2->second[xr] );
+ addEqualityToExp( it2->second[1], itm2->second[xr][1], exp );
+ addEqualityToExp( x, itm2->second[xr][0], exp );
+ valid = true;
+ }
+ }else{
+ Assert( k==kind::SETMINUS );
+ /*
+ std::map< Node, std::map< Node, Node > >::iterator itnm2 = d_pol_mems[1].find( r2 );
+ if( itnm2!=d_pol_mems[1].end() ){
+ bool not_in_r2 = itnm2->second.find( xr )!=itnm2->second.end();
+ if( not_in_r2 ){
+ exp.push_back( itnm2->second[xr] );
+ if( it2->second[1]!=itnm2->second[xr][1] ){
+ Assert( d_equalityEngine.areEqual( it2->second[1], itnm2->second[xr][1] ) );
+ exp.push_back( it2->second[1].eqNode( itnm2->second[xr][1] ) );
+ }
+ if( x!=itnm2->second[xr][0] ){
+ Assert( d_equalityEngine.areEqual( x, itnm2->second[xr][0] ) );
+ exp.push_back( NodeManager::currentNM()->mkNode( x.getType().isBoolean() ? kind::IFF : kind::EQUAL, x, itnm2->second[xr][0] ) );
+ }
+ valid = true;
+ }
+ }
+ */
+ if( !valid ){
+ bool in_r2 = itm2!=d_pol_mems[0].end() && itm2->second.find( xr )!=itm2->second.end();
+ if( !in_r2 ){
+ // must add lemma for set minus since non-membership in this case is not explained
+ exp.push_back( NodeManager::currentNM()->mkNode( kind::MEMBER, x, it2->second[1] ).negate() );
+ valid = true;
+ inferType = 1;
+ }
+ }
+ }
+ if( valid ){
+ Node rr = d_equalityEngine.getRepresentative( it2->second );
+ if( !isMember( x, rr ) ){
+ Node kk = getProxy( it2->second );
+ Node fact = NodeManager::currentNM()->mkNode( kind::MEMBER, x, kk );
+ assertInference( fact, exp, lemmas, "upc", inferType );
+ if( d_conflict ){
+ return;
+ }
+ }
+ }
+ Trace("sets-debug") << "done checking membership " << xr << " " << itm1m->second << std::endl;
+ }
+ }
+ if( k==kind::UNION ){
+ if( itm2!=d_pol_mems[0].end() ){
+ //for all members of r2
+ for( std::map< Node, Node >::iterator itm2m = itm2->second.begin(); itm2m != itm2->second.end(); ++itm2m ){
+ Node x = itm2m->second[0];
+ Node rr = d_equalityEngine.getRepresentative( it2->second );
+ if( !isMember( x, rr ) ){
+ std::vector< Node > exp;
+ exp.push_back( itm2m->second );
+ addEqualityToExp( it2->second[1], itm2m->second[1], exp );
+ Node k = getProxy( it2->second );
+ Node fact = NodeManager::currentNM()->mkNode( kind::MEMBER, x, k );
+ assertInference( fact, exp, lemmas, "upc2" );
+ if( d_conflict ){
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
+}
- /**
- * Disequality propagation if element type is set
- */
- if(x.getType().isSet()) {
- if(polarity) {
- const CDTNodeList* l = d_termInfoManager->getNonMembers(S);
- for(CDTNodeList::iterator it = l->begin(); it != l->end(); ++it) {
- TNode n = *it;
- learnLiteral( /* atom = */ EQUAL(x, n),
- /* polarity = */ false,
- /* reason = */ AND( MEMBER(x, S), NOT( MEMBER(n, S)) ) );
+void TheorySetsPrivate::checkDisequalities( std::vector< Node >& lemmas ) {
+ //disequalities
+ Trace("sets") << "Disequalities..." << std::endl;
+ for(NodeBoolMap::const_iterator it=d_deq.begin(); it !=d_deq.end(); ++it) {
+ if( (*it).second ){
+ Node deq = (*it).first;
+ bool is_sat = false;
+ //check if it is already satisfied
+ Assert( d_equalityEngine.hasTerm( deq[0] ) && d_equalityEngine.hasTerm( deq[1] ) );
+ Node r1 = d_equalityEngine.getRepresentative( deq[0] );
+ Node r2 = d_equalityEngine.getRepresentative( deq[1] );
+ TypeNode tn = r1.getType();
+ Node eqc_es = d_eqc_emptyset[tn];
+ for( unsigned e=0; e<2; e++ ){
+ Node a = e==0 ? r1 : r2;
+ Node b = e==0 ? r2 : r1;
+ //if there are members in a
+ std::map< Node, std::map< Node, Node > >::iterator itpma = d_pol_mems[0].find( a );
+ if( itpma!=d_pol_mems[0].end() ){
+ Assert( !itpma->second.empty() );
+ //if b is empty
+ if( b==eqc_es ){
+ if( !itpma->second.empty() ){
+ is_sat = true;
+ Trace("sets-deq") << "Disequality " << deq << " is satisfied because members are in " << a << " and " << b << " is empty" << std::endl;
+ }
+ }else{
+ std::map< Node, Node >::iterator itsb = d_eqc_singleton.find( b );
+ std::map< Node, std::map< Node, Node > >::iterator itpmb = d_pol_mems[1].find( b );
+ for( std::map< Node, Node >::iterator itm = itpma->second.begin(); itm != itpma->second.end(); ++itm ){
+ //if b is a singleton
+ if( false && itsb!=d_eqc_singleton.end() ){
+ //TODO?
+ //if a has positive member that is negative member in b
+ }else if( itpmb!=d_pol_mems[1].end() ){
+ for( std::map< Node, Node >::iterator itnm = itpmb->second.begin(); itnm != itpmb->second.end(); ++itnm ){
+ if( ee_areEqual( itm->first, itnm->first ) ){
+ Trace("sets-deq") << "Disequality " << deq << " is satisfied because of " << itm->second << " " << itnm->second << std::endl;
+ is_sat = true;
+ break;
+ }
+ }
+ }
+ if( is_sat ){
+ break;
+ }
+ }
+ }
+ if( is_sat ){
+ break;
+ }
+ }
}
- } else {
- const CDTNodeList* l = d_termInfoManager->getMembers(S);
- for(CDTNodeList::iterator it = l->begin(); it != l->end(); ++it) {
- TNode n = *it;
- learnLiteral( /* atom = */ EQUAL(x, n),
- /* polarity = */ false,
- /* reason = */ AND( NOT(MEMBER(x, S)), MEMBER(n, S)) );
+ /*
+ if( !is_sat ){
+ //try to make one of them empty
+ for( unsigned e=0; e<2; e++ ){
+
+ }
+ }
+ */
+
+ Trace("sets-debug") << "Check disequality " << deq << ", is_sat = " << is_sat << std::endl;
+ //will process regardless of sat/processed/unprocessed
+ d_deq[deq] = false;
+
+ if( !is_sat ){
+ if( d_deq_processed.find( deq )==d_deq_processed.end() ){
+ d_deq_processed.insert( deq );
+ d_deq_processed.insert( deq[1].eqNode( deq[0] ) );
+ Trace("sets") << "Process Disequality : " << deq.negate() << std::endl;
+ TypeNode elementType = deq[0].getType().getSetElementType();
+ Node x = NodeManager::currentNM()->mkSkolem("sde_", elementType);
+ Node mem1 = NodeManager::currentNM()->mkNode( kind::MEMBER, x, deq[0] );
+ Node mem2 = NodeManager::currentNM()->mkNode( kind::MEMBER, x, deq[1] );
+ Node lem = NodeManager::currentNM()->mkNode( kind::OR, deq, NodeManager::currentNM()->mkNode( kind::IFF, mem1, mem2 ).negate() );
+ lem = Rewriter::rewrite( lem );
+ assertInference( lem, d_emp_exp, lemmas, "diseq", 1 );
+ flushLemmas( lemmas );
+ if( hasProcessed() ){
+ return;
+ }
+ }
}
}
}
+}
- for(; !j.isFinished(); ++j) {
- TNode S = (*j);
- Node cur_atom = MEMBER(x, S);
-
- // propagation : children
- Debug("sets-prop") << "[sets-prop] Propagating 'down' for "
- << x << element_of_str << S << std::endl;
- if(S.getKind() == kind::UNION ||
- S.getKind() == kind::INTERSECTION ||
- S.getKind() == kind::SETMINUS ||
- S.getKind() == kind::SINGLETON) {
- doSettermPropagation(x, S);
- if(d_conflict) return;
- }// propagation: children
-
-
- // propagation : parents
- Debug("sets-prop") << "[sets-prop] Propagating 'up' for "
- << x << element_of_str << S << std::endl;
- const CDTNodeList* parentList = d_termInfoManager->getParents(S);
- for(CDTNodeList::const_iterator k = parentList->begin();
- k != parentList->end(); ++k) {
- doSettermPropagation(x, *k);
- if(d_conflict) return;
- }// propagation : parents
-
-
- }//j loop
-
-}/* TheorySetsPrivate::assertMemebership() */
-
-
-void TheorySetsPrivate::doSettermPropagation(TNode x, TNode S)
-{
- Debug("sets-prop") << "[sets-prop] doSettermPropagation("
- << x << ", " << S << std::endl;
-
- Assert(S.getType().isSet() && S.getType().getSetElementType() == x.getType(),
- ( std::string("types of S and x are ") + S.getType().toString() +
- std::string(" and ") + x.getType().toString() +
- std::string(" respectively") ).c_str() );
-
- Node literal, left_literal, right_literal;
-
- // axiom: literal <=> left_literal AND right_literal
- switch(S.getKind()) {
- case kind::INTERSECTION:
- literal = MEMBER(x, S) ;
- left_literal = MEMBER(x, S[0]) ;
- right_literal = MEMBER(x, S[1]) ;
- break;
- case kind::UNION:
- literal = NOT( MEMBER(x, S) );
- left_literal = NOT( MEMBER(x, S[0]) );
- right_literal = NOT( MEMBER(x, S[1]) );
- break;
- case kind::SETMINUS:
- literal = MEMBER(x, S) ;
- left_literal = MEMBER(x, S[0]) ;
- right_literal = NOT( MEMBER(x, S[1]) );
- break;
- case kind::SINGLETON: {
- Node atom = MEMBER(x, S);
- if(holds(atom, true)) {
- learnLiteral(EQUAL(x, S[0]), true, atom);
- } else if(holds(atom, false)) {
- learnLiteral(EQUAL(x, S[0]), false, NOT(atom));
+void TheorySetsPrivate::checkCardBuildGraph( std::vector< Node >& lemmas ) {
+ Trace("sets") << "Cardinality graph..." << std::endl;
+ //first, ensure cardinality relationships are added as lemmas for all non-basic set terms
+ for( unsigned i=0; i<d_set_eqc.size(); i++ ){
+ Node eqc = d_set_eqc[i];
+ std::map< Node, std::vector< Node > >::iterator itn = d_nvar_sets.find( eqc );
+ if( itn!=d_nvar_sets.end() ){
+ for( unsigned j=0; j<itn->second.size(); j++ ){
+ Node n = itn->second[j];
+ if( d_congruent.find( n )==d_congruent.end() ){
+ //if setminus, do for intersection instead
+ if( n.getKind()==kind::SETMINUS ){
+ n = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::INTERSECTION, n[0], n[1] ) );
+ }
+ registerCardinalityTerm( n, lemmas );
+ }
+ }
}
- return;
- }
- default:
- Unhandled();
}
+ Trace("sets") << "Done cardinality graph" << std::endl;
+}
- Debug("sets-prop-details")
- << "[sets-prop-details] " << literal << " IFF " << left_literal
- << " AND " << right_literal << std::endl;
-
- Debug("sets-prop-details")
- << "[sets-prop-details] "
- << (holds(literal) ? "yes" : (holds(literal.negate()) ? " no" : " _ "))
- << " IFF "
- << (holds(left_literal) ? "yes" : (holds(left_literal.negate()) ? "no " : " _ "))
- << " AND "
- << (holds(right_literal) ? "yes" : (holds(right_literal.negate()) ? "no " : " _ "))
- << std::endl;
-
- Assert( present( MEMBER(x, S) ) ||
- present( MEMBER(x, S[0]) ) ||
- present( MEMBER(x, S[1]) ) );
-
- if( holds(literal) ) {
- // 1a. literal => left_literal
- Debug("sets-prop") << "[sets-prop] ... via case 1a. ..." << std::endl;
- learnLiteral(left_literal, literal);
- if(d_conflict) return;
-
- // 1b. literal => right_literal
- Debug("sets-prop") << "[sets-prop] ... via case 1b. ..." << std::endl;
- learnLiteral(right_literal, literal);
- if(d_conflict) return;
-
- // subsumption requirement met, exit
- return;
- }
- else if( holds(literal.negate() ) ) {
- // 4. neg(literal), left_literal => neg(right_literal)
- if( holds(left_literal) ) {
- Debug("sets-prop") << "[sets-prop] ... via case 4. ..." << std::endl;
- learnLiteral(right_literal.negate(), AND( literal.negate(),
- left_literal) );
- if(d_conflict) return;
+void TheorySetsPrivate::registerCardinalityTerm( Node n, std::vector< Node >& lemmas ){
+ if( d_card_processed.find( n )==d_card_processed.end() ){
+ d_card_processed.insert( n );
+ Trace("sets-card") << "Cardinality lemmas for " << n << " : " << std::endl;
+ std::vector< Node > cterms;
+ if( n.getKind()==kind::INTERSECTION ){
+ for( unsigned e=0; e<2; e++ ){
+ Node s = NodeManager::currentNM()->mkNode( kind::SETMINUS, n[e], n[1-e] );
+ cterms.push_back( s );
+ }
+ Node pos_lem = NodeManager::currentNM()->mkNode( kind::GEQ, NodeManager::currentNM()->mkNode( kind::CARD, n ), d_zero );
+ assertInference( pos_lem, d_emp_exp, lemmas, "pcard", 1 );
+ }else{
+ cterms.push_back( n );
+ }
+ for( unsigned k=0; k<cterms.size(); k++ ){
+ Node nn = cterms[k];
+ Node nk = getProxy( nn );
+ Node pos_lem = NodeManager::currentNM()->mkNode( kind::GEQ, NodeManager::currentNM()->mkNode( kind::CARD, nk ), d_zero );
+ assertInference( pos_lem, d_emp_exp, lemmas, "pcard", 1 );
+ if( nn!=nk ){
+ Node lem = NodeManager::currentNM()->mkNode( kind::EQUAL, NodeManager::currentNM()->mkNode( kind::CARD, nk ),
+ NodeManager::currentNM()->mkNode( kind::CARD, nn ) );
+ lem = Rewriter::rewrite( lem );
+ Trace("sets-card") << " " << k << " : " << lem << std::endl;
+ assertInference( lem, d_emp_exp, lemmas, "card", 1 );
+ }
}
+ }
+}
- // 5. neg(literal), right_literal => neg(left_literal)
- if( holds(right_literal) ) {
- Debug("sets-prop") << "[sets-prop] ... via case 5. ..." << std::endl;
- learnLiteral(left_literal.negate(), AND( literal.negate(),
- right_literal) );
- if(d_conflict) return;
+void TheorySetsPrivate::checkCardCycles( std::vector< Node >& lemmas ) {
+ Trace("sets") << "Check cardinality cycles..." << std::endl;
+ //build order of equivalence classes, also build cardinality graph
+ std::vector< Node > set_eqc_tmp;
+ set_eqc_tmp.insert( set_eqc_tmp.end(), d_set_eqc.begin(), d_set_eqc.end() );
+ d_set_eqc.clear();
+ d_card_parent.clear();
+ for( unsigned i=0; i<set_eqc_tmp.size(); i++ ){
+ std::vector< Node > curr;
+ std::vector< Node > exp;
+ checkCardCyclesRec( set_eqc_tmp[i], curr, exp, lemmas );
+ flushLemmas( lemmas );
+ if( hasProcessed() ){
+ return;
}
}
- else {
- // 2,3. neg(left_literal) v neg(right_literal) => neg(literal)
- if(holds(left_literal.negate())) {
- Debug("sets-prop") << "[sets-prop] ... via case 2. ..." << std::endl;
- learnLiteral(literal.negate(), left_literal.negate());
- if(d_conflict) return;
- }
- else if(holds(right_literal.negate())) {
- Debug("sets-prop") << "[sets-prop] ... via case 3. ..." << std::endl;
- learnLiteral(literal.negate(), right_literal.negate());
- if(d_conflict) return;
+ Trace("sets") << "Done check cardinality cycles" << std::endl;
+}
+
+void TheorySetsPrivate::checkCardCyclesRec( Node eqc, std::vector< Node >& curr, std::vector< Node >& exp, std::vector< Node >& lemmas ) {
+ if( std::find( curr.begin(), curr.end(), eqc )!=curr.end() ){
+ Trace("sets-debug") << "Found venn region loop..." << std::endl;
+ if( curr.size()>1 ){
+ //all regions must be equal
+ std::vector< Node > conc;
+ for( unsigned i=1; i<curr.size(); i++ ){
+ conc.push_back( curr[0].eqNode( curr[i] ) );
+ }
+ Node fact = conc.size()==1 ? conc[0] : NodeManager::currentNM()->mkNode( kind::AND, conc );
+ assertInference( fact, exp, lemmas, "card_cycle" );
+ flushLemmas( lemmas );
+ }else{
+ //should be guaranteed based on not exploring equal parents
+ Assert( false );
+ }
+ }else if( std::find( d_set_eqc.begin(), d_set_eqc.end(), eqc )==d_set_eqc.end() ){
+ curr.push_back( eqc );
+ TypeNode tn = eqc.getType();
+ bool is_empty = eqc==d_eqc_emptyset[tn];
+ Node emp_set = getEmptySet( tn );
+ std::map< Node, std::vector< Node > >::iterator itn = d_nvar_sets.find( eqc );
+ if( itn!=d_nvar_sets.end() ){
+ for( unsigned j=0; j<itn->second.size(); j++ ){
+ Node n = itn->second[j];
+ if( n.getKind()==kind::INTERSECTION || n.getKind()==kind::SETMINUS ){
+ Trace("sets-debug") << "Build cardinality parents for " << n << "..." << std::endl;
+ std::vector< Node > sib;
+ unsigned true_sib = 0;
+ if( n.getKind()==kind::INTERSECTION ){
+ d_card_base[n] = n;
+ for( unsigned e=0; e<2; e++ ){
+ Node sm = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::SETMINUS, n[e], n[1-e] ) );
+ sib.push_back( sm );
+ }
+ true_sib = 2;
+ }else{
+ Node si = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::INTERSECTION, n[0], n[1] ) );
+ sib.push_back( si );
+ d_card_base[n] = si;
+ Node osm = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::SETMINUS, n[1], n[0] ) );
+ sib.push_back( osm );
+ true_sib = 1;
+ }
+ Node u = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::UNION, n[0], n[1] ) );
+ if( !d_equalityEngine.hasTerm( u ) ){
+ u = Node::null();
+ }
+ unsigned n_parents = true_sib + ( u.isNull() ? 0 : 1 );
+ //if this set is empty
+ if( is_empty ){
+ Assert( ee_areEqual( n, emp_set ) );
+ Trace("sets-debug") << " empty, parents equal siblings" << std::endl;
+ std::vector< Node > conc;
+ //parent equal siblings
+ for( unsigned e=0; e<true_sib; e++ ){
+ if( d_equalityEngine.hasTerm( sib[e] ) && !ee_areEqual( n[e], sib[e] ) ){
+ conc.push_back( n[e].eqNode( sib[e] ) );
+ }
+ }
+ assertInference( conc, n.eqNode( emp_set ), lemmas, "cg_emp" );
+ flushLemmas( lemmas );
+ if( hasProcessed() ){
+ return;
+ }else{
+ //justify why there is no edge to parents (necessary?)
+ for( unsigned e=0; e<n_parents; e++ ){
+ Node p = (e==true_sib) ? u : n[e];
+
+ }
+ }
+ }else{
+ std::vector< Node > card_parents;
+ std::vector< int > card_parent_ids;
+ //check if equal to a parent
+ for( unsigned e=0; e<n_parents; e++ ){
+ Trace("sets-debug") << " check parent " << e << "/" << n_parents << std::endl;
+ bool is_union = e==true_sib;
+ Node p = (e==true_sib) ? u : n[e];
+ Trace("sets-debug") << " check relation to parent " << p << ", isu=" << is_union << "..." << std::endl;
+ //if parent is empty
+ if( ee_areEqual( p, emp_set ) ){
+ Trace("sets-debug") << " it is empty..." << std::endl;
+ Assert( !ee_areEqual( n, emp_set ) );
+ assertInference( n.eqNode( emp_set ), p.eqNode( emp_set ), lemmas, "cg_emppar" );
+ if( hasProcessed() ){
+ return;
+ }
+ //if we are equal to a parent
+ }else if( ee_areEqual( p, n ) ){
+ Trace("sets-debug") << " it is equal to this..." << std::endl;
+ std::vector< Node > conc;
+ std::vector< int > sib_emp_indices;
+ if( is_union ){
+ for( unsigned s=0; s<sib.size(); s++ ){
+ sib_emp_indices.push_back( s );
+ }
+ }else{
+ sib_emp_indices.push_back( e );
+ }
+ //sibling(s) are empty
+ for( unsigned s=0; s<sib_emp_indices.size(); s++ ){
+ unsigned si = sib_emp_indices[s];
+ if( !ee_areEqual( sib[si], emp_set ) ){
+ conc.push_back( sib[si].eqNode( emp_set ) );
+ }else{
+ Trace("sets-debug") << "Sibling " << sib[si] << " is already empty." << std::endl;
+ }
+ }
+ if( !is_union && n.getKind()==kind::INTERSECTION && !u.isNull() ){
+ //union is equal to other parent
+ if( !ee_areEqual( u, n[1-e] ) ){
+ conc.push_back( u.eqNode( n[1-e] ) );
+ }
+ }
+ Trace("sets-debug") << "...derived " << conc.size() << " conclusions" << std::endl;
+ assertInference( conc, n.eqNode( p ), lemmas, "cg_eqpar" );
+ flushLemmas( lemmas );
+ if( hasProcessed() ){
+ return;
+ }
+ }else{
+ Trace("sets-cdg") << "Card graph : " << n << " -> " << p << std::endl;
+ //otherwise, we a syntactic subset of p
+ card_parents.push_back( p );
+ card_parent_ids.push_back( is_union ? 2 : e );
+ }
+ }
+ Assert( d_card_parent[n].empty() );
+ Trace("sets-debug") << "get parent representatives..." << std::endl;
+ //for each parent, take their representatives
+ for( unsigned k=0; k<card_parents.size(); k++ ){
+ Node eqcc = d_equalityEngine.getRepresentative( card_parents[k] );
+ Trace("sets-debug") << "Check card parent " << k << "/" << card_parents.size() << std::endl;
+
+ //if parent is singleton, then we should either be empty to equal to it
+ std::map< Node, Node >::iterator itps = d_eqc_singleton.find( eqcc );
+ if( itps!=d_eqc_singleton.end() ){
+ bool eq_parent = false;
+ std::vector< Node > exp;
+ addEqualityToExp( card_parents[k], itps->second, exp );
+ if( ee_areDisequal( n, emp_set ) ){
+ exp.push_back( n.eqNode( emp_set ).negate() );
+ eq_parent = true;
+ }else{
+ std::map< Node, std::map< Node, Node > >::iterator itpm = d_pol_mems[0].find( eqc );
+ if( itpm!=d_pol_mems[0].end() && !itpm->second.empty() ){
+ Node pmem = itpm->second.begin()->second;
+ exp.push_back( pmem );
+ addEqualityToExp( n, pmem[1], exp );
+ eq_parent = true;
+ }
+ }
+ //must be equal to parent
+ if( eq_parent ){
+ Node conc = n.eqNode( card_parents[k] );
+ assertInference( conc, exp, lemmas, "cg_par_sing" );
+ flushLemmas( lemmas );
+ }else{
+ //split on empty
+ Trace("sets-nf") << "Split empty : " << n << std::endl;
+ split( n.eqNode( emp_set ), 1 );
+ }
+ Assert( hasProcessed() );
+ return;
+ }else{
+ bool dup = false;
+ for( unsigned l=0; l<d_card_parent[n].size(); l++ ){
+ if( eqcc==d_card_parent[n][l] ){
+ Trace("sets-debug") << " parents " << l << " and " << k << " are equal, ids = " << card_parent_ids[l] << " " << card_parent_ids[k] << std::endl;
+ dup = true;
+ if( n.getKind()==kind::INTERSECTION ){
+ Assert( card_parent_ids[l]!=2 );
+ std::vector< Node > conc;
+ if( card_parent_ids[k]==2 ){
+ //intersection is equal to other parent
+ unsigned pid = 1-card_parent_ids[l];
+ if( !ee_areEqual( n[pid], n ) ){
+ Trace("sets-debug") << " one of them is union, make equal to other..." << std::endl;
+ conc.push_back( n[pid].eqNode( n ) );
+ }
+ }else{
+ if( !ee_areEqual( card_parents[k], n ) ){
+ Trace("sets-debug") << " neither is union, make equal to one parent..." << std::endl;
+ //intersection is equal to one of the parents
+ conc.push_back( card_parents[k].eqNode( n ) );
+ }
+ }
+ assertInference( conc, card_parents[k].eqNode( d_card_parent[n][l] ), lemmas, "cg_pareq" );
+ flushLemmas( lemmas );
+ if( hasProcessed() ){
+ return;
+ }
+ }
+ }
+ }
+ if( !dup ){
+ d_card_parent[n].push_back( eqcc );
+ }
+ }
+ }
+ //now recurse on parents (to ensure their normal will be computed after this eqc)
+ exp.push_back( eqc.eqNode( n ) );
+ for( unsigned k=0; k<d_card_parent[n].size(); k++ ){
+ checkCardCyclesRec( d_card_parent[n][k], curr, exp, lemmas );
+ if( hasProcessed() ){
+ return;
+ }
+ }
+ exp.pop_back();
+ }
+ }
+ }
}
+ curr.pop_back();
+ //parents now processed, can add to ordered list
+ d_set_eqc.push_back( eqc );
+ }else{
+ //already processed
+ }
+}
- // 6. the axiom itself:
- else if(holds(left_literal) && holds(right_literal)) {
- Debug("sets-prop") << "[sets-prop] ... via case 6. ..." << std::endl;
- learnLiteral(literal, AND(left_literal, right_literal) );
- if(d_conflict) return;
+void TheorySetsPrivate::checkNormalForms( std::vector< Node >& lemmas, std::vector< Node >& intro_sets ){
+ Trace("sets") << "Check normal forms..." << std::endl;
+ // now, build normal form for each equivalence class
+ // d_set_eqc is now sorted such that for each d_set_eqc[i], d_set_eqc[j],
+ // if d_set_eqc[i] is a strict syntactic subterm of d_set_eqc[j], then i<j.
+ d_ff.clear();
+ d_nf.clear();
+ for( int i=(int)(d_set_eqc.size()-1); i>=0; i-- ){
+ checkNormalForm( d_set_eqc[i], intro_sets );
+ if( hasProcessed() || !intro_sets.empty() ){
+ return;
}
}
-
- // check fulfilling rule
- Node n;
- switch(S.getKind()) {
- case kind::UNION:
- if( holds(MEMBER(x, S)) &&
- !present( MEMBER(x, S[0]) ) )
- addToPending( MEMBER(x, S[0]) );
- break;
- case kind::SETMINUS: // intentional fallthrough
- if( holds(MEMBER(x, S[0])) &&
- !present( MEMBER(x, S[1]) ))
- addToPending( MEMBER(x, S[1]) );
- break;
- case kind::INTERSECTION:
- return;
- default:
- Assert(false, "MembershipEngine::doSettermPropagation");
+ Trace("sets") << "Done check normal forms" << std::endl;
+}
+
+void TheorySetsPrivate::checkNormalForm( Node eqc, std::vector< Node >& intro_sets ){
+ TypeNode tn = eqc.getType();
+ Trace("sets") << "Compute normal form for " << eqc << std::endl;
+ Trace("sets-nf") << "Compute N " << eqc << "..." << std::endl;
+ if( eqc==d_eqc_emptyset[tn] ){
+ d_nf[eqc].clear();
+ Trace("sets-nf") << "----> N " << eqc << " => {}" << std::endl;
+ }else{
+ //flat/normal forms are sets of equivalence classes
+ Node base;
+ std::vector< Node > comps;
+ std::map< Node, std::map< Node, std::vector< Node > > >::iterator it = d_ff.find( eqc );
+ if( it!=d_ff.end() ){
+ for( std::map< Node, std::vector< Node > >::iterator itf = it->second.begin(); itf != it->second.end(); ++itf ){
+ std::sort( itf->second.begin(), itf->second.end() );
+ if( base.isNull() ){
+ base = itf->first;
+ }else{
+ comps.push_back( itf->first );
+ }
+ Trace("sets-nf") << " F " << itf->first << " : ";
+ if( Trace.isOn("sets-nf") ){
+ Trace("sets-nf") << "{ ";
+ for( unsigned k=0; k<itf->second.size(); k++ ){
+ if( k>0 ){ Trace("sets-nf") << ", "; }
+ Trace("sets-nf") << "[" << itf->second[k] << "]";
+ }
+ Trace("sets-nf") << " }" << std::endl;
+ }
+ Trace("sets-nf-debug") << " ...";
+ debugPrintSet( itf->first, "sets-nf-debug" );
+ Trace("sets-nf-debug") << std::endl;
+ }
+ }else{
+ Trace("sets-nf") << "(no flat forms)" << std::endl;
+ }
+
+ Assert( d_nf.find( eqc )==d_nf.end() );
+ bool success = true;
+ if( !base.isNull() ){
+ Node emp_set = getEmptySet( tn );
+ for( unsigned j=0; j<comps.size(); j++ ){
+ //compare if equal
+ std::vector< Node > c;
+ c.push_back( base );
+ c.push_back( comps[j] );
+ std::vector< Node > only[2];
+ std::vector< Node > common;
+ Trace("sets-nf-debug") << "Compare venn regions of " << base << " vs " << comps[j] << std::endl;
+ unsigned k[2] = { 0, 0 };
+ while( k[0]<d_ff[eqc][c[0]].size() || k[1]<d_ff[eqc][c[1]].size() ){
+ bool proc = true;
+ for( unsigned e=0; e<2; e++ ){
+ if( k[e]==d_ff[eqc][c[e]].size() ){
+ for( ; k[1-e]<d_ff[eqc][c[1-e]].size(); ++k[1-e] ){
+ only[1-e].push_back( d_ff[eqc][c[1-e]][k[1-e]] );
+ }
+ proc = false;
+ }
+ }
+ if( proc ){
+ if( d_ff[eqc][c[0]][k[0]]==d_ff[eqc][c[1]][k[1]] ){
+ common.push_back( d_ff[eqc][c[0]][k[0]] );
+ k[0]++;
+ k[1]++;
+ }else if( d_ff[eqc][c[0]][k[0]]<d_ff[eqc][c[1]][k[1]] ){
+ only[0].push_back( d_ff[eqc][c[0]][k[0]] );
+ k[0]++;
+ }else{
+ only[1].push_back( d_ff[eqc][c[1]][k[1]] );
+ k[1]++;
+ }
+ }
+ }
+ if( !only[0].empty() || !only[1].empty() ){
+ if( Trace.isOn("sets-nf-debug") ){
+ Trace("sets-nf-debug") << "Unique venn regions : " << std::endl;
+ for( unsigned e=0; e<2; e++ ){
+ Trace("sets-nf-debug") << " " << c[e] << " : { ";
+ for( unsigned l=0; l<only[e].size(); l++ ){
+ if( l>0 ){ Trace("sets-nf-debug") << ", "; }
+ Trace("sets-nf-debug") << "[" << only[e][l] << "]";
+ }
+ Trace("sets-nf-debug") << " }" << std::endl;
+ }
+ }
+ //try to make one empty, prefer the unique ones first
+ for( unsigned e=0; e<3; e++ ){
+ unsigned sz = e==2 ? common.size() : only[e].size();
+ for( unsigned l=0; l<sz; l++ ){
+ Node r = e==2 ? common[l] : only[e][l];
+ Trace("sets-nf-debug") << "Try split empty : " << r << std::endl;
+ Trace("sets-nf-debug") << " actual : ";
+ debugPrintSet( r, "sets-nf-debug" );
+ Trace("sets-nf-debug") << std::endl;
+ Assert( !ee_areEqual( r, emp_set ) );
+ if( !ee_areDisequal( r, emp_set ) && ( d_pol_mems[0].find( r )==d_pol_mems[0].end() || d_pol_mems[0][r].empty() ) ){
+ //guess that its equal empty if it has no explicit members
+ Trace("sets-nf") << " Split empty : " << r << std::endl;
+ Trace("sets-nf") << "Actual Split : ";
+ debugPrintSet( r, "sets-nf" );
+ Trace("sets-nf") << std::endl;
+ split( r.eqNode( emp_set ), 1 );
+ Assert( hasProcessed() );
+ return;
+ }
+ }
+ }
+ for( unsigned l=0; l<only[0].size(); l++ ){
+ for( unsigned m=0; m<only[1].size(); m++ ){
+ bool disjoint = false;
+ Trace("sets-nf-debug") << "Try split " << only[0][l] << " against " << only[1][m] << std::endl;
+ //split them
+ for( unsigned e=0; e<2; e++ ){
+ Node r1 = e==0 ? only[0][l] : only[1][m];
+ Node r2 = e==0 ? only[1][m] : only[0][l];
+ //check if their intersection exists modulo equality
+ std::map< Node, Node >::iterator itb = d_bop_index[kind::INTERSECTION][r1].find( r2 );
+ if( itb!=d_bop_index[kind::INTERSECTION][r1].end() ){
+ Trace("sets-nf-debug") << "Split term already exists, but not in cardinality graph : " << itb->second << ", should be empty." << std::endl;
+ //their intersection is empty (probably?)
+ // e.g. these are two disjoint venn regions, proceed to next pair
+ Assert( ee_areEqual( emp_set, itb->second ) );
+ disjoint = true;
+ break;
+ }
+ }
+ if( !disjoint ){
+ //simply introduce their intersection
+ Assert( only[0][l]!=only[1][m] );
+ Node kca = getProxy( only[0][l] );
+ Node kcb = getProxy( only[1][m] );
+ Node intro = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::INTERSECTION, kca, kcb ) );
+ Trace("sets-nf") << " Intro split : " << only[0][l] << " against " << only[1][m] << ", term is " << intro << std::endl;
+ intro_sets.push_back( intro );
+ Assert( !d_equalityEngine.hasTerm( intro ) );
+ return;
+ }
+ }
+ }
+ //should never get here
+ success = false;
+ }
+ }
+ if( success ){
+ //normal form is flat form of base
+ d_nf[eqc].insert( d_nf[eqc].end(), d_ff[eqc][base].begin(), d_ff[eqc][base].end() );
+ Trace("sets-nf") << "----> N " << eqc << " => F " << base << std::endl;
+ }else{
+ Trace("sets-nf") << "failed to build N " << eqc << std::endl;
+ Assert( false );
+ }
+ }else{
+ //normal form is this equivalence class
+ d_nf[eqc].push_back( eqc );
+ Trace("sets-nf") << "----> N " << eqc << " => { " << eqc << " }" << std::endl;
+ }
+ if( success ){
+ //send to parents
+ std::map< Node, std::vector< Node > >::iterator itn = d_nvar_sets.find( eqc );
+ if( itn!=d_nvar_sets.end() ){
+ std::map< Node, std::map< Node, bool > > parents_proc;
+ for( unsigned j=0; j<itn->second.size(); j++ ){
+ Node n = itn->second[j];
+ Trace("sets-nf-debug") << "Carry nf for term " << n << std::endl;
+ if( !d_card_parent[n].empty() ){
+ Assert( d_card_base.find( n )!=d_card_base.end() );
+ Node cbase = d_card_base[n];
+ Trace("sets-nf-debug") << "Card base is " << cbase << std::endl;
+ for( unsigned k=0; k<d_card_parent[n].size(); k++ ){
+ Node p = d_card_parent[n][k];
+ Trace("sets-nf-debug") << "Check parent " << p << std::endl;
+ if( parents_proc[cbase].find( p )==parents_proc[cbase].end() ){
+ parents_proc[cbase][p] = true;
+ Trace("sets-nf-debug") << "Carry nf to parent ( " << cbase << ", [" << p << "] ), from " << n << "..." << std::endl;
+ //for( unsigned i=0; i<d_nf[eqc].size(); i++ ){
+ // Assert( std::find( d_ff[p][cbase].begin(), d_ff[p][cbase].end(), d_nf[eqc][i] )==d_ff[p][cbase].end() );
+ //}
+ for( unsigned i=0; i<d_nf[eqc].size(); i++ ){
+ if( std::find( d_ff[p][cbase].begin(), d_ff[p][cbase].end(), d_nf[eqc][i] )==d_ff[p][cbase].end() ){
+ d_ff[p][cbase].insert( d_ff[p][cbase].end(), d_nf[eqc].begin(), d_nf[eqc].end() );
+ }else{
+ //if it is a duplicate venn region, it must be empty since it is coming from syntactically disjoint siblings TODO?
+ }
+ }
+ }else{
+ Trace("sets-nf-debug") << "..already processed parent " << p << " for " << cbase << std::endl;
+ }
+ }
+ }
+ }
+ }
+ }else{
+ Assert( hasProcessed() );
+ }
}
}
+void TheorySetsPrivate::checkMinCard( std::vector< Node >& lemmas ) {
-void TheorySetsPrivate::learnLiteral(TNode atom, bool polarity, Node reason) {
- Debug("sets-learn") << "[sets-learn] learnLiteral(" << atom
- << ", " << polarity << ")" << std::endl;
-
- if( holds(atom, polarity) ) {
- Debug("sets-learn") << "[sets-learn] \u2514 already known, skipping" << std::endl;
- return;
+ for( int i=(int)(d_set_eqc.size()-1); i>=0; i-- ){
+ Node eqc = d_set_eqc[i];
+ //get members in class
+ std::map< Node, std::map< Node, Node > >::iterator itm = d_pol_mems[0].find( eqc );
+ if( itm!=d_pol_mems[0].end() ){
+ std::vector< Node > exp;
+ std::vector< Node > members;
+ Node cardTerm;
+ std::map< Node, Node >::iterator it = d_eqc_to_card_term.find( eqc );
+ if( it!=d_eqc_to_card_term.end() ){
+ cardTerm = it->second;
+ }else{
+ cardTerm = NodeManager::currentNM()->mkNode( kind::CARD, eqc );
+ }
+ for( std::map< Node, Node >::iterator itmm = itm->second.begin(); itmm != itm->second.end(); ++itmm ){
+ /*
+ for( unsigned j=0; j<members.size(); j++ ){
+ if( !ee_areDisequal( members[j], itmm->second ) ){
+ Assert( !ee_areEqual( members[j], itmm->second ) );
+
+ }
+ }
+ */
+ members.push_back( itmm->first );
+ exp.push_back( NodeManager::currentNM()->mkNode( kind::MEMBER, itmm->first, cardTerm[0] ) );
+ }
+ if( members.size()>1 ){
+ exp.push_back( NodeManager::currentNM()->mkNode( kind::DISTINCT, members ) );
+ }
+ if( !members.empty() ){
+ Node conc = NodeManager::currentNM()->mkNode( kind::GEQ, cardTerm, NodeManager::currentNM()->mkConst( Rational( members.size() ) ) );
+ Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp.size()==1 ? exp[0] : NodeManager::currentNM()->mkNode( kind::AND, exp ), conc );
+ Trace("sets-lemma") << "Sets::Lemma : " << lem << " by mincard" << std::endl;
+ lemmas.push_back( lem );
+ }
+ }
}
+}
- if( holds(atom, !polarity) ) {
- Debug("sets-learn") << "[sets-learn] \u2514 conflict found" << std::endl;
-
- registerReason(reason, /*save=*/ true);
-
- if(atom.getKind() == kind::EQUAL) {
- d_equalityEngine.assertEquality(atom, polarity, reason);
- } else {
- d_equalityEngine.assertPredicate(atom, polarity, reason);
+void TheorySetsPrivate::flushLemmas( std::vector< Node >& lemmas ) {
+ //do lemmas
+ for( unsigned i=0; i<lemmas.size(); i++ ){
+ Node lem = lemmas[i];
+ if( d_lemmas_produced.find(lem)==d_lemmas_produced.end() ){
+ Trace("sets-lemma-debug") << "Send lemma : " << lem << std::endl;
+ d_lemmas_produced.insert(lem);
+ d_external.d_out->lemma(lem);
+ d_sentLemma = true;
+ }else{
+ Trace("sets-lemma-debug") << "Already sent lemma : " << lem << std::endl;
+ }
+ }
+ lemmas.clear();
+}
+
+Node TheorySetsPrivate::getProxy( Node n ) {
+ if( n.getKind()==kind::EMPTYSET || n.getKind()==kind::SINGLETON || n.getKind()==kind::INTERSECTION || n.getKind()==kind::SETMINUS || n.getKind()==kind::UNION ){
+ NodeMap::const_iterator it = d_proxy.find( n );
+ if( it==d_proxy.end() ){
+ Node k = NodeManager::currentNM()->mkSkolem( "sp", n.getType(), "proxy for set" );
+ d_proxy[n] = k;
+ d_proxy_to_term[k] = n;
+ Node eq = k.eqNode( n );
+ Trace("sets-lemma") << "Sets::Lemma : " << eq << " by proxy" << std::endl;
+ d_external.d_out->lemma( eq );
+ if( n.getKind()==kind::SINGLETON ){
+ Node slem = NodeManager::currentNM()->mkNode( kind::MEMBER, n[0], k );
+ Trace("sets-lemma") << "Sets::Lemma : " << slem << " by singleton" << std::endl;
+ d_external.d_out->lemma( slem );
+ d_sentLemma = true;
+ }
+ return k;
+ }else{
+ return (*it).second;
}
- Assert(d_conflict); // should be marked due to equality engine
- return;
+ }else{
+ return n;
}
+}
- Assert(atom.getKind() == kind::EQUAL || atom.getKind() == kind::MEMBER);
-
- Node learnt_literal = polarity ? Node(atom) : NOT(atom);
- d_propagationQueue.push_back( make_pair(learnt_literal, reason) );
-}/*TheorySetsPrivate::learnLiteral(...)*/
-
-
-/************************ CardVar ************************/
+Node TheorySetsPrivate::getCongruent( Node n ) {
+ Assert( d_equalityEngine.hasTerm( n ) );
+ std::map< Node, Node >::iterator it = d_congruent.find( n );
+ if( it==d_congruent.end() ){
+ return n;
+ }else{
+ return it->second;
+ }
+}
-Node TheorySetsPrivate::getCardVar(TNode n) {
- NodeNodeHashMap::iterator it = d_setTermToCardVar.find(n);
- if(it == d_setTermToCardVar.end()) {
+Node TheorySetsPrivate::getEmptySet( TypeNode tn ) {
+ std::map< TypeNode, Node >::iterator it = d_emptyset.find( tn );
+ if( it==d_emptyset.end() ){
+ Node n = NodeManager::currentNM()->mkConst(EmptySet(tn.toType()));
+ d_emptyset[tn] = n;
+ return n;
+ }else{
return it->second;
- } else {
- NodeManager* nm = NodeManager::currentNM();
- Node cardVar = nm->mkSkolem("scv_", n.getType());
- d_setTermToCardVar[n] = cardVar;
- d_cardVarToSetTerm[cardVar] = n;
- return cardVar;
}
}
-Node TheorySetsPrivate::newCardVar(TNode n) {
- NodeNodeHashMap::iterator it = d_cardVarToSetTerm.find(n);
- Assert(it != d_cardVarToSetTerm.end());
- return it->second;
+bool TheorySetsPrivate::hasLemmaCached( Node lem ) {
+ return d_lemmas_produced.find(lem)!=d_lemmas_produced.end();
}
-bool TheorySetsPrivate::isCardVar(TNode n) {
- NodeNodeHashMap::iterator it = d_cardVarToSetTerm.find(n);
- return it != d_cardVarToSetTerm.end();
+bool TheorySetsPrivate::hasProcessed() {
+ return d_conflict || d_sentLemma || d_addedFact;
}
+void TheorySetsPrivate::debugPrintSet( Node s, const char * c ) {
+ if( s.getNumChildren()==0 ){
+ NodeMap::const_iterator it = d_proxy_to_term.find( s );
+ if( it!=d_proxy_to_term.end() ){
+ debugPrintSet( (*it).second, c );
+ }else{
+ Trace(c) << s;
+ }
+ }else{
+ Trace(c) << "(" << s.getOperator();
+ for( unsigned i=0; i<s.getNumChildren(); i++ ){
+ Trace(c) << " ";
+ debugPrintSet( s[i], c );
+ }
+ Trace(c) << ")";
+ }
+}
+
+/**************************** TheorySetsPrivate *****************************/
+/**************************** TheorySetsPrivate *****************************/
+/**************************** TheorySetsPrivate *****************************/
+
+void TheorySetsPrivate::check(Theory::Effort level) {
+ Trace("sets-check") << "Sets check effort " << level << std::endl;
+ while(!d_external.done() && !d_conflict) {
+ // Get all the assertions
+ Assertion assertion = d_external.get();
+ TNode fact = assertion.assertion;
+ Trace("sets-assert") << "Assert from input " << fact << std::endl;
+ //assert the fact
+ assertFact( fact, fact );
+ }
+ d_sentLemma = false;
+ Trace("sets-check") << "Sets finished assertions effort " << level << std::endl;
+ if( level == Theory::EFFORT_FULL && !d_conflict && !d_external.d_valuation.needCheck() ){
+ fullEffortCheck();
+ }
+ // invoke the relational solver
+ if( !d_conflict && !d_sentLemma ){
+ d_rels->check(level);
+ }
+ Trace("sets-check") << "Sets finish Check effort " << level << std::endl;
+}/* TheorySetsPrivate::check() */
+
/************************ Sharing ************************/
/************************ Sharing ************************/
@@ -461,187 +1515,135 @@ bool TheorySetsPrivate::isCardVar(TNode n) {
void TheorySetsPrivate::addSharedTerm(TNode n) {
Debug("sets") << "[sets] ThoerySetsPrivate::addSharedTerm( " << n << ")" << std::endl;
- d_termInfoManager->addTerm(n);
d_equalityEngine.addTriggerTerm(n, THEORY_SETS);
}
-void TheorySetsPrivate::dumpAssertionsHumanified() const
-{
- std::string tag = "sets-assertions";
-
- if(Trace.isOn(tag)) { /* condition can't be !Trace.isOn, that's why this empty block */ }
- else { return; }
-
- context::CDList<Assertion>::const_iterator it = d_external.facts_begin(), it_end = d_external.facts_end();
-
- typedef std::set<TNode> TNodeSet;
-
- typedef std::map<TNode, TNodeSet > EqualityMap;
- EqualityMap equalities;
-
- typedef std::set< std::pair<TNode, TNode> > TNodePairSet;
- TNodePairSet disequalities;
- typedef std::map<TNode, std::pair<TNodeSet, TNodeSet > > MemberMap;
- MemberMap members;
- static std::map<TNode, int> numbering;
- static int number = 0;
-
- for (unsigned i = 0; it != it_end; ++ it, ++i) {
- TNode ass = (*it).assertion;
- // Trace("sets-care-dump") << AssertCommand(ass.toExpr()) << endl;
- bool polarity = ass.getKind() != kind::NOT;
- ass = polarity ? ass : ass[0];
- Assert( ass.getNumChildren() == 2);
- TNode left = d_equalityEngine.getRepresentative(ass[0]);
- TNode right = d_equalityEngine.getRepresentative(ass[1]);
- if(numbering[left] == 0) numbering[left] = ++number;
- if(numbering[right] == 0) numbering[right] = ++number;
- equalities[left].insert(ass[0]);
- equalities[right].insert(ass[1]);
- if(ass.getKind() == kind::EQUAL) {
- if(polarity) {
- Assert(left == right);
- } else {
- if(left > right) std::swap(left, right);
- disequalities.insert(make_pair(left, right));
+void TheorySetsPrivate::addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth, unsigned& n_pairs ){
+ if( depth==arity ){
+ if( t2!=NULL ){
+ Node f1 = t1->getNodeData();
+ Node f2 = t2->getNodeData();
+ if( !ee_areEqual( f1, f2 ) ){
+ Trace("sets-cg") << "Check " << f1 << " and " << f2 << std::endl;
+ vector< pair<TNode, TNode> > currentPairs;
+ for (unsigned k = 0; k < f1.getNumChildren(); ++ k) {
+ TNode x = f1[k];
+ TNode y = f2[k];
+ Assert( d_equalityEngine.hasTerm(x) );
+ Assert( d_equalityEngine.hasTerm(y) );
+ Assert( !ee_areDisequal( x, y ) );
+ if( !d_equalityEngine.areEqual( x, y ) ){
+ Trace("sets-cg") << "Arg #" << k << " is " << x << " " << y << std::endl;
+ if( d_equalityEngine.isTriggerTerm(x, THEORY_SETS) && d_equalityEngine.isTriggerTerm(y, THEORY_SETS) ){
+ TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_SETS);
+ TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_SETS);
+ Trace("sets-cg") << "Arg #" << k << " shared term is " << x_shared << " " << y_shared << std::endl;
+ EqualityStatus eqStatus = d_external.d_valuation.getEqualityStatus(x_shared, y_shared);
+ Trace("sets-cg") << "...eq status is " << eqStatus << std::endl;
+ if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
+ //an argument is disequal, we are done
+ return;
+ }else{
+ currentPairs.push_back(make_pair(x_shared, y_shared));
+ }
+ }else if( isCareArg( f1, k ) && isCareArg( f2, k ) ){
+ //splitting on sets (necessary for handling set of sets properly)
+ if( x.getType().isSet() ){
+ Assert( y.getType().isSet() );
+ if( !ee_areDisequal( x, y ) ){
+ Trace("sets-cg-lemma") << "Should split on : " << x << "==" << y << std::endl;
+ split( x.eqNode( y ) );
+ }
+ }
+ }
+ }
+ }
+ for (unsigned c = 0; c < currentPairs.size(); ++ c) {
+ Trace("sets-cg-pair") << "Pair : " << currentPairs[c].first << " " << currentPairs[c].second << std::endl;
+ d_external.addCarePair(currentPairs[c].first, currentPairs[c].second);
+ n_pairs++;
}
- } else if(ass.getKind() == kind::MEMBER) {
- (polarity ? members[right].first : members[right].second).insert(left);
}
}
- for(EqualityMap::const_iterator kt =equalities.begin(); kt != equalities.end(); ++kt) {
- Trace(tag) << " Eq class of t" << numbering[(*kt).first] << ": " << std::endl;
-
- const TNodeSet& kt_second = (*kt).second;
- for(TNodeSet::const_iterator jt=kt_second.begin(); jt != kt_second.end(); ++jt) {
- TNode S = (*jt);
- if( S.getKind() != kind::UNION && S.getKind() != kind::INTERSECTION && S.getKind() != kind::SETMINUS) {
- Trace(tag) << " " << *jt << ((*jt).getType().isSet() ? "\n": " ");
- } else {
- Trace(tag) << " ";
- if(S[0].isConst() || numbering.find(d_equalityEngine.getRepresentative(S[0])) == numbering.end()) {
- Trace(tag) << S[0];
- } else {
- Trace(tag) << "t" << numbering[d_equalityEngine.getRepresentative(S[0])];
- }
- Trace(tag) << " " << (S.getKind() == kind::UNION ? "|" : (S.getKind() == kind::INTERSECTION ? "&" : "-")) << " ";
- if(S[1].isConst() || numbering.find(d_equalityEngine.getRepresentative(S[1])) == numbering.end()) {
- Trace(tag) << S[1];
- } else {
- Trace(tag) << "t" << numbering[d_equalityEngine.getRepresentative(S[1])];
- }
- Trace(tag) << std::endl;
+ }else{
+ if( t2==NULL ){
+ if( depth<(arity-1) ){
+ //add care pairs internal to each child
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ addCarePairs( &it->second, NULL, arity, depth+1, n_pairs );
}
}
- Trace(tag) << std::endl;
- }
- for(TNodePairSet::const_iterator kt=disequalities.begin(); kt != disequalities.end(); ++kt){
- Trace(tag) << "NOT(t"<<numbering[(*kt).first]<<" = t" <<numbering[(*kt).second] <<")"<< std::endl;
- }
- for(MemberMap::const_iterator kt=members.begin(); kt != members.end(); ++kt) {
- const TNode& kt_key = (*kt).first;
- const TNodeSet& kt_in_set = (*kt).second.first;
- const TNodeSet& kt_out_set = (*kt).second.first;
- if( kt_in_set.size() > 0) {
- Trace(tag) << "IN t" << numbering[kt_key] << ": ";
- //FORIT(jt, (*kt).second.first)
- for(TNodeSet::const_iterator jt=kt_in_set.begin(); jt != kt_in_set.end(); ++jt) {
- TNode x = (*jt);
- if(x.isConst() || numbering.find(d_equalityEngine.getRepresentative(x)) == numbering.end()) {
- Trace(tag) << x << ", ";
- } else {
- Trace(tag) << "t" << numbering[d_equalityEngine.getRepresentative(x)] << ", ";
+ //add care pairs based on each pair of non-disequal arguments
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ std::map< TNode, quantifiers::TermArgTrie >::iterator it2 = it;
+ ++it2;
+ for( ; it2 != t1->d_data.end(); ++it2 ){
+ if( !ee_areDisequal(it->first, it2->first) ){
+ addCarePairs( &it->second, &it2->second, arity, depth+1, n_pairs );
}
}
- Trace(tag) << std::endl;
}
- if( kt_out_set.size() > 0) {
- Trace(tag) << "NOT IN t" << numbering[kt_key] << ": ";
- for(TNodeSet::const_iterator jt=kt_out_set.begin(); jt != kt_out_set.end(); ++jt){
- TNode x = (*jt);
- if(x.isConst() || numbering.find(d_equalityEngine.getRepresentative(x)) == numbering.end()) {
- Trace(tag) << x << ", ";
- } else {
- Trace(tag) << "t" << numbering[d_equalityEngine.getRepresentative(x)] << ", ";
+ }else{
+ //add care pairs based on product of indices, non-disequal arguments
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it = t1->d_data.begin(); it != t1->d_data.end(); ++it ){
+ for( std::map< TNode, quantifiers::TermArgTrie >::iterator it2 = t2->d_data.begin(); it2 != t2->d_data.end(); ++it2 ){
+ if( !ee_areDisequal(it->first, it2->first) ){
+ addCarePairs( &it->second, &it2->second, arity, depth+1, n_pairs );
}
}
- Trace(tag) << std::endl;
}
}
- Trace(tag) << std::endl;
+ }
}
void TheorySetsPrivate::computeCareGraph() {
- Debug("sharing") << "Theory::computeCareGraph<" << d_external.identify() << ">()" << endl;
-
- if(Trace.isOn("sets-assertions")) {
- // dump our understanding of assertions
- dumpAssertionsHumanified();
- }
-
- CVC4_UNUSED unsigned edgesAddedCnt = 0;
-
- unsigned i_st = 0;
- if(options::setsCare1()) { i_st = d_ccg_i; }
- for (unsigned i = i_st; i < d_external.d_sharedTerms.size(); ++ i) {
- TNode a = d_external.d_sharedTerms[i];
- TypeNode aType = a.getType();
-
- unsigned j_st = i + 1;
- if(options::setsCare1()) { if(i == d_ccg_i) j_st = d_ccg_j + 1; }
-
- for (unsigned j = j_st; j < d_external.d_sharedTerms.size(); ++ j) {
- TNode b = d_external.d_sharedTerms[j];
- if (b.getType() != aType) {
- // We don't care about the terms of different types
- continue;
- }
-
- switch (d_external.d_valuation.getEqualityStatus(a, b)) {
- case EQUALITY_TRUE_AND_PROPAGATED:
- // If we know about it, we should have propagated it, so we can skip
- Trace("sets-care") << "[sets-care] Know: " << EQUAL(a, b) << std::endl;
- break;
- case EQUALITY_FALSE_AND_PROPAGATED:
- // If we know about it, we should have propagated it, so we can skip
- Trace("sets-care") << "[sets-care] Know: " << NOT(EQUAL(a, b)) << std::endl;
- break;
- case EQUALITY_FALSE:
- case EQUALITY_TRUE:
- Assert(false, "ERROR: Equality status true/false but not propagated (sets care graph computation).");
- break;
- case EQUALITY_TRUE_IN_MODEL:
- d_external.addCarePair(a, b);
- if(Trace.isOn("sharing")) {
- ++edgesAddedCnt;
+ for( std::map< Kind, std::vector< Node > >::iterator it = d_op_list.begin(); it != d_op_list.end(); ++it ){
+ if( it->first==kind::SINGLETON || it->first==kind::MEMBER ){
+ unsigned n_pairs = 0;
+ Trace("sets-cg-summary") << "Compute graph for sets, op=" << it->first << "..." << it->second.size() << std::endl;
+ Trace("sets-cg") << "Build index for " << it->first << "..." << std::endl;
+ std::map< TypeNode, quantifiers::TermArgTrie > index;
+ unsigned arity = 0;
+ //populate indices
+ for( unsigned i=0; i<it->second.size(); i++ ){
+ TNode f1 = it->second[i];
+ Assert(d_equalityEngine.hasTerm(f1));
+ Trace("sets-cg-debug") << "...build for " << f1 << std::endl;
+ //break into index based on operator, and type of first argument (since some operators are parametric)
+ TypeNode tn = f1[0].getType();
+ std::vector< TNode > reps;
+ bool hasCareArg = false;
+ for( unsigned j=0; j<f1.getNumChildren(); j++ ){
+ reps.push_back( d_equalityEngine.getRepresentative( f1[j] ) );
+ if( isCareArg( f1, j ) ){
+ hasCareArg = true;
+ }
}
- if(Debug.isOn("sets-care")) {
- Debug("sets-care") << "[sets-care] Requesting split between" << a << " and "
- << b << "." << std::endl << "[sets-care] "
- << " Both current have value "
- << d_external.d_valuation.getModelValue(a) << std::endl;
- }
- case EQUALITY_FALSE_IN_MODEL:
- if(Trace.isOn("sets-care-performance-test")) {
- // TODO: delete these lines, only for performance testing for now
- d_external.addCarePair(a, b);
+ if( hasCareArg ){
+ index[tn].addTerm( f1, reps );
+ arity = reps.size();
}
- break;
- case EQUALITY_UNKNOWN:
- // Let's split on it
- d_external.addCarePair(a, b);
- if(options::setsCare1()) {
- d_ccg_i = i;
- d_ccg_j = j;
- return;
+ }
+ if( arity>0 ){
+ //for each index
+ for( std::map< TypeNode, quantifiers::TermArgTrie >::iterator iti = index.begin(); iti != index.end(); ++iti ){
+ Trace("sets-cg") << "Process index " << iti->first << "..." << std::endl;
+ addCarePairs( &iti->second, NULL, arity, 0, n_pairs );
}
- break;
- default:
- Unreachable();
}
+ Trace("sets-cg-summary") << "...done, # pairs = " << n_pairs << std::endl;
}
}
- Trace("sharing") << "TheorySetsPrivate::computeCareGraph(): size = " << edgesAddedCnt << std::endl;
+}
+
+bool TheorySetsPrivate::isCareArg( Node n, unsigned a ) {
+ if( d_equalityEngine.isTriggerTerm( n[a], THEORY_SETS ) ){
+ return true;
+ }else if( ( n.getKind()==kind::MEMBER || n.getKind()==kind::SINGLETON ) && a==0 && n[0].getType().isSet() ){
+ return true;
+ }else{
+ return false;
+ }
}
EqualityStatus TheorySetsPrivate::getEqualityStatus(TNode a, TNode b) {
@@ -654,6 +1656,8 @@ EqualityStatus TheorySetsPrivate::getEqualityStatus(TNode a, TNode b) {
// The terms are implied to be dis-equal
return EQUALITY_FALSE;
}
+ return EQUALITY_UNKNOWN;
+ /*
Node aModelValue = d_external.d_valuation.getModelValue(a);
if(aModelValue.isNull()) { return EQUALITY_UNKNOWN; }
Node bModelValue = d_external.d_valuation.getModelValue(b);
@@ -664,6 +1668,7 @@ EqualityStatus TheorySetsPrivate::getEqualityStatus(TNode a, TNode b) {
} else {
return EQUALITY_FALSE_IN_MODEL;
}
+ */
// }
// //TODO: can we be more precise sometimes?
// return EQUALITY_UNKNOWN;
@@ -673,386 +1678,93 @@ EqualityStatus TheorySetsPrivate::getEqualityStatus(TNode a, TNode b) {
/******************** Model generation ********************/
/******************** Model generation ********************/
-const TheorySetsPrivate::Elements& TheorySetsPrivate::getElements
-(TNode setterm, SettermElementsMap& settermElementsMap) const {
- SettermElementsMap::const_iterator it = settermElementsMap.find(setterm);
- bool alreadyCalculated = (it != settermElementsMap.end());
- if( !alreadyCalculated ) {
-
- Kind k = setterm.getKind();
- Elements cur;
-
- switch(k) {
- case kind::UNION: {
- const Elements& left = getElements(setterm[0], settermElementsMap);
- const Elements& right = getElements(setterm[1], settermElementsMap);
- if(left.size() >= right.size()) {
- cur = left; cur.insert(right.begin(), right.end());
- } else {
- cur = right; cur.insert(left.begin(), left.end());
- }
- break;
- }
- case kind::INTERSECTION: {
- const Elements& left = getElements(setterm[0], settermElementsMap);
- const Elements& right = getElements(setterm[1], settermElementsMap);
- std::set_intersection(left.begin(), left.end(), right.begin(), right.end(),
- std::inserter(cur, cur.begin()) );
- break;
- }
- case kind::SETMINUS: {
- const Elements& left = getElements(setterm[0], settermElementsMap);
- const Elements& right = getElements(setterm[1], settermElementsMap);
- std::set_difference(left.begin(), left.end(), right.begin(), right.end(),
- std::inserter(cur, cur.begin()) );
- break;
- }
- default:
- Assert(theory::kindToTheoryId(k) != theory::THEORY_SETS,
- (std::string("Kind belonging to set theory not explicitly handled: ") + kindToString(k)).c_str());
- // Assert(k == kind::VARIABLE || k == kind::APPLY_UF || k == kind::SKOLEM,
- // (std::string("Expect variable or UF got ") + kindToString(k)).c_str() );
- /* assign emptyset, which is default */
- }
-
- it = settermElementsMap.insert(SettermElementsMap::value_type(setterm, cur)).first;
- }
- return it->second;
-}
-
-
-bool TheorySetsPrivate::checkModel(const SettermElementsMap& settermElementsMap, TNode S) const {
-
- Debug("sets-model") << "[sets-model] checkModel(..., " << S << "): "
- << std::endl;
-
- Assert(S.getType().isSet());
-
- const Elements emptySetOfElements;
- const Elements& saved =
- d_equalityEngine.getRepresentative(S).getKind() == kind::EMPTYSET ||
- settermElementsMap.find(d_equalityEngine.getRepresentative(S)) == settermElementsMap.end() ?
- emptySetOfElements :
- settermElementsMap.find(d_equalityEngine.getRepresentative(S))->second;
- Debug("sets-model") << "[sets-model] saved : { ";
- BOOST_FOREACH(TNode element, saved) { Debug("sets-model") << element << ", "; }
- Debug("sets-model") << " }" << std::endl;
-
- if(theory::kindToTheoryId(S.getKind()) == THEORY_SETS && S.getNumChildren() == 2) {
-
- Elements cur;
-
- const Elements& left =
- d_equalityEngine.getRepresentative(S[0]).getKind() == kind::EMPTYSET ||
- settermElementsMap.find(d_equalityEngine.getRepresentative(S[0])) == settermElementsMap.end() ?
- emptySetOfElements :
- settermElementsMap.find(d_equalityEngine.getRepresentative(S[0]))->second;
-
- const Elements& right =
- d_equalityEngine.getRepresentative(S[1]).getKind() == kind::EMPTYSET ||
- settermElementsMap.find(d_equalityEngine.getRepresentative(S[1])) == settermElementsMap.end() ?
- emptySetOfElements :
- settermElementsMap.find(d_equalityEngine.getRepresentative(S[1]))->second;
-
- switch(S.getKind()) {
- case kind::UNION:
- if(left.size() >= right.size()) {
- cur = left; cur.insert(right.begin(), right.end());
- } else {
- cur = right; cur.insert(left.begin(), left.end());
- }
- break;
- case kind::INTERSECTION:
- std::set_intersection(left.begin(), left.end(), right.begin(), right.end(),
- std::inserter(cur, cur.begin()) );
- break;
- case kind::SETMINUS:
- std::set_difference(left.begin(), left.end(), right.begin(), right.end(),
- std::inserter(cur, cur.begin()) );
- break;
- default:
- Unhandled();
- }
-
- Debug("sets-model") << "[sets-model] cur : { ";
- BOOST_FOREACH(TNode element, cur) { Debug("sets-model") << element << ", "; }
- Debug("sets-model") << " }" << std::endl;
-
- if(saved != cur) {
- Debug("sets-model") << "[sets-model] *** ERROR *** cur != saved "
- << std::endl;
- Debug("sets-model")
- << "[sets-model] FYI: "
- << " [" << S << "] = " << d_equalityEngine.getRepresentative(S) << ", "
- << " [" << S[0] << "] = " << d_equalityEngine.getRepresentative(S[0]) << ", "
- << " [" << S[1] << "] = " << d_equalityEngine.getRepresentative(S[1]) << "\n";
-
- return false;
- }
- }
- return true;
-}
-
-Node TheorySetsPrivate::elementsToShape(Elements elements, TypeNode setType) const
-{
- NodeManager* nm = NodeManager::currentNM();
-
- if(elements.size() == 0) {
- return nm->mkConst<EmptySet>(EmptySet(nm->toType(setType)));
- } else {
- Elements::iterator it = elements.begin();
- Node cur = SINGLETON(*it);
- while( ++it != elements.end() ) {
- cur = nm->mkNode(kind::UNION, cur, SINGLETON(*it));
- }
- return cur;
- }
-}
-
-Node TheorySetsPrivate::elementsToShape(std::set<Node> elements, TypeNode setType) const
-{
- NodeManager* nm = NodeManager::currentNM();
-
- if(elements.size() == 0) {
- return nm->mkConst<EmptySet>(EmptySet(nm->toType(setType)));
- } else {
- std::set<Node>::const_iterator it = elements.begin();
- Node cur = SINGLETON(*it);
- while( ++it != elements.end() ) {
- cur = nm->mkNode(kind::UNION, cur, SINGLETON(*it));
- }
- return cur;
- }
-}
-
-void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel)
-{
- Trace("sets-model") << "[sets-model] collectModelInfo(..., fullModel="
- << (fullModel ? "true)" : "false)") << std::endl;
-
- std::set<Node> terms;
-
- NodeManager* nm = NodeManager::currentNM();
-
- // // this is for processCard -- commenting out for now
- // if(Debug.isOn("sets-card")) {
- // for(CDNodeSet::const_iterator it = d_cardTerms.begin();
- // it != d_cardTerms.end(); ++it) {
- // Debug("sets-card") << "[sets-card] " << *it << " = "
- // << d_external.d_valuation.getModelValue(*it)
- // << std::endl;
- // }
- // }
-
- if(Trace.isOn("sets-assertions")) {
- dumpAssertionsHumanified();
- }
-
- // Compute terms appearing assertions and shared terms
- d_external.computeRelevantTerms(terms);
-
- //processCard2 begin
- if(Debug.isOn("sets-card")) {
- print_graph(true);
- for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) {
- Node n = nm->mkNode(kind::CARD, *it);
- Debug("sets-card") << "[sets-card] " << n << " = ";
- // if(d_external.d_sharedTerms.find(n) == d_external.d_sharedTerms.end()) continue;
- if((Rewriter::rewrite(n)).isConst()) {
- Debug("sets-card") << (Rewriter::rewrite(n))
- << std::endl;
- } else {
- Debug("sets-card") << d_external.d_valuation.getModelValue(n)
- << std::endl;
- }
- }
- }
- //processCard2 end
-
- // Compute for each setterm elements that it contains
- SettermElementsMap settermElementsMap;
- for(eq::EqClassIterator it_eqclasses(d_trueNode, &d_equalityEngine);
- ! it_eqclasses.isFinished() ; ++it_eqclasses) {
- TNode n = (*it_eqclasses);
- if(n.getKind() == kind::MEMBER) {
- Assert(d_equalityEngine.areEqual(n, d_trueNode));
- TNode x = d_equalityEngine.getRepresentative(n[0]);
- TNode S = d_equalityEngine.getRepresentative(n[1]);
- settermElementsMap[S].insert(x);
- }
- if(Debug.isOn("sets-model-details")) {
- Debug("sets-model-details")
- << "[sets-model-details] > node: " << n << ", explanation:" << std::endl;
- vector<TNode> explanation;
- d_equalityEngine.explainPredicate(n, true, explanation);
- BOOST_FOREACH(TNode m, explanation) {
- Debug("sets-model-details") << "[sets-model-details] >> " << m << std::endl;
- }
- }
- }
-
- if(Debug.isOn("sets-model-details")) {
- for(eq::EqClassIterator it_eqclasses(d_trueNode, &d_equalityEngine);
- ! it_eqclasses.isFinished() ; ++it_eqclasses) {
- TNode n = (*it_eqclasses);
- vector<TNode> explanation;
- Debug("sets-model-details")
- << "[sets-model-details] > node: not: " << n << ", explanation:" << std::endl;
- d_equalityEngine.explainPredicate(n, false, explanation);
- BOOST_FOREACH(TNode m, explanation) {
- Debug("sets-model-details") << "[sets-model-details] >> " << m << std::endl;
- }
- }
- }
+void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel) {
+ Trace("sets") << "Set collect model info" << std::endl;
// Assert equalities and disequalities to the model
- m->assertEqualityEngine(&d_equalityEngine, &terms);
-
- // Loop over terms to collect set-terms for which we generate models
- set<Node> settermsModEq;
- BOOST_FOREACH(TNode term, terms) {
- TNode n = term.getKind() == kind::NOT ? term[0] : term;
-
- Debug("sets-model-details") << "[sets-model-details] > " << n << std::endl;
-
- if(n.getType().isSet()) {
- n = d_equalityEngine.getRepresentative(n);
- if( !n.isConst() ) {
- settermsModEq.insert(n);
- }
- }
-
- }
-
- if(Debug.isOn("sets-model")) {
- BOOST_FOREACH( TNode node, settermsModEq ) {
- Debug("sets-model") << "[sets-model] " << node << std::endl;
- }
- }
-
- if(Debug.isOn("sets-model-details")) {
- BOOST_FOREACH( SettermElementsMap::value_type &it, settermElementsMap ) {
- BOOST_FOREACH( TNode element, it.second /* elements */ ) {
- Debug("sets-model-details") << "[sets-model-details] > " <<
- (it.first /* setterm */) << ": " << element << std::endl;
- }
- }
- }
-
- // build graph, and create sufficient number of skolems
- // buildGraph(); // this is for processCard
-
- //processCard2 begin
- leaves.clear();
- for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it)
- if(d_E.find(*it) == d_E.end())
- leaves.insert(*it);
- d_statistics.d_numLeaves.setData(leaves.size());
- d_statistics.d_numLeavesMax.maxAssign(leaves.size());
- //processCard2 end
+ m->assertEqualityEngine(&d_equalityEngine);
- std::hash_map<TNode, std::vector<TNode>, TNodeHashFunction> slackElements;
- BOOST_FOREACH( TNode setterm, leaves ) {
- if(setterm.getKind() == kind::EMPTYSET) { continue; }
- // Assert(d_cardTerms.find(nm->mkNode(kind::CARD,setterm)) != d_cardTerms.end()); // for processCard
- Assert(d_V.find(setterm) != d_V.end());
- Node cardValNode = d_external.d_valuation.getModelValue(nm->mkNode(kind::CARD,setterm));
- Rational cardValRational = cardValNode.getConst<Rational>();
- Assert(cardValRational.isIntegral());
- Integer cardValInteger = cardValRational.getNumerator();
- Assert(cardValInteger.fitsSignedInt(), "Can't build models that big.");
- int cardValInt = cardValInteger.getSignedInt();
- Assert(cardValInt >= 0);
- int numElems = getElements(setterm, settermElementsMap).size();
- Trace("sets-model-card") << "[sets-model-card] cardValInt = " << cardValInt << std::endl
- << " numElems = " << numElems << std::endl;
- Trace("sets-model-card") << "[sets-model-card] Creating " << cardValInt-numElems
- << " slack variables for " << setterm << std::endl;
- Assert(cardValInt >= numElems, "Run with -d sets-model-card for details");
-
- TypeNode elementType = setterm.getType().getSetElementType();
- std::vector<TNode>& cur = slackElements[setterm];
- for(int i = numElems; i < cardValInt; ++i) {
- // slk = slack
- cur.push_back(nm->mkSkolem("slk_", elementType));
- }
- }
-
- // assign representatives to equivalence class
- BOOST_FOREACH( TNode setterm, settermsModEq ) {
- Elements elements = getElements(setterm, settermElementsMap);
- if(d_E.find(setterm) != d_E.end()) {
- Trace("sets-model-card") << "[sets-model-card] " << setterm << " (before slacks): " << elements.size() << std::endl;
- std::set<TNode> leafChildren = get_leaves(setterm);
- BOOST_FOREACH( TNode leafChild, leafChildren ) {
- if(leaves.find(leafChild) == leaves.end()) { continue; }
- BOOST_FOREACH( TNode slackVar, slackElements[leafChild] ) {
- elements.insert(slackVar);
+ std::map< Node, Node > mvals;
+ for( int i=(int)(d_set_eqc.size()-1); i>=0; i-- ){
+ Node eqc = d_set_eqc[i];
+ std::vector< Node > els;
+ bool is_base = !d_card_enabled || ( d_nf[eqc].size()==1 && d_nf[eqc][0]==eqc );
+ if( is_base ){
+ Trace("sets-model") << "Collect elements of base eqc " << eqc << std::endl;
+ // members that must be in eqc
+ std::map< Node, std::map< Node, Node > >::iterator itm = d_pol_mems[0].find( eqc );
+ if( itm!=d_pol_mems[0].end() ){
+ for( std::map< Node, Node >::iterator itmm = itm->second.begin(); itmm != itm->second.end(); ++itmm ){
+ Node t = NodeManager::currentNM()->mkNode( kind::SINGLETON, itmm->first );
+ els.push_back( t );
}
}
- Trace("sets-model-card") << "[sets-model-card] " << setterm << " (after slacks): " << elements.size() << std::endl;
- } else if(d_V.find(setterm) != d_V.end()) {
- Trace("sets-model-card") << "[sets-model-card] " << setterm << " (before slacks): " << elements.size() << std::endl;
- BOOST_FOREACH( TNode slackVar, slackElements[setterm] ) {
- elements.insert(slackVar);
- }
- Trace("sets-model-card") << "[sets-model-card] " << setterm << " (after slacks): " << elements.size() << std::endl;
}
- Node shape = elementsToShape(elements, setterm.getType());
- shape = theory::Rewriter::rewrite(shape);
- m->assertEquality(shape, setterm, true);
- m->assertRepresentative(shape);
- }
-
-#ifdef CVC4_ASSERTIONS
- bool checkPassed = true;
- BOOST_FOREACH(TNode term, terms) {
- if( term.getType().isSet() ) {
- checkPassed &= checkModel(settermElementsMap, term);
+ if( d_card_enabled ){
+ TypeNode elementType = eqc.getType().getSetElementType();
+ if( is_base ){
+ std::map< Node, Node >::iterator it = d_eqc_to_card_term.find( eqc );
+ if( it!=d_eqc_to_card_term.end() ){
+ //slack elements from cardinality value
+ Node v = d_external.d_valuation.getModelValue(it->second);
+ Trace("sets-model") << "Cardinality of " << eqc << " is " << v << std::endl;
+ Assert(v.getConst<Rational>() <= LONG_MAX, "Exceeded LONG_MAX in sets model");
+ unsigned vu = v.getConst<Rational>().getNumerator().toUnsignedInt();
+ Assert( els.size()<=vu );
+ while( els.size()<vu ){
+ els.push_back( NodeManager::currentNM()->mkNode( kind::SINGLETON, NodeManager::currentNM()->mkSkolem( "msde", elementType ) ) );
+ }
+ }else{
+ Trace("sets-model") << "No slack elements for " << eqc << std::endl;
+ }
+ }else{
+ Trace("sets-model") << "Build value for " << eqc << " based on normal form, size = " << d_nf[eqc].size() << std::endl;
+ //it is union of venn regions
+ for( unsigned j=0; j<d_nf[eqc].size(); j++ ){
+ Assert( mvals.find( d_nf[eqc][j] )!=mvals.end() );
+ els.push_back( mvals[d_nf[eqc][j]] );
+ }
+ }
}
+ Node rep = NormalForm::mkBop( kind::UNION, els, eqc.getType() );
+ rep = Rewriter::rewrite( rep );
+ Trace("sets-model") << "Set representative of " << eqc << " to " << rep << std::endl;
+ mvals[eqc] = rep;
+ m->assertEquality( eqc, rep, true );
+ m->assertRepresentative( rep );
}
- if(Trace.isOn("sets-checkmodel-ignore")) {
- Trace("sets-checkmodel-ignore") << "[sets-checkmodel-ignore] checkPassed value was " << checkPassed << std::endl;
- } else {
- Assert( checkPassed,
- "THEORY_SETS check-model failed. Run with -d sets-model for details." );
- }
-#endif
-}
-
-Node TheorySetsPrivate::getModelValue(TNode n)
-{
- CodeTimer codeTimer(d_statistics.d_getModelValueTime);
- return d_termInfoManager->getModelValue(n);
}
/********************** Helper functions ***************************/
/********************** Helper functions ***************************/
/********************** Helper functions ***************************/
+void TheorySetsPrivate::addEqualityToExp( Node a, Node b, std::vector< Node >& exp ) {
+ if( a!=b ){
+ Assert( ee_areEqual( a, b ) );
+ exp.push_back( a.eqNode( b ) );
+ }
+}
+
Node mkAnd(const std::vector<TNode>& conjunctions) {
Assert(conjunctions.size() > 0);
std::set<TNode> all;
-
for (unsigned i = 0; i < conjunctions.size(); ++i) {
TNode t = conjunctions[i];
-
if (t.getKind() == kind::AND) {
for(TNode::iterator child_it = t.begin();
child_it != t.end(); ++child_it) {
- // Assert((*child_it).getKind() != kind::AND);
+ Assert((*child_it).getKind() != kind::AND);
all.insert(*child_it);
}
}
else {
all.insert(t);
}
-
}
Assert(all.size() > 0);
-
if (all.size() == 1) {
// All the same, or just one
return conjunctions[0];
@@ -1111,271 +1823,8 @@ TheorySetsPrivate::Statistics::~Statistics() {
smtStatisticsRegistry()->unregisterStat(&d_numLeavesMax);
}
-
-bool TheorySetsPrivate::present(TNode atom) {
- return holds(atom) || holds(atom.notNode());
-}
-
-
-bool TheorySetsPrivate::holds(TNode atom, bool polarity) {
- TNode polarity_atom = polarity ? d_trueNode : d_falseNode;
-
- Node atomModEq = NodeManager::currentNM()->mkNode
- (atom.getKind(), d_equalityEngine.getRepresentative(atom[0]),
- d_equalityEngine.getRepresentative(atom[1]) );
-
- d_equalityEngine.addTerm(atomModEq);
-
- return d_equalityEngine.areEqual(atomModEq, polarity_atom);
-}
-
-
-void TheorySetsPrivate::registerReason(TNode reason, bool save)
-{
- if(save) d_nodeSaver.insert(reason);
-
- if(reason.getKind() == kind::AND) {
- //Assert(reason.getNumChildren() == 2);
- for(unsigned i = 0; i < reason.getNumChildren(); ++i) {
- registerReason(reason[i], false);
- }
- } else if(reason.getKind() == kind::NOT) {
- registerReason(reason[0], false);
- } else if(reason.getKind() == kind::MEMBER) {
- d_equalityEngine.addTerm(reason);
- Assert(present(reason));
- } else if(reason.getKind() == kind::EQUAL) {
- d_equalityEngine.addTerm(reason);
- Assert(present(reason));
- } else if(reason.getKind() == kind::CONST_BOOLEAN) {
- // That's OK, already in EqEngine
- } else {
- Unhandled();
- }
-}
-
-void TheorySetsPrivate::finishPropagation()
-{
- while(!d_conflict && !d_settermPropagationQueue.empty()) {
- std::pair<TNode,TNode> np = d_settermPropagationQueue.front();
- d_settermPropagationQueue.pop();
- doSettermPropagation(np.first, np.second);
- }
- while(!d_conflict && !d_propagationQueue.empty()) {
- std::pair<Node,Node> np = d_propagationQueue.front();
- d_propagationQueue.pop();
- TNode atom = np.first.getKind() == kind::NOT ? np.first[0] : np.first;
- if(atom.getKind() == kind::MEMBER) {
- assertMemebership(np.first, np.second, /* learnt = */ true);
- } else {
- assertEquality(np.first, np.second, /* learnt = */ true);
- }
- }
-}
-
-void TheorySetsPrivate::addToPending(Node n) {
- Debug("sets-pending") << "[sets-pending] addToPending " << n << std::endl;
-
- if(d_pendingEverInserted.find(n) != d_pendingEverInserted.end()) {
- Debug("sets-pending") << "[sets-pending] \u2514 skipping " << n
- << " as lemma already generated." << std::endl;
- return;
- }
-
- if(n.getKind() == kind::MEMBER) {
-
- Node nRewritten = theory::Rewriter::rewrite(n);
-
- if(nRewritten.isConst()) {
- Debug("sets-pending") << "[sets-pending] \u2514 skipping " << n
- << " as we can learn one of the sides." << std::endl;
- Assert(nRewritten == d_trueNode || nRewritten == d_falseNode);
-
- bool polarity = (nRewritten == d_trueNode);
- learnLiteral(n, polarity, d_trueNode);
- return;
- }
-
- Debug("sets-pending") << "[sets-pending] \u2514 added to member queue"
- << std::endl;
- ++d_statistics.d_memberLemmas;
- d_pending.push(n);
- lemma(getLemma(), SETS_LEMMA_MEMBER);
- // d_external.d_out->splitLemma();
- Assert(isComplete());
-
- } else {
-
- Debug("sets-pending") << "[sets-pending] \u2514 added to equality queue"
- << std::endl;
- Assert(n.getKind() == kind::EQUAL);
- ++d_statistics.d_disequalityLemmas;
- d_pendingDisequal.push(n);
- lemma(getLemma(), SETS_LEMMA_DISEQUAL);
- // d_external.d_out->splitLemma();
- Assert(isComplete());
-
- }
-}
-
-bool TheorySetsPrivate::isComplete() {
- // while(!d_pending.empty() &&
- // (d_pendingEverInserted.find(d_pending.front()) != d_pendingEverInserted.end()
- // || present(d_pending.front()) ) ) {
- // Debug("sets-pending") << "[sets-pending] removing as already present: "
- // << d_pending.front() << std::endl;
- // d_pending.pop();
- // }
- return d_pending.empty() && d_pendingDisequal.empty();
-}
-
-Node TheorySetsPrivate::getLemma() {
- Assert(!d_pending.empty() || !d_pendingDisequal.empty());
-
- Node n, lemma;
-
- if(!d_pending.empty()) {
- n = d_pending.front();
- d_pending.pop();
- d_pendingEverInserted.insert(n);
-
- Assert(!present(n));
- Assert(n.getKind() == kind::MEMBER);
-
- lemma = OR(n, NOT(n));
- } else {
- n = d_pendingDisequal.front();
- d_pendingDisequal.pop();
- d_pendingEverInserted.insert(n);
-
- Assert(n.getKind() == kind::EQUAL && n[0].getType().isSet());
- TypeNode elementType = n[0].getType().getSetElementType();
- // { x } != { y } => x != y
- if( n[0].getKind()==kind::SINGLETON && n[1].getKind()==kind::SINGLETON ){
- lemma = OR(n, NodeManager::currentNM()->mkNode( elementType.isBoolean() ? kind::IFF : kind::EQUAL, n[0][0], n[1][0] ).negate() );
- }else{
- Node x = NodeManager::currentNM()->mkSkolem("sde_", elementType);
- Node l1 = MEMBER(x, n[0]), l2 = MEMBER(x, n[1]);
-
- if(n[0].getKind() == kind::EMPTYSET) {
- lemma = OR(n, l2);
- } else if(n[1].getKind() == kind::EMPTYSET) {
- lemma = OR(n, l1);
- } else {
- lemma = OR(n, AND(l1, NOT(l2)), AND(NOT(l1), l2));
- }
- }
- }
-
- Debug("sets-lemma") << "[sets-lemma] Generating for " << n
- << ", lemma: " << lemma << std::endl;
-
- return lemma;
-}
-
-
-TheorySetsPrivate::TheorySetsPrivate(TheorySets& external,
- context::Context* c,
- context::UserContext* u):
- d_external(external),
- d_notify(*this),
- d_equalityEngine(d_notify, c, "theory::sets::TheorySetsPrivate", true),
- d_trueNode(NodeManager::currentNM()->mkConst<bool>(true)),
- d_falseNode(NodeManager::currentNM()->mkConst<bool>(false)),
- d_conflict(c),
- d_termInfoManager(NULL),
- d_setTermToCardVar(),
- d_cardVarToSetTerm(),
- d_propagationQueue(c),
- d_settermPropagationQueue(c),
- d_nodeSaver(c),
- d_pending(c),
- d_pendingDisequal(c),
- d_pendingEverInserted(u),
- d_modelCache(c),
- d_ccg_i(c),
- d_ccg_j(c),
- d_scrutinize(NULL),
- d_cardEnabled(false),
- d_cardTerms(c),
- d_typesAdded(),
- d_processedCardTerms(c),
- d_processedCardPairs(),
- d_cardLowerLemmaCache(u),
- edgesFd(),
- edgesBk(),
- disjoint(),
- leaves(),
- d_V(c),
- d_E(c),
- d_graphMergesPending(c),
- d_allSetEqualitiesSoFar(c),
- d_lemmasGenerated(u),
- d_newLemmaGenerated(false),
- d_relTerms(u)
-{
- d_termInfoManager = new TermInfoManager(*this, c, &d_equalityEngine);
-
- d_equalityEngine.addFunctionKind(kind::UNION);
- d_equalityEngine.addFunctionKind(kind::INTERSECTION);
- d_equalityEngine.addFunctionKind(kind::SETMINUS);
-
- d_equalityEngine.addFunctionKind(kind::MEMBER);
- d_equalityEngine.addFunctionKind(kind::SUBSET);
-
- // If cardinality is on.
- d_equalityEngine.addFunctionKind(kind::CARD);
-
- if( Debug.isOn("sets-scrutinize") ) {
- d_scrutinize = new TheorySetsScrutinize(this);
- }
-}/* TheorySetsPrivate::TheorySetsPrivate() */
-
-
-TheorySetsPrivate::~TheorySetsPrivate()
-{
- delete d_termInfoManager;
- if( Debug.isOn("sets-scrutinize") ) {
- Assert(d_scrutinize != NULL);
- delete d_scrutinize;
- }
-}/* TheorySetsPrivate::~TheorySetsPrivate() */
-
void TheorySetsPrivate::propagate(Theory::Effort effort) {
- if(effort != Theory::EFFORT_FULL || !options::setsPropFull()) {
- return;
- }
-
- // build a model
- Trace("sets-prop-full") << "[sets-prop-full] propagate(FULL_EFFORT)" << std::endl;
- if(Trace.isOn("sets-assertions")) {
- dumpAssertionsHumanified();
- }
-
- const CDNodeSet& terms = (d_termInfoManager->d_terms);
- for(CDNodeSet::key_iterator it = terms.key_begin(); it != terms.key_end(); ++it) {
- Node node = (*it);
- Kind k = node.getKind();
- if(k == kind::UNION && node[0].getKind() == kind::SINGLETON ) {
-
- if(holds(MEMBER(node[0][0], node[1]))) {
- Trace("sets-prop-full") << "[sets-prop-full] " << MEMBER(node[0][0], node[1])
- << " => " << EQUAL(node[1], node) << std::endl;
- learnLiteral(EQUAL(node[1], node), MEMBER(node[0][0], node[1]));
- }
-
- } else if(k == kind::UNION && node[1].getKind() == kind::SINGLETON ) {
-
- if(holds(MEMBER(node[1][0], node[0]))) {
- Trace("sets-prop-full") << "[sets-prop-full] " << MEMBER(node[1][0], node[0])
- << " => " << EQUAL(node[0], node) << std::endl;
- learnLiteral(EQUAL(node[0], node), MEMBER(node[1][0], node[0]));
- }
- }
- }
-
- finishPropagation();
}
bool TheorySetsPrivate::propagate(TNode literal) {
@@ -1412,6 +1861,7 @@ void TheorySetsPrivate::conflict(TNode a, TNode b)
d_external.d_out->conflict(d_conflictNode);
Debug("sets") << "[sets] conflict: " << a << " iff " << b
<< ", explaination " << d_conflictNode << std::endl;
+ Trace("sets-lemma") << "Equality Conflict : " << d_conflictNode << std::endl;
d_conflict = true;
}
@@ -1437,43 +1887,13 @@ Node TheorySetsPrivate::explain(TNode literal)
Unhandled();
}
- if(assumptions.size()) {
- return mkAnd(assumptions);
- } else {
- return d_trueNode;
- }
-}
-
-bool TheorySetsPrivate::lemma(Node n, SetsLemmaTag t)
-{
- if(d_lemmasGenerated.find(n) != d_lemmasGenerated.end()) {
- return false;
- }
- d_lemmasGenerated.insert(n);
- d_newLemmaGenerated = true;
- switch(t) {
- case SETS_LEMMA_DISEQUAL:
- case SETS_LEMMA_MEMBER: {
- d_external.d_out->splitLemma(n);
- break;
- }
- case SETS_LEMMA_GRAPH:// {
- // d_external.d_out->preservedLemma(n, false, false);
- // break;
- // }
- case SETS_LEMMA_OTHER: {
- d_external.d_out->lemma(n);
- break;
- }
- }
- return true;
+ return mkAnd(assumptions);
}
void TheorySetsPrivate::preRegisterTerm(TNode node)
{
Debug("sets") << "TheorySetsPrivate::preRegisterTerm(" << node << ")"
<< std::endl;
-
switch(node.getKind()) {
case kind::EQUAL:
// TODO: what's the point of this
@@ -1484,49 +1904,21 @@ void TheorySetsPrivate::preRegisterTerm(TNode node)
d_equalityEngine.addTriggerPredicate(node);
break;
case kind::CARD:
- if(!d_cardEnabled) { enableCard(); }
- registerCard(node);
d_equalityEngine.addTriggerTerm(node, THEORY_SETS);
break;
default:
- d_termInfoManager->addTerm(node);
- d_equalityEngine.addTriggerTerm(node, THEORY_SETS);
- }
-
- if(node.getKind() == kind::SINGLETON) {
- learnLiteral(MEMBER(node[0], node), true, d_trueNode);
- }
-
- // ** For cardinality reasoning **
- if(node.getType().isSet() && d_typesAdded.find(node.getType()) == d_typesAdded.end()) {
- d_typesAdded.insert(node.getType());
-
- if(d_cardEnabled) {
- cardCreateEmptysetSkolem(node.getType());
- }
- }
- if(d_cardEnabled && node.getKind() == kind::SINGLETON) {
- registerCard(NodeManager::currentNM()->mkNode(kind::CARD, node));
+ //if( node.getType().isSet() ){
+ // d_equalityEngine.addTriggerTerm(node, THEORY_SETS);
+ //}else{
+ d_equalityEngine.addTerm(node);
+ //}
+ break;
}
}
void TheorySetsPrivate::presolve() {
- for(CDNodeSet::const_iterator it = d_termInfoManager->d_terms.begin();
- it != d_termInfoManager->d_terms.end(); ++it) {
- d_relTerms.insert(*it);
- }
-
- if(Trace.isOn("sets-relterms")) {
- Trace("sets-relterms") << "[sets-relterms] ";
- for(CDNodeSet::const_iterator it = d_relTerms.begin();
- it != d_relTerms.end(); ++it ) {
- Trace("sets-relterms") << (*it) << ", ";
- }
- Trace("sets-relterms") << "\n";
- }
-
}
/**************************** eq::NotifyClass *****************************/
@@ -1561,10 +1953,7 @@ bool TheorySetsPrivate::NotifyClass::eqNotifyTriggerTermEquality(TheoryId tag, T
{
Debug("sets-eq") << "[sets-eq] eqNotifyTriggerTermEquality: tag = " << tag
<< " t1 = " << t1 << " t2 = " << t2 << " value = " << value << std::endl;
- if(value && t1.getKind() != kind::CARD && t2.getKind() != kind::CARD) {
- d_theory.d_termInfoManager->mergeTerms(t1, t2);
- }
- d_theory.propagate( value ? EQUAL(t1, t2) : NOT(EQUAL(t1, t2)) );
+ d_theory.propagate( value ? t1.eqNode( t2 ) : t1.eqNode( t2 ).negate() );
return true;
}
@@ -1574,1228 +1963,30 @@ void TheorySetsPrivate::NotifyClass::eqNotifyConstantTermMerge(TNode t1, TNode t
d_theory.conflict(t1, t2);
}
-// void TheorySetsPrivate::NotifyClass::eqNotifyNewClass(TNode t)
-// {
-// Debug("sets-eq") << "[sets-eq] eqNotifyNewClass:" << " t = " << t << std::endl;
-// }
-
-// void TheorySetsPrivate::NotifyClass::eqNotifyPreMerge(TNode t1, TNode t2)
-// {
-// Debug("sets-eq") << "[sets-eq] eqNotifyPreMerge:" << " t1 = " << t1 << " t2 = " << t2 << std::endl;
-// }
-
-// void TheorySetsPrivate::NotifyClass::eqNotifyPostMerge(TNode t1, TNode t2)
-// {
-// Debug("sets-eq") << "[sets-eq] eqNotifyPostMerge:" << " t1 = " << t1 << " t2 = " << t2 << std::endl;
-// }
-
-// void TheorySetsPrivate::NotifyClass::eqNotifyDisequal(TNode t1, TNode t2, TNode reason)
-// {
-// Debug("sets-eq") << "[sets-eq] eqNotifyDisequal:" << " t1 = " << t1 << " t2 = " << t2 << " reason = " << reason << std::endl;
-// }
-
-
-/**************************** TermInfoManager *****************************/
-/**************************** TermInfoManager *****************************/
-/**************************** TermInfoManager *****************************/
-
-void TheorySetsPrivate::TermInfoManager::mergeLists
-(CDTNodeList* la, const CDTNodeList* lb) const {
- // straight from theory/arrays/array_info.cpp
- std::set<TNode> temp;
- CDTNodeList::const_iterator it;
- for(it = la->begin() ; it != la->end(); it++ ) {
- temp.insert((*it));
- }
-
- for(it = lb->begin() ; it!= lb->end(); it++ ) {
- if(temp.count(*it) == 0) {
- la->push_back(*it);
- }
- }
-}
-
-TheorySetsPrivate::TermInfoManager::TermInfoManager(
- TheorySetsPrivate& theory, context::Context* satContext,
- eq::EqualityEngine* eq)
- : d_theory(theory),
- d_context(satContext),
- d_eqEngine(eq),
- d_terms(satContext),
- d_info() {}
-
-TheorySetsPrivate::TermInfoManager::~TermInfoManager() {
- for (SetsTermInfoMap::iterator it = d_info.begin(); it != d_info.end();
- ++it) {
- delete (*it).second;
- }
-}
-
-void TheorySetsPrivate::TermInfoManager::notifyMembership(TNode fact) {
- bool polarity = fact.getKind() != kind::NOT;
- TNode atom = polarity ? fact : fact[0];
-
- TNode x = d_eqEngine->getRepresentative(atom[0]);
- TNode S = d_eqEngine->getRepresentative(atom[1]);
-
- Debug("sets-terminfo") << "[sets-terminfo] Adding membership " << x
- << " in " << S << " " << polarity << std::endl;
-
- d_info[S]->addToElementList(x, polarity);
- d_info[x]->addToSetList(S, polarity);
-
- d_theory.d_modelCache.clear();
-}
-
-const CDTNodeList* TheorySetsPrivate::TermInfoManager::getParents(TNode x) {
- return d_info[x]->parents;
-}
-
-const CDTNodeList* TheorySetsPrivate::TermInfoManager::getMembers(TNode S) {
- return d_info[S]->elementsInThisSet;
-}
-
-const CDTNodeList* TheorySetsPrivate::TermInfoManager::getNonMembers(TNode S) {
- return d_info[S]->elementsNotInThisSet;
-}
-
-void TheorySetsPrivate::TermInfoManager::addTerm(TNode n) {
- if(d_terms.contains(n)) {
- return;
- }
- d_terms.insert(n);
-
- if(d_info.find(n) == d_info.end()) {
- d_info.insert(make_pair(n, new TheorySetsTermInfo(d_context)));
- }
-
- if(n.getKind() == kind::UNION ||
- n.getKind() == kind::INTERSECTION ||
- n.getKind() == kind::SETMINUS) {
-
- unsigned numChild = n.getNumChildren();
-
- for(unsigned i = 0; i < numChild; ++i) {
- Assert(d_terms.contains(n[i]));
- if(d_terms.contains(n[i])) {
- Debug("sets-parent") << "Adding " << n << " to parent list of "
- << n[i] << std::endl;
-
- // introduce cardinality of this set if a child's cardinality appears
- d_info[n[i]]->parents->push_back(n);
- if(d_theory.d_cardTerms.find(CARD(n[i])) != d_theory.d_cardTerms.end()) {
- d_theory.registerCard(CARD(n));
- }
-
- SetsTermInfoMap::iterator ita = d_info.find(d_eqEngine->getRepresentative(n[i]));
- Assert(ita != d_info.end());
- CDTNodeList* l = (*ita).second->elementsNotInThisSet;
- for(CDTNodeList::const_iterator it = l->begin(); it != l->end(); ++it) {
- d_theory.d_settermPropagationQueue.push_back( std::make_pair( (*it), n ) );
- }
- l = (*ita).second->elementsInThisSet;
- for(CDTNodeList::const_iterator it = l->begin(); it != l->end(); ++it) {
- d_theory.d_settermPropagationQueue.push_back( std::make_pair( (*it), n ) );
- }
- }
- }
- }
-}
-
-void TheorySetsPrivate::TermInfoManager::pushToSettermPropagationQueue
-(TNode x, TNode S, bool polarity)
+void TheorySetsPrivate::NotifyClass::eqNotifyNewClass(TNode t)
{
- Node cur_atom = MEMBER(x, S);
-
- // propagation : empty set
- if(polarity && S.getKind() == kind::EMPTYSET) {
- Debug("sets-prop") << "[sets-prop] something in empty set? conflict."
- << std::endl;
- d_theory.learnLiteral(cur_atom, false, cur_atom);
- return;
- }// propagation: empty set
-
- // propagation : children
- if(S.getKind() == kind::UNION ||
- S.getKind() == kind::INTERSECTION ||
- S.getKind() == kind::SETMINUS ||
- S.getKind() == kind::SINGLETON) {
- d_theory.d_settermPropagationQueue.push_back(std::make_pair(x, S));
- }// propagation: children
-
- // propagation : parents
- const CDTNodeList* parentList = getParents(S);
- for(CDTNodeList::const_iterator k = parentList->begin();
- k != parentList->end(); ++k) {
- d_theory.d_settermPropagationQueue.push_back(std::make_pair(x, *k));
- }// propagation : parents
-
+ Debug("sets-eq") << "[sets-eq] eqNotifyNewClass:" << " t = " << t << std::endl;
+ d_theory.eqNotifyNewClass(t);
}
-void TheorySetsPrivate::TermInfoManager::pushToSettermPropagationQueue
-(TNode x, CDTNodeList* l, bool polarity)
+void TheorySetsPrivate::NotifyClass::eqNotifyPreMerge(TNode t1, TNode t2)
{
- set<TNode> alreadyProcessed;
-
- BOOST_FOREACH(TNode S, (*l) ) {
- Debug("sets-prop") << "[sets-terminfo] setterm todo: "
- << MEMBER(x, d_eqEngine->getRepresentative(S))
- << std::endl;
-
- TNode repS = d_eqEngine->getRepresentative(S);
- if(alreadyProcessed.find(repS) != alreadyProcessed.end()) {
- continue;
- } else {
- alreadyProcessed.insert(repS);
- }
-
- d_eqEngine->addTerm(MEMBER(d_eqEngine->getRepresentative(x), repS));
-
- for(eq::EqClassIterator j(d_eqEngine->getRepresentative(S), d_eqEngine);
- !j.isFinished(); ++j) {
-
- pushToSettermPropagationQueue(x, *j, polarity);
-
- }//j loop
- }
-}
-
-void TheorySetsPrivate::TermInfoManager::pushToSettermPropagationQueue
-(CDTNodeList* l, TNode S, bool polarity)
-{
- BOOST_FOREACH(TNode x, (*l) ) {
- Debug("sets-prop") << "[sets-terminfo] setterm todo: "
- << MEMBER(x, d_eqEngine->getRepresentative(S))
- << std::endl;
-
- d_eqEngine->addTerm(MEMBER(d_eqEngine->getRepresentative(x),
- d_eqEngine->getRepresentative(S)));
-
- for(eq::EqClassIterator j(d_eqEngine->getRepresentative(S), d_eqEngine);
- !j.isFinished(); ++j) {
-
- pushToSettermPropagationQueue(x, *j, polarity);
-
- }//j loop
-
- }
-
-}
-
-
-
-void TheorySetsPrivate::TermInfoManager::mergeTerms(TNode a, TNode b) {
- // merge b into a
- Debug("sets-terminfo") << "[sets-terminfo] Merging (into) a = " << a
- << ", b = " << b << std::endl;
- Debug("sets-terminfo") << "[sets-terminfo] reps"
- << ", a: " << d_eqEngine->getRepresentative(a)
- << ", b: " << d_eqEngine->getRepresentative(b)
- << std::endl;
-
- SetsTermInfoMap::iterator ita = d_info.find(a);
- SetsTermInfoMap::iterator itb = d_info.find(b);
-
- Assert(ita != d_info.end());
- Assert(itb != d_info.end());
-
- /* elements in this sets */
- pushToSettermPropagationQueue( (*ita).second->elementsInThisSet, b, true );
- pushToSettermPropagationQueue( (*ita).second->elementsNotInThisSet, b, false );
- pushToSettermPropagationQueue( (*itb).second->elementsNotInThisSet, a, false );
- pushToSettermPropagationQueue( (*itb).second->elementsInThisSet, a, true );
- mergeLists((*ita).second->elementsInThisSet,
- (*itb).second->elementsInThisSet);
- mergeLists((*ita).second->elementsNotInThisSet,
- (*itb).second->elementsNotInThisSet);
-
- /* sets containing this element */
- // pushToSettermPropagationQueue( b, (*ita).second->setsContainingThisElement, true);
- // pushToSettermPropagationQueue( b, (*ita).second->setsNotContainingThisElement, false);
- pushToSettermPropagationQueue( a, (*itb).second->setsNotContainingThisElement, false);
- pushToSettermPropagationQueue( a, (*itb).second->setsContainingThisElement, true);
- mergeLists( (*ita).second->setsContainingThisElement,
- (*itb).second->setsContainingThisElement );
- mergeLists( (*ita).second->setsNotContainingThisElement,
- (*itb).second->setsNotContainingThisElement );
-
- d_theory.d_modelCache.clear();
+ Debug("sets-eq") << "[sets-eq] eqNotifyPreMerge:" << " t1 = " << t1 << " t2 = " << t2 << std::endl;
+ d_theory.eqNotifyPreMerge(t1, t2);
}
-Node TheorySetsPrivate::TermInfoManager::getModelValue(TNode n) {
- if (d_terms.find(n) == d_terms.end()) {
- return Node();
- }
- Assert(n.getType().isSet());
- std::set<Node> elements;
- std::set<Node> elements_const;
- Node S = d_eqEngine->getRepresentative(n);
- context::CDHashMap<Node, Node, NodeHashFunction>::const_iterator it =
- d_theory.d_modelCache.find(S);
- if (it != d_theory.d_modelCache.end()) {
- return (*it).second;
- }
- const CDTNodeList* l = getMembers(S);
- for (CDTNodeList::const_iterator it = l->begin(); it != l->end(); ++it) {
- TNode n = *it;
- elements.insert(d_eqEngine->getRepresentative(n));
- }
- for(std::set<Node>::iterator it = elements.begin(); it != elements.end(); it++) {
- TNode e = *it;
- if (e.isConst()) {
- elements_const.insert(e);
- } else {
- Node eModelValue = d_theory.d_external.d_valuation.getModelValue(e);
- if (eModelValue.isNull()) {
- return eModelValue;
- }
- elements_const.insert(eModelValue);
- }
- }
- Node v = d_theory.elementsToShape(elements_const, n.getType());
- d_theory.d_modelCache[n] = v;
- return v;
-}
-
-/********************** Cardinality ***************************/
-/********************** Cardinality ***************************/
-/********************** Cardinality ***************************/
-
-void TheorySetsPrivate::enableCard()
+void TheorySetsPrivate::NotifyClass::eqNotifyPostMerge(TNode t1, TNode t2)
{
- Assert(!d_cardEnabled);
- Trace("sets-card") << "[sets-card] Enabling cardinality reasoning" << std::endl;
- d_cardEnabled = true;
-
- BOOST_FOREACH( TypeNode t, d_typesAdded ) {
- cardCreateEmptysetSkolem(t);
- }
-
- for(CDNodeSet::const_iterator it = d_termInfoManager->d_terms.begin();
- it != d_termInfoManager->d_terms.end(); ++it) {
- Node n = (*it);
- if(n.getKind() == kind::SINGLETON) {
- registerCard(NodeManager::currentNM()->mkNode(kind::CARD, n));
- }
- }
-}
-
-void TheorySetsPrivate::registerCard(TNode node) {
- Trace("sets-card") << "[sets-card] registerCard( " << node << ")" << std::endl;
- if(d_cardTerms.find(node) == d_cardTerms.end()) {
- d_cardTerms.insert(node);
-
- // introduce cardinality of any set-term containing this term
- NodeManager* nm = NodeManager::currentNM();
- const CDTNodeList* parentList = d_termInfoManager->getParents(node[0]);
- for(CDTNodeList::const_iterator it = parentList->begin();
- it != parentList->end(); ++it) {
- registerCard(nm->mkNode(kind::CARD, *it));
- }
- }
-}
-
-
-void TheorySetsPrivate::cardCreateEmptysetSkolem(TypeNode t) {
- // set cardinality zero
- NodeManager* nm = NodeManager::currentNM();
- Debug("sets-card") << "Creating skolem for emptyset for type "
- << t << std::endl;
- Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType(t)));
- Node sk = nm->mkSkolem("scz_", t);
- lemma(nm->mkNode(kind::EQUAL, sk, emptySet), SETS_LEMMA_OTHER);
- lemma(nm->mkNode(kind::EQUAL, nm->mkConst(Rational(0)), nm->mkNode(kind::CARD, sk)), SETS_LEMMA_OTHER);
-}
-
-
-void TheorySetsPrivate::buildGraph() {
-
- NodeManager* nm = NodeManager::currentNM();
-
- edgesFd.clear();
- edgesBk.clear();
- disjoint.clear();
-
- for (std::map<std::pair<Node, Node>, bool>::const_iterator it =
- d_processedCardPairs.begin();
- it != d_processedCardPairs.end(); ++it) {
- Node s = (it->first).first;
- Assert(Rewriter::rewrite(s) == s);
- Node t = (it->first).second;
- Assert(Rewriter::rewrite(t) == t);
- bool hasUnion = (it->second);
-
- Node sNt = nm->mkNode(kind::INTERSECTION, s, t);
- sNt = Rewriter::rewrite(sNt);
- Node sMt = nm->mkNode(kind::SETMINUS, s, t);
- sMt = Rewriter::rewrite(sMt);
- Node tMs = nm->mkNode(kind::SETMINUS, t, s);
- tMs = Rewriter::rewrite(tMs);
-
- edgesFd[s].insert(sNt);
- edgesFd[s].insert(sMt);
- edgesBk[sNt].insert(s);
- edgesBk[sMt].insert(s);
-
- edgesFd[t].insert(sNt);
- edgesFd[t].insert(tMs);
- edgesBk[sNt].insert(t);
- edgesBk[tMs].insert(t);
-
- if(hasUnion) {
- Node sUt = nm->mkNode(kind::UNION, s, t);
- sUt = Rewriter::rewrite(sUt);
-
- edgesFd[sUt].insert(sNt);
- edgesFd[sUt].insert(sMt);
- edgesFd[sUt].insert(tMs);
- edgesBk[sNt].insert(sUt);
- edgesBk[sMt].insert(sUt);
- edgesBk[tMs].insert(sUt);
- }
-
- disjoint.insert(make_pair(sNt, sMt));
- disjoint.insert(make_pair(sMt, sNt));
- disjoint.insert(make_pair(sNt, tMs));
- disjoint.insert(make_pair(tMs, sNt));
- disjoint.insert(make_pair(tMs, sMt));
- disjoint.insert(make_pair(sMt, tMs));
- }
-
- if (Debug.isOn("sets-card-graph")) {
- Debug("sets-card-graph") << "[sets-card-graph] Fd:" << std::endl;
- for (std::map<TNode, std::set<TNode> >::const_iterator it = edgesFd.begin();
- it != edgesFd.end(); ++it) {
- Debug("sets-card-graph") << "[sets-card-graph] " << (it->first)
- << std::endl;
- for (std::set<TNode>::const_iterator jt = (it->second).begin();
- jt != (it->second).end(); ++jt) {
- Debug("sets-card-graph") << "[sets-card-graph] " << (*jt)
- << std::endl;
- }
- }
- Debug("sets-card-graph") << "[sets-card-graph] Bk:" << std::endl;
- for (std::map<TNode, std::set<TNode> >::const_iterator it = edgesBk.begin();
- it != edgesBk.end(); ++it) {
- Debug("sets-card-graph") << "[sets-card-graph] " << (it->first)
- << std::endl;
- for (std::set<TNode>::const_iterator jt = (it->second).begin();
- jt != (it->second).end(); ++jt) {
- Debug("sets-card-graph") << "[sets-card-graph] " << (*jt)
- << std::endl;
- }
- }
- }
-
- leaves.clear();
-
- for(CDNodeSet::const_iterator it = d_processedCardTerms.begin();
- it != d_processedCardTerms.end(); ++it) {
- Node n = (*it)[0];
- if( edgesFd.find(n) == edgesFd.end() ) {
- leaves.insert(n);
- Debug("sets-card-graph") << "[sets-card-graph] Leaf: " << n << std::endl;
- }
- // if( edgesBk.find(n) != edgesBk.end() ) {
- // Assert(n.getKind() == kind::INTERSECTION ||
- // n.getKind() == kind::SETMINUS);
- // }
- }
-
-}
-
-const std::set<TNode> getReachable(map<TNode, set<TNode> >& edges, TNode node) {
- Debug("sets-getreachable-debug") << "[sets-getreachable-debug] " << node << ":" << std::endl;
- queue<TNode> Q;
- std::set<TNode> ret;
- ret.insert(node);
- if(edges.find(node) != edges.end()) {
- Debug("sets-getreachable-debug") << "[sets-getreachable-debug] " << node << ":" << std::endl;
- Q.push(node);
- }
- while(!Q.empty()) {
- TNode n = Q.front();
- Q.pop();
- for(set<TNode>::iterator it = edges[n].begin();
- it != edges[n].end(); ++it) {
- if(ret.find(*it) == ret.end()) {
- if(edges.find(*it) != edges.end()) {
- Debug("sets-getreachable-debug") << "[sets-getreachable-debug] " << *it << ":" << std::endl;
- Q.push(*it);
- }
- ret.insert(*it);
- }
- }
- }
- return ret;
-}
-
-const std::set<TNode> getLeaves(map<TNode, set<TNode> >& edges, TNode node) {
- Debug("sets-getreachable-debug") << "[sets-getreachable-debug] " << node << ":" << std::endl;
- queue<TNode> Q;
- std::set<TNode> ret;
- std::set<TNode> visited;
- visited.insert(node);
- if(edges.find(node) != edges.end()) {
- Q.push(node);
- } else {
- Debug("sets-getreachable-debug") << "[sets-getreachable-debug] " << node << std::endl;
- ret.insert(node);
- }
- while(!Q.empty()) {
- TNode n = Q.front();
- Q.pop();
- for(set<TNode>::iterator it = edges[n].begin();
- it != edges[n].end(); ++it) {
- if(visited.find(*it) == visited.end()) {
- if(edges.find(*it) != edges.end()) {
- Q.push(*it);
- } else {
- Debug("sets-getreachable-debug") << "[sets-getreachable-debug] " << *it << std::endl;
- ret.insert(*it);
- }
- visited.insert(*it);
- }
- }
- }
- return ret;
-}
-
-/************ New cardinality implementation **************/
-
-
-/***
- * Data structures:
- * d_V : vertices in the graph (context dependent data structure)
- * d_E : edges between vertices in the graph
- *
- * Methods:
- *
- * merge(vector<int> a, vector<int> b)
- * get non empty leaves
- * of a & b, for each internal node, there will be two parent nodes
- *
- * Introduce
- * <If a node already exists, merge with it>
- */
-
-void TheorySetsPrivate::add_edges(TNode source, TNode dest) {
- vector<TNode> V;
- V.push_back(dest);
- add_edges(source, V);
-}
-
-void TheorySetsPrivate::add_edges(TNode source, TNode dest1, TNode dest2) {
- vector<TNode> V;
- V.push_back(dest1);
- V.push_back(dest2);
- add_edges(source, V);
-}
-
-void TheorySetsPrivate::add_edges(TNode source, TNode dest1, TNode dest2, TNode dest3) {
- vector<TNode> V;
- V.push_back(dest1);
- V.push_back(dest2);
- V.push_back(dest3);
- add_edges(source, V);
+ Debug("sets-eq") << "[sets-eq] eqNotifyPostMerge:" << " t1 = " << t1 << " t2 = " << t2 << std::endl;
+ d_theory.eqNotifyPostMerge(t1, t2);
}
-void TheorySetsPrivate::add_edges(TNode source, const std::vector<TNode>& dests) {
-
- if(Debug.isOn("sets-graph-details")) {
- Debug("sets-graph-details") << "[sets-graph-details] add_edges " << source
- << " [";
- BOOST_FOREACH(TNode v, dests) {
- Debug("sets-graph-details") << v << ", ";
- Assert(d_V.find(v) != d_V.end());
- }
- Debug("sets-graph-details") << "]" << std::endl;
- }
-
- Assert(d_E.find(source) == d_E.end());
- if(dests.size() == 1 && dests[0] == source) {
- return;
- }
- d_E.insert(source, dests);
-}
-
-
-void TheorySetsPrivate::add_node(TNode vertex) {
- NodeManager* nm = NodeManager::currentNM();
- Debug("sets-graph-details") << "[sets-graph-details] add_node " << vertex << std::endl;
- if(d_V.find(vertex) == d_V.end()) {
- d_V.insert(vertex);
- Kind k = vertex.getKind();
- if(k == kind::SINGLETON) {
- // newLemmaGenerated = true;
- lemma(nm->mkNode(kind::EQUAL,
- nm->mkNode(kind::CARD, vertex),
- nm->mkConst(Rational(1))),
- SETS_LEMMA_OTHER);
- } else if(k != kind::EMPTYSET) {
- // newLemmaGenerated = true;
- lemma(nm->mkNode(kind::GEQ,
- nm->mkNode(kind::CARD, vertex),
- nm->mkConst(Rational(0))),
- SETS_LEMMA_OTHER);
- }
- d_statistics.d_numVerticesMax.maxAssign(d_V.size());
- }
- d_equalityEngine.addTerm(vertex);
- d_termInfoManager->addTerm(vertex);
-}
-
-std::set<TNode> TheorySetsPrivate::non_empty(std::set<TNode> vertices)
+void TheorySetsPrivate::NotifyClass::eqNotifyDisequal(TNode t1, TNode t2, TNode reason)
{
- std::set<TNode> ret;
- NodeManager* nm = NodeManager::currentNM();
- BOOST_FOREACH(TNode vertex, vertices) {
- Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType(vertex.getType())));
- if(!d_equalityEngine.areEqual(vertex, emptySet)) {
- ret.insert(vertex);
- }
- }
- return ret;
-}
-
-std::set<TNode> TheorySetsPrivate::get_leaves(Node vertex) {
- Debug("sets-graph-details") << "[sets-graph-details] get_leaves " << vertex << std::endl;
- std::set<TNode> a;
- Assert(d_V.find(vertex) != d_V.end());
- if(d_E.find(vertex) != d_E.end()) {
- Assert(d_E[vertex].get().size() > 0);
- BOOST_FOREACH(TNode v , d_E[vertex].get()) {
- std::set<TNode> s = get_leaves(v);
- a.insert(s.begin(), s.end());
- }
- } else {
- a.insert(vertex);
- }
- // a = non_empty(a);
- return a;
-}
-
-std::set<TNode> TheorySetsPrivate::get_leaves(Node vertex1, Node vertex2) {
- std::set<TNode> s = get_leaves(vertex1);
- std::set<TNode> t = get_leaves(vertex2);
- t.insert(s.begin(), s.end());
- return t;
-}
-
-std::set<TNode> TheorySetsPrivate::get_leaves(Node vertex1, Node vertex2, Node vertex3) {
- std::set<TNode> s = get_leaves(vertex1);
- std::set<TNode> t = get_leaves(vertex2);
- std::set<TNode> u = get_leaves(vertex3);
- t.insert(s.begin(), s.end());
- t.insert(u.begin(), u.end());
- return t;
-}
-
-Node TheorySetsPrivate::eqemptySoFar() {
- std::vector<Node> V;
-
- for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) {
- Node rep = d_equalityEngine.getRepresentative(*it);
- if(rep.getKind() == kind::EMPTYSET) {
- V.push_back(EQUAL(rep, (*it)));
- }
- }
-
- if(V.size() == 0) {
- return d_trueNode;
- } else if(V.size() == 1) {
- return V[0];
- } else {
- NodeManager* nm = NodeManager::currentNM();
- return nm->mkNode(kind::AND, V);
- }
-}
-
-
-void TheorySetsPrivate::merge_nodes(std::set<TNode> leaves1, std::set<TNode> leaves2, Node reason) {
- CodeTimer codeTimer(d_statistics.d_mergeTime);
-
- NodeManager* nm = NodeManager::currentNM();
-
- // do non-empty reasoning stuff
- std::vector<TNode> leaves1_nonempty, leaves2_nonempty;
- BOOST_FOREACH(TNode l, leaves1) {
- Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType(l.getType())));
- if(d_equalityEngine.getRepresentative(l).getKind() != kind::EMPTYSET) {
- leaves1_nonempty.push_back(l);
- } else {
- // reason = nm->mkNode(kind::AND, reason, EQUAL(l, emptySet));
- }
- }
- BOOST_FOREACH(TNode l, leaves2) {
- Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType(l.getType())));
- if(d_equalityEngine.getRepresentative(l).getKind() != kind::EMPTYSET) {
- leaves2_nonempty.push_back(l);
- } else {
- // reason = nm->mkNode(kind::AND, reason, EQUAL(l, emptySet));
- }
- }
-
- // last minute stuff
- reason = nm->mkNode(kind::AND, reason, eqemptySoFar());
-
- Trace("sets-graph-merge") << "[sets-graph-merge] merge_nodes(..,.., " << reason << ")"
- << std::endl;
- print_graph();
- Trace("sets-graph") << std::endl;
-
- std::set<TNode> leaves3, leaves4;
- std::set_difference(leaves1_nonempty.begin(), leaves1_nonempty.end(),
- leaves2_nonempty.begin(), leaves2_nonempty.end(),
- std::inserter(leaves3, leaves3.begin()));
- std::set_difference(leaves2_nonempty.begin(), leaves2_nonempty.end(),
- leaves1_nonempty.begin(), leaves1_nonempty.end(),
- std::inserter(leaves4, leaves4.begin()));
-
- if(leaves3.size() == 0) {
- Trace("sets-graph-merge") << "[sets-graph-merge] Merge Equality 1" << std::endl;
- // make everything in leaves4 empty
- BOOST_FOREACH(TNode v , leaves4) {
- Node zero = nm->mkConst(Rational(0));
- if(!d_equalityEngine.hasTerm(zero)) {
- d_equalityEngine.addTerm(zero);
- d_termInfoManager->addTerm(zero);
- }
- learnLiteral( /* atom = */ EQUAL(nm->mkNode(kind::CARD, v), zero),
- /* polarity = */ true,
- /* reason = */ reason);
- }
- ++d_statistics.d_numMergeEq1or2;
- } else if(leaves4.size() == 0) {
- Trace("sets-graph-merge") << "[sets-graph-merge] Merge Equality 2" << std::endl;
- // make everything in leaves3 empty
- BOOST_FOREACH(TNode v , leaves3) {
- Node zero = nm->mkConst(Rational(0));
- if(!d_equalityEngine.hasTerm(zero)) {
- d_equalityEngine.addTerm(zero);
- d_termInfoManager->addTerm(zero);
- }
- learnLiteral( /* atom = */ EQUAL(nm->mkNode(kind::CARD, v), zero),
- /* polarity = */ true,
- /* reason = */ reason);
- }
- ++d_statistics.d_numMergeEq1or2;
- } else {
- Trace("sets-graph-merge") << "[sets-graph-merge] Merge Equality 3" << std::endl;
- Trace("sets-graph-merge") << "[sets-graph-merge] #left= " << leaves1.size()
- << " #right= " << leaves2.size()
- << " #left non-empty= " << leaves1_nonempty.size()
- << " #right non-empty= " << leaves2_nonempty.size()
- << " #left-right= " << leaves3.size()
- << " #right-left= " << leaves4.size() << std::endl;
-
- std::map<TNode, vector<TNode> > children;
-
- // Merge Equality 3
- BOOST_FOREACH(TNode l1 , leaves3) {
- BOOST_FOREACH(TNode l2 , leaves4) {
- Node l1_inter_l2 = nm->mkNode(kind::INTERSECTION, min(l1, l2), max(l1, l2));
- l1_inter_l2 = Rewriter::rewrite(l1_inter_l2);
- add_node(l1_inter_l2);
- children[l1].push_back(l1_inter_l2);
- children[l2].push_back(l1_inter_l2);
- // if(d_V.find(l1_inter_l2) != d_V.end()) {
- // // This case needs to be handled, currently not
- // Warning() << "This might create a loop. We need to handle this case. Probably merge the two nodes?" << std::endl;
- // Unhandled();
- // }
- }
- ++d_statistics.d_numMergeEq3;
- }
-
- for(std::map<TNode, vector<TNode> >::iterator it = children.begin();
- it != children.end(); ++it) {
- add_edges(it->first, it->second);
- Node rhs;
- if(it->second.size() == 1) {
- rhs = nm->mkNode(kind::CARD, it->second[0]);
- } else {
- NodeBuilder<> nb(kind::PLUS);
- BOOST_FOREACH(TNode n , it->second) {
- Node card_n = nm->mkNode(kind::CARD, n);
- nb << card_n;
- }
- rhs = Node(nb);
- }
- Node lem;
- lem = nm->mkNode(kind::EQUAL,
- nm->mkNode(kind::CARD, it->first),
- rhs);
- lem = nm->mkNode(kind::IMPLIES, reason, lem);
- lem = Rewriter::rewrite(lem);
- d_external.d_out->lemma(lem);
- }
- }
-
- Trace("sets-graph") << std::endl;
- print_graph();
- Trace("sets-graph") << std::endl;
-
-}
-
-void TheorySetsPrivate::print_graph(bool printmodel) {
- NodeManager* nm = NodeManager::currentNM();
- std::string tag = "sets-graph";
- if(Trace.isOn("sets-graph")) {
- Trace(tag) << "[sets-graph] Graph : " << std::endl;
- for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) {
- TNode v = *it;
- // BOOST_FOREACH(TNode v, d_V) {
- Trace(tag) << "[" << tag << "] " << v << " : ";
- // BOOST_FOREACH(TNode w, d_E[v].get()) {
- if(d_E.find(v) != d_E.end()) {
- BOOST_FOREACH(TNode w, d_E[v].get()) {
- Trace(tag) << w << ", ";
- }
- } else {
- Trace(tag) << " leaf. " ;
- }
- Trace(tag) << std::endl;
- }
- }
-
- if(Trace.isOn("sets-graph-dot")) {
- std::ostringstream oss;
- oss << "digraph G { ";
- for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) {
- TNode v = *it;
-
- std::ostringstream v_oss;
- v_oss << v;
- if(printmodel)
- {
- Node n = nm->mkNode(kind::CARD, v);
- if((Rewriter::rewrite(n)).isConst()) {
- v_oss << " " << (Rewriter::rewrite(n));
- } else {
- v_oss << " " << d_external.d_valuation.getModelValue(n);
- }
- }
-
- if(d_E.find(v) != d_E.end()) {
- BOOST_FOREACH(TNode w, d_E[v].get()) {
-
- std::ostringstream w_oss;
- w_oss << w;
- if(printmodel) {
- Node n = nm->mkNode(kind::CARD, w);
- if((Rewriter::rewrite(n)).isConst()) {
- w_oss << " " << (Rewriter::rewrite(n));
- } else {
- w_oss << " " << d_external.d_valuation.getModelValue(n);
- }
- }
-
- //oss << v.getId() << " -> " << w.getId() << "; ";
- oss << "\"" << v_oss.str() << "\" -> \"" << w_oss.str() << "\"; ";
- }
- } else {
- oss << "\"" << v_oss.str() << "\";";
- }
- }
- oss << "}";
- Trace("sets-graph-dot") << "[sets-graph-dot] " << oss.str() << std::endl;
- }
-}
-
-Node TheorySetsPrivate::eqSoFar() {
- std::vector<Node> V(d_allSetEqualitiesSoFar.begin(), d_allSetEqualitiesSoFar.end());
- if(V.size() == 0) {
- return d_trueNode;
- } else if(V.size() == 1) {
- return V[0];
- } else {
- NodeManager* nm = NodeManager::currentNM();
- return nm->mkNode(kind::AND, V);
- }
-}
-
-
-void TheorySetsPrivate::guessLeavesEmptyLemmas() {
-
- // Guess leaf nodes being empty or non-empty
- NodeManager* nm = NodeManager::currentNM();
- leaves.clear();
- for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) {
- TNode v = *it;
- if(d_E.find(v) == d_E.end()) {
- leaves.insert(v);
- }
- }
- d_statistics.d_numLeaves.setData(leaves.size());
- d_statistics.d_numLeavesMax.maxAssign(leaves.size());
-
- int
- numLeaves = leaves.size(),
- numLemmasGenerated = 0,
- numLeavesIsEmpty = 0,
- numLeavesIsNonEmpty = 0,
- numLeavesCurrentlyNonEmpty = 0,
- numLemmaAlreadyExisted = 0;
-
- for(std::set<TNode>::iterator it = leaves.begin(); it != leaves.end(); ++it) {
- bool generateLemma = true;
- Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType((*it).getType())));
-
- if(d_equalityEngine.hasTerm(*it)) {
- Node n = d_equalityEngine.getRepresentative(*it);
- if(n.getKind() == kind::EMPTYSET) {
- ++numLeavesIsEmpty;
- continue;
- }
- if(d_termInfoManager->getMembers(n)->size() > 0) {
- ++numLeavesCurrentlyNonEmpty;
- continue;
- }
- if(!d_equalityEngine.hasTerm(emptySet)) {
- d_equalityEngine.addTerm(emptySet);
- }
- if(d_equalityEngine.areDisequal(n, emptySet, false)) {
- ++numLeavesIsNonEmpty;
- generateLemma = false;
- }
- }
-
- if(generateLemma) {
- Node n = nm->mkNode(kind::EQUAL, (*it), emptySet);
- Node lem = nm->mkNode(kind::OR, n, nm->mkNode(kind::NOT, n));
- bool lemmaGenerated =
- lemma(lem, SETS_LEMMA_GRAPH);
- if(lemmaGenerated) {
- ++numLemmasGenerated;
- } else {
- ++numLemmaAlreadyExisted;
- }
- n = d_external.d_valuation.ensureLiteral(n);
- d_external.d_out->requirePhase(n, true);
- }
-
- }
- Trace("sets-guess-empty")
- << "[sets-guess-empty] numLeaves = " << numLeaves << std::endl
- << " numLemmasGenerated = " << numLemmasGenerated << std::endl
- << " numLeavesIsEmpty = " << numLeavesIsEmpty << std::endl
- << " numLeavesIsNonEmpty = " << numLeavesIsNonEmpty << std::endl
- << " numLeavesCurrentlyNonEmpty = " << numLeavesCurrentlyNonEmpty << std::endl
- << " numLemmaAlreadyExisted = " << numLemmaAlreadyExisted << std::endl;
-
+ Debug("sets-eq") << "[sets-eq] eqNotifyDisequal:" << " t1 = " << t1 << " t2 = " << t2 << " reason = " << reason << std::endl;
+ d_theory.eqNotifyDisequal(t1, t2, reason);
}
-void TheorySetsPrivate::processCard2(Theory::Effort level) {
- CodeTimer codeTimer(d_statistics.d_processCard2Time);
-
- if(level != Theory::EFFORT_FULL) return;
-
- d_statistics.d_numVertices.setData(d_V.size());
- d_statistics.d_numVerticesMax.maxAssign(d_V.size());
-
- Trace("sets-card") << "[sets-card] processCard( " << level << ")" << std::endl;
- Trace("sets-card") << "[sets-card] # vertices = " << d_V.size() << std::endl;
-
- NodeManager* nm = NodeManager::currentNM();
-
- if(options::setsGuessEmpty() == 0) {
- Trace("sets-guess-empty") << "[sets-guess-empty] Generating lemmas before introduce." << std::endl;
- guessLeavesEmptyLemmas();
- if(d_newLemmaGenerated) {
- return;
- }
- }
-
- // Introduce
- for(CDNodeSet::const_iterator it = d_cardTerms.begin();
- it != d_cardTerms.end(); ++it) {
-
- for(eq::EqClassIterator j(d_equalityEngine.getRepresentative((*it)[0]), &d_equalityEngine);
- !j.isFinished(); ++j) {
-
- Node n = nm->mkNode(kind::CARD, (*j));
-
- if(d_processedCardTerms.find(n) != d_processedCardTerms.end()) {
- continue;
- }
-
- if(d_relTerms.find(n[0]) == d_relTerms.end()) {
- // not relevant, skip
- continue;
- }
-
- Trace("sets-graph") << std::endl;
- print_graph();
- Trace("sets-graph") << std::endl;
-
- add_node(n[0]);
-
- Trace("sets-card") << "[sets-card] Processing " << n << " in eq cl of " << (*it) << std::endl;
-
- d_processedCardTerms.insert(n);
-
- Kind k = n[0].getKind();
-
- if(k == kind::SINGLETON) {
- Trace("sets-card") << "[sets-card] Introduce Singleton " << n[0] << std::endl;
- continue;
- }
-
- // rest of the processing is for compound terms
- if(k != kind::UNION && k != kind::INTERSECTION && k != kind::SETMINUS) {
- continue;
- }
-
- Trace("sets-card") << "[sets-card] Introduce Term " << n[0] << std::endl;
-
- Node s = min(n[0][0], n[0][1]);
- Node t = max(n[0][0], n[0][1]);
- bool isUnion = (k == kind::UNION);
- Assert(Rewriter::rewrite(s) == s);
- Assert(Rewriter::rewrite(t) == t);
-
- Node sNt = nm->mkNode(kind::INTERSECTION, s, t);
- sNt = Rewriter::rewrite(sNt);
- Node sMt = nm->mkNode(kind::SETMINUS, s, t);
- sMt = Rewriter::rewrite(sMt);
- Node tMs = nm->mkNode(kind::SETMINUS, t, s);
- tMs = Rewriter::rewrite(tMs);
-
- Node card_s = nm->mkNode(kind::CARD, s);
- Node card_t = nm->mkNode(kind::CARD, t);
- Node card_sNt = nm->mkNode(kind::CARD, sNt);
- Node card_sMt = nm->mkNode(kind::CARD, sMt);
- Node card_tMs = nm->mkNode(kind::CARD, tMs);
-
- Node lem;
-
- add_node(sMt);
- add_node(sNt);
- add_node(tMs);
-
-
- // for union
- if(isUnion) {
- if(d_E.find(n[0]) != d_E.end()) {
- // do a merge of current leaves of d_E with
- // sNT sMT tMs
- Trace("sets-card") << "[sets-card] Already found in the graph, merging " << n[0] << std::endl;
- merge_nodes(get_leaves(n[0]), get_leaves(sMt, sNt, tMs), eqSoFar());
- } else {
- add_node(n[0]);
-
- lem = nm->mkNode(kind::EQUAL,
- n, // card(s union t)
- nm->mkNode(kind::PLUS, card_sNt, card_sMt, card_tMs));
- lemma(lem, SETS_LEMMA_GRAPH);
-
- Assert(d_E.find(n[0]) == d_E.end());
- add_edges(n[0], sMt, sNt, tMs);
- }
- }
-
- // for s
- if(d_E.find(s) == d_E.end()) {
- add_node(s);
- add_edges(s, sMt, sNt);
-
- lem = nm->mkNode(kind::EQUAL,
- card_s,
- nm->mkNode(kind::PLUS, card_sNt, card_sMt));
- lemma(lem, SETS_LEMMA_GRAPH);
- } else {
- if(find(d_E[s].get().begin(), d_E[s].get().end(), sMt) != d_E[s].get().end()) {
- Assert( find(d_E[s].get().begin(), d_E[s].get().end(), sMt) != d_E[s].get().end() );
- Assert( find(d_E[s].get().begin(), d_E[s].get().end(), sNt) != d_E[s].get().end() );
- Assert( find(d_E[t].get().begin(), d_E[t].get().end(), tMs) != d_E[t].get().end() );
- Assert( find(d_E[t].get().begin(), d_E[t].get().end(), sNt) != d_E[t].get().end() );
- continue;
- }
-
- Trace("sets-card") << "[sets-card] Already found in the graph, merging " << s << std::endl;
- merge_nodes(get_leaves(s), get_leaves(sMt, sNt), eqSoFar());
- }
-
- // for t
- if(d_E.find(t) == d_E.end()) {
- Assert(d_E.find(t) == d_E.end());
- add_node(t);
- add_edges(t, sNt, tMs);
-
- lem = nm->mkNode(kind::EQUAL,
- card_t,
- nm->mkNode(kind::PLUS, card_sNt, card_tMs));
- lemma(lem, SETS_LEMMA_GRAPH);
- } else {
- // Assert( find(d_E[s].get().begin(), d_E[s].get().end(), sMt) == d_E[s].get().end() );
- // Assert( find(d_E[s].get().begin(), d_E[s].get().end(), sNt) == d_E[s].get().end() );
- // Assert( find(d_E[t].get().begin(), d_E[t].get().end(), tMs) == d_E[t].get().end() );
- // Assert( find(d_E[t].get().begin(), d_E[t].get().end(), sNt) == d_E[t].get().end() );
-
- Trace("sets-card") << "[sets-card] Already found in the graph, merging " << t << std::endl;
- merge_nodes(get_leaves(t), get_leaves(sNt, tMs), eqSoFar());
- }
-
- if(options::setsSlowLemmas()) {
- if(d_newLemmaGenerated) {
- break;
- } else if(options::setsGuessEmpty() == 0) {
- guessLeavesEmptyLemmas();
- if(d_newLemmaGenerated) {
- return;
- }
- }
- }
-
- }//equivalence class loop
-
- if(options::setsSlowLemmas() && d_newLemmaGenerated) {
- break;
- }
-
- }//d_cardTerms loop
-
- print_graph();
-
- if(d_newLemmaGenerated) {
- Trace("sets-card") << "[sets-card] New introduce done. Returning." << std::endl;
- return;
- }
-
- if(options::setsGuessEmpty() == 1) {
- guessLeavesEmptyLemmas();
- if(d_newLemmaGenerated) {
- return;
- }
- }
-
- // Merge equalities from input assertions
-
- while(!d_graphMergesPending.empty()) {
- std::pair<TNode,TNode> np = d_graphMergesPending.front();
- d_graphMergesPending.pop();
-
- Debug("sets-card") << "[sets-card] Equality " << np.first << " " << np.second << std::endl;
- if(np.first.getKind() == kind::EMPTYSET || np.second.getKind() == kind::EMPTYSET) {
- Debug("sets-card") << "[sets-card] skipping merge as one side is empty set" << std::endl;
- continue;
- }
-
- if(d_V.find(np.first) == d_V.end() || d_V.find(np.second) == d_V.end()) {
- Assert((d_V.find(np.first) == d_V.end()));
- Assert((d_V.find(np.second) == d_V.end()));
- continue;
- }
- d_allSetEqualitiesSoFar.push_back(EQUAL(np.first, np.second));
- // merge_nodes(get_leaves(np.first), get_leaves(np.second), EQUAL(np.first, np.second));
- merge_nodes(get_leaves(np.first), get_leaves(np.second), eqSoFar());
- }
-
- if(d_newLemmaGenerated) {
- Trace("sets-card") << "[sets-card] New merge done. Returning." << std::endl;
- return;
- }
-
- leaves.clear();
- for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) {
- TNode v = *it;
- if(d_E.find(v) == d_E.end()) {
- leaves.insert(v);
- }
- }
- Trace("sets-card") << "[sets-card] # leaves = " << leaves.size() << std::endl;
- d_statistics.d_numLeaves.setData(leaves.size());
- d_statistics.d_numLeavesMax.maxAssign(leaves.size());
-
- Assert(!d_newLemmaGenerated);
-
-
- if(options::setsGuessEmpty() == 2) {
- guessLeavesEmptyLemmas();
- if(d_newLemmaGenerated) {
- return;
- }
- }
-
- typedef std::set<TNode>::const_iterator TNodeSetIterator;
-
- // Elements being either equal or disequal [Members Arrangement rule]
- Trace("sets-card")
- << "[sets-card] Processing elements equality/disequal to each other"
- << std::endl;
- for (TNodeSetIterator it = leaves.begin(); it != leaves.end(); ++it) {
- if (!d_equalityEngine.hasTerm(*it)) continue;
- Node n = d_equalityEngine.getRepresentative(*it);
- Assert(n.getKind() == kind::EMPTYSET || leaves.find(n) != leaves.end());
- if (n != *it) continue;
- const CDTNodeList* l = d_termInfoManager->getMembers(*it);
- std::set<TNode> elems;
- for (CDTNodeList::const_iterator l_it = l->begin(); l_it != l->end(); ++l_it) {
- elems.insert(d_equalityEngine.getRepresentative(*l_it));
- }
- for (TNodeSetIterator e1_it = elems.begin(); e1_it != elems.end();
- ++e1_it) {
- for (TNodeSetIterator e2_it = elems.begin(); e2_it != elems.end();
- ++e2_it) {
- if (*e1_it == *e2_it) continue;
- if (!d_equalityEngine.areDisequal(*e1_it, *e2_it, false)) {
- Node lem = nm->mkNode(kind::EQUAL, *e1_it, *e2_it);
- lem = nm->mkNode(kind::OR, lem, nm->mkNode(kind::NOT, lem));
- lemma(lem, SETS_LEMMA_GRAPH);
- }
- }
- }
- }
-
- if(d_newLemmaGenerated) {
- Trace("sets-card") << "[sets-card] Members arrangments lemmas. Returning." << std::endl;
- return;
- }
-
- // Assert Lower bound
- Trace("sets-card") << "[sets-card] Processing assert lower bound" << std::endl;
- for(TNodeSetIterator it = leaves.begin(); it != leaves.end(); ++it) {
- Trace("sets-cardlower") << "[sets-cardlower] Card Lower: " << *it << std::endl;
- Assert(d_equalityEngine.hasTerm(*it));
- Node n = d_equalityEngine.getRepresentative(*it);
- // Node n = (*it);
- // if(!d_equalityEngine.hasTerm(n)) {
- // Trace("sets-cardlower") << "[sets-cardlower] not in EE" << std::endl;
- // continue;
- // }
- // Assert(n.getKind() == kind::EMPTYSET || leaves.find(n) != leaves.end()); // ????
- // if(n != *it) continue;
- const CDTNodeList* l = d_termInfoManager->getMembers(n);
- std::set<TNode> elems;
- for(CDTNodeList::const_iterator l_it = l->begin(); l_it != l->end(); ++l_it) {
- elems.insert(d_equalityEngine.getRepresentative(*l_it));
- }
- if(elems.size() == 0) continue;
- NodeBuilder<> nb(kind::OR);
- nb << ( nm->mkNode(kind::LEQ, nm->mkConst(Rational(elems.size())), nm->mkNode(kind::CARD, *it)) );
- if(elems.size() > 1) {
- for(TNodeSetIterator e1_it = elems.begin(); e1_it != elems.end(); ++e1_it) {
- for(TNodeSetIterator e2_it = elems.begin(); e2_it != elems.end(); ++e2_it) {
- if(*e1_it == *e2_it) continue;
- nb << (nm->mkNode(kind::EQUAL, *e1_it, *e2_it));
- }
- }
- }
- for(TNodeSetIterator e_it = elems.begin(); e_it != elems.end(); ++e_it) {
- nb << nm->mkNode(kind::NOT, nm->mkNode(kind::MEMBER, *e_it, *it));
- }
- Node lem = Node(nb);
- // if(d_cardLowerLemmaCache.find(lem) == d_cardLowerLemmaCache.end()) {
- Trace("sets-card") << "[sets-card] Card Lower: " << lem << std::endl;
- lemma(lem, SETS_LEMMA_GRAPH);
- // d_cardLowerLemmaCache.insert(lem);
- // }
- }
-}
-
-
-
}/* CVC4::theory::sets namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/sets/theory_sets_private.h b/src/theory/sets/theory_sets_private.h
index 049e95786..25a15a84a 100644
--- a/src/theory/sets/theory_sets_private.h
+++ b/src/theory/sets/theory_sets_private.h
@@ -24,10 +24,15 @@
#include "theory/theory.h"
#include "theory/uf/equality_engine.h"
-#include "theory/sets/term_info.h"
+#include "theory/sets/theory_sets_rels.h"
namespace CVC4 {
namespace theory {
+
+namespace quantifiers{
+ class TermArgTrie;
+}
+
namespace sets {
/** Internal classes, forward declared here */
@@ -36,6 +41,107 @@ class TheorySets;
class TheorySetsScrutinize;
class TheorySetsPrivate {
+//new implementation
+ typedef context::CDHashMap< Node, bool, NodeHashFunction> NodeBoolMap;
+ typedef context::CDHashMap< Node, int, NodeHashFunction> NodeIntMap;
+ typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
+ typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap;
+private:
+ TheorySetsRels * d_rels;
+public:
+ void eqNotifyNewClass(TNode t);
+ void eqNotifyPreMerge(TNode t1, TNode t2);
+ void eqNotifyPostMerge(TNode t1, TNode t2);
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
+private:
+ bool ee_areEqual( Node a, Node b );
+ bool ee_areDisequal( Node a, Node b );
+ NodeIntMap d_members;
+ std::map< Node, std::vector< Node > > d_members_data;
+ bool assertFact( Node fact, Node exp );
+ // inferType : 1 : must send out as lemma, -1 : do internal inferences if possible, 0 : default.
+ bool assertFactRec( Node fact, Node exp, std::vector< Node >& lemma, int inferType = 0 );
+ // add inferences corresponding to ( exp => fact ) to lemmas, equality engine
+ void assertInference( Node fact, Node exp, std::vector< Node >& lemmas, const char * c, int inferType = 0 );
+ void assertInference( Node fact, std::vector< Node >& exp, std::vector< Node >& lemmas, const char * c, int inferType = 0 );
+ void assertInference( std::vector< Node >& conc, Node exp, std::vector< Node >& lemmas, const char * c, int inferType = 0 );
+ void assertInference( std::vector< Node >& conc, std::vector< Node >& exp, std::vector< Node >& lemmas, const char * c, int inferType = 0 );
+ // send lemma ( n OR (NOT n) ) immediately
+ void split( Node n, int reqPol=0 );
+ void fullEffortCheck();
+ void checkDownwardsClosure( std::vector< Node >& lemmas );
+ void checkUpwardsClosure( std::vector< Node >& lemmas );
+ void checkDisequalities( std::vector< Node >& lemmas );
+ bool isMember( Node x, Node s );
+
+ void flushLemmas( std::vector< Node >& lemmas );
+ Node getProxy( Node n );
+ Node getCongruent( Node n );
+ Node getEmptySet( TypeNode tn );
+ bool hasLemmaCached( Node lem );
+ bool hasProcessed();
+
+ void addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth, unsigned& n_pairs );
+
+ Node d_true;
+ Node d_false;
+ Node d_zero;
+ NodeBoolMap d_deq;
+ NodeSet d_deq_processed;
+ NodeSet d_keep;
+ std::vector< Node > d_emp_exp;
+
+ //propagation
+ class EqcInfo
+ {
+ public:
+ EqcInfo( context::Context* c );
+ ~EqcInfo(){}
+ // singleton or emptyset equal to this eqc
+ context::CDO< Node > d_singleton;
+ };
+ /** information necessary for equivalence classes */
+ std::map< Node, EqcInfo* > d_eqc_info;
+ /** get or make eqc info */
+ EqcInfo* getOrMakeEqcInfo( TNode n, bool doMake = false );
+
+ void addEqualityToExp( Node a, Node b, std::vector< Node >& exp );
+
+ void debugPrintSet( Node s, const char * c );
+
+ bool d_sentLemma;
+ bool d_addedFact;
+ NodeMap d_proxy;
+ NodeMap d_proxy_to_term;
+ NodeSet d_lemmas_produced;
+ std::vector< Node > d_set_eqc;
+ std::map< Node, std::vector< Node > > d_set_eqc_list;
+ std::map< TypeNode, Node > d_eqc_emptyset;
+ std::map< Node, Node > d_eqc_singleton;
+ std::map< TypeNode, Node > d_emptyset;
+ std::map< Node, Node > d_congruent;
+ std::map< Node, std::vector< Node > > d_nvar_sets;
+ std::map< Node, std::map< Node, Node > > d_pol_mems[2];
+ std::map< Node, std::map< Node, Node > > d_members_index;
+ std::map< Node, Node > d_singleton_index;
+ std::map< Kind, std::map< Node, std::map< Node, Node > > > d_bop_index;
+ std::map< Kind, std::vector< Node > > d_op_list;
+ //cardinality
+private:
+ bool d_card_enabled;
+ std::map< Node, Node > d_eqc_to_card_term;
+ NodeSet d_card_processed;
+ std::map< Node, std::vector< Node > > d_card_parent;
+ std::map< Node, std::map< Node, std::vector< Node > > > d_ff;
+ std::map< Node, std::vector< Node > > d_nf;
+ std::map< Node, Node > d_card_base;
+ void checkCardBuildGraph( std::vector< Node >& lemmas );
+ void registerCardinalityTerm( Node n, std::vector< Node >& lemmas );
+ void checkCardCycles( std::vector< Node >& lemmas );
+ void checkCardCyclesRec( Node eqc, std::vector< Node >& curr, std::vector< Node >& exp, std::vector< Node >& lemmas );
+ void checkNormalForms( std::vector< Node >& lemmas, std::vector< Node >& intro_sets );
+ void checkNormalForm( Node eqc, std::vector< Node >& intro_sets );
+ void checkMinCard( std::vector< Node >& lemmas );
public:
/**
@@ -62,8 +168,6 @@ public:
EqualityStatus getEqualityStatus(TNode a, TNode b);
- Node getModelValue(TNode);
-
void preRegisterTerm(TNode node);
void presolve();
@@ -101,19 +205,15 @@ private:
bool eqNotifyTriggerPredicate(TNode predicate, bool value);
bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value);
void eqNotifyConstantTermMerge(TNode t1, TNode t2);
- void eqNotifyNewClass(TNode t) {}
- void eqNotifyPreMerge(TNode t1, TNode t2) {}
- void eqNotifyPostMerge(TNode t1, TNode t2) {}
- void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {}
+ void eqNotifyNewClass(TNode t);
+ void eqNotifyPreMerge(TNode t1, TNode t2);
+ void eqNotifyPostMerge(TNode t1, TNode t2);
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
} d_notify;
/** Equality engine */
eq::EqualityEngine d_equalityEngine;
- /** True and false constant nodes */
- Node d_trueNode;
- Node d_falseNode;
-
context::CDO<bool> d_conflict;
Node d_conflictNode;
@@ -122,179 +222,11 @@ private:
/** generate and send out conflict node */
void conflict(TNode, TNode);
-
- /** send out a lemma */
- enum SetsLemmaTag {
- SETS_LEMMA_DISEQUAL,
- SETS_LEMMA_MEMBER,
- SETS_LEMMA_GRAPH,
- SETS_LEMMA_OTHER
- };
-
- /**
- * returns true if a lemmas was generated
- * returns false otherwise (found in cache)
- */
- bool lemma(Node n, SetsLemmaTag t);
-
- class TermInfoManager {
- TheorySetsPrivate& d_theory;
- context::Context* d_context;
- eq::EqualityEngine* d_eqEngine;
- public:
- CDNodeSet d_terms;
- private:
- typedef std::hash_map<TNode, TheorySetsTermInfo*, TNodeHashFunction> SetsTermInfoMap;
- SetsTermInfoMap d_info;
-
- void mergeLists(CDTNodeList* la, const CDTNodeList* lb) const;
- void pushToSettermPropagationQueue(TNode x, TNode S, bool polarity);
- void pushToSettermPropagationQueue(CDTNodeList* l, TNode S, bool polarity);
- void pushToSettermPropagationQueue(TNode x, CDTNodeList* l, bool polarity);
- public:
- TermInfoManager(TheorySetsPrivate&,
- context::Context* satContext,
- eq::EqualityEngine*);
- ~TermInfoManager();
- void notifyMembership(TNode fact);
- const CDTNodeList* getParents(TNode x);
- const CDTNodeList* getMembers(TNode S);
- Node getModelValue(TNode n);
- const CDTNodeList* getNonMembers(TNode S);
- void addTerm(TNode n);
- void mergeTerms(TNode a, TNode b);
- };
- TermInfoManager* d_termInfoManager;
-
- /******
- * Card Vars :
- *
- * mapping from set terms to correpsonding cardinality variable
- *
- * in the ::check function, when we get one of those cardinality
- * variables to be assigned to 0, we will assert in equality engine
- * to be equal to empty set.
- *
- * if required, we will add more filters so it doesn't leak to
- * outside world
- */
- Node getCardVar(TNode n);
- Node newCardVar(TNode n);
- bool isCardVar(TNode n);
- typedef std::hash_map <Node, Node, NodeHashFunction> NodeNodeHashMap;
- NodeNodeHashMap d_setTermToCardVar;
- NodeNodeHashMap d_cardVarToSetTerm;
- /** Assertions and helper functions */
- bool present(TNode atom);
- bool holds(TNode lit) {
- bool polarity = lit.getKind() == kind::NOT ? false : true;
- TNode atom = polarity ? lit : lit[0];
- return holds(atom, polarity);
- }
- bool holds(TNode atom, bool polarity);
-
- void assertEquality(TNode fact, TNode reason, bool learnt);
- void assertMemebership(TNode fact, TNode reason, bool learnt);
-
- /** Propagation / learning and helper functions. */
- context::CDQueue< std::pair<Node, Node> > d_propagationQueue;
- context::CDQueue< std::pair<TNode, TNode> > d_settermPropagationQueue;
-
- void doSettermPropagation(TNode x, TNode S);
- void registerReason(TNode reason, bool save);
- void learnLiteral(TNode atom, bool polarity, Node reason);
- void learnLiteral(TNode lit, Node reason) {
- if(lit.getKind() == kind::NOT) {
- learnLiteral(lit[0], false, reason);
- } else {
- learnLiteral(lit, true, reason);
- }
- }
- void finishPropagation();
-
- // for any nodes we need to save, because others use TNode
- context::CDHashSet <Node, NodeHashFunction> d_nodeSaver;
-
- /** Lemmas and helper functions */
- context::CDQueue <Node> d_pending;
- context::CDQueue <Node> d_pendingDisequal;
- context::CDHashSet <Node, NodeHashFunction> d_pendingEverInserted;
-
- void addToPending(Node n);
- bool isComplete();
- Node getLemma();
-
- /** model generation and helper function */
- typedef std::set<TNode> Elements;
- typedef std::hash_map<TNode, Elements, TNodeHashFunction> SettermElementsMap;
- const Elements& getElements(TNode setterm, SettermElementsMap& settermElementsMap) const;
- Node elementsToShape(Elements elements, TypeNode setType) const;
- Node elementsToShape(std::set<Node> elements, TypeNode setType) const;
- bool checkModel(const SettermElementsMap& settermElementsMap, TNode S) const;
-
- context::CDHashMap <Node, Node, NodeHashFunction> d_modelCache;
-
-
- // sharing related
- context::CDO<unsigned> d_ccg_i, d_ccg_j;
-
- // more debugging stuff
- friend class TheorySetsScrutinize;
- TheorySetsScrutinize* d_scrutinize;
- void dumpAssertionsHumanified() const; /** do some formatting to make them more readable */
-
-
-
- /***** Cardinality handling *****/
- bool d_cardEnabled;
- void enableCard();
- void cardCreateEmptysetSkolem(TypeNode t);
-
- CDNodeSet d_cardTerms;
- std::set<TypeNode> d_typesAdded;
- CDNodeSet d_processedCardTerms;
- std::map<std::pair<Node, Node>, bool> d_processedCardPairs;
- CDNodeSet d_cardLowerLemmaCache;
- void registerCard(TNode);
- void processCard(Theory::Effort level);
-
- /* Graph handling */
- std::map<TNode, std::set<TNode> > edgesFd;
- std::map<TNode, std::set<TNode> > edgesBk;
- std::set< std::pair<TNode, TNode> > disjoint;
- std::set<TNode> leaves;
- void buildGraph();
-
- /* For calculus as in paper */
- void processCard2(Theory::Effort level);
- CDNodeSet d_V;
- context::CDHashMap <TNode, std::vector<TNode>, TNodeHashFunction > d_E;
- void add_edges(TNode source, TNode dest);
- void add_edges(TNode source, TNode dest1, TNode dest2);
- void add_edges(TNode source, TNode dest1, TNode dest2, TNode dest3);
- void add_edges(TNode source, const std::vector<TNode>& dests);
- void add_node(TNode vertex);
- void merge_nodes(std::set<TNode> a, std::set<TNode> b, Node reason);
- std::set<TNode> get_leaves(Node vertex);
- std::set<TNode> get_leaves(Node vertex1, Node vertex2);
- std::set<TNode> get_leaves(Node vertex1, Node vertex2, Node vertex3);
- std::set<TNode> non_empty(std::set<TNode> vertices);
- void print_graph(bool printmodel=false);
- context::CDQueue < std::pair<TNode, TNode> > d_graphMergesPending;
- context::CDList<Node> d_allSetEqualitiesSoFar;
- Node eqSoFar();
- Node eqemptySoFar();
-
- std::set<TNode> getNonEmptyLeaves(TNode);
- CDNodeSet d_lemmasGenerated;
- bool d_newLemmaGenerated;
-
- void guessLeavesEmptyLemmas();
-
-
- /** relevant terms */
- CDNodeSet d_relTerms;
+ bool isCareArg( Node n, unsigned a );
+public:
+ bool isEntailed( Node n, bool pol );
+
};/* class TheorySetsPrivate */
diff --git a/src/theory/sets/theory_sets_rels.cpp b/src/theory/sets/theory_sets_rels.cpp
new file mode 100644
index 000000000..c7ec08210
--- /dev/null
+++ b/src/theory/sets/theory_sets_rels.cpp
@@ -0,0 +1,1907 @@
+/********************* */
+/*! \file theory_sets_rels.cpp
+ ** \verbatim
+ ** Original author: Paul Meng
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Sets theory implementation.
+ **
+ ** Extension to Sets theory.
+ **/
+
+#include "theory/sets/theory_sets_rels.h"
+#include "expr/datatype.h"
+#include "theory/sets/theory_sets_private.h"
+#include "theory/sets/theory_sets.h"
+
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace sets {
+
+typedef std::map< Node, std::vector< Node > >::iterator MEM_IT;
+typedef std::map< kind::Kind_t, std::vector< Node > >::iterator KIND_TERM_IT;
+typedef std::map< Node, std::hash_set< Node, NodeHashFunction > >::iterator TC_PAIR_IT;
+typedef std::map< Node, std::map< kind::Kind_t, std::vector< Node > > >::iterator TERM_IT;
+typedef std::map< Node, std::map< Node, std::hash_set< Node, NodeHashFunction > > >::iterator TC_IT;
+
+int TheorySetsRels::EqcInfo::counter = 0;
+
+ void TheorySetsRels::check(Theory::Effort level) {
+ Trace("rels") << "\n[sets-rels] ******************************* Start the relational solver *******************************\n" << std::endl;
+ if(Theory::fullEffort(level)) {
+ collectRelsInfo();
+ check();
+ doPendingLemmas();
+ Assert(d_lemma_cache.empty());
+ Assert(d_pending_facts.empty());
+ } else {
+ doPendingMerge();
+ doPendingLemmas();
+ }
+ Trace("rels") << "\n[sets-rels] ******************************* Done with the relational solver *******************************\n" << std::endl;
+ }
+
+ void TheorySetsRels::check() {
+ MEM_IT m_it = d_membership_constraints_cache.begin();
+
+ while(m_it != d_membership_constraints_cache.end()) {
+ Node rel_rep = m_it->first;
+
+ for(unsigned int i = 0; i < m_it->second.size(); i++) {
+ Node exp = d_membership_exp_cache[rel_rep][i];
+ std::map<kind::Kind_t, std::vector<Node> > kind_terms = d_terms_cache[rel_rep];
+
+ if( kind_terms.find(kind::TRANSPOSE) != kind_terms.end() ) {
+ std::vector<Node> tp_terms = kind_terms[kind::TRANSPOSE];
+ // exp is a membership term and tp_terms contains all
+ // transposed terms that are equal to the right hand side of exp
+ for(unsigned int j = 0; j < tp_terms.size(); j++) {
+ applyTransposeRule( exp, tp_terms[j] );
+ }
+ }
+ if( kind_terms.find(kind::JOIN) != kind_terms.end() ) {
+ std::vector<Node> join_terms = kind_terms[kind::JOIN];
+ // exp is a membership term and join_terms contains all
+ // terms involving "join" operator that are in the same
+ // equivalence class with the right hand side of exp
+ for(unsigned int j = 0; j < join_terms.size(); j++) {
+ applyJoinRule( exp, join_terms[j] );
+ }
+ }
+ if( kind_terms.find(kind::PRODUCT) != kind_terms.end() ) {
+ std::vector<Node> product_terms = kind_terms[kind::PRODUCT];
+ for(unsigned int j = 0; j < product_terms.size(); j++) {
+ applyProductRule( exp, product_terms[j] );
+ }
+ }
+ if( kind_terms.find(kind::TCLOSURE) != kind_terms.end() ) {
+ std::vector<Node> tc_terms = kind_terms[kind::TCLOSURE];
+ for(unsigned int j = 0; j < tc_terms.size(); j++) {
+ applyTCRule( exp, tc_terms[j] );
+ }
+ }
+
+ MEM_IT tp_it = d_arg_rep_tp_terms.find( rel_rep );
+
+ if( tp_it != d_arg_rep_tp_terms.end() ) {
+ std::vector< Node >::iterator tp_ts_it = tp_it->second.begin();
+
+ while( tp_ts_it != tp_it->second.end() ) {
+ applyTransposeRule( exp, *tp_ts_it, (*tp_ts_it)[0] == rel_rep?Node::null():explain(NodeManager::currentNM()->mkNode(kind::EQUAL,(*tp_ts_it)[0], rel_rep)), true );
+ ++tp_ts_it;
+ }
+ ++tp_it;
+ }
+ }
+ m_it++;
+ }
+
+ TERM_IT t_it = d_terms_cache.begin();
+ while( t_it != d_terms_cache.end() ) {
+ if( d_membership_constraints_cache.find(t_it->first) == d_membership_constraints_cache.end() ) {
+ Trace("rels-debug") << "[sets-rels] A term does not have membership constraints: " << t_it->first << std::endl;
+ KIND_TERM_IT k_t_it = t_it->second.begin();
+
+ while( k_t_it != t_it->second.end() ) {
+ if( k_t_it->first == kind::JOIN || k_t_it->first == kind::PRODUCT ) {
+ std::vector<Node>::iterator term_it = k_t_it->second.begin();
+ while(term_it != k_t_it->second.end()) {
+ computeMembersForRelofMultArities(*term_it);
+ term_it++;
+ }
+ } else if ( k_t_it->first == kind::TRANSPOSE ) {
+ std::vector<Node>::iterator term_it = k_t_it->second.begin();
+ while( term_it != k_t_it->second.end() ) {
+ computeMembersForUnaryRel(*term_it);
+ term_it++;
+ }
+ } else if ( k_t_it->first == kind::TCLOSURE ) {
+ Trace("rels-debug") << "[sets-rels] ********** A TCLOSURE term does not have membership constraints: " << t_it->first << std::endl;
+ d_tc_rep_term[t_it->first] = k_t_it->second[0];
+ }
+ k_t_it++;
+ }
+ }
+ t_it++;
+ }
+
+ finalizeTCInference();
+ }
+
+ /*
+ * Populate relational terms data structure
+ */
+
+ void TheorySetsRels::collectRelsInfo() {
+ Trace("rels") << "[sets-rels] Start collecting relational terms..." << std::endl;
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( d_eqEngine );
+ while( !eqcs_i.isFinished() ){
+ Node eqc_rep = (*eqcs_i);
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc_rep, d_eqEngine );
+
+ Trace("rels-ee") << "[sets-rels-ee] term representative: " << eqc_rep << std::endl;
+
+ while( !eqc_i.isFinished() ){
+ Node eqc_node = (*eqc_i);
+
+ Trace("rels-ee") << " term : " << eqc_node << std::endl;
+
+ if(getRepresentative(eqc_rep) == getRepresentative(d_trueNode) ||
+ getRepresentative(eqc_rep) == getRepresentative(d_falseNode)) {
+ // collect membership info
+ if(eqc_node.getKind() == kind::MEMBER && eqc_node[1].getType().getSetElementType().isTuple()) {
+ Node tup_rep = getRepresentative(eqc_node[0]);
+ Node rel_rep = getRepresentative(eqc_node[1]);
+
+ if(eqc_node[0].isVar()){
+ reduceTupleVar(eqc_node);
+ }
+ if( safelyAddToMap(d_membership_constraints_cache, rel_rep, tup_rep) ) {
+ bool is_true_eq = areEqual(eqc_rep, d_trueNode);
+ Node reason = is_true_eq ? eqc_node : eqc_node.negate();
+ addToMap(d_membership_exp_cache, rel_rep, reason);
+ if( is_true_eq ) {
+ // add tup_rep to membership database
+ // and store mapping between tuple and tuple's elements representatives
+ addToMembershipDB(rel_rep, tup_rep, reason);
+ }
+ }
+ }
+ // collect relational terms info
+ } else if( eqc_rep.getType().isSet() && eqc_rep.getType().getSetElementType().isTuple() ) {
+ if( eqc_node.getKind() == kind::TRANSPOSE || eqc_node.getKind() == kind::JOIN ||
+ eqc_node.getKind() == kind::PRODUCT || eqc_node.getKind() == kind::TCLOSURE ) {
+ std::vector<Node> terms;
+ std::map<kind::Kind_t, std::vector<Node> > rel_terms;
+ TERM_IT terms_it = d_terms_cache.find(eqc_rep);
+
+ if( eqc_node.getKind() == kind::TRANSPOSE ) {
+ Node eqc_node0_rep = getRepresentative( eqc_node[0] );
+ MEM_IT mem_it = d_arg_rep_tp_terms.find( eqc_node0_rep );
+
+ if( mem_it != d_arg_rep_tp_terms.end() ) {
+ mem_it->second.push_back( eqc_node );
+ } else {
+ std::vector< Node > tp_terms;
+ tp_terms.push_back( eqc_node );
+ d_arg_rep_tp_terms[eqc_node0_rep] = tp_terms;
+ }
+ }
+
+ if( terms_it == d_terms_cache.end() ) {
+ terms.push_back(eqc_node);
+ rel_terms[eqc_node.getKind()] = terms;
+ d_terms_cache[eqc_rep] = rel_terms;
+ } else {
+ KIND_TERM_IT kind_term_it = terms_it->second.find(eqc_node.getKind());
+
+ if( kind_term_it == terms_it->second.end() ) {
+ terms.push_back(eqc_node);
+ d_terms_cache[eqc_rep][eqc_node.getKind()] = terms;
+ } else {
+ kind_term_it->second.push_back(eqc_node);
+ }
+ }
+ }
+ // need to add all tuple elements as shared terms
+ } else if(eqc_node.getType().isTuple() && !eqc_node.isConst() && !eqc_node.isVar()) {
+ for(unsigned int i = 0; i < eqc_node.getType().getTupleLength(); i++) {
+ Node element = RelsUtils::nthElementOfTuple(eqc_node, i);
+ if(!element.isConst()) {
+ makeSharedTerm(element);
+ }
+ }
+ }
+ ++eqc_i;
+ }
+ ++eqcs_i;
+ }
+ Trace("rels-debug") << "[sets-rels] Done with collecting relational terms!" << std::endl;
+ }
+
+ /*
+ * Construct transitive closure graph for tc_rep based on the members of tc_r_rep
+ */
+
+ std::map< Node, std::hash_set< Node, NodeHashFunction > > TheorySetsRels::constructTCGraph(Node tc_r_rep, Node tc_rep, Node tc_term) {
+ Trace("rels-tc") << "[sets-rels] Construct TC graph for transitive closure relation " << tc_rep << std::endl;
+
+ std::map< Node, std::hash_set< Node, NodeHashFunction > > tc_graph;
+ std::map< Node, std::hash_set< Node, NodeHashFunction > > tc_r_graph;
+ MEM_IT mem_it = d_membership_db.find(tc_r_rep);
+
+ if(mem_it != d_membership_db.end()) {
+ for(std::vector<Node>::iterator pair_it = mem_it->second.begin();
+ pair_it != mem_it->second.end(); pair_it++) {
+ Node fst_rep = getRepresentative(RelsUtils::nthElementOfTuple(*pair_it, 0));
+ Node snd_rep = getRepresentative(RelsUtils::nthElementOfTuple(*pair_it, 1));
+ TC_PAIR_IT pair_set_it = tc_graph.find(fst_rep);
+ TC_PAIR_IT r_pair_set_it = tc_r_graph.find(fst_rep);
+
+ Trace("rels-tc") << "[sets-rels] **** Member of r = (" << fst_rep << ", " << snd_rep << ")" << std::endl;
+
+ if( pair_set_it != tc_graph.end() ) {
+ pair_set_it->second.insert(snd_rep);
+ r_pair_set_it->second.insert(snd_rep);
+ } else {
+ std::hash_set< Node, NodeHashFunction > snd_set;
+ snd_set.insert(snd_rep);
+ tc_r_graph[fst_rep] = snd_set;
+ tc_graph[fst_rep] = snd_set;
+ }
+ }
+ }
+
+ Node reason = getReason(tc_rep, tc_term, tc_r_rep, tc_term[0]);
+
+ if(!reason.isNull()) {
+ d_membership_tc_exp_cache[tc_rep] = reason;
+ }
+ d_tc_r_graph[tc_rep] = tc_r_graph;
+
+ TC_PAIR_IT tc_mem_it = d_tc_membership_db.find(tc_term);
+
+ if( tc_mem_it != d_tc_membership_db.end() ) {
+ for(std::hash_set<Node, NodeHashFunction>::iterator pair_it = tc_mem_it->second.begin();
+ pair_it != tc_mem_it->second.end(); pair_it++) {
+ Node fst_rep = getRepresentative(RelsUtils::nthElementOfTuple(*pair_it, 0));
+ Node snd_rep = getRepresentative(RelsUtils::nthElementOfTuple(*pair_it, 1));
+ TC_PAIR_IT pair_set_it = tc_graph.find(fst_rep);
+ Trace("rels-tc") << "[sets-rels] **** Member of TC(r) = (" << fst_rep << ", " << snd_rep << ")" << std::endl;
+
+ if( pair_set_it != tc_graph.end() ) {
+ pair_set_it->second.insert(snd_rep);
+ } else {
+ std::hash_set< Node, NodeHashFunction > snd_set;
+ snd_set.insert(snd_rep);
+ tc_graph[fst_rep] = snd_set;
+ }
+ }
+ }
+
+ return tc_graph;
+ }
+
+ /*
+ *
+ *
+ * transitive closure rule 1: y = (TCLOSURE x)
+ * ---------------------------------------------
+ * y = x | x.x | x.x.x | ... (| is union)
+ *
+ *
+ *
+ * transitive closure rule 2: TCLOSURE(x)
+ * -----------------------------------------------------------
+ * x <= TCLOSURE(x) && (x JOIN x) <= TCLOSURE(x) ....
+ *
+ * TC(x) = TC(y) => x = y ?
+ *
+ */
+
+ void TheorySetsRels::applyTCRule(Node exp, Node tc_term) {
+ Trace("rels-debug") << "\n[sets-rels] *********** Applying TRANSITIVE CLOSURE rule on "
+ << tc_term << " with explanation " << exp << std::endl;
+
+ Node tc_rep = getRepresentative(tc_term);
+ bool polarity = exp.getKind() != kind::NOT;
+
+ if( d_rel_nodes.find(tc_rep) == d_rel_nodes.end() ) {
+ d_tc_rep_term[tc_rep] = tc_term;
+ d_rel_nodes.insert(tc_rep);
+ }
+ if(polarity) {
+ TC_PAIR_IT mem_it = d_tc_membership_db.find(tc_term);
+
+ if( mem_it == d_tc_membership_db.end() ) {
+ std::hash_set<Node, NodeHashFunction> members;
+ members.insert(exp[0]);
+ d_tc_membership_db[tc_term] = members;
+ } else {
+ mem_it->second.insert(exp[0]);
+ }
+ } else {
+ Trace("rels-tc") << "TC non-member = " << exp << std::endl;
+ }
+ }
+
+ /* product-split rule: (a, b) IS_IN (X PRODUCT Y)
+ * ----------------------------------
+ * a IS_IN X && b IS_IN Y
+ *
+ * product-compose rule: (a, b) IS_IN X (c, d) IS_IN Y NOT (r, s, t, u) IS_IN (X PRODUCT Y)
+ * ----------------------------------------------------------------------
+ * (a, b, c, d) IS_IN (X PRODUCT Y)
+ */
+
+ void TheorySetsRels::applyProductRule(Node exp, Node product_term) {
+ Trace("rels-debug") << "\n[sets-rels] *********** Applying PRODUCT rule " << std::endl;
+
+ if(d_rel_nodes.find(product_term) == d_rel_nodes.end()) {
+ computeMembersForRelofMultArities(product_term);
+ d_rel_nodes.insert(product_term);
+ }
+ bool polarity = exp.getKind() != kind::NOT;
+ Node atom = polarity ? exp : exp[0];
+ Node r1_rep = getRepresentative(product_term[0]);
+ Node r2_rep = getRepresentative(product_term[1]);
+
+ Trace("rels-debug") << "\n[sets-rels] Apply PRODUCT-SPLIT rule on term: " << product_term
+ << " with explanation: " << exp << std::endl;
+ std::vector<Node> r1_element;
+ std::vector<Node> r2_element;
+ NodeManager *nm = NodeManager::currentNM();
+ Datatype dt = r1_rep.getType().getSetElementType().getDatatype();
+ unsigned int i = 0;
+ unsigned int s1_len = r1_rep.getType().getSetElementType().getTupleLength();
+ unsigned int tup_len = product_term.getType().getSetElementType().getTupleLength();
+
+ r1_element.push_back(Node::fromExpr(dt[0].getConstructor()));
+ for(; i < s1_len; ++i) {
+ r1_element.push_back(RelsUtils::nthElementOfTuple(atom[0], i));
+ }
+
+ dt = r2_rep.getType().getSetElementType().getDatatype();
+ r2_element.push_back(Node::fromExpr(dt[0].getConstructor()));
+ for(; i < tup_len; ++i) {
+ r2_element.push_back(RelsUtils::nthElementOfTuple(atom[0], i));
+ }
+
+ Node fact_1;
+ Node fact_2;
+ Node reason_1 = exp;
+ Node reason_2 = exp;
+ Node t1 = nm->mkNode(kind::APPLY_CONSTRUCTOR, r1_element);
+ Node t1_rep = getRepresentative(t1);
+ Node t2 = nm->mkNode(kind::APPLY_CONSTRUCTOR, r2_element);
+ Node t2_rep = getRepresentative(t2);
+
+ fact_1 = NodeManager::currentNM()->mkNode(kind::MEMBER, t1, r1_rep );
+ fact_2 = NodeManager::currentNM()->mkNode(kind::MEMBER, t2, r2_rep );
+ if(r1_rep != product_term[0]) {
+ reason_1 = NodeManager::currentNM()->mkNode(kind::AND,reason_1, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r1_rep, product_term[0])));
+ }
+ if(t1 != t1_rep) {
+ reason_1 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND,reason_1, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1, t1_rep))));
+ }
+ if(r2_rep != product_term[1]) {
+ reason_2 = NodeManager::currentNM()->mkNode(kind::AND,reason_2, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r2_rep, product_term[1])));
+ }
+ if(t2 != t2_rep) {
+ reason_2 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND,reason_2, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t2, t2_rep))));
+ }
+ if(polarity) {
+ sendInfer(fact_1, reason_1, "product-split");
+ sendInfer(fact_2, reason_2, "product-split");
+ } else {
+ sendInfer(fact_1.negate(), reason_1, "product-split");
+ sendInfer(fact_2.negate(), reason_2, "product-split");
+ }
+ }
+
+ /* join-split rule: (a, b) IS_IN (X JOIN Y)
+ * --------------------------------------------
+ * exists z | (a, z) IS_IN X && (z, b) IS_IN Y
+ *
+ *
+ * join-compose rule: (a, b) IS_IN X (b, c) IS_IN Y NOT (t, u) IS_IN (X JOIN Y)
+ * -------------------------------------------------------------
+ * (a, c) IS_IN (X JOIN Y)
+ */
+ void TheorySetsRels::applyJoinRule(Node exp, Node join_term) {
+ Trace("rels-debug") << "\n[sets-rels] *********** Applying JOIN rule " << std::endl;
+
+ if(d_rel_nodes.find(join_term) == d_rel_nodes.end()) {
+ Trace("rels-debug") << "\n[sets-rels] Apply JOIN-COMPOSE rule on term: " << join_term
+ << " with explanation: " << exp << std::endl;
+
+ computeMembersForRelofMultArities(join_term);
+ d_rel_nodes.insert(join_term);
+ }
+
+ bool polarity = exp.getKind() != kind::NOT;
+ Node atom = polarity ? exp : exp[0];
+ Node r1_rep = getRepresentative(join_term[0]);
+ Node r2_rep = getRepresentative(join_term[1]);
+
+ if(polarity) {
+ Trace("rels-debug") << "\n[sets-rels] Apply JOIN-SPLIT rule on term: " << join_term
+ << " with explanation: " << exp << std::endl;
+
+ std::vector<Node> r1_element;
+ std::vector<Node> r2_element;
+ NodeManager *nm = NodeManager::currentNM();
+ TypeNode shared_type = r2_rep.getType().getSetElementType().getTupleTypes()[0];
+ Node shared_x = nm->mkSkolem("sde_", shared_type);
+ Datatype dt = r1_rep.getType().getSetElementType().getDatatype();
+ unsigned int i = 0;
+ unsigned int s1_len = r1_rep.getType().getSetElementType().getTupleLength();
+ unsigned int tup_len = join_term.getType().getSetElementType().getTupleLength();
+
+ r1_element.push_back(Node::fromExpr(dt[0].getConstructor()));
+ for(; i < s1_len-1; ++i) {
+ r1_element.push_back(RelsUtils::nthElementOfTuple(atom[0], i));
+ }
+ r1_element.push_back(shared_x);
+ dt = r2_rep.getType().getSetElementType().getDatatype();
+ r2_element.push_back(Node::fromExpr(dt[0].getConstructor()));
+ r2_element.push_back(shared_x);
+ for(; i < tup_len; ++i) {
+ r2_element.push_back(RelsUtils::nthElementOfTuple(atom[0], i));
+ }
+
+ Node t1 = nm->mkNode(kind::APPLY_CONSTRUCTOR, r1_element);
+ Node t2 = nm->mkNode(kind::APPLY_CONSTRUCTOR, r2_element);
+
+ computeTupleReps(t1);
+ computeTupleReps(t2);
+
+ std::vector<Node> elements = d_membership_trie[r1_rep].findTerms(d_tuple_reps[t1]);
+
+ for(unsigned int j = 0; j < elements.size(); j++) {
+ std::vector<Node> new_tup;
+ new_tup.push_back(elements[j]);
+ new_tup.insert(new_tup.end(), d_tuple_reps[t2].begin()+1, d_tuple_reps[t2].end());
+ if(d_membership_trie[r2_rep].existsTerm(new_tup) != Node::null()) {
+ return;
+ }
+ }
+
+ Node fact;
+ Node reason = atom[1] == join_term ? exp : NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,atom[1], join_term)));
+ Node reasons = reason;
+
+ fact = NodeManager::currentNM()->mkNode(kind::MEMBER,t1, r1_rep);
+ if(r1_rep != join_term[0]) {
+ reasons = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r1_rep, join_term[0]))));
+ }
+ Trace("rels-debug") << "\n[sets-rels] After applying JOIN-split rule, generate a fact : " << fact
+ << " with explanation: " << reasons << std::endl;
+ sendInfer(fact, reasons, "join-split");
+ reasons = reason;
+ fact = NodeManager::currentNM()->mkNode(kind::MEMBER,t2, r2_rep);
+ if(r2_rep != join_term[1]) {
+ reasons = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r2_rep, join_term[1]))));
+ }
+ Trace("rels-debug") << "[sets-rels] After applying JOIN-split rule, generate a fact : " << fact
+ << " with explanation: " << reasons << std::endl;
+ sendInfer(fact, reasons, "join-split");
+ makeSharedTerm(shared_x);
+ }
+ }
+
+ /*
+ * transpose-occur rule: [NOT] (a, b) IS_IN X (TRANSPOSE X) occurs
+ * -------------------------------------------------------
+ * [NOT] (b, a) IS_IN (TRANSPOSE X)
+ *
+ * transpose-reverse rule: [NOT] (a, b) IS_IN (TRANSPOSE X)
+ * ------------------------------------------------
+ * [NOT] (b, a) IS_IN X
+ *
+ * Not implemented yet!
+ * transpose-equal rule: [NOT] (TRANSPOSE X) = (TRANSPOSE Y)
+ * -----------------------------------------------
+ * [NOT] (X = Y)
+ */
+ void TheorySetsRels::applyTransposeRule(Node exp, Node tp_term, Node more_reason, bool tp_occur) {
+ Trace("rels-debug") << "\n[sets-rels] *********** Applying TRANSPOSE rule on term " << tp_term << std::endl;
+
+ bool polarity = exp.getKind() != kind::NOT;
+ Node atom = polarity ? exp : exp[0];
+ Node reversedTuple = getRepresentative(RelsUtils::reverseTuple(atom[0]));
+
+ if(tp_occur) {
+ Trace("rels-debug") << "\n[sets-rels] Apply TRANSPOSE-OCCUR rule on term: " << tp_term
+ << " with explanation: " << exp << std::endl;
+
+ Node fact = polarity ? NodeManager::currentNM()->mkNode(kind::MEMBER,reversedTuple, tp_term) : NodeManager::currentNM()->mkNode(kind::MEMBER,reversedTuple, tp_term).negate();
+ sendInfer(fact, more_reason == Node::null()?exp:NodeManager::currentNM()->mkNode(kind::AND,exp, more_reason), "transpose-occur");
+ return;
+ }
+
+ Node tp_t0_rep = getRepresentative(tp_term[0]);
+ Node reason = atom[1] == tp_term ? exp : Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND,exp, NodeManager::currentNM()->mkNode(kind::EQUAL,atom[1], tp_term)));
+ Node fact = NodeManager::currentNM()->mkNode(kind::MEMBER,reversedTuple, tp_t0_rep);
+
+ if(!polarity) {
+ fact = fact.negate();
+ }
+ sendInfer(fact, reason, "transpose-rule");
+ }
+
+
+ void TheorySetsRels::finalizeTCInference() {
+ Trace("rels-tc") << "[sets-rels] ****** Finalizing transitive closure inferences!" << std::endl;
+ std::map<Node, Node>::iterator map_it = d_tc_rep_term.begin();
+
+ while( map_it != d_tc_rep_term.end() ) {
+ Trace("rels-tc") << "[sets-rels] Start building the TC graph for " << map_it->first << std::endl;
+
+ std::map< Node, std::hash_set<Node, NodeHashFunction> > d_tc_graph = constructTCGraph(getRepresentative(map_it->second[0]), map_it->first, map_it->second);
+ inferTC(map_it->first, d_tc_graph);
+ map_it++;
+ }
+ }
+
+ void TheorySetsRels::inferTC(Node tc_rep, std::map< Node, std::hash_set< Node, NodeHashFunction > >& tc_graph) {
+ Trace("rels-tc") << "[sets-rels] Infer TC lemma from tc_graph of " << tc_rep << std::endl;
+
+ for(TC_PAIR_IT pair_set_it = tc_graph.begin(); pair_set_it != tc_graph.end(); pair_set_it++) {
+ for(std::hash_set< Node, NodeHashFunction >::iterator set_it = pair_set_it->second.begin();
+ set_it != pair_set_it->second.end(); set_it++) {
+ std::hash_set<Node, NodeHashFunction> elements;
+ Node pair = constructPair(tc_rep, pair_set_it->first, *set_it);
+ Node exp = findMemExp(tc_rep, pair);
+
+ if(d_membership_tc_exp_cache.find(tc_rep) != d_membership_tc_exp_cache.end()) {
+ exp = NodeManager::currentNM()->mkNode(kind::AND,d_membership_tc_exp_cache[tc_rep], exp);
+ }
+ Assert(!exp.isNull());
+ elements.insert(pair_set_it->first);
+ inferTC( exp, tc_rep, tc_graph, pair_set_it->first, *set_it, elements );
+ }
+ }
+ }
+
+ void TheorySetsRels::inferTC( Node exp, Node tc_rep, std::map< Node, std::hash_set< Node, NodeHashFunction > >& tc_graph,
+ Node start_node, Node cur_node, std::hash_set< Node, NodeHashFunction >& traversed ) {
+ Node pair = constructPair(tc_rep, start_node, cur_node);
+ MEM_IT mem_it = d_membership_db.find(tc_rep);
+
+ if(mem_it != d_membership_db.end()) {
+ if(std::find(mem_it->second.begin(), mem_it->second.end(), pair) == mem_it->second.end()) {
+ Trace("rels-tc") << "[sets-rels] Infered a TC lemma = " << NodeManager::currentNM()->mkNode(kind::MEMBER,pair, tc_rep) << " by Transitivity"
+ << " with explanation = " << Rewriter::rewrite(exp) << std::endl;
+ sendLemma( NodeManager::currentNM()->mkNode(kind::MEMBER,pair, tc_rep), Rewriter::rewrite(exp), "Transitivity" );
+ }
+ } else {
+ Trace("rels-tc") << "[sets-rels] Infered a TC lemma = " << NodeManager::currentNM()->mkNode(kind::MEMBER,pair, tc_rep) << " by Transitivity"
+ << " with explanation = " << Rewriter::rewrite(exp) << std::endl;
+ sendLemma( NodeManager::currentNM()->mkNode(kind::MEMBER,pair, tc_rep), Rewriter::rewrite(exp), "Transitivity" );
+ }
+ // check if cur_node has been traversed or not
+ if(traversed.find(cur_node) != traversed.end()) {
+ return;
+ }
+ traversed.insert(cur_node);
+
+ Node reason = exp;
+ TC_PAIR_IT cur_set = tc_graph.find(cur_node);
+
+ if(cur_set != tc_graph.end()) {
+ for(std::hash_set< Node, NodeHashFunction >::iterator set_it = cur_set->second.begin();
+ set_it != cur_set->second.end(); set_it++) {
+ Node new_pair = constructPair( tc_rep, cur_node, *set_it );
+ Assert(!reason.isNull());
+ inferTC( NodeManager::currentNM()->mkNode(kind::AND, findMemExp(tc_rep, new_pair), reason ), tc_rep, tc_graph, start_node, *set_it, traversed );
+ }
+ }
+ }
+
+ // Bottom-up fashion to compute relations with more than 1 arity
+ void TheorySetsRels::computeMembersForRelofMultArities(Node n) {
+ Trace("rels-debug") << "\n[sets-rels] computeJoinOrProductRelations for relation " << n << std::endl;
+ switch(n[0].getKind()) {
+ case kind::TRANSPOSE:
+ case kind::TCLOSURE:
+ computeMembersForUnaryRel(n[0]);
+ break;
+ case kind::JOIN:
+ case kind::PRODUCT:
+ computeMembersForRelofMultArities(n[0]);
+ break;
+ default:
+ break;
+ }
+
+ switch(n[1].getKind()) {
+ case kind::TRANSPOSE:
+ computeMembersForUnaryRel(n[1]);
+ break;
+ case kind::JOIN:
+ case kind::PRODUCT:
+ computeMembersForRelofMultArities(n[1]);
+ break;
+ default:
+ break;
+ }
+
+ if(d_membership_db.find(getRepresentative(n[0])) == d_membership_db.end() ||
+ d_membership_db.find(getRepresentative(n[1])) == d_membership_db.end())
+ return;
+ composeTupleMemForRel(n);
+ }
+
+ // Bottom-up fashion to compute unary relation
+ void TheorySetsRels::computeMembersForUnaryRel(Node n) {
+ switch(n[0].getKind()) {
+ case kind::TRANSPOSE:
+ case kind::TCLOSURE:
+ computeMembersForUnaryRel(n[0]);
+ break;
+ case kind::JOIN:
+ case kind::PRODUCT:
+ computeMembersForRelofMultArities(n[0]);
+ break;
+ default:
+ break;
+ }
+
+ if(d_membership_db.find(getRepresentative(n[0])) == d_membership_db.end())
+ return;
+
+ Node n_rep = getRepresentative(n);
+ Node n0_rep = getRepresentative(n[0]);
+ std::vector<Node> tuples = d_membership_db[n0_rep];
+ std::vector<Node> exps = d_membership_exp_db[n0_rep];
+ Assert(tuples.size() == exps.size());
+ for(unsigned int i = 0; i < tuples.size(); i++) {
+ Node reason = exps[i][1] == n0_rep ? exps[i] : NodeManager::currentNM()->mkNode(kind::AND,exps[i], NodeManager::currentNM()->mkNode(kind::EQUAL,exps[i][1], n0_rep));
+ if( n.getKind() == kind::TRANSPOSE) {
+ Node rev_tup = getRepresentative(RelsUtils::reverseTuple(tuples[i]));
+ Node fact = NodeManager::currentNM()->mkNode(kind::MEMBER,rev_tup, n_rep);
+
+ if(holds(fact)) {
+ Trace("rels-debug") << "[sets-rels] New fact: " << fact << " already holds! Skip..." << std::endl;
+ } else {
+ sendInfer(fact, Rewriter::rewrite(reason), "transpose-rule");
+ }
+ } else if( n.getKind() == kind::TCLOSURE ) {
+
+ }
+ }
+ }
+
+ /*
+ * Explicitly compose the join or product relations of r1 and r2
+ * e.g. If (a, b) in X and (b, c) in Y, (a, c) in (X JOIN Y)
+ *
+ */
+ void TheorySetsRels::composeTupleMemForRel( Node n ) {
+ Node r1 = n[0];
+ Node r2 = n[1];
+ Node r1_rep = getRepresentative(r1);
+ Node r2_rep = getRepresentative(r2);
+ NodeManager* nm = NodeManager::currentNM();
+
+ Trace("rels-debug") << "[sets-rels] start composing tuples in relations "
+ << r1 << " and " << r2 << std::endl;
+
+ if(d_membership_db.find(r1_rep) == d_membership_db.end() ||
+ d_membership_db.find(r2_rep) == d_membership_db.end())
+ return;
+
+ std::vector<Node> new_tups;
+ std::vector<Node> new_exps;
+ std::vector<Node> r1_elements = d_membership_db[r1_rep];
+ std::vector<Node> r2_elements = d_membership_db[r2_rep];
+ std::vector<Node> r1_exps = d_membership_exp_db[r1_rep];
+ std::vector<Node> r2_exps = d_membership_exp_db[r2_rep];
+
+ Node n_rep = getRepresentative(n);
+ unsigned int t1_len = r1_elements.front().getType().getTupleLength();
+ unsigned int t2_len = r2_elements.front().getType().getTupleLength();
+
+ for(unsigned int i = 0; i < r1_elements.size(); i++) {
+ for(unsigned int j = 0; j < r2_elements.size(); j++) {
+ std::vector<Node> composed_tuple;
+ TypeNode tn = n.getType().getSetElementType();
+ Node r1_rmost = RelsUtils::nthElementOfTuple(r1_elements[i], t1_len-1);
+ Node r2_lmost = RelsUtils::nthElementOfTuple(r2_elements[j], 0);
+ composed_tuple.push_back(Node::fromExpr(tn.getDatatype()[0].getConstructor()));
+
+ if((areEqual(r1_rmost, r2_lmost) && n.getKind() == kind::JOIN) ||
+ n.getKind() == kind::PRODUCT) {
+ bool isProduct = n.getKind() == kind::PRODUCT;
+ unsigned int k = 0;
+ unsigned int l = 1;
+
+ for(; k < t1_len - 1; ++k) {
+ composed_tuple.push_back(RelsUtils::nthElementOfTuple(r1_elements[i], k));
+ }
+ if(isProduct) {
+ composed_tuple.push_back(RelsUtils::nthElementOfTuple(r1_elements[i], k));
+ composed_tuple.push_back(RelsUtils::nthElementOfTuple(r2_elements[j], 0));
+ }
+ for(; l < t2_len; ++l) {
+ composed_tuple.push_back(RelsUtils::nthElementOfTuple(r2_elements[j], l));
+ }
+ Node composed_tuple_rep = getRepresentative(nm->mkNode(kind::APPLY_CONSTRUCTOR, composed_tuple));
+ Node fact = NodeManager::currentNM()->mkNode(kind::MEMBER,composed_tuple_rep, n_rep);
+
+ if(holds(fact)) {
+ Trace("rels-debug") << "[sets-rels] New fact: " << fact << " already holds! Skip..." << std::endl;
+ } else {
+ std::vector<Node> reasons;
+ reasons.push_back(explain(r1_exps[i]));
+ reasons.push_back(explain(r2_exps[j]));
+ if(n != n_rep) {
+ reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL, n_rep, n)));
+ }
+ if(r1_exps[i].getKind() == kind::MEMBER && r1_exps[i][0] != r1_elements[i]) {
+ reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r1_elements[i], r1_exps[i][0])));
+ }
+ if(r2_exps[j].getKind() == kind::MEMBER && r2_exps[j][0] != r2_elements[j]) {
+ reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r2_elements[j], r2_exps[j][0])));
+ }
+ if(r1_exps[i].getKind() == kind::MEMBER && r1_exps[i][1] != r1_rep) {
+ reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r1_exps[i][1], r1_rep)));
+ }
+ if(r2_exps[j].getKind() == kind::MEMBER && r2_exps[j][1] != r2_rep) {
+ reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r2_exps[j][1], r2_rep)));
+ }
+
+ if(!isProduct) {
+ if(r1_rmost != r2_lmost) {
+ reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r1_rmost, r2_lmost)));
+ }
+ }
+ if(r1 != r1_rep) {
+ reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r1, r1_rep)));
+ }
+ if(r2 != r2_rep) {
+ reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r2, r2_rep)));
+ }
+
+ Node reason = Rewriter::rewrite(nm->mkNode(kind::AND, reasons));
+ if(isProduct) {
+ sendInfer( fact, reason, "product-compose" );
+ } else {
+ sendInfer( fact, reason, "join-compose" );
+ }
+
+ Trace("rels-debug") << "[sets-rels] Compose tuples: " << r1_elements[i]
+ << " and " << r2_elements[j]
+ << "\n Produce a new fact: " << fact
+ << "\n Reason: " << reason<< std::endl;
+ }
+ }
+ }
+ }
+ Trace("rels-debug") << "[sets-rels] Done with composing tuples !" << std::endl;
+ }
+
+ void TheorySetsRels::doPendingLemmas() {
+ if( !(*d_conflict) ){
+ if ( (!d_lemma_cache.empty() || !d_pending_facts.empty()) ) {
+ for( unsigned i=0; i < d_lemma_cache.size(); i++ ){
+ Assert(d_lemma_cache[i].getKind() == kind::IMPLIES);
+ if(holds( d_lemma_cache[i][1] )) {
+ Trace("rels-lemma") << "[sets-rels-lemma-skip] Skip an already held lemma: "
+ << d_lemma_cache[i]<< std::endl;
+ continue;
+ }
+ Trace("rels-lemma") << "[sets-rels-lemma] Send out a lemma : "
+ << d_lemma_cache[i] << std::endl;
+ d_sets_theory.d_out->lemma( d_lemma_cache[i] );
+ }
+ for( std::map<Node, Node>::iterator child_it = d_pending_facts.begin();
+ child_it != d_pending_facts.end(); child_it++ ) {
+ if(holds(child_it->first)) {
+ Trace("rels-lemma") << "[sets-rels-fact-lemma-skip] Skip an already held fact,: "
+ << child_it->first << std::endl;
+ continue;
+ }
+ Trace("rels-lemma") << "[sets-rels-fact-lemma] Send out a fact as lemma : "
+ << child_it->first << " with reason " << child_it->second << std::endl;
+ d_sets_theory.d_out->lemma(NodeManager::currentNM()->mkNode(kind::IMPLIES, child_it->second, child_it->first));
+ }
+ }
+ doTCLemmas();
+ }
+
+ d_arg_rep_tp_terms.clear();
+ d_tc_membership_db.clear();
+ d_rel_nodes.clear();
+ d_pending_facts.clear();
+ d_membership_constraints_cache.clear();
+ d_tc_r_graph.clear();
+ d_membership_tc_exp_cache.clear();
+ d_membership_exp_cache.clear();
+ d_membership_db.clear();
+ d_membership_exp_db.clear();
+ d_terms_cache.clear();
+ d_lemma_cache.clear();
+ d_membership_trie.clear();
+ d_tuple_reps.clear();
+ d_id_node.clear();
+ d_node_id.clear();
+ d_tc_rep_term.clear();
+ }
+
+ void TheorySetsRels::doTCLemmas() {
+ Trace("rels-debug") << "[sets-rels] Start processing TC lemmas .......... " << std::endl;
+ std::map< Node, std::hash_set< Node, NodeHashFunction > >::iterator mem_it = d_tc_membership_db.begin();
+
+ while(mem_it != d_tc_membership_db.end()) {
+ Node tc_rep = getRepresentative(mem_it->first);
+ Node tc_r_rep = getRepresentative(mem_it->first[0]);
+ std::hash_set< Node, NodeHashFunction >::iterator set_it = mem_it->second.begin();
+
+ while(set_it != mem_it->second.end()) {
+ std::hash_set<Node, NodeHashFunction> hasSeen;
+ bool isReachable = false;
+ Node fst = RelsUtils::nthElementOfTuple(*set_it, 0);
+ Node snd = RelsUtils::nthElementOfTuple(*set_it, 1);
+ Node fst_rep = getRepresentative(fst);
+ Node snd_rep = getRepresentative(snd);
+ TC_IT tc_graph_it = d_tc_r_graph.find(tc_rep);
+
+ // the tc_graph of TC(r) is built based on the members of r and TC(r)????????
+ isTCReachable(fst_rep, snd_rep, hasSeen, tc_graph_it->second, isReachable);
+ Trace("rels-tc") << "tuple = " << *set_it << " with rep = (" << fst_rep << ", " << snd_rep << ") "
+ << " isReachable? = " << isReachable << std::endl;
+ if((tc_graph_it != d_tc_r_graph.end() && !isReachable) ||
+ (tc_graph_it == d_tc_r_graph.end())) {
+ Node reason = explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*set_it, mem_it->first));
+ Node sk_1 = NodeManager::currentNM()->mkSkolem("sde", fst_rep.getType());
+ Node sk_2 = NodeManager::currentNM()->mkSkolem("sde", snd_rep.getType());
+ Node mem_of_r = NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::constructPair(tc_r_rep, fst_rep, snd_rep), tc_r_rep);
+ Node sk_eq = NodeManager::currentNM()->mkNode(kind::EQUAL,sk_1, sk_2);
+
+ if(fst_rep != fst) {
+ reason = NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,fst_rep, fst)));
+ }
+ if(snd_rep != snd) {
+ reason = NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,snd_rep, snd)));
+ }
+ if(tc_r_rep != mem_it->first[0]) {
+ reason = NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_r_rep, mem_it->first[0])));
+ }
+ if(tc_rep != mem_it->first) {
+ reason = NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_rep, mem_it->first)));
+ }
+
+ Node tc_lemma = NodeManager::currentNM()->mkNode(kind::IMPLIES, reason,
+ NodeManager::currentNM()->mkNode(kind::OR,mem_of_r,
+ (NodeManager::currentNM()->mkNode(kind::AND,NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::constructPair(tc_r_rep, fst_rep, sk_1), tc_r_rep),
+ (NodeManager::currentNM()->mkNode(kind::AND,NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::constructPair(tc_r_rep, sk_2, snd_rep), tc_r_rep),
+ (NodeManager::currentNM()->mkNode(kind::OR,sk_eq, NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::constructPair(tc_rep, sk_1, sk_2), tc_rep)))))))));
+ Trace("rels-lemma") << "[sets-rels-lemma] Send out a TC lemma : "
+ << tc_lemma << std::endl;
+ d_sets_theory.d_out->lemma(tc_lemma);
+ d_sets_theory.d_out->requirePhase(Rewriter::rewrite(mem_of_r), true);
+ d_sets_theory.d_out->requirePhase(Rewriter::rewrite(sk_eq), true);
+ }
+ set_it++;
+ }
+ mem_it++;
+ }
+ }
+
+ void TheorySetsRels::isTCReachable(Node start, Node dest, std::hash_set<Node, NodeHashFunction>& hasSeen,
+ std::map< Node, std::hash_set< Node, NodeHashFunction > >& tc_graph, bool& isReachable) {
+ if(hasSeen.find(start) == hasSeen.end()) {
+ hasSeen.insert(start);
+ }
+
+ TC_PAIR_IT pair_set_it = tc_graph.find(start);
+
+ if(pair_set_it != tc_graph.end()) {
+ if(pair_set_it->second.find(dest) != pair_set_it->second.end()) {
+ isReachable = true;
+ return;
+ } else {
+ std::hash_set< Node, NodeHashFunction >::iterator set_it = pair_set_it->second.begin();
+
+ while(set_it != pair_set_it->second.end()) {
+ // need to check if *set_it has been looked already
+ if(hasSeen.find(*set_it) == hasSeen.end()) {
+ isTCReachable(*set_it, dest, hasSeen, tc_graph, isReachable);
+ }
+ set_it++;
+ }
+ }
+ }
+ }
+
+ void TheorySetsRels::sendLemma(Node conc, Node ant, const char * c) {
+ Node lemma = NodeManager::currentNM()->mkNode(kind::IMPLIES, ant, conc);
+ d_lemma_cache.push_back(lemma);
+ d_lemma.insert(lemma);
+ }
+
+ void TheorySetsRels::sendInfer( Node fact, Node exp, const char * c ) {
+ d_pending_facts[fact] = exp;
+ d_infer.push_back( fact );
+ d_infer_exp.push_back( exp );
+ }
+
+ void TheorySetsRels::assertMembership( Node fact, Node reason, bool polarity ) {
+ d_eqEngine->assertPredicate( fact, polarity, reason );
+ }
+
+ Node TheorySetsRels::getRepresentative( Node t ) {
+ if( d_eqEngine->hasTerm( t ) ){
+ return d_eqEngine->getRepresentative( t );
+ }else{
+ return t;
+ }
+ }
+
+ bool TheorySetsRels::hasTerm( Node a ){
+ return d_eqEngine->hasTerm( a );
+ }
+
+ bool TheorySetsRels::areEqual( Node a, Node b ){
+ Assert(a.getType() == b.getType());
+ Trace("rels-eq") << "[sets-rels]**** checking equality between " << a << " and " << b << std::endl;
+ if(a == b) {
+ return true;
+ } else if( hasTerm( a ) && hasTerm( b ) ){
+ return d_eqEngine->areEqual( a, b );
+ } else if(a.getType().isTuple()) {
+ bool equal = true;
+ for(unsigned int i = 0; i < a.getType().getTupleLength(); i++) {
+ equal = equal && areEqual(RelsUtils::nthElementOfTuple(a, i), RelsUtils::nthElementOfTuple(b, i));
+ }
+ return equal;
+ } else if(!a.getType().isBoolean()){
+ makeSharedTerm(a);
+ makeSharedTerm(b);
+ }
+ return false;
+ }
+
+ /*
+ * Make sure duplicate members are not added in map
+ */
+ bool TheorySetsRels::safelyAddToMap(std::map< Node, std::vector<Node> >& map, Node rel_rep, Node member) {
+ std::map< Node, std::vector< Node > >::iterator mem_it = map.find(rel_rep);
+ if(mem_it == map.end()) {
+ std::vector<Node> members;
+ members.push_back(member);
+ map[rel_rep] = members;
+ return true;
+ } else {
+ std::vector<Node>::iterator mems = mem_it->second.begin();
+ while(mems != mem_it->second.end()) {
+ if(areEqual(*mems, member)) {
+ return false;
+ }
+ mems++;
+ }
+ map[rel_rep].push_back(member);
+ return true;
+ }
+ return false;
+ }
+
+ void TheorySetsRels::addToMap(std::map< Node, std::vector<Node> >& map, Node rel_rep, Node member) {
+ if(map.find(rel_rep) == map.end()) {
+ std::vector<Node> members;
+ members.push_back(member);
+ map[rel_rep] = members;
+ } else {
+ map[rel_rep].push_back(member);
+ }
+ }
+
+ inline Node TheorySetsRels::getReason(Node tc_rep, Node tc_term, Node tc_r_rep, Node tc_r) {
+ if(tc_term != tc_rep) {
+ Node reason = explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_term, tc_rep));
+ if(tc_term[0] != tc_r_rep) {
+ return NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_term[0], tc_r_rep)));
+ }
+ }
+ return Node::null();
+ }
+
+ // tuple might be a member of tc_rep; or it might be a member of rels or tc_terms such that
+ // tc_terms are transitive closure of rels and are modulo equal to tc_rep
+ Node TheorySetsRels::findMemExp(Node tc_rep, Node pair) {
+ Trace("rels-exp") << "TheorySetsRels::findMemExp ( tc_rep = " << tc_rep << ", pair = " << pair << ")" << std::endl;
+ Node fst = RelsUtils::nthElementOfTuple(pair, 0);
+ Node snd = RelsUtils::nthElementOfTuple(pair, 1);
+ std::vector<Node> tc_terms = d_terms_cache.find(tc_rep)->second[kind::TCLOSURE];
+
+ Assert(tc_terms.size() > 0);
+ for(unsigned int i = 0; i < tc_terms.size(); i++) {
+ Node tc_term = tc_terms[i];
+ Node tc_r_rep = getRepresentative(tc_term[0]);
+
+ Trace("rels-exp") << "TheorySetsRels::findMemExp ( r_rep = " << tc_r_rep << ", pair = " << pair << ")" << std::endl;
+ std::map< Node, std::vector< Node > >::iterator tc_r_mems = d_membership_db.find(tc_r_rep);
+ if(tc_r_mems != d_membership_db.end()) {
+ for(unsigned int i = 0; i < tc_r_mems->second.size(); i++) {
+ Node fst_mem = RelsUtils::nthElementOfTuple(tc_r_mems->second[i], 0);
+ Node snd_mem = RelsUtils::nthElementOfTuple(tc_r_mems->second[i], 1);
+
+ if(areEqual(fst_mem, fst) && areEqual(snd_mem, snd)) {
+ Node exp = NodeManager::currentNM()->mkNode(kind::MEMBER,tc_r_mems->second[i], tc_r_mems->first);
+
+ if(tc_r_rep != tc_term[0]) {
+ exp = explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_r_rep, tc_term[0]));
+ }
+ if(tc_rep != tc_term) {
+ exp = NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_rep, tc_term)));
+ }
+ if(tc_r_mems->second[i] != pair) {
+ if(fst_mem != fst) {
+ exp = NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,fst_mem, fst)));
+ }
+ if(snd_mem != snd) {
+ exp = NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,snd_mem, snd)));
+ }
+ exp = NodeManager::currentNM()->mkNode(kind::AND,exp, NodeManager::currentNM()->mkNode(kind::EQUAL,tc_r_mems->second[i], pair));
+ }
+ return Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND,exp, explain(d_membership_exp_db[tc_r_rep][i])));
+ }
+ }
+ }
+
+ Node tc_term_rep = getRepresentative(tc_terms[i]);
+ std::map< Node, std::vector< Node > >::iterator tc_t_mems = d_membership_db.find(tc_term_rep);
+
+ if(tc_t_mems != d_membership_db.end()) {
+ for(unsigned int j = 0; j < tc_t_mems->second.size(); j++) {
+ Node fst_mem = RelsUtils::nthElementOfTuple(tc_t_mems->second[j], 0);
+ Node snd_mem = RelsUtils::nthElementOfTuple(tc_t_mems->second[j], 1);
+
+ if(areEqual(fst_mem, fst) && areEqual(snd_mem, snd)) {
+ Node exp = NodeManager::currentNM()->mkNode(kind::MEMBER,tc_t_mems->second[j], tc_t_mems->first);
+ if(tc_rep != tc_terms[i]) {
+ exp = NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_rep, tc_terms[i])));
+ }
+ if(tc_term_rep != tc_terms[i]) {
+ exp = NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_term_rep, tc_terms[i])));
+ }
+ if(tc_t_mems->second[j] != pair) {
+ if(fst_mem != fst) {
+ exp = NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,fst_mem, fst)));
+ }
+ if(snd_mem != snd) {
+ exp = NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,snd_mem, snd)));
+ }
+ exp = NodeManager::currentNM()->mkNode(kind::AND,exp, NodeManager::currentNM()->mkNode(kind::EQUAL,tc_t_mems->second[j], pair));
+ }
+ return Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND,exp, explain(d_membership_exp_db[tc_term_rep][j])));
+ }
+ }
+ }
+ }
+ return Node::null();
+ }
+
+ void TheorySetsRels::addSharedTerm( TNode n ) {
+ Trace("rels-debug") << "[sets-rels] Add a shared term: " << n << std::endl;
+ d_sets_theory.addSharedTerm(n);
+ d_eqEngine->addTriggerTerm(n, THEORY_SETS);
+ }
+
+ void TheorySetsRels::makeSharedTerm( Node n ) {
+ Trace("rels-share") << " [sets-rels] making shared term " << n << std::endl;
+ if(d_shared_terms.find(n) == d_shared_terms.end()) {
+ Node skolem = NodeManager::currentNM()->mkSkolem( "sts", NodeManager::currentNM()->mkSetType( n.getType() ) );
+ sendLemma(skolem.eqNode(NodeManager::currentNM()->mkNode(kind::SINGLETON,n)), d_trueNode, "share-term");
+ d_shared_terms.insert(n);
+ }
+ }
+
+ bool TheorySetsRels::holds(Node node) {
+ bool polarity = node.getKind() != kind::NOT;
+ Node atom = polarity ? node : node[0];
+ return d_sets_theory.isEntailed( atom, polarity );
+ }
+
+ /*
+ * For each tuple n, we store a mapping between n and a list of its elements representatives
+ * in d_tuple_reps. This would later be used for applying JOIN operator.
+ */
+ void TheorySetsRels::computeTupleReps( Node n ) {
+ if( d_tuple_reps.find( n ) == d_tuple_reps.end() ){
+ for( unsigned i = 0; i < n.getType().getTupleLength(); i++ ){
+ d_tuple_reps[n].push_back( getRepresentative( RelsUtils::nthElementOfTuple(n, i) ) );
+ }
+ }
+ }
+
+ inline void TheorySetsRels::addToMembershipDB(Node rel, Node member, Node reasons) {
+ addToMap(d_membership_db, rel, member);
+ addToMap(d_membership_exp_db, rel, reasons);
+ computeTupleReps(member);
+ d_membership_trie[rel].addTerm(member, d_tuple_reps[member]);
+ }
+
+ inline Node TheorySetsRels::constructPair(Node tc_rep, Node a, Node b) {
+ Datatype dt = tc_rep.getType().getSetElementType().getDatatype();
+ return NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, Node::fromExpr(dt[0].getConstructor()), a, b);
+ }
+
+ /*
+ * Node n[0] is a tuple variable, reduce n[0] to a concrete representation,
+ * which is (e1, ..., en) where e1, ... ,en are concrete elements of tuple n[0].
+ */
+ void TheorySetsRels::reduceTupleVar(Node n) {
+ if(d_symbolic_tuples.find(n) == d_symbolic_tuples.end()) {
+ Trace("rels-debug") << "Reduce tuple var: " << n[0] << " to concrete one " << " node = " << n << std::endl;
+ std::vector<Node> tuple_elements;
+ tuple_elements.push_back(Node::fromExpr((n[0].getType().getDatatype())[0].getConstructor()));
+ for(unsigned int i = 0; i < n[0].getType().getTupleLength(); i++) {
+ Node element = RelsUtils::nthElementOfTuple(n[0], i);
+ makeSharedTerm(element);
+ tuple_elements.push_back(element);
+ }
+ Node tuple_reduct = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, tuple_elements);
+ tuple_reduct = NodeManager::currentNM()->mkNode(kind::MEMBER,tuple_reduct, n[1]);
+ Node tuple_reduction_lemma = NodeManager::currentNM()->mkNode(kind::IFF, n, tuple_reduct);
+ sendLemma(tuple_reduction_lemma, d_trueNode, "tuple-reduction");
+ d_symbolic_tuples.insert(n);
+ }
+ }
+
+ TheorySetsRels::TheorySetsRels( context::Context* c,
+ context::UserContext* u,
+ eq::EqualityEngine* eq,
+ context::CDO<bool>* conflict,
+ TheorySets& d_set ):
+ d_vec_size(c),
+ d_eqEngine(eq),
+ d_conflict(conflict),
+ d_sets_theory(d_set),
+ d_trueNode(NodeManager::currentNM()->mkConst<bool>(true)),
+ d_falseNode(NodeManager::currentNM()->mkConst<bool>(false)),
+ d_pending_merge(c),
+ d_infer(c),
+ d_infer_exp(c),
+ d_lemma(u),
+ d_shared_terms(u)
+ {
+ d_eqEngine->addFunctionKind(kind::PRODUCT);
+ d_eqEngine->addFunctionKind(kind::JOIN);
+ d_eqEngine->addFunctionKind(kind::TRANSPOSE);
+ d_eqEngine->addFunctionKind(kind::TCLOSURE);
+ }
+
+ TheorySetsRels::~TheorySetsRels() {}
+
+ std::vector<Node> TupleTrie::findTerms( std::vector< Node >& reps, int argIndex ) {
+ std::vector<Node> nodes;
+ std::map< Node, TupleTrie >::iterator it;
+
+ if( argIndex==(int)reps.size()-1 ){
+ if(reps[argIndex].getKind() == kind::SKOLEM) {
+ it = d_data.begin();
+ while(it != d_data.end()) {
+ nodes.push_back(it->first);
+ it++;
+ }
+ }
+ return nodes;
+ }else{
+ it = d_data.find( reps[argIndex] );
+ if( it==d_data.end() ){
+ return nodes;
+ }else{
+ return it->second.findTerms( reps, argIndex+1 );
+ }
+ }
+ }
+
+ Node TupleTrie::existsTerm( std::vector< Node >& reps, int argIndex ) {
+ if( argIndex==(int)reps.size() ){
+ if( d_data.empty() ){
+ return Node::null();
+ }else{
+ return d_data.begin()->first;
+ }
+ }else{
+ std::map< Node, TupleTrie >::iterator it = d_data.find( reps[argIndex] );
+ if( it==d_data.end() ){
+ return Node::null();
+ }else{
+ return it->second.existsTerm( reps, argIndex+1 );
+ }
+ }
+ }
+
+ bool TupleTrie::addTerm( Node n, std::vector< Node >& reps, int argIndex ){
+ if( argIndex==(int)reps.size() ){
+ if( d_data.empty() ){
+ //store n in d_data (this should be interpretted as the "data" and not as a reference to a child)
+ d_data[n].clear();
+ return true;
+ }else{
+ return false;
+ }
+ }else{
+ return d_data[reps[argIndex]].addTerm( n, reps, argIndex+1 );
+ }
+ }
+
+ void TupleTrie::debugPrint( const char * c, Node n, unsigned depth ) {
+ for( std::map< Node, TupleTrie >::iterator it = d_data.begin(); it != d_data.end(); ++it ){
+ for( unsigned i=0; i<depth; i++ ){ Debug(c) << " "; }
+ Debug(c) << it->first << std::endl;
+ it->second.debugPrint( c, n, depth+1 );
+ }
+ }
+
+ Node TheorySetsRels::explain( Node literal )
+ {
+ Trace("rels-exp") << "[sets-rels] TheorySetsRels::explain(" << literal << ")"<< std::endl;
+ std::vector<TNode> assumptions;
+ bool polarity = literal.getKind() != kind::NOT;
+ TNode atom = polarity ? literal : literal[0];
+
+ if(atom.getKind() == kind::EQUAL || atom.getKind() == kind::IFF) {
+ d_eqEngine->explainEquality(atom[0], atom[1], polarity, assumptions);
+ } else if(atom.getKind() == kind::MEMBER) {
+ if( !d_eqEngine->hasTerm(atom)) {
+ d_eqEngine->addTerm(atom);
+ }
+ d_eqEngine->explainPredicate(atom, polarity, assumptions);
+ } else {
+ Trace("rels-exp") << "unhandled: " << literal << "; (" << atom << ", "
+ << polarity << "); kind" << atom.getKind() << std::endl;
+ Unhandled();
+ }
+ Trace("rels-exp") << "[sets-rels] ****** done with TheorySetsRels::explain(" << literal << ")"<< std::endl;
+ return mkAnd(assumptions);
+ }
+
+ TheorySetsRels::EqcInfo::EqcInfo( context::Context* c ) :
+ d_mem(c), d_not_mem(c), d_mem_exp(c), d_in(c), d_out(c),
+ d_tp(c), d_pt(c), d_join(c), d_tc(c) {}
+
+ void TheorySetsRels::eqNotifyNewClass( Node n ) {
+ Trace("rels-std") << "[sets-rels] eqNotifyNewClass:" << " t = " << n << std::endl;
+ if(isRel(n) && (n.getKind() == kind::TRANSPOSE ||
+ n.getKind() == kind::PRODUCT ||
+ n.getKind() == kind::JOIN ||
+ n.getKind() == kind::TCLOSURE)) {
+ getOrMakeEqcInfo( n, true );
+ }
+ }
+
+ // Create an integer id for tuple element
+ int TheorySetsRels::getOrMakeElementRepId(EqcInfo* ei, Node e_rep) {
+ Trace("rels-std") << "[sets-rels] getOrMakeElementRepId:" << " e_rep = " << e_rep << std::endl;
+ std::map< Node, int >::iterator nid_it = d_node_id.find(e_rep);
+
+ if( nid_it == d_node_id.end() ) {
+ if( d_eqEngine->hasTerm(e_rep) ) {
+ // it is possible that e's rep changes at this moment, thus we need to know the previous rep id of eqc of e
+ eq::EqClassIterator rep_eqc_i = eq::EqClassIterator( e_rep, d_eqEngine );
+ while( !rep_eqc_i.isFinished() ) {
+ std::map< Node, int >::iterator id_it = d_node_id.find(*rep_eqc_i);
+
+ if( id_it != d_node_id.end() ) {
+ d_id_node[id_it->second] = e_rep;
+ d_node_id[e_rep] = id_it->second;
+ return id_it->second;
+ }
+ rep_eqc_i++;
+ }
+ }
+ d_id_node[ei->counter] = e_rep;
+ d_node_id[e_rep] = ei->counter;
+ ei->counter++;
+ return ei->counter-1;
+ }
+ Trace("rels-std") << "[sets-rels] finish getOrMakeElementRepId:" << " e_rep = " << e_rep << std::endl;
+ return nid_it->second;
+ }
+
+ bool TheorySetsRels::insertIntoIdList(IdList& idList, int mem) {
+ IdList::const_iterator idListIt = idList.begin();
+ while(idListIt != idList.end()) {
+ if(*idListIt == mem) {
+ return false;
+ }
+ idListIt++;
+ }
+ idList.push_back(mem);
+ return true;
+ }
+
+ void TheorySetsRels::addTCMemAndSendInfer( EqcInfo* tc_ei, Node membership, Node exp, bool fromRel ) {
+ Trace("rels-std") << "[sets-rels] addTCMemAndSendInfer:" << " membership = " << membership << " from a relation? " << fromRel<< std::endl;
+
+ Node fst = RelsUtils::nthElementOfTuple(membership[0], 0);
+ Node snd = RelsUtils::nthElementOfTuple(membership[0], 1);
+ Node fst_rep = getRepresentative(fst);
+ Node snd_rep = getRepresentative(snd);
+ Node mem_rep = RelsUtils::constructPair(membership[1], fst_rep, snd_rep);
+
+ if(tc_ei->d_mem.find(mem_rep) != tc_ei->d_mem.end()) {
+ return;
+ }
+
+ int fst_rep_id = getOrMakeElementRepId( tc_ei, fst_rep );
+ int snd_rep_id = getOrMakeElementRepId( tc_ei, snd_rep );
+
+ std::hash_set<int> in_reachable;
+ std::hash_set<int> out_reachable;
+ collectReachableNodes(tc_ei->d_id_inIds, fst_rep_id, in_reachable);
+ collectReachableNodes(tc_ei->d_id_outIds, snd_rep_id, out_reachable);
+
+ // If fst_rep is inserted into in_lst successfully,
+ // save rep pair's exp and send out TC inference lemmas.
+ // Otherwise, mem's rep is already in the TC and return.
+ if( addId(tc_ei->d_id_inIds, snd_rep_id, fst_rep_id) ) {
+ Node reason = exp == Node::null() ? explain(membership) : exp;
+ if(!fromRel && tc_ei->d_tc.get() != membership[1]) {
+ reason = NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_ei->d_tc.get(), membership[1])));
+ }
+ if(fst != fst_rep) {
+ reason = NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,fst, fst_rep)));
+ }
+ if(snd != snd_rep) {
+ reason = NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,snd, snd_rep)));
+ }
+ tc_ei->d_mem_exp[mem_rep] = reason;
+ Trace("rels-std") << "Added member " << mem_rep << " for " << tc_ei->d_tc.get()<< " with reason = " << reason << std::endl;
+ tc_ei->d_mem.insert(mem_rep);
+ Trace("rels-std") << "Added in membership arrow for " << snd_rep << " from: " << fst_rep << std::endl;
+ } else {
+ // Nothing inserted into the eqc
+ return;
+ }
+ Trace("rels-std") << "Add out membership arrow for " << fst_rep << " to : " << snd_rep << std::endl;
+ addId(tc_ei->d_id_inIds, fst_rep_id, snd_rep_id);
+ sendTCInference(tc_ei, in_reachable, out_reachable, mem_rep, fst_rep, snd_rep, fst_rep_id, snd_rep_id);
+ }
+
+ Node TheorySetsRels::explainTCMem(EqcInfo* ei, Node pair, Node fst, Node snd) {
+ Trace("rels-tc") << "explainTCMem ############ pair = " << pair << std::endl;
+ if(ei->d_mem_exp.find(pair) != ei->d_mem_exp.end()) {
+ return (*ei->d_mem_exp.find(pair)).second;
+ }
+ NodeMap::iterator mem_exp_it = ei->d_mem_exp.begin();
+ while(mem_exp_it != ei->d_mem_exp.end()) {
+ Node tuple = (*mem_exp_it).first;
+ Node fst_e = RelsUtils::nthElementOfTuple(tuple, 0);
+ Node snd_e = RelsUtils::nthElementOfTuple(tuple, 1);
+ if(areEqual(fst, fst_e) && areEqual(snd, snd_e)) {
+ return NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,snd, snd_e)), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,fst, fst_e)), (*mem_exp_it).second));
+ }
+ ++mem_exp_it;
+ }
+ if(!ei->d_tc.get().isNull()) {
+ Node rel_rep = getRepresentative(ei->d_tc.get()[0]);
+ EqcInfo* rel_ei = getOrMakeEqcInfo(rel_rep);
+ if(rel_ei != NULL) {
+ NodeMap::iterator rel_mem_exp_it = rel_ei->d_mem_exp.begin();
+ while(rel_mem_exp_it != rel_ei->d_mem_exp.end()) {
+ Node exp = rel_rep == ei->d_tc.get()[0] ? d_trueNode : explain(NodeManager::currentNM()->mkNode(kind::EQUAL,rel_rep, ei->d_tc.get()[0]));
+ Node tuple = (*rel_mem_exp_it).first;
+ Node fst_e = RelsUtils::nthElementOfTuple(tuple, 0);
+ Node snd_e = RelsUtils::nthElementOfTuple(tuple, 1);
+ if(areEqual(fst, fst_e) && areEqual(snd, snd_e)) {
+ return NodeManager::currentNM()->mkNode(kind::AND,exp, NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,snd, snd_e)), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,fst, fst_e)), (*rel_mem_exp_it).second)));
+ }
+ ++rel_mem_exp_it;
+ }
+ }
+ }
+ return Node::null();
+ }
+
+ void TheorySetsRels::sendTCInference(EqcInfo* tc_ei, std::hash_set<int> in_reachable, std::hash_set<int> out_reachable, Node mem_rep, Node fst_rep, Node snd_rep, int id1, int id2) {
+ Trace("rels-std") << "Start making TC inference after adding a member " << mem_rep << " to " << tc_ei->d_tc.get() << std::endl;
+
+ Node exp = explainTCMem(tc_ei, mem_rep, fst_rep, snd_rep);
+ Assert(!exp.isNull());
+ Node tc_lemma = NodeManager::currentNM()->mkNode(kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER,mem_rep, tc_ei->d_tc.get()));
+ d_pending_merge.push_back(tc_lemma);
+ d_lemma.insert(tc_lemma);
+ std::hash_set<int>::iterator in_reachable_it = in_reachable.begin();
+ while(in_reachable_it != in_reachable.end()) {
+ Node in_node = d_id_node[*in_reachable_it];
+ Node in_pair = RelsUtils::constructPair(tc_ei->d_tc.get(), in_node, fst_rep);
+ Node new_pair = RelsUtils::constructPair(tc_ei->d_tc.get(), in_node, snd_rep);
+ Node tc_exp = explainTCMem(tc_ei, in_pair, in_node, fst_rep);
+ Node reason = tc_exp.isNull() ? exp : NodeManager::currentNM()->mkNode(kind::AND,tc_exp, exp);
+
+ tc_ei->d_mem_exp[new_pair] = reason;
+ tc_ei->d_mem.insert(new_pair);
+ Node tc_lemma = NodeManager::currentNM()->mkNode(kind::IMPLIES, reason, NodeManager::currentNM()->mkNode(kind::MEMBER,new_pair, tc_ei->d_tc.get()));
+
+ d_pending_merge.push_back(tc_lemma);
+ d_lemma.insert(tc_lemma);
+ in_reachable_it++;
+ }
+
+ std::hash_set<int>::iterator out_reachable_it = out_reachable.begin();
+ while(out_reachable_it != out_reachable.end()) {
+ Node out_node = d_id_node[*out_reachable_it];
+ Node out_pair = RelsUtils::constructPair(tc_ei->d_tc.get(), snd_rep, out_node);
+ Node reason = explainTCMem(tc_ei, out_pair, snd_rep, out_node);
+ Assert(reason != Node::null());
+
+ std::hash_set<int>::iterator in_reachable_it = in_reachable.begin();
+
+ while(in_reachable_it != in_reachable.end()) {
+ Node in_node = d_id_node[*in_reachable_it];
+ Node in_pair = RelsUtils::constructPair(tc_ei->d_tc.get(), in_node, snd_rep);
+ Node new_pair = RelsUtils::constructPair(tc_ei->d_tc.get(), in_node, out_node);
+ Node in_pair_exp = explainTCMem(tc_ei, in_pair, in_node, snd_rep);
+
+ Assert(in_pair_exp != Node::null());
+ reason = NodeManager::currentNM()->mkNode(kind::AND,reason, in_pair_exp);
+ tc_ei->d_mem_exp[new_pair] = reason;
+ tc_ei->d_mem.insert(new_pair);
+ Node tc_lemma = NodeManager::currentNM()->mkNode(kind::IMPLIES, reason, NodeManager::currentNM()->mkNode(kind::MEMBER,new_pair, tc_ei->d_tc.get()));
+ d_pending_merge.push_back(tc_lemma);
+ d_lemma.insert(tc_lemma);
+ in_reachable_it++;
+ }
+ out_reachable_it++;
+ }
+ }
+
+ void TheorySetsRels::collectReachableNodes(std::map< int, std::vector< int > >& id_map, int start_id, std::hash_set< int >& reachable_set, bool firstRound) {
+ Trace("rels-std") << "**** Collecting reachable nodes for node with id " << start_id << std::endl;
+ if(reachable_set.find(start_id) != reachable_set.end()) {
+ return;
+ }
+ if(!firstRound) {
+ reachable_set.insert(start_id);
+ }
+
+ std::vector< int > id_list = getIdList(id_map, start_id);
+ std::vector< int >::iterator id_list_it = id_list.begin();
+
+ while( id_list_it != id_list.end() ) {
+ collectReachableNodes( id_map, *id_list_it, reachable_set, false );
+ id_list_it++;
+ }
+ }
+
+ // Merge t2 into t1, t1 will be the rep of the new eqc
+ void TheorySetsRels::eqNotifyPostMerge( Node t1, Node t2 ) {
+ Trace("rels-std") << "[sets-rels] eqNotifyPostMerge:" << " t1 = " << t1 << " t2 = " << t2 << std::endl;
+
+ // Merge membership constraint with "true" or "false" eqc
+ if( (t1 == d_trueNode || t1 == d_falseNode) && t2.getKind() == kind::MEMBER && t2[0].getType().isTuple() ) {
+
+ Assert(t1 == d_trueNode || t1 == d_falseNode);
+ bool polarity = t1 == d_trueNode;
+ Node t2_1rep = getRepresentative(t2[1]);
+ EqcInfo* ei = getOrMakeEqcInfo( t2_1rep, true );
+
+ if( polarity ) {
+ ei->d_mem.insert(t2[0]);
+ ei->d_mem_exp[t2[0]] = explain(t2);
+ } else {
+ ei->d_not_mem.insert(t2[0]);
+ }
+ // Process a membership constraint that a tuple is a member of transpose of rel
+ if( !ei->d_tp.get().isNull() ) {
+ Node exp = polarity ? explain(t2) : explain(t2.negate());
+ if(ei->d_tp.get() != t2[1]) {
+ exp = NodeManager::currentNM()->mkNode(kind::AND, explain(NodeManager::currentNM()->mkNode(kind::EQUAL, ei->d_tp.get(), t2[1]) ), exp );
+ }
+ sendInferTranspose( polarity, t2[0], ei->d_tp.get(), exp, true );
+ }
+ // Process a membership constraint that a tuple is a member of product of rel
+ if( !ei->d_pt.get().isNull() ) {
+ Node exp = polarity ? explain(t2) : explain(t2.negate());
+ if(ei->d_pt.get() != t2[1]) {
+ exp = NodeManager::currentNM()->mkNode(kind::AND, explain(NodeManager::currentNM()->mkNode(kind::EQUAL, ei->d_pt.get(), t2[1]) ), exp );
+ }
+ sendInferProduct( polarity, t2[0], ei->d_pt.get(), exp );
+ }
+ // Process a membership constraint that a tuple is a member of transitive closure of rel
+ if( polarity && !ei->d_tc.get().isNull() ) {
+ addTCMemAndSendInfer( ei, t2, Node::null() );
+ }
+
+ // Merge two relation eqcs
+ } else if( t1.getType().isSet() && t2.getType().isSet() && t1.getType().getSetElementType().isTuple() ) {
+ mergeTransposeEqcs(t1, t2);
+ mergeProductEqcs(t1, t2);
+ mergeTCEqcs(t1, t2);
+ }
+
+ Trace("rels-std") << "[sets-rels] done with eqNotifyPostMerge:" << " t1 = " << t1 << " t2 = " << t2 << std::endl;
+ }
+
+ void TheorySetsRels::mergeTCEqcs(Node t1, Node t2) {
+ Trace("rels-std") << "[sets-rels] Merge TC eqcs t1 = " << t1 << " and t2 = " << t2 << std::endl;
+
+ EqcInfo* t1_ei = getOrMakeEqcInfo(t1);
+ EqcInfo* t2_ei = getOrMakeEqcInfo(t2);
+
+ if(t1_ei != NULL && t2_ei != NULL) {
+ NodeSet::const_iterator non_mem_it = t2_ei->d_not_mem.begin();
+
+ while(non_mem_it != t2_ei->d_not_mem.end()) {
+ t1_ei->d_not_mem.insert(*non_mem_it);
+ non_mem_it++;
+ }
+ if(!t1_ei->d_tc.get().isNull()) {
+ NodeSet::const_iterator mem_it = t2_ei->d_mem.begin();
+
+ while(mem_it != t2_ei->d_mem.end()) {
+ addTCMemAndSendInfer(t1_ei, NodeManager::currentNM()->mkNode(kind::MEMBER,*mem_it, t2_ei->d_tc.get()), (*t2_ei->d_mem_exp.find(*mem_it)).second);
+ mem_it++;
+ }
+ } else if(!t2_ei->d_tc.get().isNull()) {
+ t1_ei->d_tc.set(t2_ei->d_tc);
+ NodeSet::const_iterator t1_mem_it = t1_ei->d_mem.begin();
+
+ while(t1_mem_it != t1_ei->d_mem.end()) {
+ NodeMap::const_iterator reason_it = t1_ei->d_mem_exp.find(*t1_mem_it);
+ Assert(reason_it != t1_ei->d_mem_exp.end());
+ addTCMemAndSendInfer(t1_ei, NodeManager::currentNM()->mkNode(kind::MEMBER,*t1_mem_it, t1_ei->d_tc.get()), (*reason_it).second);
+ t1_mem_it++;
+ }
+
+ NodeSet::const_iterator t2_mem_it = t2_ei->d_mem.begin();
+
+ while(t2_mem_it != t2_ei->d_mem.end()) {
+ addTCMemAndSendInfer(t1_ei, NodeManager::currentNM()->mkNode(kind::MEMBER,*t2_mem_it, t2_ei->d_tc.get()), (*t2_ei->d_mem_exp.find(*t2_mem_it)).second);
+ t2_mem_it++;
+ }
+ }
+ }
+ Trace("rels-std") << "[sets-rels] Done with merging TC eqcs t1 = " << t1 << " and t2 = " << t2 << std::endl;
+ }
+
+
+
+
+ void TheorySetsRels::mergeProductEqcs(Node t1, Node t2) {
+ Trace("rels-std") << "[sets-rels] Merge PRODUCT eqcs t1 = " << t1 << " and t2 = " << t2 << std::endl;
+ EqcInfo* t1_ei = getOrMakeEqcInfo(t1);
+ EqcInfo* t2_ei = getOrMakeEqcInfo(t2);
+
+ if(t1_ei != NULL && t2_ei != NULL) {
+ // PT(t1) = PT(t2) -> t1 = t2;
+ if(!t1_ei->d_pt.get().isNull() && !t2_ei->d_pt.get().isNull()) {
+ sendInferProduct( true, t1_ei->d_pt.get(), t2_ei->d_pt.get(), explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1, t2)) );
+ }
+ // Apply Product rule on (non)members of t2 and t1->pt
+ if(!t1_ei->d_pt.get().isNull()) {
+ for(NodeSet::key_iterator itr = t2_ei->d_mem.key_begin(); itr != t2_ei->d_mem.key_end(); itr++) {
+ if(!t1_ei->d_mem.contains(*itr)) {
+ sendInferProduct( true, *itr, t1_ei->d_pt.get(), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1_ei->d_pt.get(), t2)), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t2))) );
+ }
+ }
+ for(NodeSet::key_iterator itr = t2_ei->d_not_mem.key_begin(); itr != t2_ei->d_not_mem.key_end(); itr++) {
+ if(!t1_ei->d_not_mem.contains(*itr)) {
+ sendInferProduct( false, *itr, t1_ei->d_pt.get(), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1_ei->d_pt.get(), t2)), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t2).negate())) );
+ }
+ }
+ } else if(!t2_ei->d_pt.get().isNull()) {
+ t1_ei->d_pt.set(t2_ei->d_pt);
+ for(NodeSet::key_iterator itr = t1_ei->d_mem.key_begin(); itr != t1_ei->d_mem.key_end(); itr++) {
+ if(!t2_ei->d_mem.contains(*itr)) {
+ sendInferProduct( true, *itr, t2_ei->d_pt.get(), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1, t2_ei->d_pt.get())), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t1))) );
+ }
+ }
+ for(NodeSet::key_iterator itr = t1_ei->d_not_mem.key_begin(); itr != t1_ei->d_not_mem.key_end(); itr++) {
+ if(!t2_ei->d_not_mem.contains(*itr)) {
+ sendInferProduct( false, *itr, t2_ei->d_pt.get(), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1, t2_ei->d_pt.get())), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t1).negate())) );
+ }
+ }
+ }
+ // t1 was created already and t2 was not
+ } else if(t1_ei != NULL) {
+ if(t1_ei->d_pt.get().isNull() && t2.getKind() == kind::PRODUCT) {
+ t1_ei->d_pt.set( t2 );
+ }
+ } else if(t2_ei != NULL){
+ t1_ei = getOrMakeEqcInfo(t1, true);
+ if(t1_ei->d_pt.get().isNull() && !t2_ei->d_pt.get().isNull()) {
+ t1_ei->d_pt.set(t2_ei->d_pt);
+ for(NodeSet::key_iterator itr = t2_ei->d_mem.key_begin(); itr != t2_ei->d_mem.key_end(); itr++) {
+ t1_ei->d_mem.insert(*itr);
+ t1_ei->d_mem_exp.insert(*itr, t2_ei->d_mem_exp[*itr]);
+ }
+ for(NodeSet::key_iterator itr = t2_ei->d_not_mem.key_begin(); itr != t2_ei->d_not_mem.key_end(); itr++) {
+ t1_ei->d_not_mem.insert(*itr);
+ }
+ }
+ }
+ }
+
+ void TheorySetsRels::mergeTransposeEqcs( Node t1, Node t2 ) {
+ Trace("rels-std") << "[sets-rels] Merge TRANSPOSE eqcs t1 = " << t1 << " and t2 = " << t2 << std::endl;
+ EqcInfo* t1_ei = getOrMakeEqcInfo( t1 );
+ EqcInfo* t2_ei = getOrMakeEqcInfo( t2 );
+
+ if( t1_ei != NULL && t2_ei != NULL ) {
+ Trace("rels-std") << "[sets-rels] 0 Merge TRANSPOSE eqcs t1 = " << t1 << " and t2 = " << t2 << std::endl;
+ // TP(t1) = TP(t2) -> t1 = t2;
+ if( !t1_ei->d_tp.get().isNull() && !t2_ei->d_tp.get().isNull() ) {
+ sendInferTranspose( true, t1_ei->d_tp.get(), t2_ei->d_tp.get(), explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1, t2)) );
+ }
+ // Apply transpose rule on (non)members of t2 and t1->tp
+ if( !t1_ei->d_tp.get().isNull() ) {
+ for( NodeSet::key_iterator itr = t2_ei->d_mem.key_begin(); itr != t2_ei->d_mem.key_end(); itr++ ) {
+ if( !t1_ei->d_mem.contains( *itr ) ) {
+ sendInferTranspose( true, *itr, t1_ei->d_tp.get(), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1_ei->d_tp.get(), t2)), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t2))) );
+ }
+ }
+ for( NodeSet::key_iterator itr = t2_ei->d_not_mem.key_begin(); itr != t2_ei->d_not_mem.key_end(); itr++ ) {
+ if(!t1_ei->d_not_mem.contains(*itr)) {
+ sendInferTranspose( false, *itr, t1_ei->d_tp.get(), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1_ei->d_tp.get(), t2)), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t2).negate())) );
+ }
+ }
+ // Apply transpose rule on (non)members of t1 and t2->tp
+ } else if( !t2_ei->d_tp.get().isNull() ) {
+ t1_ei->d_tp.set( t2_ei->d_tp );
+ for( NodeSet::key_iterator itr = t1_ei->d_mem.key_begin(); itr != t1_ei->d_mem.key_end(); itr++ ) {
+ if( !t2_ei->d_mem.contains(*itr) ) {
+ sendInferTranspose( true, *itr, t2_ei->d_tp.get(), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1, t2_ei->d_tp.get())), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t1))) );
+ }
+ }
+ for( NodeSet::key_iterator itr = t1_ei->d_not_mem.key_begin(); itr != t1_ei->d_not_mem.key_end(); itr++ ) {
+ if( !t2_ei->d_not_mem.contains(*itr) ) {
+ sendInferTranspose( false, *itr, t2_ei->d_tp.get(), NodeManager::currentNM()->mkNode(kind::AND, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1, t2_ei->d_tp.get())), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t1).negate()) ) );
+ }
+ }
+ }
+ // t1 was created already and t2 was not
+ } else if(t1_ei != NULL) {
+ if( t1_ei->d_tp.get().isNull() && t2.getKind() == kind::TRANSPOSE ) {
+ t1_ei->d_tp.set( t2 );
+ }
+ } else if( t2_ei != NULL ){
+ t1_ei = getOrMakeEqcInfo( t1, true );
+ if( t1_ei->d_tp.get().isNull() && !t2_ei->d_tp.get().isNull() ) {
+ t1_ei->d_tp.set( t2_ei->d_tp );
+ for( NodeSet::key_iterator itr = t2_ei->d_mem.key_begin(); itr != t2_ei->d_mem.key_end(); itr++ ) {
+ t1_ei->d_mem.insert( *itr );
+ t1_ei->d_mem_exp.insert( *itr, t2_ei->d_mem_exp[*itr] );
+ }
+ for( NodeSet::key_iterator itr = t2_ei->d_not_mem.key_begin(); itr != t2_ei->d_not_mem.key_end(); itr++ ) {
+ t1_ei->d_not_mem.insert( *itr );
+ }
+ }
+ }
+ }
+
+ void TheorySetsRels::doPendingMerge() {
+ for( NodeList::const_iterator itr = d_pending_merge.begin(); itr != d_pending_merge.end(); itr++ ) {
+ Trace("rels-std") << "[sets-rels-lemma] Process pending merge fact : "
+ << *itr << std::endl;
+ d_sets_theory.d_out->lemma( *itr );
+ }
+ }
+
+ void TheorySetsRels::sendInferTranspose( bool polarity, Node t1, Node t2, Node exp, bool reverseOnly ) {
+ Assert( t2.getKind() == kind::TRANSPOSE );
+ if( polarity && isRel(t1) && isRel(t2) ) {
+ Assert(t1.getKind() == kind::TRANSPOSE);
+ Node n = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::EQUAL,t1[0], t2[0]) );
+ Trace("rels-std") << "[sets-rels-lemma] Generate a lemma by applying transpose rule: "
+ << n << std::endl;
+ d_pending_merge.push_back( n );
+ d_lemma.insert( n );
+ return;
+ }
+
+ Node n1;
+ if( reverseOnly ) {
+ if( polarity ) {
+ n1 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::reverseTuple(t1), t2[0]) );
+ } else {
+ n1 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::reverseTuple(t1), t2[0]).negate() );
+ }
+ } else {
+ Node n2;
+ if(polarity) {
+ n1 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER,t1, t2) );
+ n2 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::reverseTuple(t1), t2[0]) );
+ } else {
+ n1 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER,t1, t2).negate() );
+ n2 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::reverseTuple(t1), t2[0]).negate() );
+ }
+ Trace("rels-std") << "[sets-rels-lemma] Generate a lemma by applying transpose rule: "
+ << n2 << std::endl;
+ d_pending_merge.push_back(n2);
+ d_lemma.insert(n2);
+ }
+ Trace("rels-std") << "[sets-rels-lemma] Generate a lemma by applying transpose rule: "
+ << n1 << std::endl;
+ d_pending_merge.push_back(n1);
+ d_lemma.insert(n1);
+
+ }
+
+ void TheorySetsRels::sendInferProduct( bool polarity, Node t1, Node t2, Node exp ) {
+ Assert( t2.getKind() == kind::PRODUCT );
+ if( polarity && isRel(t1) && isRel(t2) ) {
+ //PRODUCT(x) = PRODUCT(y) => x = y;
+ Assert( t1.getKind() == kind::PRODUCT );
+ Node n = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::EQUAL,t1[0], t2[0]) );
+ Trace("rels-std") << "[sets-rels-lemma] Generate a lemma by applying product rule: "
+ << n << std::endl;
+ d_pending_merge.push_back( n );
+ d_lemma.insert( n );
+ return;
+ }
+
+ std::vector<Node> r1_element;
+ std::vector<Node> r2_element;
+ Node r1 = t2[0];
+ Node r2 = t2[1];
+ NodeManager *nm = NodeManager::currentNM();
+ Datatype dt = r1.getType().getSetElementType().getDatatype();
+ unsigned int i = 0;
+ unsigned int s1_len = r1.getType().getSetElementType().getTupleLength();
+ unsigned int tup_len = t2.getType().getSetElementType().getTupleLength();
+
+ r1_element.push_back(Node::fromExpr(dt[0].getConstructor()));
+ for( ; i < s1_len; ++i ) {
+ r1_element.push_back( RelsUtils::nthElementOfTuple( t1, i ) );
+ }
+
+ dt = r2.getType().getSetElementType().getDatatype();
+ r2_element.push_back( Node::fromExpr( dt[0].getConstructor() ) );
+ for( ; i < tup_len; ++i ) {
+ r2_element.push_back( RelsUtils::nthElementOfTuple(t1, i) );
+ }
+
+ Node n1;
+ Node n2;
+ Node tuple_1 = getRepresentative( nm->mkNode( kind::APPLY_CONSTRUCTOR, r1_element ) );
+ Node tuple_2 = getRepresentative( nm->mkNode( kind::APPLY_CONSTRUCTOR, r2_element ) );
+
+ if( polarity ) {
+ n1 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER, tuple_1, r1 ) );
+ n2 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER, tuple_2, r2 ) );
+ } else {
+ n1 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER, tuple_1, r1 ).negate() );
+ n2 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER, tuple_2, r2 ).negate() );
+ }
+ Trace("rels-std") << "[sets-rels-lemma] Generate a lemma by applying product-split rule: "
+ << n1 << std::endl;
+ d_pending_merge.push_back( n1 );
+ d_lemma.insert( n1 );
+ Trace("rels-std") << "[sets-rels-lemma] Generate a lemma by applying product-split rule: "
+ << n2 << std::endl;
+ d_pending_merge.push_back( n2 );
+ d_lemma.insert( n2 );
+
+ }
+
+ TheorySetsRels::EqcInfo* TheorySetsRels::getOrMakeEqcInfo( Node n, bool doMake ){
+ std::map< Node, EqcInfo* >::iterator eqc_i = d_eqc_info.find( n );
+ if( eqc_i == d_eqc_info.end() ){
+ if( doMake ){
+ EqcInfo* ei;
+ if( eqc_i!=d_eqc_info.end() ){
+ ei = eqc_i->second;
+ }else{
+ ei = new EqcInfo(d_sets_theory.getSatContext());
+ d_eqc_info[n] = ei;
+ }
+ if( n.getKind() == kind::TRANSPOSE ){
+ ei->d_tp = n;
+ } else if( n.getKind() == kind::PRODUCT ) {
+ ei->d_pt = n;
+ } else if( n.getKind() == kind::TCLOSURE ) {
+ ei->d_tc = n;
+ } else if( n.getKind() == kind::JOIN ) {
+ ei->d_join = n;
+ }
+ return ei;
+ }else{
+ return NULL;
+ }
+ }else{
+ return (*eqc_i).second;
+ }
+ }
+
+
+ Node TheorySetsRels::mkAnd( std::vector<TNode>& conjunctions ) {
+ Assert(conjunctions.size() > 0);
+ std::set<TNode> all;
+
+ for (unsigned i = 0; i < conjunctions.size(); ++i) {
+ TNode t = conjunctions[i];
+ if (t.getKind() == kind::AND) {
+ for(TNode::iterator child_it = t.begin();
+ child_it != t.end(); ++child_it) {
+ Assert((*child_it).getKind() != kind::AND);
+ all.insert(*child_it);
+ }
+ }
+ else {
+ all.insert(t);
+ }
+ }
+ Assert(all.size() > 0);
+ if (all.size() == 1) {
+ // All the same, or just one
+ return conjunctions[0];
+ }
+
+ NodeBuilder<> conjunction(kind::AND);
+ std::set<TNode>::const_iterator it = all.begin();
+ std::set<TNode>::const_iterator it_end = all.end();
+ while (it != it_end) {
+ conjunction << *it;
+ ++ it;
+ }
+
+ return conjunction;
+ }/* mkAnd() */
+
+ void TheorySetsRels::printNodeMap(char* fst, char* snd, NodeMap map) {
+ NodeMap::iterator map_it = map.begin();
+ while(map_it != map.end()) {
+ Trace("rels-debug") << fst << " "<< (*map_it).first << " " << snd << " " << (*map_it).second<< std::endl;
+ map_it++;
+ }
+ }
+
+ bool TheorySetsRels::addId( std::map< int, std::vector< int > >& id_map, int key, int id ) {
+ int n_data = d_vec_size[key];
+ int len = n_data < (int)id_map[key].size() ? n_data : id_map[key].size();
+
+ for( int i = 0; i < len; i++ ) {
+ if( id_map[key][i] == id) {
+ return false;
+ }
+ }
+ if( n_data < (int)id_map[key].size() ) {
+ id_map[key][n_data] = id;
+ } else {
+ id_map[key].push_back( id );
+ }
+ d_vec_size[key] = n_data+1;
+ return true;
+ }
+
+ std::vector< int > TheorySetsRels::getIdList( std::map< int, std::vector< int > >& id_map, int key ) {
+ std::vector< int > id_list;
+ int n_data = d_vec_size[key];
+ int len = n_data < (int)id_map[key].size() ? n_data : id_map[key].size();
+
+ for( int i = 0; i < len; i++ ) {
+ id_list.push_back(id_map[key][i]);
+ }
+ return id_list;
+ }
+
+}
+}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/theory/sets/theory_sets_rels.h b/src/theory/sets/theory_sets_rels.h
new file mode 100644
index 000000000..e5c0ad10c
--- /dev/null
+++ b/src/theory/sets/theory_sets_rels.h
@@ -0,0 +1,260 @@
+/********************* */
+/*! \file theory_sets_rels.h
+ ** \verbatim
+ ** Original author: Paul Meng
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Sets theory implementation.
+ **
+ ** Extension to Sets theory.
+ **/
+
+#ifndef SRC_THEORY_SETS_THEORY_SETS_RELS_H_
+#define SRC_THEORY_SETS_THEORY_SETS_RELS_H_
+
+#include "theory/theory.h"
+#include "theory/uf/equality_engine.h"
+#include "context/cdhashset.h"
+#include "context/cdchunk_list.h"
+#include "theory/sets/rels_utils.h"
+
+namespace CVC4 {
+namespace theory {
+namespace sets {
+
+class TheorySets;
+
+
+class TupleTrie {
+public:
+ /** the data */
+ std::map< Node, TupleTrie > d_data;
+public:
+ std::vector<Node> findTerms( std::vector< Node >& reps, int argIndex = 0 );
+ Node existsTerm( std::vector< Node >& reps, int argIndex = 0 );
+ bool addTerm( Node n, std::vector< Node >& reps, int argIndex = 0 );
+ void debugPrint( const char * c, Node n, unsigned depth = 0 );
+ void clear() { d_data.clear(); }
+};/* class TupleTrie */
+
+class TheorySetsRels {
+
+ typedef context::CDChunkList< Node > NodeList;
+ typedef context::CDChunkList< int > IdList;
+ typedef context::CDHashMap< int, IdList* > IdListMap;
+ typedef context::CDHashSet< Node, NodeHashFunction > NodeSet;
+ typedef context::CDHashMap< Node, bool, NodeHashFunction > NodeBoolMap;
+ typedef context::CDHashMap< Node, NodeList*, NodeHashFunction > NodeListMap;
+ typedef context::CDHashMap< Node, NodeSet*, NodeHashFunction > NodeSetMap;
+ typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap;
+
+public:
+ TheorySetsRels(context::Context* c,
+ context::UserContext* u,
+ eq::EqualityEngine*,
+ context::CDO<bool>*,
+ TheorySets&);
+
+ ~TheorySetsRels();
+ void check(Theory::Effort);
+ void doPendingLemmas();
+
+private:
+ /** equivalence class info
+ * d_mem tuples that are members of this equivalence class
+ * d_not_mem tuples that are not members of this equivalence class
+ * d_tp is a node of kind TRANSPOSE (if any) in this equivalence class,
+ * d_pt is a node of kind PRODUCT (if any) in this equivalence class,
+ * d_join is a node of kind JOIN (if any) in this equivalence class,
+ * d_tc is a node of kind TCLOSURE (if any) in this equivalence class,
+ */
+ class EqcInfo
+ {
+ public:
+ EqcInfo( context::Context* c );
+ ~EqcInfo(){}
+ static int counter;
+ NodeSet d_mem;
+ NodeSet d_not_mem;
+ NodeMap d_mem_exp;
+ NodeListMap d_in;
+ NodeListMap d_out;
+ context::CDO< Node > d_tp;
+ context::CDO< Node > d_pt;
+ context::CDO< Node > d_join;
+ context::CDO< Node > d_tc;
+ /** mapping from an element rep id to a list of rep ids that pointed by */
+ /** Context dependent map Int -> IntList */
+ std::map< int, std::vector< int > > d_id_inIds;
+ /** mapping from an element rep id to a list of rep ids that point to */
+ /** Context dependent map Int -> IntList */
+ std::map< int, std::vector< int > > d_id_outIds;
+ };
+
+private:
+ /** Context */
+ context::CDHashMap< int, int > d_vec_size;
+
+ /** Mapping between integer id and tuple element rep */
+ std::map< int, Node > d_id_node;
+
+ /** Mapping between tuple element rep and integer id*/
+ std::map< Node, int > d_node_id;
+
+ /** has eqc info */
+ bool hasEqcInfo( TNode n ) { return d_eqc_info.find( n )!=d_eqc_info.end(); }
+
+ bool addId( std::map< int, std::vector< int > >& id_map, int key, int id );
+ std::vector< int > getIdList( std::map< int, std::vector< int > >& id_map, int key );
+
+ void collectReachableNodes( std::map< int, std::vector< int > >&, int, std::hash_set<int>& , bool first_round = true);
+
+
+private:
+ eq::EqualityEngine *d_eqEngine;
+ context::CDO<bool> *d_conflict;
+ TheorySets& d_sets_theory;
+
+ /** True and false constant nodes */
+ Node d_trueNode;
+ Node d_falseNode;
+
+ /** Facts and lemmas to be sent to EE */
+ std::map< Node, Node > d_pending_facts;
+ std::map< Node, Node > d_pending_split_facts;
+ std::vector< Node > d_lemma_cache;
+ NodeList d_pending_merge;
+
+ /** inferences: maintained to ensure ref count for internally introduced nodes */
+ NodeList d_infer;
+ NodeList d_infer_exp;
+ NodeSet d_lemma;
+ NodeSet d_shared_terms;
+
+ /** Relations that have been applied JOIN, PRODUCT, TC composition rules */
+ std::hash_set< Node, NodeHashFunction > d_rel_nodes;
+ std::map< Node, std::vector<Node> > d_tuple_reps;
+ std::map< Node, TupleTrie > d_membership_trie;
+
+ /** Symbolic tuple variables that has been reduced to concrete ones */
+ std::hash_set< Node, NodeHashFunction > d_symbolic_tuples;
+
+ /** Mapping between relation and its (non)members representatives */
+ std::map< Node, std::vector<Node> > d_membership_constraints_cache;
+
+ /** Mapping between relation and its (non)members' explanation */
+ std::map< Node, std::vector<Node> > d_membership_exp_cache;
+
+ /** Mapping between relation and its member representatives */
+ std::map< Node, std::vector<Node> > d_membership_db;
+
+ /** Mapping between relation and its members' explanation */
+ std::map< Node, std::vector<Node> > d_membership_exp_db;
+
+ /** Mapping between a relation representative and its equivalent relations involving relational operators */
+ std::map< Node, std::map<kind::Kind_t, std::vector<Node> > > d_terms_cache;
+
+ /** Mapping between relation and its member representatives */
+ std::map< Node, std::vector<Node> > d_arg_rep_tp_terms;
+
+ /** Mapping between TC(r) and one explanation when building TC graph*/
+ std::map< Node, Node > d_membership_tc_exp_cache;
+
+ /** Mapping between transitive closure relation TC(r) (is not necessary a representative) and members directly asserted members */
+ std::map< Node, std::hash_set<Node, NodeHashFunction> > d_tc_membership_db;
+
+ /** Mapping between transitive closure relation TC(r) and its TC graph constructed based on the members of r*/
+ std::map< Node, std::map< Node, std::hash_set<Node, NodeHashFunction> > > d_tc_r_graph;
+
+ /** Mapping between transitive closure TC(r)'s representative and TC(r) */
+ std::map< Node, Node > d_tc_rep_term;
+ std::map< Node, EqcInfo* > d_eqc_info;
+
+public:
+ void eqNotifyNewClass(Node t);
+ void eqNotifyPostMerge(Node t1, Node t2);
+
+private:
+
+ void doPendingMerge();
+ Node findTCMemExp(EqcInfo*, Node);
+ void buildTCAndExp(Node, EqcInfo*);
+ void mergeTCEqcs(Node t1, Node t2);
+ void mergeTCEqcExp(EqcInfo*, EqcInfo*);
+ void mergeProductEqcs(Node t1, Node t2);
+ int getOrMakeElementRepId(EqcInfo*, Node);
+ void mergeTransposeEqcs(Node t1, Node t2);
+ Node explainTCMem(EqcInfo*, Node, Node, Node);
+ void sendInferProduct(bool, Node, Node, Node);
+ EqcInfo* getOrMakeEqcInfo( Node n, bool doMake = false );
+ void sendInferTranspose(bool, Node, Node, Node, bool reverseOnly = false);
+ void addTCMemAndSendInfer(EqcInfo* tc_ei, Node mem, Node exp, bool fromRel = false);
+ void sendTCInference(EqcInfo* tc_ei, std::hash_set<int> in_reachable, std::hash_set<int> out_reachable, Node mem_rep, Node fst_rep, Node snd_rep, int id1, int id2);
+
+
+
+ void check();
+ Node explain(Node);
+ void collectRelsInfo();
+ void applyTCRule( Node, Node );
+ void applyJoinRule( Node, Node );
+ void applyProductRule( Node, Node );
+ void composeTupleMemForRel( Node );
+ void assertMembership( Node fact, Node reason, bool polarity );
+ void applyTransposeRule( Node, Node, Node more_reason = Node::null(), bool tp_occur_rule = false );
+
+
+
+ void computeMembersForRelofMultArities( Node );
+ void computeMembersForUnaryRel( Node );
+ void finalizeTCInference();
+ void inferTC( Node, std::map< Node, std::hash_set< Node, NodeHashFunction > >& );
+ void inferTC( Node, Node, std::map< Node, std::hash_set< Node, NodeHashFunction > >&,
+ Node, Node, std::hash_set< Node, NodeHashFunction >&);
+ void isTCReachable(Node fst, Node snd, std::hash_set<Node, NodeHashFunction>& hasSeen,
+ std::map< Node, std::hash_set< Node, NodeHashFunction > >& tc_graph, bool&);
+ std::map< Node, std::hash_set< Node, NodeHashFunction > > constructTCGraph( Node, Node, Node );
+
+
+ void doTCLemmas();
+ void addSharedTerm( TNode n );
+ void sendInfer( Node fact, Node exp, const char * c );
+ void sendLemma( Node fact, Node reason, const char * c );
+
+ // Helper functions
+ bool holds( Node );
+ bool hasTerm( Node a );
+ void makeSharedTerm( Node );
+ void reduceTupleVar( Node );
+ bool hasMember( Node, Node );
+ void computeTupleReps( Node );
+ bool areEqual( Node a, Node b );
+ Node getRepresentative( Node t );
+ Node findMemExp(Node r, Node pair);
+ bool insertIntoIdList(IdList&, int);
+ bool exists( std::vector<Node>&, Node );
+ Node mkAnd( std::vector< TNode >& assumptions );
+ inline void addToMembershipDB( Node, Node, Node );
+ void printNodeMap(char* fst, char* snd, NodeMap map);
+ inline Node constructPair(Node tc_rep, Node a, Node b);
+ void addToMap( std::map< Node, std::vector<Node> >&, Node, Node );
+ bool safelyAddToMap( std::map< Node, std::vector<Node> >&, Node, Node );
+ inline Node getReason(Node tc_rep, Node tc_term, Node tc_r_rep, Node tc_r);
+ bool isRel( Node n ) {return n.getType().isSet() && n.getType().getSetElementType().isTuple();}
+
+
+};
+
+
+}/* CVC4::theory::sets namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+
+
+#endif /* SRC_THEORY_SETS_THEORY_SETS_RELS_H_ */
diff --git a/src/theory/sets/theory_sets_rewriter.cpp b/src/theory/sets/theory_sets_rewriter.cpp
index 8dbca1e73..d21e3fd67 100644
--- a/src/theory/sets/theory_sets_rewriter.cpp
+++ b/src/theory/sets/theory_sets_rewriter.cpp
@@ -16,6 +16,7 @@
#include "theory/sets/theory_sets_rewriter.h"
#include "theory/sets/normal_form.h"
+#include "theory/sets/rels_utils.h"
#include "expr/attribute.h"
#include "options/sets_options.h"
@@ -158,6 +159,20 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
TNode S = preRewrite(node[1]).node;
bool isMember = checkConstantMembership(node[0], S);
return RewriteResponse(REWRITE_DONE, nm->mkConst(isMember));
+ }else if( node[1].getKind()==kind::EMPTYSET ){
+ return RewriteResponse(REWRITE_DONE, nm->mkConst(false));
+ }else if( node[1].getKind()==kind::SINGLETON ){
+ return RewriteResponse(REWRITE_AGAIN_FULL, nm->mkNode(kind::EQUAL, node[0], node[1][0] ) );
+ }else if( node[1].getKind()==kind::UNION || node[1].getKind()==kind::INTERSECTION || node[1].getKind()==kind::SETMINUS ){
+ std::vector< Node > children;
+ for( unsigned i=0; i<node[1].getNumChildren(); i++ ){
+ Node nc = nm->mkNode(kind::MEMBER, node[0], node[1][i] );
+ if( node[1].getKind()==kind::SETMINUS && i==1 ){
+ nc = nc.negate();
+ }
+ children.push_back( nc );
+ }
+ return RewriteResponse(REWRITE_AGAIN_FULL, nm->mkNode( node[1].getKind()==kind::UNION ? kind::OR : kind::AND, children ) );
}
break;
}//kind::MEMBER
@@ -198,92 +213,69 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
}//kind::IFF
case kind::SETMINUS: {
- if( options::setsAggRewrite() ){
- Node newNode = rewriteSet( node );
- if( newNode!=node ){
- return RewriteResponse(REWRITE_DONE, newNode);
- }
- }else{
- if(node[0] == node[1]) {
- Node newNode = nm->mkConst(EmptySet(nm->toType(node[0].getType())));
- Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
- return RewriteResponse(REWRITE_DONE, newNode);
- } else if(node[0].getKind() == kind::EMPTYSET ||
- node[1].getKind() == kind::EMPTYSET) {
- Trace("sets-postrewrite") << "Sets::postRewrite returning " << node[0] << std::endl;
- return RewriteResponse(REWRITE_DONE, node[0]);
- } else if(node[0].isConst() && node[1].isConst()) {
- std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
- std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
- std::set<Node> newSet;
- std::set_difference(left.begin(), left.end(), right.begin(), right.end(),
- std::inserter(newSet, newSet.begin()));
- Node newNode = NormalForm::elementsToSet(newSet, node.getType());
- Assert(newNode.isConst());
- Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
- return RewriteResponse(REWRITE_DONE, newNode);
- }
+ if(node[0] == node[1]) {
+ Node newNode = nm->mkConst(EmptySet(nm->toType(node[0].getType())));
+ Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
+ return RewriteResponse(REWRITE_DONE, newNode);
+ } else if(node[0].getKind() == kind::EMPTYSET ||
+ node[1].getKind() == kind::EMPTYSET) {
+ Trace("sets-postrewrite") << "Sets::postRewrite returning " << node[0] << std::endl;
+ return RewriteResponse(REWRITE_DONE, node[0]);
+ } else if(node[0].isConst() && node[1].isConst()) {
+ std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
+ std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
+ std::set<Node> newSet;
+ std::set_difference(left.begin(), left.end(), right.begin(), right.end(),
+ std::inserter(newSet, newSet.begin()));
+ Node newNode = NormalForm::elementsToSet(newSet, node.getType());
+ Assert(newNode.isConst());
+ Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
+ return RewriteResponse(REWRITE_DONE, newNode);
}
break;
}//kind::SETMINUS
case kind::INTERSECTION: {
- if( options::setsAggRewrite() ){
- Node newNode = rewriteSet( node );
- if( newNode!=node ){
- return RewriteResponse(REWRITE_DONE, newNode);
- }
- // }else{
- // Node emptySet = nm->mkConst(EmptySet(nm->toType(node[0].getType())));
- // if(node[0].isConst() && node[1].isConst()) {
- // std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
- // std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
- // std::set<Node> newSet;
- // std::set_intersection(left.begin(), left.end(), right.begin(), right.end(),
- // std::inserter(newSet, newSet.begin()));
- // Node newNode = NormalForm::elementsToSet(newSet, node.getType());
- // Assert(newNode.isConst());
- // Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
- // return RewriteResponse(REWRITE_DONE, newNode);
- // } else {
- // return flattenNode(node, /* trivialNode = */ emptySet, /* skipNode = */ Node());
- // }
- // }
- }else{
- if(node[0] == node[1]) {
- Trace("sets-postrewrite") << "Sets::postRewrite returning " << node[0] << std::endl;
- return RewriteResponse(REWRITE_DONE, node[0]);
- } else if(node[0].getKind() == kind::EMPTYSET) {
- return RewriteResponse(REWRITE_DONE, node[0]);
- } else if(node[1].getKind() == kind::EMPTYSET) {
- return RewriteResponse(REWRITE_DONE, node[1]);
- } else if(node[0].isConst() && node[1].isConst()) {
- std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
- std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
- std::set<Node> newSet;
- std::set_intersection(left.begin(), left.end(), right.begin(), right.end(),
- std::inserter(newSet, newSet.begin()));
- Node newNode = NormalForm::elementsToSet(newSet, node.getType());
- Assert(newNode.isConst());
- Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
- return RewriteResponse(REWRITE_DONE, newNode);
- } else if (node[0] > node[1]) {
- Node newNode = nm->mkNode(node.getKind(), node[1], node[0]);
- Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
- return RewriteResponse(REWRITE_DONE, newNode);
+ if(node[0] == node[1]) {
+ Trace("sets-postrewrite") << "Sets::postRewrite returning " << node[0] << std::endl;
+ return RewriteResponse(REWRITE_DONE, node[0]);
+ } else if(node[0].getKind() == kind::EMPTYSET) {
+ return RewriteResponse(REWRITE_DONE, node[0]);
+ } else if(node[1].getKind() == kind::EMPTYSET) {
+ return RewriteResponse(REWRITE_DONE, node[1]);
+ } else if(node[0].isConst() && node[1].isConst()) {
+ std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
+ std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
+ std::set<Node> newSet;
+ std::set_intersection(left.begin(), left.end(), right.begin(), right.end(),
+ std::inserter(newSet, newSet.begin()));
+ Node newNode = NormalForm::elementsToSet(newSet, node.getType());
+ Assert(newNode.isConst());
+ Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
+ return RewriteResponse(REWRITE_DONE, newNode);
+ } else {
+ std::vector< Node > els;
+ NormalForm::getElementsFromBop( kind::INTERSECTION, node, els );
+ std::sort( els.begin(), els.end() );
+ Node rew = NormalForm::mkBop( kind::INTERSECTION, els, node.getType() );
+ if( rew!=node ){
+ Trace("sets-rewrite") << "Sets::rewrite " << node << " -> " << rew << std::endl;
}
+ return RewriteResponse(REWRITE_DONE, rew);
+ }
+ /*
+ } else if (node[0] > node[1]) {
+ Node newNode = nm->mkNode(node.getKind(), node[1], node[0]);
+ Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
+ return RewriteResponse(REWRITE_DONE, newNode);
}
+ */
break;
}//kind::INTERSECION
case kind::UNION: {
// NOTE: case where it is CONST is taken care of at the top
- if( options::setsAggRewrite() ){
- Node newNode = rewriteSet( node );
- if( newNode!=node ){
- return RewriteResponse(REWRITE_DONE, newNode);
- }
- }else if(node[0] == node[1]) {
+ if(node[0] == node[1]) {
Trace("sets-postrewrite") << "Sets::postRewrite returning " << node[0] << std::endl;
return RewriteResponse(REWRITE_DONE, node[0]);
} else if(node[0].getKind() == kind::EMPTYSET) {
@@ -300,10 +292,15 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
Assert(newNode.isConst());
Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
return RewriteResponse(REWRITE_DONE, newNode);
- }else if (node[0] > node[1]) {
- Node newNode = nm->mkNode(node.getKind(), node[1], node[0]);
- Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
- return RewriteResponse(REWRITE_DONE, newNode);
+ } else {
+ std::vector< Node > els;
+ NormalForm::getElementsFromBop( kind::UNION, node, els );
+ std::sort( els.begin(), els.end() );
+ Node rew = NormalForm::mkBop( kind::UNION, els, node.getType() );
+ if( rew!=node ){
+ Trace("sets-rewrite") << "Sets::rewrite " << node << " -> " << rew << std::endl;
+ }
+ return RewriteResponse(REWRITE_DONE, rew);
}
break;
}//kind::UNION
@@ -312,9 +309,160 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
if(node[0].isConst()) {
std::set<Node> elements = NormalForm::getElementsFromNormalConstant(node[0]);
return RewriteResponse(REWRITE_DONE, nm->mkConst(Rational(elements.size())));
+ }else if( node[0].getKind()==kind::SINGLETON ){
+ return RewriteResponse(REWRITE_DONE, nm->mkConst(Rational(1)));
+ }else if( node[0].getKind()==kind::UNION ){
+ Node ret = NodeManager::currentNM()->mkNode( kind::MINUS,
+ NodeManager::currentNM()->mkNode( kind::PLUS, NodeManager::currentNM()->mkNode( kind::CARD, node[0][0] ),
+ NodeManager::currentNM()->mkNode( kind::CARD, node[0][1] ) ),
+ NodeManager::currentNM()->mkNode( kind::CARD, NodeManager::currentNM()->mkNode( kind::INTERSECTION, node[0][0], node[0][1] ) ) );
+ return RewriteResponse(REWRITE_DONE, ret );
+ }else if( node[0].getKind()==kind::SETMINUS ){
+ Node ret = NodeManager::currentNM()->mkNode( kind::MINUS,
+ NodeManager::currentNM()->mkNode( kind::CARD, node[0][0] ),
+ NodeManager::currentNM()->mkNode( kind::CARD, NodeManager::currentNM()->mkNode( kind::INTERSECTION, node[0][0], node[0][1] ) ) );
+ return RewriteResponse(REWRITE_DONE, ret );
+ }
+ }
+ case kind::TRANSPOSE: {
+ if(node[0].getKind() == kind::TRANSPOSE) {
+ return RewriteResponse(REWRITE_AGAIN, node[0][0]);
+ }
+
+ if(node[0].getKind() == kind::EMPTYSET) {
+ return RewriteResponse(REWRITE_DONE, nm->mkConst(EmptySet(nm->toType(node.getType()))));
+ } else if(node[0].isConst()) {
+ std::set<Node> new_tuple_set;
+ std::set<Node> tuple_set = NormalForm::getElementsFromNormalConstant(node[0]);
+ std::set<Node>::iterator tuple_it = tuple_set.begin();
+
+ while(tuple_it != tuple_set.end()) {
+ new_tuple_set.insert(RelsUtils::reverseTuple(*tuple_it));
+ tuple_it++;
+ }
+ Node new_node = NormalForm::elementsToSet(new_tuple_set, node.getType());
+ Assert(new_node.isConst());
+ Trace("sets-postrewrite") << "Sets::postRewrite returning " << new_node << std::endl;
+ return RewriteResponse(REWRITE_DONE, new_node);
+
+ }
+ if(node[0].getKind() != kind::TRANSPOSE) {
+ Trace("sets-postrewrite") << "Sets::postRewrite returning " << node << std::endl;
+ return RewriteResponse(REWRITE_DONE, node);
+ }
+ break;
+ }
+
+ case kind::PRODUCT: {
+ Trace("sets-rels-postrewrite") << "Sets::postRewrite processing " << node << std::endl;
+ if( node[0].getKind() == kind::EMPTYSET ||
+ node[1].getKind() == kind::EMPTYSET) {
+ return RewriteResponse(REWRITE_DONE, nm->mkConst(EmptySet(nm->toType(node.getType()))));
+ } else if( node[0].isConst() && node[1].isConst() ) {
+ Trace("sets-rels-postrewrite") << "Sets::postRewrite processing **** " << node << std::endl;
+ std::set<Node> new_tuple_set;
+ std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
+ std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
+ std::set<Node>::iterator left_it = left.begin();
+ int left_len = (*left_it).getType().getTupleLength();
+ TypeNode tn = node.getType().getSetElementType();
+ while(left_it != left.end()) {
+ Trace("rels-debug") << "Sets::postRewrite processing left_it = " << *left_it << std::endl;
+ std::vector<Node> left_tuple;
+ left_tuple.push_back(Node::fromExpr(tn.getDatatype()[0].getConstructor()));
+ for(int i = 0; i < left_len; i++) {
+ left_tuple.push_back(RelsUtils::nthElementOfTuple(*left_it,i));
+ }
+ std::set<Node>::iterator right_it = right.begin();
+ int right_len = (*right_it).getType().getTupleLength();
+ while(right_it != right.end()) {
+ Trace("rels-debug") << "Sets::postRewrite processing left_it = " << *right_it << std::endl;
+ std::vector<Node> right_tuple;
+ for(int j = 0; j < right_len; j++) {
+ right_tuple.push_back(RelsUtils::nthElementOfTuple(*right_it,j));
+ }
+ std::vector<Node> new_tuple;
+ new_tuple.insert(new_tuple.end(), left_tuple.begin(), left_tuple.end());
+ new_tuple.insert(new_tuple.end(), right_tuple.begin(), right_tuple.end());
+ Node composed_tuple = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, new_tuple);
+ new_tuple_set.insert(composed_tuple);
+ right_it++;
+ }
+ left_it++;
+ }
+ Node new_node = NormalForm::elementsToSet(new_tuple_set, node.getType());
+ Assert(new_node.isConst());
+ Trace("sets-postrewrite") << "Sets::postRewrite returning " << new_node << std::endl;
+ return RewriteResponse(REWRITE_DONE, new_node);
+ }
+ break;
+ }
+
+ case kind::JOIN: {
+ if( node[0].getKind() == kind::EMPTYSET ||
+ node[1].getKind() == kind::EMPTYSET) {
+ return RewriteResponse(REWRITE_DONE, nm->mkConst(EmptySet(nm->toType(node.getType()))));
+ } else if( node[0].isConst() && node[1].isConst() ) {
+ Trace("sets-rels-postrewrite") << "Sets::postRewrite processing " << node << std::endl;
+ std::set<Node> new_tuple_set;
+ std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
+ std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
+ std::set<Node>::iterator left_it = left.begin();
+ int left_len = (*left_it).getType().getTupleLength();
+ TypeNode tn = node.getType().getSetElementType();
+ while(left_it != left.end()) {
+ std::vector<Node> left_tuple;
+ left_tuple.push_back(Node::fromExpr(tn.getDatatype()[0].getConstructor()));
+ for(int i = 0; i < left_len - 1; i++) {
+ left_tuple.push_back(RelsUtils::nthElementOfTuple(*left_it,i));
+ }
+ std::set<Node>::iterator right_it = right.begin();
+ int right_len = (*right_it).getType().getTupleLength();
+ while(right_it != right.end()) {
+ if(RelsUtils::nthElementOfTuple(*left_it,left_len-1) == RelsUtils::nthElementOfTuple(*right_it,0)) {
+ std::vector<Node> right_tuple;
+ for(int j = 1; j < right_len; j++) {
+ right_tuple.push_back(RelsUtils::nthElementOfTuple(*right_it,j));
+ }
+ std::vector<Node> new_tuple;
+ new_tuple.insert(new_tuple.end(), left_tuple.begin(), left_tuple.end());
+ new_tuple.insert(new_tuple.end(), right_tuple.begin(), right_tuple.end());
+ Node composed_tuple = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, new_tuple);
+ new_tuple_set.insert(composed_tuple);
+ }
+ right_it++;
+ }
+ left_it++;
+ }
+ Node new_node = NormalForm::elementsToSet(new_tuple_set, node.getType());
+ Assert(new_node.isConst());
+ Trace("sets-postrewrite") << "Sets::postRewrite returning " << new_node << std::endl;
+ return RewriteResponse(REWRITE_DONE, new_node);
}
+
+ break;
}
+ case kind::TCLOSURE: {
+ if(node[0].getKind() == kind::EMPTYSET) {
+ return RewriteResponse(REWRITE_DONE, nm->mkConst(EmptySet(nm->toType(node.getType()))));
+ } else if (node[0].isConst()) {
+ std::set<Node> rel_mems = NormalForm::getElementsFromNormalConstant(node[0]);
+ std::set<Node> tc_rel_mems = RelsUtils::computeTC(rel_mems, node);
+ Node new_node = NormalForm::elementsToSet(tc_rel_mems, node.getType());
+ Assert(new_node.isConst());
+ Trace("sets-postrewrite") << "Sets::postRewrite returning " << new_node << std::endl;
+ return RewriteResponse(REWRITE_DONE, new_node);
+
+ } else if(node[0].getKind() == kind::TCLOSURE) {
+ return RewriteResponse(REWRITE_AGAIN, node[0]);
+ } else if(node[0].getKind() != kind::TCLOSURE) {
+ Trace("sets-postrewrite") << "Sets::postRewrite returning " << node << std::endl;
+ return RewriteResponse(REWRITE_DONE, node);
+ }
+ break;
+ }
+
default:
break;
}//switch(node.getKind())
@@ -363,180 +511,6 @@ RewriteResponse TheorySetsRewriter::preRewrite(TNode node) {
return RewriteResponse(REWRITE_DONE, node);
}
-Node TheorySetsRewriter::rewriteSet( Node s ) {
- Trace("sets-rewrite-debug") << "Rewrite set : " << s << std::endl;
- Node empSet = NodeManager::currentNM()->mkConst(EmptySet(NodeManager::currentNM()->toType(s.getType())));
- bool success;
- do{
- success = false;
- std::map< Node, bool > ca;
- Node ss = rewriteSet( s, ca, empSet );
- if( ss!=s ){
- Assert( !ss.isNull() );
- Trace("sets-rewrite") << "Rewrite set : " << s << std::endl;
- Trace("sets-rewrite") << "........got : " << ss << std::endl;
- success = true;
- s = ss;
- }
- }while( success );
- return s;
-}
-
-Node TheorySetsRewriter::rewriteSet( Node s, std::map< Node, bool >& ca, Node empSet ) {
- if( s.getKind()!=kind::UNION && s.getKind()!=kind::INTERSECTION && s.getKind()!=kind::SETMINUS ){
- std::map< Node, bool >::iterator it = ca.find( s );
- if( it==ca.end() ){
- return s;
- }else if( it->second ){
- return Node::null();
- }else{
- return empSet;
- }
- }else{
- Trace("sets-rewrite-debug") << "Get components : " << s << std::endl;
- std::map< Node, bool > c;
- bool pol = s.getKind()!=kind::UNION;
- if( pol ){
- //copy current components
- for( std::map< Node, bool >::iterator it = ca.begin(); it != ca.end(); ++it ){
- c[it->first] = it->second;
- }
- }
- if( collectSetComponents( s, c, pol ) ){
- if( Trace.isOn("sets-rewrite-debug") ){
- Trace("sets-rewrite-debug") << " got components : " << std::endl;
- for( std::map< Node, bool >::iterator it = c.begin(); it != c.end(); ++it ){
- Trace("sets-rewrite-debug") << " " << it->first << " -> " << it->second << std::endl;
- }
- }
-
- //simplify components based on what is asserted in ca, recursively
- std::map< Node, bool > nc;
- if( pol ){
- //copy map
- for( std::map< Node, bool >::iterator it = c.begin(); it != c.end(); ++it ){
- nc[it->first] = it->second;
- }
- //rewrite each new component based on current assertions
- for( std::map< Node, bool >::iterator it = c.begin(); it != c.end(); ++it ){
- if( ca.find( it->first )==ca.end() ){
- nc.erase( it->first );
- Node prev = it->first;
- //only rewrite positive components here
- Node ss = it->second ? rewriteSet( it->first, nc, empSet ) : it->first;
- if( prev!=ss ){
- Trace("sets-rewrite-debug") << " simplify component : " << prev << "..." << ss << std::endl;
- }
- if( ss==empSet ){
- Trace("sets-rewrite-debug") << " return singularity " << ss << std::endl;
- return ss;
- }else if( !ss.isNull() ){
- std::map< Node, bool >::iterator itc = nc.find( ss );
- if( itc==nc.end() ){
- nc[ss] = it->second;
- }else if( it->second!=itc->second ){
- Trace("sets-rewrite-debug") << "...conflict, return empty set." << std::endl;
- return empSet;
- }
- }
- }
- }
- }else{
- for( std::map< Node, bool >::iterator it = c.begin(); it != c.end(); ++it ){
- Node prev = it->first;
- Node ss = rewriteSet( it->first, ca, empSet );
- if( prev!=ss ){
- Trace("sets-rewrite-debug") << " simplify component : " << prev << "..." << ss << std::endl;
- }
- if( ss.isNull() ){
- Trace("sets-rewrite-debug") << " return singularity " << ss << std::endl;
- return ss;
- }else if( ss!=empSet ){
- std::map< Node, bool >::iterator itc = nc.find( ss );
- if( itc==nc.end() ){
- nc[ss] = it->second;
- }else if( it->second!=itc->second ){
- Trace("sets-rewrite-debug") << "...conflict, return complete set." << std::endl;
- return Node::null();
- }
- }
- }
- }
-
-
- //construct sorted lists of positive, negative components
- std::vector< Node > comp[2];
- for( std::map< Node, bool >::iterator it = nc.begin(); it != nc.end(); ++it ){
- if( !pol || ca.find( it->first )==ca.end() ){
- comp[ ( it->second==pol ) ? 0 : 1 ].push_back( it->first );
- }
- }
- //construct normalized set
- Node curr;
- for( unsigned i=0; i<2; i++ ){
- if( comp[i].size()>1 ){
- std::sort( comp[i].begin(), comp[i].end() );
- }
- if( i==0 ){
- if( comp[i].empty() ){
- Trace("sets-rewrite-debug") << "...return trivial set (no components)." << std::endl;
- if( pol ){
- return Node::null();
- }else{
- return empSet;
- }
- }else{
- curr = comp[i][0];
- for( unsigned j=1; j<comp[i].size(); j++ ){
- curr = NodeManager::currentNM()->mkNode( pol ? kind::INTERSECTION : kind::UNION, curr, comp[i][j] );
- }
- }
- }else if( i==1 ){
- if( !comp[i].empty() ){
- Assert( pol );
- Node rem = comp[i][0];
- for( unsigned j=1; j<comp[i].size(); j++ ){
- rem = NodeManager::currentNM()->mkNode( kind::UNION, rem, comp[i][j] );
- }
- curr = NodeManager::currentNM()->mkNode( kind::SETMINUS, curr, rem );
- }
- }
- }
- Trace("sets-rewrite-debug") << "...return " << curr << std::endl;
- return curr;
- }else{
- if( pol ){
- Trace("sets-rewrite-debug") << "...return empty set." << std::endl;
- return NodeManager::currentNM()->mkConst(EmptySet(NodeManager::currentNM()->toType(s.getType())));
- }else{
- Trace("sets-rewrite-debug") << "...return complete set." << std::endl;
- return Node::null();
- }
- }
- }
-}
-
-bool TheorySetsRewriter::collectSetComponents( Node n, std::map< Node, bool >& c, bool pol ) {
- std::map< Node, bool >::iterator itc = c.find( n );
- if( itc!=c.end() ){
- if( itc->second!=pol ){
- return false;
- }
- }else{
- if( ( pol && ( n.getKind()==kind::INTERSECTION || n.getKind()==kind::SETMINUS ) ) || ( !pol && n.getKind()==kind::UNION ) ){
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- bool newPol = ( i==1 && n.getKind()==kind::SETMINUS ) ? !pol : pol;
- if( !collectSetComponents( n[i], c, newPol ) ){
- return false;
- }
- }
- }else{
- c[n] = pol;
- }
- }
- return true;
-}
-
}/* CVC4::theory::sets namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/sets/theory_sets_rewriter.h b/src/theory/sets/theory_sets_rewriter.h
index 97c89520a..50128b63d 100644
--- a/src/theory/sets/theory_sets_rewriter.h
+++ b/src/theory/sets/theory_sets_rewriter.h
@@ -26,10 +26,6 @@ namespace theory {
namespace sets {
class TheorySetsRewriter {
-private:
- static bool collectSetComponents( Node n, std::map< Node, bool >& c, bool pol );
- static Node rewriteSet( Node s, std::map< Node, bool >& ca, Node empSet );
- static Node rewriteSet( Node s );
public:
/**
diff --git a/src/theory/sets/theory_sets_type_rules.h b/src/theory/sets/theory_sets_type_rules.h
index 7a8d7eed4..89d481746 100644
--- a/src/theory/sets/theory_sets_type_rules.h
+++ b/src/theory/sets/theory_sets_type_rules.h
@@ -105,7 +105,7 @@ struct MemberTypeRule {
throw TypeCheckingExceptionPrivate(n, "checking for membership in a non-set");
}
TypeNode elementType = n[0].getType(check);
- if(elementType != setType.getSetElementType()) {
+ if(!setType.getSetElementType().isSubtypeOf(elementType)) {
throw TypeCheckingExceptionPrivate(n, "member operating on sets of different types");
}
}
@@ -183,6 +183,97 @@ struct InsertTypeRule {
}
};/* struct InsertTypeRule */
+struct RelBinaryOperatorTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ Assert(n.getKind() == kind::PRODUCT ||
+ n.getKind() == kind::JOIN);
+
+ TypeNode firstRelType = n[0].getType(check);
+ TypeNode secondRelType = n[1].getType(check);
+ TypeNode resultType = firstRelType;
+
+ if(!firstRelType.isSet() || !secondRelType.isSet()) {
+ throw TypeCheckingExceptionPrivate(n, " set operator operates on non-sets");
+ }
+ if(!firstRelType[0].isTuple() || !secondRelType[0].isTuple()) {
+ throw TypeCheckingExceptionPrivate(n, " set operator operates on non-relations (sets of tuples)");
+ }
+
+ std::vector<TypeNode> newTupleTypes;
+ std::vector<TypeNode> firstTupleTypes = firstRelType[0].getTupleTypes();
+ std::vector<TypeNode> secondTupleTypes = secondRelType[0].getTupleTypes();
+
+ // JOIN is not allowed to apply on two unary sets
+ if( n.getKind() == kind::JOIN ) {
+ if((firstTupleTypes.size() == 1) && (secondTupleTypes.size() == 1)) {
+ throw TypeCheckingExceptionPrivate(n, " Join operates on two unary relations");
+ } else if(firstTupleTypes.back() != secondTupleTypes.front()) {
+ throw TypeCheckingExceptionPrivate(n, " Join operates on two non-joinable relations");
+ }
+ newTupleTypes.insert(newTupleTypes.end(), firstTupleTypes.begin(), firstTupleTypes.end()-1);
+ newTupleTypes.insert(newTupleTypes.end(), secondTupleTypes.begin()+1, secondTupleTypes.end());
+ }else if( n.getKind() == kind::PRODUCT ) {
+ newTupleTypes.insert(newTupleTypes.end(), firstTupleTypes.begin(), firstTupleTypes.end());
+ newTupleTypes.insert(newTupleTypes.end(), secondTupleTypes.begin(), secondTupleTypes.end());
+ }
+ resultType = nodeManager->mkSetType(nodeManager->mkTupleType(newTupleTypes));
+
+ return resultType;
+ }
+
+ inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
+ Assert(n.getKind() == kind::JOIN ||
+ n.getKind() == kind::PRODUCT);
+ return false;
+ }
+};/* struct RelBinaryOperatorTypeRule */
+
+struct RelTransposeTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ Assert(n.getKind() == kind::TRANSPOSE);
+ TypeNode setType = n[0].getType(check);
+ if(check && !setType.isSet() && !setType.getSetElementType().isTuple()) {
+ throw TypeCheckingExceptionPrivate(n, "relation transpose operats on non-relation");
+ }
+ std::vector<TypeNode> tupleTypes = setType[0].getTupleTypes();
+ std::reverse(tupleTypes.begin(), tupleTypes.end());
+ return nodeManager->mkSetType(nodeManager->mkTupleType(tupleTypes));
+ }
+
+ inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
+ return false;
+ }
+};/* struct RelTransposeTypeRule */
+
+struct RelTransClosureTypeRule {
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ Assert(n.getKind() == kind::TCLOSURE);
+ TypeNode setType = n[0].getType(check);
+ if(check) {
+ if(!setType.isSet() && !setType.getSetElementType().isTuple()) {
+ throw TypeCheckingExceptionPrivate(n, " transitive closure operates on non-relation");
+ }
+ std::vector<TypeNode> tupleTypes = setType[0].getTupleTypes();
+ if(tupleTypes.size() != 2) {
+ throw TypeCheckingExceptionPrivate(n, " transitive closure operates on non-binary relations");
+ }
+ if(tupleTypes[0] != tupleTypes[1]) {
+ throw TypeCheckingExceptionPrivate(n, " transitive closure operates on non-homogeneous binary relations");
+ }
+ }
+ return setType;
+ }
+
+ inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
+ Assert(n.getKind() == kind::TCLOSURE);
+ return false;
+ }
+};/* struct RelTransClosureTypeRule */
+
+
struct SetsProperties {
inline static Cardinality computeCardinality(TypeNode type) {
Assert(type.getKind() == kind::SET_TYPE);
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback