z3-z3-4.13.0.src.ast.array_decl_plugin.cpp Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
array_decl_plugin.cpp
Abstract:
Author:
Leonardo de Moura (leonardo) 2008-01-09
Revision History:
--*/
#include
#include "ast/array_decl_plugin.h"
#include "util/warning.h"
#include "ast/ast_pp.h"
#include "ast/ast_ll_pp.h"
#include "ast/arith_decl_plugin.h"
array_decl_plugin::array_decl_plugin():
m_store_sym("store"),
m_select_sym("select"),
m_const_sym("const"),
m_default_sym("default"),
m_map_sym("map"),
m_set_union_sym("union"),
m_set_intersect_sym("intersection"),
m_set_difference_sym("setminus"),
m_set_complement_sym("complement"),
m_set_subset_sym("subset"),
m_array_ext_sym("array-ext"),
m_as_array_sym("as-array"),
m_set_has_size_sym("set-has-size"),
m_set_card_sym("card") {
}
#define ARRAY_SORT_STR "Array"
sort * array_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
if (k == _SET_SORT) {
if (num_parameters != 1) {
m_manager->raise_exception("invalid array sort definition, invalid number of parameters");
return nullptr;
}
parameter params[2] = { parameter(parameters[0]), parameter(m_manager->mk_bool_sort()) };
return mk_sort(ARRAY_SORT, 2, params);
}
SASSERT(k == ARRAY_SORT);
if (num_parameters < 2) {
m_manager->raise_exception("invalid array sort definition, invalid number of parameters");
return nullptr;
}
for (unsigned i = 0; i < num_parameters; i++) {
if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast())) {
m_manager->raise_exception("invalid array sort definition, parameter is not a sort");
return nullptr;
}
}
sort * range = to_sort(parameters[num_parameters - 1].get_ast());
TRACE("array_decl_plugin_bug", tout << mk_pp(range, *m_manager) << "\n";);
if (!range->is_infinite() && !range->is_very_big() && (1 == range->get_num_elements().size())) {
return m_manager->mk_sort(symbol(ARRAY_SORT_STR), sort_info(m_family_id, ARRAY_SORT, 1,
num_parameters, parameters));
}
bool is_infinite = false;
bool is_very_big = false;
for (unsigned i = 0; i < num_parameters; i++) {
sort * s = to_sort(parameters[i].get_ast());
if (s->is_infinite()) {
is_infinite = true;
}
if (s->is_very_big()) {
is_very_big = true;
}
}
if (is_infinite) {
return m_manager->mk_sort(symbol(ARRAY_SORT_STR), sort_info(m_family_id, ARRAY_SORT, num_parameters, parameters));
}
else if (is_very_big) {
return m_manager->mk_sort(symbol(ARRAY_SORT_STR), sort_info(m_family_id, ARRAY_SORT, sort_size::mk_very_big(),
num_parameters, parameters));
}
else {
rational domain_sz(1);
rational num_elements;
for (unsigned i = 0; i < num_parameters - 1; i++) {
domain_sz *= rational(to_sort(parameters[i].get_ast())->get_num_elements().size(),rational::ui64());
}
if (domain_sz <= rational(128)) {
num_elements = rational(range->get_num_elements().size(),rational::ui64());
num_elements = power(num_elements, static_cast(domain_sz.get_int64()));
}
if (domain_sz > rational(128) || !num_elements.is_uint64()) {
// too many elements...
return m_manager->mk_sort(symbol(ARRAY_SORT_STR),
sort_info(m_family_id,
ARRAY_SORT,
sort_size::mk_very_big(),
num_parameters,
parameters));
}
else {
return m_manager->mk_sort(symbol(ARRAY_SORT_STR), sort_info(m_family_id, ARRAY_SORT, num_elements.get_uint64(),
num_parameters, parameters));
}
}
}
bool array_decl_plugin::is_array_sort(sort* s) const {
return m_family_id == s->get_family_id() && s->get_decl_kind() == ARRAY_SORT;
}
func_decl * array_decl_plugin::mk_const(sort * s, unsigned arity, sort * const * domain) {
if (arity != 1) {
m_manager->raise_exception("invalid const array definition, expected one argument");
return nullptr;
}
if (!is_array_sort(s)) {
m_manager->raise_exception("invalid const array definition, parameter is not an array sort");
return nullptr;
}
if (get_array_range(s) != domain[0]) {
m_manager->raise_exception("invalid const array definition, sort mismatch between array range and argument");
return nullptr;
}
parameter param(s);
func_decl_info info(m_family_id, OP_CONST_ARRAY, 1, ¶m);
info.m_private_parameters = true;
return m_manager->mk_func_decl(m_const_sym, arity, domain, s, info);
}
func_decl * array_decl_plugin::mk_map(func_decl* f, unsigned arity, sort* const* domain) {
if (arity != f->get_arity()) {
std::ostringstream buffer;
buffer << "map expects to take as many arguments as the function being mapped, "
<< "it was given " << arity << " but expects " << f->get_arity();
m_manager->raise_exception(buffer.str());
return nullptr;
}
if (arity == 0) {
m_manager->raise_exception("don't use map on constants");
return nullptr;
}
//
// check that each domain[i] is an array sort
// with the same domains and same ranges.
// and that the ranges coincide with the domain of f.
//
unsigned dom_arity = get_array_arity(domain[0]);
for (unsigned i = 0; i < arity; ++i) {
if (!is_array_sort(domain[i])) {
std::ostringstream buffer;
buffer << "map expects an array sort as argument at position " << i;
m_manager->raise_exception(buffer.str());
return nullptr;
}
if (get_array_arity(domain[i]) != dom_arity) {
std::ostringstream buffer;
buffer << "map expects all arguments to have the same array domain, "
<< "this is not the case for argument " << i;
m_manager->raise_exception(buffer.str());
return nullptr;
}
for (unsigned j = 0; j < dom_arity; ++j) {
if (get_array_domain(domain[i],j) != get_array_domain(domain[0],j)) {
std::ostringstream buffer;
buffer << "map expects all arguments to have the same array domain, "
<< "this is not the case for argument " << i;
m_manager->raise_exception(buffer.str());
return nullptr;
}
}
if (get_array_range(domain[i]) != f->get_domain(i)) {
std::ostringstream buffer;
buffer << "map expects the argument at position " << i
<< " to have the array range the same as the function";
m_manager->raise_exception(buffer.str());
return nullptr;
}
}
vector parameters;
for (unsigned i = 0; i < dom_arity; ++i) {
parameters.push_back(domain[0]->get_parameter(i));
}
parameters.push_back(parameter(f->get_range()));
sort* range = mk_sort(ARRAY_SORT, parameters.size(), parameters.data());
parameter param(f);
func_decl_info info(m_family_id, OP_ARRAY_MAP, 1, ¶m);
//
// left_associative, right_associative, commutative are inherited.
// m_injective is inherited, since:
// forall x . g(f(x)) = x implies forall X . map(g)(map(f)(X)) = X
// since map(g)(map(f)(X))[i] = g(f(X[i])) = X[i]
//
info.set_right_associative(f->is_right_associative());
info.set_left_associative(f->is_left_associative());
info.set_commutative(f->is_commutative());
info.set_injective(f->is_injective());
return m_manager->mk_func_decl(m_map_sym, arity, domain, range, info);
}
func_decl * array_decl_plugin::mk_default(unsigned domain_size, sort * const * domain) {
if (domain_size != 1) {
m_manager->raise_exception("invalid default array definition, invalid domain size");
return nullptr;
}
// check that domain[0] is an array sort.
unsigned num_parameters = domain[0]->get_num_parameters();
if (num_parameters <= 1) {
m_manager->raise_exception("parameter mismatch. There should be more than one parameter to defaults");
return nullptr;
}
parameter param(domain[0]->get_parameter(num_parameters-1));
if (!param.is_ast() || !is_sort(param.get_ast())) {
m_manager->raise_exception("last parameter should be a sort");
return nullptr;
}
sort * s = to_sort(param.get_ast());
return m_manager->mk_func_decl(m_default_sym, domain_size, domain, s,
func_decl_info(m_family_id, OP_ARRAY_DEFAULT));
}
func_decl* array_decl_plugin::mk_select(unsigned arity, sort * const * domain) {
if (arity <= 1) {
m_manager->raise_exception("select takes at least two arguments");
return nullptr;
}
sort * s = domain[0];
unsigned num_parameters = s->get_num_parameters();
parameter const* parameters = s->get_parameters();
if (num_parameters != arity) {
std::stringstream strm;
strm << "select requires " << num_parameters << " arguments, but was provided with " << arity << " arguments";
m_manager->raise_exception(strm.str());
return nullptr;
}
ptr_buffer new_domain; // we need this because of coercions.
new_domain.push_back(s);
for (unsigned i = 0; i + 1 < num_parameters; ++i) {
if (!parameters[i].is_ast() ||
!is_sort(parameters[i].get_ast()) ||
!m_manager->compatible_sorts(domain[i+1], to_sort(parameters[i].get_ast()))) {
std::stringstream strm;
strm << "domain sort " << sort_ref(domain[i+1], *m_manager) << " and parameter ";
strm << parameter_pp(parameters[i], *m_manager) << " do not match";
m_manager->raise_exception(strm.str());
return nullptr;
}
new_domain.push_back(to_sort(parameters[i].get_ast()));
}
SASSERT(new_domain.size() == arity);
return m_manager->mk_func_decl(m_select_sym, arity, new_domain.data(), get_array_range(domain[0]),
func_decl_info(m_family_id, OP_SELECT));
}
func_decl * array_decl_plugin::mk_store(unsigned arity, sort * const * domain) {
if (arity < 3) {
m_manager->raise_exception("store takes at least 3 arguments");
return nullptr;
}
sort * s = domain[0];
unsigned num_parameters = s->get_num_parameters();
parameter const * parameters = s->get_parameters();
if (!is_array_sort(s)) {
m_manager->raise_exception("store expects the first argument sort to be an array");
UNREACHABLE();
return nullptr;
}
if (arity != num_parameters+1) {
std::ostringstream buffer;
buffer << "store expects the first argument to be an array taking " << num_parameters+1
<< ", instead it was passed " << (arity - 1) << "arguments";
m_manager->raise_exception(buffer.str());
UNREACHABLE();
return nullptr;
}
ptr_buffer new_domain; // we need this because of coercions.
new_domain.push_back(s);
for (unsigned i = 0; i < num_parameters; ++i) {
if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast())) {
m_manager->raise_exception("expecting sort parameter");
return nullptr;
}
sort* srt1 = to_sort(parameters[i].get_ast());
sort* srt2 = domain[i+1];
if (!m_manager->compatible_sorts(srt1, srt2)) {
std::stringstream strm;
strm << "domain sort " << sort_ref(srt2, *m_manager) << " and parameter sort " << sort_ref(srt1, *m_manager) << " do not match";
m_manager->raise_exception(strm.str());
UNREACHABLE();
return nullptr;
}
new_domain.push_back(to_sort(parameters[i].get_ast()));
}
SASSERT(new_domain.size() == arity);
return m_manager->mk_func_decl(m_store_sym, arity, new_domain.data(), domain[0],
func_decl_info(m_family_id, OP_STORE));
}
func_decl * array_decl_plugin::mk_array_ext(unsigned arity, sort * const * domain, unsigned i) {
if (arity != 2 || domain[0] != domain[1]) {
m_manager->raise_exception("incorrect arguments passed to array-ext");
return nullptr;
}
sort * s = domain[0];
unsigned num_parameters = s->get_num_parameters();
if (num_parameters == 0 || i >= num_parameters - 1) {
m_manager->raise_exception("incorrect arguments passed to array-ext");
return nullptr;
}
sort * r = to_sort(s->get_parameter(i).get_ast());
parameter param(i);
func_decl_info info(func_decl_info(m_family_id, OP_ARRAY_EXT, 1, ¶m));
info.set_commutative(true);
return m_manager->mk_func_decl(m_array_ext_sym, arity, domain, r, info);
}
bool array_decl_plugin::check_set_arguments(unsigned arity, sort * const * domain) {
for (unsigned i = 0; i < arity; ++i) {
if (domain[i] != domain[0]) {
std::ostringstream buffer;
buffer << "arguments " << 1 << " and " << (i+1) << " have different sorts";
m_manager->raise_exception(buffer.str());
return false;
}
if (domain[i]->get_family_id() != m_family_id) {
std::ostringstream buffer;
buffer << "argument " << (i+1) << " is not of array sort";
m_manager->raise_exception(buffer.str());
return false;
}
}
if (arity > 0) {
unsigned num_params = domain[0]->get_num_parameters();
parameter const* params = domain[0]->get_parameters();
if (1 >= num_params) {
m_manager->raise_exception("expecting 2 or more parameters");
UNREACHABLE();
return false;
}
if (!params[num_params-1].is_ast()) {
m_manager->raise_exception("expecting term parameters");
UNREACHABLE();
return false;
}
if (!is_sort(params[num_params-1].get_ast()) || !m_manager->is_bool(to_sort(params[num_params-1].get_ast()))) {
m_manager->raise_exception("expecting boolean range");
UNREACHABLE();
return false;
}
}
return true;
}
func_decl * array_decl_plugin::mk_set_union(unsigned arity, sort * const * domain) {
if (arity == 0) {
m_manager->raise_exception("union takes at least one argument");
return nullptr;
}
sort * s = domain[0];
if (!check_set_arguments(arity, domain)) {
return nullptr;
}
parameter param(s);
func_decl_info info(m_family_id, OP_SET_UNION, 1, ¶m);
info.set_associative();
info.set_commutative();
info.set_idempotent();
sort* domain2[2] = { domain[0], domain[0] };
return m_manager->mk_func_decl(m_set_union_sym, 2, domain2, domain[0], info);
}
func_decl * array_decl_plugin::mk_set_intersect(unsigned arity, sort * const * domain) {
if (arity == 0) {
m_manager->raise_exception("intersection takes at least one argument");
return nullptr;
}
if (!check_set_arguments(arity, domain)) {
return nullptr;
}
func_decl_info info(m_family_id, OP_SET_INTERSECT);
info.set_associative();
info.set_commutative();
info.set_idempotent();
sort* domain2[2] = { domain[0], domain[0] };
return m_manager->mk_func_decl(m_set_intersect_sym, 2, domain2, domain[0], info);
}
func_decl * array_decl_plugin::mk_set_difference(unsigned arity, sort * const * domain) {
if (arity != 2) {
m_manager->raise_exception("set difference takes precisely two arguments");
return nullptr;
}
if (!check_set_arguments(arity, domain)) {
return nullptr;
}
return m_manager->mk_func_decl(m_set_difference_sym, arity, domain, domain[0],
func_decl_info(m_family_id, OP_SET_DIFFERENCE));
}
func_decl * array_decl_plugin::mk_set_complement(unsigned arity, sort * const * domain) {
if (arity != 1) {
m_manager->raise_exception("set complement takes one argument");
return nullptr;
}
if (!check_set_arguments(arity, domain)) {
return nullptr;
}
return m_manager->mk_func_decl(m_set_complement_sym, arity, domain, domain[0],
func_decl_info(m_family_id, OP_SET_COMPLEMENT));
}
func_decl * array_decl_plugin::mk_set_subset(unsigned arity, sort * const * domain) {
if (arity != 2) {
m_manager->raise_exception("subset takes two arguments");
return nullptr;
}
if (!check_set_arguments(arity, domain)) {
return nullptr;
}
sort * bool_sort = m_manager->mk_bool_sort();
return m_manager->mk_func_decl(m_set_subset_sym, arity, domain, bool_sort,
func_decl_info(m_family_id, OP_SET_SUBSET));
}
func_decl * array_decl_plugin::mk_set_card(unsigned arity, sort * const* domain) {
if (arity != 1) {
m_manager->raise_exception("card takes only one argument");
return nullptr;
}
arith_util arith(*m_manager);
if (!is_array_sort(domain[0]) || !m_manager->is_bool(get_array_range(domain[0]))) {
m_manager->raise_exception("card expects an array of Booleans");
}
sort * int_sort = arith.mk_int();
return m_manager->mk_func_decl(m_set_card_sym, arity, domain, int_sort,
func_decl_info(m_family_id, OP_SET_CARD));
}
func_decl * array_decl_plugin::mk_set_has_size(unsigned arity, sort * const* domain) {
if (arity != 2) {
m_manager->raise_exception("set-has-size takes two arguments");
return nullptr;
}
m_manager->raise_exception("set-has-size is not supported");
// domain[0] is a Boolean array,
// domain[1] is Int
arith_util arith(*m_manager);
if (!arith.is_int(domain[1])) {
m_manager->raise_exception("set-has-size expects second argument to be an integer");
}
if (!is_array_sort(domain[0]) || !m_manager->is_bool(get_array_range(domain[0]))) {
m_manager->raise_exception("set-has-size expects first argument to be an array of Booleans");
}
sort * bool_sort = m_manager->mk_bool_sort();
return m_manager->mk_func_decl(m_set_has_size_sym, arity, domain, bool_sort,
func_decl_info(m_family_id, OP_SET_HAS_SIZE));
}
func_decl * array_decl_plugin::mk_as_array(func_decl * f) {
vector parameters;
for (unsigned i = 0; i < f->get_arity(); i++) {
parameters.push_back(parameter(f->get_domain(i)));
}
parameters.push_back(parameter(f->get_range()));
sort * s = mk_sort(ARRAY_SORT, parameters.size(), parameters.data());
parameter param(f);
func_decl_info info(m_family_id, OP_AS_ARRAY, 1, ¶m);
return m_manager->mk_const_decl(m_as_array_sym, s, info);
}
func_decl * array_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
switch (k) {
case OP_SELECT:
return mk_select(arity, domain);
case OP_STORE:
return mk_store(arity, domain);
case OP_CONST_ARRAY: {
if (num_parameters == 1 && parameters[0].is_ast() && is_sort(parameters[0].get_ast())) {
sort * s = to_sort(parameters[0].get_ast());
return mk_const(s, arity, domain);
}
else if (range != nullptr) {
return mk_const(range, arity, domain);
}
else {
m_manager->raise_exception("array operation requires one sort parameter (the array sort)");
UNREACHABLE();
return nullptr;
}
}
case OP_ARRAY_MAP: {
if (num_parameters != 1 || !parameters[0].is_ast() || !is_func_decl(parameters[0].get_ast())) {
m_manager->raise_exception("array operation requires one function declaration parameter (the function to be mapped)");
UNREACHABLE();
return nullptr;
}
func_decl * f = to_func_decl(parameters[0].get_ast());
return mk_map(f, arity, domain);
}
case OP_ARRAY_EXT:
if (num_parameters == 0) {
return mk_array_ext(arity, domain, 0);
}
if (num_parameters != 1 || !parameters[0].is_int()) {
UNREACHABLE();
return nullptr;
}
return mk_array_ext(arity, domain, parameters[0].get_int());
case OP_ARRAY_DEFAULT:
return mk_default(arity, domain);
case OP_SET_UNION:
return mk_set_union(arity, domain);
case OP_SET_INTERSECT:
return mk_set_intersect(arity, domain);
case OP_SET_DIFFERENCE:
return mk_set_difference(arity, domain);
case OP_SET_COMPLEMENT:
return mk_set_complement(arity, domain);
case OP_SET_SUBSET:
return mk_set_subset(arity, domain);
case OP_SET_HAS_SIZE:
return mk_set_has_size(arity, domain);
case OP_SET_CARD:
return mk_set_card(arity, domain);
case OP_AS_ARRAY: {
if (num_parameters != 1 ||
!parameters[0].is_ast() ||
!is_func_decl(parameters[0].get_ast()) ||
to_func_decl(parameters[0].get_ast())->get_arity() == 0) {
TRACE("array_bug",
tout << "num_parameters: " << num_parameters << std::endl;
tout << "parameter.kind: " << parameters[0].is_int() << " " << parameters[0].is_ast() << " " << parameters[0].is_symbol() << "\n";
tout << "as-array-bug: " << to_func_decl(parameters[0].get_ast())->get_name() << " " << to_func_decl(parameters[0].get_ast())->get_arity() << std::endl;);
m_manager->raise_exception("as-array takes one parameter, a function declaration with arity greater than zero");
UNREACHABLE();
return nullptr;
}
func_decl * f = to_func_decl(parameters[0].get_ast());
return mk_as_array(f);
}
default: return nullptr;
}
}
void array_decl_plugin::get_sort_names(svector& sort_names, symbol const & logic) {
sort_names.push_back(builtin_name(ARRAY_SORT_STR, ARRAY_SORT));
sort_names.push_back(builtin_name("=>", ARRAY_SORT));
if (logic == symbol::null || logic == symbol("HORN") || logic == symbol("ALL")) {
// this could easily break users even though it is already used in CVC4:
sort_names.push_back(builtin_name("Set", _SET_SORT));
}
}
void array_decl_plugin::get_op_names(svector& op_names, symbol const & logic) {
op_names.push_back(builtin_name("store",OP_STORE));
op_names.push_back(builtin_name("select",OP_SELECT));
if (logic == symbol::null || logic == symbol("HORN") || logic == symbol("ALL")) {
// none of the SMT2 logics support these extensions
op_names.push_back(builtin_name("const",OP_CONST_ARRAY));
op_names.push_back(builtin_name("map",OP_ARRAY_MAP));
op_names.push_back(builtin_name("default",OP_ARRAY_DEFAULT));
op_names.push_back(builtin_name("union",OP_SET_UNION));
op_names.push_back(builtin_name("intersection",OP_SET_INTERSECT));
op_names.push_back(builtin_name("setminus",OP_SET_DIFFERENCE));
op_names.push_back(builtin_name("complement",OP_SET_COMPLEMENT));
op_names.push_back(builtin_name("subset",OP_SET_SUBSET));
op_names.push_back(builtin_name("as-array", OP_AS_ARRAY));
op_names.push_back(builtin_name("array-ext", OP_ARRAY_EXT));
#if 0
op_names.push_back(builtin_name("set-has-size", OP_SET_HAS_SIZE));
op_names.push_back(builtin_name("card", OP_SET_CARD));
#endif
}
}
expr * array_decl_plugin::get_some_value(sort * s) {
SASSERT(s->is_sort_of(m_family_id, ARRAY_SORT));
sort * r = to_sort(s->get_parameter(s->get_num_parameters() - 1).get_ast());
expr * v = m_manager->get_some_value(r);
parameter p(s);
return m_manager->mk_app(m_family_id, OP_CONST_ARRAY, 1, &p, 1, &v);
}
bool array_decl_plugin::is_fully_interp(sort * s) const {
SASSERT(s->is_sort_of(m_family_id, ARRAY_SORT));
unsigned sz = get_array_arity(s);
for (unsigned i = 0; i < sz; i++) {
if (!m_manager->is_fully_interp(get_array_domain(s, i)))
return false;
}
return m_manager->is_fully_interp(get_array_range(s));
}
bool array_decl_plugin::is_value(app * _e) const {
expr* e = _e;
array_util u(*m_manager);
while (true) {
if (u.is_const(e, e))
return m_manager->is_value(e);
if (u.is_store(e)) {
for (unsigned i = 1; i < to_app(e)->get_num_args(); ++i)
if (!m_manager->is_value(to_app(e)->get_arg(i)))
return false;
e = to_app(e)->get_arg(0);
continue;
}
return false;
}
}
bool array_decl_plugin::is_unique_value(app* _e) const {
array_util u(*m_manager);
expr* e = _e;
return u.is_const(e, e) && m_manager->is_unique_value(e);
}
func_decl * array_recognizers::get_as_array_func_decl(expr * n) const {
SASSERT(is_as_array(n));
return to_func_decl(to_app(n)->get_decl()->get_parameter(0).get_ast());
}
func_decl * array_recognizers::get_map_func_decl(func_decl* f) const {
SASSERT(f->get_num_parameters() == 1);
SASSERT(f->get_parameter(0).is_ast());
SASSERT(is_func_decl(f->get_parameter(0).get_ast()));
return to_func_decl(f->get_parameter(0).get_ast());
}
func_decl * array_recognizers::get_as_array_func_decl(func_decl * f) const {
SASSERT(is_as_array(f));
return to_func_decl(f->get_parameter(0).get_ast());
}
bool array_recognizers::is_const(expr* e, expr*& v) const {
return is_const(e) && (v = to_app(e)->get_arg(0), true);
}
bool array_recognizers::is_store_ext(expr* _e, expr_ref& a, expr_ref_vector& args, expr_ref& value) {
if (is_store(_e)) {
app* e = to_app(_e);
a = e->get_arg(0);
unsigned sz = e->get_num_args();
args.reset();
for (unsigned i = 1; i < sz-1; ++i) {
args.push_back(e->get_arg(i));
}
value = e->get_arg(sz-1);
return true;
}
return false;
}
array_util::array_util(ast_manager& m):
array_recognizers(m.mk_family_id("array")),
m_manager(m) {
}
bool array_util::is_as_array_tree(expr * n) {
ptr_buffer todo;
todo.push_back(n);
while (!todo.empty()) {
expr * curr = todo.back();
todo.pop_back();
if (is_as_array(curr))
continue;
if (m_manager.is_ite(curr)) {
todo.push_back(to_app(curr)->get_arg(1));
todo.push_back(to_app(curr)->get_arg(2));
continue;
}
return false;
}
return true;
}
sort * array_util::mk_array_sort(unsigned arity, sort* const* domain, sort* range) {
vector params;
for (unsigned i = 0; i < arity; ++i) {
params.push_back(parameter(domain[i]));
}
params.push_back(parameter(range));
return m_manager.mk_sort(m_fid, ARRAY_SORT, params.size(), params.data());
}
func_decl* array_util::mk_array_ext(sort *domain, unsigned i) {
sort * domains[2] = { domain, domain };
parameter p(i);
return m_manager.mk_func_decl(m_fid, OP_ARRAY_EXT, 1, &p, 2, domains);
}