diff --git a/src/ast/finite_sets_decl_plugin.cpp b/src/ast/finite_sets_decl_plugin.cpp index 0c23f4af9..6b70f571a 100644 --- a/src/ast/finite_sets_decl_plugin.cpp +++ b/src/ast/finite_sets_decl_plugin.cpp @@ -23,6 +23,7 @@ Revision History: finite_sets_decl_plugin::finite_sets_decl_plugin(): m_empty_sym("set.empty"), + m_singleton_sym("set.singleton"), m_union_sym("set.union"), m_intersect_sym("set.intersect"), m_difference_sym("set.difference"), @@ -96,6 +97,23 @@ func_decl * finite_sets_decl_plugin::mk_empty(sort* element_sort) { func_decl_info(m_family_id, OP_FINITE_SET_EMPTY, 1, ¶m)); } +func_decl * finite_sets_decl_plugin::mk_singleton(unsigned arity, sort * const * domain) { + if (arity != 1) { + m_manager->raise_exception("set.singleton takes exactly one argument"); + return nullptr; + } + + // The element sort is the domain + sort* element_sort = domain[0]; + + // Create the result sort: FiniteSet of the element type + parameter param(element_sort); + sort* finite_set_sort = m_manager->mk_sort(m_family_id, FINITE_SET_SORT, 1, ¶m); + + return m_manager->mk_func_decl(m_singleton_sym, arity, domain, finite_set_sort, + func_decl_info(m_family_id, OP_FINITE_SET_SINGLETON)); +} + func_decl * finite_sets_decl_plugin::mk_union(unsigned arity, sort * const * domain) { if (arity != 2) { m_manager->raise_exception("set.union takes exactly two arguments"); @@ -291,6 +309,8 @@ func_decl * finite_sets_decl_plugin::mk_func_decl(decl_kind k, unsigned num_para return nullptr; } return mk_empty(to_sort(parameters[0].get_ast())); + case OP_FINITE_SET_SINGLETON: + return mk_singleton(arity, domain); case OP_FINITE_SET_UNION: return mk_union(arity, domain); case OP_FINITE_SET_INTERSECT: @@ -324,6 +344,7 @@ func_decl * finite_sets_decl_plugin::mk_func_decl(decl_kind k, unsigned num_para void finite_sets_decl_plugin::get_op_names(svector& op_names, symbol const & logic) { op_names.push_back(builtin_name("set.empty", OP_FINITE_SET_EMPTY)); + op_names.push_back(builtin_name("set.singleton", OP_FINITE_SET_SINGLETON)); op_names.push_back(builtin_name("set.union", OP_FINITE_SET_UNION)); op_names.push_back(builtin_name("set.intersect", OP_FINITE_SET_INTERSECT)); op_names.push_back(builtin_name("set.difference", OP_FINITE_SET_DIFFERENCE)); diff --git a/src/ast/finite_sets_decl_plugin.h b/src/ast/finite_sets_decl_plugin.h index c238df34a..38e76a2df 100644 --- a/src/ast/finite_sets_decl_plugin.h +++ b/src/ast/finite_sets_decl_plugin.h @@ -13,6 +13,7 @@ Sort: Operators: set.empty : (FiniteSet S) + set.singleton : S -> (FiniteSet S) set.union : (FiniteSet S) (FiniteSet S) -> (FiniteSet S) set.intersect : (FiniteSet S) (FiniteSet S) -> (FiniteSet S) set.difference : (FiniteSet S) (FiniteSet S) -> (FiniteSet S) @@ -34,6 +35,7 @@ enum finite_sets_sort_kind { enum finite_sets_op_kind { OP_FINITE_SET_EMPTY, + OP_FINITE_SET_SINGLETON, OP_FINITE_SET_UNION, OP_FINITE_SET_INTERSECT, OP_FINITE_SET_DIFFERENCE, @@ -48,6 +50,7 @@ enum finite_sets_op_kind { class finite_sets_decl_plugin : public decl_plugin { symbol m_empty_sym; + symbol m_singleton_sym; symbol m_union_sym; symbol m_intersect_sym; symbol m_difference_sym; @@ -59,6 +62,7 @@ class finite_sets_decl_plugin : public decl_plugin { symbol m_range_sym; func_decl * mk_empty(sort* element_sort); + func_decl * mk_singleton(unsigned arity, sort * const * domain); func_decl * mk_union(unsigned arity, sort * const * domain); func_decl * mk_intersect(unsigned arity, sort * const * domain); func_decl * mk_difference(unsigned arity, sort * const * domain); @@ -116,6 +120,7 @@ public: bool is_finite_set(sort* s) const { return is_sort_of(s, m_fid, FINITE_SET_SORT); } bool is_finite_set(expr* n) const { return is_finite_set(n->get_sort()); } bool is_empty(expr* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_EMPTY); } + bool is_singleton(expr* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_SINGLETON); } bool is_union(expr* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_UNION); } bool is_intersect(expr* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_INTERSECT); } bool is_difference(expr* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_DIFFERENCE); } @@ -140,6 +145,10 @@ public: return m_manager.mk_app(m_fid, OP_FINITE_SET_EMPTY, 1, ¶m, 0, nullptr); } + app * mk_singleton(expr* elem) { + return m_manager.mk_app(m_fid, OP_FINITE_SET_SINGLETON, elem); + } + app * mk_union(expr* s1, expr* s2) { return m_manager.mk_app(m_fid, OP_FINITE_SET_UNION, s1, s2); } diff --git a/src/test/finite_sets.cpp b/src/test/finite_sets.cpp index 934541213..f89da86af 100644 --- a/src/test/finite_sets.cpp +++ b/src/test/finite_sets.cpp @@ -40,6 +40,12 @@ static void tst_finite_sets_basic() { ENSURE(fsets.is_empty(empty_set.get())); ENSURE(empty_set->get_sort() == finite_set_int.get()); + // Test set.singleton + expr_ref five(arith.mk_int(5), m); + app_ref singleton_set(fsets.mk_singleton(five), m); + ENSURE(fsets.is_singleton(singleton_set.get())); + ENSURE(singleton_set->get_sort() == finite_set_int.get()); + // Test set.range expr_ref zero(arith.mk_int(0), m); expr_ref ten(arith.mk_int(10), m); @@ -63,7 +69,6 @@ static void tst_finite_sets_basic() { ENSURE(diff_set->get_sort() == finite_set_int.get()); // Test set.in - expr_ref five(arith.mk_int(5), m); app_ref in_expr(fsets.mk_in(five, range_set), m); ENSURE(fsets.is_in(in_expr.get())); ENSURE(m.is_bool(in_expr->get_sort()));