3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-10-31 19:52:29 +00:00

Implement finite_set_decl_plugin with complete operator support and polymorphism infrastructure (#7961)

* Initial plan

* Implement finite_sets_decl_plugin with all specified operations

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* Add tests for finite_sets_decl_plugin

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* Add set.singleton operator to finite_sets_decl_plugin

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* Refactor finite_sets_decl_plugin to use polymorphic signatures and Array sorts

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* Rename finite_sets to finite_set everywhere including file names

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* Rename set.filter to set.select

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* Refactor finite_set_decl_plugin to use polymorphism_util

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* Move psig and match method to polymorphism_util

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* Add MATCH macros and fix is_fully_interp return value

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

* Add is_finite_set helper and parameter count validation

Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
This commit is contained in:
Copilot 2025-10-13 10:58:53 +02:00 committed by GitHub
parent 7356b5ff88
commit df4052ec69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 572 additions and 0 deletions

View file

@ -28,6 +28,7 @@ z3_add_component(ast
expr_map.cpp expr_map.cpp
expr_stat.cpp expr_stat.cpp
expr_substitution.cpp expr_substitution.cpp
finite_set_decl_plugin.cpp
for_each_ast.cpp for_each_ast.cpp
for_each_expr.cpp for_each_expr.cpp
format.cpp format.cpp

View file

@ -0,0 +1,192 @@
/*++
Copyright (c) 2025 Microsoft Corporation
Module Name:
finite_set_decl_plugin.cpp
Abstract:
Declaration plugin for finite sets
Author:
GitHub Copilot Agent 2025
Revision History:
--*/
#include<sstream>
#include "ast/finite_set_decl_plugin.h"
#include "ast/arith_decl_plugin.h"
#include "ast/array_decl_plugin.h"
#include "ast/polymorphism_util.h"
#include "util/warning.h"
finite_set_decl_plugin::finite_set_decl_plugin():
m_init(false) {
}
finite_set_decl_plugin::~finite_set_decl_plugin() {
for (polymorphism::psig* s : m_sigs)
dealloc(s);
}
void finite_set_decl_plugin::init() {
if (m_init) return;
ast_manager& m = *m_manager;
array_util autil(m);
m_init = true;
sort* A = m.mk_type_var(symbol("A"));
sort* B = m.mk_type_var(symbol("B"));
parameter paramA(A);
parameter paramB(B);
sort* setA = m.mk_sort(m_family_id, FINITE_SET_SORT, 1, &paramA);
sort* setB = m.mk_sort(m_family_id, FINITE_SET_SORT, 1, &paramB);
sort* boolT = m.mk_bool_sort();
sort* intT = arith_util(m).mk_int();
parameter paramInt(intT);
sort* setInt = m.mk_sort(m_family_id, FINITE_SET_SORT, 1, &paramInt);
sort* arrAB = autil.mk_array_sort(A, B);
sort* arrABool = autil.mk_array_sort(A, boolT);
sort* setAsetA[2] = { setA, setA };
sort* AsetA[2] = { A, setA };
sort* arrABsetA[2] = { arrAB, setA };
sort* arrABoolsetA[2] = { arrABool, setA };
sort* intintT[2] = { intT, intT };
m_sigs.resize(LAST_FINITE_SET_OP);
m_sigs[OP_FINITE_SET_EMPTY] = alloc(polymorphism::psig, m, "set.empty", 1, 0, nullptr, setA);
m_sigs[OP_FINITE_SET_SINGLETON] = alloc(polymorphism::psig, m, "set.singleton", 1, 1, &A, setA);
m_sigs[OP_FINITE_SET_UNION] = alloc(polymorphism::psig, m, "set.union", 1, 2, setAsetA, setA);
m_sigs[OP_FINITE_SET_INTERSECT] = alloc(polymorphism::psig, m, "set.intersect", 1, 2, setAsetA, setA);
m_sigs[OP_FINITE_SET_DIFFERENCE] = alloc(polymorphism::psig, m, "set.difference", 1, 2, setAsetA, setA);
m_sigs[OP_FINITE_SET_IN] = alloc(polymorphism::psig, m, "set.in", 1, 2, AsetA, boolT);
m_sigs[OP_FINITE_SET_SIZE] = alloc(polymorphism::psig, m, "set.size", 1, 1, &setA, intT);
m_sigs[OP_FINITE_SET_SUBSET] = alloc(polymorphism::psig, m, "set.subset", 1, 2, setAsetA, boolT);
m_sigs[OP_FINITE_SET_MAP] = alloc(polymorphism::psig, m, "set.map", 2, 2, arrABsetA, setB);
m_sigs[OP_FINITE_SET_SELECT] = alloc(polymorphism::psig, m, "set.select", 1, 2, arrABoolsetA, setA);
m_sigs[OP_FINITE_SET_RANGE] = alloc(polymorphism::psig, m, "set.range", 0, 2, intintT, setInt);
}
sort * finite_set_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
if (k == FINITE_SET_SORT) {
if (num_parameters != 1) {
m_manager->raise_exception("FiniteSet sort expects exactly one parameter (element sort)");
return nullptr;
}
if (!parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) {
m_manager->raise_exception("FiniteSet sort parameter must be a sort");
return nullptr;
}
sort * element_sort = to_sort(parameters[0].get_ast());
sort_size sz = sort_size::mk_very_big();
sort_info info(m_family_id, FINITE_SET_SORT, sz, num_parameters, parameters);
return m_manager->mk_sort(symbol("FiniteSet"), info);
}
m_manager->raise_exception("unknown finite set sort");
return nullptr;
}
bool finite_set_decl_plugin::is_finite_set(sort* s) const {
return s->get_family_id() == m_family_id && s->get_decl_kind() == FINITE_SET_SORT;
}
sort * finite_set_decl_plugin::get_element_sort(sort* finite_set_sort) const {
if (!is_finite_set(finite_set_sort)) {
return nullptr;
}
if (finite_set_sort->get_num_parameters() != 1) {
return nullptr;
}
parameter const* params = finite_set_sort->get_parameters();
if (!params[0].is_ast() || !is_sort(params[0].get_ast())) {
return nullptr;
}
return to_sort(params[0].get_ast());
}
func_decl * finite_set_decl_plugin::mk_empty(sort* element_sort) {
parameter param(element_sort);
sort * finite_set_sort = m_manager->mk_sort(m_family_id, FINITE_SET_SORT, 1, &param);
sort * const * no_domain = nullptr;
return m_manager->mk_func_decl(m_sigs[OP_FINITE_SET_EMPTY]->m_name, 0u, no_domain, finite_set_sort,
func_decl_info(m_family_id, OP_FINITE_SET_EMPTY, 1, &param));
}
func_decl * finite_set_decl_plugin::mk_finite_set_op(decl_kind k, unsigned arity, sort * const * domain, sort* range) {
ast_manager& m = *m_manager;
polymorphism::util poly_util(m);
sort_ref rng(m);
poly_util.match(*m_sigs[k], arity, domain, range, rng);
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
}
func_decl * finite_set_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
parameter const * parameters,
unsigned arity, sort * const * domain,
sort * range) {
init();
switch (k) {
case OP_FINITE_SET_EMPTY:
if (num_parameters != 1 || !parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) {
m_manager->raise_exception("set.empty requires one sort parameter");
return nullptr;
}
return mk_empty(to_sort(parameters[0].get_ast()));
case OP_FINITE_SET_SINGLETON:
case OP_FINITE_SET_UNION:
case OP_FINITE_SET_INTERSECT:
case OP_FINITE_SET_DIFFERENCE:
case OP_FINITE_SET_IN:
case OP_FINITE_SET_SIZE:
case OP_FINITE_SET_SUBSET:
case OP_FINITE_SET_MAP:
case OP_FINITE_SET_SELECT:
case OP_FINITE_SET_RANGE:
return mk_finite_set_op(k, arity, domain, range);
default:
return nullptr;
}
}
void finite_set_decl_plugin::get_op_names(svector<builtin_name>& op_names, symbol const & logic) {
init();
for (unsigned i = 0; i < m_sigs.size(); ++i) {
if (m_sigs[i])
op_names.push_back(builtin_name(m_sigs[i]->m_name.str(), i));
}
}
void finite_set_decl_plugin::get_sort_names(svector<builtin_name>& sort_names, symbol const & logic) {
sort_names.push_back(builtin_name("FiniteSet", FINITE_SET_SORT));
}
expr * finite_set_decl_plugin::get_some_value(sort * s) {
if (is_finite_set(s)) {
// Return empty set for the given sort
sort* element_sort = get_element_sort(s);
if (element_sort) {
parameter param(element_sort);
return m_manager->mk_app(m_family_id, OP_FINITE_SET_EMPTY, 1, &param, 0, nullptr);
}
}
return nullptr;
}
bool finite_set_decl_plugin::is_fully_interp(sort * s) const {
return false;
}
bool finite_set_decl_plugin::is_value(app * e) const {
// Empty set is a value
return is_app_of(e, m_family_id, OP_FINITE_SET_EMPTY);
}
bool finite_set_decl_plugin::is_unique_value(app* e) const {
// Empty set is a unique value for its sort
return is_value(e);
}

View file

@ -0,0 +1,188 @@
/*++
Copyright (c) 2025 Microsoft Corporation
Module Name:
finite_set_decl_plugin.h
Abstract:
Declaration plugin for finite sets signatures
Sort:
FiniteSet(S)
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)
set.in : S (FiniteSet S) -> Bool
set.size : (FiniteSet S) -> Int
set.subset : (FiniteSet S) (FiniteSet S) -> Bool
set.map : (S -> T) (FiniteSet S) -> (FiniteSet T)
set.select : (S -> Bool) (FiniteSet S) -> (FiniteSet S)
set.range : Int Int -> (FiniteSet Int)
--*/
#pragma once
#include "ast/ast.h"
#include "ast/polymorphism_util.h"
enum finite_set_sort_kind {
FINITE_SET_SORT
};
enum finite_set_op_kind {
OP_FINITE_SET_EMPTY,
OP_FINITE_SET_SINGLETON,
OP_FINITE_SET_UNION,
OP_FINITE_SET_INTERSECT,
OP_FINITE_SET_DIFFERENCE,
OP_FINITE_SET_IN,
OP_FINITE_SET_SIZE,
OP_FINITE_SET_SUBSET,
OP_FINITE_SET_MAP,
OP_FINITE_SET_SELECT,
OP_FINITE_SET_RANGE,
LAST_FINITE_SET_OP
};
class finite_set_decl_plugin : public decl_plugin {
ptr_vector<polymorphism::psig> m_sigs;
bool m_init;
void init();
func_decl * mk_empty(sort* element_sort);
func_decl * mk_finite_set_op(decl_kind k, unsigned arity, sort * const * domain, sort* range);
sort * get_element_sort(sort* finite_set_sort) const;
bool is_finite_set(sort* s) const;
public:
finite_set_decl_plugin();
~finite_set_decl_plugin() override;
decl_plugin * mk_fresh() override {
return alloc(finite_set_decl_plugin);
}
void finalize() override {
for (polymorphism::psig* s : m_sigs)
dealloc(s);
m_sigs.reset();
}
//
// Contract for sort:
// parameters[0] - element sort
//
sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) override;
//
// Contract for func_decl:
// For OP_FINITE_SET_MAP and OP_FINITE_SET_FILTER:
// parameters[0] - function declaration
// For others:
// no parameters
func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) override;
void get_op_names(svector<builtin_name> & op_names, symbol const & logic) override;
void get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) override;
expr * get_some_value(sort * s) override;
bool is_fully_interp(sort * s) const override;
bool is_value(app * e) const override;
bool is_unique_value(app* e) const override;
};
class finite_set_recognizers {
protected:
family_id m_fid;
public:
finite_set_recognizers(family_id fid):m_fid(fid) {}
family_id get_family_id() const { return m_fid; }
bool is_finite_set(sort* s) const { return is_sort_of(s, m_fid, FINITE_SET_SORT); }
bool is_finite_set(expr const* n) const { return is_finite_set(n->get_sort()); }
bool is_empty(expr const* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_EMPTY); }
bool is_singleton(expr const* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_SINGLETON); }
bool is_union(expr const* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_UNION); }
bool is_intersect(expr const* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_INTERSECT); }
bool is_difference(expr const* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_DIFFERENCE); }
bool is_in(expr const* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_IN); }
bool is_size(expr const* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_SIZE); }
bool is_subset(expr const* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_SUBSET); }
bool is_map(expr const* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_MAP); }
bool is_select(expr const* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_SELECT); }
bool is_range(expr const* n) const { return is_app_of(n, m_fid, OP_FINITE_SET_RANGE); }
MATCH_UNARY(is_singleton);
MATCH_UNARY(is_size);
MATCH_BINARY(is_union);
MATCH_BINARY(is_intersect);
MATCH_BINARY(is_difference);
MATCH_BINARY(is_in);
MATCH_BINARY(is_subset);
MATCH_BINARY(is_map);
MATCH_BINARY(is_select);
MATCH_BINARY(is_range);
};
class finite_set_util : public finite_set_recognizers {
ast_manager& m_manager;
public:
finite_set_util(ast_manager& m):
finite_set_recognizers(m.mk_family_id("finite_set")), m_manager(m) {}
ast_manager& get_manager() const { return m_manager; }
app * mk_empty(sort* element_sort) {
parameter param(element_sort);
return m_manager.mk_app(m_fid, OP_FINITE_SET_EMPTY, 1, &param, 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);
}
app * mk_intersect(expr* s1, expr* s2) {
return m_manager.mk_app(m_fid, OP_FINITE_SET_INTERSECT, s1, s2);
}
app * mk_difference(expr* s1, expr* s2) {
return m_manager.mk_app(m_fid, OP_FINITE_SET_DIFFERENCE, s1, s2);
}
app * mk_in(expr* elem, expr* set) {
return m_manager.mk_app(m_fid, OP_FINITE_SET_IN, elem, set);
}
app * mk_size(expr* set) {
return m_manager.mk_app(m_fid, OP_FINITE_SET_SIZE, set);
}
app * mk_subset(expr* s1, expr* s2) {
return m_manager.mk_app(m_fid, OP_FINITE_SET_SUBSET, s1, s2);
}
app * mk_map(expr* arr, expr* set) {
return m_manager.mk_app(m_fid, OP_FINITE_SET_MAP, arr, set);
}
app * mk_select(expr* arr, expr* set) {
return m_manager.mk_app(m_fid, OP_FINITE_SET_SELECT, arr, set);
}
app * mk_range(expr* low, expr* high) {
return m_manager.mk_app(m_fid, OP_FINITE_SET_RANGE, low, high);
}
};

View file

@ -350,4 +350,31 @@ namespace polymorphism {
proc proc(m, tvs); proc proc(m, tvs);
for_each_ast(proc, e, true); for_each_ast(proc, e, true);
} }
void util::match(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& range_out) {
if (dsz != sig.m_dom.size()) {
std::ostringstream strm;
strm << "Incorrect number of arguments to '" << sig.m_name << "' ";
strm << "expected " << sig.m_dom.size() << " given " << dsz;
m.raise_exception(strm.str());
}
substitution sub(m);
bool is_match = true;
for (unsigned i = 0; is_match && i < dsz; ++i) {
SASSERT(dom[i]);
is_match = sub.match(sig.m_dom.get(i), dom[i]);
}
if (range && is_match) {
is_match = sub.match(sig.m_range, range);
}
if (!is_match) {
std::ostringstream strm;
strm << "Sort mismatch for function '" << sig.m_name << "'";
m.raise_exception(strm.str());
}
// Apply substitution to get the range
range_out = sub(sig.m_range);
}
} }

View file

@ -77,6 +77,24 @@ namespace polymorphism {
}; };
typedef hashtable<substitution*, substitution::hash, substitution::eq> substitutions; typedef hashtable<substitution*, substitution::hash, substitution::eq> substitutions;
/**
* Polymorphic signature for operators
*/
struct psig {
symbol m_name;
unsigned m_num_params;
sort_ref_vector m_dom;
sort_ref m_range;
psig(ast_manager& m, char const* name, unsigned n, unsigned dsz, sort* const* dom, sort* rng):
m_name(name),
m_num_params(n),
m_dom(m),
m_range(rng, m)
{
m_dom.append(dsz, dom);
}
};
class util { class util {
ast_manager& m; ast_manager& m;
@ -99,6 +117,13 @@ namespace polymorphism {
substitution& sub); substitution& sub);
bool match(substitution& sub, sort* s1, sort* s_ground); bool match(substitution& sub, sort* s1, sort* s_ground);
/**
* Match a polymorphic signature against concrete argument sorts.
* Raises exception if arity mismatch or type mismatch.
* Returns the instantiated range sort via range_out.
*/
void match(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& range_out);
// collect instantiations of polymorphic functions // collect instantiations of polymorphic functions
void collect_poly_instances(expr* e, ptr_vector<func_decl>& instances); void collect_poly_instances(expr* e, ptr_vector<func_decl>& instances);

View file

@ -29,6 +29,7 @@ Revision History:
#include "ast/pb_decl_plugin.h" #include "ast/pb_decl_plugin.h"
#include "ast/fpa_decl_plugin.h" #include "ast/fpa_decl_plugin.h"
#include "ast/special_relations_decl_plugin.h" #include "ast/special_relations_decl_plugin.h"
#include "ast/finite_set_decl_plugin.h"
void reg_decl_plugins(ast_manager & m) { void reg_decl_plugins(ast_manager & m) {
if (!m.get_plugin(m.mk_family_id(symbol("arith")))) { if (!m.get_plugin(m.mk_family_id(symbol("arith")))) {
@ -64,4 +65,7 @@ void reg_decl_plugins(ast_manager & m) {
if (!m.get_plugin(m.mk_family_id(symbol("specrels")))) { if (!m.get_plugin(m.mk_family_id(symbol("specrels")))) {
m.register_plugin(symbol("specrels"), alloc(special_relations_decl_plugin)); m.register_plugin(symbol("specrels"), alloc(special_relations_decl_plugin));
} }
if (!m.get_plugin(m.mk_family_id(symbol("finite_set")))) {
m.register_plugin(symbol("finite_set"), alloc(finite_set_decl_plugin));
}
} }

View file

@ -54,6 +54,7 @@ add_executable(test-z3
expr_substitution.cpp expr_substitution.cpp
ext_numeral.cpp ext_numeral.cpp
f2n.cpp f2n.cpp
finite_set.cpp
factor_rewriter.cpp factor_rewriter.cpp
finder.cpp finder.cpp
fixed_bit_vector.cpp fixed_bit_vector.cpp

133
src/test/finite_set.cpp Normal file
View file

@ -0,0 +1,133 @@
/*++
Copyright (c) 2025 Microsoft Corporation
Module Name:
tst_finite_set.cpp
Abstract:
Test finite sets decl plugin
Author:
GitHub Copilot Agent 2025
Revision History:
--*/
#include "ast/ast.h"
#include "ast/finite_set_decl_plugin.h"
#include "ast/reg_decl_plugins.h"
#include "ast/arith_decl_plugin.h"
#include "ast/array_decl_plugin.h"
static void tst_finite_set_basic() {
ast_manager m;
reg_decl_plugins(m);
finite_set_util fsets(m);
arith_util arith(m);
// Test creating a finite set sort
sort_ref int_sort(arith.mk_int(), m);
parameter param(int_sort.get());
sort_ref finite_set_int(m.mk_sort(fsets.get_family_id(), FINITE_SET_SORT, 1, &param), m);
ENSURE(fsets.is_finite_set(finite_set_int.get()));
// Test creating empty set
app_ref empty_set(fsets.mk_empty(int_sort), m);
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);
app_ref range_set(fsets.mk_range(zero, ten), m);
ENSURE(fsets.is_range(range_set.get()));
ENSURE(range_set->get_sort() == finite_set_int.get());
// Test set.union
app_ref union_set(fsets.mk_union(empty_set, range_set), m);
ENSURE(fsets.is_union(union_set.get()));
ENSURE(union_set->get_sort() == finite_set_int.get());
// Test set.intersect
app_ref intersect_set(fsets.mk_intersect(range_set, range_set), m);
ENSURE(fsets.is_intersect(intersect_set.get()));
ENSURE(intersect_set->get_sort() == finite_set_int.get());
// Test set.difference
app_ref diff_set(fsets.mk_difference(range_set, empty_set), m);
ENSURE(fsets.is_difference(diff_set.get()));
ENSURE(diff_set->get_sort() == finite_set_int.get());
// Test set.in
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()));
// Test set.size
app_ref size_expr(fsets.mk_size(range_set), m);
ENSURE(fsets.is_size(size_expr.get()));
ENSURE(arith.is_int(size_expr->get_sort()));
// Test set.subset
app_ref subset_expr(fsets.mk_subset(empty_set, range_set), m);
ENSURE(fsets.is_subset(subset_expr.get()));
ENSURE(m.is_bool(subset_expr->get_sort()));
}
static void tst_finite_set_map_select() {
ast_manager m;
reg_decl_plugins(m);
finite_set_util fsets(m);
arith_util arith(m);
array_util autil(m);
// Create Int and Bool sorts
sort_ref int_sort(arith.mk_int(), m);
sort_ref bool_sort(m.mk_bool_sort(), m);
// Create finite set sorts
parameter int_param(int_sort.get());
sort_ref finite_set_int(m.mk_sort(fsets.get_family_id(), FINITE_SET_SORT, 1, &int_param), m);
// Create Array (Int Int) sort for map
sort_ref arr_int_int(autil.mk_array_sort(int_sort, int_sort), m);
// Create a const array (conceptually represents the function)
app_ref arr_map(autil.mk_const_array(arr_int_int, arith.mk_int(42)), m);
// Create a set and test map
expr_ref zero(arith.mk_int(0), m);
expr_ref ten(arith.mk_int(10), m);
app_ref range_set(fsets.mk_range(zero, ten), m);
app_ref mapped_set(fsets.mk_map(arr_map, range_set), m);
ENSURE(fsets.is_map(mapped_set.get()));
ENSURE(fsets.is_finite_set(mapped_set->get_sort()));
// Create Array (Int Bool) sort for select
sort_ref arr_int_bool(autil.mk_array_sort(int_sort, bool_sort), m);
// Create a const array for select (conceptually represents predicate)
app_ref arr_select(autil.mk_const_array(arr_int_bool, m.mk_true()), m);
app_ref selected_set(fsets.mk_select(arr_select, range_set), m);
ENSURE(fsets.is_select(selected_set.get()));
ENSURE(selected_set->get_sort() == finite_set_int.get());
}
void tst_finite_set() {
tst_finite_set_basic();
tst_finite_set_map_select();
}

View file

@ -282,4 +282,5 @@ int main(int argc, char ** argv) {
TST(scoped_vector); TST(scoped_vector);
TST(sls_seq_plugin); TST(sls_seq_plugin);
TST(ho_matcher); TST(ho_matcher);
TST(finite_set);
} }