Ensures that the reductions are deterministic, thus fixes cvc5/cvc5-projects#493.
The reductions can be further simplified to not introduce UF. This will be addressed in a later PR.
{
Assert(node.getKind() == BAG_CHOOSE);
- // (bag.choose A) is expanded as
- // (witness ((x elementType))
- // (ite
- // (= A (as bag.empty (Bag E)))
- // (= x (uf A))
- // (and (>= (bag.count x A) 1) (= x (uf A)))
+ // (bag.choose A) is eliminated to k, with lemma
+ // (and (= k (uf A)) (or (= A (as bag.empty (Bag E))) (>= (bag.count k A) 1)))
// where uf: (Bag E) -> E is a skolem function, and E is the type of elements
// of A
NodeManager* nm = NodeManager::currentNM();
SkolemManager* sm = nm->getSkolemManager();
+ Node x = sm->mkPurifySkolem(node, "bagChoose");
Node A = node[0];
TypeNode bagType = A.getType();
TypeNode ufType = nm->mkFunctionType(bagType, bagType.getBagElementType());
Node uf = sm->mkSkolemFunction(SkolemFunId::BAGS_CHOOSE, ufType, Node());
Node ufA = NodeManager::currentNM()->mkNode(APPLY_UF, uf, A);
- Node x = nm->mkBoundVar(bagType.getBagElementType());
-
Node equal = x.eqNode(ufA);
Node emptyBag = nm->mkConst(EmptyBag(bagType));
Node isEmpty = A.eqNode(emptyBag);
Node count = nm->mkNode(BAG_COUNT, x, A);
Node one = nm->mkConstInt(Rational(1));
Node geqOne = nm->mkNode(GEQ, count, one);
- Node geqOneAndEqual = geqOne.andNode(equal);
- Node ite = nm->mkNode(ITE, isEmpty, equal, geqOneAndEqual);
- Node ret = sm->mkSkolem(x, ite, "kBagChoose");
- lems.push_back(SkolemLemma(ret, nullptr));
+ Node lem = nm->mkNode(AND, equal, nm->mkNode(OR, isEmpty, geqOne));
+ TrustNode tlem = TrustNode::mkTrustLemma(lem, nullptr);
+ lems.push_back(SkolemLemma(tlem, x));
Trace("TheoryBags::ppRewrite")
- << "ppRewrite(" << node << ") = " << ret << std::endl;
- return TrustNode::mkTrustRewrite(node, ret, nullptr);
+ << "ppRewrite(" << node << ") = " << x << std::endl;
+ return TrustNode::mkTrustRewrite(node, x, nullptr);
}
void TheoryBags::postCheck(Effort effort)
{
Assert(node.getKind() == SET_CHOOSE);
- // (choose A) is expanded as
- // (witness ((x elementType))
- // (ite
- // (= A (as emptyset (Set E)))
- // (= x (uf A))
- // (and (member x A) (= x uf(A)))
+ // (choose A) is eliminated to k, with lemma
+ // (and (= k (uf A)) (or (= A (as set.empty (Set E))) (set.member k A)))
// where uf: (Set E) -> E is a skolem function, and E is the type of elements
// of A
NodeManager* nm = NodeManager::currentNM();
SkolemManager* sm = nm->getSkolemManager();
+ Node x = sm->mkPurifySkolem(node, "setChoose");
Node A = node[0];
TypeNode setType = A.getType();
ensureFirstClassSetType(setType);
Node uf = sm->mkSkolemFunction(SkolemFunId::SETS_CHOOSE, ufType, Node());
Node ufA = NodeManager::currentNM()->mkNode(APPLY_UF, uf, A);
- Node x = nm->mkBoundVar(setType.getSetElementType());
-
Node equal = x.eqNode(ufA);
Node emptySet = nm->mkConst(EmptySet(setType));
Node isEmpty = A.eqNode(emptySet);
Node member = nm->mkNode(SET_MEMBER, x, A);
- Node memberAndEqual = member.andNode(equal);
- Node ite = nm->mkNode(ITE, isEmpty, equal, memberAndEqual);
- Node ret = sm->mkSkolem(x, ite, "kSetChoose");
- lems.push_back(SkolemLemma(ret, nullptr));
- return TrustNode::mkTrustRewrite(node, ret, nullptr);
+ Node lem = nm->mkNode(AND, equal, nm->mkNode(OR, isEmpty, member));
+ TrustNode tlem = TrustNode::mkTrustLemma(lem, nullptr);
+ lems.push_back(SkolemLemma(tlem, x));
+ return TrustNode::mkTrustRewrite(node, x, nullptr);
}
TrustNode TheorySetsPrivate::expandIsSingletonOperator(const Node& node)
Assert(lem.getKind() == TrustNodeKind::LEMMA);
}
-SkolemLemma::SkolemLemma(Node k, ProofGenerator* pg) : d_lemma(), d_skolem(k)
-{
- Node lem = getSkolemLemmaFor(k);
- d_lemma = TrustNode::mkTrustLemma(lem, pg);
-}
-
Node SkolemLemma::getProven() const { return d_lemma.getProven(); }
-Node SkolemLemma::getSkolemLemmaFor(Node k)
-{
- Node w = SkolemManager::getWitnessForm(k);
- Assert(w.getKind() == kind::WITNESS);
- TNode tx = w[0][0];
- TNode tk = k;
- return w[1].substitute(tx, tk);
-}
-
} // namespace theory
} // namespace cvc5
* Make skolem from trust node lem of kind LEMMA and skolem k.
*/
SkolemLemma(TrustNode lem, Node k);
- /**
- * Make skolem lemma from witness form of skolem k. If non-null, pg is
- * proof generator that can generator a proof for getSkolemLemmaFor(k).
- */
- SkolemLemma(Node k, ProofGenerator* pg);
/** The lemma, a trust node of kind LEMMA */
TrustNode d_lemma;
/** Get proven from the lemma */
Node getProven() const;
- /**
- * Get the lemma for skolem k based on its witness form. If k has witness
- * form (witness ((x T)) (P x)), this is the formula (P k).
- */
- static Node getSkolemLemmaFor(Node k);
};
} // namespace theory
regress0/sets/pre-proc-univ.smt2
regress0/sets/proj-issue177.smt2
regress0/sets/proj-issue486-sets-split-eq.smt2
+ regress0/sets/proj-issue493-choose-det.smt2
regress0/sets/rec_copy_loop_check_heap_access_43_4.smt2
regress0/sets/setel-eq.smt2
regress0/sets/sets-deq-dd.smt2
--- /dev/null
+(set-logic ALL)
+(set-info :status unsat)
+(set-option :sets-ext true)
+(declare-const x Bool)
+(declare-const x3 Bool)
+(declare-const x4 Bool)
+(assert (forall ((x2 Bool)) (ite (not (set.choose (set.complement (set.insert x3 x4 false false (set.singleton x))))) (set.choose (set.complement (set.insert x3 x4 x2 false (set.singleton x)))) false)))
+(check-sat)