summaryrefslogtreecommitdiff
path: root/src/theory/sets/cardinality_extension.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/theory/sets/cardinality_extension.cpp')
-rw-r--r--src/theory/sets/cardinality_extension.cpp190
1 files changed, 179 insertions, 11 deletions
diff --git a/src/theory/sets/cardinality_extension.cpp b/src/theory/sets/cardinality_extension.cpp
index 48f5b7b35..a1c91c517 100644
--- a/src/theory/sets/cardinality_extension.cpp
+++ b/src/theory/sets/cardinality_extension.cpp
@@ -19,6 +19,7 @@
#include "expr/node_algorithm.h"
#include "options/sets_options.h"
#include "theory/sets/normal_form.h"
+#include "theory/theory_model.h"
#include "theory/valuation.h"
using namespace std;
@@ -33,8 +34,13 @@ CardinalityExtension::CardinalityExtension(SolverState& s,
eq::EqualityEngine& e,
context::Context* c,
context::UserContext* u)
- : d_state(s), d_im(im), d_ee(e), d_card_processed(u)
+ : d_state(s),
+ d_im(im),
+ d_ee(e),
+ d_card_processed(u),
+ d_finite_type_constants_processed(false)
{
+ d_true = NodeManager::currentNM()->mkConst(true);
d_zero = NodeManager::currentNM()->mkConst(Rational(0));
// we do congruence over cardinality
d_ee.addFunctionKind(CARD);
@@ -44,6 +50,9 @@ void CardinalityExtension::reset()
{
d_eqc_to_card_term.clear();
d_t_card_enabled.clear();
+ d_finite_type_elements.clear();
+ d_finite_type_slack_elements.clear();
+ d_univProxy.clear();
}
void CardinalityExtension::registerTerm(Node n)
{
@@ -57,20 +66,112 @@ void CardinalityExtension::registerTerm(Node n)
d_eqc_to_card_term[r] = n;
registerCardinalityTerm(n[0]);
}
- if (tnc.isInterpretedFinite())
+ Trace("sets-card-debug") << "...finished register term" << std::endl;
+}
+
+void CardinalityExtension::checkFiniteTypes()
+{
+ for (std::pair<const TypeNode, bool>& pair : d_t_card_enabled)
{
- std::stringstream ss;
- ss << "ERROR: cannot use cardinality on sets with finite element "
- "type (term is "
- << n << ")." << std::endl;
- throw LogicException(ss.str());
- // TODO (#1123): extend approach for this case
+ TypeNode type = pair.first;
+ if (pair.second && type.isInterpretedFinite())
+ {
+ checkFiniteType(type);
+ }
+ }
+}
+
+void CardinalityExtension::checkFiniteType(TypeNode& t)
+{
+ Assert(t.isInterpretedFinite());
+ NodeManager* nm = NodeManager::currentNM();
+ // get the universe set (as univset (Set t))
+ Node univ = d_state.getUnivSet(nm->mkSetType(t));
+ std::map<Node, Node>::iterator it = d_univProxy.find(univ);
+ Node proxy;
+ if (it == d_univProxy.end())
+ {
+ // Force cvc4 to build the cardinality graph for the universe set
+ proxy = d_state.getProxy(univ);
+ d_univProxy[univ] = proxy;
+ }
+ else
+ {
+ proxy = it->second;
+ }
+
+ // get all equivalent classes of type t
+ vector<Node> representatives = d_state.getSetsEqClasses(t);
+ // get the cardinality of the finite type t
+ Cardinality card = t.getCardinality();
+ if (!card.isFinite())
+ {
+ // TODO (#1123): support uninterpreted sorts with --finite-model-find
+ std::stringstream message;
+ message << "The cardinality " << card << " of the finite type " << t
+ << " is not supported yet." << endl;
+ Assert(false) << message.str().c_str();
+ }
+
+ Node typeCardinality = nm->mkConst(Rational(card.getFiniteCardinality()));
+
+ Node cardUniv = nm->mkNode(kind::CARD, proxy);
+ Node leq = nm->mkNode(kind::LEQ, cardUniv, typeCardinality);
+
+ // (=> true (<= (card (as univset t)) cardUniv)
+ if (!d_state.isEntailed(leq, true))
+ {
+ d_im.assertInference(leq, d_true, "finite type cardinality", 1);
+ }
+
+ // add subset lemmas for sets, and membership lemmas for negative members
+ for (Node& representative : representatives)
+ {
+ // the universe set is a subset of itself
+ if (representative != d_ee.getRepresentative(univ))
+ {
+ // here we only add representatives with variables to avoid adding
+ // infinite equivalent generated terms to the cardinality graph
+ Node variable = d_state.getVariableSet(representative);
+ if (variable.isNull())
+ {
+ continue;
+ }
+
+ // (=> true (subset representative (as univset t))
+ Node subset = nm->mkNode(kind::SUBSET, variable, proxy);
+ // subset terms are rewritten as union terms: (subset A B) implies (=
+ // (union A B) B)
+ subset = Rewriter::rewrite(subset);
+ if (!d_state.isEntailed(subset, true))
+ {
+ d_im.assertInference(subset, d_true, "univset is a super set", 1);
+ }
+
+ // negative members are members in the universe set
+ const std::map<Node, Node>& negativeMembers =
+ d_state.getNegativeMembers(representative);
+
+ for (const std::pair<Node, Node>& negativeMember : negativeMembers)
+ {
+ Node member = nm->mkNode(MEMBER, negativeMember.first, univ);
+ // negativeMember.second is the reason for the negative membership and
+ // has kind MEMBER. So we specify the negation as the reason for the
+ // negative membership lemma
+ Node notMember = nm->mkNode(NOT, negativeMember.second);
+ // (=>
+ // (not (member negativeMember representative)))
+ // (member negativeMember (as univset t)))
+ d_im.assertInference(
+ member, notMember, "negative members are in the universe", 1);
+ }
+ }
}
- Trace("sets-card-debug") << "...finished register term" << std::endl;
}
void CardinalityExtension::check()
{
+ checkFiniteTypes();
checkRegister();
if (d_im.hasProcessed())
{
@@ -858,7 +959,8 @@ void CardinalityExtension::mkModelValueElementsFor(
Valuation& val,
Node eqc,
std::vector<Node>& els,
- const std::map<Node, Node>& mvals)
+ const std::map<Node, Node>& mvals,
+ TheoryModel* model)
{
TypeNode elementType = eqc.getType().getSetElementType();
if (isModelValueBasic(eqc))
@@ -875,9 +977,37 @@ void CardinalityExtension::mkModelValueElementsFor(
unsigned vu = v.getConst<Rational>().getNumerator().toUnsignedInt();
Assert(els.size() <= vu);
NodeManager* nm = NodeManager::currentNM();
+ if (elementType.isInterpretedFinite())
+ {
+ // get all members of this finite type
+ collectFiniteTypeSetElements(model);
+ }
while (els.size() < vu)
{
- els.push_back(nm->mkNode(SINGLETON, nm->mkSkolem("msde", elementType)));
+ if (elementType.isInterpretedFinite())
+ {
+ // At this point we are sure the formula is satisfiable and all
+ // cardinality constraints are satisfied. Since this type is finite,
+ // there is only one single cardinality graph for all sets of this
+ // type because the universe cardinality constraint has been added by
+ // CardinalityExtension::checkFiniteType. This means we have enough
+ // slack elements of this finite type for all disjoint leaves in the
+ // cardinality graph. Therefore we can safely add new distinct slack
+ // elements for the leaves without worrying about conflicts with the
+ // current members of this finite type.
+
+ Node slack = nm->mkSkolem("slack", elementType);
+ Node singleton = nm->mkNode(SINGLETON, slack);
+ els.push_back(singleton);
+ d_finite_type_slack_elements[elementType].push_back(slack);
+ Trace("sets-model") << "Added slack element " << slack << " to set "
+ << eqc << std::endl;
+ }
+ else
+ {
+ els.push_back(
+ nm->mkNode(SINGLETON, nm->mkSkolem("msde", elementType)));
+ }
}
}
else
@@ -906,6 +1036,44 @@ void CardinalityExtension::mkModelValueElementsFor(
}
}
+void CardinalityExtension::collectFiniteTypeSetElements(TheoryModel* model)
+{
+ if (d_finite_type_constants_processed)
+ {
+ return;
+ }
+ for (const Node& set : getOrderedSetsEqClasses())
+ {
+ if (!set.getType().isInterpretedFinite())
+ {
+ continue;
+ }
+ if (!isModelValueBasic(set))
+ {
+ // only consider leaves in the cardinality graph
+ continue;
+ }
+ for (const std::pair<const Node, Node>& pair : d_state.getMembers(set))
+ {
+ Node member = pair.first;
+ Node modelRepresentative = model->getRepresentative(member);
+ std::vector<Node>& elements = d_finite_type_elements[member.getType()];
+ if (std::find(elements.begin(), elements.end(), modelRepresentative)
+ == elements.end())
+ {
+ elements.push_back(modelRepresentative);
+ }
+ }
+ }
+ d_finite_type_constants_processed = true;
+}
+
+const std::vector<Node>& CardinalityExtension::getFiniteTypeMembers(
+ TypeNode typeNode)
+{
+ return d_finite_type_elements[typeNode];
+}
+
} // namespace sets
} // namespace theory
} // namespace CVC4
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback