Add support for set comprehension (#3312)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Fri, 13 Dec 2019 15:53:02 +0000 (09:53 -0600)
committerGitHub <noreply@github.com>
Fri, 13 Dec 2019 15:53:02 +0000 (09:53 -0600)
19 files changed:
src/expr/node.h
src/parser/parser.h
src/parser/smt2/Smt2.g
src/printer/smt2/smt2_printer.cpp
src/theory/sets/kinds
src/theory/sets/solver_state.cpp
src/theory/sets/solver_state.h
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_type_rules.h
test/regress/CMakeLists.txt
test/regress/regress0/sets/comp-qf-error.smt2 [new file with mode: 0644]
test/regress/regress1/sets/comp-intersect.smt2 [new file with mode: 0644]
test/regress/regress1/sets/comp-odd.smt2 [new file with mode: 0644]
test/regress/regress1/sets/comp-pos-member.smt2 [new file with mode: 0644]
test/regress/regress1/sets/comp-positive.smt2 [new file with mode: 0644]
test/regress/regress1/sets/set-comp-sat.smt2 [new file with mode: 0644]

index cd3c99a78cfc932b46688166879ee2bc672bc3c3..d02cbcefd09bd0aeb953cf64c61a1be13fd1f0bb 100644 (file)
@@ -469,6 +469,7 @@ public:
     assertTNodeNotExpired();
     return getKind() == kind::LAMBDA || getKind() == kind::FORALL
            || getKind() == kind::EXISTS || getKind() == kind::CHOICE
+           || getKind() == kind::COMPREHENSION
            || getKind() == kind::MATCH_BIND_CASE;
   }
 
index 42badf4c5ed1cef6ace4ab3ec10c8954a1a582e4..642b81fb07c4ea1e33b0acf5ab7689b7f63d285b 100644 (file)
@@ -739,6 +739,14 @@ public:
    */
   inline size_t scopeLevel() const { return d_symtab->getLevel(); }
 
+  /**
+   * Pushes a scope. All subsequent symbol declarations made are only valid in
+   * this scope, i.e. they are deleted on the next call to popScope.
+   *
+   * The argument bindingLevel is true, the assertion level is set to the
+   * current scope level. This determines which scope assertions are declared
+   * at.
+   */
   inline void pushScope(bool bindingLevel = false) {
     d_symtab->pushScope();
     if(!bindingLevel) {
index 96ac7d48e9022c165b31a63d11fcaaaab86d365f..30239dc2f733618aa42319cba3b01350b82ff07b 100644 (file)
@@ -1733,6 +1733,18 @@ termNonVariable[CVC4::Expr& expr, CVC4::Expr& expr2]
         expr = MK_EXPR(kind, args);
       }
     }
+  | LPAREN_TOK COMPREHENSION_TOK
+    { PARSER_STATE->pushScope(true); }
+    boundVarList[bvl]
+    {
+      args.push_back(bvl);
+    }
+    term[f, f2] { args.push_back(f); }
+    term[f, f2] { 
+      args.push_back(f); 
+      expr = MK_EXPR(CVC4::kind::COMPREHENSION, args);
+    }
+    RPAREN_TOK
   | LPAREN_TOK qualIdentifier[p]
     termList[args,expr] RPAREN_TOK
     { 
@@ -2683,6 +2695,7 @@ DECLARE_DATATYPES_TOK : { PARSER_STATE->v2_6() || PARSER_STATE->sygus() }?'decla
 DECLARE_CODATATYPES_2_5_TOK : { !( PARSER_STATE->v2_6() || PARSER_STATE->sygus() ) }?'declare-codatatypes';
 DECLARE_CODATATYPES_TOK : { PARSER_STATE->v2_6() || PARSER_STATE->sygus() }?'declare-codatatypes';
 PAR_TOK : { PARSER_STATE->v2_6() }?'par';
+COMPREHENSION_TOK : { PARSER_STATE->isTheoryEnabled(Smt2::THEORY_SETS) }?'comprehension';
 TESTER_TOK : { ( PARSER_STATE->v2_6() || PARSER_STATE->sygus() ) && PARSER_STATE->isTheoryEnabled(Smt2::THEORY_DATATYPES) }?'is';
 MATCH_TOK : { ( PARSER_STATE->v2_6() || PARSER_STATE->sygus() ) && PARSER_STATE->isTheoryEnabled(Smt2::THEORY_DATATYPES) }?'match';
 GET_MODEL_TOK : 'get-model';
index 555908ea2878b42d91ecf49d082f27bbe29b14ce..006895df733fc91a1ea365845cb91b59b69c1f42 100644 (file)
@@ -751,6 +751,7 @@ void Smt2Printer::toStream(std::ostream& out,
     parametricTypeChildren = true;
     out << smtKindString(k, d_variant) << " ";
     break;
+  case kind::COMPREHENSION: out << smtKindString(k, d_variant) << " "; break;
   case kind::MEMBER: typeChildren = true; CVC4_FALLTHROUGH;
   case kind::INSERT:
   case kind::SET_TYPE:
@@ -1155,6 +1156,7 @@ static string smtKindString(Kind k, Variant v)
   case kind::INSERT: return "insert";
   case kind::COMPLEMENT: return "complement";
   case kind::CARD: return "card";
+  case kind::COMPREHENSION: return "comprehension";
   case kind::JOIN: return "join";
   case kind::PRODUCT: return "product";
   case kind::TRANSPOSE: return "transpose";
index 34fef7d6485f9a2bd82d8f483ec1b5fac317ee6b..058a20aebeac3381689706bc74da33aa8f737595 100644 (file)
@@ -46,6 +46,21 @@ operator CARD          1  "set cardinality operator"
 operator COMPLEMENT    1  "set COMPLEMENT (with respect to finite universe)"
 nullaryoperator UNIVERSE_SET "(finite) universe set, all set variables must be interpreted as subsets of it."
 
+# A set comprehension is specified by:
+# (1) a bound variable list x1 ... xn,
+# (2) a predicate P[x1...xn], and
+# (3) a term t[x1...xn].
+# A comprehension C with the above form has members given by the following
+# semantics:
+# forall y. ( exists x1...xn. P[x1...xn] ^ t[x1...xn] = y ) <=> (member y C)
+# where y ranges over the element type of the (set) type of the comprehension.
+# Notice that since all sets must be interpreted as finite, this means that
+# CVC4 will not be able to construct a model for any set comprehension such
+# that there are infinitely many y that satisfy the left hand side of the
+# equivalence above. The same limitation occurs more generally when combining
+# finite sets with quantified formulas.
+operator COMPREHENSION 3 "set comprehension specified by a bound variable list, a predicate, and a term."
+
 operator JOIN             2  "set join"
 operator PRODUCT          2  "set cartesian product"
 operator TRANSPOSE        1  "set transpose"
@@ -64,6 +79,7 @@ typerule INSERT         ::CVC4::theory::sets::InsertTypeRule
 typerule CARD           ::CVC4::theory::sets::CardTypeRule
 typerule COMPLEMENT     ::CVC4::theory::sets::ComplementTypeRule
 typerule UNIVERSE_SET   ::CVC4::theory::sets::UniverseSetTypeRule
+typerule COMPREHENSION  ::CVC4::theory::sets::ComprehensionTypeRule
 
 typerule JOIN                  ::CVC4::theory::sets::RelBinaryOperatorTypeRule
 typerule PRODUCT               ::CVC4::theory::sets::RelBinaryOperatorTypeRule
index 7756fe081f92951180933bede019282d986ebe7a..ca7c0bf2bced2d8c16d222900446737b50597b6c 100644 (file)
@@ -44,12 +44,14 @@ void SolverState::reset()
   d_congruent.clear();
   d_nvar_sets.clear();
   d_var_set.clear();
+  d_compSets.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_allCompSets.clear();
 }
 
 void SolverState::registerEqc(TypeNode tn, Node r)
@@ -137,6 +139,12 @@ void SolverState::registerTerm(Node r, TypeNode tnn, Node n)
     d_nvar_sets[r].push_back(n);
     Trace("sets-debug2") << "Non-var-set[" << r << "] : " << n << std::endl;
   }
+  else if (nk == COMPREHENSION)
+  {
+    d_compSets[r].push_back(n);
+    d_allCompSets.push_back(n);
+    Trace("sets-debug2") << "Comp-set[" << r << "] : " << n << std::endl;
+  }
   else if (n.isVar() && !d_skCache.isSkolem(n))
   {
     // it is important that we check it is a variable, but not an internally
@@ -146,9 +154,14 @@ void SolverState::registerTerm(Node r, TypeNode tnn, Node n)
       if (d_var_set.find(r) == d_var_set.end())
       {
         d_var_set[r] = n;
+        Trace("sets-debug2") << "var-set[" << r << "] : " << n << std::endl;
       }
     }
   }
+  else
+  {
+    Trace("sets-debug2") << "Unknown-set[" << r << "] : " << n << std::endl;
+  }
 }
 
 bool SolverState::areEqual(Node a, Node b) const
@@ -510,6 +523,17 @@ Node SolverState::getVariableSet(Node r) const
   }
   return Node::null();
 }
+
+const std::vector<Node>& SolverState::getComprehensionSets(Node r) const
+{
+  std::map<Node, std::vector<Node> >::const_iterator it = d_compSets.find(r);
+  if (it == d_compSets.end())
+  {
+    return d_emptyVec;
+  }
+  return it->second;
+}
+
 const std::map<Node, Node>& SolverState::getMembers(Node r) const
 {
   return getMembersInternal(r, 0);
@@ -550,6 +574,11 @@ const std::map<Kind, std::vector<Node> >& SolverState::getOperatorList() const
   return d_op_list;
 }
 
+const std::vector<Node>& SolverState::getComprehensionSets() const
+{
+  return d_allCompSets;
+}
+
 void SolverState::debugPrintSet(Node s, const char* c) const
 {
   if (s.getNumChildren() == 0)
index 2b4d93ed38a1a4bb92ade1be8d2c042b49b8a75d..7426a701b15627ee7477a52d4d5e94713aa24260 100644 (file)
@@ -133,6 +133,8 @@ class SolverState
    * if none exist.
    */
   Node getVariableSet(Node r) const;
+  /** Get comprehension sets in equivalence class with representative r */
+  const std::vector<Node>& getComprehensionSets(Node r) const;
   /** Get (positive) members of the set equivalence class r
    *
    * The members are return as a map, which maps members to their explanation.
@@ -161,6 +163,8 @@ class SolverState
    * map is a representative of its congruence class.
    */
   const std::map<Kind, std::vector<Node> >& getOperatorList() const;
+  /** Get the list of all comprehension sets in the current context */
+  const std::vector<Node>& getComprehensionSets() const;
 
   // --------------------------------------- commonly used terms
   /** Get type constraint skolem
@@ -225,6 +229,8 @@ class SolverState
   std::map<Node, Node> d_congruent;
   /** Map from equivalence classes to the list of non-variable sets in it */
   std::map<Node, std::vector<Node> > d_nvar_sets;
+  /** Map from equivalence classes to the list of comprehension sets in it */
+  std::map<Node, std::vector<Node> > d_compSets;
   /** Map from equivalence classes to a variable sets in it */
   std::map<Node, Node> d_var_set;
   /** polarity memberships
@@ -262,6 +268,8 @@ class SolverState
   std::map<Node, Node> d_singleton_index;
   /** Indices for the binary kinds INTERSECT, SETMINUS and UNION. */
   std::map<Kind, std::map<Node, std::map<Node, Node> > > d_bop_index;
+  /** A list of comprehension sets */
+  std::vector<Node> d_allCompSets;
   // -------------------------------- end term indices
   std::map<Kind, std::vector<Node> > d_op_list;
   /** the skolem cache */
index 869cb8926c1d1af952cacfd2a5706a2c861753c5..3b0427ec5bee0f52572f65725a47b22d3cfa7cf5 100644 (file)
  **/
 
 #include "theory/sets/theory_sets.h"
+#include "options/sets_options.h"
 #include "theory/sets/theory_sets_private.h"
+#include "theory/theory_model.h"
+
+using namespace CVC4::kind;
 
 namespace CVC4 {
 namespace theory {
@@ -40,6 +44,13 @@ TheorySets::~TheorySets()
   // Do not move me to the header. See explanation in the constructor.
 }
 
+void TheorySets::finishInit()
+{
+  TheoryModel* tm = d_valuation.getModel();
+  Assert(tm != nullptr);
+  tm->setUnevaluatedKind(COMPREHENSION);
+}
+
 void TheorySets::addSharedTerm(TNode n) {
   d_internal->addSharedTerm(n);
 }
@@ -78,6 +89,28 @@ void TheorySets::preRegisterTerm(TNode node) {
 }
 
 Node TheorySets::expandDefinition(LogicRequest &logicRequest, Node n) {
+  Kind nk = n.getKind();
+  if (nk == UNIVERSE_SET || nk == COMPLEMENT || nk == JOIN_IMAGE
+      || nk == COMPREHENSION)
+  {
+    if (!options::setsExt())
+    {
+      std::stringstream ss;
+      ss << "Extended set operators are not supported in default mode, try "
+            "--sets-ext.";
+      throw LogicException(ss.str());
+    }
+  }
+  if (nk == COMPREHENSION)
+  {
+    // set comprehension is an implicit quantifier, require it in the logic
+    if (!getLogicInfo().isQuantified())
+    {
+      std::stringstream ss;
+      ss << "Set comprehensions require quantifiers in the background logic.";
+      throw LogicException(ss.str());
+    }
+  }
   return d_internal->expandDefinition(logicRequest, n);
 }
 
index 4c145aedb1c3d4bde820218a443426b7529fd538..ed2459b32dcd885f3de4d987235f90c67b081780 100644 (file)
@@ -42,6 +42,8 @@ class TheorySets : public Theory
              const LogicInfo& logicInfo);
   ~TheorySets() override;
 
+  /** finish initialization */
+  void finishInit() override;
   void addSharedTerm(TNode) override;
   void check(Effort) override;
   bool collectModelInfo(TheoryModel* m) override;
index 94fef85f5e1e20825c56d29cf416160a497aab24..6a381d4714e661344868f83021f6052db9c7f3cb 100644 (file)
@@ -38,7 +38,7 @@ TheorySetsPrivate::TheorySetsPrivate(TheorySets& external,
                                      context::UserContext* u)
     : d_members(c),
       d_deq(c),
-      d_deq_processed(u),
+      d_termProcessed(u),
       d_keep(c),
       d_full_check_incomplete(false),
       d_external(external),
@@ -432,10 +432,16 @@ void TheorySetsPrivate::fullEffortCheck(){
           {
             checkDisequalities();
             d_im.flushPendingLemmas();
-            if (!d_im.hasProcessed() && d_card_enabled)
+            if (!d_im.hasProcessed())
             {
-              // call the check method of the cardinality solver
-              d_cardSolver->check();
+              checkReduceComprehensions();
+              d_im.flushPendingLemmas();
+
+              if (!d_im.hasProcessed() && d_card_enabled)
+              {
+                // call the check method of the cardinality solver
+                d_cardSolver->check();
+              }
             }
           }
         }
@@ -763,13 +769,13 @@ void TheorySetsPrivate::checkDisequalities()
       // already satisfied
       continue;
     }
-    if (d_deq_processed.find(deq) != d_deq_processed.end())
+    if (d_termProcessed.find(deq) != d_termProcessed.end())
     {
       // already added lemma
       continue;
     }
-    d_deq_processed.insert(deq);
-    d_deq_processed.insert(deq[1].eqNode(deq[0]));
+    d_termProcessed.insert(deq);
+    d_termProcessed.insert(deq[1].eqNode(deq[0]));
     Trace("sets") << "Process Disequality : " << deq.negate() << std::endl;
     TypeNode elementType = deq[0].getType().getSetElementType();
     Node x = d_state.getSkolemCache().mkTypedSkolemCached(
@@ -787,6 +793,41 @@ void TheorySetsPrivate::checkDisequalities()
   }
 }
 
+void TheorySetsPrivate::checkReduceComprehensions()
+{
+  NodeManager* nm = NodeManager::currentNM();
+  const std::vector<Node>& comps = d_state.getComprehensionSets();
+  for (const Node& n : comps)
+  {
+    if (d_termProcessed.find(n) != d_termProcessed.end())
+    {
+      // already reduced it
+      continue;
+    }
+    d_termProcessed.insert(n);
+    Node v = nm->mkBoundVar(n[2].getType());
+    Node body = nm->mkNode(AND, n[1], v.eqNode(n[2]));
+    // must do substitution
+    std::vector<Node> vars;
+    std::vector<Node> subs;
+    for (const Node& cv : n[0])
+    {
+      vars.push_back(cv);
+      Node cvs = nm->mkBoundVar(cv.getType());
+      subs.push_back(cvs);
+    }
+    body = body.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
+    Node bvl = nm->mkNode(BOUND_VAR_LIST, subs);
+    body = nm->mkNode(EXISTS, bvl, body);
+    Node mem = nm->mkNode(MEMBER, v, n);
+    Node lem =
+        nm->mkNode(FORALL, nm->mkNode(BOUND_VAR_LIST, v), body.eqNode(mem));
+    Trace("sets-comprehension")
+        << "Comprehension reduction: " << lem << std::endl;
+    d_im.flushLemma(lem);
+  }
+}
+
 /**************************** TheorySetsPrivate *****************************/
 /**************************** TheorySetsPrivate *****************************/
 /**************************** TheorySetsPrivate *****************************/
@@ -1190,35 +1231,22 @@ void TheorySetsPrivate::preRegisterTerm(TNode 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;
   }
 }
 
 Node TheorySetsPrivate::expandDefinition(LogicRequest &logicRequest, Node n) {
   Debug("sets-proc") << "expandDefinition : " << n << std::endl;
-  if( n.getKind()==kind::UNIVERSE_SET || n.getKind()==kind::COMPLEMENT || n.getKind()==kind::JOIN_IMAGE ){
-    if( !options::setsExt() ){
-      std::stringstream ss;
-      ss << "Extended set operators are not supported in default mode, try --sets-ext.";
-      throw LogicException(ss.str());
-    }
-  }
   return n;
 }
 
index 0468e5fb7a8e637b6271b997694b0fddf0bc9c24..5ef8c482533c5c1fcfc2303211719ef14fbde716 100644 (file)
@@ -101,6 +101,11 @@ class TheorySetsPrivate {
    * roughly corresponds the SET DISEQUALITY rule from Bansal et al IJCAR 2016.
    */
   void checkDisequalities();
+  /**
+   * Check comprehensions. This adds reduction lemmas for all set comprehensions
+   * in the current context.
+   */
+  void checkReduceComprehensions();
 
   void addCarePairs(TNodeTrie* t1,
                     TNodeTrie* t2,
@@ -112,7 +117,11 @@ class TheorySetsPrivate {
   Node d_false;
   Node d_zero;
   NodeBoolMap d_deq;
-  NodeSet d_deq_processed;
+  /**
+   * The set of terms that we have reduced via a lemma in the current user
+   * context.
+   */
+  NodeSet d_termProcessed;
   NodeSet d_keep;
   std::vector< Node > d_emp_exp;
   
index 27aa58452575ee739662070c7c635e40f820d151..4301631211eceedbbc7548cc5a21dbcc28476ebc 100644 (file)
@@ -25,26 +25,6 @@ namespace CVC4 {
 namespace theory {
 namespace sets {
 
-class SetsTypeRule {
-public:
-
-  /**
-   * Compute the type for (and optionally typecheck) a term belonging
-   * to the theory of sets.
-   *
-   * @param check if true, the node's type should be checked as well
-   * as computed.
-   */
-  inline static TypeNode computeType(NodeManager* nodeManager, TNode n,
-                                     bool check)
-  {
-    // TODO: implement me!
-    Unimplemented();
-
-  }
-
-};/* class SetsTypeRule */
-
 struct SetsBinaryOperatorTypeRule {
   inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
   {
@@ -216,6 +196,28 @@ struct UniverseSetTypeRule {
   }
 };/* struct ComplementTypeRule */
 
+struct ComprehensionTypeRule
+{
+  static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+  {
+    Assert(n.getKind() == kind::COMPREHENSION);
+    if (check)
+    {
+      if (n[0].getType(check) != nodeManager->boundVarListType())
+      {
+        throw TypeCheckingExceptionPrivate(
+            n, "first argument of set comprehension is not bound var list");
+      }
+      if (n[1].getType(check) != nodeManager->booleanType())
+      {
+        throw TypeCheckingExceptionPrivate(
+            n, "body of set comprehension is not boolean");
+      }
+    }
+    return nodeManager->mkSetType(n[2].getType(check));
+  }
+}; /* struct ComprehensionTypeRule */
+
 struct InsertTypeRule {
   inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
   {
index 73393d29a53ae303d82d76a55cea1b88932184b3..c4dfd2593df702443dda4fb76ad0f1ebbd4d205b 100644 (file)
@@ -803,6 +803,7 @@ set(regress_0_tests
   regress0/sets/complement.cvc
   regress0/sets/complement2.cvc
   regress0/sets/complement3.cvc
+  regress0/sets/comp-qf-error.smt2
   regress0/sets/cvc-sample.cvc
   regress0/sets/dt-simp-mem.smt2
   regress0/sets/emptyset.smt2
@@ -1565,6 +1566,10 @@ set(regress_1_tests
   regress1/sets/card-6.smt2
   regress1/sets/card-7.smt2
   regress1/sets/card-vc6-minimized.smt2
+  regress1/sets/comp-intersect.smt2
+  regress1/sets/comp-odd.smt2
+  regress1/sets/comp-positive.smt2
+  regress1/sets/comp-pos-member.smt2
   regress1/sets/copy_check_heap_access_33_4.smt2
   regress1/sets/deepmeas0.hs.fqout.cvc4.41.smt2
   regress1/sets/fuzz14418.smt2
@@ -1577,6 +1582,7 @@ set(regress_1_tests
   regress1/sets/remove_check_free_31_6.smt2
   regress1/sets/sets-disequal.smt2
   regress1/sets/sets-tuple-poly.cvc
+  regress1/sets/set-comp-sat.smt2
   regress1/sets/sharingbug.smt2
   regress1/sets/univ-set-uf-elim.smt2
   regress1/simplification_bug4.smt2
diff --git a/test/regress/regress0/sets/comp-qf-error.smt2 b/test/regress/regress0/sets/comp-qf-error.smt2
new file mode 100644 (file)
index 0000000..81e4d74
--- /dev/null
@@ -0,0 +1,14 @@
+; COMMAND-LINE: --sets-ext
+; EXPECT: (error "Set comprehensions require quantifiers in the background logic.")
+; EXIT: 1
+(set-logic QF_UFLIAFS)
+(set-info :status unsat)
+
+(declare-sort U 0)
+(declare-fun a () U)
+(declare-fun x () (Set U))
+
+
+(assert (subset x (comprehension ((z U)) (not (= z a)) z)))
+
+(check-sat)
diff --git a/test/regress/regress1/sets/comp-intersect.smt2 b/test/regress/regress1/sets/comp-intersect.smt2
new file mode 100644 (file)
index 0000000..ab32063
--- /dev/null
@@ -0,0 +1,14 @@
+; COMMAND-LINE: --sets-ext
+; EXPECT: unsat
+(set-logic ALL)
+(set-info :status unsat)
+
+(declare-fun x () (Set Int))
+(declare-fun y () (Set Int))
+
+(assert (= x (comprehension ((z Int)) (> z 4) (* 5 z))))
+(assert (= y (comprehension ((z Int)) (< z 10) (+ (* 5 z) 1))))
+
+(assert (not (= (intersection x y) (as emptyset (Set Int)))))
+
+(check-sat)
diff --git a/test/regress/regress1/sets/comp-odd.smt2 b/test/regress/regress1/sets/comp-odd.smt2
new file mode 100644 (file)
index 0000000..1b1a13b
--- /dev/null
@@ -0,0 +1,16 @@
+; COMMAND-LINE: --sets-ext
+; EXPECT: unsat
+(set-logic ALL)
+(set-info :status unsat)
+
+(declare-fun x () (Set Int))
+
+(assert (subset x (comprehension ((z Int)) true (* 2 z))))
+
+(declare-fun a () Int)
+(declare-fun b () Int)
+
+(assert (= a (+ (* 8 b) 1)))
+(assert (member a x))
+
+(check-sat)
diff --git a/test/regress/regress1/sets/comp-pos-member.smt2 b/test/regress/regress1/sets/comp-pos-member.smt2
new file mode 100644 (file)
index 0000000..aeba4ca
--- /dev/null
@@ -0,0 +1,23 @@
+; COMMAND-LINE: --sets-ext --full-saturate-quant
+; EXPECT: unsat
+(set-logic ALL)
+(set-info :status unsat)
+
+(declare-fun x () (Set Int))
+
+(assert (subset (comprehension ((z Int)) (>= z 0) (* 3 z)) x))
+
+(declare-fun a () Int)
+(declare-fun b () Int)
+(declare-fun c () Int)
+
+(assert (not (member a x)))
+(assert (not (member b x)))
+(assert (not (member c x)))
+(assert (<= 0 a))
+(assert (<= a b))
+(assert (<= b c))
+(assert (< (- c a) 3))
+(assert (distinct a b c))
+
+(check-sat)
diff --git a/test/regress/regress1/sets/comp-positive.smt2 b/test/regress/regress1/sets/comp-positive.smt2
new file mode 100644 (file)
index 0000000..af75230
--- /dev/null
@@ -0,0 +1,12 @@
+; COMMAND-LINE: --sets-ext
+; EXPECT: unsat
+(set-logic ALL)
+(set-info :status unsat)
+
+(declare-fun x () (Set Int))
+
+(assert (subset x (comprehension ((z Int)) (> z 0) z)))
+
+(assert (member 0 x))
+
+(check-sat)
diff --git a/test/regress/regress1/sets/set-comp-sat.smt2 b/test/regress/regress1/sets/set-comp-sat.smt2
new file mode 100644 (file)
index 0000000..d6a64c3
--- /dev/null
@@ -0,0 +1,18 @@
+; COMMAND-LINE: --sets-ext --finite-model-find
+; EXPECT: sat
+(set-logic UFFS)
+(set-info :status sat)
+
+(declare-sort U 0)
+(declare-fun a () U)
+(declare-fun b () U)
+(declare-fun c () U)
+(declare-fun x () (Set U))
+
+
+(assert (subset x (comprehension ((z U)) (not (= z a)) z)))
+
+(assert (not (member b x)))
+(assert (member c x))
+
+(check-sat)