From 031722bee8682005bd4c8700ef78b5f893fc48fe Mon Sep 17 00:00:00 2001 From: ajreynol Date: Wed, 26 Oct 2016 16:23:58 -0500 Subject: [PATCH] New implementation of sets+cardinality. Merge Paul Meng's relation solver as extension of sets solver, add regressions. --- src/Makefile.am | 6 +- src/options/sets_options | 6 +- src/parser/cvc/Cvc.g | 47 +- src/printer/cvc/cvc_printer.cpp | 20 +- src/smt/smt_engine.cpp | 4 +- .../sets/card_unused_implementation.cpp | 312 -- src/theory/sets/expr_patterns.h | 63 - src/theory/sets/kinds | 16 + src/theory/sets/normal_form.h | 25 + src/theory/sets/rels_utils.h | 96 + src/theory/sets/scrutinize.h | 73 - src/theory/sets/term_info.h | 69 - src/theory/sets/theory_sets.cpp | 6 +- src/theory/sets/theory_sets.h | 3 + src/theory/sets/theory_sets_private.cpp | 4169 +++++++---------- src/theory/sets/theory_sets_private.h | 298 +- src/theory/sets/theory_sets_rels.cpp | 1907 ++++++++ src/theory/sets/theory_sets_rels.h | 260 + src/theory/sets/theory_sets_rewriter.cpp | 478 +- src/theory/sets/theory_sets_rewriter.h | 4 - src/theory/sets/theory_sets_type_rules.h | 93 +- test/Makefile.am | 1 + test/regress/regress0/Makefile.am | 2 +- test/regress/regress0/rels/Makefile | 8 + test/regress/regress0/rels/Makefile.am | 115 + test/regress/regress0/rels/addr_book_0.cvc | 49 + test/regress/regress0/rels/addr_book_1.cvc | 45 + test/regress/regress0/rels/addr_book_1_1.cvc | 45 + test/regress/regress0/rels/bv1-unit.cvc | 21 + test/regress/regress0/rels/bv1-unitb.cvc | 22 + test/regress/regress0/rels/bv1.cvc | 20 + test/regress/regress0/rels/bv1p-sat.cvc | 22 + test/regress/regress0/rels/bv1p.cvc | 22 + test/regress/regress0/rels/bv2.cvc | 20 + .../regress/regress0/rels/garbage_collect.cvc | 60 + .../regress0/rels/join-eq-structure-and.cvc | 26 + .../regress0/rels/join-eq-structure.cvc | 26 + .../regress0/rels/join-eq-structure_0_1.cvc | 26 + test/regress/regress0/rels/join-eq-u-sat.cvc | 22 + test/regress/regress0/rels/join-eq-u.cvc | 22 + .../regress0/rels/oneLoc_no_quant-int_0_1.cvc | 19 + test/regress/regress0/rels/prod-mod-eq.cvc | 26 + test/regress/regress0/rels/prod-mod-eq2.cvc | 26 + test/regress/regress0/rels/rel_1tup_0.cvc | 24 + test/regress/regress0/rels/rel_complex_0.cvc | 31 + test/regress/regress0/rels/rel_complex_1.cvc | 34 + test/regress/regress0/rels/rel_complex_3.cvc | 49 + test/regress/regress0/rels/rel_complex_4.cvc | 52 + test/regress/regress0/rels/rel_complex_5.cvc | 55 + test/regress/regress0/rels/rel_conflict_0.cvc | 10 + test/regress/regress0/rels/rel_join_0.cvc | 24 + test/regress/regress0/rels/rel_join_0_1.cvc | 27 + test/regress/regress0/rels/rel_join_1.cvc | 31 + test/regress/regress0/rels/rel_join_1_1.cvc | 31 + test/regress/regress0/rels/rel_join_2.cvc | 20 + test/regress/regress0/rels/rel_join_2_1.cvc | 20 + test/regress/regress0/rels/rel_join_3.cvc | 29 + test/regress/regress0/rels/rel_join_3_1.cvc | 29 + test/regress/regress0/rels/rel_join_4.cvc | 32 + test/regress/regress0/rels/rel_join_5.cvc | 19 + test/regress/regress0/rels/rel_join_6.cvc | 13 + test/regress/regress0/rels/rel_join_7.cvc | 26 + test/regress/regress0/rels/rel_mix_0_1.cvc | 30 + test/regress/regress0/rels/rel_pressure_0.cvc | 617 +++ test/regress/regress0/rels/rel_product_0.cvc | 20 + .../regress/regress0/rels/rel_product_0_1.cvc | 20 + test/regress/regress0/rels/rel_product_1.cvc | 20 + .../regress/regress0/rels/rel_product_1_1.cvc | 21 + test/regress/regress0/rels/rel_symbolic_1.cvc | 21 + .../regress0/rels/rel_symbolic_1_1.cvc | 20 + .../regress0/rels/rel_symbolic_2_1.cvc | 21 + .../regress0/rels/rel_symbolic_3_1.cvc | 21 + test/regress/regress0/rels/rel_tc_10_1.cvc | 18 + test/regress/regress0/rels/rel_tc_11.cvc | 18 + test/regress/regress0/rels/rel_tc_2_1.cvc | 28 + test/regress/regress0/rels/rel_tc_3.cvc | 22 + test/regress/regress0/rels/rel_tc_3_1.cvc | 18 + test/regress/regress0/rels/rel_tc_4.cvc | 19 + test/regress/regress0/rels/rel_tc_4_1.cvc | 10 + test/regress/regress0/rels/rel_tc_5_1.cvc | 9 + test/regress/regress0/rels/rel_tc_6.cvc | 9 + test/regress/regress0/rels/rel_tc_7.cvc | 10 + test/regress/regress0/rels/rel_tc_8.cvc | 10 + test/regress/regress0/rels/rel_tc_9_1.cvc | 23 + test/regress/regress0/rels/rel_tp_2.cvc | 10 + test/regress/regress0/rels/rel_tp_3_1.cvc | 14 + test/regress/regress0/rels/rel_tp_join_0.cvc | 32 + test/regress/regress0/rels/rel_tp_join_1.cvc | 32 + test/regress/regress0/rels/rel_tp_join_2.cvc | 19 + .../regress/regress0/rels/rel_tp_join_2_1.cvc | 19 + test/regress/regress0/rels/rel_tp_join_3.cvc | 28 + .../regress0/rels/rel_tp_join_eq_0.cvc | 28 + .../regress0/rels/rel_tp_join_int_0.cvc | 26 + .../regress0/rels/rel_tp_join_pro_0.cvc | 21 + .../regress0/rels/rel_tp_join_var_0.cvc | 28 + .../regress/regress0/rels/rel_transpose_0.cvc | 18 + .../regress/regress0/rels/rel_transpose_1.cvc | 12 + .../regress0/rels/rel_transpose_1_1.cvc | 14 + .../regress/regress0/rels/rel_transpose_3.cvc | 15 + .../regress/regress0/rels/rel_transpose_4.cvc | 13 + .../regress/regress0/rels/rel_transpose_5.cvc | 22 + .../regress/regress0/rels/rel_transpose_6.cvc | 24 + .../regress/regress0/rels/rel_transpose_7.cvc | 10 + test/regress/regress0/rels/set-strat.cvc | 24 + test/regress/regress0/rels/strat.cvc | 24 + test/regress/regress0/rels/strat_0_1.cvc | 24 + 106 files changed, 7155 insertions(+), 3463 deletions(-) delete mode 100644 src/theory/sets/card_unused_implementation.cpp delete mode 100644 src/theory/sets/expr_patterns.h create mode 100644 src/theory/sets/rels_utils.h delete mode 100644 src/theory/sets/scrutinize.h delete mode 100644 src/theory/sets/term_info.h create mode 100644 src/theory/sets/theory_sets_rels.cpp create mode 100644 src/theory/sets/theory_sets_rels.h create mode 100644 test/regress/regress0/rels/Makefile create mode 100644 test/regress/regress0/rels/Makefile.am create mode 100644 test/regress/regress0/rels/addr_book_0.cvc create mode 100644 test/regress/regress0/rels/addr_book_1.cvc create mode 100644 test/regress/regress0/rels/addr_book_1_1.cvc create mode 100644 test/regress/regress0/rels/bv1-unit.cvc create mode 100644 test/regress/regress0/rels/bv1-unitb.cvc create mode 100644 test/regress/regress0/rels/bv1.cvc create mode 100644 test/regress/regress0/rels/bv1p-sat.cvc create mode 100644 test/regress/regress0/rels/bv1p.cvc create mode 100644 test/regress/regress0/rels/bv2.cvc create mode 100644 test/regress/regress0/rels/garbage_collect.cvc create mode 100644 test/regress/regress0/rels/join-eq-structure-and.cvc create mode 100644 test/regress/regress0/rels/join-eq-structure.cvc create mode 100644 test/regress/regress0/rels/join-eq-structure_0_1.cvc create mode 100644 test/regress/regress0/rels/join-eq-u-sat.cvc create mode 100644 test/regress/regress0/rels/join-eq-u.cvc create mode 100644 test/regress/regress0/rels/oneLoc_no_quant-int_0_1.cvc create mode 100644 test/regress/regress0/rels/prod-mod-eq.cvc create mode 100644 test/regress/regress0/rels/prod-mod-eq2.cvc create mode 100644 test/regress/regress0/rels/rel_1tup_0.cvc create mode 100644 test/regress/regress0/rels/rel_complex_0.cvc create mode 100644 test/regress/regress0/rels/rel_complex_1.cvc create mode 100644 test/regress/regress0/rels/rel_complex_3.cvc create mode 100644 test/regress/regress0/rels/rel_complex_4.cvc create mode 100644 test/regress/regress0/rels/rel_complex_5.cvc create mode 100644 test/regress/regress0/rels/rel_conflict_0.cvc create mode 100644 test/regress/regress0/rels/rel_join_0.cvc create mode 100644 test/regress/regress0/rels/rel_join_0_1.cvc create mode 100644 test/regress/regress0/rels/rel_join_1.cvc create mode 100644 test/regress/regress0/rels/rel_join_1_1.cvc create mode 100644 test/regress/regress0/rels/rel_join_2.cvc create mode 100644 test/regress/regress0/rels/rel_join_2_1.cvc create mode 100644 test/regress/regress0/rels/rel_join_3.cvc create mode 100644 test/regress/regress0/rels/rel_join_3_1.cvc create mode 100644 test/regress/regress0/rels/rel_join_4.cvc create mode 100644 test/regress/regress0/rels/rel_join_5.cvc create mode 100644 test/regress/regress0/rels/rel_join_6.cvc create mode 100644 test/regress/regress0/rels/rel_join_7.cvc create mode 100644 test/regress/regress0/rels/rel_mix_0_1.cvc create mode 100644 test/regress/regress0/rels/rel_pressure_0.cvc create mode 100644 test/regress/regress0/rels/rel_product_0.cvc create mode 100644 test/regress/regress0/rels/rel_product_0_1.cvc create mode 100644 test/regress/regress0/rels/rel_product_1.cvc create mode 100644 test/regress/regress0/rels/rel_product_1_1.cvc create mode 100644 test/regress/regress0/rels/rel_symbolic_1.cvc create mode 100644 test/regress/regress0/rels/rel_symbolic_1_1.cvc create mode 100644 test/regress/regress0/rels/rel_symbolic_2_1.cvc create mode 100644 test/regress/regress0/rels/rel_symbolic_3_1.cvc create mode 100644 test/regress/regress0/rels/rel_tc_10_1.cvc create mode 100644 test/regress/regress0/rels/rel_tc_11.cvc create mode 100644 test/regress/regress0/rels/rel_tc_2_1.cvc create mode 100644 test/regress/regress0/rels/rel_tc_3.cvc create mode 100644 test/regress/regress0/rels/rel_tc_3_1.cvc create mode 100644 test/regress/regress0/rels/rel_tc_4.cvc create mode 100644 test/regress/regress0/rels/rel_tc_4_1.cvc create mode 100644 test/regress/regress0/rels/rel_tc_5_1.cvc create mode 100644 test/regress/regress0/rels/rel_tc_6.cvc create mode 100644 test/regress/regress0/rels/rel_tc_7.cvc create mode 100644 test/regress/regress0/rels/rel_tc_8.cvc create mode 100644 test/regress/regress0/rels/rel_tc_9_1.cvc create mode 100644 test/regress/regress0/rels/rel_tp_2.cvc create mode 100644 test/regress/regress0/rels/rel_tp_3_1.cvc create mode 100644 test/regress/regress0/rels/rel_tp_join_0.cvc create mode 100644 test/regress/regress0/rels/rel_tp_join_1.cvc create mode 100644 test/regress/regress0/rels/rel_tp_join_2.cvc create mode 100644 test/regress/regress0/rels/rel_tp_join_2_1.cvc create mode 100644 test/regress/regress0/rels/rel_tp_join_3.cvc create mode 100644 test/regress/regress0/rels/rel_tp_join_eq_0.cvc create mode 100644 test/regress/regress0/rels/rel_tp_join_int_0.cvc create mode 100644 test/regress/regress0/rels/rel_tp_join_pro_0.cvc create mode 100644 test/regress/regress0/rels/rel_tp_join_var_0.cvc create mode 100644 test/regress/regress0/rels/rel_transpose_0.cvc create mode 100644 test/regress/regress0/rels/rel_transpose_1.cvc create mode 100644 test/regress/regress0/rels/rel_transpose_1_1.cvc create mode 100644 test/regress/regress0/rels/rel_transpose_3.cvc create mode 100644 test/regress/regress0/rels/rel_transpose_4.cvc create mode 100644 test/regress/regress0/rels/rel_transpose_5.cvc create mode 100644 test/regress/regress0/rels/rel_transpose_6.cvc create mode 100644 test/regress/regress0/rels/rel_transpose_7.cvc create mode 100644 test/regress/regress0/rels/set-strat.cvc create mode 100644 test/regress/regress0/rels/strat.cvc create mode 100644 test/regress/regress0/rels/strat_0_1.cvc 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 types; + std::vector 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 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 >()); 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(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 l1_ancestors = getReachable(edgesBk, l1); -// std::set 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 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(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 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& 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 elements; + std::vector 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(true); - std::set 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::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 CDTNodeList; -typedef context::CDHashSet CDNodeSet; -typedef context::CDHashSet 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,1037 +22,1749 @@ #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 "; - -// Declaration of functions defined later in this CPP file -const std::set getLeaves(map >& 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(); - TNode fact = assertion.assertion; - - Debug("sets") << "\n\n[sets] TheorySetsPrivate::check(): processing " - << fact << std::endl; - - bool polarity = fact.getKind() != kind::NOT; - TNode atom = polarity ? fact : fact[0]; - - 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]); - } - } - } - - // 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()); - } - 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; - } - - if( (level == Theory::EFFORT_FULL || options::setsEagerLemmas() ) && !isComplete()) { - 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() */ - - -void TheorySetsPrivate::assertEquality(TNode fact, TNode reason, bool learnt) +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) { - 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; - } - - // 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; - } - - if(atom[0].getKind() == kind::CARD && isCardVar(atom[0])) { - NodeManager* nm = NodeManager::currentNM(); - Node emptySet = nm->mkConst(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); - } + d_rels = new TheorySetsRels(c, u, &d_equalityEngine, &d_conflict, external); - // 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() */ + d_true = NodeManager::currentNM()->mkConst( true ); + d_false = NodeManager::currentNM()->mkConst( false ); + d_zero = NodeManager::currentNM()->mkConst( Rational(0) ); + d_equalityEngine.addFunctionKind(kind::SINGLETON); + d_equalityEngine.addFunctionKind(kind::UNION); + d_equalityEngine.addFunctionKind(kind::INTERSECTION); + d_equalityEngine.addFunctionKind(kind::SETMINUS); -void TheorySetsPrivate::assertMemebership(TNode fact, TNode reason, bool learnt) -{ - Debug("sets-assert") << "\n[sets-assert] adding membership: " << fact - << ", " << reason - << ", " << learnt << std::endl; + d_equalityEngine.addFunctionKind(kind::MEMBER); + d_equalityEngine.addFunctionKind(kind::SUBSET); - bool polarity = fact.getKind() == kind::NOT ? false : true; - TNode atom = polarity ? fact : fact[0]; + // If cardinality is on. + d_equalityEngine.addFunctionKind(kind::CARD); - // fact already holds - if( holds(atom, polarity) ) { - Debug("sets-assert") << "[sets-assert] already present, skipping" << std::endl; - return; - } + d_card_enabled = false; - // assert fact & check for conflict - if(learnt) { - registerReason(reason, true); - } - d_equalityEngine.assertPredicate(atom, polarity, reason); +}/* TheorySetsPrivate::TheorySetsPrivate() */ - if(!d_equalityEngine.consistent()) { - Debug("sets-assert") << "[sets-assert] running into a conflict" << std::endl; - d_conflict = true; - return; +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() */ - // 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; - } - /** - * 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::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 ); } - } 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)) ); + } + //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; jmkNode( 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; } + d_rels->eqNotifyPostMerge( t1, t2 ); } +} - 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 - +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; + } + } +} - }//j loop +TheorySetsPrivate::EqcInfo::EqcInfo( context::Context* c ) : d_singleton( c ){ + +} -}/* TheorySetsPrivate::assertMemebership() */ +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; + } +} -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)); +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; } - return; - } - default: - Unhandled(); } +} - 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; +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(); } + } +} - // 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; +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 { - // 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( n.getKind()==kind::MEMBER ){ + if( ee_areEqual( n, polarity ? d_true : d_false ) ){ + return true; } - 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; + //check members cache + if( polarity && d_equalityEngine.hasTerm( n[1] ) ){ + Node r = d_equalityEngine.getRepresentative( n[1] ); + if( isMember( n[0], r ) ){ + return true; + } } - - // 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; + }else if( n.getKind()==kind::AND && n.getKind()==kind::OR ){ + bool conj = (n.getKind()==kind::AND)==polarity; + for( unsigned i=0; isecond; - } else { - NodeManager* nm = NodeManager::currentNM(); - Node cardVar = nm->mkSkolem("scv_", n.getType()); - d_setTermToCardVar[n] = cardVar; - d_cardVarToSetTerm[cardVar] = n; - return cardVar; } + return false; } - -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 ************************/ - -void TheorySetsPrivate::addSharedTerm(TNode n) { - Debug("sets") << "[sets] ThoerySetsPrivate::addSharedTerm( " << n << ")" << std::endl; - d_termInfoManager->addTerm(n); - d_equalityEngine.addTriggerTerm(n, THEORY_SETS); + +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]; + 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; + } } -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::const_iterator it = d_external.facts_begin(), it_end = d_external.facts_end(); - - typedef std::set TNodeSet; - - typedef std::map EqualityMap; - EqualityMap equalities; - - typedef std::set< std::pair > TNodePairSet; - TNodePairSet disequalities; - typedef std::map > MemberMap; - MemberMap members; - static std::map 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)); +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; imkNode( kind::IMPLIES, exp, fact ) ); + return true; } - } 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])]; + } + 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; } - 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])]; + 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 ); } - Trace(tag) << std::endl; + }else if( isSet ){ + d_set_eqc_list[eqc].push_back( n ); } + ++eqc_i; } - Trace(tag) << std::endl; + Trace("sets-eqc") << std::endl; + ++eqcs_i; } - for(TNodePairSet::const_iterator kt=disequalities.begin(); kt != disequalities.end(); ++kt){ - Trace(tag) << "NOT(t"< 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)] << ", "; + + flushLemmas( lemmas ); + if( !hasProcessed() ){ + if( Trace.isOn("sets-mem") ){ + for( unsigned i=0; i >::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 ); } } - 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)] << ", "; + } + }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; jsecond.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 + } } } - 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; +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; + } + } + } + } + } + } + } } + } + } +} - 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; +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; + } } - 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( !is_sat ){ + //try to make one of them empty + for( unsigned e=0; e<2; e++ ){ + } - 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; + } + */ + + 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; + } } - break; - default: - Unreachable(); } } } - Trace("sharing") << "TheorySetsPrivate::computeCareGraph(): size = " << edgesAddedCnt << std::endl; } -EqualityStatus TheorySetsPrivate::getEqualityStatus(TNode a, TNode b) { - Assert(d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b)); - if (d_equalityEngine.areEqual(a, b)) { - // The terms are implied to be equal - return EQUALITY_TRUE; - } - if (d_equalityEngine.areDisequal(a, b, false)) { - // The terms are implied to be dis-equal - return EQUALITY_FALSE; - } - Node aModelValue = d_external.d_valuation.getModelValue(a); - if(aModelValue.isNull()) { return EQUALITY_UNKNOWN; } - Node bModelValue = d_external.d_valuation.getModelValue(b); - if(bModelValue.isNull()) { return EQUALITY_UNKNOWN; } - if( aModelValue == bModelValue ) { - // The term are true in current model - return EQUALITY_TRUE_IN_MODEL; - } else { - return EQUALITY_FALSE_IN_MODEL; +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 >::iterator itn = d_nvar_sets.find( eqc ); + if( itn!=d_nvar_sets.end() ){ + for( unsigned j=0; jsecond.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 ); + } + } + } } - // } - // //TODO: can we be more precise sometimes? - // return EQUALITY_UNKNOWN; + Trace("sets") << "Done cardinality graph" << std::endl; } -/******************** Model generation ********************/ -/******************** 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()); +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; kmkNode( 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 ); } - 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(); +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 curr; + std::vector< Node > exp; + checkCardCyclesRec( set_eqc_tmp[i], curr, exp, lemmas ); + flushLemmas( lemmas ); + if( hasProcessed() ){ + return; } + } + Trace("sets") << "Done check cardinality cycles" << std::endl; +} - 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; +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; imkNode( 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; jsecond.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 card_parents; + std::vector< int > card_parent_ids; + //check if equal to a parent + for( unsigned e=0; e conc; + std::vector< int > sib_emp_indices; + if( is_union ){ + for( unsigned s=0; s " << 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::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 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; kmkConst(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)); +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=0; i-- ){ + checkNormalForm( d_set_eqc[i], intro_sets ); + if( hasProcessed() || !intro_sets.empty() ){ + return; } - return cur; } -} - -Node TheorySetsPrivate::elementsToShape(std::set elements, TypeNode setType) const -{ - NodeManager* nm = NodeManager::currentNM(); - - if(elements.size() == 0) { - return nm->mkConst(EmptySet(nm->toType(setType))); - } else { - std::set::const_iterator it = elements.begin(); - Node cur = SINGLETON(*it); - while( ++it != elements.end() ) { - cur = nm->mkNode(kind::UNION, cur, SINGLETON(*it)); + 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; ksecond.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 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]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::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; jsecond.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 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(); - } +void TheorySetsPrivate::checkMinCard( std::vector< Node >& lemmas ) { - // 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; + 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 ); } - } - } - //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 explanation; - d_equalityEngine.explainPredicate(n, true, explanation); - BOOST_FOREACH(TNode m, explanation) { - Debug("sets-model-details") << "[sets-model-details] >> " << m << std::endl; + for( std::map< Node, Node >::iterator itmm = itm->second.begin(); itmm != itm->second.end(); ++itmm ){ + /* + for( unsigned j=0; jsecond ) ){ + 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(Debug.isOn("sets-model-details")) { - for(eq::EqClassIterator it_eqclasses(d_trueNode, &d_equalityEngine); - ! it_eqclasses.isFinished() ; ++it_eqclasses) { - TNode n = (*it_eqclasses); - vector 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::flushLemmas( std::vector< Node >& lemmas ) { + //do lemmas + for( unsigned i=0; ilemma(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; } + }else{ + return n; } +} - // Assert equalities and disequalities to the model - m->assertEqualityEngine(&d_equalityEngine, &terms); +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; + } +} - // Loop over terms to collect set-terms for which we generate models - set settermsModEq; - BOOST_FOREACH(TNode term, terms) { - TNode n = term.getKind() == kind::NOT ? term[0] : term; +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; + } +} - Debug("sets-model-details") << "[sets-model-details] > " << n << std::endl; +bool TheorySetsPrivate::hasLemmaCached( Node lem ) { + return d_lemmas_produced.find(lem)!=d_lemmas_produced.end(); +} - if(n.getType().isSet()) { - n = d_equalityEngine.getRepresentative(n); - if( !n.isConst() ) { - settermsModEq.insert(n); - } - } +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; icheck(level); + } + Trace("sets-check") << "Sets finish Check effort " << level << std::endl; +}/* TheorySetsPrivate::check() */ + + +/************************ Sharing ************************/ +/************************ Sharing ************************/ +/************************ Sharing ************************/ - 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; +void TheorySetsPrivate::addSharedTerm(TNode n) { + Debug("sets") << "[sets] ThoerySetsPrivate::addSharedTerm( " << n << ")" << std::endl; + d_equalityEngine.addTriggerTerm(n, THEORY_SETS); +} + +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 > 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++; + } } } - } - - // 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 - - std::hash_map, 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(); - 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& cur = slackElements[setterm]; - for(int i = numElems; i < cardValInt; ++i) { - // slk = slack - cur.push_back(nm->mkSkolem("slk_", elementType)); + }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 ); + } + } + //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 ); + } + } + } + }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 ); + } + } + } } } +} - // 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 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); +void TheorySetsPrivate::computeCareGraph() { + 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; isecond.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; j0 ){ + //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 ); + } } - Trace("sets-model-card") << "[sets-model-card] " << setterm << " (after slacks): " << elements.size() << std::endl; + Trace("sets-cg-summary") << "...done, # pairs = " << n_pairs << 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); - } +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) { + Assert(d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b)); + if (d_equalityEngine.areEqual(a, b)) { + // The terms are implied to be equal + return EQUALITY_TRUE; + } + if (d_equalityEngine.areDisequal(a, b, false)) { + // The terms are implied to be dis-equal + return EQUALITY_FALSE; } - if(Trace.isOn("sets-checkmodel-ignore")) { - Trace("sets-checkmodel-ignore") << "[sets-checkmodel-ignore] checkPassed value was " << checkPassed << std::endl; + 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); + if(bModelValue.isNull()) { return EQUALITY_UNKNOWN; } + if( aModelValue == bModelValue ) { + // The term are true in current model + return EQUALITY_TRUE_IN_MODEL; } else { - Assert( checkPassed, - "THEORY_SETS check-model failed. Run with -d sets-model for details." ); + return EQUALITY_FALSE_IN_MODEL; } -#endif + */ + // } + // //TODO: can we be more precise sometimes? + // return EQUALITY_UNKNOWN; } -Node TheorySetsPrivate::getModelValue(TNode n) -{ - CodeTimer codeTimer(d_statistics.d_getModelValueTime); - return d_termInfoManager->getModelValue(n); +/******************** Model generation ********************/ +/******************** Model generation ********************/ +/******************** Model generation ********************/ + + +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); + + 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 ); + } + } + } + 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() <= LONG_MAX, "Exceeded LONG_MAX in sets model"); + unsigned vu = v.getConst().getNumerator().toUnsignedInt(); + Assert( els.size()<=vu ); + while( els.size()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; jassertEquality( eqc, rep, true ); + m->assertRepresentative( rep ); + } } /********************** 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& conjunctions) { Assert(conjunctions.size() > 0); std::set 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,427 +1823,107 @@ TheorySetsPrivate::Statistics::~Statistics() { smtStatisticsRegistry()->unregisterStat(&d_numLeavesMax); } +void TheorySetsPrivate::propagate(Theory::Effort effort) { -bool TheorySetsPrivate::present(TNode atom) { - return holds(atom) || holds(atom.notNode()); } +bool TheorySetsPrivate::propagate(TNode literal) { + Debug("sets-prop") << " propagate(" << literal << ")" << std::endl; + + // If already in conflict, no more propagation + if (d_conflict) { + Debug("sets-prop") << "TheoryUF::propagate(" << literal << "): already in conflict" << std::endl; + return false; + } -bool TheorySetsPrivate::holds(TNode atom, bool polarity) { - TNode polarity_atom = polarity ? d_trueNode : d_falseNode; + // Propagate out + bool ok = d_external.d_out->propagate(literal); + if (!ok) { + d_conflict = true; + } - Node atomModEq = NodeManager::currentNM()->mkNode - (atom.getKind(), d_equalityEngine.getRepresentative(atom[0]), - d_equalityEngine.getRepresentative(atom[1]) ); + return ok; +}/* TheorySetsPrivate::propagate(TNode) */ - d_equalityEngine.addTerm(atomModEq); - return d_equalityEngine.areEqual(atomModEq, polarity_atom); +void TheorySetsPrivate::setMasterEqualityEngine(eq::EqualityEngine* eq) { + d_equalityEngine.setMasterEqualityEngine(eq); } -void TheorySetsPrivate::registerReason(TNode reason, bool save) +void TheorySetsPrivate::conflict(TNode a, TNode b) { - 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 + if (a.getKind() == kind::CONST_BOOLEAN) { + d_conflictNode = explain(a.iffNode(b)); } else { - Unhandled(); + d_conflictNode = explain(a.eqNode(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; } -void TheorySetsPrivate::finishPropagation() +Node TheorySetsPrivate::explain(TNode literal) { - while(!d_conflict && !d_settermPropagationQueue.empty()) { - std::pair np = d_settermPropagationQueue.front(); - d_settermPropagationQueue.pop(); - doSettermPropagation(np.first, np.second); - } - while(!d_conflict && !d_propagationQueue.empty()) { - std::pair 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); + Debug("sets") << "TheorySetsPrivate::explain(" << literal << ")" + << std::endl; + + bool polarity = literal.getKind() != kind::NOT; + TNode atom = polarity ? literal : literal[0]; + std::vector assumptions; + + if(atom.getKind() == kind::EQUAL || atom.getKind() == kind::IFF) { + d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions); + } else if(atom.getKind() == kind::MEMBER) { + if( !d_equalityEngine.hasTerm(atom)) { + d_equalityEngine.addTerm(atom); } + d_equalityEngine.explainPredicate(atom, polarity, assumptions); + } else { + Debug("sets") << "unhandled: " << literal << "; (" << atom << ", " + << polarity << "); kind" << atom.getKind() << std::endl; + Unhandled(); } -} -void TheorySetsPrivate::addToPending(Node n) { - Debug("sets-pending") << "[sets-pending] addToPending " << n << std::endl; + return mkAnd(assumptions); +} - if(d_pendingEverInserted.find(n) != d_pendingEverInserted.end()) { - Debug("sets-pending") << "[sets-pending] \u2514 skipping " << n - << " as lemma already generated." << std::endl; - return; +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 + d_equalityEngine.addTriggerEquality(node); + break; + case kind::MEMBER: + // TODO: what's the point of this + d_equalityEngine.addTriggerPredicate(node); + break; + case kind::CARD: + d_equalityEngine.addTriggerTerm(node, THEORY_SETS); + break; + default: + //if( node.getType().isSet() ){ + // d_equalityEngine.addTriggerTerm(node, THEORY_SETS); + //}else{ + d_equalityEngine.addTerm(node); + //} + break; } +} - if(n.getKind() == kind::MEMBER) { - Node nRewritten = theory::Rewriter::rewrite(n); +void TheorySetsPrivate::presolve() { - 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(true)), - d_falseNode(NodeManager::currentNM()->mkConst(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) { - Debug("sets-prop") << " propagate(" << literal << ")" << std::endl; - - // If already in conflict, no more propagation - if (d_conflict) { - Debug("sets-prop") << "TheoryUF::propagate(" << literal << "): already in conflict" << std::endl; - return false; - } - - // Propagate out - bool ok = d_external.d_out->propagate(literal); - if (!ok) { - d_conflict = true; - } - - return ok; -}/* TheorySetsPrivate::propagate(TNode) */ - - -void TheorySetsPrivate::setMasterEqualityEngine(eq::EqualityEngine* eq) { - d_equalityEngine.setMasterEqualityEngine(eq); -} - - -void TheorySetsPrivate::conflict(TNode a, TNode b) -{ - if (a.getKind() == kind::CONST_BOOLEAN) { - d_conflictNode = explain(a.iffNode(b)); - } else { - d_conflictNode = explain(a.eqNode(b)); - } - d_external.d_out->conflict(d_conflictNode); - Debug("sets") << "[sets] conflict: " << a << " iff " << b - << ", explaination " << d_conflictNode << std::endl; - d_conflict = true; -} - -Node TheorySetsPrivate::explain(TNode literal) -{ - Debug("sets") << "TheorySetsPrivate::explain(" << literal << ")" - << std::endl; - - bool polarity = literal.getKind() != kind::NOT; - TNode atom = polarity ? literal : literal[0]; - std::vector assumptions; - - if(atom.getKind() == kind::EQUAL || atom.getKind() == kind::IFF) { - d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions); - } else if(atom.getKind() == kind::MEMBER) { - if( !d_equalityEngine.hasTerm(atom)) { - d_equalityEngine.addTerm(atom); - } - d_equalityEngine.explainPredicate(atom, polarity, assumptions); - } else { - Debug("sets") << "unhandled: " << literal << "; (" << atom << ", " - << polarity << "); kind" << atom.getKind() << std::endl; - 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; -} - -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 - d_equalityEngine.addTriggerEquality(node); - break; - case kind::MEMBER: - // 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); - } - - 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(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 *****************************/ -/**************************** eq::NotifyClass *****************************/ -/**************************** eq::NotifyClass *****************************/ +/**************************** eq::NotifyClass *****************************/ +/**************************** eq::NotifyClass *****************************/ +/**************************** eq::NotifyClass *****************************/ bool TheorySetsPrivate::NotifyClass::eqNotifyTriggerEquality(TNode equality, bool value) @@ -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 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) -{ - 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 - -} - -void TheorySetsPrivate::TermInfoManager::pushToSettermPropagationQueue -(TNode x, CDTNodeList* l, bool polarity) +void TheorySetsPrivate::NotifyClass::eqNotifyNewClass(TNode t) { - set 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 - } + Debug("sets-eq") << "[sets-eq] eqNotifyNewClass:" << " t = " << t << std::endl; + d_theory.eqNotifyNewClass(t); } -void TheorySetsPrivate::TermInfoManager::pushToSettermPropagationQueue -(CDTNodeList* l, TNode S, bool polarity) +void TheorySetsPrivate::NotifyClass::eqNotifyPreMerge(TNode t1, TNode t2) { - 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(); -} - -Node TheorySetsPrivate::TermInfoManager::getModelValue(TNode n) { - if (d_terms.find(n) == d_terms.end()) { - return Node(); - } - Assert(n.getType().isSet()); - std::set elements; - std::set elements_const; - Node S = d_eqEngine->getRepresentative(n); - context::CDHashMap::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::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; + Debug("sets-eq") << "[sets-eq] eqNotifyPreMerge:" << " t1 = " << t1 << " t2 = " << t2 << std::endl; + d_theory.eqNotifyPreMerge(t1, t2); } -/********************** 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(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, 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 >::const_iterator it = edgesFd.begin(); - it != edgesFd.end(); ++it) { - Debug("sets-card-graph") << "[sets-card-graph] " << (it->first) - << std::endl; - for (std::set::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 >::const_iterator it = edgesBk.begin(); - it != edgesBk.end(); ++it) { - Debug("sets-card-graph") << "[sets-card-graph] " << (it->first) - << std::endl; - for (std::set::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 getReachable(map >& edges, TNode node) { - Debug("sets-getreachable-debug") << "[sets-getreachable-debug] " << node << ":" << std::endl; - queue Q; - std::set 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::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 getLeaves(map >& edges, TNode node) { - Debug("sets-getreachable-debug") << "[sets-getreachable-debug] " << node << ":" << std::endl; - queue Q; - std::set ret; - std::set 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::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 a, vector b) - * get non empty leaves - * of a & b, for each internal node, there will be two parent nodes - * - * Introduce - * - */ - -void TheorySetsPrivate::add_edges(TNode source, TNode dest) { - vector V; - V.push_back(dest); - add_edges(source, V); -} - -void TheorySetsPrivate::add_edges(TNode source, TNode dest1, TNode dest2) { - vector V; - V.push_back(dest1); - V.push_back(dest2); - 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, TNode dest1, TNode dest2, TNode dest3) { - vector 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& 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 TheorySetsPrivate::non_empty(std::set vertices) +void TheorySetsPrivate::NotifyClass::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) { - std::set ret; - NodeManager* nm = NodeManager::currentNM(); - BOOST_FOREACH(TNode vertex, vertices) { - Node emptySet = nm->mkConst(EmptySet(nm->toType(vertex.getType()))); - if(!d_equalityEngine.areEqual(vertex, emptySet)) { - ret.insert(vertex); - } - } - return ret; + Debug("sets-eq") << "[sets-eq] eqNotifyDisequal:" << " t1 = " << t1 << " t2 = " << t2 << " reason = " << reason << std::endl; + d_theory.eqNotifyDisequal(t1, t2, reason); } -std::set TheorySetsPrivate::get_leaves(Node vertex) { - Debug("sets-graph-details") << "[sets-graph-details] get_leaves " << vertex << std::endl; - std::set 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 s = get_leaves(v); - a.insert(s.begin(), s.end()); - } - } else { - a.insert(vertex); - } - // a = non_empty(a); - return a; -} - -std::set TheorySetsPrivate::get_leaves(Node vertex1, Node vertex2) { - std::set s = get_leaves(vertex1); - std::set t = get_leaves(vertex2); - t.insert(s.begin(), s.end()); - return t; -} - -std::set TheorySetsPrivate::get_leaves(Node vertex1, Node vertex2, Node vertex3) { - std::set s = get_leaves(vertex1); - std::set t = get_leaves(vertex2); - std::set u = get_leaves(vertex3); - t.insert(s.begin(), s.end()); - t.insert(u.begin(), u.end()); - return t; -} - -Node TheorySetsPrivate::eqemptySoFar() { - std::vector 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 leaves1, std::set leaves2, Node reason) { - CodeTimer codeTimer(d_statistics.d_mergeTime); - - NodeManager* nm = NodeManager::currentNM(); - - // do non-empty reasoning stuff - std::vector leaves1_nonempty, leaves2_nonempty; - BOOST_FOREACH(TNode l, leaves1) { - Node emptySet = nm->mkConst(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(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 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 > 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 >::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 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::iterator it = leaves.begin(); it != leaves.end(); ++it) { - bool generateLemma = true; - Node emptySet = nm->mkConst(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(); - - 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 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::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 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 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 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 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 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 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 > d_propagationQueue; - context::CDQueue< std::pair > 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 d_nodeSaver; - - /** Lemmas and helper functions */ - context::CDQueue d_pending; - context::CDQueue d_pendingDisequal; - context::CDHashSet d_pendingEverInserted; - - void addToPending(Node n); - bool isComplete(); - Node getLemma(); - - /** model generation and helper function */ - typedef std::set Elements; - typedef std::hash_map SettermElementsMap; - const Elements& getElements(TNode setterm, SettermElementsMap& settermElementsMap) const; - Node elementsToShape(Elements elements, TypeNode setType) const; - Node elementsToShape(std::set elements, TypeNode setType) const; - bool checkModel(const SettermElementsMap& settermElementsMap, TNode S) const; - - context::CDHashMap d_modelCache; - - - // sharing related - context::CDO 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 d_typesAdded; - CDNodeSet d_processedCardTerms; - std::map, bool> d_processedCardPairs; - CDNodeSet d_cardLowerLemmaCache; - void registerCard(TNode); - void processCard(Theory::Effort level); - - /* Graph handling */ - std::map > edgesFd; - std::map > edgesBk; - std::set< std::pair > disjoint; - std::set leaves; - void buildGraph(); - - /* For calculus as in paper */ - void processCard2(Theory::Effort level); - CDNodeSet d_V; - context::CDHashMap , 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& dests); - void add_node(TNode vertex); - void merge_nodes(std::set a, std::set b, Node reason); - std::set get_leaves(Node vertex); - std::set get_leaves(Node vertex1, Node vertex2); - std::set get_leaves(Node vertex1, Node vertex2, Node vertex3); - std::set non_empty(std::set vertices); - void print_graph(bool printmodel=false); - context::CDQueue < std::pair > d_graphMergesPending; - context::CDList d_allSetEqualitiesSoFar; - Node eqSoFar(); - Node eqemptySoFar(); - - std::set 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_terms = d_terms_cache[rel_rep]; + + if( kind_terms.find(kind::TRANSPOSE) != kind_terms.end() ) { + std::vector 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 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 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 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::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::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 terms; + std::map > 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::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::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 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 r1_element; + std::vector 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 r1_element; + std::vector 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 elements = d_membership_trie[r1_rep].findTerms(d_tuple_reps[t1]); + + for(unsigned int j = 0; j < elements.size(); j++) { + std::vector 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::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 > 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 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 tuples = d_membership_db[n0_rep]; + std::vector 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 new_tups; + std::vector new_exps; + std::vector r1_elements = d_membership_db[r1_rep]; + std::vector r2_elements = d_membership_db[r2_rep]; + std::vector r1_exps = d_membership_exp_db[r1_rep]; + std::vector 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 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 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::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 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& 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 >& 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 members; + members.push_back(member); + map[rel_rep] = members; + return true; + } else { + std::vector::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 >& map, Node rel_rep, Node member) { + if(map.find(rel_rep) == map.end()) { + std::vector 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 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 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* conflict, + TheorySets& d_set ): + d_vec_size(c), + d_eqEngine(eq), + d_conflict(conflict), + d_sets_theory(d_set), + d_trueNode(NodeManager::currentNM()->mkConst(true)), + d_falseNode(NodeManager::currentNM()->mkConst(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 TupleTrie::findTerms( std::vector< Node >& reps, int argIndex ) { + std::vector 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; ifirst << 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 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 in_reachable; + std::hash_set 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 in_reachable, std::hash_set 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::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::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::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 r1_element; + std::vector 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& conjunctions ) { + Assert(conjunctions.size() > 0); + std::set 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::const_iterator it = all.begin(); + std::set::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 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*, + 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& , bool first_round = true); + + +private: + eq::EqualityEngine *d_eqEngine; + context::CDO *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 > 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 > d_membership_constraints_cache; + + /** Mapping between relation and its (non)members' explanation */ + std::map< Node, std::vector > d_membership_exp_cache; + + /** Mapping between relation and its member representatives */ + std::map< Node, std::vector > d_membership_db; + + /** Mapping between relation and its members' explanation */ + std::map< Node, std::vector > d_membership_exp_db; + + /** Mapping between a relation representative and its equivalent relations involving relational operators */ + std::map< Node, std::map > > d_terms_cache; + + /** Mapping between relation and its member representatives */ + std::map< Node, std::vector > 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 > 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 > > 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 in_reachable, std::hash_set 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& 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 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 ); + bool safelyAddToMap( std::map< Node, std::vector >&, 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; imkNode(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 left = NormalForm::getElementsFromNormalConstant(node[0]); - std::set right = NormalForm::getElementsFromNormalConstant(node[1]); - std::set 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 left = NormalForm::getElementsFromNormalConstant(node[0]); + std::set right = NormalForm::getElementsFromNormalConstant(node[1]); + std::set 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 left = NormalForm::getElementsFromNormalConstant(node[0]); - // std::set right = NormalForm::getElementsFromNormalConstant(node[1]); - // std::set 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 left = NormalForm::getElementsFromNormalConstant(node[0]); - std::set right = NormalForm::getElementsFromNormalConstant(node[1]); - std::set 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 left = NormalForm::getElementsFromNormalConstant(node[0]); + std::set right = NormalForm::getElementsFromNormalConstant(node[1]); + std::set 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 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 new_tuple_set; + std::set tuple_set = NormalForm::getElementsFromNormalConstant(node[0]); + std::set::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 new_tuple_set; + std::set left = NormalForm::getElementsFromNormalConstant(node[0]); + std::set right = NormalForm::getElementsFromNormalConstant(node[1]); + std::set::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 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::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 right_tuple; + for(int j = 0; j < right_len; j++) { + right_tuple.push_back(RelsUtils::nthElementOfTuple(*right_it,j)); + } + std::vector 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 new_tuple_set; + std::set left = NormalForm::getElementsFromNormalConstant(node[0]); + std::set right = NormalForm::getElementsFromNormalConstant(node[1]); + std::set::iterator left_it = left.begin(); + int left_len = (*left_it).getType().getTupleLength(); + TypeNode tn = node.getType().getSetElementType(); + while(left_it != left.end()) { + std::vector 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::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 right_tuple; + for(int j = 1; j < right_len; j++) { + right_tuple.push_back(RelsUtils::nthElementOfTuple(*right_it,j)); + } + std::vector 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 rel_mems = NormalForm::getElementsFromNormalConstant(node[0]); + std::set 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; jmkNode( 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; jmkNode( 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& 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 newTupleTypes; + std::vector firstTupleTypes = firstRelType[0].getTupleTypes(); + std::vector 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 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 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); diff --git a/test/Makefile.am b/test/Makefile.am index 931228f41..a71cbfe60 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -57,6 +57,7 @@ subdirs_to_check = \ regress/regress0/fmf \ regress/regress0/strings \ regress/regress0/sets \ + regress/regress0/rels \ regress/regress0/parser \ regress/regress0/sygus \ regress/regress0/sep \ diff --git a/test/regress/regress0/Makefile.am b/test/regress/regress0/Makefile.am index c790165ef..ec09c9a4a 100644 --- a/test/regress/regress0/Makefile.am +++ b/test/regress/regress0/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = . arith precedence uf uflra uflia bv arrays aufbv auflia datatypes quantifiers rewriterules lemmas push-pop preprocess tptp unconstrained decision fmf strings sets parser sygus sep +SUBDIRS = . arith precedence uf uflra uflia bv arrays aufbv auflia datatypes quantifiers rewriterules lemmas push-pop preprocess tptp unconstrained decision fmf strings sets rels parser sygus sep DIST_SUBDIRS = $(SUBDIRS) # don't override a BINARY imported from a personal.mk diff --git a/test/regress/regress0/rels/Makefile b/test/regress/regress0/rels/Makefile new file mode 100644 index 000000000..bd7dc8797 --- /dev/null +++ b/test/regress/regress0/rels/Makefile @@ -0,0 +1,8 @@ +topdir = ../../../.. +srcdir = test/regress/regress0/rels + +include $(topdir)/Makefile.subdir + +# synonyms for "check" +.PHONY: test +test: check diff --git a/test/regress/regress0/rels/Makefile.am b/test/regress/regress0/rels/Makefile.am new file mode 100644 index 000000000..6b8fdfec7 --- /dev/null +++ b/test/regress/regress0/rels/Makefile.am @@ -0,0 +1,115 @@ +SUBDIRS = . + +# don't override a BINARY imported from a personal.mk +@mk_if@eq ($(BINARY),) +@mk_empty@BINARY = cvc4 +end@mk_if@ + +LOG_COMPILER = @srcdir@/../../run_regression +AM_LOG_FLAGS = $(RUN_REGRESSION_ARGS) @abs_top_builddir@/src/main/$(BINARY)$(EXEEXT) + +if AUTOMAKE_1_11 +# old-style (pre-automake 1.12) test harness +TESTS_ENVIRONMENT = \ + $(LOG_COMPILER) \ + $(AM_LOG_FLAGS) $(LOG_FLAGS) +endif + +MAKEFLAGS = -k + +# These are run for all build profiles. +# If a test shouldn't be run in e.g. competition mode, +# put it below in "TESTS +=" +TESTS = \ + addr_book_0.cvc \ + bv2.cvc \ + oneLoc_no_quant-int_0_1.cvc \ + rel_complex_5.cvc \ + rel_join_3_1.cvc \ + rel_product_0_1.cvc \ + rel_tc_10_1.cvc \ + rel_tc_6.cvc \ + rel_tp_join_2_1.cvc \ + rel_transpose_1_1.cvc \ + strat_0_1.cvc \ + addr_book_1_1.cvc \ + prod-mod-eq2.cvc \ + rel_conflict_0.cvc \ + rel_join_3.cvc \ + rel_product_0.cvc \ + rel_tc_11.cvc \ + rel_tc_7.cvc \ + rel_tp_join_2.cvc \ + rel_transpose_1.cvc \ + strat.cvc \ + addr_book_1.cvc \ + join-eq-structure_0_1.cvc \ + prod-mod-eq.cvc \ + rel_join_0_1.cvc \ + rel_join_4.cvc \ + rel_product_1_1.cvc \ + rel_tc_2_1.cvc \ + rel_tp_join_3.cvc \ + rel_transpose_3.cvc \ + bv1.cvc \ + join-eq-structure-and.cvc \ + rel_1tup_0.cvc \ + rel_join_0.cvc \ + rel_join_5.cvc \ + rel_product_1.cvc \ + rel_tc_3_1.cvc \ + rel_tc_9_1.cvc \ + rel_tp_join_eq_0.cvc \ + rel_transpose_4.cvc \ + bv1p.cvc \ + join-eq-structure.cvc \ + rel_complex_0.cvc \ + rel_join_1_1.cvc \ + rel_join_6.cvc \ + rel_symbolic_1_1.cvc \ + rel_tc_3.cvc \ + rel_tp_2.cvc \ + rel_tp_join_int_0.cvc \ + rel_transpose_5.cvc \ + bv1p-sat.cvc \ + join-eq-u.cvc \ + rel_complex_1.cvc \ + rel_join_1.cvc \ + rel_join_7.cvc \ + rel_symbolic_1.cvc \ + rel_tc_4_1.cvc \ + rel_tp_3_1.cvc \ + rel_tp_join_pro_0.cvc \ + rel_transpose_6.cvc \ + bv1-unitb.cvc \ + join-eq-u-sat.cvc \ + rel_complex_3.cvc \ + rel_join_2_1.cvc \ + rel_mix_0_1.cvc \ + rel_symbolic_2_1.cvc \ + rel_tc_4.cvc \ + rel_tp_join_0.cvc \ + rel_tp_join_var_0.cvc \ + rel_transpose_7.cvc \ + bv1-unit.cvc \ + rel_complex_4.cvc \ + rel_join_2.cvc \ + rel_pressure_0.cvc \ + rel_symbolic_3_1.cvc \ + rel_tc_5_1.cvc \ + rel_tp_join_1.cvc \ + rel_transpose_0.cvc \ + set-strat.cvc + +# unsolved : garbage_collect.cvc +# dump-unsat-core crash : rel_tc_8.cvc + +EXTRA_DIST = $(TESTS) + +# synonyms for "check" +.PHONY: regress regress0 test +regress regress0 test: check + +# do nothing in this subdir +.PHONY: regress1 regress2 regress3 +regress1 regress2 regress3: diff --git a/test/regress/regress0/rels/addr_book_0.cvc b/test/regress/regress0/rels/addr_book_0.cvc new file mode 100644 index 000000000..5b1ecefd8 --- /dev/null +++ b/test/regress/regress0/rels/addr_book_0.cvc @@ -0,0 +1,49 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +Atom : TYPE; +AtomTup : TYPE = [Atom]; +AtomBinTup : TYPE = [Atom, Atom]; +AtomTerTup : TYPE = [Atom, Atom, Atom]; +Target: SET OF AtomTup; + +Name: SET OF AtomTup; +Addr: SET OF AtomTup; +Book: SET OF AtomTup; +names: SET OF AtomBinTup; +addr: SET OF AtomTerTup; + +b1: Atom; +b1_tup : AtomTup; +ASSERT b1_tup = TUPLE(b1); +ASSERT b1_tup IS_IN Book; + +b2: Atom; +b2_tup : AtomTup; +ASSERT b2_tup = TUPLE(b2); +ASSERT b2_tup IS_IN Book; + +b3: Atom; +b3_tup : AtomTup; +ASSERT b3_tup = TUPLE(b3); +ASSERT b3_tup IS_IN Book; + +n: Atom; +n_tup : AtomTup; +ASSERT n_tup = TUPLE(n); +ASSERT n_tup IS_IN Name; + +t: Atom; +t_tup : AtomTup; +ASSERT t_tup = TUPLE(t); +ASSERT t_tup IS_IN Target; + +ASSERT ((Book JOIN addr) JOIN Target) <= Name; +ASSERT (Book JOIN names) <= Name; +ASSERT (Name & Addr) = {}::SET OF AtomTup; + +ASSERT ({n_tup} JOIN ({b1_tup} JOIN addr)) = {}::SET OF AtomTup; +ASSERT ({n_tup} JOIN ({b2_tup} JOIN addr)) = ({n_tup} JOIN ({b1_tup} JOIN addr)) | {t_tup}; +ASSERT ({n_tup} JOIN ({b3_tup} JOIN addr)) = ({n_tup} JOIN ({b2_tup} JOIN addr)) - {t_tup}; +ASSERT NOT (({n_tup} JOIN ({b1_tup} JOIN addr)) = ({n_tup} JOIN ({b3_tup} JOIN addr))); + +CHECKSAT; \ No newline at end of file diff --git a/test/regress/regress0/rels/addr_book_1.cvc b/test/regress/regress0/rels/addr_book_1.cvc new file mode 100644 index 000000000..34176f274 --- /dev/null +++ b/test/regress/regress0/rels/addr_book_1.cvc @@ -0,0 +1,45 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +Atom : TYPE; +AtomTup : TYPE = [Atom]; +AtomBinTup : TYPE = [Atom, Atom]; +AtomTerTup : TYPE = [Atom, Atom, Atom]; +Target: SET OF AtomTup; + +Name: SET OF AtomTup; +Addr: SET OF AtomTup; +Book: SET OF AtomTup; +names: SET OF AtomBinTup; +addr: SET OF AtomTerTup; + +b1: Atom; +b1_tup : AtomTup; +ASSERT b1_tup = TUPLE(b1); +ASSERT b1_tup IS_IN Book; + +b2: Atom; +b2_tup : AtomTup; +ASSERT b2_tup = TUPLE(b2); +ASSERT b2_tup IS_IN Book; + +b3: Atom; +b3_tup : AtomTup; +ASSERT b3_tup = TUPLE(b3); +ASSERT b3_tup IS_IN Book; + +m: Atom; +m_tup : AtomTup; +ASSERT m_tup = TUPLE(m); +ASSERT m_tup IS_IN Name; + +t: Atom; +t_tup : AtomTup; +ASSERT t_tup = TUPLE(t); +ASSERT t_tup IS_IN Target; + +ASSERT ({m_tup} JOIN ({b1_tup} JOIN addr)) = {}::SET OF AtomTup; +ASSERT ({b2_tup} JOIN addr) = ({b1_tup} JOIN addr) | {(m,t)}; +ASSERT ({b3_tup} JOIN addr) = ({b2_tup} JOIN addr) - {(m,t)}; +ASSERT NOT (({b1_tup} JOIN addr) = ({b3_tup} JOIN addr)); + +CHECKSAT; \ No newline at end of file diff --git a/test/regress/regress0/rels/addr_book_1_1.cvc b/test/regress/regress0/rels/addr_book_1_1.cvc new file mode 100644 index 000000000..3273ade3a --- /dev/null +++ b/test/regress/regress0/rels/addr_book_1_1.cvc @@ -0,0 +1,45 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +Atom : TYPE; +AtomTup : TYPE = [Atom]; +AtomBinTup : TYPE = [Atom, Atom]; +AtomTerTup : TYPE = [Atom, Atom, Atom]; +Target: SET OF AtomTup; + +Name: SET OF AtomTup; +Addr: SET OF AtomTup; +Book: SET OF AtomTup; +names: SET OF AtomBinTup; +addr: SET OF AtomTerTup; + +b1: Atom; +b1_tup : AtomTup; +ASSERT b1_tup = TUPLE(b1); +ASSERT b1_tup IS_IN Book; + +b2: Atom; +b2_tup : AtomTup; +ASSERT b2_tup = TUPLE(b2); +ASSERT b2_tup IS_IN Book; + +b3: Atom; +b3_tup : AtomTup; +ASSERT b3_tup = TUPLE(b3); +ASSERT b3_tup IS_IN Book; + +m: Atom; +m_tup : AtomTup; +ASSERT m_tup = TUPLE(m); +ASSERT m_tup IS_IN Name; + +t: Atom; +t_tup : AtomTup; +ASSERT t_tup = TUPLE(t); +ASSERT t_tup IS_IN Target; + +ASSERT ({m_tup} JOIN ({b1_tup} JOIN addr)) = {}::SET OF AtomTup; +ASSERT ({b2_tup} JOIN addr) = ({b1_tup} JOIN addr) | {(m,t)}; +ASSERT ({b3_tup} JOIN addr) = ({b2_tup} JOIN addr) - {(m,t)}; +ASSERT (({b1_tup} JOIN addr) = ({b3_tup} JOIN addr)); + +CHECKSAT; \ No newline at end of file diff --git a/test/regress/regress0/rels/bv1-unit.cvc b/test/regress/regress0/rels/bv1-unit.cvc new file mode 100644 index 000000000..970ebdc8c --- /dev/null +++ b/test/regress/regress0/rels/bv1-unit.cvc @@ -0,0 +1,21 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +DATATYPE unit = u END; +BvPair: TYPE = [BITVECTOR(1), unit, BITVECTOR(1)]; +x : SET OF BvPair; +y : SET OF BvPair; + +a : BITVECTOR(1); +b : BITVECTOR(1); +c : BITVECTOR(1); +d : BITVECTOR(1); +e : BITVECTOR(1); + +ASSERT NOT ( b = c ); + +ASSERT (a, u, b) IS_IN x; +ASSERT (a, u, c) IS_IN x; +ASSERT (d, u, a) IS_IN y; +ASSERT NOT ( ( a, u, u, a ) IS_IN (x JOIN y)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/bv1-unitb.cvc b/test/regress/regress0/rels/bv1-unitb.cvc new file mode 100644 index 000000000..50a5bb48a --- /dev/null +++ b/test/regress/regress0/rels/bv1-unitb.cvc @@ -0,0 +1,22 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +DATATYPE unitb = ub(data : BITVECTOR(1)) END; +BvPair: TYPE = [BITVECTOR(1), unitb, BITVECTOR(1)]; +x : SET OF BvPair; +y : SET OF BvPair; + +a : BITVECTOR(1); +b : BITVECTOR(1); +c : BITVECTOR(1); +d : BITVECTOR(1); +e : BITVECTOR(1); +u : unitb; + +ASSERT NOT ( b = c ); + +ASSERT (a, u, b) IS_IN x; +ASSERT (a, u, c) IS_IN x; +ASSERT (d, u, a) IS_IN y; +ASSERT NOT ( ( a, u, u, a ) IS_IN (x JOIN y)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/bv1.cvc b/test/regress/regress0/rels/bv1.cvc new file mode 100644 index 000000000..95e7419ba --- /dev/null +++ b/test/regress/regress0/rels/bv1.cvc @@ -0,0 +1,20 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +BvPair: TYPE = [BITVECTOR(1), BITVECTOR(1)]; +x : SET OF BvPair; +y : SET OF BvPair; + +a : BITVECTOR(1); +b : BITVECTOR(1); +c : BITVECTOR(1); +d : BITVECTOR(1); +e : BITVECTOR(1); + +ASSERT NOT ( b = c ); + +ASSERT (a, b) IS_IN x; +ASSERT (a, c) IS_IN x; +ASSERT (d, a) IS_IN y; +ASSERT NOT ( ( a, a ) IS_IN (x JOIN y)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/bv1p-sat.cvc b/test/regress/regress0/rels/bv1p-sat.cvc new file mode 100644 index 000000000..5eceb214c --- /dev/null +++ b/test/regress/regress0/rels/bv1p-sat.cvc @@ -0,0 +1,22 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +BvPair: TYPE = [BITVECTOR(1), BITVECTOR(1)]; +x : SET OF BvPair; +y : SET OF BvPair; + +a : BvPair; +b : BvPair; +c : BvPair; +d : BvPair; + +ASSERT DISTINCT ( a, b ); +ASSERT DISTINCT ( c, d ); + +ASSERT a IS_IN x; +ASSERT b IS_IN x; +ASSERT a IS_IN y; +ASSERT b IS_IN y; +ASSERT NOT ( c IS_IN (x JOIN y)) AND NOT ( d IS_IN (x JOIN y)); + + +CHECKSAT; diff --git a/test/regress/regress0/rels/bv1p.cvc b/test/regress/regress0/rels/bv1p.cvc new file mode 100644 index 000000000..130ccae97 --- /dev/null +++ b/test/regress/regress0/rels/bv1p.cvc @@ -0,0 +1,22 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +BvPair: TYPE = [BITVECTOR(1), BITVECTOR(1)]; +x : SET OF BvPair; +y : SET OF BvPair; + +a : BvPair; +b : BvPair; +c : BvPair; +d : BvPair; +e : BvPair; + +ASSERT DISTINCT ( a, b ); +ASSERT DISTINCT ( c, d, e ); + +ASSERT a IS_IN x; +ASSERT b IS_IN x; +ASSERT a IS_IN y; +ASSERT b IS_IN y; +ASSERT (NOT ( c IS_IN (x JOIN y)) AND NOT ( d IS_IN (x JOIN y)) AND NOT ( e IS_IN (x JOIN y)) ); + +CHECKSAT; diff --git a/test/regress/regress0/rels/bv2.cvc b/test/regress/regress0/rels/bv2.cvc new file mode 100644 index 000000000..d7162de7c --- /dev/null +++ b/test/regress/regress0/rels/bv2.cvc @@ -0,0 +1,20 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +BvPair: TYPE = [BITVECTOR(2), BITVECTOR(2)]; +x : SET OF BvPair; +y : SET OF BvPair; + +a : BITVECTOR(2); +b : BITVECTOR(2); +c : BITVECTOR(2); +d : BITVECTOR(2); +e : BITVECTOR(2); + +ASSERT NOT ( b = c ); + +ASSERT (a, b) IS_IN x; +ASSERT (a, c) IS_IN x; +ASSERT (d, a) IS_IN y; +ASSERT NOT ( ( a, a ) IS_IN (x JOIN y)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/garbage_collect.cvc b/test/regress/regress0/rels/garbage_collect.cvc new file mode 100644 index 000000000..1fc1f2fea --- /dev/null +++ b/test/regress/regress0/rels/garbage_collect.cvc @@ -0,0 +1,60 @@ +% EXPECT: unsat +H_TYPE: TYPE; +H: TYPE = [H_TYPE]; +Obj: TYPE; +Obj_Tup: TYPE = [Obj]; +MARK_TYPE: TYPE = [H_TYPE, Obj]; +RELATE: TYPE = [Obj, Obj]; +REF_TYPE: TYPE = [H_TYPE, Obj, Obj]; + +% Symbols h0 to h3 are constants of type H that represents the system state; +h0: SET OF H; +h1: SET OF H; +h2: SET OF H; +h3: SET OF H; +s0: H_TYPE; +s1: H_TYPE; +s2: H_TYPE; +s3: H_TYPE; +ASSERT h0 = {TUPLE(s0)}; +ASSERT h1 = {TUPLE(s1)}; +ASSERT h2 = {TUPLE(s2)}; +ASSERT h3 = {TUPLE(s3)}; + +% ref ⊆ H × Obj × Obj represents references between objects in each state; +ref : SET OF REF_TYPE; + +% mark ⊆ H × Obj represents the marked objects in each state +mark: SET OF MARK_TYPE; + +empty_obj_set: SET OF Obj_Tup; +ASSERT empty_obj_set = {}:: SET OF Obj_Tup; + +% root and live are two constants of type Obj that represents objects; +root: Obj; +live: Obj; + +% The state transition (h0–h1) resets all the marks +ASSERT (h1 JOIN mark) = empty_obj_set; +ASSERT (h0 JOIN ref) <= (h1 JOIN ref); + +% (h1–h2) marks objects reachable from root +ASSERT FORALL (n : Obj) : ((root, n) IS_IN TCLOSURE(h1 JOIN ref)) + => (TUPLE(n) IS_IN (h2 JOIN mark)); +ASSERT (h1 JOIN ref) <= (h2 JOIN ref); + +% (h2–h3) sweeps references of non-marked objects + +ASSERT FORALL (n: Obj) : (NOT (TUPLE(n) IS_IN (h2 JOIN mark))) + => ({TUPLE(n)} JOIN (h3 JOIN ref)) = empty_obj_set; + +ASSERT FORALL (n: Obj) : (TUPLE(n) IS_IN (h2 JOIN mark)) + => ({TUPLE(n)} JOIN (h3 JOIN ref)) = ({TUPLE(n)} JOIN (h2 JOIN ref)); + +%The safety property is negated, thus it checks if +%in the final state, there is a live object that was originally reachable from root +%in the beginning state, but some of its references have been swept +ASSERT (root, live) IS_IN TCLOSURE(h0 JOIN ref); +ASSERT NOT (({TUPLE(live)} JOIN (h0 JOIN ref)) <= ({TUPLE(live)} JOIN (h3 JOIN ref))); + +CHECKSAT; \ No newline at end of file diff --git a/test/regress/regress0/rels/join-eq-structure-and.cvc b/test/regress/regress0/rels/join-eq-structure-and.cvc new file mode 100644 index 000000000..177410b1e --- /dev/null +++ b/test/regress/regress0/rels/join-eq-structure-and.cvc @@ -0,0 +1,26 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +DATATYPE unit = u END; +IntUPair: TYPE = [INT, unit]; +UIntPair: TYPE = [unit, INT]; +w : SET OF IntUPair; +z : SET OF UIntPair; + +ASSERT (x JOIN y) = (w JOIN z) AND (x JOIN y ) = TRANSPOSE(w JOIN z); + +ASSERT (0,1) IS_IN (x JOIN y); + +t : INT; +ASSERT t >= 0 AND t <=1; +s : INT; +ASSERT s >= 0 AND s <=1; + +ASSERT s+t = 1; + +ASSERT ( s ,u ) IS_IN w; +ASSERT NOT ( u, t ) IS_IN z; + +CHECKSAT; diff --git a/test/regress/regress0/rels/join-eq-structure.cvc b/test/regress/regress0/rels/join-eq-structure.cvc new file mode 100644 index 000000000..e27d3811c --- /dev/null +++ b/test/regress/regress0/rels/join-eq-structure.cvc @@ -0,0 +1,26 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +DATATYPE unit = u END; +IntUPair: TYPE = [INT, unit]; +UIntPair: TYPE = [unit, INT]; +w : SET OF IntUPair; +z : SET OF UIntPair; + +ASSERT (x JOIN y) = (w JOIN z) OR (x JOIN y ) = TRANSPOSE(w JOIN z); + +ASSERT (0,1) IS_IN (x JOIN y); + +t : INT; +ASSERT t >= 0 AND t <=1; +s : INT; +ASSERT s >= 0 AND s <=1; + +ASSERT s+t = 1; + +ASSERT ( s ,u ) IS_IN w; +ASSERT NOT ( u, t ) IS_IN z; + +CHECKSAT; diff --git a/test/regress/regress0/rels/join-eq-structure_0_1.cvc b/test/regress/regress0/rels/join-eq-structure_0_1.cvc new file mode 100644 index 000000000..e27d3811c --- /dev/null +++ b/test/regress/regress0/rels/join-eq-structure_0_1.cvc @@ -0,0 +1,26 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +DATATYPE unit = u END; +IntUPair: TYPE = [INT, unit]; +UIntPair: TYPE = [unit, INT]; +w : SET OF IntUPair; +z : SET OF UIntPair; + +ASSERT (x JOIN y) = (w JOIN z) OR (x JOIN y ) = TRANSPOSE(w JOIN z); + +ASSERT (0,1) IS_IN (x JOIN y); + +t : INT; +ASSERT t >= 0 AND t <=1; +s : INT; +ASSERT s >= 0 AND s <=1; + +ASSERT s+t = 1; + +ASSERT ( s ,u ) IS_IN w; +ASSERT NOT ( u, t ) IS_IN z; + +CHECKSAT; diff --git a/test/regress/regress0/rels/join-eq-u-sat.cvc b/test/regress/regress0/rels/join-eq-u-sat.cvc new file mode 100644 index 000000000..0202cbb41 --- /dev/null +++ b/test/regress/regress0/rels/join-eq-u-sat.cvc @@ -0,0 +1,22 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +DATATYPE unit = u END; +IntUPair: TYPE = [INT, unit]; +UIntPair: TYPE = [unit, INT]; +w : SET OF IntUPair; +z : SET OF UIntPair; + +ASSERT (x JOIN y) = (w JOIN z); + +ASSERT (0,1) IS_IN (x JOIN y); +ASSERT (0,u) IS_IN w; + +t : INT; +ASSERT t > 0 AND t < 3; + +ASSERT NOT (u, t ) IS_IN z; + +CHECKSAT; diff --git a/test/regress/regress0/rels/join-eq-u.cvc b/test/regress/regress0/rels/join-eq-u.cvc new file mode 100644 index 000000000..4bc498aec --- /dev/null +++ b/test/regress/regress0/rels/join-eq-u.cvc @@ -0,0 +1,22 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +DATATYPE unit = u END; +IntUPair: TYPE = [INT, unit]; +UIntPair: TYPE = [unit, INT]; +w : SET OF IntUPair; +z : SET OF UIntPair; + +ASSERT (x JOIN y) = (w JOIN z); + +ASSERT (0,1) IS_IN (x JOIN y); +ASSERT (0,u) IS_IN w; + +t : INT; +ASSERT t > 0 AND t < 2; + +ASSERT NOT (u, t ) IS_IN z; + +CHECKSAT; diff --git a/test/regress/regress0/rels/oneLoc_no_quant-int_0_1.cvc b/test/regress/regress0/rels/oneLoc_no_quant-int_0_1.cvc new file mode 100644 index 000000000..f39c23438 --- /dev/null +++ b/test/regress/regress0/rels/oneLoc_no_quant-int_0_1.cvc @@ -0,0 +1,19 @@ +% EXPECT: sat +OPTION "logic" "QF_UFDTFS"; +DATATYPE Atom = atom END; + + +t : SET OF [Atom, Atom]; +b : Atom; +a : Atom; +c : Atom; +J : ( SET OF [Atom], SET OF [Atom, Atom] ) -> SET OF [Atom]; +T : SET OF [Atom, Atom] -> SET OF [Atom, Atom]; + +%ASSERT t = {} :: SET OF [Atom, Atom]; + + +ASSERT ({TUPLE(a)} JOIN t) = J({TUPLE(a)}, t); +ASSERT NOT( ({TUPLE(c)} JOIN TCLOSURE(t)) = {TUPLE(c)} ); + +CHECKSAT; diff --git a/test/regress/regress0/rels/prod-mod-eq.cvc b/test/regress/regress0/rels/prod-mod-eq.cvc new file mode 100644 index 000000000..96ef2ffba --- /dev/null +++ b/test/regress/regress0/rels/prod-mod-eq.cvc @@ -0,0 +1,26 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +IntPairPair: TYPE = [INT, INT, INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPairPair; +z1 : SET OF IntPair; +w1 : SET OF IntPair; +z2 : SET OF IntPair; +w2 : SET OF IntPair; + +%ASSERT NOT (0,1,2,3) IS_IN (x PRODUCT y); + +ASSERT NOT( z = (x PRODUCT y) ); + +ASSERT (0,1,2,3) IS_IN z; + +ASSERT (0,1) IS_IN z1; +ASSERT (0,1) IS_IN z2; +ASSERT (2,3) IS_IN w1; +ASSERT (2,3) IS_IN w2; + +ASSERT ( x = z1 AND y = w1 ) OR ( x = z2 AND y = w2 ); + +CHECKSAT; diff --git a/test/regress/regress0/rels/prod-mod-eq2.cvc b/test/regress/regress0/rels/prod-mod-eq2.cvc new file mode 100644 index 000000000..b9341a216 --- /dev/null +++ b/test/regress/regress0/rels/prod-mod-eq2.cvc @@ -0,0 +1,26 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +IntPairPair: TYPE = [INT, INT, INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPairPair; +z1 : SET OF IntPair; +w1 : SET OF IntPair; +z2 : SET OF IntPair; +w2 : SET OF IntPair; +P : SET OF IntPairPair -> BOOLEAN; + +ASSERT z = (x PRODUCT y); + +ASSERT P( z ); +ASSERT NOT P( {(0,1,2,3)} ); + +ASSERT (0,1) IS_IN z1; +ASSERT (0,1) IS_IN z2; +ASSERT (2,3) IS_IN w1; +ASSERT (2,3) IS_IN w2; + +ASSERT ( x = z1 AND y = w1 ) OR ( x = z2 AND y = w2 ); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_1tup_0.cvc b/test/regress/regress0/rels/rel_1tup_0.cvc new file mode 100644 index 000000000..50d4defd5 --- /dev/null +++ b/test/regress/regress0/rels/rel_1tup_0.cvc @@ -0,0 +1,24 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntTup: TYPE = [INT]; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntTup; +z: SET OF IntTup; + +b : IntPair; +ASSERT b = (2, 1); +ASSERT b IS_IN x; + +a : IntTup; +ASSERT a = TUPLE(1); +ASSERT a IS_IN y; + +c : IntTup; +ASSERT c = TUPLE(2); + +ASSERT z = (x JOIN y); + +ASSERT NOT (c IS_IN z); + +CHECKSAT; \ No newline at end of file diff --git a/test/regress/regress0/rels/rel_complex_0.cvc b/test/regress/regress0/rels/rel_complex_0.cvc new file mode 100644 index 000000000..dcb753973 --- /dev/null +++ b/test/regress/regress0/rels/rel_complex_0.cvc @@ -0,0 +1,31 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; +z : SET OF INT; +f : INT; +g : INT; + +e : IntPair; +ASSERT e = (4, f); +ASSERT e IS_IN x; + +d : IntPair; +ASSERT d = (g,3); +ASSERT d IS_IN y; + + +ASSERT z = {f, g}; +ASSERT 0 = f - g; + + + +a : IntPair; +ASSERT a = (4,3); + +ASSERT r = (x JOIN y); + +ASSERT NOT (a IS_IN r); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_complex_1.cvc b/test/regress/regress0/rels/rel_complex_1.cvc new file mode 100644 index 000000000..969d0d71c --- /dev/null +++ b/test/regress/regress0/rels/rel_complex_1.cvc @@ -0,0 +1,34 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +IntTup: TYPE = [INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + +w : SET OF IntTup; +z : SET OF IntTup; +r2 : SET OF IntPair; + +a : IntPair; +ASSERT a = (3,1); +ASSERT a IS_IN x; + +d : IntPair; +ASSERT d = (1,3); +ASSERT d IS_IN y; + +e : IntPair; +ASSERT e = (4,3); +ASSERT r = (x JOIN y); + +ASSERT TUPLE(1) IS_IN w; +ASSERT TUPLE(2) IS_IN z; +ASSERT r2 = (w PRODUCT z); + +ASSERT NOT (e IS_IN r); +%ASSERT e IS_IN r2; +ASSERT (r <= r2); +ASSERT NOT ((3,3) IS_IN r2); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_complex_3.cvc b/test/regress/regress0/rels/rel_complex_3.cvc new file mode 100644 index 000000000..492c94432 --- /dev/null +++ b/test/regress/regress0/rels/rel_complex_3.cvc @@ -0,0 +1,49 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +r : SET OF IntPair; +w : SET OF IntPair; + + +f : IntPair; +ASSERT f = (3,1); +ASSERT f IS_IN x; + +g : IntPair; +ASSERT g = (1,3); +ASSERT g IS_IN y; + +h : IntPair; +ASSERT h = (3,5); +ASSERT h IS_IN x; +ASSERT h IS_IN y; + +ASSERT r = (x JOIN y); + +e : IntPair; + +ASSERT NOT (e IS_IN r); +ASSERT NOT(z = (x & y)); +ASSERT z = (x - y); +ASSERT x <= y; +ASSERT e IS_IN (r JOIN z); +ASSERT e IS_IN x; +ASSERT e IS_IN (x & y); +CHECKSAT TRUE; + + + + + + + + + + + + + + diff --git a/test/regress/regress0/rels/rel_complex_4.cvc b/test/regress/regress0/rels/rel_complex_4.cvc new file mode 100644 index 000000000..f473b00aa --- /dev/null +++ b/test/regress/regress0/rels/rel_complex_4.cvc @@ -0,0 +1,52 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +r : SET OF IntPair; +w : SET OF IntPair; + + +f : IntPair; +ASSERT f = (3,1); +ASSERT f IS_IN x; + +g : IntPair; +ASSERT g = (1,3); +ASSERT g IS_IN y; + +h : IntPair; +ASSERT h = (3,5); +ASSERT h IS_IN x; +ASSERT h IS_IN y; + +ASSERT r = (x JOIN y); +a:INT; +e : IntPair; +ASSERT e = (a,a); +ASSERT w = {e}; +ASSERT TRANSPOSE(w) <= y; + +ASSERT NOT (e IS_IN r); +ASSERT NOT(z = (x & y)); +ASSERT z = (x - y); +ASSERT x <= y; +ASSERT e IS_IN (r JOIN z); +ASSERT e IS_IN x; +ASSERT e IS_IN (x & y); +CHECKSAT TRUE; + + + + + + + + + + + + + + diff --git a/test/regress/regress0/rels/rel_complex_5.cvc b/test/regress/regress0/rels/rel_complex_5.cvc new file mode 100644 index 000000000..d64817187 --- /dev/null +++ b/test/regress/regress0/rels/rel_complex_5.cvc @@ -0,0 +1,55 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +IntTup: TYPE = [INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +r : SET OF IntPair; +w : SET OF IntPair; + + +f : IntPair; +ASSERT f = (3,1); +ASSERT f IS_IN x; + +g : IntPair; +ASSERT g = (1,3); +ASSERT g IS_IN y; + +h : IntPair; +ASSERT h = (3,5); +ASSERT h IS_IN x; +ASSERT h IS_IN y; + +ASSERT r = (x JOIN y); +a:IntTup; +ASSERT a = TUPLE(1); +e : IntPair; +ASSERT e = (1,1); + +ASSERT w = ({a} PRODUCT {a}); +ASSERT TRANSPOSE(w) <= y; + +ASSERT NOT (e IS_IN r); +ASSERT NOT(z = (x & y)); +ASSERT z = (x - y); +ASSERT x <= y; +ASSERT e IS_IN (r JOIN z); +ASSERT e IS_IN x; +ASSERT e IS_IN (x & y); +CHECKSAT TRUE; + + + + + + + + + + + + + + diff --git a/test/regress/regress0/rels/rel_conflict_0.cvc b/test/regress/regress0/rels/rel_conflict_0.cvc new file mode 100644 index 000000000..c1b82339f --- /dev/null +++ b/test/regress/regress0/rels/rel_conflict_0.cvc @@ -0,0 +1,10 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +e : IntPair; +ASSERT e = (4, 4); +ASSERT e IS_IN x; + +ASSERT NOT ((4, 4) IS_IN x); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_join_0.cvc b/test/regress/regress0/rels/rel_join_0.cvc new file mode 100644 index 000000000..406b8d312 --- /dev/null +++ b/test/regress/regress0/rels/rel_join_0.cvc @@ -0,0 +1,24 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); +v : IntPair; +ASSERT v = (1,1); +a : IntPair; +ASSERT a = (1,5); + +ASSERT (1, 7) IS_IN x; +ASSERT (7, 5) IS_IN y; + +ASSERT z IS_IN x; +ASSERT zt IS_IN y; +ASSERT NOT (a IS_IN (x JOIN y)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_join_0_1.cvc b/test/regress/regress0/rels/rel_join_0_1.cvc new file mode 100644 index 000000000..a7fa7efb9 --- /dev/null +++ b/test/regress/regress0/rels/rel_join_0_1.cvc @@ -0,0 +1,27 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); +v : IntPair; +ASSERT v = (1,1); +a : IntPair; +ASSERT a = (1,5); + +ASSERT (1, 7) IS_IN x; +ASSERT (4, 3) IS_IN x; +ASSERT (7, 5) IS_IN y; + +ASSERT z IS_IN x; +ASSERT zt IS_IN y; +%ASSERT a IS_IN (x JOIN y); +%ASSERT NOT (v IS_IN (x JOIN y)); +ASSERT a IS_IN (x JOIN y); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_join_1.cvc b/test/regress/regress0/rels/rel_join_1.cvc new file mode 100644 index 000000000..c8921afb9 --- /dev/null +++ b/test/regress/regress0/rels/rel_join_1.cvc @@ -0,0 +1,31 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); +v : IntPair; +ASSERT v = (1,1); +a : IntPair; +ASSERT a = (1,5); + +ASSERT (1, 7) IS_IN x; +ASSERT (2, 3) IS_IN x; +ASSERT (3, 4) IS_IN x; + +ASSERT (7, 5) IS_IN y; +ASSERT (7, 3) IS_IN y; +ASSERT (4, 7) IS_IN y; + +%ASSERT (a IS_IN (r JOIN(x JOIN y))); + +ASSERT z IS_IN x; +ASSERT zt IS_IN y; +ASSERT NOT (a IS_IN (x JOIN y)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_join_1_1.cvc b/test/regress/regress0/rels/rel_join_1_1.cvc new file mode 100644 index 000000000..75fc08387 --- /dev/null +++ b/test/regress/regress0/rels/rel_join_1_1.cvc @@ -0,0 +1,31 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); +v : IntPair; +ASSERT v = (1,1); +a : IntPair; +ASSERT a = (1,5); + +ASSERT (1, 7) IS_IN x; +ASSERT (2, 3) IS_IN x; +ASSERT (3, 4) IS_IN x; + +ASSERT (7, 5) IS_IN y; +ASSERT (7, 3) IS_IN y; +ASSERT (4, 7) IS_IN y; + +%ASSERT (a IS_IN (r JOIN(x JOIN y))); + +ASSERT z IS_IN x; +ASSERT zt IS_IN y; +ASSERT r = (x JOIN y); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_join_2.cvc b/test/regress/regress0/rels/rel_join_2.cvc new file mode 100644 index 000000000..cac7ce84d --- /dev/null +++ b/test/regress/regress0/rels/rel_join_2.cvc @@ -0,0 +1,20 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +IntTup: TYPE = [INT, INT, INT]; +x : SET OF IntPair; +y : SET OF IntTup; + +z : IntPair; +ASSERT z = (1,2); +zt : IntTup; +ASSERT zt = (2,1,3); +a : IntTup; +ASSERT a = (1,1,3); + +ASSERT z IS_IN x; +ASSERT zt IS_IN y; + +ASSERT NOT (a IS_IN (x JOIN y)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_join_2_1.cvc b/test/regress/regress0/rels/rel_join_2_1.cvc new file mode 100644 index 000000000..3e27b9cc5 --- /dev/null +++ b/test/regress/regress0/rels/rel_join_2_1.cvc @@ -0,0 +1,20 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +IntTup: TYPE = [INT, INT, INT]; +x : SET OF IntPair; +y : SET OF IntTup; + +z : IntPair; +ASSERT z = (1,2); +zt : IntTup; +ASSERT zt = (2,1,3); +a : IntTup; +ASSERT a = (1,1,3); + +ASSERT z IS_IN x; +ASSERT zt IS_IN y; + +ASSERT a IS_IN (x JOIN y); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_join_3.cvc b/test/regress/regress0/rels/rel_join_3.cvc new file mode 100644 index 000000000..6e190cecf --- /dev/null +++ b/test/regress/regress0/rels/rel_join_3.cvc @@ -0,0 +1,29 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); +v : IntPair; +ASSERT v = (1,1); +a : IntPair; +ASSERT a = (1,5); + +ASSERT (1, 7) IS_IN x; +ASSERT (2, 3) IS_IN x; +ASSERT (3, 4) IS_IN x; + +ASSERT (7, 5) IS_IN y; +ASSERT (7, 3) IS_IN y; +ASSERT (4, 7) IS_IN y; +ASSERT r = (x JOIN y); +ASSERT z IS_IN x; +ASSERT zt IS_IN y; +ASSERT NOT (a IS_IN r); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_join_3_1.cvc b/test/regress/regress0/rels/rel_join_3_1.cvc new file mode 100644 index 000000000..dedc4ae44 --- /dev/null +++ b/test/regress/regress0/rels/rel_join_3_1.cvc @@ -0,0 +1,29 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); +v : IntPair; +ASSERT v = (1,1); +a : IntPair; +ASSERT a = (1,5); + +ASSERT (1, 7) IS_IN x; +ASSERT (2, 3) IS_IN x; +ASSERT (3, 4) IS_IN x; + +ASSERT (7, 5) IS_IN y; +ASSERT (7, 3) IS_IN y; +ASSERT (4, 7) IS_IN y; +ASSERT r = (x JOIN y); +ASSERT z IS_IN x; +ASSERT zt IS_IN y; +ASSERT a IS_IN r; + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_join_4.cvc b/test/regress/regress0/rels/rel_join_4.cvc new file mode 100644 index 000000000..030810f3d --- /dev/null +++ b/test/regress/regress0/rels/rel_join_4.cvc @@ -0,0 +1,32 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); +v : IntPair; +ASSERT v = (1,1); +a : IntPair; +ASSERT a = (1,5); + +b : IntPair; +ASSERT b = (7, 5); + +ASSERT (1, 7) IS_IN x; +ASSERT (2, 3) IS_IN x; +ASSERT (3, 4) IS_IN x; + +ASSERT b IS_IN y; +ASSERT (7, 3) IS_IN y; +ASSERT (4, 7) IS_IN y; +ASSERT r = (x JOIN y); +ASSERT z IS_IN x; +ASSERT zt IS_IN y; +ASSERT NOT (a IS_IN r); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_join_5.cvc b/test/regress/regress0/rels/rel_join_5.cvc new file mode 100644 index 000000000..5209d8131 --- /dev/null +++ b/test/regress/regress0/rels/rel_join_5.cvc @@ -0,0 +1,19 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +r : SET OF IntPair; + +ASSERT (7, 1) IS_IN x; +ASSERT (2, 3) IS_IN x; +ASSERT (7, 3) IS_IN y; +ASSERT (4, 7) IS_IN y; +ASSERT (3, 4) IS_IN z; + +a : IntPair; +ASSERT a = (1,4); +ASSERT r = (((TRANSPOSE x) JOIN y) JOIN z); +ASSERT NOT (a IS_IN r); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_join_6.cvc b/test/regress/regress0/rels/rel_join_6.cvc new file mode 100644 index 000000000..17318872f --- /dev/null +++ b/test/regress/regress0/rels/rel_join_6.cvc @@ -0,0 +1,13 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; +ASSERT x = {(1,2), (3, 4)}; + +ASSERT y = (x JOIN {(2,1), (4,3)}); + +ASSERT NOT ((1,1) IS_IN y); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_join_7.cvc b/test/regress/regress0/rels/rel_join_7.cvc new file mode 100644 index 000000000..fff5b6efe --- /dev/null +++ b/test/regress/regress0/rels/rel_join_7.cvc @@ -0,0 +1,26 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; +w : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); +v : IntPair; +ASSERT v = (1,1); +a : IntPair; +ASSERT a = (1,5); + +ASSERT (1, 7) IS_IN x; +ASSERT (7, 5) IS_IN y; + +ASSERT z IS_IN x; +ASSERT zt IS_IN y; +ASSERT w = (r | (x JOIN y)); +ASSERT NOT (a IS_IN w); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_mix_0_1.cvc b/test/regress/regress0/rels/rel_mix_0_1.cvc new file mode 100644 index 000000000..723a9b2e2 --- /dev/null +++ b/test/regress/regress0/rels/rel_mix_0_1.cvc @@ -0,0 +1,30 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +IntTup: TYPE = [INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + +w : SET OF IntTup; +z : SET OF IntTup; +r2 : SET OF IntPair; + +d : IntPair; +ASSERT d = (1,3); +ASSERT (1,3) IS_IN y; + +a : IntPair; +ASSERT a IS_IN x; + +e : IntPair; +ASSERT e = (4,3); + +ASSERT r = (x JOIN y); +ASSERT r2 = (w PRODUCT z); + +ASSERT NOT (e IS_IN r); +%ASSERT e IS_IN r2; +ASSERT NOT (r = r2); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_pressure_0.cvc b/test/regress/regress0/rels/rel_pressure_0.cvc new file mode 100644 index 000000000..6cdf03600 --- /dev/null +++ b/test/regress/regress0/rels/rel_pressure_0.cvc @@ -0,0 +1,617 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +r : SET OF IntPair; + +a11 : IntPair; +ASSERT a11 = (1, 1); +ASSERT a11 IS_IN x; +a12 : IntPair; +ASSERT a12 = (1, 2); +ASSERT a12 IS_IN x; +a13 : IntPair; +ASSERT a13 = (1, 3); +ASSERT a13 IS_IN x; +a14 : IntPair; +ASSERT a14 = (1, 4); +ASSERT a14 IS_IN x; +a15 : IntPair; +ASSERT a15 = (1, 5); +ASSERT a15 IS_IN x; +a16 : IntPair; +ASSERT a16 = (1, 6); +ASSERT a16 IS_IN x; +a17 : IntPair; +ASSERT a17 = (1, 7); +ASSERT a17 IS_IN x; +a18 : IntPair; +ASSERT a18 = (1, 8); +ASSERT a18 IS_IN x; +a19 : IntPair; +ASSERT a19 = (1, 9); +ASSERT a19 IS_IN x; +a110 : IntPair; +ASSERT a110 = (1, 10); +ASSERT a110 IS_IN x; +a21 : IntPair; +ASSERT a21 = (2, 1); +ASSERT a21 IS_IN x; +a22 : IntPair; +ASSERT a22 = (2, 2); +ASSERT a22 IS_IN x; +a23 : IntPair; +ASSERT a23 = (2, 3); +ASSERT a23 IS_IN x; +a24 : IntPair; +ASSERT a24 = (2, 4); +ASSERT a24 IS_IN x; +a25 : IntPair; +ASSERT a25 = (2, 5); +ASSERT a25 IS_IN x; +a26 : IntPair; +ASSERT a26 = (2, 6); +ASSERT a26 IS_IN x; +a27 : IntPair; +ASSERT a27 = (2, 7); +ASSERT a27 IS_IN x; +a28 : IntPair; +ASSERT a28 = (2, 8); +ASSERT a28 IS_IN x; +a29 : IntPair; +ASSERT a29 = (2, 9); +ASSERT a29 IS_IN x; +a210 : IntPair; +ASSERT a210 = (2, 10); +ASSERT a210 IS_IN x; +a31 : IntPair; +ASSERT a31 = (3, 1); +ASSERT a31 IS_IN x; +a32 : IntPair; +ASSERT a32 = (3, 2); +ASSERT a32 IS_IN x; +a33 : IntPair; +ASSERT a33 = (3, 3); +ASSERT a33 IS_IN x; +a34 : IntPair; +ASSERT a34 = (3, 4); +ASSERT a34 IS_IN x; +a35 : IntPair; +ASSERT a35 = (3, 5); +ASSERT a35 IS_IN x; +a36 : IntPair; +ASSERT a36 = (3, 6); +ASSERT a36 IS_IN x; +a37 : IntPair; +ASSERT a37 = (3, 7); +ASSERT a37 IS_IN x; +a38 : IntPair; +ASSERT a38 = (3, 8); +ASSERT a38 IS_IN x; +a39 : IntPair; +ASSERT a39 = (3, 9); +ASSERT a39 IS_IN x; +a310 : IntPair; +ASSERT a310 = (3, 10); +ASSERT a310 IS_IN x; +a41 : IntPair; +ASSERT a41 = (4, 1); +ASSERT a41 IS_IN x; +a42 : IntPair; +ASSERT a42 = (4, 2); +ASSERT a42 IS_IN x; +a43 : IntPair; +ASSERT a43 = (4, 3); +ASSERT a43 IS_IN x; +a44 : IntPair; +ASSERT a44 = (4, 4); +ASSERT a44 IS_IN x; +a45 : IntPair; +ASSERT a45 = (4, 5); +ASSERT a45 IS_IN x; +a46 : IntPair; +ASSERT a46 = (4, 6); +ASSERT a46 IS_IN x; +a47 : IntPair; +ASSERT a47 = (4, 7); +ASSERT a47 IS_IN x; +a48 : IntPair; +ASSERT a48 = (4, 8); +ASSERT a48 IS_IN x; +a49 : IntPair; +ASSERT a49 = (4, 9); +ASSERT a49 IS_IN x; +a410 : IntPair; +ASSERT a410 = (4, 10); +ASSERT a410 IS_IN x; +a51 : IntPair; +ASSERT a51 = (5, 1); +ASSERT a51 IS_IN x; +a52 : IntPair; +ASSERT a52 = (5, 2); +ASSERT a52 IS_IN x; +a53 : IntPair; +ASSERT a53 = (5, 3); +ASSERT a53 IS_IN x; +a54 : IntPair; +ASSERT a54 = (5, 4); +ASSERT a54 IS_IN x; +a55 : IntPair; +ASSERT a55 = (5, 5); +ASSERT a55 IS_IN x; +a56 : IntPair; +ASSERT a56 = (5, 6); +ASSERT a56 IS_IN x; +a57 : IntPair; +ASSERT a57 = (5, 7); +ASSERT a57 IS_IN x; +a58 : IntPair; +ASSERT a58 = (5, 8); +ASSERT a58 IS_IN x; +a59 : IntPair; +ASSERT a59 = (5, 9); +ASSERT a59 IS_IN x; +a510 : IntPair; +ASSERT a510 = (5, 10); +ASSERT a510 IS_IN x; +a61 : IntPair; +ASSERT a61 = (6, 1); +ASSERT a61 IS_IN x; +a62 : IntPair; +ASSERT a62 = (6, 2); +ASSERT a62 IS_IN x; +a63 : IntPair; +ASSERT a63 = (6, 3); +ASSERT a63 IS_IN x; +a64 : IntPair; +ASSERT a64 = (6, 4); +ASSERT a64 IS_IN x; +a65 : IntPair; +ASSERT a65 = (6, 5); +ASSERT a65 IS_IN x; +a66 : IntPair; +ASSERT a66 = (6, 6); +ASSERT a66 IS_IN x; +a67 : IntPair; +ASSERT a67 = (6, 7); +ASSERT a67 IS_IN x; +a68 : IntPair; +ASSERT a68 = (6, 8); +ASSERT a68 IS_IN x; +a69 : IntPair; +ASSERT a69 = (6, 9); +ASSERT a69 IS_IN x; +a610 : IntPair; +ASSERT a610 = (6, 10); +ASSERT a610 IS_IN x; +a71 : IntPair; +ASSERT a71 = (7, 1); +ASSERT a71 IS_IN x; +a72 : IntPair; +ASSERT a72 = (7, 2); +ASSERT a72 IS_IN x; +a73 : IntPair; +ASSERT a73 = (7, 3); +ASSERT a73 IS_IN x; +a74 : IntPair; +ASSERT a74 = (7, 4); +ASSERT a74 IS_IN x; +a75 : IntPair; +ASSERT a75 = (7, 5); +ASSERT a75 IS_IN x; +a76 : IntPair; +ASSERT a76 = (7, 6); +ASSERT a76 IS_IN x; +a77 : IntPair; +ASSERT a77 = (7, 7); +ASSERT a77 IS_IN x; +a78 : IntPair; +ASSERT a78 = (7, 8); +ASSERT a78 IS_IN x; +a79 : IntPair; +ASSERT a79 = (7, 9); +ASSERT a79 IS_IN x; +a710 : IntPair; +ASSERT a710 = (7, 10); +ASSERT a710 IS_IN x; +a81 : IntPair; +ASSERT a81 = (8, 1); +ASSERT a81 IS_IN x; +a82 : IntPair; +ASSERT a82 = (8, 2); +ASSERT a82 IS_IN x; +a83 : IntPair; +ASSERT a83 = (8, 3); +ASSERT a83 IS_IN x; +a84 : IntPair; +ASSERT a84 = (8, 4); +ASSERT a84 IS_IN x; +a85 : IntPair; +ASSERT a85 = (8, 5); +ASSERT a85 IS_IN x; +a86 : IntPair; +ASSERT a86 = (8, 6); +ASSERT a86 IS_IN x; +a87 : IntPair; +ASSERT a87 = (8, 7); +ASSERT a87 IS_IN x; +a88 : IntPair; +ASSERT a88 = (8, 8); +ASSERT a88 IS_IN x; +a89 : IntPair; +ASSERT a89 = (8, 9); +ASSERT a89 IS_IN x; +a810 : IntPair; +ASSERT a810 = (8, 10); +ASSERT a810 IS_IN x; +a91 : IntPair; +ASSERT a91 = (9, 1); +ASSERT a91 IS_IN x; +a92 : IntPair; +ASSERT a92 = (9, 2); +ASSERT a92 IS_IN x; +a93 : IntPair; +ASSERT a93 = (9, 3); +ASSERT a93 IS_IN x; +a94 : IntPair; +ASSERT a94 = (9, 4); +ASSERT a94 IS_IN x; +a95 : IntPair; +ASSERT a95 = (9, 5); +ASSERT a95 IS_IN x; +a96 : IntPair; +ASSERT a96 = (9, 6); +ASSERT a96 IS_IN x; +a97 : IntPair; +ASSERT a97 = (9, 7); +ASSERT a97 IS_IN x; +a98 : IntPair; +ASSERT a98 = (9, 8); +ASSERT a98 IS_IN x; +a99 : IntPair; +ASSERT a99 = (9, 9); +ASSERT a99 IS_IN x; +a910 : IntPair; +ASSERT a910 = (9, 10); +ASSERT a910 IS_IN x; +a101 : IntPair; +ASSERT a101 = (10, 1); +ASSERT a101 IS_IN x; +a102 : IntPair; +ASSERT a102 = (10, 2); +ASSERT a102 IS_IN x; +a103 : IntPair; +ASSERT a103 = (10, 3); +ASSERT a103 IS_IN x; +a104 : IntPair; +ASSERT a104 = (10, 4); +ASSERT a104 IS_IN x; +a105 : IntPair; +ASSERT a105 = (10, 5); +ASSERT a105 IS_IN x; +a106 : IntPair; +ASSERT a106 = (10, 6); +ASSERT a106 IS_IN x; +a107 : IntPair; +ASSERT a107 = (10, 7); +ASSERT a107 IS_IN x; +a108 : IntPair; +ASSERT a108 = (10, 8); +ASSERT a108 IS_IN x; +a109 : IntPair; +ASSERT a109 = (10, 9); +ASSERT a109 IS_IN x; +a1010 : IntPair; +ASSERT a1010 = (10, 10); +ASSERT a1010 IS_IN x; +b11 : IntPair; +ASSERT b11 = (1, 1); +ASSERT b11 IS_IN y; +b12 : IntPair; +ASSERT b12 = (1, 2); +ASSERT b12 IS_IN y; +b13 : IntPair; +ASSERT b13 = (1, 3); +ASSERT b13 IS_IN y; +b14 : IntPair; +ASSERT b14 = (1, 4); +ASSERT b14 IS_IN y; +b15 : IntPair; +ASSERT b15 = (1, 5); +ASSERT b15 IS_IN y; +b16 : IntPair; +ASSERT b16 = (1, 6); +ASSERT b16 IS_IN y; +b17 : IntPair; +ASSERT b17 = (1, 7); +ASSERT b17 IS_IN y; +b18 : IntPair; +ASSERT b18 = (1, 8); +ASSERT b18 IS_IN y; +b19 : IntPair; +ASSERT b19 = (1, 9); +ASSERT b19 IS_IN y; +b110 : IntPair; +ASSERT b110 = (1, 10); +ASSERT b110 IS_IN y; +b21 : IntPair; +ASSERT b21 = (2, 1); +ASSERT b21 IS_IN y; +b22 : IntPair; +ASSERT b22 = (2, 2); +ASSERT b22 IS_IN y; +b23 : IntPair; +ASSERT b23 = (2, 3); +ASSERT b23 IS_IN y; +b24 : IntPair; +ASSERT b24 = (2, 4); +ASSERT b24 IS_IN y; +b25 : IntPair; +ASSERT b25 = (2, 5); +ASSERT b25 IS_IN y; +b26 : IntPair; +ASSERT b26 = (2, 6); +ASSERT b26 IS_IN y; +b27 : IntPair; +ASSERT b27 = (2, 7); +ASSERT b27 IS_IN y; +b28 : IntPair; +ASSERT b28 = (2, 8); +ASSERT b28 IS_IN y; +b29 : IntPair; +ASSERT b29 = (2, 9); +ASSERT b29 IS_IN y; +b210 : IntPair; +ASSERT b210 = (2, 10); +ASSERT b210 IS_IN y; +b31 : IntPair; +ASSERT b31 = (3, 1); +ASSERT b31 IS_IN y; +b32 : IntPair; +ASSERT b32 = (3, 2); +ASSERT b32 IS_IN y; +b33 : IntPair; +ASSERT b33 = (3, 3); +ASSERT b33 IS_IN y; +b34 : IntPair; +ASSERT b34 = (3, 4); +ASSERT b34 IS_IN y; +b35 : IntPair; +ASSERT b35 = (3, 5); +ASSERT b35 IS_IN y; +b36 : IntPair; +ASSERT b36 = (3, 6); +ASSERT b36 IS_IN y; +b37 : IntPair; +ASSERT b37 = (3, 7); +ASSERT b37 IS_IN y; +b38 : IntPair; +ASSERT b38 = (3, 8); +ASSERT b38 IS_IN y; +b39 : IntPair; +ASSERT b39 = (3, 9); +ASSERT b39 IS_IN y; +b310 : IntPair; +ASSERT b310 = (3, 10); +ASSERT b310 IS_IN y; +b41 : IntPair; +ASSERT b41 = (4, 1); +ASSERT b41 IS_IN y; +b42 : IntPair; +ASSERT b42 = (4, 2); +ASSERT b42 IS_IN y; +b43 : IntPair; +ASSERT b43 = (4, 3); +ASSERT b43 IS_IN y; +b44 : IntPair; +ASSERT b44 = (4, 4); +ASSERT b44 IS_IN y; +b45 : IntPair; +ASSERT b45 = (4, 5); +ASSERT b45 IS_IN y; +b46 : IntPair; +ASSERT b46 = (4, 6); +ASSERT b46 IS_IN y; +b47 : IntPair; +ASSERT b47 = (4, 7); +ASSERT b47 IS_IN y; +b48 : IntPair; +ASSERT b48 = (4, 8); +ASSERT b48 IS_IN y; +b49 : IntPair; +ASSERT b49 = (4, 9); +ASSERT b49 IS_IN y; +b410 : IntPair; +ASSERT b410 = (4, 10); +ASSERT b410 IS_IN y; +b51 : IntPair; +ASSERT b51 = (5, 1); +ASSERT b51 IS_IN y; +b52 : IntPair; +ASSERT b52 = (5, 2); +ASSERT b52 IS_IN y; +b53 : IntPair; +ASSERT b53 = (5, 3); +ASSERT b53 IS_IN y; +b54 : IntPair; +ASSERT b54 = (5, 4); +ASSERT b54 IS_IN y; +b55 : IntPair; +ASSERT b55 = (5, 5); +ASSERT b55 IS_IN y; +b56 : IntPair; +ASSERT b56 = (5, 6); +ASSERT b56 IS_IN y; +b57 : IntPair; +ASSERT b57 = (5, 7); +ASSERT b57 IS_IN y; +b58 : IntPair; +ASSERT b58 = (5, 8); +ASSERT b58 IS_IN y; +b59 : IntPair; +ASSERT b59 = (5, 9); +ASSERT b59 IS_IN y; +b510 : IntPair; +ASSERT b510 = (5, 10); +ASSERT b510 IS_IN y; +b61 : IntPair; +ASSERT b61 = (6, 1); +ASSERT b61 IS_IN y; +b62 : IntPair; +ASSERT b62 = (6, 2); +ASSERT b62 IS_IN y; +b63 : IntPair; +ASSERT b63 = (6, 3); +ASSERT b63 IS_IN y; +b64 : IntPair; +ASSERT b64 = (6, 4); +ASSERT b64 IS_IN y; +b65 : IntPair; +ASSERT b65 = (6, 5); +ASSERT b65 IS_IN y; +b66 : IntPair; +ASSERT b66 = (6, 6); +ASSERT b66 IS_IN y; +b67 : IntPair; +ASSERT b67 = (6, 7); +ASSERT b67 IS_IN y; +b68 : IntPair; +ASSERT b68 = (6, 8); +ASSERT b68 IS_IN y; +b69 : IntPair; +ASSERT b69 = (6, 9); +ASSERT b69 IS_IN y; +b610 : IntPair; +ASSERT b610 = (6, 10); +ASSERT b610 IS_IN y; +b71 : IntPair; +ASSERT b71 = (7, 1); +ASSERT b71 IS_IN y; +b72 : IntPair; +ASSERT b72 = (7, 2); +ASSERT b72 IS_IN y; +b73 : IntPair; +ASSERT b73 = (7, 3); +ASSERT b73 IS_IN y; +b74 : IntPair; +ASSERT b74 = (7, 4); +ASSERT b74 IS_IN y; +b75 : IntPair; +ASSERT b75 = (7, 5); +ASSERT b75 IS_IN y; +b76 : IntPair; +ASSERT b76 = (7, 6); +ASSERT b76 IS_IN y; +b77 : IntPair; +ASSERT b77 = (7, 7); +ASSERT b77 IS_IN y; +b78 : IntPair; +ASSERT b78 = (7, 8); +ASSERT b78 IS_IN y; +b79 : IntPair; +ASSERT b79 = (7, 9); +ASSERT b79 IS_IN y; +b710 : IntPair; +ASSERT b710 = (7, 10); +ASSERT b710 IS_IN y; +b81 : IntPair; +ASSERT b81 = (8, 1); +ASSERT b81 IS_IN y; +b82 : IntPair; +ASSERT b82 = (8, 2); +ASSERT b82 IS_IN y; +b83 : IntPair; +ASSERT b83 = (8, 3); +ASSERT b83 IS_IN y; +b84 : IntPair; +ASSERT b84 = (8, 4); +ASSERT b84 IS_IN y; +b85 : IntPair; +ASSERT b85 = (8, 5); +ASSERT b85 IS_IN y; +b86 : IntPair; +ASSERT b86 = (8, 6); +ASSERT b86 IS_IN y; +b87 : IntPair; +ASSERT b87 = (8, 7); +ASSERT b87 IS_IN y; +b88 : IntPair; +ASSERT b88 = (8, 8); +ASSERT b88 IS_IN y; +b89 : IntPair; +ASSERT b89 = (8, 9); +ASSERT b89 IS_IN y; +b810 : IntPair; +ASSERT b810 = (8, 10); +ASSERT b810 IS_IN y; +b91 : IntPair; +ASSERT b91 = (9, 1); +ASSERT b91 IS_IN y; +b92 : IntPair; +ASSERT b92 = (9, 2); +ASSERT b92 IS_IN y; +b93 : IntPair; +ASSERT b93 = (9, 3); +ASSERT b93 IS_IN y; +b94 : IntPair; +ASSERT b94 = (9, 4); +ASSERT b94 IS_IN y; +b95 : IntPair; +ASSERT b95 = (9, 5); +ASSERT b95 IS_IN y; +b96 : IntPair; +ASSERT b96 = (9, 6); +ASSERT b96 IS_IN y; +b97 : IntPair; +ASSERT b97 = (9, 7); +ASSERT b97 IS_IN y; +b98 : IntPair; +ASSERT b98 = (9, 8); +ASSERT b98 IS_IN y; +b99 : IntPair; +ASSERT b99 = (9, 9); +ASSERT b99 IS_IN y; +b910 : IntPair; +ASSERT b910 = (9, 10); +ASSERT b910 IS_IN y; +b101 : IntPair; +ASSERT b101 = (10, 1); +ASSERT b101 IS_IN y; +b102 : IntPair; +ASSERT b102 = (10, 2); +ASSERT b102 IS_IN y; +b103 : IntPair; +ASSERT b103 = (10, 3); +ASSERT b103 IS_IN y; +b104 : IntPair; +ASSERT b104 = (10, 4); +ASSERT b104 IS_IN y; +b105 : IntPair; +ASSERT b105 = (10, 5); +ASSERT b105 IS_IN y; +b106 : IntPair; +ASSERT b106 = (10, 6); +ASSERT b106 IS_IN y; +b107 : IntPair; +ASSERT b107 = (10, 7); +ASSERT b107 IS_IN y; +b108 : IntPair; +ASSERT b108 = (10, 8); +ASSERT b108 IS_IN y; +b109 : IntPair; +ASSERT b109 = (10, 9); +ASSERT b109 IS_IN y; +b1010 : IntPair; +ASSERT b1010 = (10, 10); +ASSERT b1010 IS_IN y; + +ASSERT (1, 9) IS_IN z; + +a : IntPair; +ASSERT a = (9,1); +ASSERT r = (((TRANSPOSE x) JOIN y) JOIN z); +ASSERT NOT (a IS_IN (TRANSPOSE r)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_product_0.cvc b/test/regress/regress0/rels/rel_product_0.cvc new file mode 100644 index 000000000..09981be0b --- /dev/null +++ b/test/regress/regress0/rels/rel_product_0.cvc @@ -0,0 +1,20 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +IntTup: TYPE = [INT, INT, INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); +v : IntTup; +ASSERT v = (1,2,2,1); + +ASSERT z IS_IN x; +ASSERT zt IS_IN y; +ASSERT NOT (v IS_IN (x PRODUCT y)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_product_0_1.cvc b/test/regress/regress0/rels/rel_product_0_1.cvc new file mode 100644 index 000000000..f141c7bd4 --- /dev/null +++ b/test/regress/regress0/rels/rel_product_0_1.cvc @@ -0,0 +1,20 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +IntTup: TYPE = [INT, INT, INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); +v : IntTup; +ASSERT v = (1,2,2,1); + +ASSERT z IS_IN x; +ASSERT zt IS_IN y; +ASSERT v IS_IN (x PRODUCT y); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_product_1.cvc b/test/regress/regress0/rels/rel_product_1.cvc new file mode 100644 index 000000000..1826e5a75 --- /dev/null +++ b/test/regress/regress0/rels/rel_product_1.cvc @@ -0,0 +1,20 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT, INT]; +IntTup: TYPE = [INT, INT, INT, INT,INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2,3); +zt : IntPair; +ASSERT zt = (3,2,1); +v : IntTup; +ASSERT v = (1,2,3,3,2,1); + +ASSERT z IS_IN x; +ASSERT zt IS_IN y; +ASSERT NOT (v IS_IN (x PRODUCT y)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_product_1_1.cvc b/test/regress/regress0/rels/rel_product_1_1.cvc new file mode 100644 index 000000000..2d79cbc0c --- /dev/null +++ b/test/regress/regress0/rels/rel_product_1_1.cvc @@ -0,0 +1,21 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT, INT]; +IntTup: TYPE = [INT, INT, INT, INT,INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntTup; + +z : IntPair; +ASSERT z = (1,2,3); +zt : IntPair; +ASSERT zt = (3,2,1); + + +ASSERT z IS_IN x; +ASSERT zt IS_IN y; +ASSERT (1,1,1,1,1,1) IS_IN r; +ASSERT r = (x PRODUCT y); + + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_symbolic_1.cvc b/test/regress/regress0/rels/rel_symbolic_1.cvc new file mode 100644 index 000000000..08ed32411 --- /dev/null +++ b/test/regress/regress0/rels/rel_symbolic_1.cvc @@ -0,0 +1,21 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; +f : INT; +d : IntPair; +ASSERT d = (f,3); +ASSERT d IS_IN y; +e : IntPair; +ASSERT e = (4, f); +ASSERT e IS_IN x; + +a : IntPair; +ASSERT a = (4,3); + +ASSERT r = (x JOIN y); + +ASSERT NOT (a IS_IN r); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_symbolic_1_1.cvc b/test/regress/regress0/rels/rel_symbolic_1_1.cvc new file mode 100644 index 000000000..df2d7f412 --- /dev/null +++ b/test/regress/regress0/rels/rel_symbolic_1_1.cvc @@ -0,0 +1,20 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + +d : IntPair; +ASSERT d IS_IN y; + +a : IntPair; +ASSERT a IS_IN x; + +e : IntPair; +ASSERT e = (4,3); + +ASSERT r = (x JOIN y); + +ASSERT NOT (e IS_IN r); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_symbolic_2_1.cvc b/test/regress/regress0/rels/rel_symbolic_2_1.cvc new file mode 100644 index 000000000..082604dc2 --- /dev/null +++ b/test/regress/regress0/rels/rel_symbolic_2_1.cvc @@ -0,0 +1,21 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + +d : IntPair; +ASSERT d = (1,3); +ASSERT (1,3) IS_IN y; + +a : IntPair; +ASSERT a IS_IN x; + +e : IntPair; +ASSERT e = (4,3); + +ASSERT r = (x JOIN y); + +ASSERT NOT (e IS_IN r); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_symbolic_3_1.cvc b/test/regress/regress0/rels/rel_symbolic_3_1.cvc new file mode 100644 index 000000000..da0906dd2 --- /dev/null +++ b/test/regress/regress0/rels/rel_symbolic_3_1.cvc @@ -0,0 +1,21 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; +f : INT; +d : IntPair; +ASSERT d IS_IN y; + +e : IntPair; +ASSERT e = (4, f); +ASSERT e IS_IN x; + +a : IntPair; +ASSERT a = (4,3); + +ASSERT r = (x JOIN y); + +ASSERT NOT (a IS_IN r); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tc_10_1.cvc b/test/regress/regress0/rels/rel_tc_10_1.cvc new file mode 100644 index 000000000..67c444070 --- /dev/null +++ b/test/regress/regress0/rels/rel_tc_10_1.cvc @@ -0,0 +1,18 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +a: INT; +b:INT; +c:INT; +d:INT; +ASSERT a = c; +ASSERT a = d; +ASSERT (1, c) IS_IN x; +ASSERT (2, d) IS_IN x; +ASSERT (a, 5) IS_IN y; +ASSERT y = (TCLOSURE x); +ASSERT ((2, 5) IS_IN y); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tc_11.cvc b/test/regress/regress0/rels/rel_tc_11.cvc new file mode 100644 index 000000000..7edeb0efb --- /dev/null +++ b/test/regress/regress0/rels/rel_tc_11.cvc @@ -0,0 +1,18 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +IntTup: TYPE = [INT, INT, INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntTup; +ASSERT (2, 3) IS_IN x; +ASSERT (5, 3) IS_IN x; +ASSERT (3, 9) IS_IN x; +ASSERT z = (x PRODUCT y); +ASSERT (1, 2, 3, 4) IS_IN z; +ASSERT NOT ((5, 9) IS_IN x); +ASSERT (3, 8) IS_IN y; +ASSERT y = (TCLOSURE x); +ASSERT NOT ((1, 2) IS_IN y); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tc_2_1.cvc b/test/regress/regress0/rels/rel_tc_2_1.cvc new file mode 100644 index 000000000..d5d42eaad --- /dev/null +++ b/test/regress/regress0/rels/rel_tc_2_1.cvc @@ -0,0 +1,28 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; + e: INT; + +a : IntPair; +ASSERT a = (1, e); + +d : IntPair; +ASSERT d = (e,5); + +ASSERT a IS_IN x; +ASSERT d IS_IN x; +ASSERT NOT ((1,1) IS_IN x); +ASSERT NOT ((1,2) IS_IN x); +ASSERT NOT ((1,3) IS_IN x); +ASSERT NOT ((1,4) IS_IN x); +ASSERT NOT ((1,5) IS_IN x); +ASSERT NOT ((1,6) IS_IN x); +ASSERT NOT ((1,7) IS_IN x); + +ASSERT y = TCLOSURE(x); + +ASSERT (1, 5) IS_IN y; + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tc_3.cvc b/test/regress/regress0/rels/rel_tc_3.cvc new file mode 100644 index 000000000..39564c4cf --- /dev/null +++ b/test/regress/regress0/rels/rel_tc_3.cvc @@ -0,0 +1,22 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +a: INT; +b:INT; +c:INT; +d:INT; +ASSERT (1, a) IS_IN x; +ASSERT (1, c) IS_IN x; +ASSERT (1, d) IS_IN x; +ASSERT (b, 1) IS_IN x; +ASSERT (b = d); +ASSERT (b > (d -1)); +ASSERT (b < (d+1)); +%ASSERT (2,3) IS_IN ((x JOIN x) JOIN x); +%ASSERT NOT (2, 3) IS_IN (TCLOSURE x); +ASSERT y = (TCLOSURE x); +ASSERT NOT ((1, 1) IS_IN y); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tc_3_1.cvc b/test/regress/regress0/rels/rel_tc_3_1.cvc new file mode 100644 index 000000000..7f5535656 --- /dev/null +++ b/test/regress/regress0/rels/rel_tc_3_1.cvc @@ -0,0 +1,18 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +a: INT; +b:INT; +c:INT; +d:INT; +ASSERT (1, a) IS_IN x; +ASSERT (1, c) IS_IN x; +ASSERT (1, d) IS_IN x; +ASSERT (b, 1) IS_IN x; +ASSERT (b = d); + +ASSERT y = (TCLOSURE x); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tc_4.cvc b/test/regress/regress0/rels/rel_tc_4.cvc new file mode 100644 index 000000000..decd38fe1 --- /dev/null +++ b/test/regress/regress0/rels/rel_tc_4.cvc @@ -0,0 +1,19 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +a: INT; +b:INT; +c:INT; +d:INT; +ASSERT (1, a) IS_IN x; +ASSERT (1, c) IS_IN x; +ASSERT (1, d) IS_IN x; +ASSERT (b, 1) IS_IN x; +ASSERT (b = d); +ASSERT (2,b) IS_IN ((x JOIN x) JOIN x); +ASSERT NOT (2, 1) IS_IN (TCLOSURE x); + + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tc_4_1.cvc b/test/regress/regress0/rels/rel_tc_4_1.cvc new file mode 100644 index 000000000..8ee75f7e9 --- /dev/null +++ b/test/regress/regress0/rels/rel_tc_4_1.cvc @@ -0,0 +1,10 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +ASSERT y = ((TCLOSURE x) JOIN x); +ASSERT NOT (y = TCLOSURE x); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tc_5_1.cvc b/test/regress/regress0/rels/rel_tc_5_1.cvc new file mode 100644 index 000000000..fd9caeade --- /dev/null +++ b/test/regress/regress0/rels/rel_tc_5_1.cvc @@ -0,0 +1,9 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +ASSERT y = (TCLOSURE x); +ASSERT NOT ( y = ((x JOIN x) JOIN x)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tc_6.cvc b/test/regress/regress0/rels/rel_tc_6.cvc new file mode 100644 index 000000000..4570c5a8d --- /dev/null +++ b/test/regress/regress0/rels/rel_tc_6.cvc @@ -0,0 +1,9 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +ASSERT y = (TCLOSURE x); +ASSERT NOT (((x JOIN x) JOIN x) <= y); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tc_7.cvc b/test/regress/regress0/rels/rel_tc_7.cvc new file mode 100644 index 000000000..15c0510a6 --- /dev/null +++ b/test/regress/regress0/rels/rel_tc_7.cvc @@ -0,0 +1,10 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +ASSERT y = ((TCLOSURE x) JOIN x); +ASSERT (1,2) IS_IN ((x JOIN x) JOIN x); +ASSERT NOT (y <= TCLOSURE x); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tc_8.cvc b/test/regress/regress0/rels/rel_tc_8.cvc new file mode 100644 index 000000000..9f5879c6d --- /dev/null +++ b/test/regress/regress0/rels/rel_tc_8.cvc @@ -0,0 +1,10 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; + +ASSERT (2, 2) IS_IN (TCLOSURE x); +ASSERT x = {}::SET OF IntPair; + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tc_9_1.cvc b/test/regress/regress0/rels/rel_tc_9_1.cvc new file mode 100644 index 000000000..f884349b1 --- /dev/null +++ b/test/regress/regress0/rels/rel_tc_9_1.cvc @@ -0,0 +1,23 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +w : SET OF IntPair; + +ASSERT z = (TCLOSURE x); +ASSERT w = (x JOIN y); +ASSERT (2, 2) IS_IN z; +ASSERT (0,3) IS_IN y; +ASSERT (-1,3) IS_IN y; +ASSERT (1,3) IS_IN y; +ASSERT (-2,3) IS_IN y; +ASSERT (2,3) IS_IN y; +ASSERT (3,3) IS_IN y; +ASSERT (4,3) IS_IN y; +ASSERT (5,3) IS_IN y; +ASSERT NOT (2, 3) IS_IN (x JOIN y); +ASSERT NOT (2,1) IS_IN x; + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tp_2.cvc b/test/regress/regress0/rels/rel_tp_2.cvc new file mode 100644 index 000000000..441e79c45 --- /dev/null +++ b/test/regress/regress0/rels/rel_tp_2.cvc @@ -0,0 +1,10 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +ASSERT (z = TRANSPOSE(y) OR z = TRANSPOSE(x)); +ASSERT NOT (TRANSPOSE(z) = y); +ASSERT NOT (TRANSPOSE(z) = x); +CHECKSAT; \ No newline at end of file diff --git a/test/regress/regress0/rels/rel_tp_3_1.cvc b/test/regress/regress0/rels/rel_tp_3_1.cvc new file mode 100644 index 000000000..46806b432 --- /dev/null +++ b/test/regress/regress0/rels/rel_tp_3_1.cvc @@ -0,0 +1,14 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z: SET OF IntPair; + +ASSERT (1, 3) IS_IN x; +ASSERT ((2,3) IS_IN z OR (2,1) IS_IN z); +ASSERT y = (TRANSPOSE x); +ASSERT NOT (1,2) IS_IN y; + +ASSERT x = z; +CHECKSAT; \ No newline at end of file diff --git a/test/regress/regress0/rels/rel_tp_join_0.cvc b/test/regress/regress0/rels/rel_tp_join_0.cvc new file mode 100644 index 000000000..a03f0e3fd --- /dev/null +++ b/test/regress/regress0/rels/rel_tp_join_0.cvc @@ -0,0 +1,32 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +r : SET OF IntPair; + + +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); +v : IntPair; +ASSERT v = (1,1); +a : IntPair; +ASSERT a = (5,1); + +b : IntPair; +ASSERT b = (7, 5); + +ASSERT (1, 7) IS_IN x; +ASSERT (2, 3) IS_IN x; +ASSERT (3, 4) IS_IN x; + +ASSERT b IS_IN y; +ASSERT (7, 3) IS_IN y; +ASSERT (4, 7) IS_IN y; +ASSERT r = (x JOIN y); +ASSERT z IS_IN x; +ASSERT zt IS_IN y; +ASSERT NOT (a IS_IN (TRANSPOSE r)); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tp_join_1.cvc b/test/regress/regress0/rels/rel_tp_join_1.cvc new file mode 100644 index 000000000..60b6edf58 --- /dev/null +++ b/test/regress/regress0/rels/rel_tp_join_1.cvc @@ -0,0 +1,32 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +r : SET OF IntPair; + +b : IntPair; +ASSERT b = (1,7); +c : IntPair; +ASSERT c = (2,3); +ASSERT b IS_IN x; +ASSERT c IS_IN x; + +d : IntPair; +ASSERT d = (7,3); +e : IntPair; +ASSERT e = (4,7); + +ASSERT d IS_IN y; +ASSERT e IS_IN y; + +ASSERT (3, 4) IS_IN z; + +a : IntPair; +ASSERT a = (4,1); + +ASSERT r = ((x JOIN y) JOIN z); + +ASSERT NOT (a IS_IN (TRANSPOSE r)); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tp_join_2.cvc b/test/regress/regress0/rels/rel_tp_join_2.cvc new file mode 100644 index 000000000..cc851f622 --- /dev/null +++ b/test/regress/regress0/rels/rel_tp_join_2.cvc @@ -0,0 +1,19 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +r : SET OF IntPair; + +ASSERT (7, 1) IS_IN x; +ASSERT (2, 3) IS_IN x; +ASSERT (7, 3) IS_IN y; +ASSERT (4, 7) IS_IN y; +ASSERT (3, 4) IS_IN z; + +a : IntPair; +ASSERT a = (4,1); +ASSERT r = (((TRANSPOSE x) JOIN y) JOIN z); +ASSERT NOT (a IS_IN (TRANSPOSE r)); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tp_join_2_1.cvc b/test/regress/regress0/rels/rel_tp_join_2_1.cvc new file mode 100644 index 000000000..acf3dbccf --- /dev/null +++ b/test/regress/regress0/rels/rel_tp_join_2_1.cvc @@ -0,0 +1,19 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +r : SET OF IntPair; +ASSERT (7, 1) IS_IN x; +ASSERT (2, 3) IS_IN x; + +ASSERT (7, 3) IS_IN y; +ASSERT (4, 7) IS_IN y; +ASSERT (3, 4) IS_IN z; +a : IntPair; +ASSERT a = (4,1); + +ASSERT r = (((TRANSPOSE x) JOIN y) JOIN z); +ASSERT a IS_IN (TRANSPOSE r); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tp_join_3.cvc b/test/regress/regress0/rels/rel_tp_join_3.cvc new file mode 100644 index 000000000..25277f43a --- /dev/null +++ b/test/regress/regress0/rels/rel_tp_join_3.cvc @@ -0,0 +1,28 @@ +% EXPECT: unsat +% crash on this +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +w : SET OF IntPair; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +r : SET OF IntPair; + +ASSERT (7, 1) IS_IN x; +ASSERT (2, 3) IS_IN x; +ASSERT (7, 3) IS_IN y; +ASSERT (4, 7) IS_IN y; +ASSERT (3, 4) IS_IN z; +ASSERT (3, 3) IS_IN w; + +a : IntPair; +ASSERT a = (4,1); +%ASSERT r = (((TRANSPOSE x) JOIN y) JOIN (w JOIN z)); +ASSERT NOT (a IS_IN (TRANSPOSE r)); + +zz : SET OF IntPair; +ASSERT zz = ((TRANSPOSE x) JOIN y); +ASSERT NOT ((1,3) IS_IN w); +ASSERT NOT ((1,3) IS_IN (w | zz) ); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tp_join_eq_0.cvc b/test/regress/regress0/rels/rel_tp_join_eq_0.cvc new file mode 100644 index 000000000..54e16dd51 --- /dev/null +++ b/test/regress/regress0/rels/rel_tp_join_eq_0.cvc @@ -0,0 +1,28 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +r : SET OF IntPair; + + +ASSERT x = {(1,7), (2,3)}; + +d : IntPair; +ASSERT d = (7,3); +e : IntPair; +ASSERT e = (4,7); + +ASSERT d IS_IN y; +ASSERT e IS_IN y; + +ASSERT (3, 4) IS_IN z; + +a : IntPair; +ASSERT a = (4,1); + +ASSERT r = ((x JOIN y) JOIN z); + +ASSERT NOT (a IS_IN (TRANSPOSE r)); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tp_join_int_0.cvc b/test/regress/regress0/rels/rel_tp_join_int_0.cvc new file mode 100644 index 000000000..8d149a48d --- /dev/null +++ b/test/regress/regress0/rels/rel_tp_join_int_0.cvc @@ -0,0 +1,26 @@ +% EXPECT: unsat +% crash on this +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +w : SET OF IntPair; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +r : SET OF IntPair; + +t : INT; +u : INT; + +ASSERT 4 < t AND t < 6; +ASSERT 4 < u AND u < 6; + +ASSERT (1, u) IS_IN x; +ASSERT (t, 3) IS_IN y; + +a : IntPair; +ASSERT a = (1,3); + +ASSERT NOT (a IS_IN (x JOIN y)); + + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tp_join_pro_0.cvc b/test/regress/regress0/rels/rel_tp_join_pro_0.cvc new file mode 100644 index 000000000..b05026bc9 --- /dev/null +++ b/test/regress/regress0/rels/rel_tp_join_pro_0.cvc @@ -0,0 +1,21 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +IntTup: TYPE = [INT, INT, INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +r : SET OF IntTup; + +ASSERT (2, 1) IS_IN x; +ASSERT (2, 3) IS_IN x; +ASSERT (2, 2) IS_IN y; +ASSERT (4, 7) IS_IN y; +ASSERT (3, 4) IS_IN z; + +v : IntTup; +ASSERT v = (4,3,2,1); + +ASSERT r = (((TRANSPOSE x) JOIN y) PRODUCT z); +ASSERT NOT (v IS_IN (TRANSPOSE r)); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_tp_join_var_0.cvc b/test/regress/regress0/rels/rel_tp_join_var_0.cvc new file mode 100644 index 000000000..aacf6c054 --- /dev/null +++ b/test/regress/regress0/rels/rel_tp_join_var_0.cvc @@ -0,0 +1,28 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +w : SET OF IntPair; +x : SET OF IntPair; +y : SET OF IntPair; +z : SET OF IntPair; +r : SET OF IntPair; + +t : INT; +u : INT; + +ASSERT 4 < t AND t < 6; +ASSERT 4 < u AND u < 6; + +ASSERT (1, t) IS_IN x; +ASSERT (u, 3) IS_IN y; + +a : IntPair; +ASSERT a = (1,3); + +ASSERT NOT (a IS_IN (x JOIN y)); + +st : SET OF INT; +su : SET OF INT; +ASSERT t IS_IN st; +ASSERT u IS_IN su; +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_transpose_0.cvc b/test/regress/regress0/rels/rel_transpose_0.cvc new file mode 100644 index 000000000..49fb87569 --- /dev/null +++ b/test/regress/regress0/rels/rel_transpose_0.cvc @@ -0,0 +1,18 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; + +a: INT; +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); + +ASSERT z IS_IN x; +ASSERT NOT (zt IS_IN (TRANSPOSE x)); + +ASSERT y = (TRANSPOSE x); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_transpose_1.cvc b/test/regress/regress0/rels/rel_transpose_1.cvc new file mode 100644 index 000000000..bdcf31bb8 --- /dev/null +++ b/test/regress/regress0/rels/rel_transpose_1.cvc @@ -0,0 +1,12 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntTup: TYPE = [INT, INT, INT]; +x : SET OF IntTup; +y : SET OF IntTup; +z : IntTup; +ASSERT z = (1,2,3); +zt : IntTup; +ASSERT zt = (3,2,1); +ASSERT z IS_IN x; +ASSERT NOT (zt IS_IN (TRANSPOSE x)); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_transpose_1_1.cvc b/test/regress/regress0/rels/rel_transpose_1_1.cvc new file mode 100644 index 000000000..fa6ee5069 --- /dev/null +++ b/test/regress/regress0/rels/rel_transpose_1_1.cvc @@ -0,0 +1,14 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntTup: TYPE = [INT, INT, INT]; +x : SET OF IntTup; +y : SET OF IntTup; +z : IntTup; +a: INT; +ASSERT z = (1,2,a); +zt : IntTup; +ASSERT zt = (3,2,2); +ASSERT z IS_IN x; +ASSERT zt IS_IN (TRANSPOSE x); +ASSERT y = (TRANSPOSE x); +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_transpose_3.cvc b/test/regress/regress0/rels/rel_transpose_3.cvc new file mode 100644 index 000000000..5dfe3b031 --- /dev/null +++ b/test/regress/regress0/rels/rel_transpose_3.cvc @@ -0,0 +1,15 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); +ASSERT (x = y); +ASSERT z IS_IN x; +ASSERT NOT (zt IS_IN (TRANSPOSE y)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_transpose_4.cvc b/test/regress/regress0/rels/rel_transpose_4.cvc new file mode 100644 index 000000000..b260147c8 --- /dev/null +++ b/test/regress/regress0/rels/rel_transpose_4.cvc @@ -0,0 +1,13 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2); + +ASSERT z IS_IN x; +ASSERT NOT ((2, 1) IS_IN (TRANSPOSE x)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_transpose_5.cvc b/test/regress/regress0/rels/rel_transpose_5.cvc new file mode 100644 index 000000000..203e8b3d2 --- /dev/null +++ b/test/regress/regress0/rels/rel_transpose_5.cvc @@ -0,0 +1,22 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; + +r : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); +ASSERT zt IS_IN y; + +w : IntPair; +ASSERT w = (2, 2); +ASSERT w IS_IN y; +ASSERT z IS_IN x; + +ASSERT NOT (zt IS_IN (TRANSPOSE (x JOIN y))); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_transpose_6.cvc b/test/regress/regress0/rels/rel_transpose_6.cvc new file mode 100644 index 000000000..a2e8bcf10 --- /dev/null +++ b/test/regress/regress0/rels/rel_transpose_6.cvc @@ -0,0 +1,24 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; + +z : IntPair; +ASSERT z = (1,2); +zt : IntPair; +ASSERT zt = (2,1); + +ASSERT z IS_IN x; +ASSERT (3, 4) IS_IN x; +ASSERT (3, 5) IS_IN x; +ASSERT (3, 3) IS_IN x; + +ASSERT x = TRANSPOSE(y); + +ASSERT NOT (zt IS_IN y); + +ASSERT z IS_IN y; +ASSERT NOT (zt IS_IN (TRANSPOSE y)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/rel_transpose_7.cvc b/test/regress/regress0/rels/rel_transpose_7.cvc new file mode 100644 index 000000000..bcc3babc8 --- /dev/null +++ b/test/regress/regress0/rels/rel_transpose_7.cvc @@ -0,0 +1,10 @@ +% EXPECT: unsat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [INT, INT]; +x : SET OF IntPair; +y : SET OF IntPair; + +ASSERT x = y; +ASSERT NOT (TRANSPOSE(x) = TRANSPOSE(y)); + +CHECKSAT; diff --git a/test/regress/regress0/rels/set-strat.cvc b/test/regress/regress0/rels/set-strat.cvc new file mode 100644 index 000000000..0dee0e84d --- /dev/null +++ b/test/regress/regress0/rels/set-strat.cvc @@ -0,0 +1,24 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [ INT, INT]; +SetIntPair: TYPE = [ SET OF IntPair, SET OF IntPair ]; +x : SET OF IntPair; +y : SET OF IntPair; +w : SET OF IntPair; +z : SET OF SetIntPair; + +a : IntPair; +b : IntPair; + +ASSERT NOT a = b; + +ASSERT a IS_IN x; +ASSERT b IS_IN y; +ASSERT b IS_IN w; +ASSERT (x,y) IS_IN z; +ASSERT (w,x) IS_IN z; +ASSERT NOT ( (x,x) IS_IN (z JOIN z) ); + +ASSERT (x, { ( 0, 0 ) } ) IS_IN (z JOIN z); + +CHECKSAT; diff --git a/test/regress/regress0/rels/strat.cvc b/test/regress/regress0/rels/strat.cvc new file mode 100644 index 000000000..b91ddbbe8 --- /dev/null +++ b/test/regress/regress0/rels/strat.cvc @@ -0,0 +1,24 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [ INT, INT]; +IntIntPair: TYPE = [ IntPair, IntPair]; +x : SET OF IntIntPair; +y : SET OF IntIntPair; +z : SET OF IntPair; +w : SET OF IntPair; + +a : IntPair; +b : IntPair; +c : IntIntPair; + +ASSERT NOT a = b; + +ASSERT a IS_IN z; +ASSERT b IS_IN z; +ASSERT (a,b) IS_IN x; +ASSERT (b,a) IS_IN x; +ASSERT c IS_IN x; +ASSERT NOT ( c = (a,b) ) AND NOT ( c = (b,a) ); + + +CHECKSAT; diff --git a/test/regress/regress0/rels/strat_0_1.cvc b/test/regress/regress0/rels/strat_0_1.cvc new file mode 100644 index 000000000..b91ddbbe8 --- /dev/null +++ b/test/regress/regress0/rels/strat_0_1.cvc @@ -0,0 +1,24 @@ +% EXPECT: sat +OPTION "logic" "ALL_SUPPORTED"; +IntPair: TYPE = [ INT, INT]; +IntIntPair: TYPE = [ IntPair, IntPair]; +x : SET OF IntIntPair; +y : SET OF IntIntPair; +z : SET OF IntPair; +w : SET OF IntPair; + +a : IntPair; +b : IntPair; +c : IntIntPair; + +ASSERT NOT a = b; + +ASSERT a IS_IN z; +ASSERT b IS_IN z; +ASSERT (a,b) IS_IN x; +ASSERT (b,a) IS_IN x; +ASSERT c IS_IN x; +ASSERT NOT ( c = (a,b) ) AND NOT ( c = (b,a) ); + + +CHECKSAT; -- 2.30.2