diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/clock_gettime.c | 2 | ||||
-rw-r--r-- | src/options/options_public_functions.cpp | 2 | ||||
-rw-r--r-- | src/options/sets_options | 8 | ||||
-rw-r--r-- | src/parser/cvc/Cvc.g | 5 | ||||
-rw-r--r-- | src/parser/smt2/smt2.cpp | 1 | ||||
-rw-r--r-- | src/printer/cvc/cvc_printer.cpp | 7 | ||||
-rw-r--r-- | src/printer/smt2/smt2_printer.cpp | 2 | ||||
-rw-r--r-- | src/smt/smt_engine_check_proof.cpp | 2 | ||||
-rw-r--r-- | src/theory/output_channel.h | 1 | ||||
-rw-r--r-- | src/theory/sets/card_unused_implementation.cpp | 312 | ||||
-rw-r--r-- | src/theory/sets/expr_patterns.h | 4 | ||||
-rw-r--r-- | src/theory/sets/kinds | 5 | ||||
-rw-r--r-- | src/theory/sets/theory_sets.cpp | 4 | ||||
-rw-r--r-- | src/theory/sets/theory_sets.h | 2 | ||||
-rw-r--r-- | src/theory/sets/theory_sets_private.cpp | 1197 | ||||
-rw-r--r-- | src/theory/sets/theory_sets_private.h | 95 | ||||
-rw-r--r-- | src/theory/sets/theory_sets_rewriter.cpp | 397 | ||||
-rw-r--r-- | src/theory/sets/theory_sets_rewriter.h | 4 | ||||
-rw-r--r-- | src/theory/sets/theory_sets_type_rules.h | 20 | ||||
-rw-r--r-- | src/theory/theory.cpp | 4 | ||||
-rw-r--r-- | src/theory/theory.h | 2 | ||||
-rw-r--r-- | src/theory/theory_engine.cpp | 1 | ||||
-rw-r--r-- | src/theory/theory_engine.h | 9 |
23 files changed, 2013 insertions, 73 deletions
diff --git a/src/lib/clock_gettime.c b/src/lib/clock_gettime.c index d9143a14f..9bd4eafe8 100644 --- a/src/lib/clock_gettime.c +++ b/src/lib/clock_gettime.c @@ -16,7 +16,7 @@ ** OS X). **/ -#warning "TODO(taking): Make lib/clock_gettime.h cvc4_private.h again." +// #warning "TODO(taking): Make lib/clock_gettime.h cvc4_private.h again." #include "lib/clock_gettime.h" diff --git a/src/options/options_public_functions.cpp b/src/options/options_public_functions.cpp index 0ee9cc21a..8f3a63175 100644 --- a/src/options/options_public_functions.cpp +++ b/src/options/options_public_functions.cpp @@ -204,7 +204,7 @@ std::ostream* Options::getOut(){ } std::ostream* Options::getOutConst() const{ -#warning "Remove Options::getOutConst" + // #warning "Remove Options::getOutConst" return (*this)[options::out]; } diff --git a/src/options/sets_options b/src/options/sets_options index 67bed5fe7..be945e4c9 100644 --- a/src/options/sets_options +++ b/src/options/sets_options @@ -17,4 +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 + endmodule diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g index 4a8f7eb7b..470fc5253 100644 --- a/src/parser/cvc/Cvc.g +++ b/src/parser/cvc/Cvc.g @@ -1985,6 +1985,11 @@ simpleTerm[CVC4::Expr& f] } } + /* set cardinality literal */ + | BAR BAR formula[f] { args.push_back(f); } BAR BAR + { f = MK_EXPR(kind::CARD, args[0]); + } + /* array literals */ | ARRAY_TOK /* { PARSER_STATE->pushScope(); } */ LPAREN restrictedType[t, CHECK_DECLARED] OF_TOK restrictedType[t2, CHECK_DECLARED] diff --git a/src/parser/smt2/smt2.cpp b/src/parser/smt2/smt2.cpp index 55fb4f60d..ebad90583 100644 --- a/src/parser/smt2/smt2.cpp +++ b/src/parser/smt2/smt2.cpp @@ -226,6 +226,7 @@ void Smt2::addTheory(Theory theory) { addOperator(kind::MEMBER, "member"); addOperator(kind::SINGLETON, "singleton"); addOperator(kind::INSERT, "insert"); + addOperator(kind::CARD, "card"); break; case THEORY_DATATYPES: diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp index 55e19510b..bc59e37ba 100644 --- a/src/printer/cvc/cvc_printer.cpp +++ b/src/printer/cvc/cvc_printer.cpp @@ -793,6 +793,13 @@ void CvcPrinter::toStream(std::ostream& out, TNode n, int depth, bool types, boo return; break; } + case kind::CARD: { + out << "||"; + toStream(out, n[0], depth, types, false); + out << "||"; + return; + break; + } // Quantifiers case kind::FORALL: diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp index 62153571c..4defc7691 100644 --- a/src/printer/smt2/smt2_printer.cpp +++ b/src/printer/smt2/smt2_printer.cpp @@ -977,7 +977,7 @@ void Smt2Printer::toStream(std::ostream& out, const Command* c, static std::string quoteSymbol(TNode n) { -#warning "check the old implementation. It seems off." + // #warning "check the old implementation. It seems off." std::stringstream ss; ss << language::SetLanguage(language::output::LANG_SMTLIB_V2_5); return CVC4::quoteSymbol(ss.str()); diff --git a/src/smt/smt_engine_check_proof.cpp b/src/smt/smt_engine_check_proof.cpp index a58102d86..5634a4651 100644 --- a/src/smt/smt_engine_check_proof.cpp +++ b/src/smt/smt_engine_check_proof.cpp @@ -22,7 +22,7 @@ #include <fstream> #include <string> -#warning "TODO: Why is lfsc's check.h being included like this?" +// #warning "TODO: Why is lfsc's check.h being included like this?" #include "check.h" #include "base/configuration_private.h" diff --git a/src/theory/output_channel.h b/src/theory/output_channel.h index da0b92ae8..639793c7f 100644 --- a/src/theory/output_channel.h +++ b/src/theory/output_channel.h @@ -142,7 +142,6 @@ public: return lemma(n, RULE_INVALID, removable, preprocess, sendAtoms); } - /** * Request a split on a new theory atom. This is equivalent to * calling lemma({OR n (NOT n)}). diff --git a/src/theory/sets/card_unused_implementation.cpp b/src/theory/sets/card_unused_implementation.cpp new file mode 100644 index 000000000..488ee1026 --- /dev/null +++ b/src/theory/sets/card_unused_implementation.cpp @@ -0,0 +1,312 @@ +// 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 index 768797ecf..32e77d8b8 100644 --- a/src/theory/sets/expr_patterns.h +++ b/src/theory/sets/expr_patterns.h @@ -54,6 +54,10 @@ 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 a43902b1b..14c87a947 100644 --- a/src/theory/sets/kinds +++ b/src/theory/sets/kinds @@ -12,7 +12,7 @@ rewriter ::CVC4::theory::sets::TheorySetsRewriter \ "theory/sets/theory_sets_rewriter.h" properties parametric -properties check propagate +properties check propagate presolve # constants constant EMPTYSET \ @@ -42,6 +42,7 @@ operator SUBSET 2 "subset predicate; first parameter a subset of second" operator MEMBER 2 "set membership predicate; first parameter a member of second" 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" typerule UNION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule typerule INTERSECTION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule @@ -51,11 +52,13 @@ typerule MEMBER ::CVC4::theory::sets::MemberTypeRule typerule SINGLETON ::CVC4::theory::sets::SingletonTypeRule typerule EMPTYSET ::CVC4::theory::sets::EmptySetTypeRule typerule INSERT ::CVC4::theory::sets::InsertTypeRule +typerule CARD ::CVC4::theory::sets::CardTypeRule construle UNION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule construle INTERSECTION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule construle SETMINUS ::CVC4::theory::sets::SetsBinaryOperatorTypeRule construle SINGLETON ::CVC4::theory::sets::SingletonTypeRule construle INSERT ::CVC4::theory::sets::InsertTypeRule +construle CARD ::CVC4::theory::sets::CardTypeRule endtheory diff --git a/src/theory/sets/theory_sets.cpp b/src/theory/sets/theory_sets.cpp index 36265134f..bdbc964c6 100644 --- a/src/theory/sets/theory_sets.cpp +++ b/src/theory/sets/theory_sets.cpp @@ -70,6 +70,10 @@ void TheorySets::preRegisterTerm(TNode node) { d_internal->preRegisterTerm(node); } +void TheorySets::presolve() { + d_internal->presolve(); +} + void TheorySets::propagate(Effort e) { d_internal->propagate(e); } diff --git a/src/theory/sets/theory_sets.h b/src/theory/sets/theory_sets.h index d5a965799..bbeaf4a4c 100644 --- a/src/theory/sets/theory_sets.h +++ b/src/theory/sets/theory_sets.h @@ -63,6 +63,8 @@ public: void preRegisterTerm(TNode node); + void presolve(); + void propagate(Effort); void setMasterEqualityEngine(eq::EqualityEngine* eq); diff --git a/src/theory/sets/theory_sets_private.cpp b/src/theory/sets/theory_sets_private.cpp index dbdec0cdc..a16e857dd 100644 --- a/src/theory/sets/theory_sets_private.cpp +++ b/src/theory/sets/theory_sets_private.cpp @@ -14,6 +14,7 @@ ** Sets theory implementation. **/ +#include <algorithm> #include "theory/sets/theory_sets_private.h" #include <boost/foreach.hpp> @@ -36,12 +37,15 @@ namespace sets { const char* element_of_str = " \u2208 "; +// Declaration of functions defined later in this CPP file +const std::set<TNode> getLeaves(map<TNode, set<TNode> >& edges, TNode node); + /**************************** TheorySetsPrivate *****************************/ /**************************** TheorySetsPrivate *****************************/ /**************************** TheorySetsPrivate *****************************/ void TheorySetsPrivate::check(Theory::Effort level) { - + d_newLemmaGenerated = false; while(!d_external.done() && !d_conflict) { // Get all the assertions Assertion assertion = d_external.get(); @@ -96,13 +100,17 @@ void TheorySetsPrivate::check(Theory::Effort level) { } if( (level == Theory::EFFORT_FULL || options::setsEagerLemmas() ) && !isComplete()) { - d_external.d_out->lemma(getLemma()); + lemma(getLemma(), SETS_LEMMA_OTHER); return; } + + //processCard(level); + processCard2(level); + // if we are here, there is no conflict and we are complete if(Debug.isOn("sets-scrutinize")) { d_scrutinize->postCheckInvariants(); } - + return; }/* TheorySetsPrivate::check() */ @@ -134,10 +142,23 @@ void TheorySetsPrivate::assertEquality(TNode fact, TNode reason, bool learnt) return; } + 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); } + // for cardinality + if(polarity && atom[0].getType().isSet()) { + d_graphMergesPending.push(make_pair(atom[0], atom[1])); + } }/* TheorySetsPrivate::assertEquality() */ @@ -365,11 +386,12 @@ void TheorySetsPrivate::doSettermPropagation(TNode x, TNode S) addToPending( MEMBER(x, S[0]) ); break; case kind::SETMINUS: // intentional fallthrough - case kind::INTERSECTION: 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"); } @@ -406,6 +428,33 @@ void TheorySetsPrivate::learnLiteral(TNode atom, bool polarity, Node reason) { }/*TheorySetsPrivate::learnLiteral(...)*/ +/************************ CardVar ************************/ + +Node TheorySetsPrivate::getCardVar(TNode n) { + NodeNodeHashMap::iterator it = d_setTermToCardVar.find(n); + if(it == d_setTermToCardVar.end()) { + 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::isCardVar(TNode n) { + NodeNodeHashMap::iterator it = d_cardVarToSetTerm.find(n); + return it != d_cardVarToSetTerm.end(); +} + + /************************ Sharing ************************/ /************************ Sharing ************************/ /************************ Sharing ************************/ @@ -765,11 +814,23 @@ Node TheorySetsPrivate::elementsToShape(set<Node> elements, TypeNode setType) co void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel) { - Debug("sets-model") << "[sets-model] collectModelInfo(..., fullModel=" + Trace("sets-model") << "[sets-model] collectModelInfo(..., fullModel=" << (fullModel ? "true)" : "false)") << std::endl; set<Node> terms; + NodeManager* nm = NodeManager::currentNM(); + + // // this is for processCard -- commenting out for now + // if(Debug.isOn("sets-card")) { + // for(typeof(d_cardTerms.begin()) 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(); } @@ -777,6 +838,23 @@ void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel) // Compute terms appearing assertions and shared terms d_external.computeRelevantTerms(terms); + //processCard2 begin + if(Debug.isOn("sets-card")) { + for(typeof(d_V.begin()) 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); @@ -789,10 +867,10 @@ void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel) settermElementsMap[S].insert(x); } if(Debug.isOn("sets-model-details")) { - vector<TNode> explanation; - d_equalityEngine.explainPredicate(n, true, explanation); 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; } @@ -804,9 +882,9 @@ void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel) ! it_eqclasses.isFinished() ; ++it_eqclasses) { TNode n = (*it_eqclasses); vector<TNode> explanation; - d_equalityEngine.explainPredicate(n, false, 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; } @@ -838,16 +916,74 @@ void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel) } } - 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; + 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(typeof(d_V.begin()) 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 + + 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); + } + } + 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); @@ -921,20 +1057,44 @@ Node mkAnd(const std::vector<TNode>& conjunctions) { TheorySetsPrivate::Statistics::Statistics() : - d_getModelValueTime("theory::sets::getModelValueTime") + d_getModelValueTime("theory::sets::getModelValueTime") + , d_mergeTime("theory::sets::merge_nodes::time") + , d_processCard2Time("theory::sets::processCard2::time") , d_memberLemmas("theory::sets::lemmas::member", 0) , d_disequalityLemmas("theory::sets::lemmas::disequality", 0) + , d_numVertices("theory::sets::vertices", 0) + , d_numVerticesMax("theory::sets::vertices-max", 0) + , d_numMergeEq1or2("theory::sets::merge1or2", 0) + , d_numMergeEq3("theory::sets::merge3", 0) + , d_numLeaves("theory::sets::leaves", 0) + , d_numLeavesMax("theory::sets::leaves-max", 0) { smtStatisticsRegistry()->registerStat(&d_getModelValueTime); + smtStatisticsRegistry()->registerStat(&d_mergeTime); + smtStatisticsRegistry()->registerStat(&d_processCard2Time); smtStatisticsRegistry()->registerStat(&d_memberLemmas); smtStatisticsRegistry()->registerStat(&d_disequalityLemmas); + smtStatisticsRegistry()->registerStat(&d_numVertices); + smtStatisticsRegistry()->registerStat(&d_numVerticesMax); + smtStatisticsRegistry()->registerStat(&d_numMergeEq1or2); + smtStatisticsRegistry()->registerStat(&d_numMergeEq3); + smtStatisticsRegistry()->registerStat(&d_numLeaves); + smtStatisticsRegistry()->registerStat(&d_numLeavesMax); } TheorySetsPrivate::Statistics::~Statistics() { smtStatisticsRegistry()->unregisterStat(&d_getModelValueTime); + smtStatisticsRegistry()->unregisterStat(&d_mergeTime); + smtStatisticsRegistry()->unregisterStat(&d_processCard2Time); smtStatisticsRegistry()->unregisterStat(&d_memberLemmas); smtStatisticsRegistry()->unregisterStat(&d_disequalityLemmas); + smtStatisticsRegistry()->unregisterStat(&d_numVertices); + smtStatisticsRegistry()->unregisterStat(&d_numVerticesMax); + smtStatisticsRegistry()->unregisterStat(&d_numMergeEq1or2); + smtStatisticsRegistry()->unregisterStat(&d_numMergeEq3); + smtStatisticsRegistry()->unregisterStat(&d_numLeaves); + smtStatisticsRegistry()->unregisterStat(&d_numLeavesMax); } @@ -961,9 +1121,10 @@ void TheorySetsPrivate::registerReason(TNode reason, bool save) if(save) d_nodeSaver.insert(reason); if(reason.getKind() == kind::AND) { - Assert(reason.getNumChildren() == 2); - registerReason(reason[0], false); - registerReason(reason[1], false); + //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) { @@ -1025,7 +1186,8 @@ void TheorySetsPrivate::addToPending(Node n) { << std::endl; ++d_statistics.d_memberLemmas; d_pending.push(n); - d_external.d_out->splitLemma(getLemma()); + lemma(getLemma(), SETS_LEMMA_MEMBER); + // d_external.d_out->splitLemma(); Assert(isComplete()); } else { @@ -1035,7 +1197,8 @@ void TheorySetsPrivate::addToPending(Node n) { Assert(n.getKind() == kind::EQUAL); ++d_statistics.d_disequalityLemmas; d_pendingDisequal.push(n); - d_external.d_out->splitLemma(getLemma()); + lemma(getLemma(), SETS_LEMMA_DISEQUAL); + // d_external.d_out->splitLemma(); Assert(isComplete()); } @@ -1076,7 +1239,13 @@ Node TheorySetsPrivate::getLemma() { Node x = NodeManager::currentNM()->mkSkolem("sde_", elementType); Node l1 = MEMBER(x, n[0]), l2 = MEMBER(x, n[1]); - lemma = OR(n, AND(l1, NOT(l2)), AND(NOT(l1), l2)); + 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 @@ -1096,6 +1265,8 @@ TheorySetsPrivate::TheorySetsPrivate(TheorySets& external, 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), @@ -1105,7 +1276,24 @@ TheorySetsPrivate::TheorySetsPrivate(TheorySets& external, d_modelCache(c), d_ccg_i(c), d_ccg_j(c), - d_scrutinize(NULL) + 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); @@ -1116,6 +1304,9 @@ TheorySetsPrivate::TheorySetsPrivate(TheorySets& external, 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); } @@ -1230,6 +1421,30 @@ Node TheorySetsPrivate::explain(TNode literal) return mkAnd(assumptions); } +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; +} void TheorySetsPrivate::preRegisterTerm(TNode node) { @@ -1245,6 +1460,11 @@ void TheorySetsPrivate::preRegisterTerm(TNode node) // TODO: what's the point of this 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); @@ -1253,9 +1473,38 @@ void TheorySetsPrivate::preRegisterTerm(TNode node) 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)); + } } +void TheorySetsPrivate::presolve() { + + for(typeof(d_termInfoManager->d_terms.begin()) 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(typeof(d_relTerms.begin()) it = d_relTerms.begin(); + it != d_relTerms.end(); ++it ) { + Trace("sets-relterms") << (*it) << ", "; + } + Trace("sets-relterms") << "\n"; + } + +} /**************************** eq::NotifyClass *****************************/ /**************************** eq::NotifyClass *****************************/ @@ -1289,7 +1538,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) { + 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)) ); @@ -1408,7 +1657,12 @@ void TheorySetsPrivate::TermInfoManager::addTerm(TNode n) { 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)); + } typeof(d_info.begin()) ita = d_info.find(d_eqEngine->getRepresentative(n[i])); Assert(ita != d_info.end()); @@ -1576,6 +1830,907 @@ Node TheorySetsPrivate::TermInfoManager::getModelValue(TNode n) return v; } + + + +/********************** Cardinality ***************************/ +/********************** Cardinality ***************************/ +/********************** Cardinality ***************************/ + +void TheorySetsPrivate::enableCard() +{ + 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(typeof(d_termInfoManager->d_terms.begin()) 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(typeof(parentList->begin()) 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(typeof(d_processedCardPairs.begin()) 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(typeof(edgesFd.begin()) it = edgesFd.begin(); + it != edgesFd.end(); ++it) { + Debug("sets-card-graph") << "[sets-card-graph] " << (it->first) << std::endl; + for(typeof( (it->second).begin()) 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(typeof(edgesBk.begin()) it = edgesBk.begin(); + it != edgesBk.end(); ++it) { + Debug("sets-card-graph") << "[sets-card-graph] " << (it->first) << std::endl; + for(typeof( (it->second).begin()) jt = (it->second).begin(); + jt != (it->second).end(); ++jt) { + Debug("sets-card-graph") << "[sets-card-graph] " << (*jt) << std::endl; + } + } + } + + + + leaves.clear(); + + for(typeof(d_processedCardTerms.begin()) 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); +} + +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) +{ + 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(typeof(d_V.begin()) 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() { + std::string tag = "sets-graph"; + if(Trace.isOn("sets-graph")) { + Trace(tag) << "[sets-graph] Graph : " << std::endl; + for(typeof(d_V.begin()) 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(typeof(d_V.begin()) it = d_V.begin(); it != d_V.end(); ++it) { + TNode v = *it; + if(d_E.find(v) != d_E.end()) { + BOOST_FOREACH(TNode w, d_E[v].get()) { + //oss << v.getId() << " -> " << w.getId() << "; "; + oss << "\"" << v << "\" -> \"" << w << "\"; "; + } + } else { + oss << "\"" << v << "\";"; + } + } + 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(typeof(d_V.begin()) 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(typeof(leaves.begin()) 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; + +} + +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(); + + // Introduce + 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; + } + + 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(typeof(d_V.begin()) 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; + } + } + + // Elements being either equal or disequal [Members Arrangement rule] + Trace("sets-card") << "[sets-card] Processing elements equality/disequal to each other" << std::endl; + for(typeof(leaves.begin()) 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(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)); + 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(typeof(leaves.begin()) 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(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, *it)) ); + 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, *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 2be77a831..e14efd7a4 100644 --- a/src/theory/sets/theory_sets_private.h +++ b/src/theory/sets/theory_sets_private.h @@ -66,6 +66,8 @@ public: void preRegisterTerm(TNode node); + void presolve(); + void propagate(Theory::Effort); private: @@ -74,8 +76,16 @@ private: class Statistics { public: TimerStat d_getModelValueTime; + TimerStat d_mergeTime; + TimerStat d_processCard2Time; IntStat d_memberLemmas; IntStat d_disequalityLemmas; + IntStat d_numVertices; + IntStat d_numVerticesMax; + IntStat d_numMergeEq1or2; + IntStat d_numMergeEq3; + IntStat d_numLeaves; + IntStat d_numLeavesMax; Statistics(); ~Statistics(); @@ -113,6 +123,20 @@ 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; @@ -141,6 +165,25 @@ private: }; 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) { @@ -199,6 +242,58 @@ private: 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(); + 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; };/* class TheorySetsPrivate */ diff --git a/src/theory/sets/theory_sets_rewriter.cpp b/src/theory/sets/theory_sets_rewriter.cpp index 360957d05..8dbca1e73 100644 --- a/src/theory/sets/theory_sets_rewriter.cpp +++ b/src/theory/sets/theory_sets_rewriter.cpp @@ -16,6 +16,8 @@ #include "theory/sets/theory_sets_rewriter.h" #include "theory/sets/normal_form.h" +#include "expr/attribute.h" +#include "options/sets_options.h" namespace CVC4 { namespace theory { @@ -24,6 +26,101 @@ namespace sets { typedef std::set<TNode> Elements; typedef std::hash_map<TNode, Elements, TNodeHashFunction> SettermElementsMap; +struct FlattenedNodeTag {}; +typedef expr::Attribute<FlattenedNodeTag, bool> flattened; + + +/** + * flattenNode looks for children of same kind, and if found merges + * them into the parent. + * + * It simultaneously handles a couple of other optimizations: + * - trivialNode - if found during exploration, return that node itself + * (like in case of OR, if "true" is found, makes sense to replace + * whole formula with "true") + * - skipNode - as name suggests, skip them + * (like in case of OR, you may want to skip any "false" nodes found) + * + * Use a null node if you want to ignore any of the optimizations. + */ +RewriteResponse flattenNode(TNode n, TNode trivialNode, TNode skipNode) +{ + if(n.hasAttribute(flattened()) && n.getAttribute(flattened())) { + return RewriteResponse(REWRITE_DONE, n); + } + + typedef std::hash_set<TNode, TNodeHashFunction> node_set; + + node_set visited; + visited.insert(skipNode); + + std::vector<TNode> toProcess; + toProcess.push_back(n); + + Kind k = n.getKind(); + typedef std::vector<TNode> ChildList; + ChildList childList; //TNode should be fine, since 'n' is still there + + Debug("sets-rewrite-flatten") << "[sets-rewrite-flatten] " << n << std::endl; + for (unsigned i = 0; i < toProcess.size(); ++ i) { + TNode current = toProcess[i]; + Debug("sets-rewrite-flatten") << "[sets-rewrite-flatten] > Processing " << current << std::endl; + for(unsigned j = 0, j_end = current.getNumChildren(); j < j_end; ++ j) { + TNode child = current[j]; + if(visited.find(child) != visited.end()) { + continue; + } else if(child == trivialNode) { + return RewriteResponse(REWRITE_DONE, trivialNode); + } else { + visited.insert(child); + if(child.getKind() == k) { + toProcess.push_back(child); + } else { + childList.push_back(child); + } + } + } + } + if (childList.size() == 0) return RewriteResponse(REWRITE_DONE, skipNode); + if (childList.size() == 1) return RewriteResponse(REWRITE_AGAIN, childList[0]); + + sort(childList.begin(), childList.end()); + + /* Make sure we are under number of children possible in a node */ + NodeManager* nodeManager = NodeManager::currentNM(); + static const unsigned MAX_CHILDREN = (1u << __CVC4__EXPR__NODE_VALUE__NBITS__NCHILDREN ) - 1; + AlwaysAssert(childList.size() < MAX_CHILDREN, "do not support formulas this big"); + + ChildList::iterator cur = childList.begin(), next, en = childList.end(); + Node ret = (*cur); + ++cur; + while( cur != en ) { + ret = nodeManager->mkNode(k, ret, *cur); + ret.setAttribute(flattened(), true); + ++cur; + } + Trace("sets-postrewrite") << "flatten Sets::postRewrite returning " << ret << std::endl; + if(ret != n) { + return RewriteResponse(REWRITE_AGAIN, ret); // again for constants + } else { + return RewriteResponse(REWRITE_DONE, ret); + } + // if (childList.size() < MAX_CHILDREN) { + // Node retNode = nodeManager->mkNode(k, childList); + // return RewriteResponse(REWRITE_DONE, retNode); + // } else { + // Assert(childList.size() < size_t(MAX_CHILDREN) * size_t(MAX_CHILDREN) ); + // NodeBuilder<> nb(k); + // ChildList::iterator cur = childList.begin(), next, en = childList.end(); + // while( cur != en ) { + // next = min(cur + MAX_CHILDREN, en); + // nb << (nodeManager->mkNode(k, ChildList(cur, next) )); + // cur = next; + // } + // return RewriteResponse(REWRITE_DONE, nb.constructNode()); + // } +} + bool checkConstantMembership(TNode elementTerm, TNode setTerm) { if(setTerm.getKind() == kind::EMPTYSET) { @@ -101,57 +198,92 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) { }//kind::IFF case kind::SETMINUS: { - 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( 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); + } } break; - }//kind::INTERSECION + }//kind::SETMINUS case kind::INTERSECTION: { - 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( 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); + } } break; }//kind::INTERSECION case kind::UNION: { // NOTE: case where it is CONST is taken care of at the top - if(node[0] == node[1]) { + if( options::setsAggRewrite() ){ + Node newNode = rewriteSet( node ); + if( newNode!=node ){ + return RewriteResponse(REWRITE_DONE, newNode); + } + }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) { @@ -168,7 +300,7 @@ 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]) { + }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); @@ -176,6 +308,13 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) { break; }//kind::UNION + case kind::CARD: { + if(node[0].isConst()) { + std::set<Node> elements = NormalForm::getElementsFromNormalConstant(node[0]); + return RewriteResponse(REWRITE_DONE, nm->mkConst(Rational(elements.size()))); + } + } + default: break; }//switch(node.getKind()) @@ -224,6 +363,180 @@ 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 50128b63d..97c89520a 100644 --- a/src/theory/sets/theory_sets_rewriter.h +++ b/src/theory/sets/theory_sets_rewriter.h @@ -26,6 +26,10 @@ 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 8c5f37591..7a8d7eed4 100644 --- a/src/theory/sets/theory_sets_type_rules.h +++ b/src/theory/sets/theory_sets_type_rules.h @@ -136,6 +136,25 @@ struct EmptySetTypeRule { } };/* struct EmptySetTypeRule */ +struct CardTypeRule { + inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) + throw (TypeCheckingExceptionPrivate, AssertionException) { + Assert(n.getKind() == kind::CARD); + TypeNode setType = n[0].getType(check); + if( check ) { + if(!setType.isSet()) { + throw TypeCheckingExceptionPrivate(n, "cardinality operates on a set, non-set object found"); + } + } + return nodeManager->integerType(); + } + + inline static bool computeIsConst(NodeManager* nodeManager, TNode n) { + Assert(n.getKind() == kind::CARD); + return false; + } +};/* struct CardTypeRule */ + struct InsertTypeRule { inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check) throw (TypeCheckingExceptionPrivate, AssertionException) { @@ -164,7 +183,6 @@ struct InsertTypeRule { } };/* struct InsertTypeRule */ - struct SetsProperties { inline static Cardinality computeCardinality(TypeNode type) { Assert(type.getKind() == kind::SET_TYPE); diff --git a/src/theory/theory.cpp b/src/theory/theory.cpp index e05363bf2..7e2b6df55 100644 --- a/src/theory/theory.cpp +++ b/src/theory/theory.cpp @@ -231,7 +231,7 @@ void Theory::collectTerms(TNode n, set<Node>& termSet) const } -void Theory::computeRelevantTerms(set<Node>& termSet) const +void Theory::computeRelevantTerms(set<Node>& termSet, bool includeShared) const { // Collect all terms appearing in assertions context::CDList<Assertion>::const_iterator assert_it = facts_begin(), assert_it_end = facts_end(); @@ -239,6 +239,8 @@ void Theory::computeRelevantTerms(set<Node>& termSet) const collectTerms(*assert_it, termSet); } + if (!includeShared) return; + // Add terms that are shared terms context::CDList<TNode>::const_iterator shared_it = shared_terms_begin(), shared_it_end = shared_terms_end(); for (; shared_it != shared_it_end; ++shared_it) { diff --git a/src/theory/theory.h b/src/theory/theory.h index a08463b24..382d4cf65 100644 --- a/src/theory/theory.h +++ b/src/theory/theory.h @@ -237,7 +237,7 @@ protected: * termSet. This is used by collectModelInfo to delimit the set of * terms that should be used when constructing a model */ - void computeRelevantTerms(std::set<Node>& termSet) const; + void computeRelevantTerms(std::set<Node>& termSet, bool includeShared = true) const; /** * Construct a Theory. diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp index 11f736e83..f2231ff7a 100644 --- a/src/theory/theory_engine.cpp +++ b/src/theory/theory_engine.cpp @@ -347,6 +347,7 @@ void TheoryEngine::check(Theory::Effort effort) { if (theory::TheoryTraits<THEORY>::hasCheck && d_logicInfo.isTheoryEnabled(THEORY)) { \ theoryOf(THEORY)->check(effort); \ if (d_inConflict) { \ + Debug("conflict") << THEORY << " in conflict. " << std::endl; \ break; \ } \ } diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h index e675af3ec..db94edd7c 100644 --- a/src/theory/theory_engine.h +++ b/src/theory/theory_engine.h @@ -297,8 +297,15 @@ class TheoryEngine { return d_engine->lemma(lemma, rule, false, removable, preprocess, sendAtoms ? d_theory : theory::THEORY_LAST, d_theory); } + /*theory::LemmaStatus preservedLemma(TNode lemma, bool removable = false, bool preprocess = false) throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException, LogicException) { + Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::preservedLemma(" << lemma << ")" << std::endl; + ++ d_statistics.lemmas; + d_engine->d_outputChannelUsed = true; + return d_engine->lemma(lemma, false, removable, preprocess, d_theory); + }*/ + theory::LemmaStatus splitLemma(TNode lemma, bool removable = false) throw(TypeCheckingExceptionPrivate, AssertionException, UnsafeInterruptException) { - Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma(" << lemma << ")" << std::endl; + Trace("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::splitLemma(" << lemma << ")" << std::endl; ++ d_statistics.lemmas; d_engine->d_outputChannelUsed = true; return d_engine->lemma(lemma, RULE_SPLIT, false, removable, false, d_theory, d_theory); |