This PR enables THEORY_UF by default for sets and adds the operator CHOOSE for sets which returns an element from a given set. The semantics is as follows:
If a set A = {x}, then the term (choose A) is equivalent to the term x.
If the set is empty, then (choose A) is an arbitrary value.
If the set has cardinality > 1, then (choose A) will deterministically return an element in A.
{JOIN_IMAGE, CVC4::Kind::JOIN_IMAGE},
{IDEN, CVC4::Kind::IDEN},
{COMPREHENSION, CVC4::Kind::COMPREHENSION},
+ {CHOOSE, CVC4::Kind::CHOOSE},
/* Strings ------------------------------------------------------------- */
{STRING_CONCAT, CVC4::Kind::STRING_CONCAT},
{STRING_IN_REGEXP, CVC4::Kind::STRING_IN_REGEXP},
{CVC4::Kind::JOIN_IMAGE, JOIN_IMAGE},
{CVC4::Kind::IDEN, IDEN},
{CVC4::Kind::COMPREHENSION, COMPREHENSION},
+ {CVC4::Kind::CHOOSE, CHOOSE},
/* Strings --------------------------------------------------------- */
{CVC4::Kind::STRING_CONCAT, STRING_CONCAT},
{CVC4::Kind::STRING_IN_REGEXP, STRING_IN_REGEXP},
* mkTerm(Kind kind, const std::vector<Term>& children)
*/
COMPREHENSION,
+ /**
+ * Returns an element from a given set.
+ * If a set A = {x}, then the term (choose A) is equivalent to the term x.
+ * If the set is empty, then (choose A) is an arbitrary value.
+ * If the set has cardinality > 1, then (choose A) will deterministically
+ * return an element in A.
+ * Parameters: 1
+ * -[1]: Term of set sort
+ * Create with:
+ * mkTerm(Kind kind, Term child)
+ */
+ CHOOSE,
/* Strings --------------------------------------------------------------- */
BVSLE_TOK = 'BVSLE';
BVSGE_TOK = 'BVSGE';
+ // Sets
+ SETS_CHOOSE_TOK = 'CHOOSE';
+
// Relations
JOIN_TOK = 'JOIN';
TRANSPOSE_TOK = 'TRANSPOSE';
case PRODUCT_TOK:
case IDEN_TOK:
case JOIN_IMAGE_TOK:
- case TRANSCLOSURE_TOK: return 24;
+ case TRANSCLOSURE_TOK:
+ case SETS_CHOOSE_TOK: return 24;
case LEQ_TOK:
case LT_TOK:
case GEQ_TOK:
case XOR_TOK: return api::XOR;
case AND_TOK: return api::AND;
+ case SETS_CHOOSE_TOK: return api::CHOOSE;
case PRODUCT_TOK: return api::PRODUCT;
case JOIN_TOK: return api::JOIN;
case JOIN_IMAGE_TOK: return api::JOIN_IMAGE;
+
// comparisonBinop
case EQUAL_TOK: return api::EQUAL;
case DISEQUAL_TOK: negate = true; return api::EQUAL;
/* Sets prefix operators */
: SETS_CARD_TOK LPAREN formula[f] RPAREN
{ f = MK_TERM(CVC4::api::CARD, f); }
+ | SETS_CHOOSE_TOK LPAREN formula[f] RPAREN
+ { f = MK_TERM(CVC4::api::CHOOSE, f); }
| simpleTerm[f]
;
addOperator(api::INSERT, "insert");
addOperator(api::CARD, "card");
addOperator(api::COMPLEMENT, "complement");
+ addOperator(api::CHOOSE, "choose");
addOperator(api::JOIN, "join");
addOperator(api::PRODUCT, "product");
addOperator(api::TRANSPOSE, "transpose");
case kind::INSERT:
case kind::SET_TYPE:
case kind::SINGLETON:
- case kind::COMPLEMENT: out << smtKindString(k, d_variant) << " "; break;
+ case kind::COMPLEMENT:
+ case kind::CHOOSE: out << smtKindString(k, d_variant) << " "; break;
case kind::UNIVERSE_SET:out << "(as univset " << n.getType() << ")";break;
// fp theory
case kind::COMPLEMENT: return "complement";
case kind::CARD: return "card";
case kind::COMPREHENSION: return "comprehension";
+ case kind::CHOOSE: return "choose";
case kind::JOIN: return "join";
case kind::PRODUCT: return "product";
case kind::TRANSPOSE: return "transpose";
# finite sets with quantified formulas.
operator COMPREHENSION 3 "set comprehension specified by a bound variable list, a predicate, and a term."
+# The operator choose returns an element from a given set.
+# If set A = {x}, then the term (choose A) is equivalent to the term x.
+# If the set is empty, then (choose A) is an arbitrary value.
+# If the set has cardinality > 1, then (choose A) will deterministically return an element in A.
+operator CHOOSE 1 "return an element in the set given as a parameter"
+
operator JOIN 2 "set join"
operator PRODUCT 2 "set cartesian product"
operator TRANSPOSE 1 "set transpose"
typerule COMPLEMENT ::CVC4::theory::sets::ComplementTypeRule
typerule UNIVERSE_SET ::CVC4::theory::sets::UniverseSetTypeRule
typerule COMPREHENSION ::CVC4::theory::sets::ComprehensionTypeRule
+typerule CHOOSE ::CVC4::theory::sets::ChooseTypeRule
typerule JOIN ::CVC4::theory::sets::RelBinaryOperatorTypeRule
typerule PRODUCT ::CVC4::theory::sets::RelBinaryOperatorTypeRule
construle INSERT ::CVC4::theory::sets::InsertTypeRule
construle CARD ::CVC4::theory::sets::CardTypeRule
construle COMPLEMENT ::CVC4::theory::sets::ComplementTypeRule
+construle CHOOSE ::CVC4::theory::sets::ChooseTypeRule
construle JOIN ::CVC4::theory::sets::RelBinaryOperatorTypeRule
construle PRODUCT ::CVC4::theory::sets::RelBinaryOperatorTypeRule
}
}
-Node TheorySetsPrivate::expandDefinition(Node n)
+Node TheorySetsPrivate::expandDefinition(Node node)
{
- Debug("sets-proc") << "expandDefinition : " << n << std::endl;
- return n;
+ Debug("sets-proc") << "expandDefinition : " << node << std::endl;
+
+ if (node.getKind() == kind::CHOOSE)
+ {
+ // (choose A) is expanded as
+ // (witness ((x elementType))
+ // (ite
+ // (= A (as emptyset setType))
+ // (= x chooseUf(A))
+ // (and (member x A) (= x chooseUf(A)))
+
+ NodeManager* nm = NodeManager::currentNM();
+ Node set = node[0];
+ TypeNode setType = set.getType();
+ Node chooseSkolem = getChooseFunction(setType);
+ Node apply = NodeManager::currentNM()->mkNode(APPLY_UF, chooseSkolem, set);
+
+ Node witnessVariable = nm->mkBoundVar(setType.getSetElementType());
+
+ Node equal = witnessVariable.eqNode(apply);
+ Node emptySet = nm->mkConst(EmptySet(setType.toType()));
+ Node isEmpty = set.eqNode(emptySet);
+ Node member = nm->mkNode(MEMBER, witnessVariable, set);
+ Node memberAndEqual = member.andNode(equal);
+ Node ite = nm->mkNode(kind::ITE, isEmpty, equal, memberAndEqual);
+ Node witnessVariables = nm->mkNode(BOUND_VAR_LIST, witnessVariable);
+ Node witness = nm->mkNode(CHOICE, witnessVariables, ite);
+ return witness;
+ }
+
+ return node;
+}
+
+Node TheorySetsPrivate::getChooseFunction(const TypeNode& setType)
+{
+ std::map<TypeNode, Node>::iterator it = d_chooseFunctions.find(setType);
+ if (it != d_chooseFunctions.end())
+ {
+ return it->second;
+ }
+
+ NodeManager* nm = NodeManager::currentNM();
+ TypeNode chooseUf = nm->mkFunctionType(setType, setType.getSetElementType());
+ stringstream stream;
+ stream << "chooseUf" << setType.getId();
+ string name = stream.str();
+ Node chooseSkolem = nm->mkSkolem(
+ name, chooseUf, "choose function", NodeManager::SKOLEM_EXACT_NAME);
+ d_chooseFunctions[setType] = chooseSkolem;
+ return chooseSkolem;
}
Theory::PPAssertStatus TheorySetsPrivate::ppAssert(
bool isMember(Node x, Node s);
private:
+ /** get choose function
+ *
+ * Returns the existing uninterpreted function for the choose operator for the
+ * given set type, or creates a new one if it does not exist.
+ */
+ Node getChooseFunction(const TypeNode& setType);
/** The state of the sets solver at full effort */
SolverState d_state;
/** The inference manager of the sets solver */
/** The theory rewriter for this theory. */
TheorySetsRewriter d_rewriter;
+
+ /*
+ * a map that stores the choose functions for set types
+ */
+ std::map<TypeNode, Node> d_chooseFunctions;
};/* class TheorySetsPrivate */
}
}; /* struct ComprehensionTypeRule */
+struct ChooseTypeRule
+{
+ inline static TypeNode computeType(NodeManager* nodeManager,
+ TNode n,
+ bool check)
+ {
+ Assert(n.getKind() == kind::CHOOSE);
+ TypeNode setType = n[0].getType(check);
+ if (check)
+ {
+ if (!setType.isSet())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "CHOOSE operator expects a set, a non-set is found");
+ }
+ }
+ return setType.getSetElementType();
+ }
+ inline static bool computeIsConst(NodeManager* nodeManager, TNode n)
+ {
+ Assert(n.getKind() == kind::CHOOSE);
+ // choose nodes should be expanded
+ return false;
+ }
+}; /* struct ChooseTypeRule */
+
struct InsertTypeRule {
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
{
regress1/sep/wand-simp-sat.smt2
regress1/sep/wand-simp-sat2.smt2
regress1/sep/wand-simp-unsat.smt2
+ regress1/sets/choose.cvc
+ regress1/sets/choose1.smt2
+ regress1/sets/choose2.smt2
+ regress1/sets/choose3.smt2
+ regress1/sets/choose4.smt2
regress1/sets/ListElem.hs.fqout.cvc4.38.smt2
regress1/sets/ListElts.hs.fqout.cvc4.317.smt2
regress1/sets/TalkingAboutSets.hs.fqout.cvc4.3577.smt2
; COMMAND-LINE: --finite-model-find --lang=smt2.5
; EXPECT: sat
; Preamble --------------
-(set-logic ALL_SUPPORTED)
+(set-logic AUFDTLIA)
(set-info :status sat)
(declare-datatypes () ((UNIT (Unit))))
(declare-datatypes () ((BOOL (Truth) (Falsity))))
; COMMAND-LINE: --finite-model-find --lang=smt2.5
; EXPECT: unsat
; Preamble --------------
-(set-logic ALL_SUPPORTED)
+(set-logic AUFDTLIA)
(set-info :status unsat)
(declare-datatypes () ((UNIT (Unit))))
(declare-datatypes () ((BOOL (Truth) (Falsity))))
--- /dev/null
+% COMMAND-LINE: --no-check-models
+% EXPECT: sat
+
+A : SET OF INT;
+a : INT;
+
+ASSERT NOT (A = {} :: SET OF INT);
+ASSERT CHOOSE (A) = 10;
+ASSERT CHOOSE (A) = a;
+
+CHECKSAT;
--- /dev/null
+; COMMAND-LINE: --no-check-models
+(set-logic ALL)
+(set-info :status sat)
+(set-option :produce-models true)
+(declare-fun A () (Set Int))
+(declare-fun a () Int)
+(assert (not (= A (as emptyset (Set Int)))))
+(assert (= (choose A) 10))
+(assert (= a (choose A)))
+(assert (exists ((x Int)) (and (= x (choose A)) (= x a))))
+(check-sat)
--- /dev/null
+(set-logic ALL)
+(set-info :status unsat)
+(set-option :produce-models true)
+(declare-fun A () (Set Int))
+(assert (distinct (choose A) (choose A)))
+(check-sat)
\ No newline at end of file
--- /dev/null
+(set-logic ALL)
+(set-info :status sat)
+(set-option :produce-models true)
+(declare-fun A () (Set Int))
+(assert (= (choose A) 10))
+(assert (= A (as emptyset (Set Int))))
+(check-sat)
\ No newline at end of file
--- /dev/null
+; COMMAND-LINE: --no-check-models
+(set-logic ALL)
+(set-info :status sat)
+(set-option :produce-models true)
+(declare-fun A () (Set Int))
+(declare-fun a () Int)
+(assert (not (= A (as emptyset (Set Int)))))
+(assert (member 10 A))
+; this line raises an assertion error
+(assert (= a (choose A)))
+; this line raises an assertion error
+;(assert (exists ((x Int)) (and (= x (choose A)) (= x a))))
+(check-sat)
\ No newline at end of file