{BAG_CARD, CVC4::Kind::BAG_CARD},
{BAG_CHOOSE, CVC4::Kind::BAG_CHOOSE},
{BAG_IS_SINGLETON, CVC4::Kind::BAG_IS_SINGLETON},
+ {BAG_FROM_SET, CVC4::Kind::BAG_FROM_SET},
+ {BAG_TO_SET, CVC4::Kind::BAG_TO_SET},
/* Strings ------------------------------------------------------------- */
{STRING_CONCAT, CVC4::Kind::STRING_CONCAT},
{STRING_IN_REGEXP, CVC4::Kind::STRING_IN_REGEXP},
{CVC4::Kind::BAG_CARD, BAG_CARD},
{CVC4::Kind::BAG_CHOOSE, BAG_CHOOSE},
{CVC4::Kind::BAG_IS_SINGLETON, BAG_IS_SINGLETON},
+ {CVC4::Kind::BAG_FROM_SET, BAG_FROM_SET},
+ {CVC4::Kind::BAG_TO_SET, BAG_TO_SET},
/* Strings --------------------------------------------------------- */
{CVC4::Kind::STRING_CONCAT, STRING_CONCAT},
{CVC4::Kind::STRING_IN_REGEXP, STRING_IN_REGEXP},
* mkTerm(Kind kind, Term child)
*/
BAG_IS_SINGLETON,
+ /**
+ * Bag.from_set converts a set to a bag.
+ * Parameters: 1
+ * -[1]: Term of set sort
+ * Create with:
+ * mkTerm(Kind kind, Term child)
+ */
+ BAG_FROM_SET,
+ /**
+ * Bag.to_set converts a bag to a set.
+ * Parameters: 1
+ * -[1]: Term of bag sort
+ * Create with:
+ * mkTerm(Kind kind, Term child)
+ */
+ BAG_TO_SET,
/* Strings --------------------------------------------------------------- */
addOperator(api::BAG_CARD, "bag.card");
addOperator(api::BAG_CHOOSE, "bag.choose");
addOperator(api::BAG_IS_SINGLETON, "bag.is_singleton");
+ addOperator(api::BAG_FROM_SET, "bag.from_set");
+ addOperator(api::BAG_TO_SET, "bag.to_set");
}
if(d_logic.isTheoryEnabled(theory::THEORY_STRINGS)) {
defineType("String", d_solver->getStringSort());
case BAG_CHOOSE: response = rewriteChoose(n); break;
case BAG_CARD: response = rewriteCard(n); break;
case BAG_IS_SINGLETON: response = rewriteIsSingleton(n); break;
+ case BAG_FROM_SET: response = rewriteFromSet(n); break;
+ case BAG_TO_SET: response = rewriteToSet(n); break;
default: response = BagsRewriteResponse(n, Rewrite::NONE); break;
}
}
return BagsRewriteResponse(n, Rewrite::NONE);
}
+BagsRewriteResponse BagsRewriter::rewriteFromSet(const TNode& n) const
+{
+ Assert(n.getKind() == BAG_FROM_SET);
+ if (n[0].getKind() == SINGLETON)
+ {
+ // (bag.from_set (singleton (singleton_op Int) x)) = (mkBag x 1)
+ Node one = d_nm->mkConst(Rational(1));
+ Node bag = d_nm->mkNode(MK_BAG, n[0][0], one);
+ return BagsRewriteResponse(bag, Rewrite::FROM_SINGLETON);
+ }
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteToSet(const TNode& n) const
+{
+ Assert(n.getKind() == BAG_TO_SET);
+ if (n[0].getKind() == MK_BAG && n[0][1].isConst()
+ && n[0][1].getConst<Rational>().sgn() == 1)
+ {
+ // (bag.to_set (mkBag x n)) = (singleton (singleton_op T) x)
+ // where n is a positive constant and T is the type of the bag's elements
+ Node bag = d_nm->mkSingleton(n[0][0].getType(), n[0][0]);
+ return BagsRewriteResponse(bag, Rewrite::TO_SINGLETON);
+ }
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
} // namespace bags
} // namespace theory
} // namespace CVC4
*/
BagsRewriteResponse rewriteIsSingleton(const TNode& n) const;
+ /**
+ * rewrites for n include:
+ * - (bag.from_set (singleton (singleton_op Int) x)) = (mkBag x 1)
+ */
+ BagsRewriteResponse rewriteFromSet(const TNode& n) const;
+
+ /**
+ * rewrites for n include:
+ * - (bag.to_set (mkBag x n)) = (singleton (singleton_op T) x)
+ * where n is a positive constant and T is the type of the bag's elements
+ */
+ BagsRewriteResponse rewriteToSet(const TNode& n) const;
+
private:
/** Reference to the rewriter statistics. */
NodeManager* d_nm;
operator BAG_IS_SINGLETON 1 "return whether the given bag is a singleton"
operator BAG_CARD 1 "bag cardinality operator"
+operator BAG_FROM_SET 1 "converts a set to a bag"
+operator BAG_TO_SET 1 "converts a bag to a set"
# The operator choose returns an element from a given bag.
# If bag A = {("a", 1)}, then the term (choose A) is equivalent to the term a.
typerule BAG_CARD ::CVC4::theory::bags::CardTypeRule
typerule BAG_CHOOSE ::CVC4::theory::bags::ChooseTypeRule
typerule BAG_IS_SINGLETON ::CVC4::theory::bags::IsSingletonTypeRule
+typerule BAG_FROM_SET ::CVC4::theory::bags::FromSetTypeRule
+typerule BAG_TO_SET ::CVC4::theory::bags::ToSetTypeRule
construle UNION_DISJOINT ::CVC4::theory::bags::BinaryOperatorTypeRule
construle MK_BAG ::CVC4::theory::bags::MkBagTypeRule
case Rewrite::CONSTANT_EVALUATION: return "CONSTANT_EVALUATION";
case Rewrite::COUNT_EMPTY: return "COUNT_EMPTY";
case Rewrite::COUNT_MK_BAG: return "COUNT_MK_BAG";
+ case Rewrite::FROM_SINGLETON: return "FROM_SINGLETON";
case Rewrite::IDENTICAL_NODES: return "IDENTICAL_NODES";
case Rewrite::INTERSECTION_EMPTY_LEFT: return "INTERSECTION_EMPTY_LEFT";
case Rewrite::INTERSECTION_EMPTY_RIGHT: return "INTERSECTION_EMPTY_RIGHT";
case Rewrite::SUBTRACT_RETURN_LEFT: return "SUBTRACT_RETURN_LEFT";
case Rewrite::SUBTRACT_SAME: return "SUBTRACT_SAME";
case Rewrite::UNION_DISJOINT_EMPTY_LEFT: return "UNION_DISJOINT_EMPTY_LEFT";
+ case Rewrite::TO_SINGLETON: return "TO_SINGLETON";
case Rewrite::UNION_DISJOINT_EMPTY_RIGHT:
return "UNION_DISJOINT_EMPTY_RIGHT";
case Rewrite::UNION_DISJOINT_MAX_MIN: return "UNION_DISJOINT_MAX_MIN";
*/
enum class Rewrite : uint32_t
{
- NONE, // no rewrite happened
+ NONE, // no rewrite happened
CARD_DISJOINT,
CARD_MK_BAG,
CHOOSE_MK_BAG,
CONSTANT_EVALUATION,
COUNT_EMPTY,
COUNT_MK_BAG,
+ FROM_SINGLETON,
IDENTICAL_NODES,
INTERSECTION_EMPTY_LEFT,
INTERSECTION_EMPTY_RIGHT,
SUBTRACT_MIN,
SUBTRACT_RETURN_LEFT,
SUBTRACT_SAME,
+ TO_SINGLETON,
UNION_DISJOINT_EMPTY_LEFT,
UNION_DISJOINT_EMPTY_RIGHT,
UNION_DISJOINT_MAX_MIN,
d_equalityEngine->addFunctionKind(BAG_COUNT);
d_equalityEngine->addFunctionKind(MK_BAG);
d_equalityEngine->addFunctionKind(BAG_CARD);
+ d_equalityEngine->addFunctionKind(BAG_FROM_SET);
+ d_equalityEngine->addFunctionKind(BAG_TO_SET);
}
void TheoryBags::postCheck(Effort level) {}
}
}; /* struct ChooseTypeRule */
+struct FromSetTypeRule
+{
+ static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ {
+ Assert(n.getKind() == kind::BAG_FROM_SET);
+ TypeNode setType = n[0].getType(check);
+ if (check)
+ {
+ if (!setType.isSet())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "bag.from_set operator expects a set, a non-set is found");
+ }
+ }
+ TypeNode elementType = setType.getSetElementType();
+ TypeNode bagType = nodeManager->mkBagType(elementType);
+ return bagType;
+ }
+}; /* struct FromSetTypeRule */
+
+struct ToSetTypeRule
+{
+ static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ {
+ Assert(n.getKind() == kind::BAG_TO_SET);
+ TypeNode bagType = n[0].getType(check);
+ if (check)
+ {
+ if (!bagType.isBag())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "bag.to_set operator expects a bag, a non-bag is found");
+ }
+ }
+ TypeNode elementType = bagType.getBagElementType();
+ TypeNode setType = nodeManager->mkSetType(elementType);
+ return setType;
+ }
+}; /* struct ToSetTypeRule */
+
struct BagsProperties
{
static Cardinality computeCardinality(TypeNode type)
&& response2.d_status == REWRITE_AGAIN_FULL);
}
+ void testFromSet()
+ {
+ Node x = d_nm->mkSkolem("x", d_nm->stringType());
+ Node singleton = d_nm->mkSingleton(d_nm->stringType(), x);
+
+ // (bag.from_set (singleton (singleton_op Int) x)) = (mkBag x 1)
+ Node n = d_nm->mkNode(BAG_FROM_SET, singleton);
+ RewriteResponse response = d_rewriter->postRewrite(n);
+ Node one = d_nm->mkConst(Rational(1));
+ Node bag = d_nm->mkNode(MK_BAG, x, one);
+ TS_ASSERT(response.d_node == bag
+ && response.d_status == REWRITE_AGAIN_FULL);
+ }
+
+ void testToSet()
+ {
+ Node x = d_nm->mkSkolem("x", d_nm->stringType());
+ Node bag = d_nm->mkNode(MK_BAG, x, d_nm->mkConst(Rational(5)));
+
+ // (bag.to_set (mkBag x n)) = (singleton (singleton_op T) x)
+ Node n = d_nm->mkNode(BAG_TO_SET, bag);
+ RewriteResponse response = d_rewriter->postRewrite(n);
+ Node singleton = d_nm->mkSingleton(d_nm->stringType(), x);
+ TS_ASSERT(response.d_node == singleton
+ && response.d_status == REWRITE_AGAIN_FULL);
+ }
+
private:
std::unique_ptr<ExprManager> d_em;
std::unique_ptr<SmtEngine> d_smt;
void testMkBagOperator()
{
vector<Node> elements = getNStrings(1);
- Node negative = d_nm->mkNode(MK_BAG, elements[0], d_nm->mkConst(Rational(-1)));
+ Node negative =
+ d_nm->mkNode(MK_BAG, elements[0], d_nm->mkConst(Rational(-1)));
Node zero = d_nm->mkNode(MK_BAG, elements[0], d_nm->mkConst(Rational(0)));
- Node positive = d_nm->mkNode(MK_BAG, elements[0], d_nm->mkConst(Rational(1)));
+ Node positive =
+ d_nm->mkNode(MK_BAG, elements[0], d_nm->mkConst(Rational(1)));
// only positive multiplicity are constants
- TS_ASSERT(! MkBagTypeRule::computeIsConst(d_nm.get(), negative));
- TS_ASSERT(! MkBagTypeRule::computeIsConst(d_nm.get(), zero));
+ TS_ASSERT(!MkBagTypeRule::computeIsConst(d_nm.get(), negative));
+ TS_ASSERT(!MkBagTypeRule::computeIsConst(d_nm.get(), zero));
TS_ASSERT(MkBagTypeRule::computeIsConst(d_nm.get(), positive));
}
+ void testFromSetOperator()
+ {
+ vector<Node> elements = getNStrings(1);
+ Node set = d_nm->mkSingleton(d_nm->stringType(), elements[0]);
+ TS_ASSERT_THROWS_NOTHING(d_nm->mkNode(BAG_FROM_SET, set));
+ TS_ASSERT(d_nm->mkNode(BAG_FROM_SET, set).getType().isBag());
+ }
+
+ void testToSetOperator()
+ {
+ vector<Node> elements = getNStrings(1);
+ Node bag = d_nm->mkNode(MK_BAG, elements[0], d_nm->mkConst(Rational(10)));
+ TS_ASSERT_THROWS_NOTHING(d_nm->mkNode(BAG_TO_SET, bag));
+ TS_ASSERT(d_nm->mkNode(BAG_TO_SET, bag).getType().isSet());
+ }
+
private:
std::unique_ptr<ExprManager> d_em;
std::unique_ptr<SmtEngine> d_smt;