New implementation of sets+cardinality. Merge Paul Meng's relation solver as extensi...
authorajreynol <andrew.j.reynolds@gmail.com>
Wed, 26 Oct 2016 21:23:58 +0000 (16:23 -0500)
committerajreynol <andrew.j.reynolds@gmail.com>
Wed, 26 Oct 2016 21:23:58 +0000 (16:23 -0500)
106 files changed:
src/Makefile.am
src/options/sets_options
src/parser/cvc/Cvc.g
src/printer/cvc/cvc_printer.cpp
src/smt/smt_engine.cpp
src/theory/sets/card_unused_implementation.cpp [deleted file]
src/theory/sets/expr_patterns.h [deleted file]
src/theory/sets/kinds
src/theory/sets/normal_form.h
src/theory/sets/rels_utils.h [new file with mode: 0644]
src/theory/sets/scrutinize.h [deleted file]
src/theory/sets/term_info.h [deleted file]
src/theory/sets/theory_sets.cpp
src/theory/sets/theory_sets.h
src/theory/sets/theory_sets_private.cpp
src/theory/sets/theory_sets_private.h
src/theory/sets/theory_sets_rels.cpp [new file with mode: 0644]
src/theory/sets/theory_sets_rels.h [new file with mode: 0644]
src/theory/sets/theory_sets_rewriter.cpp
src/theory/sets/theory_sets_rewriter.h
src/theory/sets/theory_sets_type_rules.h
test/Makefile.am
test/regress/regress0/Makefile.am
test/regress/regress0/rels/Makefile [new file with mode: 0644]
test/regress/regress0/rels/Makefile.am [new file with mode: 0644]
test/regress/regress0/rels/addr_book_0.cvc [new file with mode: 0644]
test/regress/regress0/rels/addr_book_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/addr_book_1_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/bv1-unit.cvc [new file with mode: 0644]
test/regress/regress0/rels/bv1-unitb.cvc [new file with mode: 0644]
test/regress/regress0/rels/bv1.cvc [new file with mode: 0644]
test/regress/regress0/rels/bv1p-sat.cvc [new file with mode: 0644]
test/regress/regress0/rels/bv1p.cvc [new file with mode: 0644]
test/regress/regress0/rels/bv2.cvc [new file with mode: 0644]
test/regress/regress0/rels/garbage_collect.cvc [new file with mode: 0644]
test/regress/regress0/rels/join-eq-structure-and.cvc [new file with mode: 0644]
test/regress/regress0/rels/join-eq-structure.cvc [new file with mode: 0644]
test/regress/regress0/rels/join-eq-structure_0_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/join-eq-u-sat.cvc [new file with mode: 0644]
test/regress/regress0/rels/join-eq-u.cvc [new file with mode: 0644]
test/regress/regress0/rels/oneLoc_no_quant-int_0_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/prod-mod-eq.cvc [new file with mode: 0644]
test/regress/regress0/rels/prod-mod-eq2.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_1tup_0.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_complex_0.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_complex_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_complex_3.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_complex_4.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_complex_5.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_conflict_0.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_join_0.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_join_0_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_join_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_join_1_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_join_2.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_join_2_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_join_3.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_join_3_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_join_4.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_join_5.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_join_6.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_join_7.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_mix_0_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_pressure_0.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_product_0.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_product_0_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_product_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_product_1_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_symbolic_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_symbolic_1_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_symbolic_2_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_symbolic_3_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tc_10_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tc_11.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tc_2_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tc_3.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tc_3_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tc_4.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tc_4_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tc_5_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tc_6.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tc_7.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tc_8.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tc_9_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tp_2.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tp_3_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tp_join_0.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tp_join_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tp_join_2.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tp_join_2_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tp_join_3.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tp_join_eq_0.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tp_join_int_0.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tp_join_pro_0.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_tp_join_var_0.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_transpose_0.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_transpose_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_transpose_1_1.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_transpose_3.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_transpose_4.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_transpose_5.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_transpose_6.cvc [new file with mode: 0644]
test/regress/regress0/rels/rel_transpose_7.cvc [new file with mode: 0644]
test/regress/regress0/rels/set-strat.cvc [new file with mode: 0644]
test/regress/regress0/rels/strat.cvc [new file with mode: 0644]
test/regress/regress0/rels/strat_0_1.cvc [new file with mode: 0644]

index f5e3776e5edae95aa7be945f0f9ee9f856be43c3..6117ca0572c4add54feaf39c40d7daf40f8ddba9 100644 (file)
@@ -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 \
index be945e4c9e507124d4bb0af65f7959d4fe2cf4ea..4c019c039777b7e695b6c9d3055fc47c52a13852 100644 (file)
@@ -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
index 4c0516eb6a13d566cfd2e01ff9657de0236da1f8..e6d7f9d86fd0961e487107a17ce8fab7e1a330e4 100644 (file)
@@ -109,6 +109,8 @@ tokens {
 
   SUBTYPE_TOK = 'SUBTYPE';
   SET_TOK = 'SET';
+  
+  TUPLE_TOK = 'TUPLE';
 
   FORALL_TOK = 'FORALL';
   EXISTS_TOK = 'EXISTS';
@@ -201,6 +203,12 @@ tokens {
   BVSGT_TOK = 'BVSGT';
   BVSLE_TOK = 'BVSLE';
   BVSGE_TOK = 'BVSGE';
+  
+  // Relations
+  JOIN_TOK = 'JOIN';
+  TRANSPOSE_TOK = 'TRANSPOSE';
+  PRODUCT_TOK = 'PRODUCT';
+  TRANSCLOSURE_TOK = 'TCLOSURE';
 
   // Strings
 
@@ -307,9 +315,14 @@ int getOperatorPrecedence(int type) {
   case STAR_TOK:
   case INTDIV_TOK:
   case DIV_TOK:
+  case TUPLE_TOK:
   case MOD_TOK: return 23;
   case PLUS_TOK:
-  case MINUS_TOK: return 24;
+  case MINUS_TOK:
+  case JOIN_TOK:
+  case TRANSPOSE_TOK:
+  case PRODUCT_TOK:
+  case TRANSCLOSURE_TOK: return 24;
   case LEQ_TOK:
   case LT_TOK:
   case GEQ_TOK:
@@ -346,6 +359,9 @@ Kind getOperatorKind(int type, bool& negate) {
   case OR_TOK: return kind::OR;
   case XOR_TOK: return kind::XOR;
   case AND_TOK: return kind::AND;
+  
+  case PRODUCT_TOK: return kind::PRODUCT;
+  case JOIN_TOK: return kind::JOIN;
 
     // comparisonBinop
   case EQUAL_TOK: return kind::EQUAL;
@@ -1222,8 +1238,8 @@ restrictedTypePossiblyFunctionLHS[CVC4::Type& t,
   | ARRAY_TOK restrictedType[t,check] OF_TOK restrictedType[t2,check]
     { t = EXPR_MANAGER->mkArrayType(t, t2); }
   | SET_TOK OF_TOK restrictedType[t,check]
-    { t = EXPR_MANAGER->mkSetType(t); }
-
+    { t = EXPR_MANAGER->mkSetType(t); } 
+  
     /* subtypes */
   | SUBTYPE_TOK LPAREN
     /* A bit tricky: this LAMBDA expression cannot refer to constants
@@ -1472,6 +1488,8 @@ booleanBinop[unsigned& op]
   | OR_TOK
   | XOR_TOK
   | AND_TOK
+  | JOIN_TOK
+  | PRODUCT_TOK
   ;
 
 comparison[CVC4::Expr& f]
@@ -1651,6 +1669,20 @@ bvNegTerm[CVC4::Expr& f]
     /* BV neg */
   : BVNEG_TOK bvNegTerm[f]
     { f = MK_EXPR(CVC4::kind::BITVECTOR_NOT, f); }
+  | TRANSPOSE_TOK bvNegTerm[f]
+    { f = MK_EXPR(CVC4::kind::TRANSPOSE, f); } 
+  | TRANSCLOSURE_TOK bvNegTerm[f]
+    { f = MK_EXPR(CVC4::kind::TCLOSURE, f); }
+  | TUPLE_TOK LPAREN bvNegTerm[f] RPAREN
+    { std::vector<Type> types;
+      std::vector<Expr> args;
+      args.push_back(f);
+         types.push_back(f.getType());
+      DatatypeType t = EXPR_MANAGER->mkTupleType(types);
+      const Datatype& dt = t.getDatatype();
+      args.insert( args.begin(), dt[0].getConstructor() );
+      f = MK_EXPR(kind::APPLY_CONSTRUCTOR, args);
+    }             
   | postfixTerm[f]
   ;
 
@@ -1969,8 +2001,8 @@ simpleTerm[CVC4::Expr& f]
   Type t, t2;
 }
     /* if-then-else */
-  : iteTerm[f]
-
+  : iteTerm[f] 
+        
     /* parenthesized sub-formula / tuple literals */
   | LPAREN formula[f] { args.push_back(f); }
     ( COMMA formula[f] { args.push_back(f); } )* RPAREN
@@ -1987,14 +2019,15 @@ simpleTerm[CVC4::Expr& f]
         args.insert( args.begin(), dt[0].getConstructor() );
         f = MK_EXPR(kind::APPLY_CONSTRUCTOR, args);
       }
-    }
+    }    
 
     /* empty tuple literal */
   | LPAREN RPAREN
     { std::vector<Type> types;
       DatatypeType t = EXPR_MANAGER->mkTupleType(types);
       const Datatype& dt = t.getDatatype();
-      f = MK_EXPR(kind::APPLY_CONSTRUCTOR, dt[0].getConstructor()); }
+      f = MK_EXPR(kind::APPLY_CONSTRUCTOR, dt[0].getConstructor()); }       
+                  
     /* empty record literal */
   | PARENHASH HASHPAREN
     { DatatypeType t = EXPR_MANAGER->mkRecordType(std::vector< std::pair<std::string, Type> >());
index d09290db58dffd0f2fb819ad54af00d68ed76de0..550f8708155f53bcf9845ed1fef293111e9791d4 100644 (file)
@@ -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);
index 19bc85e3e443e028251b37608231e37ab130d352..f288c6c0acc4cacd639153f37877ae660f0ccc08 100644 (file)
@@ -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 (file)
index 488ee10..0000000
+++ /dev/null
@@ -1,312 +0,0 @@
-// Removing old cardinality implementation, dumping it here.
-
-///////////////////////////////////////////////////////////////
-// Commenting out processCard, creates confusion when writing
-// processCard2
-///////////////////////////////////////////////////////////////
-
-
-// void TheorySetsPrivate::processCard(Theory::Effort level) {
-//   if(level != Theory::EFFORT_FULL) return;
-
-
-//   Trace("sets-card") << "[sets-card] processCard( " << level << ")" << std::endl;
-//   Trace("sets-card") << "[sets-card]   # processed terms = " << d_processedCardTerms.size() << std::endl;
-//   Trace("sets-card") << "[sets-card]   # processed pairs = " << d_processedCardPairs.size() << std::endl;
-//   NodeManager* nm = NodeManager::currentNM();
-
-//   bool newLemmaGenerated = false;
-  
-//   // Introduce lemma
-//   for(typeof(d_cardTerms.begin()) it = d_cardTerms.begin();
-//       it != d_cardTerms.end(); ++it) {
-
-//     for(eq::EqClassIterator j(d_equalityEngine.getRepresentative((*it)[0]), &d_equalityEngine);
-//         !j.isFinished(); ++j) {
-
-//       Node n = nm->mkNode(kind::CARD, (*j));
-
-//       if(d_processedCardTerms.find(n) != d_processedCardTerms.end()) {
-//         continue;
-//       }
-
-//       Trace("sets-card") << "[sets-card]  Processing " << n << " in eq cl of " << (*it) << std::endl;
-
-//       newLemmaGenerated = true;
-//       d_processedCardTerms.insert(n);
-      
-//       Kind k = n[0].getKind();
-
-//       if(k == kind::SINGLETON) {
-//         d_external.d_out->lemma(nm->mkNode(kind::EQUAL,
-//                                            n,
-//                                            nm->mkConst(Rational(1))));
-//         continue;
-//       } else {
-//         d_external.d_out->lemma(nm->mkNode(kind::GEQ,
-//                                            n,
-//                                            nm->mkConst(Rational(0))));
-//       }
-
-//       // rest of the processing is for compound terms
-//       if(k != kind::UNION && k != kind::INTERSECTION && k != kind::SETMINUS) {
-//         continue;
-//       }
-  
-//       Node s = min(n[0][0], n[0][1]);
-//       Node t = max(n[0][0], n[0][1]);
-//       bool isUnion = (k == kind::UNION);
-//       Assert(Rewriter::rewrite(s) == s);
-//       Assert(Rewriter::rewrite(t) == t);
-
-//       typeof(d_processedCardPairs.begin()) processedInfo = d_processedCardPairs.find(make_pair(s, t));
-
-//       if(processedInfo == d_processedCardPairs.end()) {
-
-//         Node sNt = nm->mkNode(kind::INTERSECTION, s, t);
-//         sNt = Rewriter::rewrite(sNt);
-//         Node sMt = nm->mkNode(kind::SETMINUS, s, t);
-//         sMt = Rewriter::rewrite(sMt);
-//         Node tMs = nm->mkNode(kind::SETMINUS, t, s);
-//         tMs = Rewriter::rewrite(tMs);
-
-//         Node card_s = nm->mkNode(kind::CARD, s);
-//         Node card_t = nm->mkNode(kind::CARD, t);
-//         Node card_sNt = nm->mkNode(kind::CARD, sNt);
-//         Node card_sMt = nm->mkNode(kind::CARD, sMt);
-//         Node card_tMs = nm->mkNode(kind::CARD, tMs);
-
-//         Node lem;
-      
-//         // for s
-//         lem = nm->mkNode(kind::EQUAL,
-//                          card_s,
-//                          nm->mkNode(kind::PLUS, card_sNt, card_sMt));
-//         d_external.d_out->lemma(lem);
-
-//         // for t
-//         lem = nm->mkNode(kind::EQUAL,
-//                          card_t,
-//                          nm->mkNode(kind::PLUS, card_sNt, card_tMs));
-
-//         d_external.d_out->lemma(lem);
-
-//         // for union
-//         if(isUnion) {
-//           lem = nm->mkNode(kind::EQUAL,
-//                            n,     // card(s union t)
-//                            nm->mkNode(kind::PLUS, card_sNt, card_sMt, card_tMs));
-//           d_external.d_out->lemma(lem);
-//         }
-      
-//         d_processedCardPairs.insert(make_pair(make_pair(s, t), isUnion));
-
-//       } else if(isUnion && processedInfo->second == false) {
-      
-//         Node sNt = nm->mkNode(kind::INTERSECTION, s, t);
-//         sNt = Rewriter::rewrite(sNt);
-//         Node sMt = nm->mkNode(kind::SETMINUS, s, t);
-//         sMt = Rewriter::rewrite(sMt);
-//         Node tMs = nm->mkNode(kind::SETMINUS, t, s);
-//         tMs = Rewriter::rewrite(tMs);
-
-//         Node card_s = nm->mkNode(kind::CARD, s);
-//         Node card_t = nm->mkNode(kind::CARD, t);
-//         Node card_sNt = nm->mkNode(kind::CARD, sNt);
-//         Node card_sMt = nm->mkNode(kind::CARD, sMt);
-//         Node card_tMs = nm->mkNode(kind::CARD, tMs);
-
-//         Assert(Rewriter::rewrite(n[0]) == n[0]);
-
-//         Node lem = nm->mkNode(kind::EQUAL,
-//                               n,     // card(s union t)
-//                               nm->mkNode(kind::PLUS, card_sNt, card_sMt, card_tMs));
-//         d_external.d_out->lemma(lem);
-
-//         processedInfo->second = true;
-//       }
-    
-//     }//equivalence class loop
-
-//   }//d_cardTerms loop
-
-//   if(newLemmaGenerated) {
-//     Trace("sets-card") << "[sets-card] New introduce done. Returning." << std::endl;
-//     return;
-//   }
-
-
-
-//   // Leaves disjoint lemmas
-//   buildGraph();
-
-//   // Leaves disjoint lemmas
-//   for(typeof(leaves.begin()) it = leaves.begin(); it != leaves.end(); ++it) {
-//     TNode l1 = (*it);
-//     if(d_equalityEngine.getRepresentative(l1).getKind() == kind::EMPTYSET) continue;
-//     for(typeof(leaves.begin()) jt = leaves.begin(); jt != leaves.end(); ++jt) {
-//       TNode l2 = (*jt);
-
-//       if(d_equalityEngine.getRepresentative(l2).getKind() == kind::EMPTYSET) continue;
-
-//       if( l1 == l2 ) continue;
-
-//       Node l1_inter_l2 = nm->mkNode(kind::INTERSECTION, min(l1, l2), max(l1, l2));
-//       l1_inter_l2 = Rewriter::rewrite(l1_inter_l2);
-//       Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType(l1_inter_l2.getType())));
-//       if(d_equalityEngine.hasTerm(l1_inter_l2) &&
-//          d_equalityEngine.hasTerm(emptySet) &&
-//          d_equalityEngine.areEqual(l1_inter_l2, emptySet)) {
-//         Debug("sets-card-graph") << "[sets-card-graph] Disjoint (asserted): " << l1 << " and " << l2 << std::endl;
-//         continue;               // known to be disjoint
-//       }
-
-//       std::set<TNode> l1_ancestors = getReachable(edgesBk, l1);
-//       std::set<TNode> l2_ancestors = getReachable(edgesBk, l2);
-
-//       // have a disjoint edge
-//       bool loop = true;
-//       bool equality = false;
-//       for(typeof(l1_ancestors.begin()) l1_it = l1_ancestors.begin();
-//           l1_it != l1_ancestors.end() && loop; ++l1_it) {
-//         for(typeof(l2_ancestors.begin()) l2_it = l2_ancestors.begin();
-//             l2_it != l2_ancestors.end() && loop; ++l2_it) {
-//           TNode n1 = (*l1_it);
-//           TNode n2 = (*l2_it);
-//           if(disjoint.find(make_pair(n1, n2)) != disjoint.find(make_pair(n2, n1))) {
-//             loop = false;
-//           }
-//           if(n1 == n2) {
-//             equality = true;
-//           }
-//           if(d_equalityEngine.hasTerm(n1) && d_equalityEngine.hasTerm(n2) &&
-//              d_equalityEngine.areEqual(n1, n2)) {
-//             equality = true;
-//           }
-//         }
-//       }
-//       if(loop == false) {
-//         Debug("sets-card-graph") << "[sets-card-graph] Disjoint (always): " << l1 << " and " << l2 << std::endl;
-//         continue;
-//       }
-//       if(equality == false) {
-//         Debug("sets-card-graph") << "[sets-card-graph] No equality found: " << l1 << " and " << l2 << std::endl;
-//         continue;
-//       }
-
-//       Node lem = nm->mkNode(kind::OR,
-//                             nm->mkNode(kind::EQUAL, l1_inter_l2, emptySet),
-//                             nm->mkNode(kind::LT, nm->mkConst(Rational(0)),
-//                                        nm->mkNode(kind::CARD, l1_inter_l2)));
-
-//       d_external.d_out->lemma(lem);
-//       Trace("sets-card") << "[sets-card] Guessing disjointness of : " << l1 << " and " << l2 << std::endl;
-//       if(Debug.isOn("sets-card-disjoint")) {
-//         Debug("sets-card-disjoint") << "[sets-card-disjoint] Lemma for " << l1 << " and " << l2 << " generated because:" << std::endl;
-//         for(typeof(disjoint.begin()) it = disjoint.begin(); it != disjoint.end(); ++it) {
-//           Debug("sets-card-disjoint") << "[sets-card-disjoint]   " << it->first << " " << it->second << std::endl;
-//         }
-//       }
-//       newLemmaGenerated = true;
-//       Trace("sets-card") << "[sets-card] New intersection being empty lemma generated. Returning." << std::endl;
-//       return;
-//     }
-//   }
-
-//   Assert(!newLemmaGenerated);
-
-
-
-//   // Elements being either equal or disequal
-  
-//   for(typeof(leaves.begin()) it = leaves.begin();
-//       it != leaves.end(); ++it) {
-//     Assert(d_equalityEngine.hasTerm(*it));
-//     Node n = d_equalityEngine.getRepresentative(*it);
-//     Assert(n.getKind() == kind::EMPTYSET || leaves.find(n) != leaves.end());
-//     if(n != *it) continue;
-//     const CDTNodeList* l = d_termInfoManager->getMembers(*it);
-//     std::set<TNode> elems;
-//     for(typeof(l->begin()) l_it = l->begin(); l_it != l->end(); ++l_it) {
-//       elems.insert(d_equalityEngine.getRepresentative(*l_it));
-//     }
-//     for(typeof(elems.begin()) e1_it = elems.begin(); e1_it != elems.end(); ++e1_it) {
-//       for(typeof(elems.begin()) e2_it = elems.begin(); e2_it != elems.end(); ++e2_it) {
-//         if(*e1_it == *e2_it) continue;
-//         if(!d_equalityEngine.areDisequal(*e1_it, *e2_it, false)) {
-//           Node lem = nm->mkNode(kind::EQUAL, *e1_it, *e2_it);
-//           lem = nm->mkNode(kind::OR, lem, nm->mkNode(kind::NOT, lem));
-//           d_external.d_out->lemma(lem);
-//           newLemmaGenerated = true;
-//         }
-//       }
-//     }
-//   }
-
-//   if(newLemmaGenerated) {
-//     Trace("sets-card") << "[sets-card] Members arrangments lemmas. Returning." << std::endl;
-//     return;
-//   }
-
-
-//   // Guess leaf nodes being empty or non-empty
-//   for(typeof(leaves.begin()) it = leaves.begin(); it != leaves.end(); ++it) {
-//     Node n = d_equalityEngine.getRepresentative(*it);
-//     if(n.getKind() == kind::EMPTYSET) continue;
-//     if(d_termInfoManager->getMembers(n)->size() > 0) continue;
-//     Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType(n.getType())));
-//     if(!d_equalityEngine.hasTerm(emptySet)) {
-//       d_equalityEngine.addTerm(emptySet);
-//     }
-//     if(!d_equalityEngine.areDisequal(n, emptySet, false)) {
-//       Node lem = nm->mkNode(kind::EQUAL, n, emptySet);
-//       lem = nm->mkNode(kind::OR, lem, nm->mkNode(kind::NOT, lem));
-//       Assert(d_cardLowerLemmaCache.find(lem) == d_cardLowerLemmaCache.end());
-//       d_cardLowerLemmaCache.insert(lem);
-//       d_external.d_out->lemma(lem);
-//       newLemmaGenerated = true;
-//       break;
-//     }
-//   }
-
-//   if(newLemmaGenerated) {
-//     Trace("sets-card") << "[sets-card] New guessing leaves being empty done." << std::endl;
-//     return;
-//   }
-
-//   // Assert Lower bound
-//   for(typeof(leaves.begin()) it = leaves.begin();
-//       it != leaves.end(); ++it) {
-//     Assert(d_equalityEngine.hasTerm(*it));
-//     Node n = d_equalityEngine.getRepresentative(*it);
-//     Assert(n.getKind() == kind::EMPTYSET || leaves.find(n) != leaves.end());
-//     if(n != *it) continue;
-//     const CDTNodeList* l = d_termInfoManager->getMembers(n);
-//     std::set<TNode> elems;
-//     for(typeof(l->begin()) l_it = l->begin(); l_it != l->end(); ++l_it) {
-//       elems.insert(d_equalityEngine.getRepresentative(*l_it));
-//     }
-//     if(elems.size() == 0) continue;
-//     NodeBuilder<> nb(kind::OR);
-//     nb << ( nm->mkNode(kind::LEQ, nm->mkConst(Rational(elems.size())), nm->mkNode(kind::CARD, n)) );
-//     if(elems.size() > 1) {
-//       for(typeof(elems.begin()) e1_it = elems.begin(); e1_it != elems.end(); ++e1_it) {
-//         for(typeof(elems.begin()) e2_it = elems.begin(); e2_it != elems.end(); ++e2_it) {
-//           if(*e1_it == *e2_it) continue;
-//           nb << (nm->mkNode(kind::EQUAL, *e1_it, *e2_it));
-//         }
-//       }
-//     }
-//     for(typeof(elems.begin()) e_it = elems.begin(); e_it != elems.end(); ++e_it) {
-//       nb << nm->mkNode(kind::NOT, nm->mkNode(kind::MEMBER, *e_it, n));
-//     }
-//     Node lem = Node(nb);
-//     if(d_cardLowerLemmaCache.find(lem) == d_cardLowerLemmaCache.end()) {
-//       Trace("sets-card") << "[sets-card] Card Lower: " << lem << std::endl;
-//       d_external.d_out->lemma(lem);
-//       d_cardLowerLemmaCache.insert(lem);
-//       newLemmaGenerated = true;
-//     }
-//   }  
-// }
-
diff --git a/src/theory/sets/expr_patterns.h b/src/theory/sets/expr_patterns.h
deleted file mode 100644 (file)
index 32e77d8..0000000
+++ /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 */
index 14c87a947c6be49f52124071ac69732932a3f376..c92eab4bde9badff796edd91c6ec7efdeb55ed3d 100644 (file)
@@ -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
index c1f05ae85da3064631ef0c83d005d46e7bae8f4d..6379fb29909b35c965acdaff7acfeb187d4d17e3 100644 (file)
@@ -106,6 +106,31 @@ class NormalForm {
     ret.insert(n[0]);
     return ret;
   }
+  
+  
+  //AJR
+  
+  static void getElementsFromBop( Kind k, Node n, std::vector< Node >& els ){
+    if( n.getKind()==k ){
+      for( unsigned i=0; i<n.getNumChildren(); i++ ){
+        getElementsFromBop( k, n[i], els );
+      }
+    }else{
+      if( std::find( els.begin(), els.end(), n )==els.end() ){
+        els.push_back( n );
+      }
+    }
+  }
+  static Node mkBop( Kind k, std::vector< Node >& els, TypeNode tn, unsigned index = 0 ){
+    if( index>=els.size() ){
+      return NodeManager::currentNM()->mkConst(EmptySet(tn.toType()));
+    }else if( index==els.size()-1 ){
+      return els[index];
+    }else{
+      return NodeManager::currentNM()->mkNode( k, els[index], mkBop( k, els, tn, index+1 ) );
+    }
+  }
+
 };
 }
 }
diff --git a/src/theory/sets/rels_utils.h b/src/theory/sets/rels_utils.h
new file mode 100644 (file)
index 0000000..df14bf5
--- /dev/null
@@ -0,0 +1,96 @@
+/*********************                                                        */
+/*! \file rels_utils.h
+ ** \verbatim
+ ** Original author: Paul Meng
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014  New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Sets theory implementation.
+ **
+ ** Extension to Sets theory.
+ **/
+
+#ifndef SRC_THEORY_SETS_RELS_UTILS_H_
+#define SRC_THEORY_SETS_RELS_UTILS_H_
+
+namespace CVC4 {
+namespace theory {
+namespace sets {
+
+class RelsUtils {
+
+public:
+
+  // Assumption: the input rel_mem contains all constant pairs
+  static std::set< Node > computeTC( std::set< Node > rel_mem, Node rel ) {
+    std::set< Node >::iterator mem_it = rel_mem.begin();
+    std::map< Node, int > ele_num_map;
+    std::set< Node > tc_rel_mem;
+       
+    while( mem_it != rel_mem.end() ) {
+      Node fst = nthElementOfTuple( *mem_it, 0 );
+      Node snd = nthElementOfTuple( *mem_it, 1 );
+      std::set< Node > traversed;
+      traversed.insert(fst);
+      computeTC(rel, rel_mem, fst, snd, traversed, tc_rel_mem);      
+      mem_it++;             
+    }
+    return tc_rel_mem;
+  }
+  
+  static void computeTC( Node rel, std::set< Node >& rel_mem, Node fst, 
+                         Node snd, std::set< Node >& traversed, std::set< Node >& tc_rel_mem ) {    
+    tc_rel_mem.insert(constructPair(rel, fst, snd));
+    if( traversed.find(snd) == traversed.end() ) {
+      traversed.insert(snd);
+    } else {
+      return;
+    }
+
+    std::set< Node >::iterator mem_it = rel_mem.begin();
+    while( mem_it != rel_mem.end() ) {
+      Node new_fst = nthElementOfTuple( *mem_it, 0 );
+      Node new_snd = nthElementOfTuple( *mem_it, 1 );
+      if( snd == new_fst ) {
+        computeTC(rel, rel_mem, fst, new_snd, traversed, tc_rel_mem);
+      }
+      mem_it++; 
+    }  
+  }
+  static Node nthElementOfTuple( Node tuple, int n_th ) {    
+    if( tuple.getKind() == kind::APPLY_CONSTRUCTOR ) {
+      return tuple[n_th];
+    }
+    Datatype dt = tuple.getType().getDatatype();
+    return NodeManager::currentNM()->mkNode(kind::APPLY_SELECTOR_TOTAL, dt[0][n_th].getSelector(), tuple);
+  } 
+  
+  static Node reverseTuple( Node tuple ) {
+    Assert( tuple.getType().isTuple() );
+    std::vector<Node> elements;
+    std::vector<TypeNode> tuple_types = tuple.getType().getTupleTypes();
+    std::reverse( tuple_types.begin(), tuple_types.end() );
+    TypeNode tn = NodeManager::currentNM()->mkTupleType( tuple_types );
+    Datatype dt = tn.getDatatype();
+    elements.push_back( Node::fromExpr(dt[0].getConstructor() ) );
+    for(int i = tuple_types.size() - 1; i >= 0; --i) {
+      elements.push_back( nthElementOfTuple(tuple, i) );
+    }
+    return NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, elements );
+  }
+  static Node constructPair(Node rel, Node a, Node b) {
+    Datatype dt = rel.getType().getSetElementType().getDatatype();
+    return NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, Node::fromExpr(dt[0].getConstructor()), a, b);
+  }     
+    
+};             
+}/* CVC4::theory::sets namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif
diff --git a/src/theory/sets/scrutinize.h b/src/theory/sets/scrutinize.h
deleted file mode 100644 (file)
index 88f6001..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*********************                                                        */
-/*! \file scrutinize.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Kshitij Bansal, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Check consistency of internal data structures.
- **
- ** Some checks are very low-level with respect to TheorySetsPrivate
- ** implementation, and hence might become outdated pretty quickly.
- **/
-
-#pragma once
-
-#include "theory/sets/theory_sets.h"
-#include "theory/sets/theory_sets_private.h"
-
-namespace CVC4 {
-namespace theory {
-namespace sets {
-
-class TheorySetsScrutinize {
-  /* we don't want to accidentally modify theory data */
-  const TheorySetsPrivate* d_theory;
-public:
-  TheorySetsScrutinize(TheorySetsPrivate* theory): d_theory(theory) {
-    Debug("sets") << "[sets] scrunitize enabled" << std::endl;
-  }
-  void postCheckInvariants() const {
-    Debug("sets-scrutinize") << "[sets-scrutinize] postCheckInvariants()" << std::endl;
-
-    // assume not in conflict, and complete:
-    // - try building model
-    // - check it
-
-    TheorySetsPrivate::SettermElementsMap settermElementsMap;
-    TNode true_atom = NodeManager::currentNM()->mkConst<bool>(true);
-    std::set<Node> terms;
-    (d_theory->d_external).computeRelevantTerms(terms);
-    for(eq::EqClassIterator it_eqclasses(true_atom, &d_theory->d_equalityEngine);
-        ! it_eqclasses.isFinished() ; ++it_eqclasses) {
-      TNode n = (*it_eqclasses);
-      if(n.getKind() == kind::MEMBER) {
-        Assert(d_theory->d_equalityEngine.areEqual(n, true_atom));
-        TNode x = d_theory->d_equalityEngine.getRepresentative(n[0]);
-        TNode S = d_theory->d_equalityEngine.getRepresentative(n[1]);
-        settermElementsMap[S].insert(x);
-      }
-    }
-    bool checkPassed = true;
-    for (std::set<Node>::const_iterator it = terms.begin(); it != terms.end(); it++){
-      TNode term = *it;
-      if( term.getType().isSet() ) {
-        checkPassed &= d_theory->checkModel(settermElementsMap, term);
-      }
-    }
-    if(Debug.isOn("sets-checkmodel-ignore")) {
-      Debug("sets-checkmodel-ignore") << "[sets-checkmodel-ignore] checkPassed value was " << checkPassed << std::endl;
-    } else {
-      Assert( checkPassed,
-              "THEORY_SETS check-model failed. Run with -d sets-model for details." );
-    }
-  }
-};
-
-}/* CVC4::theory::sets namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
diff --git a/src/theory/sets/term_info.h b/src/theory/sets/term_info.h
deleted file mode 100644 (file)
index c7d4b38..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*********************                                                        */
-/*! \file term_info.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Kshitij Bansal, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2016 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved.  See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Term info.
- **
- ** Term info.
- **/
-
-#include "cvc4_private.h"
-
-#pragma once
-
-namespace CVC4 {
-namespace theory {
-namespace sets {
-
-
-typedef context::CDList<TNode> CDTNodeList;
-typedef context::CDHashSet<Node, NodeHashFunction> CDNodeSet;
-typedef context::CDHashSet<Node, NodeHashFunction> CDNodeSet;
-
-class TheorySetsTermInfo {
-public:
-  CDTNodeList* elementsInThisSet;
-  CDTNodeList* elementsNotInThisSet;
-  CDTNodeList* setsContainingThisElement;
-  CDTNodeList* setsNotContainingThisElement;
-  CDTNodeList* parents;
-
-  TheorySetsTermInfo(context::Context* c)
-  {
-    elementsInThisSet = new(true)CDTNodeList(c);
-    elementsNotInThisSet = new(true)CDTNodeList(c);
-    setsContainingThisElement = new(true)CDTNodeList(c);
-    setsNotContainingThisElement = new(true)CDTNodeList(c);
-    parents = new(true)CDTNodeList(c);
-  }
-
-  void addToElementList(TNode n, bool polarity) {
-    if(polarity) elementsInThisSet -> push_back(n);
-    else elementsNotInThisSet -> push_back(n);
-  }
-
-  void addToSetList(TNode n, bool polarity) {
-    if(polarity) setsContainingThisElement -> push_back(n);
-    else setsNotContainingThisElement -> push_back(n);
-  }
-
-  ~TheorySetsTermInfo() {
-    elementsInThisSet -> deleteSelf();
-    elementsNotInThisSet -> deleteSelf();
-    setsContainingThisElement -> deleteSelf();
-    setsNotContainingThisElement -> deleteSelf();
-    parents -> deleteSelf();
-  }
-
-};
-
-}/* CVC4::theory::sets namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
index bdbc964c6bafc683874fbdc392334c1eb5bb0a4d..52afe05e27b2593354f56512e68a282755d06de5 100644 (file)
@@ -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 */
index bbeaf4a4cb51982ea342eda89f422cc7231166bf..2ebb9947dc7c861f8a96aa78b7005955f2108ee5 100644 (file)
@@ -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 */
 
index 6fb90fea3978808461ee946364ba3c28da7b27c5..edf250c4d895ade0e1f5691630a01c1a8058ff88 100644 (file)
 #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<TNode> getLeaves(map<TNode, set<TNode> >& edges, TNode node);
-
-/**************************** TheorySetsPrivate *****************************/
-/**************************** TheorySetsPrivate *****************************/
-/**************************** TheorySetsPrivate *****************************/
-
-void TheorySetsPrivate::check(Theory::Effort level) {
-  d_newLemmaGenerated = false;
-  while(!d_external.done() && !d_conflict) {
-    // Get all the assertions
-    Assertion assertion = d_external.get();
-    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>(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; j<n_members; j++ ){
+          Assert( j<(int)d_members_data[t1].size() && d_members_data[t1][j].getKind()==kind::MEMBER );
+          if( ee_areEqual( m2[0], d_members_data[t1][j][0] ) ){
+            add = false;
+            break;
+          }
+        }
+        if( add ){
+          if( !s1.isNull() && s2.isNull() ){
+            Assert( m2[1].getType()==s1.getType() );
+            Assert( ee_areEqual( m2[1], s1 ) );
+            Node exp = NodeManager::currentNM()->mkNode( kind::AND, m2[1].eqNode( s1 ), m2 );
+            if( s1.getKind()==kind::SINGLETON ){
+              if( s1[0]!=m2[0] ){
+                Node eq = s1[0].eqNode( m2[0] );
+                d_keep.insert( exp );
+                d_keep.insert( eq );
+                Trace("sets-prop") << "Propagate eq-mem eq inference : " << exp << " => " << eq << std::endl;
+                assertFact( eq, exp );
+              }
+            }else{
+              //conflict
+              Trace("sets-prop") << "Propagate eq-mem conflict : " << exp << std::endl;
+              d_conflict = true;
+              d_external.d_out->conflict( exp );
+              return;
+            }
+          }
+          if( n_members<(int)d_members_data[t1].size() ){
+            d_members_data[t1][n_members] = m2;
+          }else{
+            d_members_data[t1].push_back( m2 );
+          }
+          n_members++;
+        }
       }
+      d_members[t1] = n_members;
     }
+    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; i<n.getNumChildren(); i++ ){
+      bool isEnt = isEntailed( n[i], polarity );
+      if( isEnt==conj ){
+        return conj;
+      }
     }
+    return !conj;
+  }else if( n.isConst() ){
+    return ( polarity && n==d_true ) || ( !polarity && n==d_false );
   }
-
-  // check fulfilling rule
-  Node n;
-  switch(S.getKind()) {
-  case kind::UNION:
-    if( holds(MEMBER(x, S)) &&
-        !present( MEMBER(x, S[0]) ) )
-      addToPending( MEMBER(x, S[0]) );
-    break;
-  case kind::SETMINUS: // intentional fallthrough
-    if( holds(MEMBER(x, S[0])) &&
-        !present( MEMBER(x, S[1]) ))
-      addToPending( MEMBER(x, S[1]) );
-    break;
-  case kind::INTERSECTION:
-    return;
-  default:
-    Assert(false, "MembershipEngine::doSettermPropagation");
-  }
+  return false;
 }
 
-
-void TheorySetsPrivate::learnLiteral(TNode atom, bool polarity, Node reason) {
-  Debug("sets-learn") << "[sets-learn] learnLiteral(" << atom
-                      << ", " << polarity << ")" << std::endl;
-
-  if( holds(atom, polarity) ) {
-    Debug("sets-learn") << "[sets-learn] \u2514 already known, skipping" << std::endl;
-    return;
-  }
-
-  if( holds(atom, !polarity) ) {
-    Debug("sets-learn") << "[sets-learn] \u2514 conflict found" << std::endl;
-
-    registerReason(reason, /*save=*/ true);
-
-    if(atom.getKind() == kind::EQUAL) {
-      d_equalityEngine.assertEquality(atom, polarity, reason);
-    } else {
-      d_equalityEngine.assertPredicate(atom, polarity, reason);
+bool TheorySetsPrivate::isMember( Node x, Node s ) {
+  Assert( d_equalityEngine.hasTerm( s ) && d_equalityEngine.getRepresentative( s )==s );
+  NodeIntMap::iterator mem_i = d_members.find( s );
+  if( mem_i != d_members.end() ) {
+    for( int i=0; i<(*mem_i).second; i++ ){
+      if( ee_areEqual( d_members_data[s][i][0], x ) ){
+        return true;
+      }
     }
-    Assert(d_conflict);       // should be marked due to equality engine
-    return;
-  }
-
-  Assert(atom.getKind() == kind::EQUAL || atom.getKind() == kind::MEMBER);
-
-  Node learnt_literal = polarity ? Node(atom) : NOT(atom);
-  d_propagationQueue.push_back( make_pair(learnt_literal, reason) );
-}/*TheorySetsPrivate::learnLiteral(...)*/
-
-
-/************************ CardVar ************************/
-
-Node TheorySetsPrivate::getCardVar(TNode n) {
-  NodeNodeHashMap::iterator it = d_setTermToCardVar.find(n);
-  if(it == d_setTermToCardVar.end()) {
-    return it->second;
-  } else {
-    NodeManager* nm = NodeManager::currentNM();
-    Node cardVar = nm->mkSkolem("scv_",  n.getType());
-    d_setTermToCardVar[n] = cardVar;
-    d_cardVarToSetTerm[cardVar] = n;
-    return cardVar;
   }
+  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<Assertion>::const_iterator it = d_external.facts_begin(), it_end = d_external.facts_end();
-
-    typedef std::set<TNode> TNodeSet;
-
-    typedef std::map<TNode, TNodeSet > EqualityMap;
-    EqualityMap equalities;
-
-    typedef std::set< std::pair<TNode, TNode> > TNodePairSet;
-    TNodePairSet disequalities;
-    typedef std::map<TNode, std::pair<TNodeSet, TNodeSet > > MemberMap;
-    MemberMap members;
-    static std::map<TNode, int> numbering;
-    static int number = 0;
-
-    for (unsigned i = 0; it != it_end; ++ it, ++i) {
-      TNode ass = (*it).assertion;
-      // Trace("sets-care-dump") << AssertCommand(ass.toExpr()) << endl;
-      bool polarity = ass.getKind() != kind::NOT;
-      ass = polarity ? ass : ass[0];
-      Assert( ass.getNumChildren() == 2);
-      TNode left = d_equalityEngine.getRepresentative(ass[0]);
-      TNode right = d_equalityEngine.getRepresentative(ass[1]);
-      if(numbering[left] == 0) numbering[left] = ++number;
-      if(numbering[right] == 0) numbering[right] = ++number;
-      equalities[left].insert(ass[0]);
-      equalities[right].insert(ass[1]);
-      if(ass.getKind() == kind::EQUAL) {
-        if(polarity) {
-          Assert(left == right);
-        } else {
-          if(left > right) std::swap(left, right);
-          disequalities.insert(make_pair(left, right));
+bool TheorySetsPrivate::assertFactRec( Node fact, Node exp, std::vector< Node >& lemma, int inferType ) {
+  if( ( options::setsInferAsLemmas() && inferType!=-1 ) || inferType==1 ){
+    if( !isEntailed( fact, true ) ){
+      lemma.push_back( exp==d_true ? fact : NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, fact ) );
+      return true;
+    }
+  }else{
+    Trace("sets-fact") << "Assert fact rec : " << fact << ", exp = " << exp << std::endl;
+    if( fact.isConst() ){
+      //either trivial or a conflict
+      if( fact==d_false ){
+        Trace("sets-lemma") << "Conflict : " << exp << std::endl;
+        d_conflict = true;
+        d_external.d_out->conflict( exp );
+        return true;
+      }
+    }else if( fact.getKind()==kind::AND || ( fact.getKind()==kind::NOT && fact[0].getKind()==kind::OR ) ){
+      bool ret = false;
+      Node f = fact.getKind()==kind::NOT ? fact[0] : fact;
+      for( unsigned i=0; i<f.getNumChildren(); i++ ){
+        Node factc = fact.getKind()==kind::NOT ? f[i].negate() : f[i];
+        bool tret = assertFactRec( factc, exp, lemma, inferType );
+        ret = ret || tret;
+        if( d_conflict ){
+          return true;
+        }
+      }
+      return ret;
+    }else{
+      bool polarity = fact.getKind() != kind::NOT;
+      TNode atom = polarity ? fact : fact[0];
+      //things we can assert to equality engine
+      if( atom.getKind()==kind::MEMBER || ( atom.getKind()==kind::EQUAL && atom[0].getType().isSet() ) ){
+        //send to equality engine
+        if( assertFact( fact, exp ) ){
+          d_addedFact = true;
+          return true;
+        }
+      }else{
+        if( !isEntailed( fact, true ) ){
+          //must send as lemma
+          lemma.push_back( exp==d_true ? fact : NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, fact ) );
+          return true;
         }
-      } 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"<<numbering[(*kt).first]<<" = t" <<numbering[(*kt).second] <<")"<< std::endl;
-    }
-    for(MemberMap::const_iterator kt=members.begin(); kt != members.end(); ++kt) {
-      const TNode& kt_key = (*kt).first;
-      const TNodeSet& kt_in_set = (*kt).second.first;
-      const TNodeSet& kt_out_set = (*kt).second.first;
-      if( kt_in_set.size() > 0) {
-        Trace(tag) << "IN t" << numbering[kt_key] << ": ";
-        //FORIT(jt, (*kt).second.first)
-        for(TNodeSet::const_iterator jt=kt_in_set.begin(); jt != kt_in_set.end(); ++jt) {
-          TNode x = (*jt);
-          if(x.isConst() || numbering.find(d_equalityEngine.getRepresentative(x)) == numbering.end()) {
-            Trace(tag) << x << ", ";
-          } else {
-            Trace(tag) << "t" << numbering[d_equalityEngine.getRepresentative(x)] << ", ";
+    
+    flushLemmas( lemmas );
+    if( !hasProcessed() ){
+      if( Trace.isOn("sets-mem") ){
+        for( unsigned i=0; i<d_set_eqc.size(); i++ ){
+          Node s = d_set_eqc[i];
+          Trace("sets-mem") << "Eqc " << s << " : ";
+          std::map< Node, std::map< Node, Node > >::iterator it = d_pol_mems[0].find( s );
+          if( it!=d_pol_mems[0].end() ){
+            Trace("sets-mem") << "Memberships : ";
+            for( std::map< Node, Node >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){
+              Trace("sets-mem") << it2->first << " ";
+            }
+          }
+          std::map< Node, Node >::iterator its = d_eqc_singleton.find( s );
+          if( its!=d_eqc_singleton.end() ){
+            Trace("sets-mem") << " : Singleton : " << its->second;
+          }
+          Trace("sets-mem") << std::endl;
+        }
+      }
+    
+      checkDownwardsClosure( lemmas );
+      if( options::setsInferAsLemmas() ){
+        flushLemmas( lemmas );
+      }
+      if( !hasProcessed() ){
+        checkUpwardsClosure( lemmas );
+        flushLemmas( lemmas );
+        if( !hasProcessed() ){
+          if( d_card_enabled ){
+            //for cardinality
+            checkCardBuildGraph( lemmas );
+            flushLemmas( lemmas );
+            if( !hasProcessed() ){
+              checkMinCard( lemmas );
+              flushLemmas( lemmas );
+              if( !hasProcessed() ){
+                checkCardCycles( lemmas );
+                flushLemmas( lemmas );
+                if( !hasProcessed() ){
+                  std::vector< Node > intro_sets;
+                  checkNormalForms( lemmas, intro_sets );
+                  flushLemmas( lemmas );
+                  if( !hasProcessed() ){
+                    checkDisequalities( lemmas );
+                    flushLemmas( lemmas );
+                    if( !hasProcessed() && !intro_sets.empty() ){
+                      Assert( intro_sets.size()==1 );
+                      Trace("sets-intro") << "Introduce term : " << intro_sets[0] << std::endl;
+                      Trace("sets-intro") << "  Actual Intro : ";
+                      debugPrintSet( intro_sets[0], "sets-nf" );
+                      Trace("sets-nf") << std::endl;
+                      Node k = getProxy( intro_sets[0] );
+                      d_sentLemma = true;
+                    }
+                  }
+                }
+              }
+            }
+          }else{
+            checkDisequalities( lemmas );
+            flushLemmas( lemmas );
           }
         }
-        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; j<itn->second.size(); j++ ){
+        if( d_congruent.find( itn->second[j] )==d_congruent.end() ){
+          for( std::map< Node, Node >::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2 ){ 
+            Node mem = it2->second;
+            Node eq_set = itn->second[j];
+            Assert( d_equalityEngine.areEqual( mem[1], eq_set ) );
+            if( mem[1]!=eq_set ){
+              Trace("sets-debug") << "Downwards closure based on " << mem << ", eq_set = " << eq_set << std::endl;
+  #if 1
+              Node nmem = NodeManager::currentNM()->mkNode( kind::MEMBER, mem[0], eq_set );
+              nmem = Rewriter::rewrite( nmem );
+              std::vector< Node > exp;
+              exp.push_back( mem );
+              exp.push_back( mem[1].eqNode( eq_set ) );
+              assertInference( nmem, exp, lemmas, "downc" );
+              if( d_conflict ){
+                return;
+              }
+  #else
+              Node k = getProxy( eq_set );
+              Node pmem = NodeManager::currentNM()->mkNode( kind::MEMBER, mem[0], k );
+              if( ee_areEqual( mem, pmem ) ){
+                Node nmem = NodeManager::currentNM()->mkNode( kind::MEMBER, mem[0], eq_set );
+                nmem = Rewriter::rewrite( nmem );
+                d_keep.insert( nmem );
+                d_keep.insert( pmem );
+                assertFactRec( nmem, pmem, lemmas );
+              }else{
+                Trace("sets-debug") << "...infer proxy membership" << std::endl;
+                Node exp = NodeManager::currentNM()->mkNode( kind::AND, mem, mem[1].eqNode( eq_set ) );
+                d_keep.insert( pmem );
+                d_keep.insert( exp );
+                assertFactRec( pmem, exp, lemmas );
+              }
+              if( d_conflict ){
+                return;
+              }
+  #endif
+            }
           }
         }
-        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<d_set_eqc.size(); i++ ){
+    Node eqc = d_set_eqc[i];
+    std::map< Node, std::vector< Node > >::iterator itn = d_nvar_sets.find( eqc );
+    if( itn!=d_nvar_sets.end() ){
+      for( unsigned j=0; j<itn->second.size(); j++ ){
+        Node n = itn->second[j];
+        if( d_congruent.find( n )==d_congruent.end() ){
+          //if setminus, do for intersection instead
+          if( n.getKind()==kind::SETMINUS ){
+            n = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::INTERSECTION, n[0], n[1] ) );
+          }
+          registerCardinalityTerm( n, lemmas );
+        }
+      }
+    }
   }
-  // }
-  // //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; k<cterms.size(); k++ ){
+      Node nn = cterms[k];
+      Node nk = getProxy( nn );
+      Node pos_lem = NodeManager::currentNM()->mkNode( kind::GEQ, NodeManager::currentNM()->mkNode( kind::CARD, nk ), d_zero );
+      assertInference( pos_lem, d_emp_exp, lemmas, "pcard", 1 );
+      if( nn!=nk ){
+        Node lem = NodeManager::currentNM()->mkNode( kind::EQUAL, NodeManager::currentNM()->mkNode( kind::CARD, nk ),
+                                                                  NodeManager::currentNM()->mkNode( kind::CARD, nn ) );
+        lem = Rewriter::rewrite( lem );
+        Trace("sets-card") << "  " << k << " : " << lem << std::endl;
+        assertInference( lem, d_emp_exp, lemmas, "card", 1 );
       }
-      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<set_eqc_tmp.size(); i++ ){
+    std::vector< Node > curr;
+    std::vector< Node > exp;
+    checkCardCyclesRec( set_eqc_tmp[i], curr, exp, lemmas );
+    flushLemmas( lemmas );
+    if( hasProcessed() ){
+      return;
     }
+  }
+  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; i<curr.size(); i++ ){
+        conc.push_back( curr[0].eqNode( curr[i] ) );
+      }
+      Node fact = conc.size()==1 ? conc[0] : NodeManager::currentNM()->mkNode( kind::AND, conc );
+      assertInference( fact, exp, lemmas, "card_cycle" );
+      flushLemmas( lemmas );
+    }else{
+      //should be guaranteed based on not exploring equal parents
+      Assert( false );
+    }
+  }else if( std::find( d_set_eqc.begin(), d_set_eqc.end(), eqc )==d_set_eqc.end() ){
+    curr.push_back( eqc );
+    TypeNode tn = eqc.getType();
+    bool is_empty = eqc==d_eqc_emptyset[tn];
+    Node emp_set = getEmptySet( tn );
+    std::map< Node, std::vector< Node > >::iterator itn = d_nvar_sets.find( eqc );
+    if( itn!=d_nvar_sets.end() ){
+      for( unsigned j=0; j<itn->second.size(); j++ ){
+        Node n = itn->second[j];
+        if( n.getKind()==kind::INTERSECTION || n.getKind()==kind::SETMINUS ){
+          Trace("sets-debug") << "Build cardinality parents for " << n << "..." << std::endl;
+          std::vector< Node > sib;
+          unsigned true_sib = 0;
+          if( n.getKind()==kind::INTERSECTION ){
+            d_card_base[n] = n;
+            for( unsigned e=0; e<2; e++ ){
+              Node sm = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::SETMINUS, n[e], n[1-e] ) );
+              sib.push_back( sm );
+            }
+            true_sib = 2;
+          }else{
+            Node si = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::INTERSECTION, n[0], n[1] ) );
+            sib.push_back( si );
+            d_card_base[n] = si;
+            Node osm = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::SETMINUS, n[1], n[0] ) );
+            sib.push_back( osm );
+            true_sib = 1;
+          }
+          Node u = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::UNION, n[0], n[1] ) );
+          if( !d_equalityEngine.hasTerm( u ) ){
+            u = Node::null();
+          }
+          unsigned n_parents = true_sib + ( u.isNull() ? 0 : 1 );
+          //if this set is empty
+          if( is_empty ){
+            Assert( ee_areEqual( n, emp_set ) );
+            Trace("sets-debug") << "  empty, parents equal siblings" << std::endl;
+            std::vector< Node > conc;
+            //parent equal siblings
+            for( unsigned e=0; e<true_sib; e++ ){
+              if( d_equalityEngine.hasTerm( sib[e] ) && !ee_areEqual( n[e], sib[e] ) ){
+                conc.push_back( n[e].eqNode( sib[e] ) );
+              }
+            }
+            assertInference( conc, n.eqNode( emp_set ), lemmas, "cg_emp" );
+            flushLemmas( lemmas );
+            if( hasProcessed() ){
+              return;
+            }else{
+              //justify why there is no edge to parents (necessary?)
+              for( unsigned e=0; e<n_parents; e++ ){
+                Node p = (e==true_sib) ? u : n[e];
+                
+              }
+            }
+          }else{
+            std::vector< Node > card_parents;
+            std::vector< int > card_parent_ids;
+            //check if equal to a parent
+            for( unsigned e=0; e<n_parents; e++ ){
+              Trace("sets-debug") << "  check parent " << e << "/" << n_parents << std::endl;
+              bool is_union = e==true_sib;
+              Node p = (e==true_sib) ? u : n[e];
+              Trace("sets-debug") << "  check relation to parent " << p << ", isu=" << is_union << "..." << std::endl;
+              //if parent is empty
+              if( ee_areEqual( p, emp_set ) ){
+                Trace("sets-debug") << "  it is empty..." << std::endl;
+                Assert( !ee_areEqual( n, emp_set ) );
+                assertInference( n.eqNode( emp_set ), p.eqNode( emp_set ), lemmas, "cg_emppar" );
+                if( hasProcessed() ){
+                  return;
+                }
+              //if we are equal to a parent
+              }else if( ee_areEqual( p, n ) ){
+                Trace("sets-debug") << "  it is equal to this..." << std::endl;
+                std::vector< Node > conc;
+                std::vector< int > sib_emp_indices;
+                if( is_union ){
+                  for( unsigned s=0; s<sib.size(); s++ ){
+                    sib_emp_indices.push_back( s );
+                  }
+                }else{
+                  sib_emp_indices.push_back( e );
+                }
+                //sibling(s) are empty
+                for( unsigned s=0; s<sib_emp_indices.size(); s++ ){
+                  unsigned si = sib_emp_indices[s];
+                  if( !ee_areEqual( sib[si], emp_set ) ){
+                    conc.push_back( sib[si].eqNode( emp_set ) );
+                  }else{
+                    Trace("sets-debug") << "Sibling " << sib[si] << " is already empty." << std::endl;
+                  }
+                }
+                if( !is_union && n.getKind()==kind::INTERSECTION && !u.isNull() ){
+                  //union is equal to other parent
+                  if( !ee_areEqual( u, n[1-e] ) ){
+                    conc.push_back( u.eqNode( n[1-e] ) );
+                  }
+                }
+                Trace("sets-debug") << "...derived " << conc.size() << " conclusions" << std::endl;
+                assertInference( conc, n.eqNode( p ), lemmas, "cg_eqpar" );
+                flushLemmas( lemmas );
+                if( hasProcessed() ){
+                  return;
+                }
+              }else{
+                Trace("sets-cdg") << "Card graph : " << n << " -> " << p << std::endl;
+                //otherwise, we a syntactic subset of p
+                card_parents.push_back( p );
+                card_parent_ids.push_back( is_union ? 2 : e );
+              }
+            }
+            Assert( d_card_parent[n].empty() );
+            Trace("sets-debug") << "get parent representatives..." << std::endl;
+            //for each parent, take their representatives
+            for( unsigned k=0; k<card_parents.size(); k++ ){
+              Node eqcc = d_equalityEngine.getRepresentative( card_parents[k] );
+              Trace("sets-debug") << "Check card parent " << k << "/" << card_parents.size() << std::endl;
+              
+              //if parent is singleton, then we should either be empty to equal to it
+              std::map< Node, Node >::iterator itps = d_eqc_singleton.find( eqcc );
+              if( itps!=d_eqc_singleton.end() ){
+                bool eq_parent = false;
+                std::vector< Node > exp;
+                addEqualityToExp( card_parents[k], itps->second, exp );
+                if( ee_areDisequal( n, emp_set ) ){
+                  exp.push_back( n.eqNode( emp_set ).negate() );
+                  eq_parent = true;
+                }else{
+                  std::map< Node, std::map< Node, Node > >::iterator itpm = d_pol_mems[0].find( eqc );
+                  if( itpm!=d_pol_mems[0].end() && !itpm->second.empty() ){
+                    Node pmem = itpm->second.begin()->second;
+                    exp.push_back( pmem );
+                    addEqualityToExp( n, pmem[1], exp );
+                    eq_parent = true;
+                  }
+                }
+                //must be equal to parent
+                if( eq_parent ){
+                  Node conc = n.eqNode(  card_parents[k] );
+                  assertInference( conc, exp, lemmas, "cg_par_sing" );
+                  flushLemmas( lemmas );
+                }else{
+                  //split on empty
+                  Trace("sets-nf") << "Split empty : " << n << std::endl;
+                  split( n.eqNode( emp_set ), 1 );
+                }
+                Assert( hasProcessed() );
+                return;
+              }else{
+                bool dup = false;
+                for( unsigned l=0; l<d_card_parent[n].size(); l++ ){
+                  if( eqcc==d_card_parent[n][l] ){
+                    Trace("sets-debug") << "  parents " << l << " and " << k << " are equal, ids = " << card_parent_ids[l] << " " << card_parent_ids[k] << std::endl;
+                    dup = true;
+                    if( n.getKind()==kind::INTERSECTION ){
+                      Assert( card_parent_ids[l]!=2 );
+                      std::vector< Node > conc;
+                      if( card_parent_ids[k]==2 ){
+                        //intersection is equal to other parent
+                        unsigned pid = 1-card_parent_ids[l];
+                        if( !ee_areEqual( n[pid], n ) ){
+                          Trace("sets-debug") << "  one of them is union, make equal to other..." << std::endl;
+                          conc.push_back( n[pid].eqNode( n ) );
+                        }
+                      }else{
+                        if( !ee_areEqual( card_parents[k], n ) ){
+                          Trace("sets-debug") << "  neither is union, make equal to one parent..." << std::endl;
+                          //intersection is equal to one of the parents
+                          conc.push_back( card_parents[k].eqNode( n ) );
+                        }
+                      }
+                      assertInference( conc, card_parents[k].eqNode( d_card_parent[n][l] ), lemmas, "cg_pareq" );
+                      flushLemmas( lemmas );
+                      if( hasProcessed() ){
+                        return;
+                      }
+                    }
+                  }
+                }
+                if( !dup ){
+                  d_card_parent[n].push_back( eqcc );
+                }
+              }
+            }
+            //now recurse on parents (to ensure their normal will be computed after this eqc)
+            exp.push_back( eqc.eqNode( n ) );
+            for( unsigned k=0; k<d_card_parent[n].size(); k++ ){
+              checkCardCyclesRec( d_card_parent[n][k], curr, exp, lemmas );
+              if( hasProcessed() ){
+                return;
+              }
+            }
+            exp.pop_back();
+          }
+        }
+      }
     }
-  }
-  return true;
+    curr.pop_back();
+    //parents now processed, can add to ordered list
+    d_set_eqc.push_back( eqc );
+  }else{
+    //already processed
+  }  
 }
 
-Node TheorySetsPrivate::elementsToShape(Elements elements, TypeNode setType) const
-{
-  NodeManager* nm = NodeManager::currentNM();
-
-  if(elements.size() == 0) {
-    return nm->mkConst<EmptySet>(EmptySet(nm->toType(setType)));
-  } else {
-    Elements::iterator it = elements.begin();
-    Node cur = SINGLETON(*it);
-    while( ++it != elements.end() ) {
-      cur = nm->mkNode(kind::UNION, cur, SINGLETON(*it));
+void TheorySetsPrivate::checkNormalForms( std::vector< Node >& lemmas, std::vector< Node >& intro_sets ){
+  Trace("sets") << "Check normal forms..." << std::endl;
+  // now, build normal form for each equivalence class
+  //   d_set_eqc is now sorted such that for each d_set_eqc[i], d_set_eqc[j], 
+  //      if d_set_eqc[i] is a strict syntactic subterm of d_set_eqc[j], then i<j.
+  d_ff.clear();
+  d_nf.clear();
+  for( int i=(int)(d_set_eqc.size()-1); i>=0; i-- ){
+    checkNormalForm( d_set_eqc[i], intro_sets );
+    if( hasProcessed() || !intro_sets.empty() ){
+      return;
     }
-    return cur;
   }
-}
-
-Node TheorySetsPrivate::elementsToShape(std::set<Node> elements, TypeNode setType) const
-{
-  NodeManager* nm = NodeManager::currentNM();
-
-  if(elements.size() == 0) {
-    return nm->mkConst<EmptySet>(EmptySet(nm->toType(setType)));
-  } else {
-    std::set<Node>::const_iterator it = elements.begin();
-    Node cur = SINGLETON(*it);
-    while( ++it != elements.end() ) {
-      cur = nm->mkNode(kind::UNION, cur, SINGLETON(*it));
+  Trace("sets") << "Done check normal forms" << std::endl;
+}
+
+void TheorySetsPrivate::checkNormalForm( Node eqc, std::vector< Node >& intro_sets ){
+  TypeNode tn = eqc.getType();
+  Trace("sets") << "Compute normal form for " << eqc << std::endl;
+  Trace("sets-nf") << "Compute N " << eqc << "..." << std::endl;
+  if( eqc==d_eqc_emptyset[tn] ){
+    d_nf[eqc].clear();
+    Trace("sets-nf") << "----> N " << eqc << " => {}" << std::endl;
+  }else{
+    //flat/normal forms are sets of equivalence classes
+    Node base;
+    std::vector< Node > comps;
+    std::map< Node, std::map< Node, std::vector< Node > > >::iterator it = d_ff.find( eqc );
+    if( it!=d_ff.end() ){
+      for( std::map< Node, std::vector< Node > >::iterator itf = it->second.begin(); itf != it->second.end(); ++itf ){
+        std::sort( itf->second.begin(), itf->second.end() );
+        if( base.isNull() ){
+          base = itf->first;
+        }else{
+          comps.push_back( itf->first );
+        }
+        Trace("sets-nf") << "  F " << itf->first << " : ";
+        if( Trace.isOn("sets-nf") ){
+          Trace("sets-nf") << "{ ";
+          for( unsigned k=0; k<itf->second.size(); k++ ){
+            if( k>0 ){ Trace("sets-nf") << ", "; }
+            Trace("sets-nf") << "[" << itf->second[k] << "]";
+          }
+          Trace("sets-nf") << " }" << std::endl;
+        }
+        Trace("sets-nf-debug") << " ...";
+        debugPrintSet( itf->first, "sets-nf-debug" );
+        Trace("sets-nf-debug") << std::endl;
+      }
+    }else{
+      Trace("sets-nf") << "(no flat forms)" << std::endl;
+    }
+
+    Assert( d_nf.find( eqc )==d_nf.end() );
+    bool success = true;
+    if( !base.isNull() ){
+      Node emp_set = getEmptySet( tn );
+      for( unsigned j=0; j<comps.size(); j++ ){
+        //compare if equal
+        std::vector< Node > c;
+        c.push_back( base );
+        c.push_back( comps[j] );
+        std::vector< Node > only[2];
+        std::vector< Node > common;
+        Trace("sets-nf-debug") << "Compare venn regions of " << base << " vs " << comps[j] << std::endl;
+        unsigned k[2] = { 0, 0 };
+        while( k[0]<d_ff[eqc][c[0]].size() || k[1]<d_ff[eqc][c[1]].size() ){
+          bool proc = true;
+          for( unsigned e=0; e<2; e++ ){
+            if( k[e]==d_ff[eqc][c[e]].size() ){
+              for( ; k[1-e]<d_ff[eqc][c[1-e]].size(); ++k[1-e] ){
+                only[1-e].push_back( d_ff[eqc][c[1-e]][k[1-e]] );
+              }
+              proc = false;
+            }
+          }
+          if( proc ){
+            if( d_ff[eqc][c[0]][k[0]]==d_ff[eqc][c[1]][k[1]] ){
+              common.push_back( d_ff[eqc][c[0]][k[0]] );
+              k[0]++;
+              k[1]++;
+            }else if( d_ff[eqc][c[0]][k[0]]<d_ff[eqc][c[1]][k[1]] ){
+              only[0].push_back( d_ff[eqc][c[0]][k[0]] );
+              k[0]++;
+            }else{
+              only[1].push_back( d_ff[eqc][c[1]][k[1]] );
+              k[1]++;
+            }
+          }
+        }
+        if( !only[0].empty() || !only[1].empty() ){
+          if( Trace.isOn("sets-nf-debug") ){
+            Trace("sets-nf-debug") << "Unique venn regions : " << std::endl;
+            for( unsigned e=0; e<2; e++ ){
+              Trace("sets-nf-debug") << "  " << c[e] << " : { ";
+              for( unsigned l=0; l<only[e].size(); l++ ){
+                if( l>0 ){ Trace("sets-nf-debug") << ", "; }
+                Trace("sets-nf-debug") << "[" << only[e][l] << "]";
+              }
+              Trace("sets-nf-debug") << " }" << std::endl;
+            }
+          }
+          //try to make one empty, prefer the unique ones first
+          for( unsigned e=0; e<3; e++ ){
+            unsigned sz = e==2 ? common.size() : only[e].size();
+            for( unsigned l=0; l<sz; l++ ){
+              Node r = e==2 ? common[l] : only[e][l];
+              Trace("sets-nf-debug") << "Try split empty : " << r << std::endl;
+              Trace("sets-nf-debug") << "         actual : ";
+              debugPrintSet( r, "sets-nf-debug" );
+              Trace("sets-nf-debug") << std::endl;
+              Assert( !ee_areEqual( r, emp_set ) );
+              if( !ee_areDisequal( r, emp_set ) && ( d_pol_mems[0].find( r )==d_pol_mems[0].end() || d_pol_mems[0][r].empty() ) ){
+                //guess that its equal empty if it has no explicit members
+                Trace("sets-nf") << " Split empty : " << r << std::endl;
+                Trace("sets-nf") << "Actual Split : ";
+                debugPrintSet( r, "sets-nf" );
+                Trace("sets-nf") << std::endl;
+                split( r.eqNode( emp_set ), 1 );
+                Assert( hasProcessed() );
+                return;
+              }
+            }
+          }
+          for( unsigned l=0; l<only[0].size(); l++ ){
+            for( unsigned m=0; m<only[1].size(); m++ ){
+              bool disjoint = false;
+              Trace("sets-nf-debug") << "Try split " << only[0][l] << " against " << only[1][m] << std::endl;
+              //split them
+              for( unsigned e=0; e<2; e++ ){
+                Node r1 = e==0 ? only[0][l] : only[1][m];
+                Node r2 = e==0 ? only[1][m] : only[0][l];
+                //check if their intersection exists modulo equality
+                std::map< Node, Node >::iterator itb = d_bop_index[kind::INTERSECTION][r1].find( r2 );
+                if( itb!=d_bop_index[kind::INTERSECTION][r1].end() ){
+                  Trace("sets-nf-debug") << "Split term already exists, but not in cardinality graph : " << itb->second << ", should be empty." << std::endl;
+                  //their intersection is empty (probably?)
+                  // e.g. these are two disjoint venn regions, proceed to next pair
+                  Assert( ee_areEqual( emp_set, itb->second ) );
+                  disjoint = true;
+                  break;
+                }
+              }
+              if( !disjoint ){
+                //simply introduce their intersection
+                Assert( only[0][l]!=only[1][m] );
+                Node kca = getProxy( only[0][l] );
+                Node kcb = getProxy( only[1][m] );
+                Node intro = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::INTERSECTION, kca, kcb ) );
+                Trace("sets-nf") << "   Intro split : " << only[0][l] << " against " << only[1][m] << ", term is " << intro << std::endl;
+                intro_sets.push_back( intro );
+                Assert( !d_equalityEngine.hasTerm( intro ) );
+                return;
+              }
+            }
+          }
+          //should never get here
+          success = false;
+        }
+      }
+      if( success ){
+        //normal form is flat form of base
+        d_nf[eqc].insert( d_nf[eqc].end(), d_ff[eqc][base].begin(), d_ff[eqc][base].end() );
+        Trace("sets-nf") << "----> N " << eqc << " => F " << base << std::endl;
+      }else{
+        Trace("sets-nf") << "failed to build N " << eqc << std::endl;
+        Assert( false );
+      }
+    }else{
+      //normal form is this equivalence class
+      d_nf[eqc].push_back( eqc );
+      Trace("sets-nf") << "----> N " << eqc << " => { " << eqc << " }" << std::endl;
+    }
+    if( success ){
+      //send to parents
+      std::map< Node, std::vector< Node > >::iterator itn = d_nvar_sets.find( eqc );
+      if( itn!=d_nvar_sets.end() ){
+        std::map< Node, std::map< Node, bool > > parents_proc;
+        for( unsigned j=0; j<itn->second.size(); j++ ){
+          Node n = itn->second[j];
+          Trace("sets-nf-debug") << "Carry nf for term " << n << std::endl;
+          if( !d_card_parent[n].empty() ){
+            Assert( d_card_base.find( n )!=d_card_base.end() );
+            Node cbase = d_card_base[n];
+            Trace("sets-nf-debug") << "Card base is " << cbase << std::endl;
+            for( unsigned k=0; k<d_card_parent[n].size(); k++ ){
+              Node p = d_card_parent[n][k];
+              Trace("sets-nf-debug") << "Check parent " << p << std::endl;
+              if( parents_proc[cbase].find( p )==parents_proc[cbase].end() ){
+                parents_proc[cbase][p] = true;
+                Trace("sets-nf-debug") << "Carry nf to parent ( " << cbase << ", [" << p << "] ), from " << n << "..." << std::endl;
+                //for( unsigned i=0; i<d_nf[eqc].size(); i++ ){
+                //  Assert( std::find( d_ff[p][cbase].begin(), d_ff[p][cbase].end(), d_nf[eqc][i] )==d_ff[p][cbase].end() );
+                //}
+                for( unsigned i=0; i<d_nf[eqc].size(); i++ ){
+                  if( std::find( d_ff[p][cbase].begin(), d_ff[p][cbase].end(), d_nf[eqc][i] )==d_ff[p][cbase].end() ){
+                    d_ff[p][cbase].insert( d_ff[p][cbase].end(), d_nf[eqc].begin(), d_nf[eqc].end() );
+                  }else{
+                    //if it is a duplicate venn region, it must be empty since it is coming from syntactically disjoint siblings TODO?
+                  }
+                }
+              }else{
+                Trace("sets-nf-debug") << "..already processed parent " << p << " for " << cbase << std::endl;
+              }
+            }
+          }
+        }
+      }
+    }else{
+      Assert( hasProcessed() );
     }
-    return cur;
   }
 }
 
-void TheorySetsPrivate::collectModelInfo(TheoryModel* m, bool fullModel)
-{
-  Trace("sets-model") << "[sets-model] collectModelInfo(..., fullModel="
-                      << (fullModel ? "true)" : "false)") << std::endl;
-
-  std::set<Node> terms;
-
-  NodeManager* nm = NodeManager::currentNM();
-
-  // // this is for processCard -- commenting out for now
-  // if(Debug.isOn("sets-card")) {
-  //   for(CDNodeSet::const_iterator it = d_cardTerms.begin();
-  //       it != d_cardTerms.end(); ++it) {
-  //     Debug("sets-card") << "[sets-card] " << *it << " = "
-  //                        << d_external.d_valuation.getModelValue(*it)
-  //                        << std::endl;
-  //   }
-  // }
-
-  if(Trace.isOn("sets-assertions")) {
-    dumpAssertionsHumanified();
-  }
+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<TNode> 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; j<members.size(); j++ ){
+          if( !ee_areDisequal( members[j], itmm->second ) ){
+            Assert( !ee_areEqual( members[j], itmm->second ) );
+            
+          }
+        }
+      */
+        members.push_back( itmm->first );
+        exp.push_back( NodeManager::currentNM()->mkNode( kind::MEMBER, itmm->first, cardTerm[0] ) );
+      }
+      if( members.size()>1 ){
+        exp.push_back( NodeManager::currentNM()->mkNode( kind::DISTINCT, members ) );
+      }
+      if( !members.empty() ){
+        Node conc = NodeManager::currentNM()->mkNode( kind::GEQ, cardTerm, NodeManager::currentNM()->mkConst( Rational( members.size() ) ) );
+        Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp.size()==1 ? exp[0] : NodeManager::currentNM()->mkNode( kind::AND, exp ), conc );
+        Trace("sets-lemma") << "Sets::Lemma : " << lem << " by mincard" << std::endl;
+        lemmas.push_back( lem );
       }
     }
   }
+}
 
-  if(Debug.isOn("sets-model-details")) {
-    for(eq::EqClassIterator it_eqclasses(d_trueNode, &d_equalityEngine);
-        ! it_eqclasses.isFinished() ; ++it_eqclasses) {
-      TNode n = (*it_eqclasses);
-      vector<TNode> explanation;
-      Debug("sets-model-details")
-        << "[sets-model-details]  >  node: not: " << n << ", explanation:" << std::endl;
-      d_equalityEngine.explainPredicate(n, false, explanation);
-      BOOST_FOREACH(TNode m, explanation) {
-        Debug("sets-model-details") << "[sets-model-details]  >>  " << m << std::endl;
+void TheorySetsPrivate::flushLemmas( std::vector< Node >& lemmas ) {
+  //do lemmas
+  for( unsigned i=0; i<lemmas.size(); i++ ){
+    Node lem = lemmas[i];
+    if( d_lemmas_produced.find(lem)==d_lemmas_produced.end() ){
+      Trace("sets-lemma-debug") << "Send lemma : " << lem << std::endl;
+      d_lemmas_produced.insert(lem);
+      d_external.d_out->lemma(lem);
+      d_sentLemma = true;
+    }else{
+      Trace("sets-lemma-debug") << "Already sent lemma : " << lem << std::endl;
+    }
+  }
+  lemmas.clear();
+}
+
+Node TheorySetsPrivate::getProxy( Node n ) {
+  if( n.getKind()==kind::EMPTYSET || n.getKind()==kind::SINGLETON || n.getKind()==kind::INTERSECTION || n.getKind()==kind::SETMINUS || n.getKind()==kind::UNION ){
+    NodeMap::const_iterator it = d_proxy.find( n );
+    if( it==d_proxy.end() ){
+      Node k = NodeManager::currentNM()->mkSkolem( "sp", n.getType(), "proxy for set" );
+      d_proxy[n] = k;
+      d_proxy_to_term[k] = n;
+      Node eq = k.eqNode( n );
+      Trace("sets-lemma") << "Sets::Lemma : " << eq << " by proxy" << std::endl;
+      d_external.d_out->lemma( eq );
+      if( n.getKind()==kind::SINGLETON ){
+        Node slem = NodeManager::currentNM()->mkNode( kind::MEMBER, n[0], k );
+        Trace("sets-lemma") << "Sets::Lemma : " << slem << " by singleton" << std::endl;
+        d_external.d_out->lemma( slem );
+        d_sentLemma = true;
       }
+      return k;
+    }else{
+      return (*it).second;
     }
+  }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<Node> 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; i<s.getNumChildren(); i++ ){
+      Trace(c) << " ";
+      debugPrintSet( s[i], c );
+    }
+    Trace(c) << ")";
   }
+}
 
-  if(Debug.isOn("sets-model")) {
-    BOOST_FOREACH( TNode node, settermsModEq ) {
-      Debug("sets-model") << "[sets-model]   " << node << std::endl;
-    }
+/**************************** TheorySetsPrivate *****************************/
+/**************************** TheorySetsPrivate *****************************/
+/**************************** TheorySetsPrivate *****************************/
+
+void TheorySetsPrivate::check(Theory::Effort level) {
+  Trace("sets-check") << "Sets check effort " << level << std::endl;
+  while(!d_external.done() && !d_conflict) {
+    // Get all the assertions
+    Assertion assertion = d_external.get();
+    TNode fact = assertion.assertion;
+    Trace("sets-assert") << "Assert from input " << fact << std::endl;
+    //assert the fact
+    assertFact( fact, fact );
   }
+  d_sentLemma = false;
+  Trace("sets-check") << "Sets finished assertions effort " << level << std::endl;
+  if( level == Theory::EFFORT_FULL && !d_conflict && !d_external.d_valuation.needCheck() ){
+    fullEffortCheck();
+  }
+  // invoke the relational solver
+  if( !d_conflict && !d_sentLemma ){
+    d_rels->check(level);  
+  }
+  Trace("sets-check") << "Sets finish Check effort " << level << std::endl;
+}/* TheorySetsPrivate::check() */
+
+
+/************************ Sharing ************************/
+/************************ Sharing ************************/
+/************************ 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<TNode, TNode> > currentPairs;
+        for (unsigned k = 0; k < f1.getNumChildren(); ++ k) {
+          TNode x = f1[k];
+          TNode y = f2[k];
+          Assert( d_equalityEngine.hasTerm(x) );
+          Assert( d_equalityEngine.hasTerm(y) );
+          Assert( !ee_areDisequal( x, y ) );
+          if( !d_equalityEngine.areEqual( x, y ) ){
+            Trace("sets-cg") << "Arg #" << k << " is " << x << " " << y << std::endl;
+            if( d_equalityEngine.isTriggerTerm(x, THEORY_SETS) && d_equalityEngine.isTriggerTerm(y, THEORY_SETS) ){
+              TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_SETS);
+              TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_SETS);
+              Trace("sets-cg") << "Arg #" << k << " shared term is " << x_shared << " " << y_shared << std::endl;
+              EqualityStatus eqStatus = d_external.d_valuation.getEqualityStatus(x_shared, y_shared);
+              Trace("sets-cg") << "...eq status is " << eqStatus << std::endl;
+              if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
+                //an argument is disequal, we are done
+                return;
+              }else{
+                currentPairs.push_back(make_pair(x_shared, y_shared));
+              }
+            }else if( isCareArg( f1, k ) && isCareArg( f2, k ) ){
+              //splitting on sets (necessary for handling set of sets properly)
+              if( x.getType().isSet() ){
+                Assert( y.getType().isSet() );
+                if( !ee_areDisequal( x, y ) ){
+                  Trace("sets-cg-lemma") << "Should split on : " << x << "==" << y << std::endl;
+                  split( x.eqNode( y ) );
+                }
+              }
+            }
+          }
+        }
+        for (unsigned c = 0; c < currentPairs.size(); ++ c) {
+          Trace("sets-cg-pair") << "Pair : " << currentPairs[c].first << " " << currentPairs[c].second << std::endl;
+          d_external.addCarePair(currentPairs[c].first, currentPairs[c].second);
+          n_pairs++;
+        }
       }
     }
-  }
-
-  // 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<TNode, std::vector<TNode>, TNodeHashFunction> slackElements;
-  BOOST_FOREACH( TNode setterm, leaves ) {
-    if(setterm.getKind() == kind::EMPTYSET) { continue; }
-    // Assert(d_cardTerms.find(nm->mkNode(kind::CARD,setterm)) != d_cardTerms.end()); // for processCard
-    Assert(d_V.find(setterm) != d_V.end());
-    Node cardValNode = d_external.d_valuation.getModelValue(nm->mkNode(kind::CARD,setterm));
-    Rational cardValRational = cardValNode.getConst<Rational>();
-    Assert(cardValRational.isIntegral());
-    Integer cardValInteger = cardValRational.getNumerator();
-    Assert(cardValInteger.fitsSignedInt(), "Can't build models that big.");
-    int cardValInt = cardValInteger.getSignedInt();
-    Assert(cardValInt >= 0);
-    int numElems = getElements(setterm, settermElementsMap).size();
-    Trace("sets-model-card") << "[sets-model-card] cardValInt = " << cardValInt << std::endl
-                            << "                  numElems = " << numElems << std::endl;
-    Trace("sets-model-card") << "[sets-model-card] Creating " << cardValInt-numElems
-                            << " slack variables for " << setterm << std::endl;
-    Assert(cardValInt >= numElems, "Run with -d sets-model-card for details");
-
-    TypeNode elementType = setterm.getType().getSetElementType();
-    std::vector<TNode>& cur = slackElements[setterm];
-    for(int i = numElems; i < cardValInt; ++i) {
-      // slk = slack
-      cur.push_back(nm->mkSkolem("slk_",  elementType));
+  }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<TNode> leafChildren = get_leaves(setterm);
-      BOOST_FOREACH( TNode leafChild, leafChildren ) {
-        if(leaves.find(leafChild) == leaves.end()) { continue; }
-        BOOST_FOREACH( TNode slackVar, slackElements[leafChild] ) {
-          elements.insert(slackVar);
+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; i<it->second.size(); i++ ){
+        TNode f1 = it->second[i];
+        Assert(d_equalityEngine.hasTerm(f1));
+        Trace("sets-cg-debug") << "...build for " << f1 << std::endl;
+        //break into index based on operator, and type of first argument (since some operators are parametric)
+        TypeNode tn = f1[0].getType();
+        std::vector< TNode > reps;
+        bool hasCareArg = false;
+        for( unsigned j=0; j<f1.getNumChildren(); j++ ){
+          reps.push_back( d_equalityEngine.getRepresentative( f1[j] ) );
+          if( isCareArg( f1, j ) ){
+            hasCareArg = true;
+          }
+        }
+        if( hasCareArg ){
+          index[tn].addTerm( f1, reps );
+          arity = reps.size();
         }
       }
-      Trace("sets-model-card") << "[sets-model-card] " << setterm << " (after slacks): " << elements.size() << std::endl;
-    } else if(d_V.find(setterm) != d_V.end()) {
-      Trace("sets-model-card") << "[sets-model-card] " << setterm << " (before slacks): " << elements.size() << std::endl;
-      BOOST_FOREACH( TNode slackVar, slackElements[setterm] ) {
-        elements.insert(slackVar);
+      if( arity>0 ){
+        //for each index
+        for( std::map< TypeNode, quantifiers::TermArgTrie >::iterator iti = index.begin(); iti != index.end(); ++iti ){
+          Trace("sets-cg") << "Process index " << iti->first << "..." << std::endl;
+          addCarePairs( &iti->second, NULL, arity, 0, n_pairs );
+        }
       }
-      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<Rational>() <= LONG_MAX, "Exceeded LONG_MAX in sets model");
+          unsigned vu = v.getConst<Rational>().getNumerator().toUnsignedInt();
+          Assert( els.size()<=vu );
+          while( els.size()<vu ){
+            els.push_back( NodeManager::currentNM()->mkNode( kind::SINGLETON, NodeManager::currentNM()->mkSkolem( "msde", elementType ) ) );
+          }
+        }else{
+          Trace("sets-model") << "No slack elements for " << eqc << std::endl;
+        }
+      }else{
+        Trace("sets-model") << "Build value for " << eqc << " based on normal form, size = " << d_nf[eqc].size() << std::endl;
+        //it is union of venn regions
+        for( unsigned j=0; j<d_nf[eqc].size(); j++ ){
+          Assert( mvals.find( d_nf[eqc][j] )!=mvals.end() );
+          els.push_back( mvals[d_nf[eqc][j]] );
+        }
+      }
+    }
+    Node rep = NormalForm::mkBop( kind::UNION, els, eqc.getType() );
+    rep = Rewriter::rewrite( rep );
+    Trace("sets-model") << "Set representative of " << eqc << " to " << rep << std::endl;
+    mvals[eqc] = rep;
+    m->assertEquality( eqc, rep, true );
+    m->assertRepresentative( rep );
+  }
 }
 
 /********************** Helper functions ***************************/
 /********************** Helper functions ***************************/
 /********************** Helper functions ***************************/
 
+void TheorySetsPrivate::addEqualityToExp( Node a, Node b, std::vector< Node >& exp ) {
+  if( a!=b ){
+    Assert( ee_areEqual( a, b ) );
+    exp.push_back( a.eqNode( b ) );
+  }
+}
+
 Node mkAnd(const std::vector<TNode>& conjunctions) {
   Assert(conjunctions.size() > 0);
 
   std::set<TNode> all;
-
   for (unsigned i = 0; i < conjunctions.size(); ++i) {
     TNode t = conjunctions[i];
-
     if (t.getKind() == kind::AND) {
       for(TNode::iterator child_it = t.begin();
           child_it != t.end(); ++child_it) {
-        // Assert((*child_it).getKind() != kind::AND);
+        Assert((*child_it).getKind() != kind::AND);
         all.insert(*child_it);
       }
     }
     else {
       all.insert(t);
     }
-
   }
 
   Assert(all.size() > 0);
-
   if (all.size() == 1) {
     // All the same, or just one
     return conjunctions[0];
@@ -1111,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<TNode,TNode> np = d_settermPropagationQueue.front();
-    d_settermPropagationQueue.pop();
-    doSettermPropagation(np.first, np.second);
-  }
-  while(!d_conflict && !d_propagationQueue.empty()) {
-    std::pair<Node,Node> np = d_propagationQueue.front();
-    d_propagationQueue.pop();
-    TNode atom = np.first.getKind() == kind::NOT ? np.first[0] : np.first;
-    if(atom.getKind() == kind::MEMBER) {
-      assertMemebership(np.first, np.second, /* learnt = */ true);
-    } else {
-      assertEquality(np.first, np.second, /* learnt = */ true);
+  Debug("sets") << "TheorySetsPrivate::explain(" << literal << ")"
+                << std::endl;
+
+  bool polarity = literal.getKind() != kind::NOT;
+  TNode atom = polarity ? literal : literal[0];
+  std::vector<TNode> 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<bool>(true)),
-  d_falseNode(NodeManager::currentNM()->mkConst<bool>(false)),
-  d_conflict(c),
-  d_termInfoManager(NULL),
-  d_setTermToCardVar(),
-  d_cardVarToSetTerm(),
-  d_propagationQueue(c),
-  d_settermPropagationQueue(c),
-  d_nodeSaver(c),
-  d_pending(c),
-  d_pendingDisequal(c),
-  d_pendingEverInserted(u),
-  d_modelCache(c),
-  d_ccg_i(c),
-  d_ccg_j(c),
-  d_scrutinize(NULL),
-  d_cardEnabled(false),
-  d_cardTerms(c),
-  d_typesAdded(),
-  d_processedCardTerms(c),
-  d_processedCardPairs(),
-  d_cardLowerLemmaCache(u),
-  edgesFd(),
-  edgesBk(),
-  disjoint(),
-  leaves(),
-  d_V(c),
-  d_E(c),
-  d_graphMergesPending(c),
-  d_allSetEqualitiesSoFar(c),
-  d_lemmasGenerated(u),
-  d_newLemmaGenerated(false),
-  d_relTerms(u)
-{
-  d_termInfoManager = new TermInfoManager(*this, c, &d_equalityEngine);
-
-  d_equalityEngine.addFunctionKind(kind::UNION);
-  d_equalityEngine.addFunctionKind(kind::INTERSECTION);
-  d_equalityEngine.addFunctionKind(kind::SETMINUS);
-
-  d_equalityEngine.addFunctionKind(kind::MEMBER);
-  d_equalityEngine.addFunctionKind(kind::SUBSET);
-
-  // If cardinality is on.
-  d_equalityEngine.addFunctionKind(kind::CARD);
-
-  if( Debug.isOn("sets-scrutinize") ) {
-    d_scrutinize = new TheorySetsScrutinize(this);
-  }
-}/* TheorySetsPrivate::TheorySetsPrivate() */
-
-
-TheorySetsPrivate::~TheorySetsPrivate()
-{
-  delete d_termInfoManager;
-  if( Debug.isOn("sets-scrutinize") ) {
-    Assert(d_scrutinize != NULL);
-    delete d_scrutinize;
-  }
-}/* TheorySetsPrivate::~TheorySetsPrivate() */
-
-void TheorySetsPrivate::propagate(Theory::Effort effort) {
-  if(effort != Theory::EFFORT_FULL || !options::setsPropFull()) {
-    return;
-  }
-
-  // build a model
-  Trace("sets-prop-full") << "[sets-prop-full] propagate(FULL_EFFORT)" << std::endl;
-  if(Trace.isOn("sets-assertions")) {
-    dumpAssertionsHumanified();
-  }
-
-  const CDNodeSet& terms = (d_termInfoManager->d_terms);
-  for(CDNodeSet::key_iterator it = terms.key_begin(); it != terms.key_end(); ++it) {
-    Node node = (*it);
-    Kind k = node.getKind();
-    if(k == kind::UNION && node[0].getKind() == kind::SINGLETON ) {
-
-      if(holds(MEMBER(node[0][0], node[1]))) {
-        Trace("sets-prop-full") << "[sets-prop-full] " << MEMBER(node[0][0], node[1])
-                                << " => " << EQUAL(node[1], node) << std::endl;
-        learnLiteral(EQUAL(node[1], node), MEMBER(node[0][0], node[1]));
-      }
-
-    } else if(k == kind::UNION && node[1].getKind() == kind::SINGLETON ) {
-
-      if(holds(MEMBER(node[1][0], node[0]))) {
-        Trace("sets-prop-full") << "[sets-prop-full] " << MEMBER(node[1][0], node[0])
-                                << " => " << EQUAL(node[0], node) << std::endl;
-        learnLiteral(EQUAL(node[0], node), MEMBER(node[1][0], node[0]));
-      }
-
-    }
-  }
-
-  finishPropagation();
-}
-
-bool TheorySetsPrivate::propagate(TNode literal) {
-  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<TNode> 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<TNode> temp;
-  CDTNodeList::const_iterator it;
-  for(it = la->begin() ; it != la->end(); it++ ) {
-    temp.insert((*it));
-  }
-
-  for(it = lb->begin() ; it!= lb->end(); it++ ) {
-    if(temp.count(*it) == 0) {
-      la->push_back(*it);
-    }
-  }
-}
-
-TheorySetsPrivate::TermInfoManager::TermInfoManager(
-    TheorySetsPrivate& theory, context::Context* satContext,
-    eq::EqualityEngine* eq)
-    : d_theory(theory),
-      d_context(satContext),
-      d_eqEngine(eq),
-      d_terms(satContext),
-      d_info() {}
-
-TheorySetsPrivate::TermInfoManager::~TermInfoManager() {
-  for (SetsTermInfoMap::iterator it = d_info.begin(); it != d_info.end();
-       ++it) {
-    delete (*it).second;
-  }
-}
-
-void TheorySetsPrivate::TermInfoManager::notifyMembership(TNode fact) {
-  bool polarity = fact.getKind() != kind::NOT;
-  TNode atom = polarity ? fact : fact[0];
-
-  TNode x = d_eqEngine->getRepresentative(atom[0]);
-  TNode S = d_eqEngine->getRepresentative(atom[1]);
-
-  Debug("sets-terminfo") << "[sets-terminfo] Adding membership " << x
-                         << " in " << S << " " << polarity << std::endl;
-
-  d_info[S]->addToElementList(x, polarity);
-  d_info[x]->addToSetList(S, polarity);
-
-  d_theory.d_modelCache.clear();
-}
-
-const CDTNodeList* TheorySetsPrivate::TermInfoManager::getParents(TNode x) {
-  return d_info[x]->parents;
-}
-
-const CDTNodeList* TheorySetsPrivate::TermInfoManager::getMembers(TNode S) {
-  return d_info[S]->elementsInThisSet;
-}
-
-const CDTNodeList* TheorySetsPrivate::TermInfoManager::getNonMembers(TNode S) {
-  return d_info[S]->elementsNotInThisSet;
-}
-
-void TheorySetsPrivate::TermInfoManager::addTerm(TNode n) {
-  if(d_terms.contains(n)) {
-    return;
-  }
-  d_terms.insert(n);
-
-  if(d_info.find(n) == d_info.end()) {
-    d_info.insert(make_pair(n, new TheorySetsTermInfo(d_context)));
-  }
-
-  if(n.getKind() == kind::UNION ||
-     n.getKind() == kind::INTERSECTION ||
-     n.getKind() == kind::SETMINUS) {
-
-    unsigned numChild = n.getNumChildren();
-
-    for(unsigned i = 0; i < numChild; ++i) {
-      Assert(d_terms.contains(n[i]));
-      if(d_terms.contains(n[i])) {
-        Debug("sets-parent") << "Adding " << n << " to parent list of "
-                             << n[i] << std::endl;
-
-        // introduce cardinality of this set if a child's cardinality appears
-        d_info[n[i]]->parents->push_back(n);
-        if(d_theory.d_cardTerms.find(CARD(n[i])) != d_theory.d_cardTerms.end()) {
-          d_theory.registerCard(CARD(n));
-        }
-
-        SetsTermInfoMap::iterator ita = d_info.find(d_eqEngine->getRepresentative(n[i]));
-        Assert(ita != d_info.end());
-        CDTNodeList* l = (*ita).second->elementsNotInThisSet;
-        for(CDTNodeList::const_iterator it = l->begin(); it != l->end(); ++it) {
-          d_theory.d_settermPropagationQueue.push_back( std::make_pair( (*it), n ) );
-        }
-        l = (*ita).second->elementsInThisSet;
-        for(CDTNodeList::const_iterator it = l->begin(); it != l->end(); ++it) {
-          d_theory.d_settermPropagationQueue.push_back( std::make_pair( (*it), n ) );
-        }
-      }
-    }
-  }
-}
-
-void TheorySetsPrivate::TermInfoManager::pushToSettermPropagationQueue
-(TNode x, TNode S, bool polarity)
-{
-  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<TNode> alreadyProcessed;
-
-  BOOST_FOREACH(TNode S, (*l) ) {
-    Debug("sets-prop") << "[sets-terminfo]  setterm todo: "
-                       << MEMBER(x, d_eqEngine->getRepresentative(S))
-                       << std::endl;
-
-    TNode repS = d_eqEngine->getRepresentative(S);
-    if(alreadyProcessed.find(repS) != alreadyProcessed.end()) {
-      continue;
-    } else {
-      alreadyProcessed.insert(repS);
-    }
-
-    d_eqEngine->addTerm(MEMBER(d_eqEngine->getRepresentative(x), repS));
-
-    for(eq::EqClassIterator j(d_eqEngine->getRepresentative(S), d_eqEngine);
-        !j.isFinished(); ++j) {
-
-      pushToSettermPropagationQueue(x, *j, polarity);
-
-    }//j loop
-  }
+  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<Node> elements;
-  std::set<Node> elements_const;
-  Node S = d_eqEngine->getRepresentative(n);
-  context::CDHashMap<Node, Node, NodeHashFunction>::const_iterator it =
-      d_theory.d_modelCache.find(S);
-  if (it != d_theory.d_modelCache.end()) {
-    return (*it).second;
-  }
-  const CDTNodeList* l = getMembers(S);
-  for (CDTNodeList::const_iterator it = l->begin(); it != l->end(); ++it) {
-    TNode n = *it;
-    elements.insert(d_eqEngine->getRepresentative(n));
-  }
-  for(std::set<Node>::iterator it = elements.begin(); it != elements.end(); it++) {
-    TNode e = *it;
-    if (e.isConst()) {
-      elements_const.insert(e);
-    } else {
-      Node eModelValue = d_theory.d_external.d_valuation.getModelValue(e);
-      if (eModelValue.isNull()) {
-        return eModelValue;
-      }
-      elements_const.insert(eModelValue);
-    }
-  }
-  Node v = d_theory.elementsToShape(elements_const, n.getType());
-  d_theory.d_modelCache[n] = v;
-  return v;
+  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>(EmptySet(nm->toType(t)));
-  Node sk = nm->mkSkolem("scz_",  t);
-  lemma(nm->mkNode(kind::EQUAL, sk, emptySet), SETS_LEMMA_OTHER);
-  lemma(nm->mkNode(kind::EQUAL, nm->mkConst(Rational(0)), nm->mkNode(kind::CARD, sk)), SETS_LEMMA_OTHER);
-}
-
-
-void TheorySetsPrivate::buildGraph() {
-
-  NodeManager* nm = NodeManager::currentNM();
-
-  edgesFd.clear();
-  edgesBk.clear();
-  disjoint.clear();
-
-  for (std::map<std::pair<Node, Node>, bool>::const_iterator it =
-           d_processedCardPairs.begin();
-       it != d_processedCardPairs.end(); ++it) {
-    Node s = (it->first).first;
-    Assert(Rewriter::rewrite(s) == s);
-    Node t = (it->first).second;
-    Assert(Rewriter::rewrite(t) == t);
-    bool hasUnion = (it->second);
-
-    Node sNt = nm->mkNode(kind::INTERSECTION, s, t);
-    sNt = Rewriter::rewrite(sNt);
-    Node sMt = nm->mkNode(kind::SETMINUS, s, t);
-    sMt = Rewriter::rewrite(sMt);
-    Node tMs = nm->mkNode(kind::SETMINUS, t, s);
-    tMs = Rewriter::rewrite(tMs);
-
-    edgesFd[s].insert(sNt);
-    edgesFd[s].insert(sMt);
-    edgesBk[sNt].insert(s);
-    edgesBk[sMt].insert(s);
-
-    edgesFd[t].insert(sNt);
-    edgesFd[t].insert(tMs);
-    edgesBk[sNt].insert(t);
-    edgesBk[tMs].insert(t);
-
-    if(hasUnion) {
-      Node sUt = nm->mkNode(kind::UNION, s, t);
-      sUt = Rewriter::rewrite(sUt);
-
-      edgesFd[sUt].insert(sNt);
-      edgesFd[sUt].insert(sMt);
-      edgesFd[sUt].insert(tMs);
-      edgesBk[sNt].insert(sUt);
-      edgesBk[sMt].insert(sUt);
-      edgesBk[tMs].insert(sUt);
-    }
-
-    disjoint.insert(make_pair(sNt, sMt));
-    disjoint.insert(make_pair(sMt, sNt));
-    disjoint.insert(make_pair(sNt, tMs));
-    disjoint.insert(make_pair(tMs, sNt));
-    disjoint.insert(make_pair(tMs, sMt));
-    disjoint.insert(make_pair(sMt, tMs));
-  }
-
-  if (Debug.isOn("sets-card-graph")) {
-    Debug("sets-card-graph") << "[sets-card-graph] Fd:" << std::endl;
-    for (std::map<TNode, std::set<TNode> >::const_iterator it = edgesFd.begin();
-         it != edgesFd.end(); ++it) {
-      Debug("sets-card-graph") << "[sets-card-graph]  " << (it->first)
-                               << std::endl;
-      for (std::set<TNode>::const_iterator jt = (it->second).begin();
-           jt != (it->second).end(); ++jt) {
-        Debug("sets-card-graph") << "[sets-card-graph]   " << (*jt)
-                                 << std::endl;
-      }
-    }
-    Debug("sets-card-graph") << "[sets-card-graph] Bk:" << std::endl;
-    for (std::map<TNode, std::set<TNode> >::const_iterator it = edgesBk.begin();
-         it != edgesBk.end(); ++it) {
-      Debug("sets-card-graph") << "[sets-card-graph]  " << (it->first)
-                               << std::endl;
-      for (std::set<TNode>::const_iterator jt = (it->second).begin();
-           jt != (it->second).end(); ++jt) {
-        Debug("sets-card-graph") << "[sets-card-graph]   " << (*jt)
-                                 << std::endl;
-      }
-    }
-  }
-
-  leaves.clear();
-
-  for(CDNodeSet::const_iterator it = d_processedCardTerms.begin();
-      it != d_processedCardTerms.end(); ++it) {
-    Node n = (*it)[0];
-    if( edgesFd.find(n) == edgesFd.end() ) {
-      leaves.insert(n);
-      Debug("sets-card-graph") << "[sets-card-graph] Leaf: " << n << std::endl;
-    }
-    // if( edgesBk.find(n) != edgesBk.end() ) {
-    //   Assert(n.getKind() == kind::INTERSECTION ||
-    //          n.getKind() == kind::SETMINUS);
-    // }
-  }
-
-}
-
-const std::set<TNode> getReachable(map<TNode, set<TNode> >& edges, TNode node) {
-  Debug("sets-getreachable-debug") << "[sets-getreachable-debug] " << node << ":" << std::endl;
-  queue<TNode> Q;
-  std::set<TNode> ret;
-  ret.insert(node);
-  if(edges.find(node) != edges.end()) {
-    Debug("sets-getreachable-debug") << "[sets-getreachable-debug]   " << node << ":" << std::endl;
-    Q.push(node);
-  }
-  while(!Q.empty()) {
-    TNode n = Q.front();
-    Q.pop();
-    for(set<TNode>::iterator it = edges[n].begin();
-        it != edges[n].end(); ++it) {
-      if(ret.find(*it) == ret.end()) {
-        if(edges.find(*it) != edges.end()) {
-          Debug("sets-getreachable-debug") << "[sets-getreachable-debug]   " << *it << ":" << std::endl;
-          Q.push(*it);
-        }
-        ret.insert(*it);
-      }
-    }
-  }
-  return ret;
-}
-
-const std::set<TNode> getLeaves(map<TNode, set<TNode> >& edges, TNode node) {
-  Debug("sets-getreachable-debug") << "[sets-getreachable-debug] " << node << ":" << std::endl;
-  queue<TNode> Q;
-  std::set<TNode> ret;
-  std::set<TNode> visited;
-  visited.insert(node);
-  if(edges.find(node) != edges.end()) {
-    Q.push(node);
-  } else {
-    Debug("sets-getreachable-debug") << "[sets-getreachable-debug]   " << node << std::endl;
-    ret.insert(node);
-  }
-  while(!Q.empty()) {
-    TNode n = Q.front();
-    Q.pop();
-    for(set<TNode>::iterator it = edges[n].begin();
-        it != edges[n].end(); ++it) {
-      if(visited.find(*it) == visited.end()) {
-        if(edges.find(*it) != edges.end()) {
-          Q.push(*it);
-        } else {
-          Debug("sets-getreachable-debug") << "[sets-getreachable-debug]   " << *it << std::endl;
-          ret.insert(*it);
-        }
-        visited.insert(*it);
-      }
-    }
-  }
-  return ret;
-}
-
-/************ New cardinality implementation **************/
-  
-
-/***
- * Data structures:
- * d_V : vertices in the graph (context dependent data structure)
- * d_E : edges between vertices in the graph
- *
- * Methods: 
- *
- * merge(vector<int> a, vector<int> b)
- * get non empty leaves
- * of a & b, for each internal node, there will be two parent nodes
- *
- * Introduce
- *   <If a node already exists, merge with it>
- */
-
-void TheorySetsPrivate::add_edges(TNode source, TNode dest) {
-  vector<TNode> V;
-  V.push_back(dest);
-  add_edges(source, V);
-}
-
-void TheorySetsPrivate::add_edges(TNode source, TNode dest1, TNode dest2) {
-  vector<TNode> V;
-  V.push_back(dest1);
-  V.push_back(dest2);
-  add_edges(source, V);
+  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<TNode> V;
-  V.push_back(dest1);
-  V.push_back(dest2);
-  V.push_back(dest3);
-  add_edges(source, V);
-}
-
-void TheorySetsPrivate::add_edges(TNode source, const std::vector<TNode>& dests) {
-
-  if(Debug.isOn("sets-graph-details")) {
-    Debug("sets-graph-details") << "[sets-graph-details] add_edges " << source
-                                << "  [";
-    BOOST_FOREACH(TNode v, dests) {
-      Debug("sets-graph-details") << v << ", ";
-      Assert(d_V.find(v) != d_V.end());
-    }
-    Debug("sets-graph-details") << "]" << std::endl;
-  }
-
-  Assert(d_E.find(source) == d_E.end());
-  if(dests.size() == 1 && dests[0] == source) {
-    return;
-  }
-  d_E.insert(source, dests);
-}
-
-
-void TheorySetsPrivate::add_node(TNode vertex) {
-  NodeManager* nm = NodeManager::currentNM();
-  Debug("sets-graph-details") << "[sets-graph-details] add_node " << vertex << std::endl;
-  if(d_V.find(vertex) == d_V.end()) {
-    d_V.insert(vertex);
-    Kind k = vertex.getKind();
-    if(k == kind::SINGLETON) {
-      // newLemmaGenerated = true;
-      lemma(nm->mkNode(kind::EQUAL,
-                       nm->mkNode(kind::CARD, vertex),
-                       nm->mkConst(Rational(1))),
-            SETS_LEMMA_OTHER);
-    } else if(k != kind::EMPTYSET) {
-      // newLemmaGenerated = true;
-      lemma(nm->mkNode(kind::GEQ,
-                       nm->mkNode(kind::CARD, vertex),
-                       nm->mkConst(Rational(0))),
-            SETS_LEMMA_OTHER);
-    }
-    d_statistics.d_numVerticesMax.maxAssign(d_V.size());
-  }
-  d_equalityEngine.addTerm(vertex);
-  d_termInfoManager->addTerm(vertex);
-}
-
-std::set<TNode> TheorySetsPrivate::non_empty(std::set<TNode> vertices)
+void TheorySetsPrivate::NotifyClass::eqNotifyDisequal(TNode t1, TNode t2, TNode reason)
 {
-  std::set<TNode> ret;
-  NodeManager* nm = NodeManager::currentNM();
-  BOOST_FOREACH(TNode vertex, vertices) {
-    Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType(vertex.getType())));
-    if(!d_equalityEngine.areEqual(vertex, emptySet)) {
-      ret.insert(vertex);
-    }
-  }
-  return ret;
+  Debug("sets-eq") << "[sets-eq] eqNotifyDisequal:" << " t1 = " << t1 << " t2 = " << t2 << " reason = " << reason << std::endl;
+  d_theory.eqNotifyDisequal(t1, t2, reason);
 }
 
-std::set<TNode> TheorySetsPrivate::get_leaves(Node vertex) {
-  Debug("sets-graph-details") << "[sets-graph-details] get_leaves " << vertex << std::endl;
-  std::set<TNode> a;
-  Assert(d_V.find(vertex) != d_V.end());
-  if(d_E.find(vertex) != d_E.end()) {
-    Assert(d_E[vertex].get().size() > 0);
-    BOOST_FOREACH(TNode v , d_E[vertex].get()) {
-      std::set<TNode> s = get_leaves(v);
-      a.insert(s.begin(), s.end());
-    }
-  } else {
-    a.insert(vertex);
-  }
-  // a = non_empty(a);
-  return a;
-}
-
-std::set<TNode> TheorySetsPrivate::get_leaves(Node vertex1, Node vertex2) {
-  std::set<TNode> s = get_leaves(vertex1);
-  std::set<TNode> t = get_leaves(vertex2);
-  t.insert(s.begin(), s.end());
-  return t;
-}
-
-std::set<TNode> TheorySetsPrivate::get_leaves(Node vertex1, Node vertex2, Node vertex3) {
-  std::set<TNode> s = get_leaves(vertex1);
-  std::set<TNode> t = get_leaves(vertex2);
-  std::set<TNode> u = get_leaves(vertex3);
-  t.insert(s.begin(), s.end());
-  t.insert(u.begin(), u.end());
-  return t;
-}
-
-Node TheorySetsPrivate::eqemptySoFar() {
-  std::vector<Node> V;
-
-  for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) {
-    Node rep = d_equalityEngine.getRepresentative(*it);
-    if(rep.getKind() == kind::EMPTYSET) {
-      V.push_back(EQUAL(rep, (*it)));
-    }
-  }
-
-  if(V.size() == 0) {
-    return d_trueNode;
-  } else if(V.size() == 1) {
-    return V[0];
-  } else {
-    NodeManager* nm = NodeManager::currentNM();
-    return nm->mkNode(kind::AND, V);
-  }
-}   
-
-  
-void TheorySetsPrivate::merge_nodes(std::set<TNode> leaves1, std::set<TNode> leaves2, Node reason) {
-  CodeTimer codeTimer(d_statistics.d_mergeTime);
-
-  NodeManager* nm = NodeManager::currentNM();
-
-  // do non-empty reasoning stuff
-  std::vector<TNode> leaves1_nonempty, leaves2_nonempty;
-  BOOST_FOREACH(TNode l, leaves1) {
-    Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType(l.getType())));
-    if(d_equalityEngine.getRepresentative(l).getKind() != kind::EMPTYSET) {
-      leaves1_nonempty.push_back(l);
-    } else {
-      // reason = nm->mkNode(kind::AND, reason, EQUAL(l, emptySet));
-    }
-  }
-  BOOST_FOREACH(TNode l, leaves2) {
-    Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType(l.getType())));
-    if(d_equalityEngine.getRepresentative(l).getKind() != kind::EMPTYSET) {
-      leaves2_nonempty.push_back(l);
-    } else {
-      // reason = nm->mkNode(kind::AND, reason, EQUAL(l, emptySet));
-    }
-  }
-
-  // last minute stuff
-  reason = nm->mkNode(kind::AND, reason, eqemptySoFar());
-        
-  Trace("sets-graph-merge") << "[sets-graph-merge] merge_nodes(..,.., " << reason << ")"
-                            << std::endl;
-  print_graph();
-  Trace("sets-graph") << std::endl;
-  
-  std::set<TNode> leaves3, leaves4;
-  std::set_difference(leaves1_nonempty.begin(), leaves1_nonempty.end(),
-                      leaves2_nonempty.begin(), leaves2_nonempty.end(),
-                      std::inserter(leaves3, leaves3.begin()));
-  std::set_difference(leaves2_nonempty.begin(), leaves2_nonempty.end(),
-                      leaves1_nonempty.begin(), leaves1_nonempty.end(),
-                      std::inserter(leaves4, leaves4.begin()));
-
-  if(leaves3.size() == 0) {
-    Trace("sets-graph-merge") << "[sets-graph-merge]  Merge Equality 1" << std::endl;
-    // make everything in leaves4 empty
-    BOOST_FOREACH(TNode v , leaves4) {
-      Node zero = nm->mkConst(Rational(0));
-      if(!d_equalityEngine.hasTerm(zero)) {
-        d_equalityEngine.addTerm(zero);
-        d_termInfoManager->addTerm(zero);
-      }
-      learnLiteral( /* atom = */ EQUAL(nm->mkNode(kind::CARD, v), zero),
-                    /* polarity = */ true,
-                    /* reason = */  reason);
-    }
-    ++d_statistics.d_numMergeEq1or2;
-  } else if(leaves4.size() == 0) {
-    Trace("sets-graph-merge") << "[sets-graph-merge]  Merge Equality 2" << std::endl;
-    // make everything in leaves3 empty
-    BOOST_FOREACH(TNode v , leaves3) {
-      Node zero = nm->mkConst(Rational(0));
-      if(!d_equalityEngine.hasTerm(zero)) {
-        d_equalityEngine.addTerm(zero);
-        d_termInfoManager->addTerm(zero);
-      }
-      learnLiteral( /* atom = */ EQUAL(nm->mkNode(kind::CARD, v), zero),
-                    /* polarity = */ true,
-                    /* reason = */  reason);
-    }
-    ++d_statistics.d_numMergeEq1or2;
-  } else {
-    Trace("sets-graph-merge") << "[sets-graph-merge]  Merge Equality 3" << std::endl;
-    Trace("sets-graph-merge") << "[sets-graph-merge]    #left= " << leaves1.size()
-                              << " #right= " << leaves2.size()
-                              << " #left non-empty= " << leaves1_nonempty.size()
-                              << " #right non-empty= " << leaves2_nonempty.size()
-                              << " #left-right= " << leaves3.size()
-                              << " #right-left= " << leaves4.size() << std::endl;
-    
-    std::map<TNode, vector<TNode> > children;
-  
-    // Merge Equality 3
-    BOOST_FOREACH(TNode l1 , leaves3) {
-      BOOST_FOREACH(TNode l2 , leaves4) {
-        Node l1_inter_l2 = nm->mkNode(kind::INTERSECTION, min(l1, l2), max(l1, l2));
-        l1_inter_l2 = Rewriter::rewrite(l1_inter_l2);
-        add_node(l1_inter_l2);
-        children[l1].push_back(l1_inter_l2);
-        children[l2].push_back(l1_inter_l2);
-        // if(d_V.find(l1_inter_l2) != d_V.end()) {
-        //   // This case needs to be handled, currently not
-        //   Warning() << "This might create a loop. We need to handle this case. Probably merge the two nodes?" << std::endl;
-        //   Unhandled();
-        // }
-      }
-      ++d_statistics.d_numMergeEq3;
-    }
-
-    for(std::map<TNode, vector<TNode> >::iterator it = children.begin();
-            it != children.end(); ++it) {
-      add_edges(it->first, it->second);
-      Node rhs;
-      if(it->second.size() == 1) {
-        rhs = nm->mkNode(kind::CARD, it->second[0]);
-      } else {
-        NodeBuilder<> nb(kind::PLUS);
-        BOOST_FOREACH(TNode n , it->second) {
-          Node card_n = nm->mkNode(kind::CARD, n);
-          nb << card_n;
-        }
-        rhs = Node(nb);
-      }
-      Node lem;
-      lem = nm->mkNode(kind::EQUAL,
-                       nm->mkNode(kind::CARD, it->first),
-                       rhs);
-      lem = nm->mkNode(kind::IMPLIES, reason, lem);
-      lem = Rewriter::rewrite(lem);
-      d_external.d_out->lemma(lem);
-    }
-  }
-
-  Trace("sets-graph") << std::endl;
-  print_graph();
-  Trace("sets-graph") << std::endl;
-
-}
-
-void  TheorySetsPrivate::print_graph(bool printmodel) {
-  NodeManager* nm = NodeManager::currentNM();
-  std::string tag = "sets-graph";
-  if(Trace.isOn("sets-graph")) {
-    Trace(tag) << "[sets-graph] Graph : " << std::endl;
-    for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) {
-      TNode v = *it;
-      // BOOST_FOREACH(TNode v, d_V) {
-      Trace(tag) << "[" << tag << "]  " << v << " : ";
-      // BOOST_FOREACH(TNode w, d_E[v].get()) {
-      if(d_E.find(v) != d_E.end()) {
-        BOOST_FOREACH(TNode w, d_E[v].get()) {
-          Trace(tag) << w << ", ";
-        }
-      } else {
-        Trace(tag) << " leaf. " ;
-      }
-      Trace(tag) << std::endl;
-    }
-  }
-
-  if(Trace.isOn("sets-graph-dot")) {
-    std::ostringstream oss;
-    oss << "digraph G { ";
-    for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) {
-      TNode v = *it;
-
-      std::ostringstream v_oss;
-      v_oss << v;
-      if(printmodel)
-      {
-        Node n = nm->mkNode(kind::CARD, v);
-        if((Rewriter::rewrite(n)).isConst()) {
-          v_oss << " " << (Rewriter::rewrite(n));
-        } else {
-          v_oss << " " << d_external.d_valuation.getModelValue(n);
-        }
-      }
-      
-      if(d_E.find(v) != d_E.end()) {
-        BOOST_FOREACH(TNode w, d_E[v].get()) {
-
-          std::ostringstream w_oss;
-          w_oss << w;
-          if(printmodel) {
-            Node n = nm->mkNode(kind::CARD, w);
-            if((Rewriter::rewrite(n)).isConst()) {
-              w_oss << " " << (Rewriter::rewrite(n));
-            } else {
-              w_oss << " " << d_external.d_valuation.getModelValue(n);
-            }
-          }
-          
-          //oss << v.getId() << " -> " << w.getId() << "; ";
-          oss << "\"" << v_oss.str() << "\" -> \"" << w_oss.str() << "\"; ";
-        }
-      } else {
-        oss << "\"" << v_oss.str() << "\";";
-      }
-    }
-    oss << "}";
-    Trace("sets-graph-dot") << "[sets-graph-dot] " << oss.str() << std::endl;
-  }
-}
-
-Node TheorySetsPrivate::eqSoFar() {
-  std::vector<Node> V(d_allSetEqualitiesSoFar.begin(), d_allSetEqualitiesSoFar.end());
-  if(V.size() == 0) {
-    return d_trueNode;
-  } else if(V.size() == 1) {
-    return V[0];
-  } else {
-    NodeManager* nm = NodeManager::currentNM();
-    return nm->mkNode(kind::AND, V);
-  }
-}   
-
-
-void TheorySetsPrivate::guessLeavesEmptyLemmas() {
-
-  // Guess leaf nodes being empty or non-empty
-  NodeManager* nm = NodeManager::currentNM();
-  leaves.clear();
-  for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) {
-    TNode v = *it;
-    if(d_E.find(v) == d_E.end()) {
-      leaves.insert(v);
-    }
-  }
-  d_statistics.d_numLeaves.setData(leaves.size());
-  d_statistics.d_numLeavesMax.maxAssign(leaves.size());
-
-  int
-    numLeaves = leaves.size(),
-    numLemmasGenerated = 0,
-    numLeavesIsEmpty = 0,
-    numLeavesIsNonEmpty = 0,
-    numLeavesCurrentlyNonEmpty = 0,
-    numLemmaAlreadyExisted = 0;
-
-  for(std::set<TNode>::iterator it = leaves.begin(); it != leaves.end(); ++it) {
-    bool generateLemma = true;
-    Node emptySet = nm->mkConst<EmptySet>(EmptySet(nm->toType((*it).getType())));
-
-    if(d_equalityEngine.hasTerm(*it)) {
-      Node n = d_equalityEngine.getRepresentative(*it);
-      if(n.getKind() == kind::EMPTYSET) {
-       ++numLeavesIsEmpty;
-       continue;
-      }
-      if(d_termInfoManager->getMembers(n)->size() > 0) {
-       ++numLeavesCurrentlyNonEmpty;
-       continue;
-      }
-      if(!d_equalityEngine.hasTerm(emptySet)) {
-        d_equalityEngine.addTerm(emptySet);
-      }
-      if(d_equalityEngine.areDisequal(n, emptySet, false)) {
-       ++numLeavesIsNonEmpty;
-        generateLemma = false;
-      }
-    }
-
-    if(generateLemma) {
-      Node n = nm->mkNode(kind::EQUAL, (*it), emptySet);
-      Node lem = nm->mkNode(kind::OR, n, nm->mkNode(kind::NOT, n));
-      bool lemmaGenerated =
-       lemma(lem, SETS_LEMMA_GRAPH);
-      if(lemmaGenerated) {
-       ++numLemmasGenerated;
-      } else {
-       ++numLemmaAlreadyExisted;
-      }
-      n = d_external.d_valuation.ensureLiteral(n);
-      d_external.d_out->requirePhase(n, true);
-    }
-
-  }
-  Trace("sets-guess-empty")
-    << "[sets-guess-empty] numLeaves                      = " << numLeaves << std::endl
-    << "                       numLemmasGenerated         = " << numLemmasGenerated << std::endl
-    << "                       numLeavesIsEmpty           = " << numLeavesIsEmpty << std::endl
-    << "                       numLeavesIsNonEmpty        = " << numLeavesIsNonEmpty << std::endl
-    << "                       numLeavesCurrentlyNonEmpty = " << numLeavesCurrentlyNonEmpty << std::endl
-    << "                       numLemmaAlreadyExisted     = " << numLemmaAlreadyExisted << std::endl;
-
-}
-
-void TheorySetsPrivate::processCard2(Theory::Effort level) {
-  CodeTimer codeTimer(d_statistics.d_processCard2Time);
-
-  if(level != Theory::EFFORT_FULL) return;
-
-  d_statistics.d_numVertices.setData(d_V.size());
-  d_statistics.d_numVerticesMax.maxAssign(d_V.size());
-
-  Trace("sets-card") << "[sets-card] processCard( " << level << ")" << std::endl;
-  Trace("sets-card") << "[sets-card]   # vertices = " << d_V.size() << std::endl;
-
-  NodeManager* nm = NodeManager::currentNM();
-
-  if(options::setsGuessEmpty() == 0) {
-    Trace("sets-guess-empty") << "[sets-guess-empty] Generating lemmas before introduce." << std::endl;
-    guessLeavesEmptyLemmas();
-    if(d_newLemmaGenerated) {
-      return;
-    }
-  }
-
-  // Introduce
-  for(CDNodeSet::const_iterator it = d_cardTerms.begin();
-      it != d_cardTerms.end(); ++it) {
-
-    for(eq::EqClassIterator j(d_equalityEngine.getRepresentative((*it)[0]), &d_equalityEngine);
-        !j.isFinished(); ++j) {
-
-      Node n = nm->mkNode(kind::CARD, (*j));
-
-      if(d_processedCardTerms.find(n) != d_processedCardTerms.end()) {
-        continue;
-      }
-
-      if(d_relTerms.find(n[0]) == d_relTerms.end()) {
-        // not relevant, skip
-        continue;
-      }
-
-      Trace("sets-graph") << std::endl;
-      print_graph();
-      Trace("sets-graph") << std::endl;
-      
-      add_node(n[0]);
-
-      Trace("sets-card") << "[sets-card]  Processing " << n << " in eq cl of " << (*it) << std::endl;
-
-      d_processedCardTerms.insert(n);
-      
-      Kind k = n[0].getKind();
-
-      if(k == kind::SINGLETON) {
-        Trace("sets-card") << "[sets-card]  Introduce Singleton " << n[0] << std::endl;
-        continue;
-      }
-
-      // rest of the processing is for compound terms
-      if(k != kind::UNION && k != kind::INTERSECTION && k != kind::SETMINUS) {
-        continue;
-      }
-  
-      Trace("sets-card") << "[sets-card]  Introduce Term " << n[0] << std::endl;
-      
-      Node s = min(n[0][0], n[0][1]);
-      Node t = max(n[0][0], n[0][1]);
-      bool isUnion = (k == kind::UNION);
-      Assert(Rewriter::rewrite(s) == s);
-      Assert(Rewriter::rewrite(t) == t);
-
-      Node sNt = nm->mkNode(kind::INTERSECTION, s, t);
-      sNt = Rewriter::rewrite(sNt);
-      Node sMt = nm->mkNode(kind::SETMINUS, s, t);
-      sMt = Rewriter::rewrite(sMt);
-      Node tMs = nm->mkNode(kind::SETMINUS, t, s);
-      tMs = Rewriter::rewrite(tMs);
-
-      Node card_s = nm->mkNode(kind::CARD, s);
-      Node card_t = nm->mkNode(kind::CARD, t);
-      Node card_sNt = nm->mkNode(kind::CARD, sNt);
-      Node card_sMt = nm->mkNode(kind::CARD, sMt);
-      Node card_tMs = nm->mkNode(kind::CARD, tMs);
-
-      Node lem;
-      
-      add_node(sMt);
-      add_node(sNt);
-      add_node(tMs);
-
-
-      // for union
-      if(isUnion) {
-        if(d_E.find(n[0]) != d_E.end()) {
-          // do a merge of current leaves of d_E with 
-          // sNT sMT tMs
-          Trace("sets-card") << "[sets-card] Already found in the graph, merging " << n[0] << std::endl;
-          merge_nodes(get_leaves(n[0]), get_leaves(sMt, sNt, tMs), eqSoFar());
-        } else {
-          add_node(n[0]);
-
-          lem = nm->mkNode(kind::EQUAL,
-                           n,     // card(s union t)
-                           nm->mkNode(kind::PLUS, card_sNt, card_sMt, card_tMs));
-          lemma(lem, SETS_LEMMA_GRAPH);
-
-          Assert(d_E.find(n[0]) == d_E.end());
-          add_edges(n[0], sMt, sNt, tMs);
-        }
-      }
-
-      // for s
-      if(d_E.find(s) == d_E.end()) {
-        add_node(s);
-        add_edges(s, sMt, sNt);
-
-        lem = nm->mkNode(kind::EQUAL,
-                         card_s,
-                         nm->mkNode(kind::PLUS, card_sNt, card_sMt));
-        lemma(lem, SETS_LEMMA_GRAPH);
-      } else {
-        if(find(d_E[s].get().begin(), d_E[s].get().end(), sMt) != d_E[s].get().end()) {
-          Assert( find(d_E[s].get().begin(), d_E[s].get().end(), sMt) != d_E[s].get().end() );
-          Assert( find(d_E[s].get().begin(), d_E[s].get().end(), sNt) != d_E[s].get().end() );
-          Assert( find(d_E[t].get().begin(), d_E[t].get().end(), tMs) != d_E[t].get().end() );
-          Assert( find(d_E[t].get().begin(), d_E[t].get().end(), sNt) != d_E[t].get().end() );
-          continue;
-        }
-        
-        Trace("sets-card") << "[sets-card] Already found in the graph, merging " << s << std::endl;
-        merge_nodes(get_leaves(s), get_leaves(sMt, sNt), eqSoFar());
-      }
-
-      // for t
-      if(d_E.find(t) == d_E.end()) {
-        Assert(d_E.find(t) == d_E.end());
-        add_node(t);
-        add_edges(t, sNt, tMs);
-
-        lem = nm->mkNode(kind::EQUAL,
-                         card_t,
-                         nm->mkNode(kind::PLUS, card_sNt, card_tMs));
-        lemma(lem, SETS_LEMMA_GRAPH);
-      } else {
-        // Assert( find(d_E[s].get().begin(), d_E[s].get().end(), sMt) == d_E[s].get().end() );
-        // Assert( find(d_E[s].get().begin(), d_E[s].get().end(), sNt) == d_E[s].get().end() );
-        // Assert( find(d_E[t].get().begin(), d_E[t].get().end(), tMs) == d_E[t].get().end() );
-        // Assert( find(d_E[t].get().begin(), d_E[t].get().end(), sNt) == d_E[t].get().end() );
-        
-        Trace("sets-card") << "[sets-card] Already found in the graph, merging " << t << std::endl;
-        merge_nodes(get_leaves(t), get_leaves(sNt, tMs), eqSoFar());
-      }
-
-      if(options::setsSlowLemmas()) {
-       if(d_newLemmaGenerated) {
-         break;
-       } else if(options::setsGuessEmpty() == 0) {
-         guessLeavesEmptyLemmas();
-         if(d_newLemmaGenerated) {
-           return;
-         }
-       }
-      }
-
-    }//equivalence class loop
-
-    if(options::setsSlowLemmas() && d_newLemmaGenerated) {
-      break;
-    }
-
-  }//d_cardTerms loop
-
-  print_graph();
-
-  if(d_newLemmaGenerated) {
-    Trace("sets-card") << "[sets-card] New introduce done. Returning." << std::endl;
-    return;
-  }
-
-  if(options::setsGuessEmpty() == 1) {
-    guessLeavesEmptyLemmas();
-    if(d_newLemmaGenerated) {
-      return;
-    }
-  }
-
-  // Merge equalities from input assertions
-
-  while(!d_graphMergesPending.empty()) {
-    std::pair<TNode,TNode> np = d_graphMergesPending.front();
-    d_graphMergesPending.pop();
-
-    Debug("sets-card") << "[sets-card] Equality " << np.first << " " << np.second << std::endl;
-    if(np.first.getKind() == kind::EMPTYSET || np.second.getKind() == kind::EMPTYSET) {
-      Debug("sets-card") << "[sets-card]    skipping merge as one side is empty set" << std::endl;
-      continue;
-    }
-
-    if(d_V.find(np.first) == d_V.end() || d_V.find(np.second) == d_V.end()) {
-      Assert((d_V.find(np.first) == d_V.end()));
-      Assert((d_V.find(np.second) == d_V.end()));
-      continue;
-    }
-    d_allSetEqualitiesSoFar.push_back(EQUAL(np.first, np.second));
-    // merge_nodes(get_leaves(np.first), get_leaves(np.second), EQUAL(np.first, np.second));
-    merge_nodes(get_leaves(np.first), get_leaves(np.second), eqSoFar());
-  }
-
-  if(d_newLemmaGenerated) {
-    Trace("sets-card") << "[sets-card] New merge done. Returning." << std::endl;
-    return;
-  }
-
-  leaves.clear();
-  for(CDNodeSet::const_iterator it = d_V.begin(); it != d_V.end(); ++it) {
-    TNode v = *it;
-    if(d_E.find(v) == d_E.end()) {
-      leaves.insert(v);
-    }
-  }
-  Trace("sets-card") << "[sets-card] # leaves = " << leaves.size() << std::endl;
-  d_statistics.d_numLeaves.setData(leaves.size());
-  d_statistics.d_numLeavesMax.maxAssign(leaves.size());
-
-  Assert(!d_newLemmaGenerated);
-
-
-  if(options::setsGuessEmpty() == 2) {
-    guessLeavesEmptyLemmas();
-    if(d_newLemmaGenerated) {
-      return;
-    }
-  }
-
-  typedef std::set<TNode>::const_iterator TNodeSetIterator;
-
-  // Elements being either equal or disequal [Members Arrangement rule]
-  Trace("sets-card")
-      << "[sets-card] Processing elements equality/disequal to each other"
-      << std::endl;
-  for (TNodeSetIterator it = leaves.begin(); it != leaves.end(); ++it) {
-    if (!d_equalityEngine.hasTerm(*it)) continue;
-    Node n = d_equalityEngine.getRepresentative(*it);
-    Assert(n.getKind() == kind::EMPTYSET || leaves.find(n) != leaves.end());
-    if (n != *it) continue;
-    const CDTNodeList* l = d_termInfoManager->getMembers(*it);
-    std::set<TNode> elems;
-    for (CDTNodeList::const_iterator l_it = l->begin(); l_it != l->end(); ++l_it) {
-      elems.insert(d_equalityEngine.getRepresentative(*l_it));
-    }
-    for (TNodeSetIterator e1_it = elems.begin(); e1_it != elems.end();
-         ++e1_it) {
-      for (TNodeSetIterator e2_it = elems.begin(); e2_it != elems.end();
-           ++e2_it) {
-        if (*e1_it == *e2_it) continue;
-        if (!d_equalityEngine.areDisequal(*e1_it, *e2_it, false)) {
-          Node lem = nm->mkNode(kind::EQUAL, *e1_it, *e2_it);
-          lem = nm->mkNode(kind::OR, lem, nm->mkNode(kind::NOT, lem));
-          lemma(lem, SETS_LEMMA_GRAPH);
-        }
-      }
-    }
-  }
-
-  if(d_newLemmaGenerated) {
-    Trace("sets-card") << "[sets-card] Members arrangments lemmas. Returning." << std::endl;
-    return;
-  }
-
-  // Assert Lower bound
-  Trace("sets-card") << "[sets-card] Processing assert lower bound" << std::endl;
-  for(TNodeSetIterator it = leaves.begin(); it != leaves.end(); ++it) {
-    Trace("sets-cardlower") << "[sets-cardlower] Card Lower: " << *it << std::endl;
-    Assert(d_equalityEngine.hasTerm(*it));
-    Node n = d_equalityEngine.getRepresentative(*it);
-    // Node n = (*it);
-    // if(!d_equalityEngine.hasTerm(n)) {
-    //   Trace("sets-cardlower") << "[sets-cardlower]   not in EE" << std::endl;
-    //   continue;
-    // }
-    // Assert(n.getKind() == kind::EMPTYSET || leaves.find(n) != leaves.end()); // ????
-    // if(n != *it) continue;
-    const CDTNodeList* l = d_termInfoManager->getMembers(n);
-    std::set<TNode> elems;
-    for(CDTNodeList::const_iterator l_it = l->begin(); l_it != l->end(); ++l_it) {
-      elems.insert(d_equalityEngine.getRepresentative(*l_it));
-    }
-    if(elems.size() == 0) continue;
-    NodeBuilder<> nb(kind::OR);
-    nb << ( nm->mkNode(kind::LEQ, nm->mkConst(Rational(elems.size())), nm->mkNode(kind::CARD, *it)) );
-    if(elems.size() > 1) {
-      for(TNodeSetIterator e1_it = elems.begin(); e1_it != elems.end(); ++e1_it) {
-        for(TNodeSetIterator e2_it = elems.begin(); e2_it != elems.end(); ++e2_it) {
-          if(*e1_it == *e2_it) continue;
-          nb << (nm->mkNode(kind::EQUAL, *e1_it, *e2_it));
-        }
-      }
-    }
-    for(TNodeSetIterator e_it = elems.begin(); e_it != elems.end(); ++e_it) {
-      nb << nm->mkNode(kind::NOT, nm->mkNode(kind::MEMBER, *e_it, *it));
-    }
-    Node lem = Node(nb);
-    // if(d_cardLowerLemmaCache.find(lem) == d_cardLowerLemmaCache.end()) {
-    Trace("sets-card") << "[sets-card] Card Lower: " << lem << std::endl;
-    lemma(lem, SETS_LEMMA_GRAPH);
-    // d_cardLowerLemmaCache.insert(lem);
-    // }
-  }  
-}
-
-  
-  
 }/* CVC4::theory::sets namespace */
 }/* CVC4::theory namespace */
 }/* CVC4 namespace */
index 049e957867ad0b652d6672b1565ad00ba33d470e..25a15a84a63a47320a231a88d5b2647b7f791cd4 100644 (file)
 
 #include "theory/theory.h"
 #include "theory/uf/equality_engine.h"
-#include "theory/sets/term_info.h"
+#include "theory/sets/theory_sets_rels.h"
 
 namespace CVC4 {
 namespace theory {
+
+namespace quantifiers{
+  class TermArgTrie;
+}
+
 namespace sets {
 
 /** Internal classes, forward declared here */
@@ -36,6 +41,107 @@ class TheorySets;
 class TheorySetsScrutinize;
 
 class TheorySetsPrivate {
+//new implementation
+  typedef context::CDHashMap< Node, bool, NodeHashFunction> NodeBoolMap;
+  typedef context::CDHashMap< Node, int, NodeHashFunction> NodeIntMap;
+  typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
+  typedef context::CDHashMap< Node, Node, NodeHashFunction > NodeMap;
+private:
+  TheorySetsRels * d_rels;
+public:
+  void eqNotifyNewClass(TNode t);
+  void eqNotifyPreMerge(TNode t1, TNode t2);
+  void eqNotifyPostMerge(TNode t1, TNode t2);
+  void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
+private:
+  bool ee_areEqual( Node a, Node b );
+  bool ee_areDisequal( Node a, Node b );
+  NodeIntMap d_members;
+  std::map< Node, std::vector< Node > > d_members_data;
+  bool assertFact( Node fact, Node exp );
+  // inferType : 1 : must send out as lemma, -1 : do internal inferences if possible, 0 : default.
+  bool assertFactRec( Node fact, Node exp, std::vector< Node >& lemma, int inferType = 0 );
+  // add inferences corresponding to ( exp => fact ) to lemmas, equality engine
+  void assertInference( Node fact, Node exp, std::vector< Node >& lemmas, const char * c, int inferType = 0 );
+  void assertInference( Node fact, std::vector< Node >& exp, std::vector< Node >& lemmas, const char * c, int inferType = 0 );
+  void assertInference( std::vector< Node >& conc, Node exp, std::vector< Node >& lemmas, const char * c, int inferType = 0 );
+  void assertInference( std::vector< Node >& conc, std::vector< Node >& exp, std::vector< Node >& lemmas, const char * c, int inferType = 0 );
+  // send lemma ( n OR (NOT n) ) immediately
+  void split( Node n, int reqPol=0 );
+  void fullEffortCheck();
+  void checkDownwardsClosure( std::vector< Node >& lemmas );
+  void checkUpwardsClosure( std::vector< Node >& lemmas );
+  void checkDisequalities( std::vector< Node >& lemmas );
+  bool isMember( Node x, Node s );
+  
+  void flushLemmas( std::vector< Node >& lemmas );
+  Node getProxy( Node n );
+  Node getCongruent( Node n );
+  Node getEmptySet( TypeNode tn );
+  bool hasLemmaCached( Node lem );
+  bool hasProcessed();
+  
+  void addCarePairs( quantifiers::TermArgTrie * t1, quantifiers::TermArgTrie * t2, unsigned arity, unsigned depth, unsigned& n_pairs );
+  
+  Node d_true;
+  Node d_false;
+  Node d_zero;
+  NodeBoolMap d_deq;
+  NodeSet d_deq_processed;
+  NodeSet d_keep;
+  std::vector< Node > d_emp_exp;
+  
+  //propagation
+  class EqcInfo
+  {
+  public:
+    EqcInfo( context::Context* c );
+    ~EqcInfo(){}
+    // singleton or emptyset equal to this eqc
+    context::CDO< Node > d_singleton;
+  };
+  /** information necessary for equivalence classes */
+  std::map< Node, EqcInfo* > d_eqc_info;
+  /** get or make eqc info */
+  EqcInfo* getOrMakeEqcInfo( TNode n, bool doMake = false );
+  
+  void addEqualityToExp( Node a, Node b, std::vector< Node >& exp );
+  
+  void debugPrintSet( Node s, const char * c );
+  
+  bool d_sentLemma;
+  bool d_addedFact;
+  NodeMap d_proxy;  
+  NodeMap d_proxy_to_term;  
+  NodeSet d_lemmas_produced;
+  std::vector< Node > d_set_eqc;
+  std::map< Node, std::vector< Node > > d_set_eqc_list;
+  std::map< TypeNode, Node > d_eqc_emptyset;
+  std::map< Node, Node > d_eqc_singleton;
+  std::map< TypeNode, Node > d_emptyset;
+  std::map< Node, Node > d_congruent;
+  std::map< Node, std::vector< Node > > d_nvar_sets;
+  std::map< Node, std::map< Node, Node > > d_pol_mems[2];
+  std::map< Node, std::map< Node, Node > > d_members_index;
+  std::map< Node, Node > d_singleton_index;
+  std::map< Kind, std::map< Node, std::map< Node, Node > > > d_bop_index;
+  std::map< Kind, std::vector< Node > > d_op_list;
+  //cardinality
+private:
+  bool d_card_enabled;
+  std::map< Node, Node > d_eqc_to_card_term;
+  NodeSet d_card_processed;
+  std::map< Node, std::vector< Node > > d_card_parent;
+  std::map< Node, std::map< Node, std::vector< Node > > > d_ff;
+  std::map< Node, std::vector< Node > > d_nf;
+  std::map< Node, Node > d_card_base;
+  void checkCardBuildGraph( std::vector< Node >& lemmas );
+  void registerCardinalityTerm( Node n, std::vector< Node >& lemmas );
+  void checkCardCycles( std::vector< Node >& lemmas );
+  void checkCardCyclesRec( Node eqc, std::vector< Node >& curr, std::vector< Node >& exp, std::vector< Node >& lemmas );
+  void checkNormalForms( std::vector< Node >& lemmas, std::vector< Node >& intro_sets );
+  void checkNormalForm( Node eqc, std::vector< Node >& intro_sets );
+  void checkMinCard( std::vector< Node >& lemmas );
 public:
 
   /**
@@ -62,8 +168,6 @@ public:
 
   EqualityStatus getEqualityStatus(TNode a, TNode b);
 
-  Node getModelValue(TNode);
-
   void preRegisterTerm(TNode node);
 
   void presolve();
@@ -101,19 +205,15 @@ private:
     bool eqNotifyTriggerPredicate(TNode predicate, bool value);
     bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value);
     void eqNotifyConstantTermMerge(TNode t1, TNode t2);
-    void eqNotifyNewClass(TNode t) {}
-    void eqNotifyPreMerge(TNode t1, TNode t2) {}
-    void eqNotifyPostMerge(TNode t1, TNode t2) {}
-    void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {}
+    void eqNotifyNewClass(TNode t);
+    void eqNotifyPreMerge(TNode t1, TNode t2);
+    void eqNotifyPostMerge(TNode t1, TNode t2);
+    void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
   } d_notify;
 
   /** Equality engine */
   eq::EqualityEngine d_equalityEngine;
 
-  /** True and false constant nodes */
-  Node d_trueNode;
-  Node d_falseNode;
-
   context::CDO<bool> d_conflict;
   Node d_conflictNode;
 
@@ -122,179 +222,11 @@ private:
 
   /** generate and send out conflict node */
   void conflict(TNode, TNode);
-
-  /** send out a lemma */
-  enum SetsLemmaTag {
-    SETS_LEMMA_DISEQUAL,
-    SETS_LEMMA_MEMBER,
-    SETS_LEMMA_GRAPH,
-    SETS_LEMMA_OTHER
-  };
-
-  /**
-   * returns true if a lemmas was generated
-   * returns false otherwise (found in cache)
-   */
-  bool lemma(Node n, SetsLemmaTag t);
-
-  class TermInfoManager {
-    TheorySetsPrivate& d_theory;
-    context::Context* d_context;
-    eq::EqualityEngine* d_eqEngine;
-  public:
-    CDNodeSet d_terms;
-  private:
-    typedef std::hash_map<TNode, TheorySetsTermInfo*, TNodeHashFunction> SetsTermInfoMap;
-    SetsTermInfoMap d_info;
-
-    void mergeLists(CDTNodeList* la, const CDTNodeList* lb) const;
-    void pushToSettermPropagationQueue(TNode x, TNode S, bool polarity);
-    void pushToSettermPropagationQueue(CDTNodeList* l, TNode S, bool polarity);
-    void pushToSettermPropagationQueue(TNode x, CDTNodeList* l, bool polarity);
-  public:
-    TermInfoManager(TheorySetsPrivate&,
-                    context::Context* satContext,
-                    eq::EqualityEngine*);
-    ~TermInfoManager();
-    void notifyMembership(TNode fact);
-    const CDTNodeList* getParents(TNode x);
-    const CDTNodeList* getMembers(TNode S);
-    Node getModelValue(TNode n);
-    const CDTNodeList* getNonMembers(TNode S);
-    void addTerm(TNode n);
-    void mergeTerms(TNode a, TNode b);
-  };
-  TermInfoManager* d_termInfoManager;
-
-  /******
-   * Card Vars :
-   *
-   * mapping from set terms to correpsonding cardinality variable
-   * 
-   * in the ::check function, when we get one of those cardinality
-   * variables to be assigned to 0, we will assert in equality engine
-   * to be equal to empty set.
-   *
-   * if required, we will add more filters so it doesn't leak to
-   * outside world
-   */
-  Node getCardVar(TNode n);
-  Node newCardVar(TNode n);
-  bool isCardVar(TNode n);
-  typedef std::hash_map <Node, Node, NodeHashFunction> NodeNodeHashMap;
-  NodeNodeHashMap d_setTermToCardVar;
-  NodeNodeHashMap d_cardVarToSetTerm;
   
-  /** Assertions and helper functions */
-  bool present(TNode atom);
-  bool holds(TNode lit) {
-    bool polarity = lit.getKind() == kind::NOT ? false : true;
-    TNode atom = polarity ? lit : lit[0];
-    return holds(atom, polarity);
-  }
-  bool holds(TNode atom, bool polarity);
-
-  void assertEquality(TNode fact, TNode reason, bool learnt);
-  void assertMemebership(TNode fact, TNode reason, bool learnt);
-
-  /** Propagation / learning and helper functions. */
-  context::CDQueue< std::pair<Node, Node> > d_propagationQueue;
-  context::CDQueue< std::pair<TNode, TNode> > d_settermPropagationQueue;
-
-  void doSettermPropagation(TNode x, TNode S);
-  void registerReason(TNode reason, bool save);
-  void learnLiteral(TNode atom, bool polarity, Node reason);
-  void learnLiteral(TNode lit, Node reason) {
-    if(lit.getKind() == kind::NOT) {
-      learnLiteral(lit[0], false, reason);
-    } else {
-      learnLiteral(lit, true, reason);
-    }
-  }
-  void finishPropagation();
-
-  // for any nodes we need to save, because others use TNode
-  context::CDHashSet <Node, NodeHashFunction> d_nodeSaver;
-
-  /** Lemmas and helper functions */
-  context::CDQueue <Node> d_pending;
-  context::CDQueue <Node> d_pendingDisequal;
-  context::CDHashSet <Node, NodeHashFunction> d_pendingEverInserted;
-
-  void addToPending(Node n);
-  bool isComplete();
-  Node getLemma();
-
-  /** model generation and helper function */
-  typedef std::set<TNode> Elements;
-  typedef std::hash_map<TNode, Elements, TNodeHashFunction> SettermElementsMap;
-  const Elements& getElements(TNode setterm, SettermElementsMap& settermElementsMap) const;
-  Node elementsToShape(Elements elements, TypeNode setType) const;
-  Node elementsToShape(std::set<Node> elements, TypeNode setType) const;
-  bool checkModel(const SettermElementsMap& settermElementsMap, TNode S) const;
-
-  context::CDHashMap <Node, Node, NodeHashFunction> d_modelCache;
-
-
-  // sharing related
-  context::CDO<unsigned>  d_ccg_i, d_ccg_j;
-
-  // more debugging stuff
-  friend class TheorySetsScrutinize;
-  TheorySetsScrutinize* d_scrutinize;
-  void dumpAssertionsHumanified() const;  /** do some formatting to make them more readable */
-
-
-
-  /***** Cardinality handling *****/
-  bool d_cardEnabled;
-  void enableCard();
-  void cardCreateEmptysetSkolem(TypeNode t);
-
-  CDNodeSet d_cardTerms;
-  std::set<TypeNode> d_typesAdded;
-  CDNodeSet d_processedCardTerms;
-  std::map<std::pair<Node, Node>, bool> d_processedCardPairs;
-  CDNodeSet d_cardLowerLemmaCache;
-  void registerCard(TNode);
-  void processCard(Theory::Effort level);
-
-  /* Graph handling */
-  std::map<TNode, std::set<TNode> > edgesFd;
-  std::map<TNode, std::set<TNode> > edgesBk;
-  std::set< std::pair<TNode, TNode> > disjoint;
-  std::set<TNode> leaves;
-  void buildGraph();
-
-  /* For calculus as in paper */
-  void processCard2(Theory::Effort level);
-  CDNodeSet d_V;
-  context::CDHashMap <TNode, std::vector<TNode>, TNodeHashFunction > d_E;
-  void add_edges(TNode source, TNode dest);
-  void add_edges(TNode source, TNode dest1, TNode dest2);
-  void add_edges(TNode source, TNode dest1, TNode dest2, TNode dest3);
-  void add_edges(TNode source, const std::vector<TNode>& dests);
-  void add_node(TNode vertex);
-  void merge_nodes(std::set<TNode> a, std::set<TNode> b, Node reason);
-  std::set<TNode> get_leaves(Node vertex);
-  std::set<TNode> get_leaves(Node vertex1, Node vertex2);
-  std::set<TNode> get_leaves(Node vertex1, Node vertex2, Node vertex3);
-  std::set<TNode> non_empty(std::set<TNode> vertices);
-  void print_graph(bool printmodel=false);
-  context::CDQueue < std::pair<TNode, TNode> > d_graphMergesPending;
-  context::CDList<Node> d_allSetEqualitiesSoFar;
-  Node eqSoFar();
-  Node eqemptySoFar();
-
-  std::set<TNode> getNonEmptyLeaves(TNode);
-  CDNodeSet d_lemmasGenerated;
-  bool d_newLemmaGenerated;
-
-  void guessLeavesEmptyLemmas();
-
-
-  /** relevant terms */
-  CDNodeSet d_relTerms;
+  bool isCareArg( Node n, unsigned a );
+public:
+  bool isEntailed( Node n, bool pol );
+  
 };/* class TheorySetsPrivate */
 
 
diff --git a/src/theory/sets/theory_sets_rels.cpp b/src/theory/sets/theory_sets_rels.cpp
new file mode 100644 (file)
index 0000000..c7ec082
--- /dev/null
@@ -0,0 +1,1907 @@
+/*********************                                                        */
+/*! \file theory_sets_rels.cpp
+ ** \verbatim
+ ** Original author: Paul Meng
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014  New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Sets theory implementation.
+ **
+ ** Extension to Sets theory.
+ **/
+
+#include "theory/sets/theory_sets_rels.h"
+#include "expr/datatype.h"
+#include "theory/sets/theory_sets_private.h"
+#include "theory/sets/theory_sets.h"
+
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace sets {
+
+typedef std::map< Node, std::vector< Node > >::iterator                                         MEM_IT;
+typedef std::map< kind::Kind_t, std::vector< Node > >::iterator                                 KIND_TERM_IT;
+typedef std::map< Node, std::hash_set< Node, NodeHashFunction > >::iterator                     TC_PAIR_IT;
+typedef std::map< Node, std::map< kind::Kind_t, std::vector< Node > > >::iterator               TERM_IT;
+typedef std::map< Node, std::map< Node, std::hash_set< Node, NodeHashFunction > > >::iterator   TC_IT;
+
+int TheorySetsRels::EqcInfo::counter        = 0;
+
+  void TheorySetsRels::check(Theory::Effort level) {
+    Trace("rels") << "\n[sets-rels] ******************************* Start the relational solver *******************************\n" << std::endl;
+    if(Theory::fullEffort(level)) {
+      collectRelsInfo();
+      check();
+      doPendingLemmas();
+      Assert(d_lemma_cache.empty());
+      Assert(d_pending_facts.empty());
+    } else {
+      doPendingMerge();
+      doPendingLemmas();
+    }
+    Trace("rels") << "\n[sets-rels] ******************************* Done with the relational solver *******************************\n" << std::endl;
+  }
+
+  void TheorySetsRels::check() {
+    MEM_IT m_it = d_membership_constraints_cache.begin();
+
+    while(m_it != d_membership_constraints_cache.end()) {
+      Node rel_rep = m_it->first;
+
+      for(unsigned int i = 0; i < m_it->second.size(); i++) {
+        Node                                          exp             = d_membership_exp_cache[rel_rep][i];
+        std::map<kind::Kind_t, std::vector<Node> >    kind_terms      = d_terms_cache[rel_rep];
+
+        if( kind_terms.find(kind::TRANSPOSE) != kind_terms.end() ) {
+          std::vector<Node> tp_terms = kind_terms[kind::TRANSPOSE];
+          // exp is a membership term and tp_terms contains all
+          // transposed terms that are equal to the right hand side of exp
+          for(unsigned int j = 0; j < tp_terms.size(); j++) {
+            applyTransposeRule( exp, tp_terms[j] );
+          }
+        }
+        if( kind_terms.find(kind::JOIN) != kind_terms.end() ) {
+          std::vector<Node> join_terms = kind_terms[kind::JOIN];
+          // exp is a membership term and join_terms contains all
+          // terms involving "join" operator that are in the same
+          // equivalence class with the right hand side of exp
+          for(unsigned int j = 0; j < join_terms.size(); j++) {
+            applyJoinRule( exp, join_terms[j] );
+          }
+        }
+        if( kind_terms.find(kind::PRODUCT) != kind_terms.end() ) {
+          std::vector<Node> product_terms = kind_terms[kind::PRODUCT];
+          for(unsigned int j = 0; j < product_terms.size(); j++) {
+            applyProductRule( exp, product_terms[j] );
+          }
+        }
+        if( kind_terms.find(kind::TCLOSURE) != kind_terms.end() ) {
+          std::vector<Node> tc_terms = kind_terms[kind::TCLOSURE];
+          for(unsigned int j = 0; j < tc_terms.size(); j++) {
+            applyTCRule( exp, tc_terms[j] );
+          }
+        }
+
+        MEM_IT tp_it = d_arg_rep_tp_terms.find( rel_rep );
+
+        if( tp_it != d_arg_rep_tp_terms.end() ) {
+          std::vector< Node >::iterator tp_ts_it = tp_it->second.begin();
+
+          while( tp_ts_it != tp_it->second.end() ) {
+            applyTransposeRule( exp, *tp_ts_it, (*tp_ts_it)[0] == rel_rep?Node::null():explain(NodeManager::currentNM()->mkNode(kind::EQUAL,(*tp_ts_it)[0], rel_rep)), true );
+            ++tp_ts_it;
+          }
+          ++tp_it;
+        }
+      }
+      m_it++;
+    }
+
+    TERM_IT t_it = d_terms_cache.begin();
+    while( t_it != d_terms_cache.end() ) {
+      if( d_membership_constraints_cache.find(t_it->first) == d_membership_constraints_cache.end() ) {
+        Trace("rels-debug") << "[sets-rels] A term does not have membership constraints: " << t_it->first << std::endl;
+        KIND_TERM_IT k_t_it = t_it->second.begin();
+
+        while( k_t_it != t_it->second.end() ) {
+          if( k_t_it->first == kind::JOIN || k_t_it->first == kind::PRODUCT ) {
+            std::vector<Node>::iterator term_it = k_t_it->second.begin();
+            while(term_it != k_t_it->second.end()) {
+              computeMembersForRelofMultArities(*term_it);
+              term_it++;
+            }
+          } else if ( k_t_it->first == kind::TRANSPOSE ) {
+            std::vector<Node>::iterator term_it = k_t_it->second.begin();
+            while( term_it != k_t_it->second.end() ) {
+              computeMembersForUnaryRel(*term_it);
+              term_it++;
+            }
+          } else if ( k_t_it->first == kind::TCLOSURE ) {
+            Trace("rels-debug") << "[sets-rels] ********** A TCLOSURE term does not have membership constraints: " << t_it->first << std::endl;
+            d_tc_rep_term[t_it->first] = k_t_it->second[0];
+          }
+          k_t_it++;
+        }
+      }
+      t_it++;
+    }
+
+    finalizeTCInference();
+  }
+
+  /*
+   * Populate relational terms data structure
+   */
+
+  void TheorySetsRels::collectRelsInfo() {
+    Trace("rels") << "[sets-rels] Start collecting relational terms..." << std::endl;
+    eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( d_eqEngine );
+    while( !eqcs_i.isFinished() ){
+      Node                      eqc_rep  = (*eqcs_i);
+      eq::EqClassIterator       eqc_i   = eq::EqClassIterator( eqc_rep, d_eqEngine );
+
+      Trace("rels-ee") << "[sets-rels-ee] term representative: " << eqc_rep << std::endl;
+
+      while( !eqc_i.isFinished() ){
+        Node eqc_node = (*eqc_i);
+
+        Trace("rels-ee") << "  term : " << eqc_node << std::endl;
+
+        if(getRepresentative(eqc_rep) == getRepresentative(d_trueNode) ||
+           getRepresentative(eqc_rep) == getRepresentative(d_falseNode)) {
+          // collect membership info
+          if(eqc_node.getKind() == kind::MEMBER && eqc_node[1].getType().getSetElementType().isTuple()) {
+            Node tup_rep = getRepresentative(eqc_node[0]);
+            Node rel_rep = getRepresentative(eqc_node[1]);
+
+            if(eqc_node[0].isVar()){
+              reduceTupleVar(eqc_node);
+            }
+            if( safelyAddToMap(d_membership_constraints_cache, rel_rep, tup_rep) ) {
+              bool is_true_eq    = areEqual(eqc_rep, d_trueNode);
+              Node reason        = is_true_eq ? eqc_node : eqc_node.negate();
+              addToMap(d_membership_exp_cache, rel_rep, reason);
+              if( is_true_eq ) {
+                // add tup_rep to membership database
+                // and store mapping between tuple and tuple's elements representatives
+                addToMembershipDB(rel_rep, tup_rep, reason);
+              }
+            }
+          }
+        // collect relational terms info
+        } else if( eqc_rep.getType().isSet() && eqc_rep.getType().getSetElementType().isTuple() ) {
+          if( eqc_node.getKind() == kind::TRANSPOSE || eqc_node.getKind() == kind::JOIN ||
+              eqc_node.getKind() == kind::PRODUCT || eqc_node.getKind() == kind::TCLOSURE ) {
+            std::vector<Node>                           terms;
+            std::map<kind::Kind_t, std::vector<Node> >  rel_terms;
+            TERM_IT     terms_it      = d_terms_cache.find(eqc_rep);
+
+            if( eqc_node.getKind() == kind::TRANSPOSE ) {
+              Node      eqc_node0_rep   = getRepresentative( eqc_node[0] );
+              MEM_IT    mem_it          = d_arg_rep_tp_terms.find( eqc_node0_rep );
+
+              if( mem_it != d_arg_rep_tp_terms.end() ) {
+                mem_it->second.push_back( eqc_node );
+              } else {
+                std::vector< Node > tp_terms;
+                tp_terms.push_back( eqc_node );
+                d_arg_rep_tp_terms[eqc_node0_rep] = tp_terms;
+              }
+            }
+
+            if( terms_it == d_terms_cache.end() ) {
+              terms.push_back(eqc_node);
+              rel_terms[eqc_node.getKind()]      = terms;
+              d_terms_cache[eqc_rep]             = rel_terms;
+            } else {
+              KIND_TERM_IT kind_term_it = terms_it->second.find(eqc_node.getKind());
+
+              if( kind_term_it == terms_it->second.end() ) {
+                terms.push_back(eqc_node);
+                d_terms_cache[eqc_rep][eqc_node.getKind()] = terms;
+              } else {
+                kind_term_it->second.push_back(eqc_node);
+              }
+            }
+          }
+        // need to add all tuple elements as shared terms
+        } else if(eqc_node.getType().isTuple() && !eqc_node.isConst() && !eqc_node.isVar()) {
+          for(unsigned int i = 0; i < eqc_node.getType().getTupleLength(); i++) {
+            Node element = RelsUtils::nthElementOfTuple(eqc_node, i);
+            if(!element.isConst()) {
+              makeSharedTerm(element);
+            }
+          }
+        }
+        ++eqc_i;
+      }
+      ++eqcs_i;
+    }
+    Trace("rels-debug") << "[sets-rels] Done with collecting relational terms!" << std::endl;
+  }
+
+  /*
+   * Construct transitive closure graph for tc_rep based on the members of tc_r_rep
+   */
+
+  std::map< Node, std::hash_set< Node, NodeHashFunction > > TheorySetsRels::constructTCGraph(Node tc_r_rep, Node tc_rep, Node tc_term) {
+    Trace("rels-tc") << "[sets-rels] Construct TC graph for transitive closure relation " << tc_rep << std::endl;
+
+    std::map< Node, std::hash_set< Node, NodeHashFunction > > tc_graph;
+    std::map< Node, std::hash_set< Node, NodeHashFunction > > tc_r_graph;
+    MEM_IT mem_it = d_membership_db.find(tc_r_rep);
+
+    if(mem_it != d_membership_db.end()) {
+      for(std::vector<Node>::iterator pair_it = mem_it->second.begin();
+          pair_it != mem_it->second.end(); pair_it++) {
+        Node            fst_rep         = getRepresentative(RelsUtils::nthElementOfTuple(*pair_it, 0));
+        Node            snd_rep         = getRepresentative(RelsUtils::nthElementOfTuple(*pair_it, 1));
+        TC_PAIR_IT      pair_set_it     = tc_graph.find(fst_rep);
+        TC_PAIR_IT      r_pair_set_it   = tc_r_graph.find(fst_rep);
+
+        Trace("rels-tc") << "[sets-rels]        **** Member of r = (" << fst_rep << ", " << snd_rep << ")" << std::endl;
+
+        if( pair_set_it != tc_graph.end() ) {
+          pair_set_it->second.insert(snd_rep);
+          r_pair_set_it->second.insert(snd_rep);
+        } else {
+          std::hash_set< Node, NodeHashFunction > snd_set;
+          snd_set.insert(snd_rep);
+          tc_r_graph[fst_rep] = snd_set;
+          tc_graph[fst_rep] = snd_set;
+        }
+      }
+    }
+
+    Node reason = getReason(tc_rep, tc_term, tc_r_rep, tc_term[0]);
+
+    if(!reason.isNull()) {
+      d_membership_tc_exp_cache[tc_rep] = reason;
+    }
+    d_tc_r_graph[tc_rep] = tc_r_graph;
+
+    TC_PAIR_IT tc_mem_it = d_tc_membership_db.find(tc_term);
+
+    if( tc_mem_it != d_tc_membership_db.end() ) {
+      for(std::hash_set<Node, NodeHashFunction>::iterator pair_it = tc_mem_it->second.begin();
+          pair_it != tc_mem_it->second.end(); pair_it++) {
+        Node            fst_rep         = getRepresentative(RelsUtils::nthElementOfTuple(*pair_it, 0));
+        Node            snd_rep         = getRepresentative(RelsUtils::nthElementOfTuple(*pair_it, 1));
+        TC_PAIR_IT      pair_set_it     = tc_graph.find(fst_rep);
+        Trace("rels-tc") << "[sets-rels]        **** Member of TC(r) = (" << fst_rep << ", " << snd_rep << ")" << std::endl;
+
+        if( pair_set_it != tc_graph.end() ) {
+          pair_set_it->second.insert(snd_rep);
+        } else {
+          std::hash_set< Node, NodeHashFunction > snd_set;
+          snd_set.insert(snd_rep);
+          tc_graph[fst_rep] = snd_set;
+        }
+      }
+    }
+
+    return tc_graph;
+  }
+
+  /*
+   *
+   *
+   * transitive closure rule 1:   y = (TCLOSURE x)
+   *                           ---------------------------------------------
+   *                              y = x | x.x | x.x.x | ... (| is union)
+   *
+   *
+   *
+   * transitive closure rule 2:   TCLOSURE(x)
+   *                            -----------------------------------------------------------
+   *                              x <= TCLOSURE(x) && (x JOIN x) <= TCLOSURE(x) ....
+   *
+   *                              TC(x) = TC(y) => x = y ?
+   *
+   */
+
+  void TheorySetsRels::applyTCRule(Node exp, Node tc_term) {
+    Trace("rels-debug") << "\n[sets-rels] *********** Applying TRANSITIVE CLOSURE rule on  "
+                        << tc_term << " with explanation " << exp << std::endl;
+
+    Node tc_rep         = getRepresentative(tc_term);
+    bool polarity       = exp.getKind() != kind::NOT;
+
+    if( d_rel_nodes.find(tc_rep) == d_rel_nodes.end() ) {
+      d_tc_rep_term[tc_rep] = tc_term;
+      d_rel_nodes.insert(tc_rep);
+    }
+    if(polarity) {
+      TC_PAIR_IT mem_it  = d_tc_membership_db.find(tc_term);
+
+      if( mem_it == d_tc_membership_db.end() ) {
+        std::hash_set<Node, NodeHashFunction> members;
+        members.insert(exp[0]);
+        d_tc_membership_db[tc_term] = members;
+      } else {
+        mem_it->second.insert(exp[0]);
+      }
+    } else {
+      Trace("rels-tc") << "TC non-member = " << exp << std::endl;
+    }
+  }
+
+ /*  product-split rule:  (a, b) IS_IN (X PRODUCT Y)
+  *                     ----------------------------------
+  *                       a IS_IN X  && b IS_IN Y
+  *
+  *  product-compose rule: (a, b) IS_IN X    (c, d) IS_IN Y  NOT (r, s, t, u) IS_IN (X PRODUCT Y)
+  *                        ----------------------------------------------------------------------
+  *                                         (a, b, c, d) IS_IN (X PRODUCT Y)
+  */
+
+  void TheorySetsRels::applyProductRule(Node exp, Node product_term) {
+    Trace("rels-debug") << "\n[sets-rels] *********** Applying PRODUCT rule  " << std::endl;
+
+    if(d_rel_nodes.find(product_term) == d_rel_nodes.end()) {
+      computeMembersForRelofMultArities(product_term);
+      d_rel_nodes.insert(product_term);
+    }
+    bool polarity       = exp.getKind() != kind::NOT;
+    Node atom           = polarity ? exp : exp[0];
+    Node r1_rep         = getRepresentative(product_term[0]);
+    Node r2_rep         = getRepresentative(product_term[1]);
+
+    Trace("rels-debug") << "\n[sets-rels] Apply PRODUCT-SPLIT rule on term: " << product_term
+                        << " with explanation: " << exp << std::endl;
+    std::vector<Node>   r1_element;
+    std::vector<Node>   r2_element;
+    NodeManager         *nm     = NodeManager::currentNM();
+    Datatype            dt      = r1_rep.getType().getSetElementType().getDatatype();
+    unsigned int        i       = 0;
+    unsigned int        s1_len  = r1_rep.getType().getSetElementType().getTupleLength();
+    unsigned int        tup_len = product_term.getType().getSetElementType().getTupleLength();
+
+    r1_element.push_back(Node::fromExpr(dt[0].getConstructor()));
+    for(; i < s1_len; ++i) {
+      r1_element.push_back(RelsUtils::nthElementOfTuple(atom[0], i));
+    }
+
+    dt = r2_rep.getType().getSetElementType().getDatatype();
+    r2_element.push_back(Node::fromExpr(dt[0].getConstructor()));
+    for(; i < tup_len; ++i) {
+      r2_element.push_back(RelsUtils::nthElementOfTuple(atom[0], i));
+    }
+
+    Node fact_1;
+    Node fact_2;
+    Node reason_1       = exp;
+    Node reason_2       = exp;
+    Node t1             = nm->mkNode(kind::APPLY_CONSTRUCTOR, r1_element);
+    Node t1_rep         = getRepresentative(t1);
+    Node t2             = nm->mkNode(kind::APPLY_CONSTRUCTOR, r2_element);
+    Node t2_rep         = getRepresentative(t2);
+
+    fact_1 = NodeManager::currentNM()->mkNode(kind::MEMBER, t1, r1_rep );
+    fact_2 = NodeManager::currentNM()->mkNode(kind::MEMBER, t2, r2_rep );
+    if(r1_rep != product_term[0]) {
+      reason_1 = NodeManager::currentNM()->mkNode(kind::AND,reason_1, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r1_rep, product_term[0])));
+    }
+    if(t1 != t1_rep) {
+      reason_1 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND,reason_1, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1, t1_rep))));
+    }
+    if(r2_rep != product_term[1]) {
+      reason_2 = NodeManager::currentNM()->mkNode(kind::AND,reason_2, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r2_rep, product_term[1])));
+    }
+    if(t2 != t2_rep) {
+      reason_2 = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND,reason_2, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t2, t2_rep))));
+    }
+    if(polarity) {
+      sendInfer(fact_1, reason_1, "product-split");
+      sendInfer(fact_2, reason_2, "product-split");
+    } else {
+      sendInfer(fact_1.negate(), reason_1, "product-split");
+      sendInfer(fact_2.negate(), reason_2, "product-split");
+    }
+  }
+
+  /* join-split rule:           (a, b) IS_IN (X JOIN Y)
+   *                  --------------------------------------------
+   *                  exists z | (a, z) IS_IN X  && (z, b) IS_IN Y
+   *
+   *
+   * join-compose rule: (a, b) IS_IN X    (b, c) IS_IN Y  NOT (t, u) IS_IN (X JOIN Y)
+   *                    -------------------------------------------------------------
+   *                                      (a, c) IS_IN (X JOIN Y)
+   */
+  void TheorySetsRels::applyJoinRule(Node exp, Node join_term) {
+    Trace("rels-debug") << "\n[sets-rels] *********** Applying JOIN rule  " << std::endl;
+
+    if(d_rel_nodes.find(join_term) == d_rel_nodes.end()) {
+      Trace("rels-debug") <<  "\n[sets-rels] Apply JOIN-COMPOSE rule on term: " << join_term
+                          << " with explanation: " << exp << std::endl;
+
+      computeMembersForRelofMultArities(join_term);
+      d_rel_nodes.insert(join_term);
+    }
+
+    bool polarity       = exp.getKind() != kind::NOT;
+    Node atom           = polarity ? exp : exp[0];
+    Node r1_rep         = getRepresentative(join_term[0]);
+    Node r2_rep         = getRepresentative(join_term[1]);
+
+    if(polarity) {
+      Trace("rels-debug") <<  "\n[sets-rels] Apply JOIN-SPLIT rule on term: " << join_term
+                          << " with explanation: " << exp << std::endl;
+
+      std::vector<Node> r1_element;
+      std::vector<Node> r2_element;
+      NodeManager       *nm             = NodeManager::currentNM();
+      TypeNode          shared_type     = r2_rep.getType().getSetElementType().getTupleTypes()[0];
+      Node              shared_x        = nm->mkSkolem("sde_", shared_type);
+      Datatype          dt              = r1_rep.getType().getSetElementType().getDatatype();
+      unsigned int      i               = 0;
+      unsigned int      s1_len          = r1_rep.getType().getSetElementType().getTupleLength();
+      unsigned int      tup_len         = join_term.getType().getSetElementType().getTupleLength();
+
+      r1_element.push_back(Node::fromExpr(dt[0].getConstructor()));
+      for(; i < s1_len-1; ++i) {
+        r1_element.push_back(RelsUtils::nthElementOfTuple(atom[0], i));
+      }
+      r1_element.push_back(shared_x);
+      dt = r2_rep.getType().getSetElementType().getDatatype();
+      r2_element.push_back(Node::fromExpr(dt[0].getConstructor()));
+      r2_element.push_back(shared_x);
+      for(; i < tup_len; ++i) {
+        r2_element.push_back(RelsUtils::nthElementOfTuple(atom[0], i));
+      }
+
+      Node t1 = nm->mkNode(kind::APPLY_CONSTRUCTOR, r1_element);
+      Node t2 = nm->mkNode(kind::APPLY_CONSTRUCTOR, r2_element);
+
+      computeTupleReps(t1);
+      computeTupleReps(t2);
+
+      std::vector<Node> elements = d_membership_trie[r1_rep].findTerms(d_tuple_reps[t1]);
+
+      for(unsigned int j = 0; j < elements.size(); j++) {
+        std::vector<Node> new_tup;
+        new_tup.push_back(elements[j]);
+        new_tup.insert(new_tup.end(), d_tuple_reps[t2].begin()+1, d_tuple_reps[t2].end());
+        if(d_membership_trie[r2_rep].existsTerm(new_tup) != Node::null()) {
+          return;
+        }
+      }
+
+      Node fact;
+      Node reason       = atom[1] == join_term ? exp : NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,atom[1], join_term)));
+      Node reasons      = reason;
+
+      fact = NodeManager::currentNM()->mkNode(kind::MEMBER,t1, r1_rep);
+      if(r1_rep != join_term[0]) {
+        reasons = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r1_rep, join_term[0]))));
+      }
+      Trace("rels-debug") <<  "\n[sets-rels] After applying JOIN-split rule, generate a fact : " << fact
+                                << " with explanation: " << reasons << std::endl;
+      sendInfer(fact, reasons, "join-split");
+      reasons   = reason;
+      fact      = NodeManager::currentNM()->mkNode(kind::MEMBER,t2, r2_rep);
+      if(r2_rep != join_term[1]) {
+        reasons = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r2_rep, join_term[1]))));
+      }
+      Trace("rels-debug") <<  "[sets-rels] After applying JOIN-split rule, generate a fact : " << fact
+                                << " with explanation: " << reasons << std::endl;
+      sendInfer(fact, reasons, "join-split");
+      makeSharedTerm(shared_x);
+    }
+  }
+
+  /*
+   * transpose-occur rule:   [NOT] (a, b) IS_IN X   (TRANSPOSE X) occurs
+   *                         -------------------------------------------------------
+   *                         [NOT] (b, a) IS_IN (TRANSPOSE X)
+   *
+   * transpose-reverse rule:    [NOT] (a, b) IS_IN (TRANSPOSE X)
+   *                         ------------------------------------------------
+   *                            [NOT] (b, a) IS_IN X
+   *
+   * Not implemented yet!
+   * transpose-equal rule:   [NOT]  (TRANSPOSE X) = (TRANSPOSE Y)
+   *                         -----------------------------------------------
+   *                         [NOT]  (X = Y)
+   */
+  void TheorySetsRels::applyTransposeRule(Node exp, Node tp_term, Node more_reason, bool tp_occur) {
+    Trace("rels-debug") << "\n[sets-rels] *********** Applying TRANSPOSE rule  on term " << tp_term << std::endl;
+
+    bool polarity       = exp.getKind() != kind::NOT;
+    Node atom           = polarity ? exp : exp[0];
+    Node reversedTuple  = getRepresentative(RelsUtils::reverseTuple(atom[0]));
+
+    if(tp_occur) {
+      Trace("rels-debug") << "\n[sets-rels] Apply TRANSPOSE-OCCUR rule on term: " << tp_term
+                             << " with explanation: " << exp << std::endl;
+
+      Node fact = polarity ? NodeManager::currentNM()->mkNode(kind::MEMBER,reversedTuple, tp_term) : NodeManager::currentNM()->mkNode(kind::MEMBER,reversedTuple, tp_term).negate();
+      sendInfer(fact, more_reason == Node::null()?exp:NodeManager::currentNM()->mkNode(kind::AND,exp, more_reason), "transpose-occur");
+      return;
+    }
+
+    Node tp_t0_rep      = getRepresentative(tp_term[0]);
+    Node reason         = atom[1] == tp_term ? exp : Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND,exp, NodeManager::currentNM()->mkNode(kind::EQUAL,atom[1], tp_term)));
+    Node fact           = NodeManager::currentNM()->mkNode(kind::MEMBER,reversedTuple, tp_t0_rep);
+
+    if(!polarity) {
+      fact = fact.negate();
+    }
+    sendInfer(fact, reason, "transpose-rule");    
+  }
+
+
+  void TheorySetsRels::finalizeTCInference() {
+    Trace("rels-tc") << "[sets-rels] ****** Finalizing transitive closure inferences!" << std::endl;
+    std::map<Node, Node>::iterator map_it = d_tc_rep_term.begin();
+
+    while( map_it != d_tc_rep_term.end() ) {
+      Trace("rels-tc") << "[sets-rels] Start building the TC graph for " << map_it->first << std::endl;
+
+      std::map< Node, std::hash_set<Node, NodeHashFunction> > d_tc_graph = constructTCGraph(getRepresentative(map_it->second[0]), map_it->first, map_it->second);
+      inferTC(map_it->first, d_tc_graph);
+      map_it++;
+    }
+  }
+
+  void TheorySetsRels::inferTC(Node tc_rep, std::map< Node, std::hash_set< Node, NodeHashFunction > >& tc_graph) {
+    Trace("rels-tc") << "[sets-rels] Infer TC lemma from tc_graph of " << tc_rep << std::endl;
+
+    for(TC_PAIR_IT pair_set_it = tc_graph.begin(); pair_set_it != tc_graph.end(); pair_set_it++) {
+      for(std::hash_set< Node, NodeHashFunction >::iterator set_it = pair_set_it->second.begin();
+          set_it != pair_set_it->second.end(); set_it++) {
+        std::hash_set<Node, NodeHashFunction>   elements;
+        Node    pair    = constructPair(tc_rep, pair_set_it->first, *set_it);
+        Node    exp     = findMemExp(tc_rep, pair);
+
+        if(d_membership_tc_exp_cache.find(tc_rep) != d_membership_tc_exp_cache.end()) {
+          exp = NodeManager::currentNM()->mkNode(kind::AND,d_membership_tc_exp_cache[tc_rep], exp);
+        }
+        Assert(!exp.isNull());
+        elements.insert(pair_set_it->first);
+        inferTC( exp, tc_rep, tc_graph, pair_set_it->first, *set_it, elements );
+      }
+    }
+  }
+
+  void TheorySetsRels::inferTC( Node exp, Node tc_rep, std::map< Node, std::hash_set< Node, NodeHashFunction > >& tc_graph,
+                                Node start_node, Node cur_node, std::hash_set< Node, NodeHashFunction >& traversed ) {
+    Node        pair    = constructPair(tc_rep, start_node, cur_node);
+    MEM_IT      mem_it  = d_membership_db.find(tc_rep);
+
+    if(mem_it != d_membership_db.end()) {
+      if(std::find(mem_it->second.begin(), mem_it->second.end(), pair) == mem_it->second.end()) {
+        Trace("rels-tc") << "[sets-rels] Infered a TC lemma = " << NodeManager::currentNM()->mkNode(kind::MEMBER,pair, tc_rep) << " by Transitivity"
+                         << " with explanation = " << Rewriter::rewrite(exp) << std::endl;
+        sendLemma( NodeManager::currentNM()->mkNode(kind::MEMBER,pair, tc_rep), Rewriter::rewrite(exp), "Transitivity" );
+      }
+    } else {
+      Trace("rels-tc") << "[sets-rels] Infered a TC lemma = " << NodeManager::currentNM()->mkNode(kind::MEMBER,pair, tc_rep) << " by Transitivity"
+                       << " with explanation = " << Rewriter::rewrite(exp) << std::endl;
+      sendLemma( NodeManager::currentNM()->mkNode(kind::MEMBER,pair, tc_rep), Rewriter::rewrite(exp), "Transitivity" );
+    }
+    // check if cur_node has been traversed or not
+    if(traversed.find(cur_node) != traversed.end()) {
+      return;
+    }
+    traversed.insert(cur_node);
+
+    Node        reason  = exp;
+    TC_PAIR_IT  cur_set = tc_graph.find(cur_node);
+
+    if(cur_set != tc_graph.end()) {
+      for(std::hash_set< Node, NodeHashFunction >::iterator set_it = cur_set->second.begin();
+          set_it != cur_set->second.end(); set_it++) {
+        Node new_pair = constructPair( tc_rep, cur_node, *set_it );
+        Assert(!reason.isNull());
+        inferTC( NodeManager::currentNM()->mkNode(kind::AND, findMemExp(tc_rep, new_pair), reason ), tc_rep, tc_graph, start_node, *set_it, traversed );
+      }
+    }
+  }
+
+  // Bottom-up fashion to compute relations with more than 1 arity
+  void TheorySetsRels::computeMembersForRelofMultArities(Node n) {
+    Trace("rels-debug") << "\n[sets-rels] computeJoinOrProductRelations for relation  " << n << std::endl;
+    switch(n[0].getKind()) {
+    case kind::TRANSPOSE:
+    case kind::TCLOSURE:
+      computeMembersForUnaryRel(n[0]);
+      break;
+    case kind::JOIN:
+    case kind::PRODUCT:
+      computeMembersForRelofMultArities(n[0]);
+      break;
+    default:
+      break;
+    }
+
+    switch(n[1].getKind()) {
+    case kind::TRANSPOSE:
+      computeMembersForUnaryRel(n[1]);
+      break;
+    case kind::JOIN:
+    case kind::PRODUCT:
+      computeMembersForRelofMultArities(n[1]);
+      break;
+    default:
+      break;
+    }
+
+    if(d_membership_db.find(getRepresentative(n[0])) == d_membership_db.end() ||
+       d_membership_db.find(getRepresentative(n[1])) == d_membership_db.end())
+          return;
+    composeTupleMemForRel(n);
+  }
+
+  // Bottom-up fashion to compute unary relation
+  void TheorySetsRels::computeMembersForUnaryRel(Node n) {
+    switch(n[0].getKind()) {
+    case kind::TRANSPOSE:
+    case kind::TCLOSURE:
+      computeMembersForUnaryRel(n[0]);
+      break;
+    case kind::JOIN:
+    case kind::PRODUCT:
+      computeMembersForRelofMultArities(n[0]);
+      break;
+    default:
+      break;
+    }
+
+    if(d_membership_db.find(getRepresentative(n[0])) == d_membership_db.end())
+      return;
+
+    Node                n_rep   = getRepresentative(n);
+    Node                n0_rep  = getRepresentative(n[0]);
+    std::vector<Node>   tuples  = d_membership_db[n0_rep];
+    std::vector<Node>   exps    = d_membership_exp_db[n0_rep];
+    Assert(tuples.size() == exps.size());
+    for(unsigned int i = 0; i < tuples.size(); i++) {
+      Node reason       = exps[i][1] == n0_rep ? exps[i] : NodeManager::currentNM()->mkNode(kind::AND,exps[i], NodeManager::currentNM()->mkNode(kind::EQUAL,exps[i][1], n0_rep));
+      if( n.getKind() == kind::TRANSPOSE) {
+        Node rev_tup      = getRepresentative(RelsUtils::reverseTuple(tuples[i]));
+        Node fact         = NodeManager::currentNM()->mkNode(kind::MEMBER,rev_tup, n_rep);
+
+        if(holds(fact)) {
+          Trace("rels-debug") << "[sets-rels] New fact: " << fact << " already holds! Skip..." << std::endl;
+        } else {
+          sendInfer(fact, Rewriter::rewrite(reason), "transpose-rule");
+        }
+      } else if( n.getKind() == kind::TCLOSURE ) {
+
+      }
+    }
+  }
+
+  /*
+   * Explicitly compose the join or product relations of r1 and r2
+   * e.g. If (a, b) in X and (b, c) in Y, (a, c) in (X JOIN Y)
+   *
+   */
+  void TheorySetsRels::composeTupleMemForRel( Node n ) {
+    Node r1             = n[0];
+    Node r2             = n[1];
+    Node r1_rep         = getRepresentative(r1);
+    Node r2_rep         = getRepresentative(r2);
+    NodeManager* nm     = NodeManager::currentNM();
+
+    Trace("rels-debug") << "[sets-rels] start composing tuples in relations "
+                        << r1 << " and " << r2 << std::endl;
+
+    if(d_membership_db.find(r1_rep) == d_membership_db.end() ||
+       d_membership_db.find(r2_rep) == d_membership_db.end())
+    return;
+
+    std::vector<Node> new_tups;
+    std::vector<Node> new_exps;
+    std::vector<Node> r1_elements       = d_membership_db[r1_rep];
+    std::vector<Node> r2_elements       = d_membership_db[r2_rep];
+    std::vector<Node> r1_exps           = d_membership_exp_db[r1_rep];
+    std::vector<Node> r2_exps           = d_membership_exp_db[r2_rep];
+
+    Node n_rep  = getRepresentative(n);
+    unsigned int t1_len = r1_elements.front().getType().getTupleLength();
+    unsigned int t2_len = r2_elements.front().getType().getTupleLength();
+
+    for(unsigned int i = 0; i < r1_elements.size(); i++) {
+      for(unsigned int j = 0; j < r2_elements.size(); j++) {
+        std::vector<Node> composed_tuple;
+        TypeNode          tn            = n.getType().getSetElementType();
+        Node              r1_rmost      = RelsUtils::nthElementOfTuple(r1_elements[i], t1_len-1);
+        Node              r2_lmost      = RelsUtils::nthElementOfTuple(r2_elements[j], 0);
+        composed_tuple.push_back(Node::fromExpr(tn.getDatatype()[0].getConstructor()));
+
+        if((areEqual(r1_rmost, r2_lmost) && n.getKind() == kind::JOIN) ||
+            n.getKind() == kind::PRODUCT) {
+          bool isProduct = n.getKind() == kind::PRODUCT;
+          unsigned int k = 0;
+          unsigned int l = 1;
+
+          for(; k < t1_len - 1; ++k) {
+            composed_tuple.push_back(RelsUtils::nthElementOfTuple(r1_elements[i], k));
+          }
+          if(isProduct) {
+            composed_tuple.push_back(RelsUtils::nthElementOfTuple(r1_elements[i], k));
+            composed_tuple.push_back(RelsUtils::nthElementOfTuple(r2_elements[j], 0));
+          }
+          for(; l < t2_len; ++l) {
+            composed_tuple.push_back(RelsUtils::nthElementOfTuple(r2_elements[j], l));
+          }
+          Node composed_tuple_rep       = getRepresentative(nm->mkNode(kind::APPLY_CONSTRUCTOR, composed_tuple));
+          Node fact                     = NodeManager::currentNM()->mkNode(kind::MEMBER,composed_tuple_rep, n_rep);
+
+          if(holds(fact)) {
+            Trace("rels-debug") << "[sets-rels] New fact: " << fact << " already holds! Skip..." << std::endl;
+          } else {
+            std::vector<Node> reasons;
+            reasons.push_back(explain(r1_exps[i]));
+            reasons.push_back(explain(r2_exps[j]));
+            if(n != n_rep) {
+              reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL, n_rep, n)));
+            }
+            if(r1_exps[i].getKind() == kind::MEMBER && r1_exps[i][0] != r1_elements[i]) {
+              reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r1_elements[i], r1_exps[i][0])));
+            }
+            if(r2_exps[j].getKind() == kind::MEMBER && r2_exps[j][0] != r2_elements[j]) {
+              reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r2_elements[j], r2_exps[j][0])));
+            }
+            if(r1_exps[i].getKind() == kind::MEMBER && r1_exps[i][1] != r1_rep) {
+              reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r1_exps[i][1], r1_rep)));
+            }
+            if(r2_exps[j].getKind() == kind::MEMBER && r2_exps[j][1] != r2_rep) {
+              reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r2_exps[j][1], r2_rep)));
+            }
+
+            if(!isProduct) {
+              if(r1_rmost != r2_lmost) {
+                reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r1_rmost, r2_lmost)));
+              }
+            }
+            if(r1 != r1_rep) {
+              reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r1, r1_rep)));
+            }
+            if(r2 != r2_rep) {
+              reasons.push_back(explain(NodeManager::currentNM()->mkNode(kind::EQUAL,r2, r2_rep)));
+            }
+
+            Node reason = Rewriter::rewrite(nm->mkNode(kind::AND, reasons));
+            if(isProduct) {
+              sendInfer( fact, reason, "product-compose" );
+            } else {
+              sendInfer( fact, reason, "join-compose" );
+            }
+
+            Trace("rels-debug") << "[sets-rels] Compose tuples: " << r1_elements[i]
+                               << " and " << r2_elements[j]
+                               << "\n            Produce a new fact: " << fact
+                               << "\n            Reason: " << reason<< std::endl;
+          }
+        }
+      }
+    }
+    Trace("rels-debug") << "[sets-rels] Done with composing tuples !" << std::endl;
+  }
+
+  void TheorySetsRels::doPendingLemmas() {
+    if( !(*d_conflict) ){
+      if ( (!d_lemma_cache.empty() || !d_pending_facts.empty()) ) {
+        for( unsigned i=0; i < d_lemma_cache.size(); i++ ){
+          Assert(d_lemma_cache[i].getKind() == kind::IMPLIES);
+          if(holds( d_lemma_cache[i][1] )) {
+            Trace("rels-lemma") << "[sets-rels-lemma-skip] Skip an already held lemma: "
+                                << d_lemma_cache[i]<< std::endl;
+            continue;
+          }
+          Trace("rels-lemma") << "[sets-rels-lemma] Send out a lemma : "
+                              << d_lemma_cache[i] << std::endl;
+          d_sets_theory.d_out->lemma( d_lemma_cache[i] );
+        }
+        for( std::map<Node, Node>::iterator child_it = d_pending_facts.begin();
+             child_it != d_pending_facts.end(); child_it++ ) {
+          if(holds(child_it->first)) {
+            Trace("rels-lemma") << "[sets-rels-fact-lemma-skip] Skip an already held fact,: "
+                                << child_it->first << std::endl;
+            continue;
+          }
+          Trace("rels-lemma") << "[sets-rels-fact-lemma] Send out a fact as lemma : "
+                              << child_it->first << " with reason " << child_it->second << std::endl;
+          d_sets_theory.d_out->lemma(NodeManager::currentNM()->mkNode(kind::IMPLIES, child_it->second, child_it->first));
+        }
+      }
+      doTCLemmas();
+    }
+
+    d_arg_rep_tp_terms.clear();
+    d_tc_membership_db.clear();
+    d_rel_nodes.clear();
+    d_pending_facts.clear();
+    d_membership_constraints_cache.clear();
+    d_tc_r_graph.clear();
+    d_membership_tc_exp_cache.clear();
+    d_membership_exp_cache.clear();
+    d_membership_db.clear();
+    d_membership_exp_db.clear();
+    d_terms_cache.clear();
+    d_lemma_cache.clear();
+    d_membership_trie.clear();
+    d_tuple_reps.clear();
+    d_id_node.clear();
+    d_node_id.clear();
+    d_tc_rep_term.clear();
+  }
+
+  void TheorySetsRels::doTCLemmas() {
+    Trace("rels-debug") << "[sets-rels]  Start processing TC lemmas .......... " << std::endl;
+    std::map< Node, std::hash_set< Node, NodeHashFunction > >::iterator mem_it = d_tc_membership_db.begin();
+
+    while(mem_it != d_tc_membership_db.end()) {
+      Node tc_rep       = getRepresentative(mem_it->first);
+      Node tc_r_rep     = getRepresentative(mem_it->first[0]);
+      std::hash_set< Node, NodeHashFunction >::iterator set_it = mem_it->second.begin();
+
+      while(set_it != mem_it->second.end()) {
+        std::hash_set<Node, NodeHashFunction> hasSeen;
+        bool    isReachable     = false;
+        Node    fst             = RelsUtils::nthElementOfTuple(*set_it, 0);
+        Node    snd             = RelsUtils::nthElementOfTuple(*set_it, 1);
+        Node    fst_rep         = getRepresentative(fst);
+        Node    snd_rep         = getRepresentative(snd);
+        TC_IT   tc_graph_it     = d_tc_r_graph.find(tc_rep);
+
+        // the tc_graph of TC(r) is built based on the members of r and TC(r)????????
+        isTCReachable(fst_rep, snd_rep, hasSeen, tc_graph_it->second, isReachable);
+        Trace("rels-tc") << "tuple = " << *set_it << " with rep = (" << fst_rep << ", " << snd_rep << ") "
+                         << " isReachable? = " << isReachable << std::endl;
+        if((tc_graph_it != d_tc_r_graph.end() && !isReachable) ||
+           (tc_graph_it == d_tc_r_graph.end())) {
+          Node reason   = explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*set_it, mem_it->first));
+          Node sk_1     = NodeManager::currentNM()->mkSkolem("sde", fst_rep.getType());
+          Node sk_2     = NodeManager::currentNM()->mkSkolem("sde", snd_rep.getType());
+          Node mem_of_r = NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::constructPair(tc_r_rep, fst_rep, snd_rep), tc_r_rep);
+          Node sk_eq    = NodeManager::currentNM()->mkNode(kind::EQUAL,sk_1, sk_2);
+
+          if(fst_rep != fst) {
+            reason = NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,fst_rep, fst)));
+          }
+          if(snd_rep != snd) {
+            reason = NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,snd_rep, snd)));
+          }
+          if(tc_r_rep != mem_it->first[0]) {
+            reason = NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_r_rep, mem_it->first[0])));
+          }
+          if(tc_rep != mem_it->first) {
+            reason = NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_rep, mem_it->first)));
+          }
+
+          Node tc_lemma = NodeManager::currentNM()->mkNode(kind::IMPLIES, reason,
+                                                           NodeManager::currentNM()->mkNode(kind::OR,mem_of_r,
+                                                              (NodeManager::currentNM()->mkNode(kind::AND,NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::constructPair(tc_r_rep, fst_rep, sk_1), tc_r_rep),
+                                                                   (NodeManager::currentNM()->mkNode(kind::AND,NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::constructPair(tc_r_rep, sk_2, snd_rep), tc_r_rep),
+                                                                        (NodeManager::currentNM()->mkNode(kind::OR,sk_eq, NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::constructPair(tc_rep, sk_1, sk_2), tc_rep)))))))));
+          Trace("rels-lemma") << "[sets-rels-lemma] Send out a TC lemma : "
+                              << tc_lemma << std::endl;
+          d_sets_theory.d_out->lemma(tc_lemma);
+          d_sets_theory.d_out->requirePhase(Rewriter::rewrite(mem_of_r), true);
+          d_sets_theory.d_out->requirePhase(Rewriter::rewrite(sk_eq), true);
+        }
+        set_it++;
+      }
+      mem_it++;
+    }
+  }
+
+  void TheorySetsRels::isTCReachable(Node start, Node dest, std::hash_set<Node, NodeHashFunction>& hasSeen,
+                                      std::map< Node, std::hash_set< Node, NodeHashFunction > >& tc_graph, bool& isReachable) {
+    if(hasSeen.find(start) == hasSeen.end()) {
+      hasSeen.insert(start);
+    }
+
+    TC_PAIR_IT pair_set_it = tc_graph.find(start);
+
+    if(pair_set_it != tc_graph.end()) {
+      if(pair_set_it->second.find(dest) != pair_set_it->second.end()) {
+        isReachable = true;
+        return;
+      } else {
+        std::hash_set< Node, NodeHashFunction >::iterator set_it = pair_set_it->second.begin();
+
+        while(set_it != pair_set_it->second.end()) {
+          // need to check if *set_it has been looked already
+          if(hasSeen.find(*set_it) == hasSeen.end()) {
+            isTCReachable(*set_it, dest, hasSeen, tc_graph, isReachable);
+          }
+          set_it++;
+        }
+      }
+    }
+  }
+
+  void TheorySetsRels::sendLemma(Node conc, Node ant, const char * c) {
+    Node lemma = NodeManager::currentNM()->mkNode(kind::IMPLIES, ant, conc);
+    d_lemma_cache.push_back(lemma);
+    d_lemma.insert(lemma);
+  }
+
+  void TheorySetsRels::sendInfer( Node fact, Node exp, const char * c ) {
+    d_pending_facts[fact] = exp;
+    d_infer.push_back( fact );
+    d_infer_exp.push_back( exp );
+  }
+
+  void TheorySetsRels::assertMembership( Node fact, Node reason, bool polarity ) {
+    d_eqEngine->assertPredicate( fact, polarity, reason );
+  }
+
+  Node TheorySetsRels::getRepresentative( Node t ) {
+    if( d_eqEngine->hasTerm( t ) ){
+      return d_eqEngine->getRepresentative( t );
+    }else{
+      return t;
+    }
+  }
+
+  bool TheorySetsRels::hasTerm( Node a ){
+    return d_eqEngine->hasTerm( a );
+  }
+
+  bool TheorySetsRels::areEqual( Node a, Node b ){
+    Assert(a.getType() == b.getType());
+    Trace("rels-eq") << "[sets-rels]**** checking equality between " << a << " and " << b << std::endl;
+    if(a == b) {
+      return true;
+    } else if( hasTerm( a ) && hasTerm( b ) ){
+      return d_eqEngine->areEqual( a, b );
+    } else if(a.getType().isTuple()) {
+      bool equal = true;
+      for(unsigned int i = 0; i < a.getType().getTupleLength(); i++) {
+        equal = equal && areEqual(RelsUtils::nthElementOfTuple(a, i), RelsUtils::nthElementOfTuple(b, i));
+      }
+      return equal;
+    } else if(!a.getType().isBoolean()){
+      makeSharedTerm(a);
+      makeSharedTerm(b);
+    }
+    return false;
+  }
+
+  /*
+   * Make sure duplicate members are not added in map
+   */
+  bool TheorySetsRels::safelyAddToMap(std::map< Node, std::vector<Node> >& map, Node rel_rep, Node member) {
+    std::map< Node, std::vector< Node > >::iterator mem_it = map.find(rel_rep);
+    if(mem_it == map.end()) {
+      std::vector<Node> members;
+      members.push_back(member);
+      map[rel_rep] = members;
+      return true;
+    } else {
+      std::vector<Node>::iterator mems = mem_it->second.begin();
+      while(mems != mem_it->second.end()) {
+        if(areEqual(*mems, member)) {
+          return false;
+        }
+        mems++;
+      }
+      map[rel_rep].push_back(member);
+      return true;
+    }
+    return false;
+  }
+
+  void TheorySetsRels::addToMap(std::map< Node, std::vector<Node> >& map, Node rel_rep, Node member) {
+    if(map.find(rel_rep) == map.end()) {
+      std::vector<Node> members;
+      members.push_back(member);
+      map[rel_rep] = members;
+    } else {
+      map[rel_rep].push_back(member);
+    }
+  }
+
+  inline Node TheorySetsRels::getReason(Node tc_rep, Node tc_term, Node tc_r_rep, Node tc_r) {
+    if(tc_term != tc_rep) {
+      Node reason = explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_term, tc_rep));
+      if(tc_term[0] != tc_r_rep) {
+        return NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_term[0], tc_r_rep)));
+      }
+    }
+    return Node::null();
+  }
+
+  // tuple might be a member of tc_rep; or it might be a member of rels or tc_terms such that
+  // tc_terms are transitive closure of rels and are modulo equal to tc_rep
+  Node TheorySetsRels::findMemExp(Node tc_rep, Node pair) {
+    Trace("rels-exp") << "TheorySetsRels::findMemExp ( tc_rep = " << tc_rep << ", pair = " << pair << ")" << std::endl;
+    Node                fst             = RelsUtils::nthElementOfTuple(pair, 0);
+    Node                snd             = RelsUtils::nthElementOfTuple(pair, 1);
+    std::vector<Node>   tc_terms        = d_terms_cache.find(tc_rep)->second[kind::TCLOSURE];
+
+    Assert(tc_terms.size() > 0);
+    for(unsigned int i = 0; i < tc_terms.size(); i++) {
+      Node tc_term      = tc_terms[i];
+      Node tc_r_rep     = getRepresentative(tc_term[0]);
+
+      Trace("rels-exp") << "TheorySetsRels::findMemExp ( r_rep = " << tc_r_rep << ", pair = " << pair << ")" << std::endl;
+      std::map< Node, std::vector< Node > >::iterator tc_r_mems = d_membership_db.find(tc_r_rep);
+      if(tc_r_mems != d_membership_db.end()) {
+        for(unsigned int i = 0; i < tc_r_mems->second.size(); i++) {
+          Node fst_mem = RelsUtils::nthElementOfTuple(tc_r_mems->second[i], 0);
+          Node snd_mem = RelsUtils::nthElementOfTuple(tc_r_mems->second[i], 1);
+
+          if(areEqual(fst_mem, fst) && areEqual(snd_mem, snd)) {
+            Node exp = NodeManager::currentNM()->mkNode(kind::MEMBER,tc_r_mems->second[i], tc_r_mems->first);
+
+            if(tc_r_rep != tc_term[0]) {
+              exp = explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_r_rep, tc_term[0]));
+            }
+            if(tc_rep != tc_term) {
+              exp = NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_rep, tc_term)));
+            }
+            if(tc_r_mems->second[i] != pair) {
+              if(fst_mem != fst) {
+                exp = NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,fst_mem, fst)));
+              }
+              if(snd_mem != snd) {
+                exp = NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,snd_mem, snd)));
+              }
+              exp = NodeManager::currentNM()->mkNode(kind::AND,exp, NodeManager::currentNM()->mkNode(kind::EQUAL,tc_r_mems->second[i], pair));
+            }
+            return Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND,exp, explain(d_membership_exp_db[tc_r_rep][i])));
+          }
+        }
+      }
+
+      Node                                              tc_term_rep     = getRepresentative(tc_terms[i]);
+      std::map< Node, std::vector< Node > >::iterator   tc_t_mems       = d_membership_db.find(tc_term_rep);
+
+      if(tc_t_mems != d_membership_db.end()) {
+        for(unsigned int j = 0; j < tc_t_mems->second.size(); j++) {
+          Node fst_mem = RelsUtils::nthElementOfTuple(tc_t_mems->second[j], 0);
+          Node snd_mem = RelsUtils::nthElementOfTuple(tc_t_mems->second[j], 1);
+
+          if(areEqual(fst_mem, fst) && areEqual(snd_mem, snd)) {
+            Node exp = NodeManager::currentNM()->mkNode(kind::MEMBER,tc_t_mems->second[j], tc_t_mems->first);
+            if(tc_rep != tc_terms[i]) {
+              exp = NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_rep, tc_terms[i])));
+            }
+            if(tc_term_rep != tc_terms[i]) {
+              exp = NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_term_rep, tc_terms[i])));
+            }
+            if(tc_t_mems->second[j] != pair) {
+              if(fst_mem != fst) {
+                exp = NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,fst_mem, fst)));
+              }
+              if(snd_mem != snd) {
+                exp = NodeManager::currentNM()->mkNode(kind::AND,exp, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,snd_mem, snd)));
+              }
+              exp = NodeManager::currentNM()->mkNode(kind::AND,exp, NodeManager::currentNM()->mkNode(kind::EQUAL,tc_t_mems->second[j], pair));
+            }
+            return Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::AND,exp, explain(d_membership_exp_db[tc_term_rep][j])));
+          }
+        }
+      }
+    }
+    return Node::null();
+  }
+
+  void TheorySetsRels::addSharedTerm( TNode n ) {
+    Trace("rels-debug") << "[sets-rels] Add a shared term:  " << n << std::endl;
+    d_sets_theory.addSharedTerm(n);
+    d_eqEngine->addTriggerTerm(n, THEORY_SETS);
+  }
+
+  void TheorySetsRels::makeSharedTerm( Node n ) {
+    Trace("rels-share") << " [sets-rels] making shared term " << n << std::endl;
+    if(d_shared_terms.find(n) == d_shared_terms.end()) {
+      Node skolem = NodeManager::currentNM()->mkSkolem( "sts", NodeManager::currentNM()->mkSetType( n.getType() ) );
+      sendLemma(skolem.eqNode(NodeManager::currentNM()->mkNode(kind::SINGLETON,n)), d_trueNode, "share-term");
+      d_shared_terms.insert(n);
+    }
+  }
+
+  bool TheorySetsRels::holds(Node node) {
+    bool polarity       = node.getKind() != kind::NOT;
+    Node atom           = polarity ? node : node[0];
+    return d_sets_theory.isEntailed( atom, polarity );
+  }
+
+  /*
+   * For each tuple n, we store a mapping between n and a list of its elements representatives
+   * in d_tuple_reps. This would later be used for applying JOIN operator.
+   */
+  void TheorySetsRels::computeTupleReps( Node n ) {
+    if( d_tuple_reps.find( n ) == d_tuple_reps.end() ){
+      for( unsigned i = 0; i < n.getType().getTupleLength(); i++ ){
+        d_tuple_reps[n].push_back( getRepresentative( RelsUtils::nthElementOfTuple(n, i) ) );
+      }
+    }
+  }
+
+  inline void TheorySetsRels::addToMembershipDB(Node rel, Node member, Node reasons) {
+    addToMap(d_membership_db, rel, member);
+    addToMap(d_membership_exp_db, rel, reasons);
+    computeTupleReps(member);
+    d_membership_trie[rel].addTerm(member, d_tuple_reps[member]);
+  }
+
+  inline Node TheorySetsRels::constructPair(Node tc_rep, Node a, Node b) {
+    Datatype dt = tc_rep.getType().getSetElementType().getDatatype();
+    return NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, Node::fromExpr(dt[0].getConstructor()), a, b);
+  }
+
+  /*
+   * Node n[0] is a tuple variable, reduce n[0] to a concrete representation,
+   * which is (e1, ..., en) where e1, ... ,en are concrete elements of tuple n[0].
+   */
+  void TheorySetsRels::reduceTupleVar(Node n) {
+    if(d_symbolic_tuples.find(n) == d_symbolic_tuples.end()) {
+      Trace("rels-debug") << "Reduce tuple var: " << n[0] << " to concrete one " << " node = " << n << std::endl;
+      std::vector<Node> tuple_elements;
+      tuple_elements.push_back(Node::fromExpr((n[0].getType().getDatatype())[0].getConstructor()));
+      for(unsigned int i = 0; i < n[0].getType().getTupleLength(); i++) {
+        Node element = RelsUtils::nthElementOfTuple(n[0], i);
+        makeSharedTerm(element);
+        tuple_elements.push_back(element);
+      }
+      Node tuple_reduct = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, tuple_elements);
+      tuple_reduct = NodeManager::currentNM()->mkNode(kind::MEMBER,tuple_reduct, n[1]);
+      Node tuple_reduction_lemma = NodeManager::currentNM()->mkNode(kind::IFF, n, tuple_reduct);
+      sendLemma(tuple_reduction_lemma, d_trueNode, "tuple-reduction");
+      d_symbolic_tuples.insert(n);
+    }
+  }
+
+  TheorySetsRels::TheorySetsRels( context::Context* c,
+                                  context::UserContext* u,
+                                  eq::EqualityEngine* eq,
+                                  context::CDO<bool>* conflict,
+                                  TheorySets& d_set ):
+    d_vec_size(c),
+    d_eqEngine(eq),
+    d_conflict(conflict),
+    d_sets_theory(d_set),
+    d_trueNode(NodeManager::currentNM()->mkConst<bool>(true)),
+    d_falseNode(NodeManager::currentNM()->mkConst<bool>(false)),
+    d_pending_merge(c),
+    d_infer(c),
+    d_infer_exp(c),
+    d_lemma(u),
+    d_shared_terms(u)
+  {
+    d_eqEngine->addFunctionKind(kind::PRODUCT);
+    d_eqEngine->addFunctionKind(kind::JOIN);
+    d_eqEngine->addFunctionKind(kind::TRANSPOSE);
+    d_eqEngine->addFunctionKind(kind::TCLOSURE);
+  }
+
+  TheorySetsRels::~TheorySetsRels() {}
+
+  std::vector<Node> TupleTrie::findTerms( std::vector< Node >& reps, int argIndex ) {
+    std::vector<Node>                           nodes;
+    std::map< Node, TupleTrie >::iterator       it;
+
+    if( argIndex==(int)reps.size()-1 ){
+      if(reps[argIndex].getKind() == kind::SKOLEM) {
+        it = d_data.begin();
+        while(it != d_data.end()) {
+          nodes.push_back(it->first);
+          it++;
+        }
+      }
+      return nodes;
+    }else{
+      it = d_data.find( reps[argIndex] );
+      if( it==d_data.end() ){
+        return nodes;
+      }else{
+        return it->second.findTerms( reps, argIndex+1 );
+      }
+    }
+  }
+
+  Node TupleTrie::existsTerm( std::vector< Node >& reps, int argIndex ) {
+    if( argIndex==(int)reps.size() ){
+      if( d_data.empty() ){        
+        return Node::null();
+      }else{
+        return d_data.begin()->first;
+      }
+    }else{
+      std::map< Node, TupleTrie >::iterator it = d_data.find( reps[argIndex] );
+      if( it==d_data.end() ){
+        return Node::null();
+      }else{
+        return it->second.existsTerm( reps, argIndex+1 );
+      }
+    }
+  }
+
+  bool TupleTrie::addTerm( Node n, std::vector< Node >& reps, int argIndex ){
+    if( argIndex==(int)reps.size() ){
+      if( d_data.empty() ){
+        //store n in d_data (this should be interpretted as the "data" and not as a reference to a child)
+        d_data[n].clear();
+        return true;
+      }else{
+        return false;
+      }
+    }else{
+      return d_data[reps[argIndex]].addTerm( n, reps, argIndex+1 );
+    }
+  }
+
+  void TupleTrie::debugPrint( const char * c, Node n, unsigned depth ) {
+    for( std::map< Node, TupleTrie >::iterator it = d_data.begin(); it != d_data.end(); ++it ){
+      for( unsigned i=0; i<depth; i++ ){ Debug(c) << "  "; }
+      Debug(c) << it->first << std::endl;
+      it->second.debugPrint( c, n, depth+1 );
+    }
+  }
+
+  Node TheorySetsRels::explain( Node literal )
+  {
+    Trace("rels-exp") << "[sets-rels] TheorySetsRels::explain(" << literal << ")"<< std::endl;
+    std::vector<TNode>  assumptions;
+    bool                polarity        = literal.getKind() != kind::NOT;
+    TNode               atom            = polarity ? literal : literal[0];
+
+    if(atom.getKind() == kind::EQUAL || atom.getKind() == kind::IFF) {
+      d_eqEngine->explainEquality(atom[0], atom[1], polarity, assumptions);
+    } else if(atom.getKind() == kind::MEMBER) {
+      if( !d_eqEngine->hasTerm(atom)) {
+        d_eqEngine->addTerm(atom);
+      }
+      d_eqEngine->explainPredicate(atom, polarity, assumptions);
+    } else {
+      Trace("rels-exp") << "unhandled: " << literal << "; (" << atom << ", "
+                    << polarity << "); kind" << atom.getKind() << std::endl;
+      Unhandled();
+    }
+    Trace("rels-exp") << "[sets-rels] ****** done with TheorySetsRels::explain(" << literal << ")"<< std::endl;
+    return mkAnd(assumptions);
+  }
+
+  TheorySetsRels::EqcInfo::EqcInfo( context::Context* c ) :
+  d_mem(c), d_not_mem(c), d_mem_exp(c), d_in(c), d_out(c),
+  d_tp(c), d_pt(c), d_join(c), d_tc(c) {}
+
+  void TheorySetsRels::eqNotifyNewClass( Node n ) {
+    Trace("rels-std") << "[sets-rels] eqNotifyNewClass:" << " t = " << n << std::endl;
+    if(isRel(n) && (n.getKind() == kind::TRANSPOSE || 
+                    n.getKind() == kind::PRODUCT ||
+                    n.getKind() == kind::JOIN ||
+                    n.getKind() == kind::TCLOSURE)) {
+      getOrMakeEqcInfo( n, true );
+    }
+  }
+
+  // Create an integer id for tuple element
+  int TheorySetsRels::getOrMakeElementRepId(EqcInfo* ei, Node e_rep) {
+    Trace("rels-std") << "[sets-rels] getOrMakeElementRepId:" << " e_rep = " << e_rep << std::endl;
+    std::map< Node, int >::iterator nid_it  = d_node_id.find(e_rep);
+
+    if( nid_it == d_node_id.end() ) {
+      if( d_eqEngine->hasTerm(e_rep) ) {
+        // it is possible that e's rep changes at this moment, thus we need to know the previous rep id of eqc of e
+        eq::EqClassIterator rep_eqc_i = eq::EqClassIterator( e_rep, d_eqEngine );
+        while( !rep_eqc_i.isFinished() ) {
+          std::map< Node, int >::iterator id_it = d_node_id.find(*rep_eqc_i);
+
+          if( id_it != d_node_id.end() ) {
+            d_id_node[id_it->second]    = e_rep;
+            d_node_id[e_rep]            = id_it->second;
+            return id_it->second;
+          }
+          rep_eqc_i++;
+        }
+      }
+      d_id_node[ei->counter]    = e_rep;
+      d_node_id[e_rep]          = ei->counter;
+      ei->counter++;
+      return ei->counter-1;
+    }
+    Trace("rels-std") << "[sets-rels] finish getOrMakeElementRepId:" << " e_rep = " << e_rep << std::endl;
+    return nid_it->second;
+  }
+
+  bool TheorySetsRels::insertIntoIdList(IdList& idList, int mem) {
+    IdList::const_iterator      idListIt = idList.begin();
+    while(idListIt != idList.end()) {
+      if(*idListIt == mem) {
+        return false;
+      }
+      idListIt++;
+    }
+    idList.push_back(mem);
+    return true;
+  }
+
+  void TheorySetsRels::addTCMemAndSendInfer( EqcInfo* tc_ei, Node membership, Node exp, bool fromRel ) {
+    Trace("rels-std") << "[sets-rels] addTCMemAndSendInfer:" << " membership = " << membership << " from a relation? " << fromRel<< std::endl;
+
+    Node     fst     = RelsUtils::nthElementOfTuple(membership[0], 0);
+    Node     snd     = RelsUtils::nthElementOfTuple(membership[0], 1);
+    Node     fst_rep = getRepresentative(fst);
+    Node     snd_rep = getRepresentative(snd);
+    Node     mem_rep = RelsUtils::constructPair(membership[1], fst_rep, snd_rep);
+
+    if(tc_ei->d_mem.find(mem_rep) != tc_ei->d_mem.end()) {
+      return;
+    }
+
+    int fst_rep_id = getOrMakeElementRepId( tc_ei, fst_rep );
+    int snd_rep_id = getOrMakeElementRepId( tc_ei, snd_rep );
+
+    std::hash_set<int>       in_reachable;
+    std::hash_set<int>       out_reachable;
+    collectReachableNodes(tc_ei->d_id_inIds, fst_rep_id, in_reachable);
+    collectReachableNodes(tc_ei->d_id_outIds, snd_rep_id, out_reachable);
+
+    // If fst_rep is inserted into in_lst successfully,
+    // save rep pair's exp and send out TC inference lemmas.
+    // Otherwise, mem's rep is already in the TC and return.
+    if( addId(tc_ei->d_id_inIds, snd_rep_id, fst_rep_id) ) {
+      Node reason       = exp == Node::null() ? explain(membership) : exp;
+      if(!fromRel && tc_ei->d_tc.get() != membership[1]) {
+        reason  = NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,tc_ei->d_tc.get(), membership[1])));
+      }
+      if(fst != fst_rep) {
+        reason  = NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,fst, fst_rep)));
+      }
+      if(snd != snd_rep) {
+        reason  = NodeManager::currentNM()->mkNode(kind::AND,reason, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,snd, snd_rep)));
+      }
+      tc_ei->d_mem_exp[mem_rep] = reason;
+      Trace("rels-std") << "Added member " << mem_rep << " for " << tc_ei->d_tc.get()<< " with reason = " << reason << std::endl;
+      tc_ei->d_mem.insert(mem_rep);
+      Trace("rels-std") << "Added in membership arrow for " << snd_rep << " from: " << fst_rep << std::endl;
+    } else {
+      // Nothing inserted into the eqc
+      return;
+    }
+    Trace("rels-std") << "Add out membership arrow for " << fst_rep << " to : " << snd_rep << std::endl;
+    addId(tc_ei->d_id_inIds, fst_rep_id, snd_rep_id);
+    sendTCInference(tc_ei, in_reachable, out_reachable, mem_rep, fst_rep, snd_rep, fst_rep_id, snd_rep_id);
+  }
+
+  Node TheorySetsRels::explainTCMem(EqcInfo* ei, Node pair, Node fst, Node snd) {
+    Trace("rels-tc") << "explainTCMem ############ pair = " << pair << std::endl;
+    if(ei->d_mem_exp.find(pair) != ei->d_mem_exp.end()) {
+      return (*ei->d_mem_exp.find(pair)).second;
+    }
+    NodeMap::iterator   mem_exp_it      = ei->d_mem_exp.begin();
+    while(mem_exp_it != ei->d_mem_exp.end()) {
+      Node      tuple   = (*mem_exp_it).first;
+      Node      fst_e   = RelsUtils::nthElementOfTuple(tuple, 0);
+      Node      snd_e   = RelsUtils::nthElementOfTuple(tuple, 1);
+      if(areEqual(fst, fst_e) && areEqual(snd, snd_e)) {
+        return NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,snd, snd_e)), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,fst, fst_e)), (*mem_exp_it).second));
+      }
+      ++mem_exp_it;
+    }
+    if(!ei->d_tc.get().isNull()) {
+      Node      rel_rep = getRepresentative(ei->d_tc.get()[0]);
+      EqcInfo*  rel_ei  = getOrMakeEqcInfo(rel_rep);
+      if(rel_ei != NULL) {
+        NodeMap::iterator rel_mem_exp_it = rel_ei->d_mem_exp.begin();
+        while(rel_mem_exp_it != rel_ei->d_mem_exp.end()) {
+          Node  exp     = rel_rep == ei->d_tc.get()[0] ? d_trueNode : explain(NodeManager::currentNM()->mkNode(kind::EQUAL,rel_rep, ei->d_tc.get()[0]));
+          Node  tuple   = (*rel_mem_exp_it).first;
+          Node  fst_e   = RelsUtils::nthElementOfTuple(tuple, 0);
+          Node  snd_e   = RelsUtils::nthElementOfTuple(tuple, 1);
+          if(areEqual(fst, fst_e) && areEqual(snd, snd_e)) {
+            return NodeManager::currentNM()->mkNode(kind::AND,exp, NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,snd, snd_e)), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,fst, fst_e)), (*rel_mem_exp_it).second)));
+          }
+          ++rel_mem_exp_it;
+        }
+      }
+    }
+    return Node::null();
+  }
+
+  void TheorySetsRels::sendTCInference(EqcInfo* tc_ei, std::hash_set<int> in_reachable, std::hash_set<int> out_reachable, Node mem_rep, Node fst_rep, Node snd_rep, int id1, int id2) {
+    Trace("rels-std") << "Start making TC inference after adding a member " << mem_rep << " to " << tc_ei->d_tc.get() << std::endl;
+
+    Node exp            = explainTCMem(tc_ei, mem_rep, fst_rep, snd_rep);
+    Assert(!exp.isNull());
+    Node tc_lemma       = NodeManager::currentNM()->mkNode(kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER,mem_rep, tc_ei->d_tc.get()));
+    d_pending_merge.push_back(tc_lemma);
+    d_lemma.insert(tc_lemma);
+    std::hash_set<int>::iterator        in_reachable_it = in_reachable.begin();
+    while(in_reachable_it != in_reachable.end()) {
+      Node    in_node   = d_id_node[*in_reachable_it];
+      Node    in_pair   = RelsUtils::constructPair(tc_ei->d_tc.get(), in_node, fst_rep);
+      Node    new_pair  = RelsUtils::constructPair(tc_ei->d_tc.get(), in_node, snd_rep);
+      Node    tc_exp    = explainTCMem(tc_ei, in_pair, in_node, fst_rep);
+      Node    reason    =  tc_exp.isNull() ? exp : NodeManager::currentNM()->mkNode(kind::AND,tc_exp, exp);
+
+      tc_ei->d_mem_exp[new_pair] = reason;
+      tc_ei->d_mem.insert(new_pair);
+      Node tc_lemma = NodeManager::currentNM()->mkNode(kind::IMPLIES, reason, NodeManager::currentNM()->mkNode(kind::MEMBER,new_pair, tc_ei->d_tc.get()));
+
+      d_pending_merge.push_back(tc_lemma);
+      d_lemma.insert(tc_lemma);
+      in_reachable_it++;
+    }
+
+    std::hash_set<int>::iterator        out_reachable_it = out_reachable.begin();
+    while(out_reachable_it != out_reachable.end()) {
+      Node    out_node        = d_id_node[*out_reachable_it];
+      Node    out_pair        = RelsUtils::constructPair(tc_ei->d_tc.get(), snd_rep, out_node);
+      Node    reason          = explainTCMem(tc_ei, out_pair, snd_rep, out_node);
+      Assert(reason != Node::null());
+
+      std::hash_set<int>::iterator        in_reachable_it = in_reachable.begin();
+
+      while(in_reachable_it != in_reachable.end()) {
+        Node    in_node         = d_id_node[*in_reachable_it];
+        Node    in_pair         = RelsUtils::constructPair(tc_ei->d_tc.get(), in_node, snd_rep);
+        Node    new_pair        = RelsUtils::constructPair(tc_ei->d_tc.get(), in_node, out_node);
+        Node    in_pair_exp     = explainTCMem(tc_ei, in_pair, in_node, snd_rep);
+
+        Assert(in_pair_exp != Node::null());
+        reason  = NodeManager::currentNM()->mkNode(kind::AND,reason, in_pair_exp);
+        tc_ei->d_mem_exp[new_pair] = reason;
+        tc_ei->d_mem.insert(new_pair);
+        Node tc_lemma = NodeManager::currentNM()->mkNode(kind::IMPLIES, reason, NodeManager::currentNM()->mkNode(kind::MEMBER,new_pair, tc_ei->d_tc.get()));
+        d_pending_merge.push_back(tc_lemma);
+        d_lemma.insert(tc_lemma);
+        in_reachable_it++;
+      }
+      out_reachable_it++;
+    }
+  }
+
+  void TheorySetsRels::collectReachableNodes(std::map< int, std::vector< int > >& id_map, int start_id, std::hash_set< int >& reachable_set, bool firstRound) {
+    Trace("rels-std") << "****  Collecting reachable nodes for node with id " << start_id << std::endl;
+    if(reachable_set.find(start_id) != reachable_set.end()) {
+      return;
+    }
+    if(!firstRound) {
+      reachable_set.insert(start_id);
+    }
+
+    std::vector< int > id_list              = getIdList(id_map, start_id);
+    std::vector< int >::iterator id_list_it = id_list.begin();
+
+    while( id_list_it != id_list.end() ) {
+      collectReachableNodes( id_map, *id_list_it, reachable_set, false );
+      id_list_it++;
+    }
+  }
+
+  // Merge t2 into t1, t1 will be the rep of the new eqc
+  void TheorySetsRels::eqNotifyPostMerge( Node t1, Node t2 ) {
+    Trace("rels-std") << "[sets-rels] eqNotifyPostMerge:" << " t1 = " << t1 << " t2 = " << t2 << std::endl;
+
+    // Merge membership constraint with "true" or "false" eqc
+    if( (t1 == d_trueNode || t1 == d_falseNode) && t2.getKind() == kind::MEMBER && t2[0].getType().isTuple() ) {
+
+      Assert(t1 == d_trueNode || t1 == d_falseNode);
+      bool      polarity        = t1 == d_trueNode;
+      Node      t2_1rep         = getRepresentative(t2[1]);
+      EqcInfo*  ei              = getOrMakeEqcInfo( t2_1rep, true );
+
+      if( polarity ) {
+        ei->d_mem.insert(t2[0]);
+        ei->d_mem_exp[t2[0]] = explain(t2);
+      } else {
+        ei->d_not_mem.insert(t2[0]);
+      }
+      // Process a membership constraint that a tuple is a member of transpose of rel
+      if( !ei->d_tp.get().isNull() ) {
+        Node exp = polarity ? explain(t2) : explain(t2.negate());
+        if(ei->d_tp.get() != t2[1]) {
+          exp = NodeManager::currentNM()->mkNode(kind::AND, explain(NodeManager::currentNM()->mkNode(kind::EQUAL, ei->d_tp.get(), t2[1]) ), exp );
+        }
+        sendInferTranspose( polarity, t2[0], ei->d_tp.get(), exp, true );
+      }
+      // Process a membership constraint that a tuple is a member of product of rel
+      if( !ei->d_pt.get().isNull() ) {
+        Node exp = polarity ? explain(t2) : explain(t2.negate());
+        if(ei->d_pt.get() != t2[1]) {
+          exp = NodeManager::currentNM()->mkNode(kind::AND, explain(NodeManager::currentNM()->mkNode(kind::EQUAL, ei->d_pt.get(), t2[1]) ), exp );
+        }
+        sendInferProduct( polarity, t2[0], ei->d_pt.get(), exp );
+      }
+      // Process a membership constraint that a tuple is a member of transitive closure of rel
+      if( polarity && !ei->d_tc.get().isNull() ) {
+        addTCMemAndSendInfer( ei, t2, Node::null() );
+      }
+
+    // Merge two relation eqcs
+    } else if( t1.getType().isSet() && t2.getType().isSet() && t1.getType().getSetElementType().isTuple() ) {
+      mergeTransposeEqcs(t1, t2);
+      mergeProductEqcs(t1, t2);
+      mergeTCEqcs(t1, t2);
+    }
+
+    Trace("rels-std") << "[sets-rels] done with eqNotifyPostMerge:" << " t1 = " << t1 << " t2 = " << t2 << std::endl;
+  }
+
+  void TheorySetsRels::mergeTCEqcs(Node t1, Node t2) {
+    Trace("rels-std") << "[sets-rels] Merge TC eqcs t1 = " << t1 << " and t2 = " << t2 << std::endl;
+
+    EqcInfo* t1_ei = getOrMakeEqcInfo(t1);
+    EqcInfo* t2_ei = getOrMakeEqcInfo(t2);
+
+    if(t1_ei != NULL && t2_ei != NULL) {
+      NodeSet::const_iterator     non_mem_it  = t2_ei->d_not_mem.begin();
+
+      while(non_mem_it != t2_ei->d_not_mem.end()) {
+        t1_ei->d_not_mem.insert(*non_mem_it);
+        non_mem_it++;
+      }
+      if(!t1_ei->d_tc.get().isNull()) {
+        NodeSet::const_iterator     mem_it  = t2_ei->d_mem.begin();
+
+        while(mem_it != t2_ei->d_mem.end()) {
+          addTCMemAndSendInfer(t1_ei, NodeManager::currentNM()->mkNode(kind::MEMBER,*mem_it, t2_ei->d_tc.get()), (*t2_ei->d_mem_exp.find(*mem_it)).second);
+          mem_it++;
+        }
+      } else if(!t2_ei->d_tc.get().isNull()) {
+        t1_ei->d_tc.set(t2_ei->d_tc);
+        NodeSet::const_iterator     t1_mem_it  = t1_ei->d_mem.begin();
+
+        while(t1_mem_it != t1_ei->d_mem.end()) {
+          NodeMap::const_iterator       reason_it       = t1_ei->d_mem_exp.find(*t1_mem_it);
+          Assert(reason_it != t1_ei->d_mem_exp.end());
+          addTCMemAndSendInfer(t1_ei, NodeManager::currentNM()->mkNode(kind::MEMBER,*t1_mem_it, t1_ei->d_tc.get()), (*reason_it).second);
+          t1_mem_it++;
+        }
+
+        NodeSet::const_iterator     t2_mem_it  = t2_ei->d_mem.begin();
+
+        while(t2_mem_it != t2_ei->d_mem.end()) {
+          addTCMemAndSendInfer(t1_ei, NodeManager::currentNM()->mkNode(kind::MEMBER,*t2_mem_it, t2_ei->d_tc.get()), (*t2_ei->d_mem_exp.find(*t2_mem_it)).second);
+          t2_mem_it++;
+        }
+      }
+    }
+    Trace("rels-std") << "[sets-rels] Done with merging TC eqcs t1 = " << t1 << " and t2 = " << t2 << std::endl;
+  }
+
+
+
+
+  void TheorySetsRels::mergeProductEqcs(Node t1, Node t2) {
+    Trace("rels-std") << "[sets-rels] Merge PRODUCT eqcs t1 = " << t1 << " and t2 = " << t2 << std::endl;
+    EqcInfo* t1_ei = getOrMakeEqcInfo(t1);
+    EqcInfo* t2_ei = getOrMakeEqcInfo(t2);
+
+    if(t1_ei != NULL && t2_ei != NULL) {
+      // PT(t1) = PT(t2) -> t1 = t2;
+      if(!t1_ei->d_pt.get().isNull() && !t2_ei->d_pt.get().isNull()) {
+        sendInferProduct( true, t1_ei->d_pt.get(), t2_ei->d_pt.get(), explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1, t2)) );
+      }
+      // Apply Product rule on (non)members of t2 and t1->pt
+      if(!t1_ei->d_pt.get().isNull()) {
+        for(NodeSet::key_iterator itr = t2_ei->d_mem.key_begin(); itr != t2_ei->d_mem.key_end(); itr++) {
+          if(!t1_ei->d_mem.contains(*itr)) {
+            sendInferProduct( true, *itr, t1_ei->d_pt.get(), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1_ei->d_pt.get(), t2)), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t2))) );
+          }
+        }
+        for(NodeSet::key_iterator itr = t2_ei->d_not_mem.key_begin(); itr != t2_ei->d_not_mem.key_end(); itr++) {
+          if(!t1_ei->d_not_mem.contains(*itr)) {
+            sendInferProduct( false, *itr, t1_ei->d_pt.get(), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1_ei->d_pt.get(), t2)), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t2).negate())) );
+          }
+        }
+      } else if(!t2_ei->d_pt.get().isNull()) {
+        t1_ei->d_pt.set(t2_ei->d_pt);
+        for(NodeSet::key_iterator itr = t1_ei->d_mem.key_begin(); itr != t1_ei->d_mem.key_end(); itr++) {
+          if(!t2_ei->d_mem.contains(*itr)) {
+            sendInferProduct( true, *itr, t2_ei->d_pt.get(), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1, t2_ei->d_pt.get())), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t1))) );
+          }
+        }
+        for(NodeSet::key_iterator itr = t1_ei->d_not_mem.key_begin(); itr != t1_ei->d_not_mem.key_end(); itr++) {
+          if(!t2_ei->d_not_mem.contains(*itr)) {
+            sendInferProduct( false, *itr, t2_ei->d_pt.get(), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1, t2_ei->d_pt.get())), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t1).negate())) );
+          }
+        }
+      }
+    // t1 was created already and t2 was not
+    } else if(t1_ei != NULL) {
+      if(t1_ei->d_pt.get().isNull() && t2.getKind() == kind::PRODUCT) {
+        t1_ei->d_pt.set( t2 );
+      }
+    } else if(t2_ei != NULL){
+      t1_ei = getOrMakeEqcInfo(t1, true);
+      if(t1_ei->d_pt.get().isNull() && !t2_ei->d_pt.get().isNull()) {
+        t1_ei->d_pt.set(t2_ei->d_pt);
+        for(NodeSet::key_iterator itr = t2_ei->d_mem.key_begin(); itr != t2_ei->d_mem.key_end(); itr++) {
+          t1_ei->d_mem.insert(*itr);
+          t1_ei->d_mem_exp.insert(*itr, t2_ei->d_mem_exp[*itr]);
+        }
+        for(NodeSet::key_iterator itr = t2_ei->d_not_mem.key_begin(); itr != t2_ei->d_not_mem.key_end(); itr++) {
+          t1_ei->d_not_mem.insert(*itr);
+        }
+      }
+    }
+  }
+
+  void TheorySetsRels::mergeTransposeEqcs( Node t1, Node t2 ) {
+    Trace("rels-std") << "[sets-rels] Merge TRANSPOSE eqcs t1 = " << t1 << " and t2 = " << t2 << std::endl;
+    EqcInfo* t1_ei = getOrMakeEqcInfo( t1 );
+    EqcInfo* t2_ei = getOrMakeEqcInfo( t2 );
+
+    if( t1_ei != NULL && t2_ei != NULL ) {
+      Trace("rels-std") << "[sets-rels] 0 Merge TRANSPOSE eqcs t1 = " << t1 << " and t2 = " << t2 << std::endl;
+      // TP(t1) = TP(t2) -> t1 = t2;
+      if( !t1_ei->d_tp.get().isNull() && !t2_ei->d_tp.get().isNull() ) {
+        sendInferTranspose( true, t1_ei->d_tp.get(), t2_ei->d_tp.get(), explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1, t2)) );
+      }
+      // Apply transpose rule on (non)members of t2 and t1->tp
+      if( !t1_ei->d_tp.get().isNull() ) {
+        for( NodeSet::key_iterator itr = t2_ei->d_mem.key_begin(); itr != t2_ei->d_mem.key_end(); itr++ ) {
+          if( !t1_ei->d_mem.contains( *itr ) ) {
+            sendInferTranspose( true, *itr, t1_ei->d_tp.get(), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1_ei->d_tp.get(), t2)), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t2))) );
+          }
+        }
+        for( NodeSet::key_iterator itr = t2_ei->d_not_mem.key_begin(); itr != t2_ei->d_not_mem.key_end(); itr++ ) {
+          if(!t1_ei->d_not_mem.contains(*itr)) {
+            sendInferTranspose( false, *itr, t1_ei->d_tp.get(), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1_ei->d_tp.get(), t2)), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t2).negate())) );
+          }
+        }
+        // Apply transpose rule on (non)members of t1 and t2->tp
+      } else if( !t2_ei->d_tp.get().isNull() ) {
+        t1_ei->d_tp.set( t2_ei->d_tp );
+        for( NodeSet::key_iterator itr = t1_ei->d_mem.key_begin(); itr != t1_ei->d_mem.key_end(); itr++ ) {
+          if( !t2_ei->d_mem.contains(*itr) ) {
+            sendInferTranspose( true, *itr, t2_ei->d_tp.get(), NodeManager::currentNM()->mkNode(kind::AND,explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1, t2_ei->d_tp.get())), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t1))) );
+          }
+        }
+        for( NodeSet::key_iterator itr = t1_ei->d_not_mem.key_begin(); itr != t1_ei->d_not_mem.key_end(); itr++ ) {
+          if( !t2_ei->d_not_mem.contains(*itr) ) {
+            sendInferTranspose( false, *itr, t2_ei->d_tp.get(), NodeManager::currentNM()->mkNode(kind::AND, explain(NodeManager::currentNM()->mkNode(kind::EQUAL,t1, t2_ei->d_tp.get())), explain(NodeManager::currentNM()->mkNode(kind::MEMBER,*itr, t1).negate()) ) );
+          }
+        }
+      }
+    // t1 was created already and t2 was not
+    } else if(t1_ei != NULL) {
+      if( t1_ei->d_tp.get().isNull() && t2.getKind() == kind::TRANSPOSE ) {
+        t1_ei->d_tp.set( t2 );
+      }
+    } else if( t2_ei != NULL ){
+      t1_ei = getOrMakeEqcInfo( t1, true );
+      if( t1_ei->d_tp.get().isNull() && !t2_ei->d_tp.get().isNull() ) {
+        t1_ei->d_tp.set( t2_ei->d_tp );
+        for( NodeSet::key_iterator itr = t2_ei->d_mem.key_begin(); itr != t2_ei->d_mem.key_end(); itr++ ) {
+          t1_ei->d_mem.insert( *itr );
+          t1_ei->d_mem_exp.insert( *itr, t2_ei->d_mem_exp[*itr] );
+        }
+        for( NodeSet::key_iterator itr = t2_ei->d_not_mem.key_begin(); itr != t2_ei->d_not_mem.key_end(); itr++ ) {
+          t1_ei->d_not_mem.insert( *itr );
+        }
+      }
+    }
+  }
+
+  void TheorySetsRels::doPendingMerge() {
+    for( NodeList::const_iterator itr = d_pending_merge.begin(); itr != d_pending_merge.end(); itr++ ) {
+      Trace("rels-std") << "[sets-rels-lemma] Process pending merge fact : "
+                        << *itr << std::endl;
+      d_sets_theory.d_out->lemma( *itr );
+    }
+  }
+
+  void TheorySetsRels::sendInferTranspose( bool polarity, Node t1, Node t2, Node exp, bool reverseOnly ) {
+    Assert( t2.getKind() == kind::TRANSPOSE );
+    if( polarity && isRel(t1) && isRel(t2) ) {
+      Assert(t1.getKind() == kind::TRANSPOSE);
+      Node n = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::EQUAL,t1[0], t2[0]) );
+      Trace("rels-std") << "[sets-rels-lemma] Generate a lemma by applying transpose rule: "
+                        << n << std::endl;
+      d_pending_merge.push_back( n );
+      d_lemma.insert( n );
+      return;
+    }
+
+    Node n1;
+    if( reverseOnly ) {
+      if( polarity ) {
+        n1 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::reverseTuple(t1), t2[0]) );
+      } else {
+        n1 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::reverseTuple(t1), t2[0]).negate() );
+      }
+    } else {
+      Node n2;
+      if(polarity) {
+        n1 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER,t1, t2) );
+        n2 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::reverseTuple(t1), t2[0]) );
+      } else {
+        n1 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER,t1, t2).negate() );
+        n2 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER,RelsUtils::reverseTuple(t1), t2[0]).negate() );
+      }
+      Trace("rels-std") << "[sets-rels-lemma] Generate a lemma by applying transpose rule: "
+                        << n2 << std::endl;
+      d_pending_merge.push_back(n2);
+      d_lemma.insert(n2);
+    }
+    Trace("rels-std") << "[sets-rels-lemma] Generate a lemma by applying transpose rule: "
+                      << n1 << std::endl;
+    d_pending_merge.push_back(n1);
+    d_lemma.insert(n1);
+
+  }
+
+  void TheorySetsRels::sendInferProduct( bool polarity, Node t1, Node t2, Node exp ) {
+    Assert( t2.getKind() == kind::PRODUCT );
+    if( polarity && isRel(t1) && isRel(t2) ) {
+      //PRODUCT(x) = PRODUCT(y) => x = y;
+      Assert( t1.getKind() == kind::PRODUCT );
+      Node n = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::EQUAL,t1[0], t2[0]) );
+      Trace("rels-std") << "[sets-rels-lemma] Generate a lemma by applying product rule: "
+                        << n << std::endl;
+      d_pending_merge.push_back( n );
+      d_lemma.insert( n );
+      return;
+    }
+
+    std::vector<Node>   r1_element;
+    std::vector<Node>   r2_element;
+    Node                r1      = t2[0];
+    Node                r2      = t2[1];
+    NodeManager         *nm     = NodeManager::currentNM();
+    Datatype            dt      = r1.getType().getSetElementType().getDatatype();
+    unsigned int        i       = 0;
+    unsigned int        s1_len  = r1.getType().getSetElementType().getTupleLength();
+    unsigned int        tup_len = t2.getType().getSetElementType().getTupleLength();
+
+    r1_element.push_back(Node::fromExpr(dt[0].getConstructor()));
+    for( ; i < s1_len; ++i ) {
+      r1_element.push_back( RelsUtils::nthElementOfTuple( t1, i ) );
+    }
+
+    dt = r2.getType().getSetElementType().getDatatype();
+    r2_element.push_back( Node::fromExpr( dt[0].getConstructor() ) );
+    for( ; i < tup_len; ++i ) {
+      r2_element.push_back( RelsUtils::nthElementOfTuple(t1, i) );
+    }
+
+    Node n1;
+    Node n2;
+    Node tuple_1 = getRepresentative( nm->mkNode( kind::APPLY_CONSTRUCTOR, r1_element ) );
+    Node tuple_2 = getRepresentative( nm->mkNode( kind::APPLY_CONSTRUCTOR, r2_element ) );
+
+    if( polarity ) {
+      n1 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER, tuple_1, r1 ) );
+      n2 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER, tuple_2, r2 ) );
+    } else {
+      n1 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER, tuple_1, r1 ).negate() );
+      n2 = NodeManager::currentNM()->mkNode( kind::IMPLIES, exp, NodeManager::currentNM()->mkNode(kind::MEMBER, tuple_2, r2 ).negate() );
+    }
+    Trace("rels-std") << "[sets-rels-lemma] Generate a lemma by applying product-split rule: "
+                      << n1 << std::endl;
+    d_pending_merge.push_back( n1 );
+    d_lemma.insert( n1 );
+    Trace("rels-std") << "[sets-rels-lemma] Generate a lemma by applying product-split rule: "
+                      << n2 << std::endl;
+    d_pending_merge.push_back( n2 );
+    d_lemma.insert( n2 );
+
+  }
+
+  TheorySetsRels::EqcInfo* TheorySetsRels::getOrMakeEqcInfo( Node n, bool doMake ){
+    std::map< Node, EqcInfo* >::iterator eqc_i = d_eqc_info.find( n );
+    if( eqc_i == d_eqc_info.end() ){
+      if( doMake ){
+        EqcInfo* ei;
+        if( eqc_i!=d_eqc_info.end() ){
+          ei = eqc_i->second;
+        }else{
+          ei = new EqcInfo(d_sets_theory.getSatContext());
+          d_eqc_info[n] = ei;
+        }
+        if( n.getKind() == kind::TRANSPOSE ){
+          ei->d_tp = n;
+        } else if( n.getKind() == kind::PRODUCT ) {
+          ei->d_pt = n;
+        } else if( n.getKind() == kind::TCLOSURE ) {
+          ei->d_tc = n;
+        } else if( n.getKind() == kind::JOIN ) {
+          ei->d_join = n;
+        }
+        return ei;
+      }else{
+        return NULL;
+      }
+    }else{
+      return (*eqc_i).second;
+    }
+  }
+
+
+  Node TheorySetsRels::mkAnd( std::vector<TNode>& conjunctions ) {
+    Assert(conjunctions.size() > 0);
+    std::set<TNode> all;
+
+    for (unsigned i = 0; i < conjunctions.size(); ++i) {
+      TNode t = conjunctions[i];
+      if (t.getKind() == kind::AND) {
+        for(TNode::iterator child_it = t.begin();
+            child_it != t.end(); ++child_it) {
+          Assert((*child_it).getKind() != kind::AND);
+          all.insert(*child_it);
+        }
+      }
+      else {
+        all.insert(t);
+      }
+    }
+    Assert(all.size() > 0);
+    if (all.size() == 1) {
+      // All the same, or just one
+      return conjunctions[0];
+    }
+
+    NodeBuilder<> conjunction(kind::AND);
+    std::set<TNode>::const_iterator it = all.begin();
+    std::set<TNode>::const_iterator it_end = all.end();
+    while (it != it_end) {
+      conjunction << *it;
+      ++ it;
+    }
+
+    return conjunction;
+  }/* mkAnd() */
+
+  void TheorySetsRels::printNodeMap(char* fst, char* snd, NodeMap map) {
+    NodeMap::iterator map_it    = map.begin();
+    while(map_it != map.end()) {
+      Trace("rels-debug") << fst << " "<< (*map_it).first << " " << snd << " " << (*map_it).second<< std::endl;
+      map_it++;
+    }
+  }
+
+  bool TheorySetsRels::addId( std::map< int, std::vector< int > >& id_map, int key, int id ) {
+    int n_data = d_vec_size[key];
+    int len    = n_data < (int)id_map[key].size() ? n_data : id_map[key].size();
+
+    for( int i = 0; i < len; i++ ) {
+      if( id_map[key][i] == id) {
+        return false;
+      }
+    }
+    if( n_data < (int)id_map[key].size() ) {
+      id_map[key][n_data] = id;
+    } else {
+      id_map[key].push_back( id );
+    }
+    d_vec_size[key] = n_data+1;
+    return true;
+  }
+
+  std::vector< int > TheorySetsRels::getIdList( std::map< int, std::vector< int > >& id_map, int key ) {
+    std::vector< int > id_list;
+    int n_data = d_vec_size[key];
+    int len    = n_data < (int)id_map[key].size() ? n_data : id_map[key].size();
+
+    for( int i = 0; i < len; i++ ) {
+      id_list.push_back(id_map[key][i]);
+    }
+    return id_list;
+  }
+
+}
+}
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/theory/sets/theory_sets_rels.h b/src/theory/sets/theory_sets_rels.h
new file mode 100644 (file)
index 0000000..e5c0ad1
--- /dev/null
@@ -0,0 +1,260 @@
+/*********************                                                        */
+/*! \file theory_sets_rels.h
+ ** \verbatim
+ ** Original author: Paul Meng
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014  New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief Sets theory implementation.
+ **
+ ** Extension to Sets theory.
+ **/
+
+#ifndef SRC_THEORY_SETS_THEORY_SETS_RELS_H_
+#define SRC_THEORY_SETS_THEORY_SETS_RELS_H_
+
+#include "theory/theory.h"
+#include "theory/uf/equality_engine.h"
+#include "context/cdhashset.h"
+#include "context/cdchunk_list.h"
+#include "theory/sets/rels_utils.h"
+
+namespace CVC4 {
+namespace theory {
+namespace sets {
+
+class TheorySets;
+
+
+class TupleTrie {
+public:
+  /** the data */
+  std::map< Node, TupleTrie > d_data;
+public:
+  std::vector<Node> findTerms( std::vector< Node >& reps, int argIndex = 0 );
+  Node existsTerm( std::vector< Node >& reps, int argIndex = 0 );
+  bool addTerm( Node n, std::vector< Node >& reps, int argIndex = 0 );
+  void debugPrint( const char * c, Node n, unsigned depth = 0 );
+  void clear() { d_data.clear(); }
+};/* class TupleTrie */
+
+class TheorySetsRels {
+
+  typedef context::CDChunkList< Node >                            NodeList;
+  typedef context::CDChunkList< int >                             IdList;
+  typedef context::CDHashMap< int, IdList* >                      IdListMap;
+  typedef context::CDHashSet< Node, NodeHashFunction >            NodeSet;
+  typedef context::CDHashMap< Node, bool, NodeHashFunction >      NodeBoolMap;
+  typedef context::CDHashMap< Node, NodeList*, NodeHashFunction > NodeListMap;
+  typedef context::CDHashMap< Node, NodeSet*, NodeHashFunction >  NodeSetMap;
+  typedef context::CDHashMap< Node, Node, NodeHashFunction >      NodeMap;
+
+public:
+  TheorySetsRels(context::Context* c,
+                 context::UserContext* u,
+                 eq::EqualityEngine*,
+                 context::CDO<bool>*,
+                 TheorySets&);
+
+  ~TheorySetsRels();
+  void check(Theory::Effort);
+  void doPendingLemmas();
+
+private:
+  /** equivalence class info
+   * d_mem tuples that are members of this equivalence class
+   * d_not_mem tuples that are not members of this equivalence class
+   * d_tp is a node of kind TRANSPOSE (if any) in this equivalence class,
+   * d_pt is a node of kind PRODUCT (if any) in this equivalence class,
+   * d_join is a node of kind JOIN (if any) in this equivalence class,
+   * d_tc is a node of kind TCLOSURE (if any) in this equivalence class,
+   */
+  class EqcInfo
+  {
+  public:
+    EqcInfo( context::Context* c );
+    ~EqcInfo(){}
+    static int                  counter;
+    NodeSet                     d_mem;
+    NodeSet                     d_not_mem;
+    NodeMap                     d_mem_exp;
+    NodeListMap                 d_in;
+    NodeListMap                 d_out;
+    context::CDO< Node >        d_tp;
+    context::CDO< Node >        d_pt;
+    context::CDO< Node >        d_join;
+    context::CDO< Node >        d_tc;
+    /** mapping from an element rep id to a list of rep ids that pointed by */
+    /** Context dependent map Int -> IntList */
+    std::map< int, std::vector< int > > d_id_inIds;
+    /** mapping from an element rep id to a list of rep ids that point to */
+    /** Context dependent map Int -> IntList */
+    std::map< int, std::vector< int > > d_id_outIds;
+  };
+
+private:
+  /** Context */
+  context::CDHashMap< int, int > d_vec_size;
+
+  /** Mapping between integer id and tuple element rep */
+  std::map< int, Node >      d_id_node;
+
+  /** Mapping between tuple element rep and integer id*/
+  std::map< Node, int >      d_node_id;
+
+  /** has eqc info */
+  bool hasEqcInfo( TNode n ) { return d_eqc_info.find( n )!=d_eqc_info.end(); }
+
+  bool addId( std::map< int, std::vector< int > >& id_map, int key, int id );
+  std::vector< int > getIdList( std::map< int, std::vector< int > >& id_map, int key );
+
+  void collectReachableNodes( std::map< int, std::vector< int > >&, int, std::hash_set<int>& , bool first_round = true);
+
+
+private:
+  eq::EqualityEngine            *d_eqEngine;
+  context::CDO<bool>            *d_conflict;
+  TheorySets&                   d_sets_theory;
+
+  /** True and false constant nodes */
+  Node                          d_trueNode;
+  Node                          d_falseNode;
+
+  /** Facts and lemmas to be sent to EE */
+  std::map< Node, Node >        d_pending_facts;
+  std::map< Node, Node >        d_pending_split_facts;
+  std::vector< Node >           d_lemma_cache;
+  NodeList                      d_pending_merge;
+
+  /** inferences: maintained to ensure ref count for internally introduced nodes */
+  NodeList                      d_infer;
+  NodeList                      d_infer_exp;
+  NodeSet                       d_lemma;
+  NodeSet                       d_shared_terms;
+
+  /** Relations that have been applied JOIN, PRODUCT, TC composition rules */
+  std::hash_set< Node, NodeHashFunction >       d_rel_nodes;
+  std::map< Node, std::vector<Node> >           d_tuple_reps;
+  std::map< Node, TupleTrie >                   d_membership_trie;
+
+  /** Symbolic tuple variables that has been reduced to concrete ones */
+  std::hash_set< Node, NodeHashFunction >       d_symbolic_tuples;
+
+  /** Mapping between relation and its (non)members representatives */
+  std::map< Node, std::vector<Node> >           d_membership_constraints_cache;
+
+  /** Mapping between relation and its (non)members' explanation */
+  std::map< Node, std::vector<Node> >           d_membership_exp_cache;
+
+  /** Mapping between relation and its member representatives */
+  std::map< Node, std::vector<Node> >           d_membership_db;
+
+  /** Mapping between relation and its members' explanation */
+  std::map< Node, std::vector<Node> >           d_membership_exp_db;
+
+  /** Mapping between a relation representative and its equivalent relations involving relational operators */
+  std::map< Node, std::map<kind::Kind_t, std::vector<Node> > >                  d_terms_cache;
+
+  /** Mapping between relation and its member representatives */
+  std::map< Node, std::vector<Node> >           d_arg_rep_tp_terms;
+
+  /** Mapping between TC(r) and one explanation when building TC graph*/
+  std::map< Node, Node >                                                        d_membership_tc_exp_cache;
+
+  /** Mapping between transitive closure relation TC(r) (is not necessary a representative) and members directly asserted members */
+  std::map< Node, std::hash_set<Node, NodeHashFunction> >                       d_tc_membership_db;
+
+  /** Mapping between transitive closure relation TC(r) and its TC graph constructed based on the members of r*/
+  std::map< Node, std::map< Node, std::hash_set<Node, NodeHashFunction> > >     d_tc_r_graph;
+
+  /** Mapping between transitive closure TC(r)'s representative and TC(r) */
+  std::map< Node, Node > d_tc_rep_term;
+  std::map< Node, EqcInfo* > d_eqc_info;
+
+public:
+  void eqNotifyNewClass(Node t);
+  void eqNotifyPostMerge(Node t1, Node t2);
+
+private:
+
+  void doPendingMerge();
+  Node findTCMemExp(EqcInfo*, Node);
+  void buildTCAndExp(Node, EqcInfo*);
+  void mergeTCEqcs(Node t1, Node t2);
+  void mergeTCEqcExp(EqcInfo*, EqcInfo*);
+  void mergeProductEqcs(Node t1, Node t2);
+  int getOrMakeElementRepId(EqcInfo*, Node);
+  void mergeTransposeEqcs(Node t1, Node t2);
+  Node explainTCMem(EqcInfo*, Node, Node, Node);
+  void sendInferProduct(bool, Node, Node, Node);
+  EqcInfo* getOrMakeEqcInfo( Node n, bool doMake = false );
+  void sendInferTranspose(bool, Node, Node, Node, bool reverseOnly = false);
+  void addTCMemAndSendInfer(EqcInfo* tc_ei, Node mem, Node exp, bool fromRel = false);
+  void sendTCInference(EqcInfo* tc_ei, std::hash_set<int> in_reachable, std::hash_set<int> out_reachable, Node mem_rep, Node fst_rep, Node snd_rep, int id1, int id2);
+
+
+
+  void check();
+  Node explain(Node);
+  void collectRelsInfo();
+  void applyTCRule( Node, Node );
+  void applyJoinRule( Node, Node );
+  void applyProductRule( Node, Node );
+  void composeTupleMemForRel( Node );
+  void assertMembership( Node fact, Node reason, bool polarity );
+  void applyTransposeRule( Node, Node, Node more_reason = Node::null(), bool tp_occur_rule = false );
+
+
+
+  void computeMembersForRelofMultArities( Node );
+  void computeMembersForUnaryRel( Node );
+  void finalizeTCInference();
+  void inferTC( Node, std::map< Node, std::hash_set< Node, NodeHashFunction > >& );
+  void inferTC( Node, Node, std::map< Node, std::hash_set< Node, NodeHashFunction > >&,
+                Node, Node, std::hash_set< Node, NodeHashFunction >&);
+  void isTCReachable(Node fst, Node snd, std::hash_set<Node, NodeHashFunction>& hasSeen,
+                      std::map< Node, std::hash_set< Node, NodeHashFunction > >& tc_graph, bool&);
+  std::map< Node, std::hash_set< Node, NodeHashFunction > > constructTCGraph( Node, Node, Node );
+
+
+  void doTCLemmas();
+  void addSharedTerm( TNode n );
+  void sendInfer( Node fact, Node exp, const char * c );
+  void sendLemma( Node fact, Node reason, const char * c );
+
+  // Helper functions
+  bool holds( Node );
+  bool hasTerm( Node a );
+  void makeSharedTerm( Node );
+  void reduceTupleVar( Node );
+  bool hasMember( Node, Node );
+  void computeTupleReps( Node );
+  bool areEqual( Node a, Node b );
+  Node getRepresentative( Node t );
+  Node findMemExp(Node r, Node pair);
+  bool insertIntoIdList(IdList&, int);
+  bool exists( std::vector<Node>&, Node );
+  Node mkAnd( std::vector< TNode >& assumptions );
+  inline void addToMembershipDB( Node, Node, Node  );
+  void printNodeMap(char* fst, char* snd, NodeMap map);
+  inline Node constructPair(Node tc_rep, Node a, Node b);
+  void addToMap( std::map< Node, std::vector<Node> >&, Node, Node );
+  bool safelyAddToMap( std::map< Node, std::vector<Node> >&, Node, Node );
+  inline Node getReason(Node tc_rep, Node tc_term, Node tc_r_rep, Node tc_r);
+  bool isRel( Node n ) {return n.getType().isSet() && n.getType().getSetElementType().isTuple();}
+
+
+};
+
+
+}/* CVC4::theory::sets namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+
+
+#endif /* SRC_THEORY_SETS_THEORY_SETS_RELS_H_ */
index 8dbca1e7369a51aad702fb534d20bd960816a363..d21e3fd67e953b05dddca3860a8a8a49284abc0e 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "theory/sets/theory_sets_rewriter.h"
 #include "theory/sets/normal_form.h"
+#include "theory/sets/rels_utils.h"
 #include "expr/attribute.h"
 #include "options/sets_options.h"
 
@@ -158,6 +159,20 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
       TNode S = preRewrite(node[1]).node;
       bool isMember = checkConstantMembership(node[0], S);
       return RewriteResponse(REWRITE_DONE, nm->mkConst(isMember));
+    }else if( node[1].getKind()==kind::EMPTYSET ){
+      return RewriteResponse(REWRITE_DONE, nm->mkConst(false));
+    }else if( node[1].getKind()==kind::SINGLETON ){
+      return RewriteResponse(REWRITE_AGAIN_FULL, nm->mkNode(kind::EQUAL, node[0], node[1][0] ) );
+    }else if( node[1].getKind()==kind::UNION || node[1].getKind()==kind::INTERSECTION || node[1].getKind()==kind::SETMINUS ){
+      std::vector< Node > children;
+      for( unsigned i=0; i<node[1].getNumChildren(); i++ ){
+        Node nc = nm->mkNode(kind::MEMBER, node[0], node[1][i] );
+        if( node[1].getKind()==kind::SETMINUS && i==1 ){
+          nc = nc.negate();
+        }
+        children.push_back( nc );
+      }
+      return RewriteResponse(REWRITE_AGAIN_FULL, nm->mkNode( node[1].getKind()==kind::UNION ? kind::OR : kind::AND, children ) );
     }
     break;
   }//kind::MEMBER
@@ -198,92 +213,69 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
   }//kind::IFF
 
   case kind::SETMINUS: {
-    if( options::setsAggRewrite() ){
-      Node newNode = rewriteSet( node );
-      if( newNode!=node ){
-        return RewriteResponse(REWRITE_DONE, newNode);
-      }
-    }else{
-      if(node[0] == node[1]) {
-        Node newNode = nm->mkConst(EmptySet(nm->toType(node[0].getType())));
-        Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
-        return RewriteResponse(REWRITE_DONE, newNode);
-      } else if(node[0].getKind() == kind::EMPTYSET ||
-                node[1].getKind() == kind::EMPTYSET) {
-        Trace("sets-postrewrite") << "Sets::postRewrite returning " << node[0] << std::endl;
-        return RewriteResponse(REWRITE_DONE, node[0]);
-      } else if(node[0].isConst() && node[1].isConst()) {
-        std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
-        std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
-        std::set<Node> newSet;
-        std::set_difference(left.begin(), left.end(), right.begin(), right.end(),
-          std::inserter(newSet, newSet.begin()));
-        Node newNode = NormalForm::elementsToSet(newSet, node.getType());
-        Assert(newNode.isConst());
-        Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
-        return RewriteResponse(REWRITE_DONE, newNode);
-      }
+    if(node[0] == node[1]) {
+      Node newNode = nm->mkConst(EmptySet(nm->toType(node[0].getType())));
+      Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
+      return RewriteResponse(REWRITE_DONE, newNode);
+    } else if(node[0].getKind() == kind::EMPTYSET ||
+              node[1].getKind() == kind::EMPTYSET) {
+      Trace("sets-postrewrite") << "Sets::postRewrite returning " << node[0] << std::endl;
+      return RewriteResponse(REWRITE_DONE, node[0]);
+    } else if(node[0].isConst() && node[1].isConst()) {
+      std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
+      std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
+      std::set<Node> newSet;
+      std::set_difference(left.begin(), left.end(), right.begin(), right.end(),
+        std::inserter(newSet, newSet.begin()));
+      Node newNode = NormalForm::elementsToSet(newSet, node.getType());
+      Assert(newNode.isConst());
+      Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
+      return RewriteResponse(REWRITE_DONE, newNode);
     }
     break;
   }//kind::SETMINUS
 
   case kind::INTERSECTION: {
-    if( options::setsAggRewrite() ){
-      Node newNode = rewriteSet( node );
-      if( newNode!=node ){
-        return RewriteResponse(REWRITE_DONE, newNode);
-      }
-    // }else{
-    //   Node emptySet = nm->mkConst(EmptySet(nm->toType(node[0].getType())));
-    //   if(node[0].isConst() && node[1].isConst()) {
-    //     std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
-    //     std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
-    //     std::set<Node> newSet;
-    //     std::set_intersection(left.begin(), left.end(), right.begin(), right.end(),
-    //             std::inserter(newSet, newSet.begin()));
-    //     Node newNode = NormalForm::elementsToSet(newSet, node.getType());
-    //     Assert(newNode.isConst());
-    //     Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
-    //     return RewriteResponse(REWRITE_DONE, newNode);
-    //   } else {
-    //     return flattenNode(node, /* trivialNode = */ emptySet, /* skipNode = */ Node());
-    //   }
-    // }
-    }else{
-      if(node[0] == node[1]) {
-        Trace("sets-postrewrite") << "Sets::postRewrite returning " << node[0] << std::endl;
-        return RewriteResponse(REWRITE_DONE, node[0]);
-      } else if(node[0].getKind() == kind::EMPTYSET) {
-        return RewriteResponse(REWRITE_DONE, node[0]);
-      } else if(node[1].getKind() == kind::EMPTYSET) {
-        return RewriteResponse(REWRITE_DONE, node[1]);
-      } else if(node[0].isConst() && node[1].isConst()) {
-        std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
-        std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
-        std::set<Node> newSet;
-        std::set_intersection(left.begin(), left.end(), right.begin(), right.end(),
-                              std::inserter(newSet, newSet.begin()));
-        Node newNode = NormalForm::elementsToSet(newSet, node.getType());
-        Assert(newNode.isConst());
-        Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
-        return RewriteResponse(REWRITE_DONE, newNode);
-      } else if (node[0] > node[1]) {
-        Node newNode = nm->mkNode(node.getKind(), node[1], node[0]);
-        Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
-        return RewriteResponse(REWRITE_DONE, newNode);
+    if(node[0] == node[1]) {
+      Trace("sets-postrewrite") << "Sets::postRewrite returning " << node[0] << std::endl;
+      return RewriteResponse(REWRITE_DONE, node[0]);
+    } else if(node[0].getKind() == kind::EMPTYSET) {
+      return RewriteResponse(REWRITE_DONE, node[0]);
+    } else if(node[1].getKind() == kind::EMPTYSET) {
+      return RewriteResponse(REWRITE_DONE, node[1]);
+    } else if(node[0].isConst() && node[1].isConst()) {
+      std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
+      std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
+      std::set<Node> newSet;
+      std::set_intersection(left.begin(), left.end(), right.begin(), right.end(),
+                            std::inserter(newSet, newSet.begin()));
+      Node newNode = NormalForm::elementsToSet(newSet, node.getType());
+      Assert(newNode.isConst());
+      Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
+      return RewriteResponse(REWRITE_DONE, newNode);
+    } else {
+      std::vector< Node > els;
+      NormalForm::getElementsFromBop( kind::INTERSECTION, node, els );
+      std::sort( els.begin(), els.end() );
+      Node rew = NormalForm::mkBop( kind::INTERSECTION, els, node.getType() );
+      if( rew!=node ){
+        Trace("sets-rewrite") << "Sets::rewrite " << node << " -> " << rew << std::endl;
       }
+      return RewriteResponse(REWRITE_DONE, rew);
+    }
+    /*
+    } else if (node[0] > node[1]) {
+      Node newNode = nm->mkNode(node.getKind(), node[1], node[0]);
+      Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
+      return RewriteResponse(REWRITE_DONE, newNode);
     }
+    */
     break;
   }//kind::INTERSECION
 
   case kind::UNION: {
     // NOTE: case where it is CONST is taken care of at the top
-    if( options::setsAggRewrite() ){
-      Node newNode = rewriteSet( node );
-      if( newNode!=node ){
-        return RewriteResponse(REWRITE_DONE, newNode);
-      }
-    }else if(node[0] == node[1]) {
+    if(node[0] == node[1]) {
       Trace("sets-postrewrite") << "Sets::postRewrite returning " << node[0] << std::endl;
       return RewriteResponse(REWRITE_DONE, node[0]);
     } else if(node[0].getKind() == kind::EMPTYSET) {
@@ -300,10 +292,15 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
       Assert(newNode.isConst());
       Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
       return RewriteResponse(REWRITE_DONE, newNode);
-    }else if (node[0] > node[1]) {
-      Node newNode = nm->mkNode(node.getKind(), node[1], node[0]);
-      Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
-      return RewriteResponse(REWRITE_DONE, newNode);
+    } else {
+      std::vector< Node > els;
+      NormalForm::getElementsFromBop( kind::UNION, node, els );
+      std::sort( els.begin(), els.end() );
+      Node rew = NormalForm::mkBop( kind::UNION, els, node.getType() );
+      if( rew!=node ){
+        Trace("sets-rewrite") << "Sets::rewrite " << node << " -> " << rew << std::endl;
+      }
+      return RewriteResponse(REWRITE_DONE, rew);
     }
     break;
   }//kind::UNION
@@ -312,9 +309,160 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
     if(node[0].isConst()) {
       std::set<Node> elements = NormalForm::getElementsFromNormalConstant(node[0]);
       return RewriteResponse(REWRITE_DONE, nm->mkConst(Rational(elements.size())));
+    }else if( node[0].getKind()==kind::SINGLETON ){
+      return RewriteResponse(REWRITE_DONE, nm->mkConst(Rational(1)));
+    }else if( node[0].getKind()==kind::UNION ){
+      Node ret = NodeManager::currentNM()->mkNode( kind::MINUS,
+                   NodeManager::currentNM()->mkNode( kind::PLUS, NodeManager::currentNM()->mkNode( kind::CARD, node[0][0] ), 
+                                                                 NodeManager::currentNM()->mkNode( kind::CARD, node[0][1] ) ),
+                   NodeManager::currentNM()->mkNode( kind::CARD, NodeManager::currentNM()->mkNode( kind::INTERSECTION, node[0][0], node[0][1] ) ) );                                      
+      return RewriteResponse(REWRITE_DONE, ret );
+    }else if( node[0].getKind()==kind::SETMINUS ){
+      Node ret = NodeManager::currentNM()->mkNode( kind::MINUS,
+                   NodeManager::currentNM()->mkNode( kind::CARD, node[0][0] ),
+                   NodeManager::currentNM()->mkNode( kind::CARD, NodeManager::currentNM()->mkNode( kind::INTERSECTION, node[0][0], node[0][1] ) ) );                                      
+      return RewriteResponse(REWRITE_DONE, ret );
+    }
+  }
+  case kind::TRANSPOSE: {
+    if(node[0].getKind() == kind::TRANSPOSE) {
+      return RewriteResponse(REWRITE_AGAIN, node[0][0]);
+    }
+
+    if(node[0].getKind() == kind::EMPTYSET) {
+      return RewriteResponse(REWRITE_DONE, nm->mkConst(EmptySet(nm->toType(node.getType()))));
+    } else if(node[0].isConst()) {
+      std::set<Node> new_tuple_set;
+      std::set<Node> tuple_set = NormalForm::getElementsFromNormalConstant(node[0]);
+      std::set<Node>::iterator tuple_it = tuple_set.begin();
+
+      while(tuple_it != tuple_set.end()) {
+        new_tuple_set.insert(RelsUtils::reverseTuple(*tuple_it));
+        tuple_it++;
+      }
+      Node new_node = NormalForm::elementsToSet(new_tuple_set, node.getType());
+      Assert(new_node.isConst());
+      Trace("sets-postrewrite") << "Sets::postRewrite returning " << new_node << std::endl;
+      return RewriteResponse(REWRITE_DONE, new_node);
+
+    }
+    if(node[0].getKind() != kind::TRANSPOSE) {
+      Trace("sets-postrewrite") << "Sets::postRewrite returning " << node << std::endl;
+      return RewriteResponse(REWRITE_DONE, node);
+    }
+    break;
+  }
+
+  case kind::PRODUCT: {
+    Trace("sets-rels-postrewrite") << "Sets::postRewrite processing " <<  node << std::endl;
+    if( node[0].getKind() == kind::EMPTYSET ||
+        node[1].getKind() == kind::EMPTYSET) {
+      return RewriteResponse(REWRITE_DONE, nm->mkConst(EmptySet(nm->toType(node.getType()))));
+    } else if( node[0].isConst() && node[1].isConst() ) {
+      Trace("sets-rels-postrewrite") << "Sets::postRewrite processing **** " <<  node << std::endl;
+      std::set<Node> new_tuple_set;
+      std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
+      std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
+      std::set<Node>::iterator left_it = left.begin();
+      int left_len = (*left_it).getType().getTupleLength();
+      TypeNode tn = node.getType().getSetElementType();
+      while(left_it != left.end()) {
+        Trace("rels-debug") << "Sets::postRewrite processing left_it = " <<  *left_it << std::endl;
+        std::vector<Node> left_tuple;
+        left_tuple.push_back(Node::fromExpr(tn.getDatatype()[0].getConstructor()));
+        for(int i = 0; i < left_len; i++) {
+          left_tuple.push_back(RelsUtils::nthElementOfTuple(*left_it,i));
+        }
+        std::set<Node>::iterator right_it = right.begin();
+        int right_len = (*right_it).getType().getTupleLength();
+        while(right_it != right.end()) {
+          Trace("rels-debug") << "Sets::postRewrite processing left_it = " <<  *right_it << std::endl;
+          std::vector<Node> right_tuple;
+          for(int j = 0; j < right_len; j++) {
+            right_tuple.push_back(RelsUtils::nthElementOfTuple(*right_it,j));
+          }
+          std::vector<Node> new_tuple;
+          new_tuple.insert(new_tuple.end(), left_tuple.begin(), left_tuple.end());
+          new_tuple.insert(new_tuple.end(), right_tuple.begin(), right_tuple.end());
+          Node composed_tuple = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, new_tuple);
+          new_tuple_set.insert(composed_tuple);
+          right_it++;
+        }
+        left_it++;
+      }
+      Node new_node = NormalForm::elementsToSet(new_tuple_set, node.getType());
+      Assert(new_node.isConst());
+      Trace("sets-postrewrite") << "Sets::postRewrite returning " << new_node << std::endl;
+      return RewriteResponse(REWRITE_DONE, new_node);
+    }
+    break;
+  }
+
+  case kind::JOIN: {
+    if( node[0].getKind() == kind::EMPTYSET ||
+        node[1].getKind() == kind::EMPTYSET) {
+      return RewriteResponse(REWRITE_DONE, nm->mkConst(EmptySet(nm->toType(node.getType()))));
+    } else if( node[0].isConst() && node[1].isConst() ) {
+      Trace("sets-rels-postrewrite") << "Sets::postRewrite processing " <<  node << std::endl;
+      std::set<Node> new_tuple_set;
+      std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
+      std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
+      std::set<Node>::iterator left_it = left.begin();
+      int left_len = (*left_it).getType().getTupleLength();
+      TypeNode tn = node.getType().getSetElementType();
+      while(left_it != left.end()) {
+        std::vector<Node> left_tuple;
+        left_tuple.push_back(Node::fromExpr(tn.getDatatype()[0].getConstructor()));
+        for(int i = 0; i < left_len - 1; i++) {
+          left_tuple.push_back(RelsUtils::nthElementOfTuple(*left_it,i));
+        }
+        std::set<Node>::iterator right_it = right.begin();
+        int right_len = (*right_it).getType().getTupleLength();
+        while(right_it != right.end()) {
+          if(RelsUtils::nthElementOfTuple(*left_it,left_len-1) == RelsUtils::nthElementOfTuple(*right_it,0)) {
+            std::vector<Node> right_tuple;
+            for(int j = 1; j < right_len; j++) {
+              right_tuple.push_back(RelsUtils::nthElementOfTuple(*right_it,j));
+            }
+            std::vector<Node> new_tuple;
+            new_tuple.insert(new_tuple.end(), left_tuple.begin(), left_tuple.end());
+            new_tuple.insert(new_tuple.end(), right_tuple.begin(), right_tuple.end());
+            Node composed_tuple = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, new_tuple);
+            new_tuple_set.insert(composed_tuple);
+          }
+          right_it++;
+        }
+        left_it++;
+      }
+      Node new_node = NormalForm::elementsToSet(new_tuple_set, node.getType());
+      Assert(new_node.isConst());
+      Trace("sets-postrewrite") << "Sets::postRewrite returning " << new_node << std::endl;
+      return RewriteResponse(REWRITE_DONE, new_node);
     }
+
+    break;
   }
 
+  case kind::TCLOSURE: {
+    if(node[0].getKind() == kind::EMPTYSET) {
+      return RewriteResponse(REWRITE_DONE, nm->mkConst(EmptySet(nm->toType(node.getType()))));
+    } else if (node[0].isConst()) {
+      std::set<Node> rel_mems = NormalForm::getElementsFromNormalConstant(node[0]);
+      std::set<Node> tc_rel_mems = RelsUtils::computeTC(rel_mems, node);
+      Node new_node = NormalForm::elementsToSet(tc_rel_mems, node.getType());
+      Assert(new_node.isConst());
+      Trace("sets-postrewrite") << "Sets::postRewrite returning " << new_node << std::endl;
+      return RewriteResponse(REWRITE_DONE, new_node);
+      
+    } else if(node[0].getKind() == kind::TCLOSURE) {
+      return RewriteResponse(REWRITE_AGAIN, node[0]);
+    } else if(node[0].getKind() != kind::TCLOSURE) {
+      Trace("sets-postrewrite") << "Sets::postRewrite returning " << node << std::endl;
+      return RewriteResponse(REWRITE_DONE, node);
+    }
+    break;
+  }
+  
   default:
     break;
   }//switch(node.getKind())
@@ -363,180 +511,6 @@ RewriteResponse TheorySetsRewriter::preRewrite(TNode node) {
   return RewriteResponse(REWRITE_DONE, node);
 }
 
-Node TheorySetsRewriter::rewriteSet( Node s ) {
-  Trace("sets-rewrite-debug") << "Rewrite set : " << s << std::endl;
-  Node empSet = NodeManager::currentNM()->mkConst(EmptySet(NodeManager::currentNM()->toType(s.getType())));
-  bool success;
-  do{
-    success = false;
-    std::map< Node, bool > ca;
-    Node ss = rewriteSet( s, ca, empSet );
-    if( ss!=s ){
-      Assert( !ss.isNull() );
-      Trace("sets-rewrite") << "Rewrite set : " << s << std::endl;
-      Trace("sets-rewrite") << "........got : " << ss << std::endl;
-      success = true;
-      s = ss;
-    }
-  }while( success );
-  return s;
-}
-
-Node TheorySetsRewriter::rewriteSet( Node s, std::map< Node, bool >& ca, Node empSet ) {
-  if( s.getKind()!=kind::UNION && s.getKind()!=kind::INTERSECTION && s.getKind()!=kind::SETMINUS ){
-    std::map< Node, bool >::iterator it = ca.find( s );
-    if( it==ca.end() ){
-      return s;
-    }else if( it->second ){
-      return Node::null();
-    }else{
-      return empSet;
-    }
-  }else{
-    Trace("sets-rewrite-debug") << "Get components : " << s << std::endl;
-    std::map< Node, bool > c;
-    bool pol = s.getKind()!=kind::UNION;
-    if( pol ){
-      //copy current components
-      for( std::map< Node, bool >::iterator it = ca.begin(); it != ca.end(); ++it ){
-        c[it->first] = it->second;
-      }
-    }
-    if( collectSetComponents( s, c, pol ) ){
-      if( Trace.isOn("sets-rewrite-debug") ){
-        Trace("sets-rewrite-debug") << "  got components : " << std::endl;
-        for( std::map< Node, bool >::iterator it = c.begin(); it != c.end(); ++it ){
-          Trace("sets-rewrite-debug") << "    " << it->first << " -> " << it->second << std::endl;
-        }
-      }
-      
-      //simplify components based on what is asserted in ca, recursively
-      std::map< Node, bool > nc;
-      if( pol ){
-        //copy map
-        for( std::map< Node, bool >::iterator it = c.begin(); it != c.end(); ++it ){
-          nc[it->first] = it->second;
-        }
-        //rewrite each new component based on current assertions
-        for( std::map< Node, bool >::iterator it = c.begin(); it != c.end(); ++it ){
-          if( ca.find( it->first )==ca.end() ){
-            nc.erase( it->first );
-            Node prev = it->first;
-            //only rewrite positive components here
-            Node ss = it->second ? rewriteSet( it->first, nc, empSet ) : it->first;
-            if( prev!=ss ){
-              Trace("sets-rewrite-debug") << "  simplify component : " << prev << "..." << ss << std::endl;
-            }
-            if( ss==empSet ){
-              Trace("sets-rewrite-debug") << "  return singularity " << ss << std::endl;
-              return ss;
-            }else if( !ss.isNull() ){
-              std::map< Node, bool >::iterator itc = nc.find( ss );
-              if( itc==nc.end() ){
-                nc[ss] = it->second;
-              }else if( it->second!=itc->second ){
-                Trace("sets-rewrite-debug") << "...conflict, return empty set." << std::endl;
-                return empSet;
-              }
-            }
-          }
-        }
-      }else{
-        for( std::map< Node, bool >::iterator it = c.begin(); it != c.end(); ++it ){
-          Node prev = it->first;
-          Node ss = rewriteSet( it->first, ca, empSet );
-          if( prev!=ss ){
-            Trace("sets-rewrite-debug") << "  simplify component : " << prev << "..." << ss << std::endl;
-          }
-          if( ss.isNull() ){
-            Trace("sets-rewrite-debug") << "  return singularity " << ss << std::endl;
-            return ss;
-          }else if( ss!=empSet ){
-            std::map< Node, bool >::iterator itc = nc.find( ss );
-            if( itc==nc.end() ){
-              nc[ss] = it->second;
-            }else if( it->second!=itc->second ){
-                Trace("sets-rewrite-debug") << "...conflict, return complete set." << std::endl;
-              return Node::null();
-            }
-          }
-        }
-      }
-
-      
-      //construct sorted lists of positive, negative components
-      std::vector< Node > comp[2];
-      for( std::map< Node, bool >::iterator it = nc.begin(); it != nc.end(); ++it ){
-        if( !pol || ca.find( it->first )==ca.end() ){
-          comp[ ( it->second==pol ) ? 0 : 1 ].push_back( it->first );
-        }
-      }
-      //construct normalized set
-      Node curr;
-      for( unsigned i=0; i<2; i++ ){
-        if( comp[i].size()>1 ){
-          std::sort( comp[i].begin(), comp[i].end() );
-        }
-        if( i==0 ){
-          if( comp[i].empty() ){
-            Trace("sets-rewrite-debug") << "...return trivial set (no components)." << std::endl;
-            if( pol ){
-              return Node::null();
-            }else{
-              return empSet;
-            }
-          }else{
-            curr = comp[i][0];
-            for( unsigned j=1; j<comp[i].size(); j++ ){
-              curr = NodeManager::currentNM()->mkNode( pol ? kind::INTERSECTION : kind::UNION, curr, comp[i][j] );
-            }
-          }
-        }else if( i==1 ){
-          if( !comp[i].empty() ){
-            Assert( pol );
-            Node rem = comp[i][0];
-            for( unsigned j=1; j<comp[i].size(); j++ ){
-              rem = NodeManager::currentNM()->mkNode( kind::UNION, rem, comp[i][j] );
-            }
-            curr = NodeManager::currentNM()->mkNode( kind::SETMINUS, curr, rem );
-          }
-        }
-      }
-      Trace("sets-rewrite-debug") << "...return " << curr << std::endl;
-      return curr;
-    }else{
-      if( pol ){
-        Trace("sets-rewrite-debug") << "...return empty set." << std::endl;
-        return NodeManager::currentNM()->mkConst(EmptySet(NodeManager::currentNM()->toType(s.getType())));
-      }else{
-        Trace("sets-rewrite-debug") << "...return complete set." << std::endl;
-        return Node::null();
-      }
-    }
-  }
-}
-
-bool TheorySetsRewriter::collectSetComponents( Node n, std::map< Node, bool >& c, bool pol ) {
-  std::map< Node, bool >::iterator itc = c.find( n );
-  if( itc!=c.end() ){
-    if( itc->second!=pol ){
-      return false;
-    }
-  }else{
-    if( ( pol && ( n.getKind()==kind::INTERSECTION || n.getKind()==kind::SETMINUS ) ) || ( !pol && n.getKind()==kind::UNION ) ){
-      for( unsigned i=0; i<n.getNumChildren(); i++ ){
-        bool newPol = ( i==1 && n.getKind()==kind::SETMINUS ) ? !pol : pol;
-        if( !collectSetComponents( n[i], c, newPol ) ){
-          return false;
-        }
-      }
-    }else{
-      c[n] = pol;
-    }
-  }
-  return true;
-}
-
 }/* CVC4::theory::sets namespace */
 }/* CVC4::theory namespace */
 }/* CVC4 namespace */
index 97c89520aa0dc3bce9d91aa67a5d36c771c7f9fb..50128b63d59daa601841e1400beadd2cc3a09a4c 100644 (file)
@@ -26,10 +26,6 @@ namespace theory {
 namespace sets {
 
 class TheorySetsRewriter {
-private:
-  static bool collectSetComponents( Node n, std::map< Node, bool >& c, bool pol );
-  static Node rewriteSet( Node s, std::map< Node, bool >& ca, Node empSet );
-  static Node rewriteSet( Node s );
 public:
 
   /**
index 7a8d7eed4168e865db517a8975c42736c1f7e04c..89d481746cc4557c11ee4e67fd5c50dc471c8012 100644 (file)
@@ -105,7 +105,7 @@ struct MemberTypeRule {
         throw TypeCheckingExceptionPrivate(n, "checking for membership in a non-set");
       }
       TypeNode elementType = n[0].getType(check);
-      if(elementType != setType.getSetElementType()) {
+      if(!setType.getSetElementType().isSubtypeOf(elementType)) {
         throw TypeCheckingExceptionPrivate(n, "member operating on sets of different types");
       }
     }
@@ -183,6 +183,97 @@ struct InsertTypeRule {
   }
 };/* struct InsertTypeRule */
 
+struct RelBinaryOperatorTypeRule {
+  inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+    throw (TypeCheckingExceptionPrivate, AssertionException) {
+    Assert(n.getKind() == kind::PRODUCT ||
+           n.getKind() == kind::JOIN);
+
+    TypeNode firstRelType = n[0].getType(check);
+    TypeNode secondRelType = n[1].getType(check);
+    TypeNode resultType = firstRelType;
+
+    if(!firstRelType.isSet() || !secondRelType.isSet()) {
+      throw TypeCheckingExceptionPrivate(n, " set operator operates on non-sets");
+    }
+    if(!firstRelType[0].isTuple() || !secondRelType[0].isTuple()) {
+      throw TypeCheckingExceptionPrivate(n, " set operator operates on non-relations (sets of tuples)");
+    }
+
+    std::vector<TypeNode> newTupleTypes;
+    std::vector<TypeNode> firstTupleTypes = firstRelType[0].getTupleTypes();
+    std::vector<TypeNode> secondTupleTypes = secondRelType[0].getTupleTypes();
+
+    // JOIN is not allowed to apply on two unary sets
+    if( n.getKind() == kind::JOIN ) {
+      if((firstTupleTypes.size() == 1) && (secondTupleTypes.size() == 1)) {
+        throw TypeCheckingExceptionPrivate(n, " Join operates on two unary relations");
+      } else if(firstTupleTypes.back() != secondTupleTypes.front()) {
+        throw TypeCheckingExceptionPrivate(n, " Join operates on two non-joinable relations");
+      }
+      newTupleTypes.insert(newTupleTypes.end(), firstTupleTypes.begin(), firstTupleTypes.end()-1);
+      newTupleTypes.insert(newTupleTypes.end(), secondTupleTypes.begin()+1, secondTupleTypes.end());
+    }else if( n.getKind() == kind::PRODUCT ) {
+      newTupleTypes.insert(newTupleTypes.end(), firstTupleTypes.begin(), firstTupleTypes.end());
+      newTupleTypes.insert(newTupleTypes.end(), secondTupleTypes.begin(), secondTupleTypes.end());
+    }
+    resultType = nodeManager->mkSetType(nodeManager->mkTupleType(newTupleTypes));
+
+    return resultType;
+  }
+
+  inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
+    Assert(n.getKind() == kind::JOIN ||
+           n.getKind() == kind::PRODUCT);
+    return false;
+  }
+};/* struct RelBinaryOperatorTypeRule */
+
+struct RelTransposeTypeRule {
+  inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+    throw (TypeCheckingExceptionPrivate, AssertionException) {
+    Assert(n.getKind() == kind::TRANSPOSE);
+    TypeNode setType = n[0].getType(check);
+    if(check && !setType.isSet() && !setType.getSetElementType().isTuple()) {
+        throw TypeCheckingExceptionPrivate(n, "relation transpose operats on non-relation");
+    }
+    std::vector<TypeNode> tupleTypes = setType[0].getTupleTypes();
+    std::reverse(tupleTypes.begin(), tupleTypes.end());
+    return nodeManager->mkSetType(nodeManager->mkTupleType(tupleTypes));
+  }
+
+  inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
+      return false;
+    }
+};/* struct RelTransposeTypeRule */
+
+struct RelTransClosureTypeRule {
+  inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+    throw (TypeCheckingExceptionPrivate, AssertionException) {
+    Assert(n.getKind() == kind::TCLOSURE);
+    TypeNode setType = n[0].getType(check);
+    if(check) {
+      if(!setType.isSet() && !setType.getSetElementType().isTuple()) {
+        throw TypeCheckingExceptionPrivate(n, " transitive closure operates on non-relation");
+      }
+      std::vector<TypeNode> tupleTypes = setType[0].getTupleTypes();
+      if(tupleTypes.size() != 2) {
+        throw TypeCheckingExceptionPrivate(n, " transitive closure operates on non-binary relations");
+      }
+      if(tupleTypes[0] != tupleTypes[1]) {
+        throw TypeCheckingExceptionPrivate(n, " transitive closure operates on non-homogeneous binary relations");
+      }
+    }
+    return setType;
+  }
+
+  inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
+      Assert(n.getKind() == kind::TCLOSURE);
+      return false;
+    }
+};/* struct RelTransClosureTypeRule */
+
+
 struct SetsProperties {
   inline static Cardinality computeCardinality(TypeNode type) {
     Assert(type.getKind() == kind::SET_TYPE);
index 931228f41eae880343010a33e4a313ec92cdec33..a71cbfe601eedd017e9c78f81c98834e544af832 100644 (file)
@@ -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 \
index c790165ef49a118bd21220b627840bdc5ab36e5a..ec09c9a4a490ee5c1d443bde9606b75076de3972 100644 (file)
@@ -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 (file)
index 0000000..bd7dc87
--- /dev/null
@@ -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 (file)
index 0000000..6b8fdfe
--- /dev/null
@@ -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 (file)
index 0000000..5b1ecef
--- /dev/null
@@ -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 (file)
index 0000000..34176f2
--- /dev/null
@@ -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 (file)
index 0000000..3273ade
--- /dev/null
@@ -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 (file)
index 0000000..970ebdc
--- /dev/null
@@ -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 (file)
index 0000000..50a5bb4
--- /dev/null
@@ -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 (file)
index 0000000..95e7419
--- /dev/null
@@ -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 (file)
index 0000000..5eceb21
--- /dev/null
@@ -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 (file)
index 0000000..130ccae
--- /dev/null
@@ -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 (file)
index 0000000..d7162de
--- /dev/null
@@ -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 (file)
index 0000000..1fc1f2f
--- /dev/null
@@ -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 (file)
index 0000000..177410b
--- /dev/null
@@ -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 (file)
index 0000000..e27d381
--- /dev/null
@@ -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 (file)
index 0000000..e27d381
--- /dev/null
@@ -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 (file)
index 0000000..0202cbb
--- /dev/null
@@ -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 (file)
index 0000000..4bc498a
--- /dev/null
@@ -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 (file)
index 0000000..f39c234
--- /dev/null
@@ -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 (file)
index 0000000..96ef2ff
--- /dev/null
@@ -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 (file)
index 0000000..b9341a2
--- /dev/null
@@ -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 (file)
index 0000000..50d4def
--- /dev/null
@@ -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 (file)
index 0000000..dcb7539
--- /dev/null
@@ -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 (file)
index 0000000..969d0d7
--- /dev/null
@@ -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 (file)
index 0000000..492c944
--- /dev/null
@@ -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 (file)
index 0000000..f473b00
--- /dev/null
@@ -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 (file)
index 0000000..d648171
--- /dev/null
@@ -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 (file)
index 0000000..c1b8233
--- /dev/null
@@ -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 (file)
index 0000000..406b8d3
--- /dev/null
@@ -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 (file)
index 0000000..a7fa7ef
--- /dev/null
@@ -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 (file)
index 0000000..c8921af
--- /dev/null
@@ -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 (file)
index 0000000..75fc083
--- /dev/null
@@ -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 (file)
index 0000000..cac7ce8
--- /dev/null
@@ -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 (file)
index 0000000..3e27b9c
--- /dev/null
@@ -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 (file)
index 0000000..6e190ce
--- /dev/null
@@ -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 (file)
index 0000000..dedc4ae
--- /dev/null
@@ -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 (file)
index 0000000..030810f
--- /dev/null
@@ -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 (file)
index 0000000..5209d81
--- /dev/null
@@ -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 (file)
index 0000000..1731887
--- /dev/null
@@ -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 (file)
index 0000000..fff5b6e
--- /dev/null
@@ -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 (file)
index 0000000..723a9b2
--- /dev/null
@@ -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 (file)
index 0000000..6cdf036
--- /dev/null
@@ -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 (file)
index 0000000..09981be
--- /dev/null
@@ -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 (file)
index 0000000..f141c7b
--- /dev/null
@@ -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 (file)
index 0000000..1826e5a
--- /dev/null
@@ -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 (file)
index 0000000..2d79cbc
--- /dev/null
@@ -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 (file)
index 0000000..08ed324
--- /dev/null
@@ -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 (file)
index 0000000..df2d7f4
--- /dev/null
@@ -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 (file)
index 0000000..082604d
--- /dev/null
@@ -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 (file)
index 0000000..da0906d
--- /dev/null
@@ -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 (file)
index 0000000..67c4440
--- /dev/null
@@ -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 (file)
index 0000000..7edeb0e
--- /dev/null
@@ -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 (file)
index 0000000..d5d42ea
--- /dev/null
@@ -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 (file)
index 0000000..39564c4
--- /dev/null
@@ -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 (file)
index 0000000..7f55356
--- /dev/null
@@ -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 (file)
index 0000000..decd38f
--- /dev/null
@@ -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 (file)
index 0000000..8ee75f7
--- /dev/null
@@ -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 (file)
index 0000000..fd9caea
--- /dev/null
@@ -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 (file)
index 0000000..4570c5a
--- /dev/null
@@ -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 (file)
index 0000000..15c0510
--- /dev/null
@@ -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 (file)
index 0000000..9f5879c
--- /dev/null
@@ -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 (file)
index 0000000..f884349
--- /dev/null
@@ -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 (file)
index 0000000..441e79c
--- /dev/null
@@ -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 (file)
index 0000000..46806b4
--- /dev/null
@@ -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 (file)
index 0000000..a03f0e3
--- /dev/null
@@ -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 (file)
index 0000000..60b6edf
--- /dev/null
@@ -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 (file)
index 0000000..cc851f6
--- /dev/null
@@ -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 (file)
index 0000000..acf3dbc
--- /dev/null
@@ -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 (file)
index 0000000..25277f4
--- /dev/null
@@ -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 (file)
index 0000000..54e16dd
--- /dev/null
@@ -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 (file)
index 0000000..8d149a4
--- /dev/null
@@ -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 (file)
index 0000000..b05026b
--- /dev/null
@@ -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 (file)
index 0000000..aacf6c0
--- /dev/null
@@ -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 (file)
index 0000000..49fb875
--- /dev/null
@@ -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 (file)
index 0000000..bdcf31b
--- /dev/null
@@ -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 (file)
index 0000000..fa6ee50
--- /dev/null
@@ -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 (file)
index 0000000..5dfe3b0
--- /dev/null
@@ -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 (file)
index 0000000..b260147
--- /dev/null
@@ -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 (file)
index 0000000..203e8b3
--- /dev/null
@@ -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 (file)
index 0000000..a2e8bcf
--- /dev/null
@@ -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 (file)
index 0000000..bcc3bab
--- /dev/null
@@ -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 (file)
index 0000000..0dee0e8
--- /dev/null
@@ -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 (file)
index 0000000..b91ddbb
--- /dev/null
@@ -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 (file)
index 0000000..b91ddbb
--- /dev/null
@@ -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;