3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-13 12:28:44 +00:00

Merge pull request #1226 from NikolajBjorner/master

removing dependencies on simplifier, support SMTLIB2 parametric algebraic datatypes.
This is a breaking change. It introduces two substantial changes:
1. The legacy simplifier is removed. It was obsoleted with the introduction of the rewriter facilities, but many dependencies made it a major change to remove the legacy simplifier. All uses of the legacy simplifier have now been replaced by corresponding calls to the rewriter. It means that some normalization may behave differently. At this point, Z3 passes regressions and passes performance tests without regressing.
2. Algebraic datatypes in the form of SMT-LIB2.6 are now supported. These generalize the datatypes supported so far as parametric datatype constructors may be applied to different arguments within a recursive definition.
This commit is contained in:
Nikolaj Bjorner 2017-09-11 00:40:51 +03:00 committed by GitHub
commit 77008dc411
198 changed files with 5392 additions and 12493 deletions

View file

@ -470,7 +470,7 @@ void unsat_core_example2() {
// The solver s already contains p1 => F
// To disable F, we add (not p1) as an additional assumption
qs.push_back(!p1);
std::cout << s.check(qs.size(), &qs[0]) << "\n";
std::cout << s.check((unsigned)qs.size(), &qs[0]) << "\n";
expr_vector core2 = s.unsat_core();
std::cout << core2 << "\n";
std::cout << "size: " << core2.size() << "\n";

View file

@ -23,10 +23,7 @@ def init_project_def():
add_lib('subpaving', ['interval'], 'math/subpaving')
add_lib('ast', ['util', 'polynomial'])
add_lib('rewriter', ['ast', 'polynomial', 'automata'], 'ast/rewriter')
# Simplifier module will be deleted in the future.
# It has been replaced with rewriter module.
add_lib('simplifier', ['rewriter'], 'ast/simplifier')
add_lib('macros', ['simplifier'], 'ast/macros')
add_lib('macros', ['rewriter'], 'ast/macros')
add_lib('normal_forms', ['rewriter'], 'ast/normal_forms')
add_lib('model', ['rewriter'])
add_lib('tactic', ['ast', 'model'])
@ -47,11 +44,11 @@ def init_project_def():
add_lib('extra_cmds', ['cmd_context', 'subpaving_tactic', 'arith_tactics'], 'cmd_context/extra_cmds')
add_lib('smt2parser', ['cmd_context', 'parser_util'], 'parsers/smt2')
add_lib('proof_checker', ['rewriter'], 'ast/proof_checker')
add_lib('fpa', ['ast', 'util', 'simplifier', 'model'], 'ast/fpa')
add_lib('pattern', ['normal_forms', 'smt2parser', 'simplifier'], 'ast/pattern')
add_lib('bit_blaster', ['rewriter', 'simplifier'], 'ast/rewriter/bit_blaster')
add_lib('smt_params', ['ast', 'simplifier', 'pattern', 'bit_blaster'], 'smt/params')
add_lib('proto_model', ['model', 'simplifier', 'smt_params'], 'smt/proto_model')
add_lib('fpa', ['ast', 'util', 'rewriter', 'model'], 'ast/fpa')
add_lib('pattern', ['normal_forms', 'smt2parser', 'rewriter'], 'ast/pattern')
add_lib('bit_blaster', ['rewriter', 'rewriter'], 'ast/rewriter/bit_blaster')
add_lib('smt_params', ['ast', 'rewriter', 'pattern', 'bit_blaster'], 'smt/params')
add_lib('proto_model', ['model', 'rewriter', 'smt_params'], 'smt/proto_model')
add_lib('smt', ['bit_blaster', 'macros', 'normal_forms', 'cmd_context', 'proto_model',
'substitution', 'grobner', 'euclid', 'simplex', 'proof_checker', 'pattern', 'parser_util', 'fpa', 'lp'])
add_lib('bv_tactics', ['tactic', 'bit_blaster', 'core_tactics'], 'tactic/bv')

View file

@ -68,9 +68,6 @@ add_subdirectory(cmd_context)
add_subdirectory(cmd_context/extra_cmds)
add_subdirectory(parsers/smt2)
add_subdirectory(ast/proof_checker)
## Simplifier module will be deleted in the future.
## It has been replaced with rewriter component.
add_subdirectory(ast/simplifier)
add_subdirectory(ast/fpa)
add_subdirectory(ast/macros)
add_subdirectory(ast/pattern)

View file

@ -150,8 +150,9 @@ namespace api {
void context::set_error_code(Z3_error_code err) {
m_error_code = err;
if (err != Z3_OK)
if (err != Z3_OK) {
invoke_error_handler(err);
}
}
void context::check_searching() {

View file

@ -45,13 +45,13 @@ extern "C" {
ptr_vector<accessor_decl> acc;
for (unsigned i = 0; i < num_fields; ++i) {
acc.push_back(mk_accessor_decl(to_symbol(field_names[i]), type_ref(to_sort(field_sorts[i]))));
acc.push_back(mk_accessor_decl(m, to_symbol(field_names[i]), type_ref(to_sort(field_sorts[i]))));
}
constructor_decl* constrs[1] = { mk_constructor_decl(to_symbol(name), recognizer, acc.size(), acc.c_ptr()) };
{
datatype_decl * dt = mk_datatype_decl(to_symbol(name), 1, constrs);
datatype_decl * dt = mk_datatype_decl(dt_util, to_symbol(name), 0, nullptr, 1, constrs);
bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &dt, 0, 0, tuples);
del_datatype_decl(dt);
@ -69,18 +69,13 @@ extern "C" {
// create constructor
SASSERT(dt_util.is_datatype(tuple));
SASSERT(!dt_util.is_recursive(tuple));
ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(tuple);
func_decl* decl = (*decls)[0];
ptr_vector<func_decl> const & decls = *dt_util.get_datatype_constructors(tuple);
func_decl* decl = (decls)[0];
mk_c(c)->save_multiple_ast_trail(decl);
*mk_tuple_decl = of_func_decl(decl);
// Create projections
ptr_vector<func_decl> const * accs = dt_util.get_constructor_accessors(decl);
if (!accs) {
SET_ERROR_CODE(Z3_INVALID_ARG);
RETURN_Z3(0);
}
ptr_vector<func_decl> const & _accs = *accs;
ptr_vector<func_decl> const & _accs = *dt_util.get_constructor_accessors(decl);
SASSERT(_accs.size() == num_fields);
for (unsigned i = 0; i < _accs.size(); i++) {
mk_c(c)->save_multiple_ast_trail(_accs[i]);
@ -118,7 +113,7 @@ extern "C" {
{
datatype_decl * dt = mk_datatype_decl(to_symbol(name), n, constrs.c_ptr());
datatype_decl * dt = mk_datatype_decl(dt_util, to_symbol(name), 0, 0, n, constrs.c_ptr());
bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &dt, 0, 0, sorts);
del_datatype_decl(dt);
@ -136,10 +131,10 @@ extern "C" {
// create constructor
SASSERT(dt_util.is_datatype(e));
SASSERT(!dt_util.is_recursive(e));
ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(e);
SASSERT(decls && decls->size() == n);
ptr_vector<func_decl> const & decls = *dt_util.get_datatype_constructors(e);
SASSERT(decls.size() == n);
for (unsigned i = 0; i < n; ++i) {
func_decl* decl = (*decls)[i];
func_decl* decl = (decls)[i];
mk_c(c)->save_multiple_ast_trail(decl);
enum_consts[i] = of_func_decl(decl);
decl = dt_util.get_constructor_recognizer(decl);
@ -165,11 +160,12 @@ extern "C" {
LOG_Z3_mk_list_sort(c, name, elem_sort, nil_decl, is_nil_decl, cons_decl, is_cons_decl, head_decl, tail_decl);
RESET_ERROR_CODE();
ast_manager& m = mk_c(c)->m();
datatype_util& dt_util = mk_c(c)->dtutil();
mk_c(c)->reset_last_result();
datatype_util data_util(m);
accessor_decl* head_tail[2] = {
mk_accessor_decl(symbol("head"), type_ref(to_sort(elem_sort))),
mk_accessor_decl(symbol("tail"), type_ref(0))
mk_accessor_decl(m, symbol("head"), type_ref(to_sort(elem_sort))),
mk_accessor_decl(m, symbol("tail"), type_ref(0))
};
constructor_decl* constrs[2] = {
mk_constructor_decl(symbol("nil"), symbol("is_nil"), 0, 0),
@ -179,7 +175,7 @@ extern "C" {
sort_ref_vector sorts(m);
{
datatype_decl * decl = mk_datatype_decl(to_symbol(name), 2, constrs);
datatype_decl * decl = mk_datatype_decl(dt_util, to_symbol(name), 0, nullptr, 2, constrs);
bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &decl, 0, 0, sorts);
del_datatype_decl(decl);
@ -215,18 +211,16 @@ extern "C" {
*is_cons_decl = of_func_decl(f);
}
if (head_decl) {
ptr_vector<func_decl> const* acc = data_util.get_constructor_accessors(cnstrs[1]);
SASSERT(acc);
SASSERT(acc->size() == 2);
f = (*acc)[0];
ptr_vector<func_decl> const& acc = *data_util.get_constructor_accessors(cnstrs[1]);
SASSERT(acc.size() == 2);
f = (acc)[0];
mk_c(c)->save_multiple_ast_trail(f);
*head_decl = of_func_decl(f);
}
if (tail_decl) {
ptr_vector<func_decl> const* acc = data_util.get_constructor_accessors(cnstrs[1]);
SASSERT(acc);
SASSERT(acc->size() == 2);
f = (*acc)[1];
ptr_vector<func_decl> const& acc = *data_util.get_constructor_accessors(cnstrs[1]);
SASSERT(acc.size() == 2);
f = (acc)[1];
mk_c(c)->save_multiple_ast_trail(f);
*tail_decl = of_func_decl(f);
}
@ -301,13 +295,9 @@ extern "C" {
*tester = of_func_decl(f2);
}
ptr_vector<func_decl> const* accs = data_util.get_constructor_accessors(f);
if (!accs && num_fields > 0) {
SET_ERROR_CODE(Z3_INVALID_ARG);
return;
}
ptr_vector<func_decl> const& accs = *data_util.get_constructor_accessors(f);
for (unsigned i = 0; i < num_fields; ++i) {
func_decl* f2 = (*accs)[i];
func_decl* f2 = (accs)[i];
mk_c(c)->save_multiple_ast_trail(f2);
accessors[i] = of_func_decl(f2);
}
@ -327,21 +317,23 @@ extern "C" {
Z3_symbol name,
unsigned num_constructors,
Z3_constructor constructors[]) {
datatype_util& dt_util = mk_c(c)->dtutil();
ast_manager& m = mk_c(c)->m();
ptr_vector<constructor_decl> constrs;
for (unsigned i = 0; i < num_constructors; ++i) {
constructor* cn = reinterpret_cast<constructor*>(constructors[i]);
ptr_vector<accessor_decl> acc;
for (unsigned j = 0; j < cn->m_sorts.size(); ++j) {
if (cn->m_sorts[j].get()) {
acc.push_back(mk_accessor_decl(cn->m_field_names[j], type_ref(cn->m_sorts[j].get())));
acc.push_back(mk_accessor_decl(m, cn->m_field_names[j], type_ref(cn->m_sorts[j].get())));
}
else {
acc.push_back(mk_accessor_decl(cn->m_field_names[j], type_ref(cn->m_sort_refs[j])));
acc.push_back(mk_accessor_decl(m, cn->m_field_names[j], type_ref(cn->m_sort_refs[j])));
}
}
constrs.push_back(mk_constructor_decl(cn->m_name, cn->m_tester, acc.size(), acc.c_ptr()));
}
return mk_datatype_decl(to_symbol(name), num_constructors, constrs.c_ptr());
return mk_datatype_decl(dt_util, to_symbol(name), 0, nullptr, num_constructors, constrs.c_ptr());
}
Z3_sort Z3_API Z3_mk_datatype(Z3_context c,
@ -368,11 +360,11 @@ extern "C" {
sort * s = sorts.get(0);
mk_c(c)->save_ast_trail(s);
ptr_vector<func_decl> const* cnstrs = data_util.get_datatype_constructors(s);
ptr_vector<func_decl> const& cnstrs = *data_util.get_datatype_constructors(s);
for (unsigned i = 0; i < num_constructors; ++i) {
constructor* cn = reinterpret_cast<constructor*>(constructors[i]);
cn->m_constructor = (*cnstrs)[i];
cn->m_constructor = cnstrs[i];
}
RETURN_Z3_mk_datatype(of_sort(s));
Z3_CATCH_RETURN(0);
@ -417,7 +409,7 @@ extern "C" {
ptr_vector<datatype_decl> datas;
for (unsigned i = 0; i < num_sorts; ++i) {
constructor_list* cl = reinterpret_cast<constructor_list*>(constructor_lists[i]);
datas.push_back(mk_datatype_decl(c,sort_names[i], cl->size(), reinterpret_cast<Z3_constructor*>(cl->c_ptr())));
datas.push_back(mk_datatype_decl(c, sort_names[i], cl->size(), reinterpret_cast<Z3_constructor*>(cl->c_ptr())));
}
sort_ref_vector _sorts(m);
bool ok = mk_c(c)->get_dt_plugin()->mk_datatypes(datas.size(), datas.c_ptr(), 0, 0, _sorts);
@ -434,10 +426,10 @@ extern "C" {
mk_c(c)->save_multiple_ast_trail(s);
sorts[i] = of_sort(s);
constructor_list* cl = reinterpret_cast<constructor_list*>(constructor_lists[i]);
ptr_vector<func_decl> const* cnstrs = data_util.get_datatype_constructors(s);
ptr_vector<func_decl> const& cnstrs = *data_util.get_datatype_constructors(s);
for (unsigned j = 0; j < cl->size(); ++j) {
constructor* cn = (*cl)[j];
cn->m_constructor = (*cnstrs)[j];
cn->m_constructor = cnstrs[j];
}
}
RETURN_Z3_mk_datatypes;
@ -456,12 +448,7 @@ extern "C" {
SET_ERROR_CODE(Z3_INVALID_ARG);
return 0;
}
ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(_t);
if (!decls) {
SET_ERROR_CODE(Z3_INVALID_ARG);
return 0;
}
return decls->size();
return dt_util.get_datatype_constructors(_t)->size();
Z3_CATCH_RETURN(0);
}
@ -474,12 +461,12 @@ extern "C" {
SET_ERROR_CODE(Z3_INVALID_ARG);
return 0;
}
ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(_t);
if (!decls || idx >= decls->size()) {
ptr_vector<func_decl> const & decls = *dt_util.get_datatype_constructors(_t);
if (idx >= decls.size()) {
SET_ERROR_CODE(Z3_INVALID_ARG);
return 0;
}
func_decl* decl = (*decls)[idx];
func_decl* decl = (decls)[idx];
mk_c(c)->save_ast_trail(decl);
return of_func_decl(decl);
}
@ -504,12 +491,12 @@ extern "C" {
SET_ERROR_CODE(Z3_INVALID_ARG);
RETURN_Z3(0);
}
ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(_t);
if (!decls || idx >= decls->size()) {
ptr_vector<func_decl> const & decls = *dt_util.get_datatype_constructors(_t);
if (idx >= decls.size()) {
SET_ERROR_CODE(Z3_INVALID_ARG);
RETURN_Z3(0);
}
func_decl* decl = (*decls)[idx];
func_decl* decl = (decls)[idx];
decl = dt_util.get_constructor_recognizer(decl);
mk_c(c)->save_ast_trail(decl);
RETURN_Z3(of_func_decl(decl));
@ -527,23 +514,23 @@ extern "C" {
SET_ERROR_CODE(Z3_INVALID_ARG);
RETURN_Z3(0);
}
ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(_t);
if (!decls || idx_c >= decls->size()) {
ptr_vector<func_decl> const & decls = *dt_util.get_datatype_constructors(_t);
if (idx_c >= decls.size()) {
SET_ERROR_CODE(Z3_INVALID_ARG);
return 0;
}
func_decl* decl = (*decls)[idx_c];
func_decl* decl = (decls)[idx_c];
if (decl->get_arity() <= idx_a) {
SET_ERROR_CODE(Z3_INVALID_ARG);
RETURN_Z3(0);
}
ptr_vector<func_decl> const * accs = dt_util.get_constructor_accessors(decl);
SASSERT(accs && accs->size() == decl->get_arity());
if (!accs || accs->size() <= idx_a) {
ptr_vector<func_decl> const & accs = *dt_util.get_constructor_accessors(decl);
SASSERT(accs.size() == decl->get_arity());
if (accs.size() <= idx_a) {
SET_ERROR_CODE(Z3_INVALID_ARG);
RETURN_Z3(0);
}
decl = (*accs)[idx_a];
decl = (accs)[idx_a];
mk_c(c)->save_ast_trail(decl);
RETURN_Z3(of_func_decl(decl));
Z3_CATCH_RETURN(0);
@ -574,16 +561,13 @@ extern "C" {
SET_ERROR_CODE(Z3_INVALID_ARG);
return 0;
}
ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(tuple);
if (!decls || decls->size() != 1) {
ptr_vector<func_decl> const & decls = *dt_util.get_datatype_constructors(tuple);
if (decls.size() != 1) {
SET_ERROR_CODE(Z3_INVALID_ARG);
return 0;
}
ptr_vector<func_decl> const * accs = dt_util.get_constructor_accessors((*decls)[0]);
if (!accs) {
return 0;
}
return accs->size();
ptr_vector<func_decl> const & accs = *dt_util.get_constructor_accessors(decls[0]);
return accs.size();
Z3_CATCH_RETURN(0);
}
@ -597,21 +581,17 @@ extern "C" {
SET_ERROR_CODE(Z3_INVALID_ARG);
RETURN_Z3(0);
}
ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(tuple);
if (!decls || decls->size() != 1) {
ptr_vector<func_decl> const & decls = *dt_util.get_datatype_constructors(tuple);
if (decls.size() != 1) {
SET_ERROR_CODE(Z3_INVALID_ARG);
RETURN_Z3(0);
}
ptr_vector<func_decl> const * accs = dt_util.get_constructor_accessors((*decls)[0]);
if (!accs) {
SET_ERROR_CODE(Z3_INVALID_ARG);
RETURN_Z3(0);
}
if (accs->size() <= i) {
ptr_vector<func_decl> const & accs = *dt_util.get_constructor_accessors((decls)[0]);
if (accs.size() <= i) {
SET_ERROR_CODE(Z3_IOB);
RETURN_Z3(0);
}
func_decl* acc = (*accs)[i];
func_decl* acc = (accs)[i];
mk_c(c)->save_ast_trail(acc);
RETURN_Z3(of_func_decl(acc));
Z3_CATCH_RETURN(0);

View file

@ -8185,9 +8185,9 @@ def sequence_interpolant(v,p=None,ctx=None):
If parameters p are supplied, these are used in creating the
solver that determines satisfiability.
>>> x = Int('x')
>>> y = Int('y')
>>> print(sequence_interpolant([x < 0, y == x , y > 2]))
x = Int('x')
y = Int('y')
print(sequence_interpolant([x < 0, y == x , y > 2]))
[Not(x >= 0), Not(y >= 0)]
"""
f = v[0]

View file

@ -546,7 +546,7 @@ expr * array_decl_plugin::get_some_value(sort * s) {
return m_manager->mk_app(m_family_id, OP_CONST_ARRAY, 1, &p, 1, &v);
}
bool array_decl_plugin::is_fully_interp(sort const * s) const {
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++) {

View file

@ -127,7 +127,7 @@ class array_decl_plugin : public decl_plugin {
virtual expr * get_some_value(sort * s);
virtual bool is_fully_interp(sort const * s) const;
virtual bool is_fully_interp(sort * s) const;
};
class array_recognizers {

View file

@ -188,18 +188,14 @@ decl_info::decl_info(decl_info const& other) :
void decl_info::init_eh(ast_manager & m) {
vector<parameter>::iterator it = m_parameters.begin();
vector<parameter>::iterator end = m_parameters.end();
for (; it != end; ++it) {
it->init_eh(m);
for (parameter & p : m_parameters) {
p.init_eh(m);
}
}
void decl_info::del_eh(ast_manager & m) {
vector<parameter>::iterator it = m_parameters.begin();
vector<parameter>::iterator end = m_parameters.end();
for (; it != end; ++it) {
it->del_eh(m, m_family_id);
for (parameter & p : m_parameters) {
p.del_eh(m, m_family_id);
}
}
@ -1291,10 +1287,8 @@ decl_kind user_sort_plugin::register_name(symbol s) {
decl_plugin * user_sort_plugin::mk_fresh() {
user_sort_plugin * p = alloc(user_sort_plugin);
svector<symbol>::iterator it = m_sort_names.begin();
svector<symbol>::iterator end = m_sort_names.end();
for (; it != end; ++it)
p->register_name(*it);
for (symbol const& s : m_sort_names)
p->register_name(s);
return p;
}
@ -1414,26 +1408,20 @@ ast_manager::~ast_manager() {
dec_ref(m_true);
dec_ref(m_false);
dec_ref(m_undef_proof);
ptr_vector<decl_plugin>::iterator it = m_plugins.begin();
ptr_vector<decl_plugin>::iterator end = m_plugins.end();
for (; it != end; ++it) {
if (*it)
(*it)->finalize();
for (decl_plugin* p : m_plugins) {
if (p)
p->finalize();
}
it = m_plugins.begin();
for (; it != end; ++it) {
if (*it)
dealloc(*it);
for (decl_plugin* p : m_plugins) {
if (p)
dealloc(p);
}
m_plugins.reset();
while (!m_ast_table.empty()) {
DEBUG_CODE(std::cout << "ast_manager LEAKED: " << m_ast_table.size() << std::endl;);
ptr_vector<ast> roots;
ast_mark mark;
ast_table::iterator it_a = m_ast_table.begin();
ast_table::iterator end_a = m_ast_table.end();
for (; it_a != end_a; ++it_a) {
ast* n = (*it_a);
for (ast * n : m_ast_table) {
switch (n->get_kind()) {
case AST_SORT: {
sort_info* info = to_sort(n)->get_info();
@ -1466,9 +1454,7 @@ ast_manager::~ast_manager() {
break;
}
}
it_a = m_ast_table.begin();
for (; it_a != end_a; ++it_a) {
ast* n = *it_a;
for (ast * n : m_ast_table) {
if (!mark.is_marked(n)) {
roots.push_back(n);
}
@ -1543,12 +1529,15 @@ void ast_manager::raise_exception(char const * msg) {
throw ast_exception(msg);
}
#include "ast/ast_translation.h"
void ast_manager::copy_families_plugins(ast_manager const & from) {
TRACE("copy_families_plugins",
tout << "target:\n";
for (family_id fid = 0; m_family_manager.has_family(fid); fid++) {
tout << "fid: " << fid << " fidname: " << get_family_name(fid) << "\n";
});
ast_translation trans(const_cast<ast_manager&>(from), *this, false);
for (family_id fid = 0; from.m_family_manager.has_family(fid); fid++) {
SASSERT(from.is_builtin_family_id(fid) == is_builtin_family_id(fid));
SASSERT(!from.is_builtin_family_id(fid) || m_family_manager.has_family(fid));
@ -1569,6 +1558,9 @@ void ast_manager::copy_families_plugins(ast_manager const & from) {
SASSERT(new_p->get_family_id() == fid);
SASSERT(has_plugin(fid));
}
if (from.has_plugin(fid)) {
get_plugin(fid)->inherit(from.get_plugin(fid), trans);
}
SASSERT(from.m_family_manager.has_family(fid) == m_family_manager.has_family(fid));
SASSERT(from.get_family_id(fid_name) == get_family_id(fid_name));
SASSERT(!from.has_plugin(fid) || has_plugin(fid));
@ -1663,11 +1655,8 @@ bool ast_manager::is_bool(expr const * n) const {
#ifdef Z3DEBUG
bool ast_manager::slow_not_contains(ast const * n) {
ast_table::iterator it = m_ast_table.begin();
ast_table::iterator end = m_ast_table.end();
unsigned num = 0;
for (; it != end; ++it) {
ast * curr = *it;
for (ast * curr : m_ast_table) {
if (compare_nodes(curr, n)) {
TRACE("nondet_bug",
tout << "id1: " << curr->get_id() << ", id2: " << n->get_id() << "\n";
@ -1935,6 +1924,35 @@ sort * ast_manager::mk_sort(symbol const & name, sort_info * info) {
return register_node(new_node);
}
sort * ast_manager::substitute(sort* s, unsigned n, sort * const * src, sort * const * dst) {
for (unsigned i = 0; i < n; ++i) {
if (s == src[i]) return dst[i];
}
vector<parameter> ps;
bool change = false;
sort_ref_vector sorts(*this);
for (unsigned i = 0; i < s->get_num_parameters(); ++i) {
parameter const& p = s->get_parameter(i);
if (p.is_ast()) {
SASSERT(is_sort(p.get_ast()));
change = true;
sorts.push_back(substitute(to_sort(p.get_ast()), n, src, dst));
ps.push_back(parameter(sorts.back()));
}
else {
ps.push_back(p);
}
}
if (!change) {
return s;
}
decl_info dinfo(s->get_family_id(), s->get_decl_kind(), ps.size(), ps.c_ptr(), s->private_parameters());
sort_info sinfo(dinfo, s->get_num_elements());
return mk_sort(s->get_name(), &sinfo);
}
sort * ast_manager::mk_uninterpreted_sort(symbol const & name, unsigned num_parameters, parameter const * parameters) {
user_sort_plugin * plugin = get_user_sort_plugin();
decl_kind kind = plugin->register_name(name);
@ -2354,6 +2372,7 @@ quantifier * ast_manager::mk_quantifier(bool forall, unsigned num_decls, sort *
SASSERT(num_decls > 0);
DEBUG_CODE({
for (unsigned i = 0; i < num_patterns; ++i) {
TRACE("ast", tout << i << " " << mk_pp(patterns[i], *this) << "\n";);
SASSERT(is_pattern(patterns[i]));
}});
unsigned sz = quantifier::get_obj_size(num_decls, num_patterns, num_no_patterns);
@ -2579,7 +2598,7 @@ expr * ast_manager::get_some_value(sort * s) {
return mk_model_value(0, s);
}
bool ast_manager::is_fully_interp(sort const * s) const {
bool ast_manager::is_fully_interp(sort * s) const {
if (is_uninterp(s))
return false;
family_id fid = s->get_family_id();

View file

@ -335,13 +335,17 @@ public:
unsigned num_parameters = 0, parameter const * parameters = 0, bool private_parameters = false):
decl_info(family_id, k, num_parameters, parameters, private_parameters), m_num_elements(num_elements) {
}
sort_info(sort_info const& other) : decl_info(other), m_num_elements(other.m_num_elements) {
sort_info(sort_info const& other) : decl_info(other), m_num_elements(other.m_num_elements) {
}
sort_info(decl_info const& di, sort_size const& num_elements) :
decl_info(di), m_num_elements(num_elements) {}
~sort_info() {}
bool is_infinite() const { return m_num_elements.is_infinite(); }
bool is_very_big() const { return m_num_elements.is_very_big(); }
sort_size const & get_num_elements() const { return m_num_elements; }
void set_num_elements(sort_size const& s) { m_num_elements = s; }
};
std::ostream & operator<<(std::ostream & out, sort_info const & info);
@ -567,6 +571,7 @@ public:
bool is_very_big() const { return get_info() == 0 || get_info()->is_very_big(); }
bool is_sort_of(family_id fid, decl_kind k) const { return get_family_id() == fid && get_decl_kind() == k; }
sort_size const & get_num_elements() const { return get_info()->get_num_elements(); }
void set_num_elements(sort_size const& s) { get_info()->set_num_elements(s); }
unsigned get_size() const { return get_obj_size(); }
};
@ -890,6 +895,8 @@ struct ast_eq_proc {
}
};
class ast_translation;
class ast_table : public chashtable<ast*, obj_ptr_hash<ast>, ast_eq_proc> {
public:
void erase(ast * n);
@ -925,6 +932,8 @@ protected:
m_family_id = id;
}
virtual void inherit(decl_plugin* other_p, ast_translation& ) { }
friend class ast_manager;
public:
@ -988,7 +997,7 @@ public:
// Return true if the interpreted sort s does not depend on uninterpreted sorts.
// This may be the case, for example, for array and datatype sorts.
virtual bool is_fully_interp(sort const * s) const { return true; }
virtual bool is_fully_interp(sort * s) const { return true; }
// Event handlers for deleting/translating PARAM_EXTERNAL
virtual void del(parameter const & p) {}
@ -1655,6 +1664,8 @@ public:
sort * mk_sort(family_id fid, decl_kind k, unsigned num_parameters = 0, parameter const * parameters = 0);
sort * substitute(sort* s, unsigned n, sort * const * src, sort * const * dst);
sort * mk_bool_sort() const { return m_bool_sort; }
sort * mk_proof_sort() const { return m_proof_sort; }
@ -1667,7 +1678,7 @@ public:
\brief A sort is "fully" interpreted if it is interpreted,
and doesn't depend on other uninterpreted sorts.
*/
bool is_fully_interp(sort const * s) const;
bool is_fully_interp(sort * s) const;
func_decl * mk_func_decl(family_id fid, decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range = 0);
@ -2470,6 +2481,7 @@ public:
void operator()(AST * n) { m_manager.inc_ref(n); }
};
#endif /* AST_H_ */

View file

@ -434,16 +434,16 @@ format_ns::format * smt2_pp_environment::pp_sort(sort * s) {
fs.push_back(pp_sort(to_sort(s->get_parameter(0).get_ast())));
return mk_seq1(m, fs.begin(), fs.end(), f2f(), get_sutil().is_seq(s)?"Seq":"RegEx");
}
#if 0
if (get_dtutil().is_datatype(s)) {
ptr_buffer<format> fs;
unsigned sz = get_dtutil().get_datatype_num_parameter_sorts(s);
for (unsigned i = 0; i < sz; i++) {
fs.push_back(pp_sort(get_dtutil().get_datatype_parameter_sort(s, i)));
if (sz > 0) {
ptr_buffer<format> fs;
for (unsigned i = 0; i < sz; i++) {
fs.push_back(pp_sort(get_dtutil().get_datatype_parameter_sort(s, i)));
}
return mk_seq1(m, fs.begin(), fs.end(), f2f(), s->get_name().str().c_str());
}
return mk_seq1(m, fs.begin(), fs.end(), f2f(), s->get_name().str().c_str());
}
#endif
return format_ns::mk_string(get_manager(), s->get_name().str().c_str());
}
@ -1225,15 +1225,15 @@ mk_ismt2_pp::mk_ismt2_pp(ast * t, ast_manager & m, unsigned indent, unsigned num
std::ostream& operator<<(std::ostream& out, mk_ismt2_pp const & p) {
smt2_pp_environment_dbg env(p.m_manager);
if (is_expr(p.m_ast)) {
if (p.m_ast == 0) {
out << "null";
}
else if (is_expr(p.m_ast)) {
ast_smt2_pp(out, to_expr(p.m_ast), env, p.m_params, p.m_indent, p.m_num_vars, p.m_var_prefix);
}
else if (is_sort(p.m_ast)) {
ast_smt2_pp(out, to_sort(p.m_ast), env, p.m_params, p.m_indent);
}
else if (p.m_ast == 0) {
out << "null";
}
else {
SASSERT(is_func_decl(p.m_ast));
ast_smt2_pp(out, to_func_decl(p.m_ast), env, p.m_params, p.m_indent);

View file

@ -21,17 +21,17 @@ Revision History:
#include<sstream>
#include<iostream>
#include "util/vector.h"
#include "util/smt2_util.h"
#include "ast/ast_smt_pp.h"
#include "ast/arith_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
#include "ast/array_decl_plugin.h"
#include "ast/datatype_decl_plugin.h"
#include "ast/seq_decl_plugin.h"
#include "ast/fpa_decl_plugin.h"
#include "util/vector.h"
#include "ast/for_each_ast.h"
#include "ast/decl_collector.h"
#include "util/smt2_util.h"
#include "ast/seq_decl_plugin.h"
// ---------------------------------------
// smt_renaming
@ -174,7 +174,6 @@ class smt_printer {
symbol m_logic;
symbol m_AUFLIRA;
bool m_no_lets;
bool m_is_smt2;
bool m_simplify_implies;
expr* m_top;
@ -199,37 +198,30 @@ class smt_printer {
}
void pp_id(expr* n) {
if (m_is_smt2) {
m_out << (is_bool(n)?"$x":(is_proof(n)?"@x":"?x")) << n->get_id();
}
else {
m_out << (is_bool(n)?"$x":"?x") << n->get_id();
}
m_out << (is_bool(n)?"$x":(is_proof(n)?"@x":"?x")) << n->get_id();
}
void pp_decl(func_decl* d) {
symbol sym = m_renaming.get_symbol(d->get_name());
if (d->get_family_id() == m_dt_fid) {
m_out << sym;
}
else if (m_manager.is_ite(d)) {
if (!m_is_smt2 && is_bool(d->get_range())) {
m_out << "if_then_else";
datatype_util util(m_manager);
if (util.is_recognizer(d)) {
visit_params(false, sym, d->get_num_parameters(), d->get_parameters());
}
else {
m_out << "ite";
m_out << sym;
}
}
else if (!m_is_smt2 && m_manager.is_implies(d)) {
m_out << "implies";
else if (m_manager.is_ite(d)) {
m_out << "ite";
}
else if (m_is_smt2 && m_manager.is_iff(d)) {
else if (m_manager.is_iff(d)) {
m_out << "=";
}
else if (m_is_smt2 && m_manager.is_implies(d)) {
else if (m_manager.is_implies(d)) {
m_out << "=>";
}
else if (m_is_smt2 && is_decl_of(d, m_arith_fid, OP_UMINUS)) {
else if (is_decl_of(d, m_arith_fid, OP_UMINUS)) {
m_out << "-";
}
else {
@ -251,28 +243,23 @@ class smt_printer {
return;
}
if (m_is_smt2) {
if (is_sort_symbol && sym == symbol("String")) {
m_out << "String";
return;
}
if (is_sort_symbol &&
sym != symbol("BitVec") &&
sym != symbol("FloatingPoint") &&
sym != symbol("RoundingMode")) {
m_out << "(" << sym << " ";
}
else if (!is_sort_symbol && is_sort_param(num_params, params)) {
m_out << "(as " << sym << " ";
}
else {
m_out << "(_ " << sym << " ";
}
if (is_sort_symbol && sym == symbol("String")) {
m_out << "String";
return;
}
if (is_sort_symbol &&
sym != symbol("BitVec") &&
sym != symbol("FloatingPoint") &&
sym != symbol("RoundingMode")) {
m_out << "(" << sym << " ";
}
else if (!is_sort_symbol && is_sort_param(num_params, params)) {
m_out << "(as " << sym << " ";
}
else {
m_out << sym << "[";
m_out << "(_ " << sym << " ";
}
for (unsigned i = 0; i < num_params; ++i) {
parameter const& p = params[i];
if (p.is_ast()) {
@ -293,20 +280,10 @@ class smt_printer {
m_out << p;
}
if (i + 1 < num_params) {
if (m_is_smt2) {
m_out << " ";
}
else {
m_out << ": ";
}
m_out << " ";
}
}
if (m_is_smt2) {
m_out << ")";
}
else {
m_out << "]";
}
m_out << ")";
}
bool is_auflira() const {
@ -315,9 +292,7 @@ class smt_printer {
void visit_sort(sort* s, bool bool2int = false) {
symbol sym;
if (bool2int && is_bool(s) && !m_is_smt2) {
sym = symbol("Int");
} else if (s->is_sort_of(m_bv_fid, BV_SORT)) {
if (s->is_sort_of(m_bv_fid, BV_SORT)) {
sym = symbol("BitVec");
}
else if (s->is_sort_of(m_arith_fid, REAL_SORT)) {
@ -329,51 +304,16 @@ class smt_printer {
else if (s->is_sort_of(m_arith_fid, INT_SORT)) {
sym = s->get_name();
}
else if (s->is_sort_of(m_array_fid, ARRAY_SORT) && m_is_smt2) {
else if (s->is_sort_of(m_array_fid, ARRAY_SORT)) {
sym = "Array";
}
else if (s->is_sort_of(m_array_fid, ARRAY_SORT) && !m_is_smt2) {
unsigned num_params = s->get_num_parameters();
SASSERT(num_params >= 2);
if (is_auflira()) {
sort* rng = to_sort(s->get_parameter(1).get_ast());
if (rng->get_family_id() == m_array_fid) {
m_out << "Array2";
}
else {
m_out << "Array1";
}
return;
}
sort* s1 = to_sort(s->get_parameter(0).get_ast());
sort* s2 = to_sort(s->get_parameter(1).get_ast());
if (num_params == 2 &&
s1->is_sort_of(m_bv_fid, BV_SORT) &&
s2->is_sort_of(m_bv_fid, BV_SORT)) {
m_out << "Array";
m_out << "[" << s1->get_parameter(0).get_int();
m_out << ":" << s2->get_parameter(0).get_int() << "]";
return;
}
m_out << "(Array ";
for (unsigned i = 0; i < num_params; ++i) {
visit_sort(to_sort(s->get_parameter(i).get_ast()));
if (i + 1 < num_params) {
m_out << " ";
}
}
m_out << ")";
return;
}
else if (s->is_sort_of(m_dt_fid, DATATYPE_SORT)) {
m_out << m_renaming.get_symbol(s->get_name());
#if 0
datatype_util util(m_manager);
unsigned num_sorts = util.get_datatype_num_parameter_sorts(s);
if (num_sorts > 0) {
m_out << "(";
}
m_out << m_renaming.get_symbol(s->get_name());
if (num_sorts > 0) {
for (unsigned i = 0; i < num_sorts; ++i) {
m_out << " ";
@ -381,7 +321,6 @@ class smt_printer {
}
m_out << ")";
}
#endif
return;
}
else {
@ -403,20 +342,7 @@ class smt_printer {
void pp_arg(expr *arg, app *parent)
{
if (!m_is_smt2 && is_bool(arg) && is_var(arg) && parent->get_family_id() == m_basic_fid) {
m_out << "(not (= ";
pp_marked_expr(arg);
m_out << " 0))";
} else if (!m_is_smt2 && is_bool(arg) && !is_var(arg) &&
parent->get_family_id() != m_basic_fid &&
parent->get_family_id() != m_dt_fid) {
m_out << "(ite ";
pp_marked_expr(arg);
m_out << " 1 0)";
} else {
pp_marked_expr(arg);
}
pp_marked_expr(arg);
}
void visit_app(app* n) {
@ -431,12 +357,7 @@ class smt_printer {
if (m_autil.is_numeral(n, val, is_int)) {
if (val.is_neg()) {
val.neg();
if (m_is_smt2) {
m_out << "(- ";
}
else {
m_out << "(~ ";
}
m_out << "(- ";
display_rational(val, is_int);
m_out << ")";
}
@ -458,12 +379,7 @@ class smt_printer {
m_out << "\"";
}
else if (m_bvutil.is_numeral(n, val, bv_size)) {
if (m_is_smt2) {
m_out << "(_ bv" << val << " " << bv_size << ")";
}
else {
m_out << "bv" << val << "[" << bv_size << "]";
}
m_out << "(_ bv" << val << " " << bv_size << ")";
}
else if (m_futil.is_numeral(n, float_val)) {
m_out << "((_ to_fp " <<
@ -473,37 +389,17 @@ class smt_printer {
}
else if (m_bvutil.is_bit2bool(n)) {
unsigned bit = n->get_decl()->get_parameter(0).get_int();
if (m_is_smt2) {
m_out << "(= ((_ extract " << bit << " " << bit << ") ";
pp_marked_expr(n->get_arg(0));
m_out << ") (_ bv1 1))";
}
else {
m_out << "(= (extract[" << bit << ":" << bit << "] ";
pp_marked_expr(n->get_arg(0));
m_out << ") bv1[1])";
}
m_out << "(= ((_ extract " << bit << " " << bit << ") ";
pp_marked_expr(n->get_arg(0));
m_out << ") (_ bv1 1))";
}
else if (m_manager.is_label(n, pos, names) && names.size() >= 1) {
if (m_is_smt2) {
m_out << "(! ";
pp_marked_expr(n->get_arg(0));
m_out << (pos?":lblpos":":lblneg") << " " << m_renaming.get_symbol(names[0]) << ")";
}
else {
m_out << "(" << (pos?"lblpos":"lblneg") << " " << m_renaming.get_symbol(names[0]) << " ";
expr* ch = n->get_arg(0);
pp_marked_expr(ch);
m_out << ")";
}
m_out << "(! ";
pp_marked_expr(n->get_arg(0));
m_out << (pos?":lblpos":":lblneg") << " " << m_renaming.get_symbol(names[0]) << ")";
}
else if (m_manager.is_label_lit(n, names) && names.size() >= 1) {
if (m_is_smt2) {
m_out << "(! true :lblpos " << m_renaming.get_symbol(names[0]) << ")";
}
else {
m_out << "(lblpos " << m_renaming.get_symbol(names[0]) << " true )";
}
m_out << "(! true :lblpos " << m_renaming.get_symbol(names[0]) << ")";
}
else if (num_args == 0) {
if (decl->private_parameters()) {
@ -533,7 +429,8 @@ class smt_printer {
pp_arg(curr, n);
m_out << ")";
} else if (m_manager.is_distinct(decl)) {
}
else if (m_manager.is_distinct(decl)) {
ptr_vector<expr> args(num_args, n->get_args());
unsigned idx = 0;
m_out << "(and";
@ -581,14 +478,11 @@ class smt_printer {
void print_no_lets(expr *e)
{
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, m_is_smt2, m_indent, m_num_var_names, m_var_names);
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, true, m_simplify_implies, true, m_indent, m_num_var_names, m_var_names);
p(e);
}
void print_bound(symbol const& name) {
if (!m_is_smt2 && (name.is_numerical() || '?' != name.bare_str()[0])) {
m_out << "?";
}
m_out << name;
}
@ -602,9 +496,7 @@ class smt_printer {
else {
m_out << "exists ";
}
if (m_is_smt2) {
m_out << "(";
}
m_out << "(";
for (unsigned i = 0; i < q->get_num_decls(); ++i) {
sort* s = q->get_decl_sort(i);
m_out << "(";
@ -613,15 +505,13 @@ class smt_printer {
visit_sort(s, true);
m_out << ") ";
}
if (m_is_smt2) {
m_out << ")";
}
m_out << ")";
if (m_is_smt2 && (q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) {
if ((q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) {
m_out << "(! ";
}
{
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, false, m_is_smt2, m_simplify_implies, m_indent, m_num_var_names, m_var_names);
smt_printer p(m_out, m_manager, m_qlists, m_renaming, m_logic, false, true, m_simplify_implies, m_indent, m_num_var_names, m_var_names);
p(q->get_expr());
}
@ -640,28 +530,18 @@ class smt_printer {
}
}
if (m_is_smt2) {
m_out << " :pattern ( ";
}
else {
m_out << " :pat { ";
}
m_out << " :pattern ( ";
for (unsigned j = 0; j < pat->get_num_args(); ++j) {
print_no_lets(pat->get_arg(j));
m_out << " ";
}
if (m_is_smt2) {
m_out << ")";
}
else {
m_out << "}";
}
m_out << ")";
}
if (q->get_qid() != symbol::null)
m_out << " :qid " << q->get_qid();
if (m_is_smt2 && (q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) {
if ((q->get_num_patterns() > 0 || q->get_qid() != symbol::null)) {
m_out << ")";
}
m_out << ")";
@ -725,21 +605,11 @@ class smt_printer {
}
void visit_expr(expr* n) {
if (m_is_smt2) {
m_out << "(let ((";
}
else if (is_bool(n)) {
m_out << "(flet (";
}
else {
m_out << "(let (";
}
m_out << "(let ((";
pp_id(n);
m_out << " ";
pp_expr(n);
if (m_is_smt2) {
m_out << ")";
}
m_out << ")";
m_out << ")";
newline();
}
@ -851,7 +721,6 @@ public:
m_AUFLIRA("AUFLIRA"),
// It's much easier to read those testcases with that.
m_no_lets(no_lets),
m_is_smt2(is_smt2),
m_simplify_implies(simplify_implies)
{
m_basic_fid = m.get_basic_family_id();
@ -905,91 +774,59 @@ public:
}
void pp_dt(ast_mark& mark, sort* s) {
SASSERT(s->is_sort_of(m_dt_fid, DATATYPE_SORT));
datatype_util util(m_manager);
ptr_vector<func_decl> const* decls;
ptr_vector<sort> rec_sorts;
SASSERT(util.is_datatype(s));
rec_sorts.push_back(s);
mark.mark(s, true);
sort_ref_vector ps(m_manager);
ptr_vector<datatype::def> defs;
util.get_defs(s, defs);
// collect siblings and sorts that have not already been printed.
for (unsigned h = 0; h < rec_sorts.size(); ++h) {
s = rec_sorts[h];
decls = util.get_datatype_constructors(s);
for (unsigned i = 0; i < decls->size(); ++i) {
func_decl* f = (*decls)[i];
for (unsigned j = 0; j < f->get_arity(); ++j) {
sort* s2 = f->get_domain(j);
if (!mark.is_marked(s2)) {
if (m_manager.is_uninterp(s2)) {
pp_sort_decl(mark, s2);
}
else if (!util.is_datatype(s2)) {
// skip
}
else if (util.are_siblings(s, s2)) {
rec_sorts.push_back(s2);
mark.mark(s2, true);
}
else {
pp_sort_decl(mark, s2);
}
}
for (datatype::def* d : defs) {
sort_ref sr = d->instantiate(ps);
if (mark.is_marked(sr)) return; // already processed
mark.mark(sr, true);
}
m_out << "(declare-datatypes (";
bool first_def = true;
for (datatype::def* d : defs) {
if (!first_def) m_out << "\n "; else first_def = false;
m_out << "(" << d->name() << " " << d->params().size() << ")";
}
m_out << ") (";
bool first_sort = true;
for (datatype::def* d : defs) {
if (!first_sort) m_out << "\n "; else first_sort = false;
if (!d->params().empty()) {
m_out << "(par (";
bool first_param = true;
for (sort* s : d->params()) {
if (!first_param) m_out << " "; else first_param = false;
visit_sort(s);
}
m_out << ")";
}
}
if (m_is_smt2) {
// TBD: datatypes may be declared parametrically.
// get access to parametric generalization, or print
// monomorphic specialization with a tag that gets reused at use-point.
m_out << "(declare-datatypes () (";
}
else {
m_out << ":datatypes (";
}
for (unsigned si = 0; si < rec_sorts.size(); ++si) {
s = rec_sorts[si];
m_out << "(";
m_out << m_renaming.get_symbol(s->get_name());
m_out << m_renaming.get_symbol(d->name());
m_out << " ";
decls = util.get_datatype_constructors(s);
for (unsigned i = 0; i < decls->size(); ++i) {
func_decl* f = (*decls)[i];
ptr_vector<func_decl> const& accs = *util.get_constructor_accessors(f);
if (m_is_smt2 || accs.size() > 0) {
m_out << "(";
}
m_out << m_renaming.get_symbol(f->get_name());
if (!accs.empty() || !m_is_smt2) {
m_out << " ";
}
for (unsigned j = 0; j < accs.size(); ++j) {
func_decl* a = accs[j];
m_out << "(" << m_renaming.get_symbol(a->get_name()) << " ";
visit_sort(a->get_range());
bool first_constr = true;
for (datatype::constructor* f : *d) {
if (!first_constr) m_out << " "; else first_constr = false;
m_out << "(";
m_out << m_renaming.get_symbol(f->name());
for (datatype::accessor* a : *f) {
m_out << " (" << m_renaming.get_symbol(a->name()) << " ";
visit_sort(a->range());
m_out << ")";
if (j + 1 < accs.size()) m_out << " ";
}
if (m_is_smt2 || accs.size() > 0) {
m_out << ")";
if (i + 1 < decls->size()) {
m_out << " ";
}
}
m_out << ")";
}
if (!d->params().empty()) {
m_out << ")";
}
m_out << ")";
if (si + 1 < rec_sorts.size()) {
m_out << " ";
}
}
if (m_is_smt2) {
m_out << ")";
}
m_out << ")";
m_out << "))";
newline();
}
@ -1002,12 +839,7 @@ public:
pp_dt(mark, s);
}
else {
if (m_is_smt2) {
m_out << "(declare-sort ";
}
else {
m_out << ":extrasorts (";
}
m_out << "(declare-sort ";
visit_sort(s);
m_out << ")";
newline();
@ -1021,29 +853,16 @@ public:
}
void operator()(func_decl* d) {
if (m_is_smt2) {
m_out << "(declare-fun ";
pp_decl(d);
m_out << "(";
for (unsigned i = 0; i < d->get_arity(); ++i) {
if (i > 0) m_out << " ";
visit_sort(d->get_domain(i), true);
}
m_out << ") ";
visit_sort(d->get_range());
m_out << ")";
}
else {
m_out << "(";
pp_decl(d);
for (unsigned i = 0; i < d->get_arity(); ++i) {
m_out << " ";
visit_sort(d->get_domain(i), true);
}
m_out << " ";
visit_sort(d->get_range());
m_out << ")";
m_out << "(declare-fun ";
pp_decl(d);
m_out << "(";
for (unsigned i = 0; i < d->get_arity(); ++i) {
if (i > 0) m_out << " ";
visit_sort(d->get_domain(i), true);
}
m_out << ") ";
visit_sort(d->get_range());
m_out << ")";
}
void visit_pred(func_decl* d) {

View file

@ -37,11 +37,9 @@ void ast_translation::cleanup() {
}
void ast_translation::reset_cache() {
obj_map<ast, ast*>::iterator it = m_cache.begin();
obj_map<ast, ast*>::iterator end = m_cache.end();
for (; it != end; ++it) {
m_from_manager.dec_ref(it->m_key);
m_to_manager.dec_ref(it->m_value);
for (auto & kv : m_cache) {
m_from_manager.dec_ref(kv.m_key);
m_to_manager.dec_ref(kv.m_value);
}
m_cache.reset();
}

View file

@ -784,6 +784,12 @@ bool bv_recognizers::is_numeral(expr const * n, rational & val, unsigned & bv_si
return true;
}
bool bv_recognizers::is_numeral(expr const * n, rational & val) const {
unsigned bv_size = 0;
return is_numeral(n, val, bv_size);
}
bool bv_recognizers::is_allone(expr const * e) const {
rational r;
unsigned bv_size;
@ -847,7 +853,7 @@ bv_util::bv_util(ast_manager & m):
m_plugin = static_cast<bv_decl_plugin*>(m.get_plugin(m.mk_family_id("bv")));
}
app * bv_util::mk_numeral(rational const & val, sort* s) {
app * bv_util::mk_numeral(rational const & val, sort* s) const {
if (!is_bv_sort(s)) {
return 0;
}
@ -855,7 +861,7 @@ app * bv_util::mk_numeral(rational const & val, sort* s) {
return mk_numeral(val, bv_size);
}
app * bv_util::mk_numeral(rational const & val, unsigned bv_size) {
app * bv_util::mk_numeral(rational const & val, unsigned bv_size) const {
parameter p1(val);
parameter p[2] = { p1, parameter(static_cast<int>(bv_size)) };
return m_manager.mk_app(get_fid(), OP_BV_NUM, 2, p, 0, 0);

View file

@ -293,6 +293,7 @@ public:
family_id get_fid() const { return m_afid; }
family_id get_family_id() const { return get_fid(); }
bool is_numeral(expr const * n, rational & val) const;
bool is_numeral(expr const * n, rational & val, unsigned & bv_size) const;
bool is_numeral(expr const * n) const { return is_app_of(n, get_fid(), OP_BV_NUM); }
bool is_allone(expr const * e) const;
@ -381,9 +382,9 @@ public:
ast_manager & get_manager() const { return m_manager; }
app * mk_numeral(rational const & val, sort* s);
app * mk_numeral(rational const & val, unsigned bv_size);
app * mk_numeral(uint64 u, unsigned bv_size) { return mk_numeral(rational(u, rational::ui64()), bv_size); }
app * mk_numeral(rational const & val, sort* s) const;
app * mk_numeral(rational const & val, unsigned bv_size) const;
app * mk_numeral(uint64 u, unsigned bv_size) const { return mk_numeral(rational(u, rational::ui64()), bv_size); }
sort * mk_sort(unsigned bv_size);
unsigned get_bv_size(sort const * s) const {

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Copyright (c) 2017 Microsoft Corporation
Module Name:
@ -11,49 +11,390 @@ Abstract:
Author:
Leonardo de Moura (leonardo) 2008-01-09.
Nikolaj Bjorner (nbjorner) 2017-9-1
Revision History:
rewritten to support SMTLIB-2.6 parameters from
Leonardo de Moura (leonardo) 2008-01-09.
--*/
#ifndef DATATYPE_DECL_PLUGIN_H_
#define DATATYPE_DECL_PLUGIN_H_
#include "ast/ast.h"
#include "util/tptr.h"
#include "util/buffer.h"
#include "util/symbol_table.h"
#include "util/obj_hashtable.h"
enum datatype_sort_kind {
enum sort_kind {
DATATYPE_SORT
};
enum datatype_op_kind {
enum op_kind {
OP_DT_CONSTRUCTOR,
OP_DT_RECOGNISER,
OP_DT_ACCESSOR,
OP_DT_IS,
OP_DT_ACCESSOR,
OP_DT_UPDATE_FIELD,
LAST_DT_OP
};
/**
\brief Auxiliary class used to declare inductive datatypes.
It may be a sort or an integer. If it is an integer,
then it represents a reference to a recursive type.
namespace datatype {
For example, consider the datatypes
Datatype
Tree = tree(value:Real, children:TreeList)
TreeList = cons_t(first_t:Tree, rest_t:Tree)
| nil_t
End
The recursive occurrences of Tree and TreeList will have idx 0 and
1 respectively.
class util;
class def;
class accessor;
class constructor;
class accessor {
symbol m_name;
sort_ref m_range;
unsigned m_index; // reference to recursive data-type may only get resolved after all mutually recursive data-types are procssed.
constructor* m_constructor;
public:
accessor(ast_manager& m, symbol const& n, sort* range):
m_name(n),
m_range(range, m),
m_index(UINT_MAX)
{}
accessor(ast_manager& m, symbol const& n, unsigned index):
m_name(n),
m_range(m),
m_index(index)
{}
sort* range() const { return m_range; }
void fix_range(sort_ref_vector const& dts);
symbol const& name() const { return m_name; }
func_decl_ref instantiate(sort_ref_vector const& ps) const;
func_decl_ref instantiate(sort* dt) const;
void attach(constructor* d) { m_constructor = d; }
constructor const& get_constructor() const { return *m_constructor; }
def const& get_def() const;
util& u() const;
accessor* translate(ast_translation& tr);
};
class constructor {
symbol m_name;
symbol m_recognizer;
ptr_vector<accessor> m_accessors;
def* m_def;
public:
constructor(symbol n, symbol const& r): m_name(n), m_recognizer(r) {}
~constructor();
void add(accessor* a) { m_accessors.push_back(a); a->attach(this); }
symbol const& name() const { return m_name; }
symbol const& recognizer() const { return m_recognizer; }
ptr_vector<accessor> const& accessors() const { return m_accessors; }
ptr_vector<accessor>::const_iterator begin() const { return m_accessors.begin(); }
ptr_vector<accessor>::const_iterator end() const { return m_accessors.end(); }
ptr_vector<accessor>::iterator begin() { return m_accessors.begin(); }
ptr_vector<accessor>::iterator end() { return m_accessors.end(); }
func_decl_ref instantiate(sort_ref_vector const& ps) const;
func_decl_ref instantiate(sort* dt) const;
void attach(def* d) { m_def = d; }
def const& get_def() const { return *m_def; }
util& u() const;
constructor* translate(ast_translation& tr);
};
namespace param_size {
class size {
unsigned m_ref;
public:
size(): m_ref(0) {}
virtual ~size() {}
void inc_ref() { ++m_ref; }
void dec_ref() { --m_ref; if (m_ref == 0) dealloc(this); }
static size* mk_offset(sort_size const& s);
static size* mk_param(sort_ref& p);
static size* mk_plus(size* a1, size* a2);
static size* mk_times(size* a1, size* a2);
static size* mk_plus(ptr_vector<size>& szs);
static size* mk_times(ptr_vector<size>& szs);
static size* mk_power(size* a1, size* a2);
virtual size* subst(obj_map<sort, size*>& S) = 0;
virtual sort_size eval(obj_map<sort, sort_size> const& S) = 0;
};
struct offset : public size {
sort_size m_offset;
offset(sort_size const& s): m_offset(s) {}
virtual ~offset() {}
virtual size* subst(obj_map<sort,size*>& S) { return this; }
virtual sort_size eval(obj_map<sort, sort_size> const& S) { return m_offset; }
};
struct plus : public size {
size* m_arg1, *m_arg2;
plus(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref();}
virtual ~plus() { m_arg1->dec_ref(); m_arg2->dec_ref(); }
virtual size* subst(obj_map<sort,size*>& S) { return mk_plus(m_arg1->subst(S), m_arg2->subst(S)); }
virtual sort_size eval(obj_map<sort, sort_size> const& S) {
sort_size s1 = m_arg1->eval(S);
sort_size s2 = m_arg2->eval(S);
if (s1.is_infinite()) return s1;
if (s2.is_infinite()) return s2;
if (s1.is_very_big()) return s1;
if (s2.is_very_big()) return s2;
rational r = rational(s1.size(), rational::ui64()) + rational(s2.size(), rational::ui64());
return sort_size(r);
}
};
struct times : public size {
size* m_arg1, *m_arg2;
times(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); }
virtual ~times() { m_arg1->dec_ref(); m_arg2->dec_ref(); }
virtual size* subst(obj_map<sort,size*>& S) { return mk_times(m_arg1->subst(S), m_arg2->subst(S)); }
virtual sort_size eval(obj_map<sort, sort_size> const& S) {
sort_size s1 = m_arg1->eval(S);
sort_size s2 = m_arg2->eval(S);
if (s1.is_infinite()) return s1;
if (s2.is_infinite()) return s2;
if (s1.is_very_big()) return s1;
if (s2.is_very_big()) return s2;
rational r = rational(s1.size(), rational::ui64()) * rational(s2.size(), rational::ui64());
return sort_size(r);
}
};
struct power : public size {
size* m_arg1, *m_arg2;
power(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); }
virtual ~power() { m_arg1->dec_ref(); m_arg2->dec_ref(); }
virtual size* subst(obj_map<sort,size*>& S) { return mk_power(m_arg1->subst(S), m_arg2->subst(S)); }
virtual sort_size eval(obj_map<sort, sort_size> const& S) {
sort_size s1 = m_arg1->eval(S);
sort_size s2 = m_arg2->eval(S);
// s1^s2
if (s1.is_infinite()) return s1;
if (s2.is_infinite()) return s2;
if (s1.is_very_big()) return s1;
if (s2.is_very_big()) return s2;
if (s1.size() == 1) return s1;
if (s2.size() == 1) return s1;
if (s1.size() > (2 << 20) || s2.size() > 10) return sort_size::mk_very_big();
rational r = ::power(rational(s1.size(), rational::ui64()), static_cast<unsigned>(s2.size()));
return sort_size(r);
}
};
struct sparam : public size {
sort_ref m_param;
sparam(sort_ref& p): m_param(p) {}
virtual ~sparam() {}
virtual size* subst(obj_map<sort,size*>& S) { return S[m_param]; }
virtual sort_size eval(obj_map<sort, sort_size> const& S) { return S[m_param]; }
};
};
class def {
ast_manager& m;
util& m_util;
symbol m_name;
unsigned m_class_id;
param_size::size* m_sort_size;
sort_ref_vector m_params;
mutable sort_ref m_sort;
ptr_vector<constructor> m_constructors;
public:
def(ast_manager& m, util& u, symbol const& n, unsigned class_id, unsigned num_params, sort * const* params):
m(m),
m_util(u),
m_name(n),
m_class_id(class_id),
m_sort_size(0),
m_params(m, num_params, params),
m_sort(m)
{}
~def() {
if (m_sort_size) m_sort_size->dec_ref();
for (constructor* c : m_constructors) dealloc(c);
m_constructors.reset();
}
void add(constructor* c) {
m_constructors.push_back(c);
c->attach(this);
}
symbol const& name() const { return m_name; }
unsigned id() const { return m_class_id; }
sort_ref instantiate(sort_ref_vector const& ps) const;
ptr_vector<constructor> const& constructors() const { return m_constructors; }
ptr_vector<constructor>::const_iterator begin() const { return m_constructors.begin(); }
ptr_vector<constructor>::const_iterator end() const { return m_constructors.end(); }
ptr_vector<constructor>::iterator begin() { return m_constructors.begin(); }
ptr_vector<constructor>::iterator end() { return m_constructors.end(); }
sort_ref_vector const& params() const { return m_params; }
util& u() const { return m_util; }
param_size::size* sort_size() { return m_sort_size; }
void set_sort_size(param_size::size* p) { m_sort_size = p; p->inc_ref(); m_sort = 0; }
def* translate(ast_translation& tr, util& u);
};
namespace decl {
class plugin : public decl_plugin {
mutable scoped_ptr<util> m_util;
map<symbol, def*, symbol_hash_proc, symbol_eq_proc> m_defs;
svector<symbol> m_def_block;
unsigned m_class_id;
util & u() const;
virtual void inherit(decl_plugin* other_p, ast_translation& tr);
public:
plugin(): m_class_id(0) {}
virtual ~plugin();
virtual void finalize();
virtual decl_plugin * mk_fresh() { return alloc(plugin); }
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters);
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
virtual expr * get_some_value(sort * s);
virtual bool is_fully_interp(sort * s) const;
virtual bool is_value(app* e) const;
virtual bool is_unique_value(app * e) const { return is_value(e); }
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
void begin_def_block() { m_class_id++; m_def_block.reset(); }
void end_def_block();
def* mk(symbol const& name, unsigned n, sort * const * params);
void remove(symbol const& d);
bool mk_datatypes(unsigned num_datatypes, def * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_sorts);
def const& get_def(sort* s) const { return *(m_defs[datatype_name(s)]); }
def& get_def(symbol const& s) { return *(m_defs[s]); }
bool is_declared(sort* s) const { return m_defs.contains(datatype_name(s)); }
private:
bool is_value_visit(expr * arg, ptr_buffer<app> & todo) const;
func_decl * mk_update_field(
unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_constructor(
unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_accessor(
unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_recognizer(
unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
func_decl * mk_is(
unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
symbol datatype_name(sort * s) const {
//SASSERT(u().is_datatype(s));
return s->get_parameter(0).get_symbol();
}
};
}
class util {
ast_manager & m;
family_id m_family_id;
mutable decl::plugin* m_plugin;
obj_map<sort, ptr_vector<func_decl> *> m_datatype2constructors;
obj_map<sort, func_decl *> m_datatype2nonrec_constructor;
obj_map<func_decl, ptr_vector<func_decl> *> m_constructor2accessors;
obj_map<func_decl, func_decl *> m_constructor2recognizer;
obj_map<func_decl, func_decl *> m_recognizer2constructor;
obj_map<func_decl, func_decl *> m_accessor2constructor;
obj_map<sort, bool> m_is_recursive;
obj_map<sort, bool> m_is_enum;
mutable obj_map<sort, bool> m_is_fully_interp;
mutable ast_ref_vector m_asts;
ptr_vector<ptr_vector<func_decl> > m_vectors;
unsigned m_start;
mutable ptr_vector<sort> m_fully_interp_trail;
func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set);
friend class decl::plugin;
bool is_recursive_core(sort * s) const;
sort_size get_datatype_size(sort* s0);
void compute_datatype_size_functions(svector<symbol> const& names);
param_size::size* get_sort_size(sort_ref_vector const& params, sort* s);
bool is_well_founded(unsigned num_types, sort* const* sorts);
def& get_def(symbol const& s) { return m_plugin->get_def(s); }
void get_subsorts(sort* s, ptr_vector<sort>& sorts) const;
public:
util(ast_manager & m);
~util();
ast_manager & get_manager() const { return m; }
// sort * mk_datatype_sort(symbol const& name, unsigned n, sort* const* params);
bool is_datatype(sort const* s) const { return is_sort_of(s, m_family_id, DATATYPE_SORT); }
bool is_enum_sort(sort* s);
bool is_recursive(sort * ty);
bool is_constructor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_CONSTRUCTOR); }
bool is_recognizer(func_decl * f) const { return is_recognizer0(f) || is_is(f); }
bool is_recognizer0(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_RECOGNISER); }
bool is_is(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_IS); }
bool is_accessor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_ACCESSOR); }
bool is_update_field(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_UPDATE_FIELD); }
bool is_constructor(app * f) const { return is_app_of(f, m_family_id, OP_DT_CONSTRUCTOR); }
bool is_recognizer0(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER);}
bool is_is(app * f) const { return is_app_of(f, m_family_id, OP_DT_IS);}
bool is_recognizer(app * f) const { return is_recognizer0(f) || is_is(f); }
bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); }
bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); }
ptr_vector<func_decl> const * get_datatype_constructors(sort * ty);
unsigned get_datatype_num_constructors(sort * ty);
unsigned get_datatype_num_parameter_sorts(sort * ty);
sort* get_datatype_parameter_sort(sort * ty, unsigned idx);
func_decl * get_non_rec_constructor(sort * ty);
func_decl * get_constructor_recognizer(func_decl * constructor);
ptr_vector<func_decl> const * get_constructor_accessors(func_decl * constructor);
func_decl * get_accessor_constructor(func_decl * accessor);
func_decl * get_recognizer_constructor(func_decl * recognizer) const;
family_id get_family_id() const { return m_family_id; }
bool are_siblings(sort * s1, sort * s2);
bool is_func_decl(op_kind k, unsigned num_params, parameter const* params, func_decl* f);
bool is_constructor_of(unsigned num_params, parameter const* params, func_decl* f);
void reset();
bool is_declared(sort* s) const;
void display_datatype(sort *s, std::ostream& strm);
bool is_fully_interp(sort * s) const;
sort_ref_vector datatype_params(sort * s) const;
unsigned get_constructor_idx(func_decl * f) const;
unsigned get_recognizer_constructor_idx(func_decl * f) const;
decl::plugin* get_plugin() { return m_plugin; }
void get_defs(sort* s, ptr_vector<def>& defs);
def const& get_def(sort* s) const;
};
};
typedef datatype::accessor accessor_decl;
typedef datatype::constructor constructor_decl;
typedef datatype::def datatype_decl;
typedef datatype::decl::plugin datatype_decl_plugin;
typedef datatype::util datatype_util;
This is a transient value, it is only used to declare a set of
recursive datatypes.
*/
class type_ref {
void * m_data;
public:
@ -67,181 +408,29 @@ public:
int get_idx() const { return UNBOXINT(m_data); }
};
class accessor_decl;
class constructor_decl;
class datatype_decl;
class datatype_util;
inline accessor_decl * mk_accessor_decl(ast_manager& m, symbol const & n, type_ref const & t) {
if (t.is_idx()) {
return alloc(accessor_decl, m, n, t.get_idx());
}
else {
return alloc(accessor_decl, m, n, t.get_sort());
}
}
inline constructor_decl * mk_constructor_decl(symbol const & n, symbol const & r, unsigned num_accessors, accessor_decl * * acs) {
constructor_decl* c = alloc(constructor_decl, n, r);
for (unsigned i = 0; i < num_accessors; ++i) {
c->add(acs[i]);
}
return c;
}
accessor_decl * mk_accessor_decl(symbol const & n, type_ref const & t);
void del_accessor_decl(accessor_decl * d);
void del_accessor_decls(unsigned num, accessor_decl * const * as);
// Remark: the constructor becomes the owner of the accessor_decls
constructor_decl * mk_constructor_decl(symbol const & n, symbol const & r, unsigned num_accessors, accessor_decl * const * acs);
void del_constructor_decl(constructor_decl * d);
void del_constructor_decls(unsigned num, constructor_decl * const * cs);
// Remark: the datatype becomes the owner of the constructor_decls
datatype_decl * mk_datatype_decl(symbol const & n, unsigned num_constructors, constructor_decl * const * cs);
void del_datatype_decl(datatype_decl * d);
void del_datatype_decls(unsigned num, datatype_decl * const * ds);
datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_params, sort*const* params, unsigned num_constructors, constructor_decl * const * cs);
inline void del_datatype_decl(datatype_decl * d) {}
inline void del_datatype_decls(unsigned num, datatype_decl * const * ds) {}
class datatype_decl_plugin : public decl_plugin {
mutable scoped_ptr<datatype_util> m_util;
datatype_util & get_util() const;
public:
datatype_decl_plugin() {}
virtual ~datatype_decl_plugin();
virtual void finalize();
virtual decl_plugin * mk_fresh() { return alloc(datatype_decl_plugin); }
/**
Contract for sort:
parameters[0] - (int) n - number of recursive types.
parameters[1] - (int) i - index 0..n-1 of which type is defined.
parameters[2] - (int) p - number of type parameters.
for j = 0..p-1
parameters[3 + j] - (sort) s - type parameter
c_offset := 3 + p
for j in 0..n-1
parameters[c_offset + 2*j] - (symbol) name of the type
parameters[c_offset + 2*j + 1] - (int) o - offset where the constructors are defined.
for each offset o at parameters[2 + 2*j + 1] for some j in 0..n-1
parameters[o] - (int) m - number of constructors
parameters[o+1] - (int) k_1 - offset for constructor definition
...
parameters[o+m] - (int) k_m - offset for constructor definition
for each offset k_i at parameters[o+s] for some s in 0..m-1
parameters[k_i] - (symbol) name of the constructor
parameters[k_i+1] - (symbol) name of the recognizer
parameters[k_i+2] - (int) m' - number of accessors
parameters[k_i+3+2*r] - (symbol) name of the r accessor
parameters[k_i+3+2*r+1] - (int or type_ast) type of the accessor. If integer, then the value must be in [0..n-1], and it
represents an reference to the recursive type.
The idea with the additional offsets is that
access to relevant constructors and types can be performed using
a few address calculations.
*/
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters);
/**
Contract for constructors
parameters[0] - (ast) datatype ast.
parmaeters[1] - (int) constructor idx.
Contract for accessors
parameters[0] - (ast) datatype ast.
parameters[1] - (int) constructor idx.
parameters[2] - (int) accessor idx.
Contract for tester
parameters[0] - (ast) datatype ast.
parameters[1] - (int) constructor idx.
*/
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
bool mk_datatypes(unsigned num_datatypes, datatype_decl * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_sorts);
virtual expr * get_some_value(sort * s);
virtual bool is_fully_interp(sort const * s) const;
virtual bool is_value(app* e) const;
virtual bool is_unique_value(app * e) const { return is_value(e); }
virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic);
static unsigned constructor_offset(sort const* s);
static unsigned constructor_offset(parameter const& p);
static unsigned constructor_offset(parameter const* ps);
static unsigned constructor_offset(sort const* s, unsigned tid);
static unsigned constructor_offset(parameter const* ps, unsigned tid);
private:
bool is_value_visit(expr * arg, ptr_buffer<app> & todo) const;
func_decl * mk_update_field(
unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range);
};
class datatype_util {
ast_manager & m_manager;
family_id m_family_id;
func_decl * get_constructor(sort * ty, unsigned c_id) const;
obj_map<sort, ptr_vector<func_decl> *> m_datatype2constructors;
obj_map<sort, func_decl *> m_datatype2nonrec_constructor;
obj_map<func_decl, ptr_vector<func_decl> *> m_constructor2accessors;
obj_map<func_decl, func_decl *> m_constructor2recognizer;
obj_map<func_decl, func_decl *> m_recognizer2constructor;
obj_map<func_decl, func_decl *> m_accessor2constructor;
obj_map<sort, bool> m_is_recursive;
obj_map<sort, bool> m_is_enum;
ast_ref_vector m_asts;
ptr_vector<ptr_vector<func_decl> > m_vectors;
unsigned m_start;
func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set);
func_decl * get_constructor(sort * ty, unsigned c_id);
public:
datatype_util(ast_manager & m);
~datatype_util();
ast_manager & get_manager() const { return m_manager; }
bool is_datatype(sort * s) const { return is_sort_of(s, m_family_id, DATATYPE_SORT); }
bool is_enum_sort(sort* s);
bool is_recursive(sort * ty);
bool is_constructor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_CONSTRUCTOR); }
bool is_recognizer(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_RECOGNISER); }
bool is_accessor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_ACCESSOR); }
bool is_update_field(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_UPDATE_FIELD); }
bool is_constructor(app * f) const { return is_app_of(f, m_family_id, OP_DT_CONSTRUCTOR); }
bool is_recognizer(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER); }
bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); }
bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); }
ptr_vector<func_decl> const * get_datatype_constructors(sort * ty);
unsigned get_datatype_num_constructors(sort * ty) {
SASSERT(is_datatype(ty));
unsigned tid = ty->get_parameter(1).get_int();
unsigned o = datatype_decl_plugin::constructor_offset(ty, tid);
return ty->get_parameter(o).get_int();
}
unsigned get_datatype_num_parameter_sorts(sort * ty) {
SASSERT(is_datatype(ty));
return ty->get_parameter(2).get_int();
}
sort* get_datatype_parameter_sort(sort * ty, unsigned idx) {
SASSERT(is_datatype(ty));
SASSERT(idx < get_datatype_num_parameter_sorts(ty));
return to_sort(ty->get_parameter(3 + idx).get_ast());
}
unsigned get_constructor_idx(func_decl * f) const { SASSERT(is_constructor(f)); return f->get_parameter(1).get_int(); }
unsigned get_recognizer_constructor_idx(func_decl * f) const { SASSERT(is_recognizer(f)); return f->get_parameter(1).get_int(); }
func_decl * get_non_rec_constructor(sort * ty);
func_decl * get_constructor_recognizer(func_decl * constructor);
ptr_vector<func_decl> const * get_constructor_accessors(func_decl * constructor);
func_decl * get_accessor_constructor(func_decl * accessor);
func_decl * get_recognizer_constructor(func_decl * recognizer);
family_id get_family_id() const { return m_family_id; }
bool are_siblings(sort * s1, sort * s2);
bool is_func_decl(datatype_op_kind k, unsigned num_params, parameter const* params, func_decl* f);
bool is_constructor_of(unsigned num_params, parameter const* params, func_decl* f);
void reset();
void display_datatype(sort *s, std::ostream& strm);
};
#endif /* DATATYPE_DECL_PLUGIN_H_ */

View file

@ -52,4 +52,38 @@ public:
void cleanup();
};
class scoped_expr_substitution {
expr_substitution& m_subst;
expr_ref_vector m_trail;
unsigned_vector m_trail_lim;
public:
scoped_expr_substitution(expr_substitution& s): m_subst(s), m_trail(s.m()) {}
~scoped_expr_substitution() {}
void insert(expr * s, expr * def, proof * def_pr = 0, expr_dependency * def_dep = 0) {
if (!m_subst.contains(s)) {
m_subst.insert(s, def, def_pr, def_dep);
m_trail.push_back(s);
}
}
void reset() { m_subst.reset(); m_trail.reset(); m_trail_lim.reset(); }
void push() { m_trail_lim.push_back(m_trail.size()); }
void pop(unsigned n) {
if (n > 0) {
unsigned new_sz = m_trail_lim.size() - n;
unsigned old_sz = m_trail_lim[new_sz];
for (unsigned i = old_sz; i < m_trail.size(); ++i) m_subst.erase(m_trail[i].get());
m_trail.resize(old_sz);
m_trail_lim.resize(new_sz);
}
}
bool empty() const { return m_subst.empty(); }
expr* find(expr * e) { proof* pr; expr* d = 0; if (find(e, d, pr)) return d; else return e; }
bool find(expr * s, expr * & def, proof * & def_pr) { return m_subst.find(s, def, def_pr); }
bool find(expr * s, expr * & def, proof * & def_pr, expr_dependency * & def_dep) { return m_subst.find(s, def, def_pr, def_dep); }
bool contains(expr * s) { return m_subst.contains(s); }
void cleanup() { m_subst.cleanup(); }
};
#endif

View file

@ -5,7 +5,7 @@ z3_add_component(fpa
fpa2bv_rewriter.cpp
COMPONENT_DEPENDENCIES
ast
simplifier
rewriter
model
util
PYG_FILES

View file

@ -29,7 +29,7 @@ Notes:
#include "ast/dl_decl_plugin.h"
#include "ast/pb_decl_plugin.h"
#include "ast/seq_decl_plugin.h"
#include "ast/simplifier/basic_simplifier_plugin.h"
#include "ast/rewriter/bool_rewriter.h"
class fpa2bv_converter {
public:
@ -39,7 +39,7 @@ public:
protected:
ast_manager & m;
basic_simplifier_plugin m_simp;
bool_rewriter m_simp;
fpa_util m_util;
bv_util m_bv_util;
arith_util m_arith_util;

52
src/ast/justified_expr.h Normal file
View file

@ -0,0 +1,52 @@
#ifndef JUSTIFIED_EXPR_H_
#define JUSTIFIED_EXPR_H_
#include "ast/ast.h"
class justified_expr {
ast_manager& m;
expr* m_fml;
proof* m_proof;
public:
justified_expr(ast_manager& m, expr* fml, proof* p):
m(m),
m_fml(fml),
m_proof(p) {
SASSERT(fml);
m.inc_ref(fml);
m.inc_ref(p);
}
justified_expr& operator=(justified_expr const& other) {
SASSERT(&m == &other.m);
if (this != &other) {
m.inc_ref(other.get_fml());
m.inc_ref(other.get_proof());
m.dec_ref(m_fml);
m.dec_ref(m_proof);
m_fml = other.get_fml();
m_proof = other.get_proof();
}
return *this;
}
justified_expr(justified_expr const& other):
m(other.m),
m_fml(other.m_fml),
m_proof(other.m_proof)
{
m.inc_ref(m_fml);
m.inc_ref(m_proof);
}
~justified_expr() {
m.dec_ref(m_fml);
m.dec_ref(m_proof);
}
expr* get_fml() const { return m_fml; }
proof* get_proof() const { return m_proof; }
};
#endif

View file

@ -5,5 +5,5 @@ z3_add_component(macros
macro_util.cpp
quasi_macros.cpp
COMPONENT_DEPENDENCIES
simplifier
rewriter
)

View file

@ -25,7 +25,7 @@ Revision History:
bool macro_finder::is_macro(expr * n, app_ref & head, expr_ref & def) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
return false;
TRACE("macro_finder", tout << "processing: " << mk_pp(n, m_manager) << "\n";);
TRACE("macro_finder", tout << "processing: " << mk_pp(n, m) << "\n";);
expr * body = to_quantifier(n)->get_expr();
unsigned num_decls = to_quantifier(n)->get_num_decls();
return m_util.is_simple_macro(body, num_decls, head, def);
@ -48,67 +48,64 @@ bool macro_finder::is_macro(expr * n, app_ref & head, expr_ref & def) {
bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_dependency * dep, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
return false;
arith_simplifier_plugin * as = get_arith_simp();
arith_util & autil = as->get_arith_util();
expr * body = to_quantifier(n)->get_expr();
unsigned num_decls = to_quantifier(n)->get_num_decls();
if (!autil.is_le(body) && !autil.is_ge(body) && !m_manager.is_eq(body))
if (!m_autil.is_le(body) && !m_autil.is_ge(body) && !m.is_eq(body))
return false;
if (!as->is_add(to_app(body)->get_arg(0)))
if (!m_autil.is_add(to_app(body)->get_arg(0)))
return false;
app_ref head(m_manager);
expr_ref def(m_manager);
app_ref head(m);
expr_ref def(m);
bool inv = false;
if (!m_util.is_arith_macro(body, num_decls, head, def, inv))
return false;
app_ref new_body(m_manager);
app_ref new_body(m);
if (!inv || m_manager.is_eq(body))
new_body = m_manager.mk_app(to_app(body)->get_decl(), head, def);
else if (as->is_le(body))
new_body = autil.mk_ge(head, def);
if (!inv || m.is_eq(body))
new_body = m.mk_app(to_app(body)->get_decl(), head, def);
else if (m_autil.is_le(body))
new_body = m_autil.mk_ge(head, def);
else
new_body = autil.mk_le(head, def);
new_body = m_autil.mk_le(head, def);
quantifier_ref new_q(m_manager);
new_q = m_manager.update_quantifier(to_quantifier(n), new_body);
quantifier_ref new_q(m);
new_q = m.update_quantifier(to_quantifier(n), new_body);
proof * new_pr = 0;
if (m_manager.proofs_enabled()) {
proof * rw = m_manager.mk_rewrite(n, new_q);
new_pr = m_manager.mk_modus_ponens(pr, rw);
if (m.proofs_enabled()) {
proof * rw = m.mk_rewrite(n, new_q);
new_pr = m.mk_modus_ponens(pr, rw);
}
expr_dependency * new_dep = dep;
if (m_manager.is_eq(body)) {
if (m.is_eq(body)) {
return m_macro_manager.insert(head->get_decl(), new_q, new_pr, new_dep);
}
// is ge or le
//
TRACE("macro_finder", tout << "is_arith_macro: is_ge or is_le\n";);
func_decl * f = head->get_decl();
func_decl * k = m_manager.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range());
app * k_app = m_manager.mk_app(k, head->get_num_args(), head->get_args());
expr_ref_buffer new_rhs_args(m_manager);
expr_ref new_rhs2(m_manager);
as->mk_add(def, k_app, new_rhs2);
expr * body1 = m_manager.mk_eq(head, new_rhs2);
expr * body2 = m_manager.mk_app(new_body->get_decl(), k_app, as->mk_numeral(rational(0)));
quantifier * q1 = m_manager.update_quantifier(new_q, body1);
expr * patterns[1] = { m_manager.mk_pattern(k_app) };
quantifier * q2 = m_manager.update_quantifier(new_q, 1, patterns, body2);
func_decl * k = m.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range());
app * k_app = m.mk_app(k, head->get_num_args(), head->get_args());
expr_ref_buffer new_rhs_args(m);
expr_ref new_rhs2(m_autil.mk_add(def, k_app), m);
expr * body1 = m.mk_eq(head, new_rhs2);
expr * body2 = m.mk_app(new_body->get_decl(), k_app, m_autil.mk_int(0));
quantifier * q1 = m.update_quantifier(new_q, body1);
expr * patterns[1] = { m.mk_pattern(k_app) };
quantifier * q2 = m.update_quantifier(new_q, 1, patterns, body2);
new_exprs.push_back(q1);
new_exprs.push_back(q2);
if (m_manager.proofs_enabled()) {
if (m.proofs_enabled()) {
// new_pr : new_q
// rw : [rewrite] new_q ~ q1 & q2
// mp : [modus_pones new_pr rw] q1 & q2
// pr1 : [and-elim mp] q1
// pr2 : [and-elim mp] q2
app * q1q2 = m_manager.mk_and(q1,q2);
proof * rw = m_manager.mk_oeq_rewrite(new_q, q1q2);
proof * mp = m_manager.mk_modus_ponens(new_pr, rw);
proof * pr1 = m_manager.mk_and_elim(mp, 0);
proof * pr2 = m_manager.mk_and_elim(mp, 1);
app * q1q2 = m.mk_and(q1,q2);
proof * rw = m.mk_oeq_rewrite(new_q, q1q2);
proof * mp = m.mk_modus_ponens(new_pr, rw);
proof * pr1 = m.mk_and_elim(mp, 0);
proof * pr2 = m.mk_and_elim(mp, 1);
new_prs.push_back(pr1);
new_prs.push_back(pr2);
}
@ -119,6 +116,71 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_dependency * dep, e
return true;
}
bool macro_finder::is_arith_macro(expr * n, proof * pr, vector<justified_expr>& new_fmls) {
if (!is_quantifier(n) || !to_quantifier(n)->is_forall())
return false;
expr * body = to_quantifier(n)->get_expr();
unsigned num_decls = to_quantifier(n)->get_num_decls();
if (!m_autil.is_le(body) && !m_autil.is_ge(body) && !m.is_eq(body))
return false;
if (!m_autil.is_add(to_app(body)->get_arg(0)))
return false;
app_ref head(m);
expr_ref def(m);
bool inv = false;
if (!m_util.is_arith_macro(body, num_decls, head, def, inv))
return false;
app_ref new_body(m);
if (!inv || m.is_eq(body))
new_body = m.mk_app(to_app(body)->get_decl(), head, def);
else if (m_autil.is_le(body))
new_body = m_autil.mk_ge(head, def);
else
new_body = m_autil.mk_le(head, def);
quantifier_ref new_q(m);
new_q = m.update_quantifier(to_quantifier(n), new_body);
proof * new_pr = 0;
if (m.proofs_enabled()) {
proof * rw = m.mk_rewrite(n, new_q);
new_pr = m.mk_modus_ponens(pr, rw);
}
if (m.is_eq(body)) {
return m_macro_manager.insert(head->get_decl(), new_q, new_pr);
}
// is ge or le
//
TRACE("macro_finder", tout << "is_arith_macro: is_ge or is_le\n";);
func_decl * f = head->get_decl();
func_decl * k = m.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range());
app * k_app = m.mk_app(k, head->get_num_args(), head->get_args());
expr_ref_buffer new_rhs_args(m);
expr_ref new_rhs2(m_autil.mk_add(def, k_app), m);
expr * body1 = m.mk_eq(head, new_rhs2);
expr * body2 = m.mk_app(new_body->get_decl(), k_app, m_autil.mk_int(0));
quantifier * q1 = m.update_quantifier(new_q, body1);
expr * patterns[1] = { m.mk_pattern(k_app) };
quantifier * q2 = m.update_quantifier(new_q, 1, patterns, body2);
proof* pr1 = 0, *pr2 = 0;
if (m.proofs_enabled()) {
// new_pr : new_q
// rw : [rewrite] new_q ~ q1 & q2
// mp : [modus_pones new_pr rw] q1 & q2
// pr1 : [and-elim mp] q1
// pr2 : [and-elim mp] q2
app * q1q2 = m.mk_and(q1,q2);
proof * rw = m.mk_oeq_rewrite(new_q, q1q2);
proof * mp = m.mk_modus_ponens(new_pr, rw);
pr1 = m.mk_and_elim(mp, 0);
pr2 = m.mk_and_elim(mp, 1);
}
new_fmls.push_back(justified_expr(m, q1, pr1));
new_fmls.push_back(justified_expr(m, q2, pr2));
return true;
}
/**
n is of the form: (forall (X) (iff (= (f X) t) def[X]))
@ -162,10 +224,39 @@ static void pseudo_predicate_macro2macro(ast_manager & m, app * head, app * t, e
new_deps.push_back(dep);
}
static void pseudo_predicate_macro2macro(ast_manager & m, app * head, app * t, expr * def, quantifier * q, proof * pr,
vector<justified_expr>& new_fmls) {
func_decl * f = head->get_decl();
func_decl * k = m.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range());
app * k_app = m.mk_app(k, head->get_num_args(), head->get_args());
app * ite = m.mk_ite(def, t, k_app);
app * body_1 = m.mk_eq(head, ite);
app * body_2 = m.mk_not(m.mk_eq(k_app, t));
quantifier * q1 = m.update_quantifier(q, body_1);
proof * pr1 = 0, *pr2 = 0;
expr * pats[1] = { m.mk_pattern(k_app) };
quantifier * q2 = m.update_quantifier(q, 1, pats, body_2); // erase patterns
if (m.proofs_enabled()) {
// r : [rewrite] q ~ q1 & q2
// pr : q
// mp : [modus_pones pr pr1] q1 & q2
// pr1 : [and-elim mp] q1
// pr2 : [and-elim mp] q2
app * q1q2 = m.mk_and(q1,q2);
proof * r = m.mk_oeq_rewrite(q, q1q2);
proof * mp = m.mk_modus_ponens(pr, r);
pr1 = m.mk_and_elim(mp, 0);
pr2 = m.mk_and_elim(mp, 1);
}
new_fmls.push_back(justified_expr(m, q1, pr1));
new_fmls.push_back(justified_expr(m, q2, pr2));
}
macro_finder::macro_finder(ast_manager & m, macro_manager & mm):
m_manager(m),
m(m),
m_macro_manager(mm),
m_util(mm.get_util()) {
m_util(mm.get_util()),
m_autil(m) {
}
macro_finder::~macro_finder() {
@ -177,13 +268,13 @@ bool macro_finder::expand_macros(unsigned num, expr * const * exprs, proof * con
bool found_new_macro = false;
for (unsigned i = 0; i < num; i++) {
expr * n = exprs[i];
proof * pr = m_manager.proofs_enabled() ? prs[i] : 0;
proof * pr = m.proofs_enabled() ? prs[i] : 0;
expr_dependency * depi = deps != 0 ? deps[i] : 0;
expr_ref new_n(m_manager), def(m_manager);
proof_ref new_pr(m_manager);
expr_dependency_ref new_dep(m_manager);
expr_ref new_n(m), def(m);
proof_ref new_pr(m);
expr_dependency_ref new_dep(m);
m_macro_manager.expand_macros(n, pr, depi, new_n, new_pr, new_dep);
app_ref head(m_manager), t(m_manager);
app_ref head(m), t(m);
if (is_macro(new_n, head, def) && m_macro_manager.insert(head->get_decl(), to_quantifier(new_n.get()), new_pr, new_dep)) {
TRACE("macro_finder_found", tout << "found new macro: " << head->get_decl()->get_name() << "\n" << new_n << "\n";);
found_new_macro = true;
@ -194,12 +285,12 @@ bool macro_finder::expand_macros(unsigned num, expr * const * exprs, proof * con
}
else if (m_util.is_pseudo_predicate_macro(new_n, head, t, def)) {
TRACE("macro_finder_found", tout << "found new pseudo macro:\n" << head << "\n" << t << "\n" << def << "\n";);
pseudo_predicate_macro2macro(m_manager, head, t, def, to_quantifier(new_n), new_pr, new_dep, new_exprs, new_prs, new_deps);
pseudo_predicate_macro2macro(m, head, t, def, to_quantifier(new_n), new_pr, new_dep, new_exprs, new_prs, new_deps);
found_new_macro = true;
}
else {
new_exprs.push_back(new_n);
if (m_manager.proofs_enabled())
if (m.proofs_enabled())
new_prs.push_back(new_pr);
if (deps != 0)
new_deps.push_back(new_dep);
@ -210,14 +301,14 @@ bool macro_finder::expand_macros(unsigned num, expr * const * exprs, proof * con
void macro_finder::operator()(unsigned num, expr * const * exprs, proof * const * prs, expr_dependency * const * deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps) {
TRACE("macro_finder", tout << "processing macros...\n";);
expr_ref_vector _new_exprs(m_manager);
proof_ref_vector _new_prs(m_manager);
expr_dependency_ref_vector _new_deps(m_manager);
expr_ref_vector _new_exprs(m);
proof_ref_vector _new_prs(m);
expr_dependency_ref_vector _new_deps(m);
if (expand_macros(num, exprs, prs, deps, _new_exprs, _new_prs, _new_deps)) {
while (true) {
expr_ref_vector old_exprs(m_manager);
proof_ref_vector old_prs(m_manager);
expr_dependency_ref_vector old_deps(m_manager);
expr_ref_vector old_exprs(m);
proof_ref_vector old_prs(m);
expr_dependency_ref_vector old_deps(m);
_new_exprs.swap(old_exprs);
_new_prs.swap(old_prs);
_new_deps.swap(old_deps);
@ -235,3 +326,52 @@ void macro_finder::operator()(unsigned num, expr * const * exprs, proof * const
}
bool macro_finder::expand_macros(unsigned num, justified_expr const * fmls, vector<justified_expr>& new_fmls) {
TRACE("macro_finder", tout << "starting expand_macros:\n";
m_macro_manager.display(tout););
bool found_new_macro = false;
for (unsigned i = 0; i < num; i++) {
expr * n = fmls[i].get_fml();
proof * pr = m.proofs_enabled() ? fmls[i].get_proof() : 0;
expr_ref new_n(m), def(m);
proof_ref new_pr(m);
expr_dependency_ref new_dep(m);
m_macro_manager.expand_macros(n, pr, 0, new_n, new_pr, new_dep);
app_ref head(m), t(m);
if (is_macro(new_n, head, def) && m_macro_manager.insert(head->get_decl(), to_quantifier(new_n.get()), new_pr)) {
TRACE("macro_finder_found", tout << "found new macro: " << head->get_decl()->get_name() << "\n" << new_n << "\n";);
found_new_macro = true;
}
else if (is_arith_macro(new_n, new_pr, new_fmls)) {
TRACE("macro_finder_found", tout << "found new arith macro:\n" << new_n << "\n";);
found_new_macro = true;
}
else if (m_util.is_pseudo_predicate_macro(new_n, head, t, def)) {
TRACE("macro_finder_found", tout << "found new pseudo macro:\n" << head << "\n" << t << "\n" << def << "\n";);
pseudo_predicate_macro2macro(m, head, t, def, to_quantifier(new_n), new_pr, new_fmls);
found_new_macro = true;
}
else {
new_fmls.push_back(justified_expr(m, new_n, new_pr));
}
}
return found_new_macro;
}
void macro_finder::operator()(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls) {
TRACE("macro_finder", tout << "processing macros...\n";);
vector<justified_expr> _new_fmls;
if (expand_macros(n, fmls, _new_fmls)) {
while (true) {
vector<justified_expr> old_fmls;
_new_fmls.swap(old_fmls);
SASSERT(_new_fmls.empty());
if (!expand_macros(old_fmls.size(), old_fmls.c_ptr(), _new_fmls))
break;
}
}
new_fmls.append(_new_fmls);
}

View file

@ -20,7 +20,6 @@ Revision History:
#define MACRO_FINDER_H_
#include "ast/macros/macro_manager.h"
#include "ast/simplifier/arith_simplifier_plugin.h"
/**
@ -28,18 +27,24 @@ Revision History:
as macros.
*/
class macro_finder {
ast_manager & m_manager;
ast_manager & m;
macro_manager & m_macro_manager;
macro_util & m_util;
arith_simplifier_plugin * get_arith_simp() { return m_util.get_arith_simp(); }
bool expand_macros(unsigned num, expr * const * exprs, proof * const * prs, expr_dependency * const * deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps);
arith_util m_autil;
bool expand_macros(unsigned num, expr * const * exprs, proof * const * prs, expr_dependency * const* deps,
expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector& new_deps);
bool expand_macros(unsigned n, justified_expr const * fmls, vector<justified_expr>& new_fmls);
bool is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_exprs, proof_ref_vector & new_prs);
bool is_arith_macro(expr * n, proof * pr, vector<justified_expr>& new_fmls);
bool is_arith_macro(expr * n, proof * pr, expr_dependency * dep, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps);
bool is_macro(expr * n, app_ref & head, expr_ref & def);
public:
macro_finder(ast_manager & m, macro_manager & mm);
~macro_finder();
void operator()(unsigned num, expr * const * exprs, proof * const * prs, expr_dependency * const * deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps);
void operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const* deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps);
void operator()(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls);
};
#endif /* MACRO_FINDER_H_ */

View file

@ -22,13 +22,15 @@ Revision History:
#include "ast/macros/macro_manager.h"
#include "ast/for_each_expr.h"
#include "ast/rewriter/var_subst.h"
#include "ast/rewriter/th_rewriter.h"
#include "ast/rewriter/rewriter_def.h"
#include "ast/ast_pp.h"
#include "ast/recurse_expr_def.h"
macro_manager::macro_manager(ast_manager & m, simplifier & s) :
m_manager(m),
m_simplifier(s),
m_util(m, s),
macro_manager::macro_manager(ast_manager & m):
m(m),
m_util(m),
m_decls(m),
m_macros(m),
m_macro_prs(m),
@ -61,14 +63,13 @@ void macro_manager::restore_decls(unsigned old_sz) {
for (unsigned i = old_sz; i < sz; i++) {
m_decl2macro.erase(m_decls.get(i));
m_deps.erase(m_decls.get(i));
if (m_manager.proofs_enabled()) {
if (m.proofs_enabled())
m_decl2macro_pr.erase(m_decls.get(i));
m_decl2macro_dep.erase(m_decls.get(i));
}
m_decl2macro_dep.erase(m_decls.get(i));
}
m_decls.shrink(old_sz);
m_macros.shrink(old_sz);
if (m_manager.proofs_enabled())
if (m.proofs_enabled())
m_macro_prs.shrink(old_sz);
m_macro_deps.shrink(old_sz);
}
@ -94,8 +95,8 @@ void macro_manager::reset() {
m_deps.reset();
}
bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr, expr_dependency * dep) {
TRACE("macro_insert", tout << "trying to create macro: " << f->get_name() << "\n" << mk_pp(m, m_manager) << "\n";);
bool macro_manager::insert(func_decl * f, quantifier * q, proof * pr, expr_dependency* dep) {
TRACE("macro_insert", tout << "trying to create macro: " << f->get_name() << "\n" << mk_pp(q, m) << "\n";);
// if we already have a macro for f then return false;
if (m_decls.contains(f)) {
@ -105,7 +106,7 @@ bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr, expr_depen
app * head;
expr * definition;
get_head_def(m, f, head, definition);
get_head_def(q, f, head, definition);
func_decl_set * s = m_deps.mk_func_decl_set();
m_deps.collect_func_decls(definition, s);
@ -114,10 +115,10 @@ bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr, expr_depen
}
// add macro
m_decl2macro.insert(f, m);
m_decl2macro.insert(f, q);
m_decls.push_back(f);
m_macros.push_back(m);
if (m_manager.proofs_enabled()) {
m_macros.push_back(q);
if (m.proofs_enabled()) {
m_macro_prs.push_back(pr);
m_decl2macro_pr.insert(f, pr);
}
@ -158,9 +159,17 @@ void macro_manager::mark_forbidden(unsigned n, expr * const * exprs) {
for_each_expr(p, visited, exprs[i]);
}
void macro_manager::mark_forbidden(unsigned n, justified_expr const * exprs) {
expr_mark visited;
macro_manager_ns::proc p(m_forbidden_set, m_forbidden);
for (unsigned i = 0; i < n; i++)
for_each_expr(p, visited, exprs[i].get_fml());
}
void macro_manager::get_head_def(quantifier * q, func_decl * d, app * & head, expr * & def) const {
app * body = to_app(q->get_expr());
SASSERT(m_manager.is_eq(body) || m_manager.is_iff(body));
SASSERT(m.is_eq(body) || m.is_iff(body));
expr * lhs = to_app(body)->get_arg(0);
expr * rhs = to_app(body)->get_arg(1);
SASSERT(is_app_of(lhs, d) || is_app_of(rhs, d));
@ -185,7 +194,7 @@ void macro_manager::display(std::ostream & out) {
expr * def;
get_head_def(q, f, head, def);
SASSERT(q);
out << mk_pp(head, m_manager) << " ->\n" << mk_pp(def, m_manager) << "\n";
out << mk_pp(head, m) << " ->\n" << mk_pp(def, m) << "\n";
}
}
@ -196,134 +205,151 @@ func_decl * macro_manager::get_macro_interpretation(unsigned i, expr_ref & inter
expr * def;
get_head_def(q, f, head, def);
TRACE("macro_bug",
tout << f->get_name() << "\n" << mk_pp(head, m_manager) << "\n" << mk_pp(q, m_manager) << "\n";);
tout << f->get_name() << "\n" << mk_pp(head, m) << "\n" << mk_pp(q, m) << "\n";);
m_util.mk_macro_interpretation(head, q->get_num_decls(), def, interp);
return f;
}
macro_manager::macro_expander::macro_expander(ast_manager & m, macro_manager & mm, simplifier & s):
simplifier(m),
m_macro_manager(mm),
m_used_macro_dependencies(m) {
// REMARK: theory simplifier should not be used by macro_expander...
// is_arith_macro rewrites a quantifer such as:
// forall (x Int) (= (+ x (+ (f x) 1)) 2)
// into
// forall (x Int) (= (f x) (+ 1 (* -1 x)))
// The goal is to make simple macro detection detect the arith macro.
// The arith simplifier will undo this transformation.
// borrow_plugins(s);
enable_ac_support(false);
}
struct macro_manager::macro_expander_cfg : public default_rewriter_cfg {
ast_manager& m;
macro_manager& mm;
expr_dependency_ref m_used_macro_dependencies;
expr_ref_vector m_trail;
macro_manager::macro_expander::~macro_expander() {
// release_plugins();
}
macro_expander_cfg(ast_manager& m, macro_manager& mm):
m(m),
mm(mm),
m_used_macro_dependencies(m),
m_trail(m)
{}
void macro_manager::macro_expander::reduce1_quantifier(quantifier * q) {
simplifier::reduce1_quantifier(q);
// If a macro was expanded in a pattern, we must erase it since it may not be a valid pattern anymore.
// The MAM assumes valid patterns, and it crashes if invalid patterns are provided.
// For example, it will crash if the pattern does not contain all variables.
//
// Alternative solution: use pattern_validation to check if the pattern is still valid.
// I'm not sure if this is a good solution, since the pattern may be meaningless after the macro expansion.
// So, I'm just erasing them.
expr * new_q_expr = 0;
proof * new_q_pr = 0;
get_cached(q, new_q_expr, new_q_pr);
if (!is_quantifier(new_q_expr))
return;
quantifier * new_q = to_quantifier(new_q_expr);
bool erase_patterns = false;
if (q->get_num_patterns() != new_q->get_num_patterns() ||
q->get_num_no_patterns() != new_q->get_num_no_patterns()) {
erase_patterns = true;
bool rewrite_patterns() const { return false; }
bool flat_assoc(func_decl * f) const { return false; }
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
result_pr = 0;
return BR_FAILED;
}
else {
for (unsigned i = 0; !erase_patterns && i < q->get_num_patterns(); i++) {
if (q->get_pattern(i) != new_q->get_pattern(i))
bool reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
// If a macro was expanded in a pattern, we must erase it since it may not be a valid pattern anymore.
// The MAM assumes valid patterns, and it crashes if invalid patterns are provided.
// For example, it will crash if the pattern does not contain all variables.
//
// Alternative solution: use pattern_validation to check if the pattern is still valid.
// I'm not sure if this is a good solution, since the pattern may be meaningless after the macro expansion.
// So, I'm just erasing them.
bool erase_patterns = false;
for (unsigned i = 0; !erase_patterns && i < old_q->get_num_patterns(); i++) {
if (old_q->get_pattern(i) != new_patterns[i])
erase_patterns = true;
}
for (unsigned i = 0; !erase_patterns && i < q->get_num_no_patterns(); i++) {
if (q->get_no_pattern(i) != new_q->get_no_pattern(i))
for (unsigned i = 0; !erase_patterns && i < old_q->get_num_no_patterns(); i++) {
if (old_q->get_no_pattern(i) != new_no_patterns[i])
erase_patterns = true;
}
if (erase_patterns) {
result = m.update_quantifier(old_q, 0, 0, 0, 0, new_body);
}
return erase_patterns;
}
if (erase_patterns) {
ast_manager & m = get_manager();
expr * new_new_q = m.update_quantifier(new_q, 0, 0, 0, 0, new_q->get_expr());
// we can use the same proof since new_new_q and new_q are identical modulo patterns/annotations
cache_result(q, new_new_q, new_q_pr);
}
}
bool macro_manager::macro_expander::get_subst(expr * _n, expr_ref & r, proof_ref & p) {
if (!is_app(_n))
bool get_subst(expr * _n, expr* & r, proof* & p) {
if (!is_app(_n))
return false;
app * n = to_app(_n);
quantifier * q = 0;
func_decl * d = n->get_decl();
TRACE("macro_manager", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";);
if (mm.m_decl2macro.find(d, q)) {
TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";);
app * head = 0;
expr * def = 0;
mm.get_head_def(q, d, head, def);
unsigned num = n->get_num_args();
SASSERT(head && def);
ptr_buffer<expr> subst_args;
subst_args.resize(num, 0);
for (unsigned i = 0; i < num; i++) {
var * v = to_var(head->get_arg(i));
SASSERT(v->get_idx() < num);
unsigned nidx = num - v->get_idx() - 1;
SASSERT(subst_args[nidx] == 0);
subst_args[nidx] = n->get_arg(i);
}
var_subst s(m);
expr_ref rr(m);
s(def, num, subst_args.c_ptr(), rr);
m_trail.push_back(rr);
r = rr;
if (m.proofs_enabled()) {
expr_ref instance(m);
s(q->get_expr(), num, subst_args.c_ptr(), instance);
proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr());
proof * q_pr = 0;
mm.m_decl2macro_pr.find(d, q_pr);
SASSERT(q_pr != 0);
proof * prs[2] = { qi_pr, q_pr };
p = m.mk_unit_resolution(2, prs);
}
else {
p = 0;
}
expr_dependency * ed = mm.m_decl2macro_dep.find(d);
m_used_macro_dependencies = m.mk_join(m_used_macro_dependencies, ed);
return true;
}
return false;
app * n = to_app(_n);
quantifier * q = 0;
func_decl * d = n->get_decl();
TRACE("macro_manager_bug", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";);
if (m_macro_manager.m_decl2macro.find(d, q)) {
TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";);
app * head = 0;
expr * def = 0;
m_macro_manager.get_head_def(q, d, head, def);
unsigned num = n->get_num_args();
SASSERT(head && def);
ptr_buffer<expr> subst_args;
subst_args.resize(num, 0);
for (unsigned i = 0; i < num; i++) {
var * v = to_var(head->get_arg(i));
SASSERT(v->get_idx() < num);
unsigned nidx = num - v->get_idx() - 1;
SASSERT(subst_args[nidx] == 0);
subst_args[nidx] = n->get_arg(i);
}
var_subst s(m);
s(def, num, subst_args.c_ptr(), r);
if (m.proofs_enabled()) {
expr_ref instance(m);
s(q->get_expr(), num, subst_args.c_ptr(), instance);
proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr());
proof * q_pr = 0;
m_macro_manager.m_decl2macro_pr.find(d, q_pr);
SASSERT(q_pr != 0);
proof * prs[2] = { qi_pr, q_pr };
p = m.mk_unit_resolution(2, prs);
}
else {
p = 0;
expr_dependency * ed = m_macro_manager.m_decl2macro_dep.find(d);
m_used_macro_dependencies = m.mk_join(m_used_macro_dependencies, ed);
}
return true;
}
return false;
}
};
struct macro_manager::macro_expander_rw : public rewriter_tpl<macro_manager::macro_expander_cfg> {
macro_expander_cfg m_cfg;
macro_expander_rw(ast_manager& m, macro_manager& mm):
rewriter_tpl<macro_manager::macro_expander_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m, mm)
{}
};
void macro_manager::expand_macros(expr * n, proof * pr, expr_dependency * dep, expr_ref & r, proof_ref & new_pr, expr_dependency_ref & new_dep) {
if (has_macros()) {
// Expand macros with "real" proof production support (NO rewrite*)
expr_ref old_n(m_manager);
proof_ref old_pr(m_manager);
expr_dependency_ref old_dep(m_manager);
expr_ref old_n(m);
proof_ref old_pr(m);
expr_dependency_ref old_dep(m);
old_n = n;
old_pr = pr;
old_dep = dep;
bool change = false;
for (;;) {
macro_expander proc(m_manager, *this, m_simplifier);
proof_ref n_eq_r_pr(m_manager);
TRACE("macro_manager_bug", tout << "expand_macros:\n" << mk_pp(n, m_manager) << "\n";);
macro_expander_rw proc(m, *this);
proof_ref n_eq_r_pr(m);
TRACE("macro_manager_bug", tout << "expand_macros:\n" << mk_pp(n, m) << "\n";);
proc(old_n, r, n_eq_r_pr);
new_pr = m_manager.mk_modus_ponens(old_pr, n_eq_r_pr);
new_dep = m_manager.mk_join(old_dep, proc.m_used_macro_dependencies);
new_pr = m.mk_modus_ponens(old_pr, n_eq_r_pr);
new_dep = m.mk_join(old_dep, proc.m_cfg.m_used_macro_dependencies);
if (r.get() == old_n.get())
return;
break;
old_n = r;
old_pr = new_pr;
old_dep = new_dep;
change = true;
}
// apply th_rewrite to the result.
if (change) {
th_rewriter rw(m);
proof_ref rw_pr(m);
expr_ref r1(r, m);
rw(r1, r, rw_pr);
new_pr = m.mk_modus_ponens(new_pr, rw_pr);
}
}
else {

View file

@ -19,9 +19,9 @@ Revision History:
#ifndef MACRO_MANAGER_H_
#define MACRO_MANAGER_H_
#include "ast/ast_util.h"
#include "util/obj_hashtable.h"
#include "ast/simplifier/simplifier.h"
#include "ast/ast_util.h"
#include "ast/justified_expr.h"
#include "ast/recurse_expr.h"
#include "ast/func_decl_dependencies.h"
#include "ast/macros/macro_util.h"
@ -36,8 +36,7 @@ Revision History:
It has support for backtracking and tagging declarations in an expression as forbidded for being macros.
*/
class macro_manager {
ast_manager & m_manager;
simplifier & m_simplifier;
ast_manager & m;
macro_util m_util;
obj_map<func_decl, quantifier *> m_decl2macro; // func-decl -> quantifier
@ -59,30 +58,22 @@ class macro_manager {
void restore_decls(unsigned old_sz);
void restore_forbidden(unsigned old_sz);
class macro_expander : public simplifier {
protected:
macro_manager & m_macro_manager;
virtual bool get_subst(expr * n, expr_ref & r, proof_ref & p);
virtual void reduce1_quantifier(quantifier * q);
public:
expr_dependency_ref m_used_macro_dependencies;
macro_expander(ast_manager & m, macro_manager & mm, simplifier & s);
~macro_expander();
};
friend class macro_expander;
struct macro_expander_cfg;
struct macro_expander_rw;
public:
macro_manager(ast_manager & m, simplifier & s);
macro_manager(ast_manager & m);
~macro_manager();
ast_manager & get_manager() const { return m_manager; }
ast_manager & get_manager() const { return m; }
macro_util & get_util() { return m_util; }
bool insert(func_decl * f, quantifier * m, proof * pr, expr_dependency * dep);
bool insert(func_decl * f, quantifier * m, proof * pr, expr_dependency * dep = 0);
bool has_macros() const { return !m_macros.empty(); }
void push_scope();
void pop_scope(unsigned num_scopes);
void reset();
void mark_forbidden(unsigned n, expr * const * exprs);
void mark_forbidden(unsigned n, justified_expr const * exprs);
void mark_forbidden(expr * e) { mark_forbidden(1, &e); }
bool is_forbidden(func_decl * d) const { return m_forbidden_set.contains(d); }
obj_hashtable<func_decl> const & get_forbidden_set() const { return m_forbidden_set; }

View file

@ -20,8 +20,6 @@ Revision History:
#include "ast/macros/macro_util.h"
#include "ast/occurs.h"
#include "ast/ast_util.h"
#include "ast/simplifier/arith_simplifier_plugin.h"
#include "ast/simplifier/bv_simplifier_plugin.h"
#include "ast/rewriter/var_subst.h"
#include "ast/ast_pp.h"
#include "ast/ast_ll_pp.h"
@ -29,32 +27,16 @@ Revision History:
#include "ast/well_sorted.h"
#include "ast/rewriter/bool_rewriter.h"
macro_util::macro_util(ast_manager & m, simplifier & s):
macro_util::macro_util(ast_manager & m):
m_manager(m),
m_bv(m),
m_simplifier(s),
m_arith_simp(0),
m_bv_simp(0),
m_arith(m),
m_arith_rw(m),
m_bv_rw(m),
m_forbidden_set(0),
m_curr_clause(0) {
}
arith_simplifier_plugin * macro_util::get_arith_simp() const {
if (m_arith_simp == 0) {
const_cast<macro_util*>(this)->m_arith_simp = static_cast<arith_simplifier_plugin*>(m_simplifier.get_plugin(m_manager.mk_family_id("arith")));
}
SASSERT(m_arith_simp != 0);
return m_arith_simp;
}
bv_simplifier_plugin * macro_util::get_bv_simp() const {
if (m_bv_simp == 0) {
const_cast<macro_util*>(this)->m_bv_simp = static_cast<bv_simplifier_plugin*>(m_simplifier.get_plugin(m_manager.mk_family_id("bv")));
}
SASSERT(m_bv_simp != 0);
return m_bv_simp;
}
bool macro_util::is_bv(expr * n) const {
return m_bv.is_bv(n);
@ -65,60 +47,83 @@ bool macro_util::is_bv_sort(sort * s) const {
}
bool macro_util::is_add(expr * n) const {
return get_arith_simp()->is_add(n) || m_bv.is_bv_add(n);
return m_arith.is_add(n) || m_bv.is_bv_add(n);
}
bool macro_util::is_times_minus_one(expr * n, expr * & arg) const {
return get_arith_simp()->is_times_minus_one(n, arg) || get_bv_simp()->is_times_minus_one(n, arg);
return m_arith_rw.is_times_minus_one(n, arg) || m_bv_rw.is_times_minus_one(n, arg);
}
bool macro_util::is_le(expr * n) const {
return get_arith_simp()->is_le(n) || m_bv.is_bv_ule(n) || m_bv.is_bv_sle(n);
return m_arith.is_le(n) || m_bv.is_bv_ule(n) || m_bv.is_bv_sle(n);
}
bool macro_util::is_le_ge(expr * n) const {
return get_arith_simp()->is_le_ge(n) || m_bv.is_bv_ule(n) || m_bv.is_bv_sle(n);
return m_arith.is_ge(n) || m_arith.is_le(n) || m_bv.is_bv_ule(n) || m_bv.is_bv_sle(n);
}
poly_simplifier_plugin * macro_util::get_poly_simp_for(sort * s) const {
if (is_bv_sort(s))
return get_bv_simp();
else
return get_arith_simp();
bool macro_util::is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) {
return m_arith_rw.is_var_plus_ground(n, inv, v, t) || m_bv_rw.is_var_plus_ground(n, inv, v, t);
}
bool macro_util::is_zero_safe(expr * n) const {
if (m_bv_rw.is_bv(n)) {
return m_bv.is_zero(n);
}
else {
return m_arith_rw.is_zero(n);
}
}
app * macro_util::mk_zero(sort * s) const {
poly_simplifier_plugin * ps = get_poly_simp_for(s);
ps->set_curr_sort(s);
return ps->mk_zero();
if (m_bv.is_bv_sort(s)) {
return m_bv.mk_numeral(rational(0), s);
}
else {
return m_arith.mk_numeral(rational(0), s);
}
}
void macro_util::mk_sub(expr * t1, expr * t2, expr_ref & r) const {
if (is_bv(t1)) {
r = m_bv.mk_bv_sub(t1, t2);
m_bv_rw.mk_sub(t1, t2, r);
}
else {
get_arith_simp()->mk_sub(t1, t2, r);
m_arith_rw.mk_sub(t1, t2, r);
}
}
void macro_util::mk_add(expr * t1, expr * t2, expr_ref & r) const {
if (is_bv(t1)) {
r = m_bv.mk_bv_add(t1, t2);
m_bv_rw.mk_add(t1, t2, r);
}
else {
get_arith_simp()->mk_add(t1, t2, r);
m_arith_rw.mk_add(t1, t2, r);
}
}
void macro_util::mk_add(unsigned num_args, expr * const * args, sort * s, expr_ref & r) const {
if (num_args == 0) {
switch (num_args) {
case 0:
r = mk_zero(s);
return;
break;
case 1:
r = args[0];
break;
default:
if (m_bv.is_bv_sort(s)) {
r = args[0];
while (num_args >= 2) {
--num_args;
++args;
r = m_bv.mk_bv_add(r, args[0]);
}
}
else {
r = m_arith.mk_add(num_args, args);
}
break;
}
poly_simplifier_plugin * ps = get_poly_simp_for(s);
ps->set_curr_sort(s);
ps->mk_add(num_args, args, r);
}
/**
@ -241,13 +246,12 @@ bool macro_util::poly_contains_head(expr * n, func_decl * f, expr * exception) c
bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def, bool & inv) const {
// TODO: obsolete... we should move to collect_arith_macro_candidates
arith_simplifier_plugin * as = get_arith_simp();
if (!m_manager.is_eq(n) && !as->is_le(n) && !as->is_ge(n))
if (!m_manager.is_eq(n) && !m_arith.is_le(n) && !m_arith.is_ge(n))
return false;
expr * lhs = to_app(n)->get_arg(0);
expr * rhs = to_app(n)->get_arg(1);
if (!as->is_numeral(rhs))
if (!m_arith.is_numeral(rhs))
return false;
inv = false;
@ -272,7 +276,7 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex
!poly_contains_head(lhs, to_app(arg)->get_decl(), arg)) {
h = arg;
}
else if (h == 0 && as->is_times_minus_one(arg, neg_arg) &&
else if (h == 0 && m_arith_rw.is_times_minus_one(arg, neg_arg) &&
is_macro_head(neg_arg, num_decls) &&
!is_forbidden(to_app(neg_arg)->get_decl()) &&
!poly_contains_head(lhs, to_app(neg_arg)->get_decl(), arg)) {
@ -287,11 +291,12 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex
return false;
head = to_app(h);
expr_ref tmp(m_manager);
as->mk_add(args.size(), args.c_ptr(), tmp);
tmp = m_arith.mk_add(args.size(), args.c_ptr());
if (inv)
as->mk_sub(tmp, rhs, def);
mk_sub(tmp, rhs, def);
else
as->mk_sub(rhs, tmp, def);
mk_sub(rhs, tmp, def);
TRACE("macro_util", tout << def << "\n";);
return true;
}

View file

@ -22,12 +22,8 @@ Revision History:
#include "ast/ast.h"
#include "util/obj_hashtable.h"
#include "ast/simplifier/simplifier.h"
class poly_simplifier_plugin;
class arith_simplifier_plugin;
class bv_simplifier_plugin;
class basic_simplifier_plugin;
#include "ast/rewriter/arith_rewriter.h"
#include "ast/rewriter/bv_rewriter.h"
class macro_util {
public:
@ -63,9 +59,9 @@ public:
private:
ast_manager & m_manager;
bv_util m_bv;
simplifier & m_simplifier;
arith_simplifier_plugin * m_arith_simp;
bv_simplifier_plugin * m_bv_simp;
arith_util m_arith;
mutable arith_rewriter m_arith_rw;
mutable bv_rewriter m_bv_rw;
obj_hashtable<func_decl> * m_forbidden_set;
bool is_forbidden(func_decl * f) const { return m_forbidden_set != 0 && m_forbidden_set->contains(f); }
@ -94,11 +90,9 @@ private:
public:
macro_util(ast_manager & m, simplifier & s);
macro_util(ast_manager & m);
void set_forbidden_set(obj_hashtable<func_decl> * s) { m_forbidden_set = s; }
arith_simplifier_plugin * get_arith_simp() const;
bv_simplifier_plugin * get_bv_simp() const;
bool is_macro_head(expr * n, unsigned num_decls) const;
bool is_left_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const;
@ -113,6 +107,8 @@ public:
return is_arith_macro(n, num_decls, head, def, inv);
}
bool is_zero_safe(expr * n) const;
bool is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t);
bool is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, app_ref & t);
bool is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def);
@ -137,7 +133,6 @@ public:
void mk_sub(expr * t1, expr * t2, expr_ref & r) const;
void mk_add(expr * t1, expr * t2, expr_ref & r) const;
void mk_add(unsigned num_args, expr * const * args, sort * s, expr_ref & r) const;
poly_simplifier_plugin * get_poly_simp_for(sort * s) const;
};
#endif

View file

@ -22,10 +22,10 @@ Revision History:
#include "util/uint_set.h"
#include "ast/rewriter/var_subst.h"
quasi_macros::quasi_macros(ast_manager & m, macro_manager & mm, simplifier & s) :
m_manager(m),
quasi_macros::quasi_macros(ast_manager & m, macro_manager & mm) :
m_manager(m),
m_macro_manager(mm),
m_simplifier(s),
m_rewriter(m),
m_new_vars(m),
m_new_eqs(m),
m_new_qsorts(m) {
@ -293,18 +293,56 @@ bool quasi_macros::find_macros(unsigned n, expr * const * exprs) {
return res;
}
void quasi_macros::apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const * deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps) {
for (unsigned i = 0 ; i < n ; i++) {
bool quasi_macros::find_macros(unsigned n, justified_expr const * exprs) {
TRACE("quasi_macros", tout << "Finding quasi-macros in: " << std::endl;
for (unsigned i = 0 ; i < n ; i++)
tout << i << ": " << mk_pp(exprs[i].get_fml(), m_manager) << std::endl; );
bool res = false;
m_occurrences.reset();
// Find out how many non-ground appearences for each uninterpreted function there are
for ( unsigned i = 0 ; i < n ; i++ )
find_occurrences(exprs[i].get_fml());
TRACE("quasi_macros", tout << "Occurrences: " << std::endl;
for (occurrences_map::iterator it = m_occurrences.begin();
it != m_occurrences.end();
it++)
tout << it->m_key->get_name() << ": " << it->m_value << std::endl; );
// Find all macros
for ( unsigned i = 0 ; i < n ; i++ ) {
app_ref a(m_manager);
expr_ref t(m_manager);
if (is_quasi_macro(exprs[i].get_fml(), a, t)) {
quantifier_ref macro(m_manager);
quasi_macro_to_macro(to_quantifier(exprs[i].get_fml()), a, t, macro);
TRACE("quasi_macros", tout << "Found quasi macro: " << mk_pp(exprs[i].get_fml(), m_manager) << std::endl;
tout << "Macro: " << mk_pp(macro, m_manager) << std::endl; );
proof * pr = 0;
if (m_manager.proofs_enabled())
pr = m_manager.mk_def_axiom(macro);
if (m_macro_manager.insert(a->get_decl(), macro, pr))
res = true;
}
}
return res;
}
void quasi_macros::apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const* deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector& new_deps) {
for ( unsigned i = 0 ; i < n ; i++ ) {
expr_ref r(m_manager), rs(m_manager);
proof_ref pr(m_manager), ps(m_manager);
expr_dependency_ref dep(m_manager);
proof * p = m_manager.proofs_enabled() ? prs[i] : 0;
expr_dependency * dep = deps[i];
expr_dependency_ref new_dep(m_manager);
m_macro_manager.expand_macros(exprs[i], p, dep, r, pr, new_dep);
m_simplifier(r, rs, ps);
new_exprs.push_back(rs);
new_prs.push_back(ps);
new_deps.push_back(new_dep);
m_macro_manager.expand_macros(exprs[i], p, deps[i], r, pr, dep);
m_rewriter(r);
new_exprs.push_back(r);
new_prs.push_back(ps);
new_deps.push_back(dep);
}
}
@ -312,7 +350,8 @@ bool quasi_macros::operator()(unsigned n, expr * const * exprs, proof * const *
if (find_macros(n, exprs)) {
apply_macros(n, exprs, prs, deps, new_exprs, new_prs, new_deps);
return true;
} else {
}
else {
// just copy them over
for ( unsigned i = 0 ; i < n ; i++ ) {
new_exprs.push_back(exprs[i]);
@ -322,3 +361,28 @@ bool quasi_macros::operator()(unsigned n, expr * const * exprs, proof * const *
return false;
}
}
void quasi_macros::apply_macros(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls) {
for ( unsigned i = 0 ; i < n ; i++ ) {
expr_ref r(m_manager), rs(m_manager);
proof_ref pr(m_manager), ps(m_manager);
proof * p = m_manager.proofs_enabled() ? fmls[i].get_proof() : 0;
expr_dependency_ref dep(m_manager);
m_macro_manager.expand_macros(fmls[i].get_fml(), p, 0, r, pr, dep);
m_rewriter(r);
new_fmls.push_back(justified_expr(m_manager, r, pr));
}
}
bool quasi_macros::operator()(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls) {
if (find_macros(n, fmls)) {
apply_macros(n, fmls, new_fmls);
return true;
} else {
// just copy them over
for ( unsigned i = 0 ; i < n ; i++ ) {
new_fmls.push_back(fmls[i]);
}
return false;
}
}

View file

@ -20,9 +20,9 @@ Revision History:
#define QUASI_MACROS_H_
#include<sstream>
#include "ast/justified_expr.h"
#include "ast/macros/macro_manager.h"
#include "ast/simplifier/basic_simplifier_plugin.h"
#include "ast/simplifier/simplifier.h"
#include "ast/rewriter/th_rewriter.h"
/**
\brief Finds quasi macros and applies them.
@ -32,7 +32,7 @@ class quasi_macros {
ast_manager & m_manager;
macro_manager & m_macro_manager;
simplifier & m_simplifier;
th_rewriter m_rewriter;
occurrences_map m_occurrences;
ptr_vector<expr> m_todo;
@ -54,16 +54,22 @@ class quasi_macros {
void find_occurrences(expr * e);
bool find_macros(unsigned n, expr * const * exprs);
void apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const * deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps);
bool find_macros(unsigned n, justified_expr const* expr);
void apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const* deps,
expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector& new_deps);
void apply_macros(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls);
public:
quasi_macros(ast_manager & m, macro_manager & mm, simplifier & s);
quasi_macros(ast_manager & m, macro_manager & mm);
~quasi_macros();
/**
\brief Find pure function macros and apply them.
*/
// bool operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs);
bool operator()(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls);
bool operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_dependency * const * deps, expr_ref_vector & new_exprs, proof_ref_vector & new_prs, expr_dependency_ref_vector & new_deps);
};
#endif

View file

@ -29,7 +29,7 @@ z3_add_component(pattern
${CMAKE_CURRENT_BINARY_DIR}/database.h
COMPONENT_DEPENDENCIES
normal_forms
simplifier
rewriter
smt2parser
PYG_FILES
pattern_inference_params_helper.pyg

View file

@ -16,15 +16,17 @@ Author:
Revision History:
--*/
#include "util/warning.h"
#include "ast/pattern/pattern_inference.h"
#include "ast/ast_ll_pp.h"
#include "ast/ast_pp.h"
#include "ast/ast_util.h"
#include "util/warning.h"
#include "ast/arith_decl_plugin.h"
#include "ast/normal_forms/pull_quant.h"
#include "ast/well_sorted.h"
#include "ast/for_each_expr.h"
#include "ast/rewriter/rewriter_def.h"
void smaller_pattern::save(expr * p1, expr * p2) {
expr_pair e(p1, p2);
@ -87,8 +89,20 @@ bool smaller_pattern::operator()(unsigned num_bindings, expr * p1, expr * p2) {
return process(p1, p2);
}
pattern_inference::pattern_inference(ast_manager & m, pattern_inference_params & params):
simplifier(m),
#ifdef _TRACE
static void dump_app_vector(std::ostream & out, ptr_vector<app> const & v, ast_manager & m) {
for (app * e : v)
out << mk_pp(e, m) << "\n";
}
#endif
#include "ast/pattern/database.h"
pattern_inference_cfg::pattern_inference_cfg(ast_manager & m, pattern_inference_params & params):
m(m),
m_params(params),
m_bfid(m.get_basic_family_id()),
m_afid(m.mk_family_id("arith")),
@ -102,10 +116,9 @@ pattern_inference::pattern_inference(ast_manager & m, pattern_inference_params &
m_database(m) {
if (params.m_pi_arith == AP_NO)
register_forbidden_family(m_afid);
enable_ac_support(false);
}
void pattern_inference::collect::operator()(expr * n, unsigned num_bindings) {
void pattern_inference_cfg::collect::operator()(expr * n, unsigned num_bindings) {
SASSERT(m_info.empty());
SASSERT(m_todo.empty());
SASSERT(m_cache.empty());
@ -125,7 +138,7 @@ void pattern_inference::collect::operator()(expr * n, unsigned num_bindings) {
reset();
}
inline void pattern_inference::collect::visit(expr * n, unsigned delta, bool & visited) {
inline void pattern_inference_cfg::collect::visit(expr * n, unsigned delta, bool & visited) {
entry e(n, delta);
if (!m_cache.contains(e)) {
m_todo.push_back(e);
@ -133,7 +146,7 @@ inline void pattern_inference::collect::visit(expr * n, unsigned delta, bool & v
}
}
bool pattern_inference::collect::visit_children(expr * n, unsigned delta) {
bool pattern_inference_cfg::collect::visit_children(expr * n, unsigned delta) {
bool visited = true;
unsigned i;
switch (n->get_kind()) {
@ -153,13 +166,13 @@ bool pattern_inference::collect::visit_children(expr * n, unsigned delta) {
return visited;
}
inline void pattern_inference::collect::save(expr * n, unsigned delta, info * i) {
inline void pattern_inference_cfg::collect::save(expr * n, unsigned delta, info * i) {
m_cache.insert(entry(n, delta), i);
if (i != 0)
m_info.push_back(i);
}
void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
void pattern_inference_cfg::collect::save_candidate(expr * n, unsigned delta) {
switch (n->get_kind()) {
case AST_VAR: {
unsigned idx = to_var(n)->get_idx();
@ -233,7 +246,7 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
// stating properties about these operators.
family_id fid = c->get_family_id();
decl_kind k = c->get_decl_kind();
if (!free_vars.empty() &&
if (!free_vars.empty() &&
(fid != m_afid || (fid == m_afid && !m_owner.m_nested_arith_only && (k == OP_DIV || k == OP_IDIV || k == OP_MOD || k == OP_REM || k == OP_MUL)))) {
TRACE("pattern_inference", tout << "potential candidate: \n" << mk_pp(new_node, m) << "\n";);
m_owner.add_candidate(new_node, free_vars, size);
@ -247,14 +260,14 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
}
void pattern_inference::collect::reset() {
void pattern_inference_cfg::collect::reset() {
m_cache.reset();
std::for_each(m_info.begin(), m_info.end(), delete_proc<info>());
m_info.reset();
SASSERT(m_todo.empty());
}
void pattern_inference::add_candidate(app * n, uint_set const & free_vars, unsigned size) {
void pattern_inference_cfg::add_candidate(app * n, uint_set const & free_vars, unsigned size) {
for (unsigned i = 0; i < m_num_no_patterns; i++) {
if (n == m_no_patterns[i])
return;
@ -271,7 +284,7 @@ void pattern_inference::add_candidate(app * n, uint_set const & free_vars, unsig
\brief Copy the non-looping patterns in m_candidates to result when m_params.m_pi_block_loop_patterns = true.
Otherwise, copy m_candidates to result.
*/
void pattern_inference::filter_looping_patterns(ptr_vector<app> & result) {
void pattern_inference_cfg::filter_looping_patterns(ptr_vector<app> & result) {
unsigned num = m_candidates.size();
for (unsigned i1 = 0; i1 < num; i1++) {
app * n1 = m_candidates.get(i1);
@ -310,7 +323,7 @@ void pattern_inference::filter_looping_patterns(ptr_vector<app> & result) {
inline void pattern_inference::contains_subpattern::save(expr * n) {
inline void pattern_inference_cfg::contains_subpattern::save(expr * n) {
unsigned id = n->get_id();
m_already_processed.assure_domain(id);
if (!m_already_processed.contains(id)) {
@ -319,7 +332,7 @@ inline void pattern_inference::contains_subpattern::save(expr * n) {
}
}
bool pattern_inference::contains_subpattern::operator()(expr * n) {
bool pattern_inference_cfg::contains_subpattern::operator()(expr * n) {
m_already_processed.reset();
m_todo.reset();
expr2info::obj_map_entry * _e = m_owner.m_candidates_info.find_core(n);
@ -360,7 +373,7 @@ bool pattern_inference::contains_subpattern::operator()(expr * n) {
Return true if n contains a direct/indirect child that is also a
pattern, and contains the same number of free variables.
*/
inline bool pattern_inference::contains_subpattern(expr * n) {
inline bool pattern_inference_cfg::contains_subpattern(expr * n) {
return m_contains_subpattern(n);
}
@ -372,18 +385,15 @@ inline bool pattern_inference::contains_subpattern(expr * n) {
Remark: Every pattern p in patterns is also a member of
m_pattern_map.
*/
void pattern_inference::filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result) {
ptr_vector<app>::const_iterator it = patterns.begin();
ptr_vector<app>::const_iterator end = patterns.end();
for (; it != end; ++it) {
app * curr = *it;
void pattern_inference_cfg::filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result) {
for (app * curr : patterns) {
if (!contains_subpattern(curr))
result.push_back(curr);
}
}
bool pattern_inference::pattern_weight_lt::operator()(expr * n1, expr * n2) const {
bool pattern_inference_cfg::pattern_weight_lt::operator()(expr * n1, expr * n2) const {
expr2info::obj_map_entry * e1 = m_candidates_info.find_core(n1);
expr2info::obj_map_entry * e2 = m_candidates_info.find_core(n2);
SASSERT(e1 != 0);
@ -401,13 +411,10 @@ bool pattern_inference::pattern_weight_lt::operator()(expr * n1, expr * n2) cons
variables, then it is copied to remaining_candidate_patterns. The
new patterns are stored in result.
*/
void pattern_inference::candidates2unary_patterns(ptr_vector<app> const & candidate_patterns,
void pattern_inference_cfg::candidates2unary_patterns(ptr_vector<app> const & candidate_patterns,
ptr_vector<app> & remaining_candidate_patterns,
app_ref_buffer & result) {
ptr_vector<app>::const_iterator it = candidate_patterns.begin();
ptr_vector<app>::const_iterator end = candidate_patterns.end();
for (; it != end; ++it) {
app * candidate = *it;
for (app * candidate : candidate_patterns) {
expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
info const & i = e->get_data().m_value;
if (i.m_free_vars.num_elems() == m_num_bindings) {
@ -425,7 +432,7 @@ void pattern_inference::candidates2unary_patterns(ptr_vector<app> const & candid
// HACK: limit the number of case-splits:
#define MAX_SPLITS 32
void pattern_inference::candidates2multi_patterns(unsigned max_num_patterns,
void pattern_inference_cfg::candidates2multi_patterns(unsigned max_num_patterns,
ptr_vector<app> const & candidate_patterns,
app_ref_buffer & result) {
SASSERT(!candidate_patterns.empty());
@ -469,21 +476,13 @@ void pattern_inference::candidates2multi_patterns(unsigned max_num_patterns,
}
}
void pattern_inference::reset_pre_patterns() {
void pattern_inference_cfg::reset_pre_patterns() {
std::for_each(m_pre_patterns.begin(), m_pre_patterns.end(), delete_proc<pre_pattern>());
m_pre_patterns.reset();
}
#ifdef _TRACE
static void dump_app_vector(std::ostream & out, ptr_vector<app> const & v, ast_manager & m) {
ptr_vector<app>::const_iterator it = v.begin();
ptr_vector<app>::const_iterator end = v.end();
for (; it != end; ++it)
out << mk_pp(*it, m) << "\n";
}
#endif
bool pattern_inference::is_forbidden(app * n) const {
bool pattern_inference_cfg::is_forbidden(app * n) const {
func_decl const * decl = n->get_decl();
if (is_ground(n))
return false;
@ -499,14 +498,11 @@ bool pattern_inference::is_forbidden(app * n) const {
return false;
}
bool pattern_inference::has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result) {
bool pattern_inference_cfg::has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result) {
if (m_preferred.empty())
return false;
bool found = false;
ptr_vector<app>::const_iterator it = candidate_patterns.begin();
ptr_vector<app>::const_iterator end = candidate_patterns.end();
for (; it != end; ++it) {
app * candidate = *it;
for (app * candidate : candidate_patterns) {
if (m_preferred.contains(to_app(candidate)->get_decl())) {
expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
info const & i = e->get_data().m_value;
@ -521,7 +517,7 @@ bool pattern_inference::has_preferred_patterns(ptr_vector<app> & candidate_patte
return found;
}
void pattern_inference::mk_patterns(unsigned num_bindings,
void pattern_inference_cfg::mk_patterns(unsigned num_bindings,
expr * n,
unsigned num_no_patterns,
expr * const * no_patterns,
@ -576,75 +572,63 @@ void pattern_inference::mk_patterns(unsigned num_bindings,
m_candidates.reset();
}
#include "ast/pattern/database.h"
void pattern_inference::reduce1_quantifier(quantifier * q) {
bool pattern_inference_cfg::reduce_quantifier(
quantifier * q,
expr * new_body,
expr * const *, // new_patterns
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";);
if (!q->is_forall()) {
simplifier::reduce1_quantifier(q);
return;
return false;
}
int weight = q->get_weight();
if (m_params.m_pi_use_database) {
m_database.initialize(g_pattern_database);
app_ref_vector new_patterns(m);
m_database.initialize(g_pattern_database);
unsigned new_weight;
if (m_database.match_quantifier(q, new_patterns, new_weight)) {
#ifdef Z3DEBUG
for (unsigned i = 0; i < new_patterns.size(); i++) { SASSERT(is_well_sorted(m, new_patterns.get(i))); }
#endif
DEBUG_CODE(for (unsigned i = 0; i < new_patterns.size(); i++) { SASSERT(is_well_sorted(m, new_patterns.get(i))); });
quantifier_ref new_q(m);
if (q->get_num_patterns() > 0) {
// just update the weight...
TRACE("pattern_inference", tout << "updating weight to: " << new_weight << "\n" << mk_pp(q, m) << "\n";);
new_q = m.update_quantifier_weight(q, new_weight);
result = m.update_quantifier_weight(q, new_weight);
}
else {
quantifier_ref tmp(m);
tmp = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), q->get_expr());
new_q = m.update_quantifier_weight(tmp, new_weight);
tmp = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), q->get_expr());
result = m.update_quantifier_weight(tmp, new_weight);
TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(new_q, m) << "\n";);
}
proof * pr = 0;
if (m.fine_grain_proofs())
pr = m.mk_rewrite(q, new_q);
cache_result(q, new_q, pr);
return;
result_pr = m.mk_rewrite(q, new_q);
return true;
}
}
if (q->get_num_patterns() > 0) {
simplifier::reduce1_quantifier(q);
return;
return false;
}
if (m_params.m_pi_nopat_weight >= 0)
weight = m_params.m_pi_nopat_weight;
SASSERT(q->get_num_patterns() == 0);
expr * new_body;
proof * new_body_pr;
get_cached(q->get_expr(), new_body, new_body_pr);
ptr_buffer<expr> new_no_patterns;
unsigned num_no_patterns = q->get_num_no_patterns();
for (unsigned i = 0; i < num_no_patterns; i++) {
expr * new_pattern;
proof * new_pattern_pr;
get_cached(q->get_no_pattern(i), new_pattern, new_pattern_pr);
new_no_patterns.push_back(new_pattern);
}
app_ref_buffer new_patterns(m);
if (m_params.m_pi_arith == AP_CONSERVATIVE)
m_forbidden.push_back(m_afid);
mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns);
app_ref_buffer new_patterns(m);
unsigned num_no_patterns = q->get_num_no_patterns();
mk_patterns(q->get_num_decls(), new_body, num_no_patterns, new_no_patterns, new_patterns);
if (new_patterns.empty() && !new_no_patterns.empty()) {
if (new_patterns.empty() && num_no_patterns > 0) {
if (new_patterns.empty()) {
mk_patterns(q->get_num_decls(), new_body, 0, 0, new_patterns);
if (m_params.m_pi_warnings && !new_patterns.empty()) {
@ -657,7 +641,7 @@ void pattern_inference::reduce1_quantifier(quantifier * q) {
m_forbidden.pop_back();
if (new_patterns.empty()) {
flet<bool> l1(m_block_loop_patterns, false); // allow looping patterns
mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns);
mk_patterns(q->get_num_decls(), new_body, num_no_patterns, new_no_patterns, new_patterns);
if (!new_patterns.empty()) {
weight = std::max(weight, static_cast<int>(m_params.m_pi_arith_weight));
if (m_params.m_pi_warnings) {
@ -672,7 +656,7 @@ void pattern_inference::reduce1_quantifier(quantifier * q) {
if (new_patterns.empty()) {
flet<bool> l1(m_nested_arith_only, false); // try to find a non-nested arith pattern
flet<bool> l2(m_block_loop_patterns, false); // allow looping patterns
mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns);
mk_patterns(q->get_num_decls(), new_body, num_no_patterns, new_no_patterns, new_patterns);
if (!new_patterns.empty()) {
weight = std::max(weight, static_cast<int>(m_params.m_pi_non_nested_arith_weight));
if (m_params.m_pi_warnings) {
@ -684,15 +668,12 @@ void pattern_inference::reduce1_quantifier(quantifier * q) {
}
}
quantifier_ref new_q(m);
new_q = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body);
quantifier_ref new_q(m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body), m);
if (weight != q->get_weight())
new_q = m.update_quantifier_weight(new_q, weight);
proof_ref pr(m);
if (m.fine_grain_proofs()) {
if (new_body_pr == 0)
new_body_pr = m.mk_reflexivity(new_body);
pr = m.mk_quant_intro(q, new_q, new_body_pr);
proof* new_body_pr = m.mk_reflexivity(new_body);
result_pr = m.mk_quant_intro(q, new_q, new_body_pr);
}
if (new_patterns.empty() && m_params.m_pi_pull_quantifiers) {
@ -700,17 +681,16 @@ void pattern_inference::reduce1_quantifier(quantifier * q) {
expr_ref new_expr(m);
proof_ref new_pr(m);
pull(new_q, new_expr, new_pr);
quantifier * new_new_q = to_quantifier(new_expr);
if (new_new_q != new_q) {
mk_patterns(new_new_q->get_num_decls(), new_new_q->get_expr(), 0, 0, new_patterns);
quantifier * result2 = to_quantifier(new_expr);
if (result2 != new_q) {
mk_patterns(result2->get_num_decls(), result2->get_expr(), 0, 0, new_patterns);
if (!new_patterns.empty()) {
if (m_params.m_pi_warnings) {
warning_msg("pulled nested quantifier to be able to find an useable pattern (quantifier id: %s)", q->get_qid().str().c_str());
}
new_q = m.update_quantifier(new_new_q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_new_q->get_expr());
new_q = m.update_quantifier(result2, new_patterns.size(), (expr**) new_patterns.c_ptr(), result2->get_expr());
if (m.fine_grain_proofs()) {
pr = m.mk_transitivity(pr, new_pr);
pr = m.mk_transitivity(pr, m.mk_quant_intro(new_new_q, new_q, m.mk_reflexivity(new_q->get_expr())));
result_pr = m.mk_transitivity(new_pr, m.mk_quant_intro(result2, new_q, m.mk_reflexivity(new_q->get_expr())));
}
TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m) << "\n";);
}
@ -725,27 +705,21 @@ void pattern_inference::reduce1_quantifier(quantifier * q) {
}
if (new_patterns.empty() && new_body == q->get_expr()) {
cache_result(q, q, 0);
return;
return false;
}
result = new_q;
IF_IVERBOSE(10,
verbose_stream() << "(smt.inferred-patterns :qid " << q->get_qid() << "\n";
for (unsigned i = 0; i < new_patterns.size(); i++)
verbose_stream() << " " << mk_ismt2_pp(new_patterns[i], m, 2) << "\n";
verbose_stream() << ")\n"; );
cache_result(q, new_q, pr);
return true;
}
#if 0
// unused
static void dump_expr_vector(std::ostream & out, ptr_vector<expr> const & v, ast_manager & m) {
ptr_vector<expr>::const_iterator it = v.begin();
ptr_vector<expr>::const_iterator end = v.end();
for (; it != end; ++it)
out << mk_pp(*it, m) << "\n";
}
#endif
pattern_inference_rw::pattern_inference_rw(ast_manager& m, pattern_inference_params & params):
rewriter_tpl<pattern_inference_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m, params)
{}

View file

@ -20,7 +20,7 @@ Revision History:
#define PATTERN_INFERENCE_H_
#include "ast/ast.h"
#include "ast/simplifier/simplifier.h"
#include "ast/rewriter/rewriter.h"
#include "ast/pattern/pattern_inference_params.h"
#include "util/vector.h"
#include "util/uint_set.h"
@ -60,7 +60,8 @@ public:
bool operator()(unsigned num_bindings, expr * p1, expr * p2);
};
class pattern_inference : public simplifier {
class pattern_inference_cfg : public default_rewriter_cfg {
ast_manager& m;
pattern_inference_params & m_params;
family_id m_bfid;
family_id m_afid;
@ -88,7 +89,7 @@ class pattern_inference : public simplifier {
typedef obj_map<expr, info> expr2info;
expr2info m_candidates_info; // candidate -> set of free vars + size
expr2info m_candidates_info; // candidate -> set of free vars + size
app_ref_vector m_candidates;
ptr_vector<app> m_tmp1;
@ -136,7 +137,7 @@ class pattern_inference : public simplifier {
};
ast_manager & m;
pattern_inference & m_owner;
pattern_inference_cfg & m_owner;
family_id m_afid;
unsigned m_num_bindings;
typedef map<entry, info *, obj_hash<entry>, default_eq<entry> > cache;
@ -150,7 +151,7 @@ class pattern_inference : public simplifier {
void save_candidate(expr * n, unsigned delta);
void reset();
public:
collect(ast_manager & m, pattern_inference & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {}
collect(ast_manager & m, pattern_inference_cfg & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {}
void operator()(expr * n, unsigned num_bindings);
};
@ -165,12 +166,12 @@ class pattern_inference : public simplifier {
void filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result);
class contains_subpattern {
pattern_inference & m_owner;
pattern_inference_cfg & m_owner;
nat_set m_already_processed;
ptr_vector<expr> m_todo;
void save(expr * n);
public:
contains_subpattern(pattern_inference & owner):
contains_subpattern(pattern_inference_cfg & owner):
m_owner(owner) {}
bool operator()(expr * n);
};
@ -214,10 +215,8 @@ class pattern_inference : public simplifier {
expr * const * no_patterns, // IN patterns that should not be used.
app_ref_buffer & result); // OUT result
virtual void reduce1_quantifier(quantifier * q);
public:
pattern_inference(ast_manager & m, pattern_inference_params & params);
pattern_inference_cfg(ast_manager & m, pattern_inference_params & params);
void register_forbidden_family(family_id fid) {
SASSERT(fid != m_bfid);
@ -232,6 +231,13 @@ public:
m_preferred.insert(f);
}
bool reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr);
void register_preferred(unsigned num, func_decl * const * fs) { for (unsigned i = 0; i < num; i++) register_preferred(fs[i]); }
bool is_forbidden(func_decl const * decl) const {
@ -244,5 +250,11 @@ public:
bool is_forbidden(app * n) const;
};
class pattern_inference_rw : public rewriter_tpl<pattern_inference_cfg> {
pattern_inference_cfg m_cfg;
public:
pattern_inference_rw(ast_manager& m, pattern_inference_params & params);
};
#endif /* PATTERN_INFERENCE_H_ */

View file

@ -3,22 +3,29 @@ z3_add_component(rewriter
arith_rewriter.cpp
array_rewriter.cpp
ast_counter.cpp
bit2int.cpp
bool_rewriter.cpp
bv_bounds.cpp
bv_elim.cpp
bv_rewriter.cpp
datatype_rewriter.cpp
der.cpp
distribute_forall.cpp
dl_rewriter.cpp
elim_bounds.cpp
enum2bv_rewriter.cpp
expr_replacer.cpp
expr_safe_replace.cpp
factor_rewriter.cpp
fpa_rewriter.cpp
inj_axiom.cpp
label_rewriter.cpp
maximize_ac_sharing.cpp
mk_simplified_app.cpp
pb_rewriter.cpp
pb2bv_rewriter.cpp
push_app_ite.cpp
pull_ite_tree.cpp
quant_hoist.cpp
rewriter.cpp
seq_rewriter.cpp

View file

@ -25,8 +25,8 @@ Notes:
void arith_rewriter::updt_local_params(params_ref const & _p) {
arith_rewriter_params p(_p);
m_arith_lhs = p.arith_lhs();
m_arith_ineq_lhs = p.arith_ineq_lhs();
m_gcd_rounding = p.gcd_rounding();
m_eq2ineq = p.eq2ineq();
m_elim_to_real = p.elim_to_real();
m_push_to_real = p.push_to_real();
m_anum_simp = p.algebraic_number_evaluator();
@ -35,6 +35,7 @@ void arith_rewriter::updt_local_params(params_ref const & _p) {
m_mul2power = p.mul_to_power();
m_elim_rem = p.elim_rem();
m_expand_tan = p.expand_tan();
m_eq2ineq = p.eq2ineq();
set_sort_sums(p.sort_sums());
}
@ -370,8 +371,8 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin
if ((is_zero(arg1) && is_reduce_power_target(arg2, kind == EQ)) ||
(is_zero(arg2) && is_reduce_power_target(arg1, kind == EQ)))
return reduce_power(arg1, arg2, kind, result);
br_status st = cancel_monomials(arg1, arg2, m_arith_lhs, new_arg1, new_arg2);
TRACE("mk_le_bug", tout << "st: " << st << "\n";);
br_status st = cancel_monomials(arg1, arg2, m_arith_ineq_lhs || m_arith_lhs, new_arg1, new_arg2);
TRACE("mk_le_bug", tout << "st: " << st << " " << new_arg1 << " " << new_arg2 << "\n";);
if (st != BR_FAILED) {
arg1 = new_arg1;
arg2 = new_arg2;
@ -454,7 +455,16 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin
st = BR_DONE;
}
}
if (st == BR_DONE && arg1 == orig_arg1 && arg2 == orig_arg2) {
if ((m_arith_lhs || m_arith_ineq_lhs) && is_numeral(arg2, a2) && is_neg_poly(arg1, new_arg1)) {
a2.neg();
new_arg2 = m_util.mk_numeral(a2, m_util.is_int(new_arg1));
switch (kind) {
case LE: result = m_util.mk_ge(new_arg1, new_arg2); return BR_DONE;
case GE: result = m_util.mk_le(new_arg1, new_arg2); return BR_DONE;
case EQ: result = m_util.mk_eq(new_arg1, new_arg2); return BR_DONE;
}
}
else if (st == BR_DONE && arg1 == orig_arg1 && arg2 == orig_arg2) {
// Nothing new; return BR_FAILED to avoid rewriting loops.
return BR_FAILED;
}
@ -486,12 +496,69 @@ br_status arith_rewriter::mk_gt_core(expr * arg1, expr * arg2, expr_ref & result
return BR_REWRITE2;
}
bool arith_rewriter::is_arith_term(expr * n) const {
return n->get_kind() == AST_APP && to_app(n)->get_family_id() == get_fid();
}
br_status arith_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) {
if (m_eq2ineq) {
result = m().mk_and(m_util.mk_le(arg1, arg2), m_util.mk_ge(arg1, arg2));
return BR_REWRITE2;
}
return mk_le_ge_eq_core(arg1, arg2, EQ, result);
if (m_arith_lhs || is_arith_term(arg1) || is_arith_term(arg2)) {
return mk_le_ge_eq_core(arg1, arg2, EQ, result);
}
return BR_FAILED;
}
expr_ref arith_rewriter::neg_monomial(expr* e) const {
expr_ref_vector args(m());
rational a1;
if (is_app(e) & m_util.is_mul(e)) {
if (is_numeral(to_app(e)->get_arg(0), a1)) {
if (!a1.is_minus_one()) {
args.push_back(m_util.mk_numeral(-a1, m_util.is_int(e)));
}
args.append(to_app(e)->get_num_args() - 1, to_app(e)->get_args() + 1);
}
else {
args.push_back(m_util.mk_numeral(rational(-1), m_util.is_int(e)));
args.push_back(e);
}
}
else {
args.push_back(m_util.mk_numeral(rational(-1), m_util.is_int(e)));
args.push_back(e);
}
if (args.size() == 1) {
return expr_ref(args.back(), m());
}
else {
return expr_ref(m_util.mk_mul(args.size(), args.c_ptr()), m());
}
}
bool arith_rewriter::is_neg_poly(expr* t, expr_ref& neg) const {
rational r;
if (m_util.is_mul(t) && is_numeral(to_app(t)->get_arg(0), r) && r.is_neg()) {
neg = neg_monomial(t);
return true;
}
if (!m_util.is_add(t)) {
return false;
}
expr * t2 = to_app(t)->get_arg(0);
if (m_util.is_mul(t2) && is_numeral(to_app(t2)->get_arg(0), r) && r.is_neg()) {
expr_ref_vector args1(m());
for (expr* e1 : *to_app(t)) {
args1.push_back(neg_monomial(e1));
}
neg = m_util.mk_add(args1.size(), args1.c_ptr());
return true;
}
return false;
}
bool arith_rewriter::is_anum_simp_target(unsigned num_args, expr * const * args) {

View file

@ -35,7 +35,6 @@ protected:
bool is_numeral(expr * n) const { return m_util.is_numeral(n); }
bool is_numeral(expr * n, numeral & r) const { return m_util.is_numeral(n, r); }
bool is_zero(expr * n) const { return m_util.is_zero(n); }
bool is_minus_one(expr * n) const { return m_util.is_minus_one(n); }
void normalize(numeral & c, sort * s) {}
app * mk_numeral(numeral const & r, sort * s) { return m_util.mk_numeral(r, s); }
@ -45,16 +44,19 @@ protected:
decl_kind power_decl_kind() const { return OP_POWER; }
public:
arith_rewriter_core(ast_manager & m):m_util(m) {}
bool is_zero(expr * n) const { return m_util.is_zero(n); }
};
class arith_rewriter : public poly_rewriter<arith_rewriter_core> {
bool m_arith_lhs;
bool m_arith_ineq_lhs;
bool m_gcd_rounding;
bool m_eq2ineq;
bool m_elim_to_real;
bool m_push_to_real;
bool m_anum_simp;
bool m_elim_rem;
bool m_eq2ineq;
bool m_process_all_eqs;
unsigned m_max_degree;
void get_coeffs_gcd(expr * t, numeral & g, bool & first, unsigned & num_consts);
@ -82,12 +84,16 @@ class arith_rewriter : public poly_rewriter<arith_rewriter_core> {
expr * reduce_power(expr * arg, bool is_eq);
br_status reduce_power(expr * arg1, expr * arg2, op_kind kind, expr_ref & result);
bool is_arith_term(expr * n) const;
bool is_pi_multiple(expr * t, rational & k);
bool is_pi_offset(expr * t, rational & k, expr * & m);
bool is_2_pi_integer(expr * t);
bool is_2_pi_integer_offset(expr * t, expr * & m);
bool is_pi_integer(expr * t);
bool is_pi_integer_offset(expr * t, expr * & m);
bool is_neg_poly(expr* e, expr_ref& neg) const;
expr_ref neg_monomial(expr * e) const;
expr * mk_sin_value(rational const & k);
app * mk_sqrt(rational const & k);

View file

@ -6,10 +6,11 @@ def_module_params(module_name='rewriter',
("expand_power", BOOL, False, "expand (^ t k) into (* t ... t) if 1 < k <= max_degree."),
("expand_tan", BOOL, False, "replace (tan x) with (/ (sin x) (cos x))."),
("max_degree", UINT, 64, "max degree of algebraic numbers (and power operators) processed by simplifier."),
("eq2ineq", BOOL, False, "split arithmetic equalities into two inequalities."),
("sort_sums", BOOL, False, "sort the arguments of + application."),
("gcd_rounding", BOOL, False, "use gcd rounding on integer arithmetic atoms."),
("arith_lhs", BOOL, False, "all monomials are moved to the left-hand-side, and the right-hand-side is just a constant."),
("arith_ineq_lhs", BOOL, False, "rewrite inequalities so that right-hand-side is a constant."),
("elim_to_real", BOOL, False, "eliminate to_real from arithmetic predicates that contain only integers."),
("push_to_real", BOOL, True, "distribute to_real over * and +."),
("eq2ineq", BOOL, False, "expand equalities into two inequalities"),
("elim_rem", BOOL, False, "replace (rem x y) with (ite (>= y 0) (mod x y) (- (mod x y))).")))

View file

@ -19,15 +19,16 @@ Revision History:
--*/
#include "ast/simplifier/bit2int.h"
#include "ast/ast_pp.h"
#include "ast/ast_ll_pp.h"
#include "ast/for_each_ast.h"
#include "ast/rewriter/bit2int.h"
#define CHECK(_x_) if (!(_x_)) { UNREACHABLE(); }
bit2int::bit2int(ast_manager & m) :
m_manager(m), m_bv_util(m), m_arith_util(m), m_cache(m), m_bit0(m) {
m_manager(m), m_bv_util(m), m_rewriter(m), m_arith_util(m), m_cache(m), m_bit0(m) {
m_bit0 = m_bv_util.mk_numeral(0,1);
}
@ -67,7 +68,7 @@ unsigned bit2int::get_numeral_bits(numeral const& k) {
void bit2int::align_size(expr* e, unsigned sz, expr_ref& result) {
unsigned sz1 = m_bv_util.get_bv_size(e);
SASSERT(sz1 <= sz);
m_bv_simplifier->mk_zeroext(sz-sz1, e, result);
result = m_rewriter.mk_zero_extend(sz-sz1, e);
}
void bit2int::align_sizes(expr_ref& a, expr_ref& b) {
@ -75,11 +76,11 @@ void bit2int::align_sizes(expr_ref& a, expr_ref& b) {
unsigned sz2 = m_bv_util.get_bv_size(b);
expr_ref tmp(m_manager);
if (sz1 > sz2) {
m_bv_simplifier->mk_zeroext(sz1-sz2, b, tmp);
tmp = m_rewriter.mk_zero_extend(sz1-sz2, b);
b = tmp;
}
else if (sz2 > sz1) {
m_bv_simplifier->mk_zeroext(sz2-sz1, a, tmp);
tmp = m_rewriter.mk_zero_extend(sz2-sz1, a);
a = tmp;
}
}
@ -123,11 +124,11 @@ bool bit2int::mk_add(expr* e1, expr* e2, expr_ref& result) {
return true;
}
align_sizes(tmp1, tmp2);
m_bv_simplifier->mk_zeroext(1, tmp1, tmp1);
m_bv_simplifier->mk_zeroext(1, tmp2, tmp2);
tmp1 = m_rewriter.mk_zero_extend(1, tmp1);
tmp2 = m_rewriter.mk_zero_extend(1, tmp2);
SASSERT(m_bv_util.get_bv_size(tmp1) == m_bv_util.get_bv_size(tmp2));
m_bv_simplifier->mk_add(tmp1, tmp2, tmp3);
m_bv_simplifier->mk_bv2int(tmp3, m_arith_util.mk_int(), result);
tmp3 = m_rewriter.mk_bv_add(tmp1, tmp2);
result = m_rewriter.mk_bv2int(tmp3);
return true;
}
return false;
@ -143,14 +144,14 @@ bool bit2int::mk_comp(eq_type ty, expr* e1, expr* e2, expr_ref& result) {
SASSERT(m_bv_util.get_bv_size(tmp1) == m_bv_util.get_bv_size(tmp2));
switch(ty) {
case lt:
m_bv_simplifier->mk_leq_core(false, tmp2, tmp1, tmp3);
tmp3 = m_rewriter.mk_ule(tmp2, tmp1);
result = m_manager.mk_not(tmp3);
break;
case le:
m_bv_simplifier->mk_leq_core(false,tmp1, tmp2, result);
result = m_rewriter.mk_ule(tmp1, tmp2);
break;
case eq:
result = m_manager.mk_eq(tmp1,tmp2);
result = m_manager.mk_eq(tmp1, tmp2);
break;
}
return true;
@ -167,12 +168,12 @@ bool bit2int::mk_mul(expr* e1, expr* e2, expr_ref& result) {
if (extract_bv(e1, sz1, sign1, tmp1) &&
extract_bv(e2, sz2, sign2, tmp2)) {
align_sizes(tmp1, tmp2);
m_bv_simplifier->mk_zeroext(m_bv_util.get_bv_size(tmp1), tmp1, tmp1);
m_bv_simplifier->mk_zeroext(m_bv_util.get_bv_size(tmp2), tmp2, tmp2);
tmp1 = m_rewriter.mk_zero_extend(m_bv_util.get_bv_size(tmp1), tmp1);
tmp2 = m_rewriter.mk_zero_extend(m_bv_util.get_bv_size(tmp2), tmp2);
SASSERT(m_bv_util.get_bv_size(tmp1) == m_bv_util.get_bv_size(tmp2));
m_bv_simplifier->mk_mul(tmp1, tmp2, tmp3);
m_bv_simplifier->mk_bv2int(tmp3, m_arith_util.mk_int(), result);
tmp3 = m_rewriter.mk_bv_mul(tmp1, tmp2);
result = m_rewriter.mk_bv2int(tmp3);
if (sign1 != sign2) {
result = m_arith_util.mk_uminus(result);
}
@ -187,8 +188,7 @@ bool bit2int::is_bv_poly(expr* n, expr_ref& pos, expr_ref& neg) {
numeral k;
bool is_int;
todo.push_back(n);
m_bv_simplifier->mk_bv2int(m_bit0, m_arith_util.mk_int(), pos);
m_bv_simplifier->mk_bv2int(m_bit0, m_arith_util.mk_int(), neg);
neg = pos = m_rewriter.mk_bv2int(m_bit0);
while (!todo.empty()) {
n = todo.back();
@ -372,8 +372,8 @@ void bit2int::visit(app* n) {
tmp1 = tmp_p;
tmp2 = e2bv;
align_sizes(tmp1, tmp2);
m_bv_simplifier->mk_bv_urem(tmp1, tmp2, tmp3);
m_bv_simplifier->mk_bv2int(tmp3, m_arith_util.mk_int(), result);
tmp3 = m_rewriter.mk_bv_urem(tmp1, tmp2);
result = m_rewriter.mk_bv2int(tmp3);
cache_result(n, result);
return;
}
@ -382,25 +382,24 @@ void bit2int::visit(app* n) {
tmp1 = tmp_n;
tmp2 = e2bv;
align_sizes(tmp1, tmp2);
m_bv_simplifier->mk_bv_urem(tmp1, tmp2, tmp3);
tmp3 = m_rewriter.mk_bv_urem(tmp1, tmp2);
// e2 - (neg1 mod e2)
tmp1 = e2bv;
tmp2 = tmp3;
align_sizes(tmp1, tmp2);
m_bv_simplifier->mk_sub(tmp1, tmp2, tmp3);
tmp3 = m_rewriter.mk_bv_sub(tmp1, tmp2);
// pos1 + (e2 - (neg1 mod e2))
tmp1 = tmp_p;
tmp2 = tmp3;
align_sizes(tmp1, tmp2);
m_bv_simplifier->mk_zeroext(1, tmp1, tmp_p);
m_bv_simplifier->mk_zeroext(1, tmp2, tmp_n);
m_bv_simplifier->mk_add(tmp_p, tmp_n, tmp1);
tmp_p = m_rewriter.mk_zero_extend(1, tmp1);
tmp_n = m_rewriter.mk_zero_extend(1, tmp2);
tmp1 = m_rewriter.mk_bv_add(tmp_p, tmp_n);
// (pos1 + (e2 - (neg1 mod e2))) mod e2
tmp2 = e2bv;
align_sizes(tmp1, tmp2);
m_bv_simplifier->mk_bv_urem(tmp1, tmp2, tmp3);
m_bv_simplifier->mk_bv2int(tmp3, m_arith_util.mk_int(), result);
tmp3 = m_rewriter.mk_bv_urem(tmp1, tmp2);
result = m_rewriter.mk_bv2int(tmp3);
cache_result(n, result);
}

View file

@ -22,9 +22,7 @@ Revision History:
#include "ast/bv_decl_plugin.h"
#include "ast/arith_decl_plugin.h"
#include "ast/act_cache.h"
#include "ast/simplifier/basic_simplifier_plugin.h"
#include "ast/simplifier/bv_simplifier_plugin.h"
#include "ast/rewriter/bv_rewriter.h"
class bit2int {
protected:
@ -60,8 +58,8 @@ protected:
typedef act_cache expr_map;
ast_manager & m_manager;
bv_util m_bv_util;
bv_rewriter m_rewriter;
arith_util m_arith_util;
bv_simplifier_plugin * m_bv_simplifier;
expr_map m_cache; // map: ast -> ast ref. counters are incremented when inserted here.
expr_ref m_bit0;
@ -88,7 +86,6 @@ protected:
public:
bit2int(ast_manager & m);
void set_bv_simplifier(bv_simplifier_plugin * p) { m_bv_simplifier = p; }
void operator()(expr * m, expr_ref & result, proof_ref& p);
};

View file

@ -4,5 +4,4 @@ z3_add_component(bit_blaster
bit_blaster_rewriter.cpp
COMPONENT_DEPENDENCIES
rewriter
simplifier
)

View file

@ -629,61 +629,23 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result)
return BR_REWRITE2;
}
}
expr* cond2, *t2, *e2;
if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
try_ite_value(to_app(t), val, result);
result = m().mk_ite(cond, result, m().mk_eq(e, val));
return BR_REWRITE2;
}
if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
try_ite_value(to_app(e), val, result);
result = m().mk_ite(cond, m().mk_eq(t, val), result);
return BR_REWRITE2;
{
expr* cond2, *t2, *e2;
if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
try_ite_value(to_app(t), val, result);
result = m().mk_ite(cond, result, m().mk_eq(e, val));
return BR_REWRITE2;
}
if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
try_ite_value(to_app(e), val, result);
result = m().mk_ite(cond, m().mk_eq(t, val), result);
return BR_REWRITE2;
}
}
return BR_FAILED;
}
#if 0
// Return true if ite is an if-then-else tree where the leaves are values,
// and they are all different from val
static bool is_ite_value_tree_neq_value(ast_manager & m, app * ite, app * val) {
SASSERT(m.is_ite(ite));
SASSERT(m.is_value(val));
expr_fast_mark1 visited;
ptr_buffer<app> todo;
todo.push_back(ite);
#define VISIT(ARG) { \
if (m.is_value(ARG)) { \
if (ARG == val) \
return false; \
} \
else if (m.is_ite(ARG)) { \
if (!visited.is_marked(ARG)) { \
visited.mark(ARG); \
todo.push_back(to_app(ARG)); \
} \
} \
else { \
return false; \
} \
}
while (!todo.empty()) {
app * ite = todo.back();
todo.pop_back();
SASSERT(m.is_ite(ite));
expr * t = ite->get_arg(1);
expr * e = ite->get_arg(2);
VISIT(t);
VISIT(e);
}
return true;
}
#endif
br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
if (m().are_equal(lhs, rhs)) {
@ -697,26 +659,20 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
}
br_status r = BR_FAILED;
if (m().is_ite(lhs) && m().is_value(rhs)) {
// if (is_ite_value_tree_neq_value(m(), to_app(lhs), to_app(rhs))) {
// result = m().mk_false();
// return BR_DONE;
// }
r = try_ite_value(to_app(lhs), to_app(rhs), result);
CTRACE("try_ite_value", r != BR_FAILED,
tout << mk_ismt2_pp(lhs, m()) << "\n" << mk_ismt2_pp(rhs, m()) << "\n--->\n" << mk_ismt2_pp(result, m()) << "\n";);
tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";);
}
else if (m().is_ite(rhs) && m().is_value(lhs)) {
// if (is_ite_value_tree_neq_value(m(), to_app(rhs), to_app(lhs))) {
// result = m().mk_false();
// return BR_DONE;
// }
r = try_ite_value(to_app(rhs), to_app(lhs), result);
CTRACE("try_ite_value", r != BR_FAILED,
tout << mk_ismt2_pp(lhs, m()) << "\n" << mk_ismt2_pp(rhs, m()) << "\n--->\n" << mk_ismt2_pp(result, m()) << "\n";);
tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";);
}
if (r != BR_FAILED)
return r;
if (m().is_bool(lhs)) {
bool unfolded = false;

View file

@ -0,0 +1,115 @@
/*++
Copyright (c) 2015 Microsoft Corporation
--*/
#include "ast/rewriter/bv_elim.h"
#include "ast/bv_decl_plugin.h"
#include "ast/rewriter/var_subst.h"
#include "ast/rewriter/rewriter_def.h"
#include <sstream>
bool bv_elim_cfg::reduce_quantifier(quantifier * q,
expr * body,
expr * const * new_patterns,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
svector<symbol> names, _names;
sort_ref_buffer sorts(m), _sorts(m);
expr_ref_buffer pats(m);
expr_ref_buffer no_pats(m);
expr_ref_buffer subst_map(m), _subst_map(m);
var_subst subst(m);
bv_util bv(m);
expr_ref new_body(m);
expr* old_body = body;
unsigned num_decls = q->get_num_decls();
family_id bfid = m.mk_family_id("bv");
//
// Traverse sequence of bound variables to eliminate
// bit-vecctor variables and replace them by
// Booleans.
//
unsigned var_idx = 0;
bool found = false;
for (unsigned i = num_decls; i > 0; ) {
--i;
sort* s = q->get_decl_sort(i);
symbol nm = q->get_decl_name(i);
if (bv.is_bv_sort(s)) {
// convert n-bit bit-vector variable into sequence of n-Booleans.
unsigned num_bits = bv.get_bv_size(s);
expr_ref_buffer args(m);
expr_ref bv(m);
found = true;
for (unsigned j = 0; j < num_bits; ++j) {
std::ostringstream new_name;
new_name << nm.str();
new_name << "_";
new_name << j;
var* v = m.mk_var(var_idx++, m.mk_bool_sort());
args.push_back(v);
_sorts.push_back(m.mk_bool_sort());
_names.push_back(symbol(new_name.str().c_str()));
}
bv = m.mk_app(bfid, OP_MKBV, 0, 0, args.size(), args.c_ptr());
_subst_map.push_back(bv.get());
}
else {
_subst_map.push_back(m.mk_var(var_idx++, s));
_sorts.push_back(s);
_names.push_back(nm);
}
}
if (!found) {
return false;
}
//
// reverse the vectors.
//
SASSERT(_names.size() == _sorts.size());
for (unsigned i = _names.size(); i > 0; ) {
--i;
names.push_back(_names[i]);
sorts.push_back(_sorts[i]);
}
for (unsigned i = _subst_map.size(); i > 0; ) {
--i;
subst_map.push_back(_subst_map[i]);
}
expr* const* sub = subst_map.c_ptr();
unsigned sub_size = subst_map.size();
subst(old_body, sub_size, sub, new_body);
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
expr_ref pat(m);
subst(new_patterns[j], sub_size, sub, pat);
pats.push_back(pat);
}
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
expr_ref nopat(m);
subst(new_no_patterns[j], sub_size, sub, nopat);
no_pats.push_back(nopat);
}
result = m.mk_quantifier(true,
names.size(),
sorts.c_ptr(),
names.c_ptr(),
new_body.get(),
q->get_weight(),
q->get_qid(),
q->get_skid(),
pats.size(), pats.c_ptr(),
no_pats.size(), no_pats.c_ptr());
result_pr = m.mk_rewrite(q, result);
return true;
}

View file

@ -0,0 +1,50 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
bv_elim.h
Abstract:
Eliminate bit-vectors variables from clauses, by
replacing them by bound Boolean variables.
Author:
Nikolaj Bjorner (nbjorner) 2008-12-16.
Revision History:
--*/
#ifndef BV_ELIM_H_
#define BV_ELIM_H_
#include "ast/ast.h"
#include "ast/rewriter/rewriter.h"
class bv_elim_cfg : public default_rewriter_cfg {
ast_manager& m;
public:
bv_elim_cfg(ast_manager& m) : m(m) {}
bool reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr);
};
class bv_elim_rw : public rewriter_tpl<bv_elim_cfg> {
protected:
bv_elim_cfg m_cfg;
public:
bv_elim_rw(ast_manager & m):
rewriter_tpl<bv_elim_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m)
{}
};
#endif /* BV_ELIM_H_ */

View file

@ -20,6 +20,7 @@ Notes:
#include "ast/rewriter/bv_rewriter_params.hpp"
#include "ast/rewriter/poly_rewriter_def.h"
#include "ast/ast_smt2_pp.h"
#include "ast/ast_lt.h"
void bv_rewriter::updt_local_params(params_ref const & _p) {
@ -1365,13 +1366,88 @@ br_status bv_rewriter::mk_bv2int(expr * arg, expr_ref & result) {
result = m_autil.mk_numeral(v, true);
return BR_DONE;
}
// TODO: add other simplifications
if (m_util.is_concat(arg)) {
if (to_app(arg)->get_num_args() == 0) {
result = m_autil.mk_int(0);
return BR_DONE;
}
expr_ref_vector args(m());
unsigned num_args = to_app(arg)->get_num_args();
for (expr* x : *to_app(arg)) {
args.push_back(m_util.mk_bv2int(x));
}
unsigned sz = get_bv_size(to_app(arg)->get_arg(num_args-1));
for (unsigned i = num_args - 1; i > 0; ) {
expr_ref tmp(m());
--i;
tmp = args[i].get();
tmp = m_autil.mk_mul(m_autil.mk_numeral(power(numeral(2), sz), true), tmp);
args[i] = tmp;
sz += get_bv_size(to_app(arg)->get_arg(i));
}
result = m_autil.mk_add(args.size(), args.c_ptr());
return BR_REWRITE2;
}
if (is_mul_no_overflow(arg)) {
expr_ref_vector args(m());
for (expr* x : *to_app(arg)) args.push_back(m_util.mk_bv2int(x));
result = m_autil.mk_mul(args.size(), args.c_ptr());
return BR_REWRITE2;
}
if (is_add_no_overflow(arg)) {
expr_ref_vector args(m());
for (expr* x : *to_app(arg)) args.push_back(m_util.mk_bv2int(x));
result = m_autil.mk_add(args.size(), args.c_ptr());
return BR_REWRITE2;
}
return BR_FAILED;
}
bool bv_rewriter::is_mul_no_overflow(expr* e) {
if (!m_util.is_bv_mul(e)) return false;
unsigned sz = get_bv_size(e);
unsigned sum = 0;
for (expr* x : *to_app(e)) sum += sz-num_leading_zero_bits(x);
return sum < sz;
}
bool bv_rewriter::is_add_no_overflow(expr* e) {
if (!is_add(e)) return false;
for (expr* x : *to_app(e)) {
if (0 == num_leading_zero_bits(x)) return false;
}
return true;
}
unsigned bv_rewriter::num_leading_zero_bits(expr* e) {
numeral v;
unsigned sz = get_bv_size(e);
if (m_util.is_numeral(e, v)) {
while (v.is_pos()) {
SASSERT(sz > 0);
--sz;
v = div(v, numeral(2));
}
return sz;
}
else if (m_util.is_concat(e)) {
app* a = to_app(e);
unsigned sz1 = get_bv_size(a->get_arg(0));
unsigned nb1 = num_leading_zero_bits(a->get_arg(0));
if (sz1 == nb1) {
nb1 += num_leading_zero_bits(a->get_arg(1));
}
return nb1;
}
return 0;
}
br_status bv_rewriter::mk_concat(unsigned num_args, expr * const * args, expr_ref & result) {
expr_ref_buffer new_args(m());
numeral v1;

View file

@ -42,6 +42,7 @@ protected:
decl_kind mul_decl_kind() const { return OP_BMUL; }
bool use_power() const { return false; }
decl_kind power_decl_kind() const { UNREACHABLE(); return static_cast<decl_kind>(UINT_MAX); }
public:
bv_rewriter_core(ast_manager & m):m_util(m) {}
};
@ -98,17 +99,20 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
br_status mk_bv_rotate_right(unsigned n, expr * arg, expr_ref & result);
br_status mk_bv_ext_rotate_left(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_bv_ext_rotate_right(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_bv_add(expr* a, expr* b, expr_ref& result) { expr* args[2] = { a, b }; return mk_bv_add(2, args, result); }
br_status mk_bv_sub(expr* a, expr* b, expr_ref& result) { expr* args[2] = { a, b }; return mk_sub(2, args, result); }
br_status mk_bv_mul(expr* a, expr* b, expr_ref& result) { expr* args[2] = { a, b }; return mk_bv_mul(2, args, result); }
br_status mk_bv_add(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_bv_add(expr * arg1, expr * arg2, expr_ref & result) {
expr * args[2] = { arg1, arg2 };
return mk_bv_add(2, args, result);
}
br_status mk_bv_mul(unsigned num_args, expr * const * args, expr_ref & result);
br_status mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_bv_ashr(expr * arg1, expr * arg2, expr_ref & result);
bool is_minus_one_core(expr * arg) const;
bool is_x_minus_one(expr * arg, expr * & x);
bool is_add_no_overflow(expr* e);
bool is_mul_no_overflow(expr* e);
unsigned num_leading_zero_bits(expr* e);
br_status mk_bv_sdiv_core(expr * arg1, expr * arg2, bool hi_div0, expr_ref & result);
br_status mk_bv_udiv_core(expr * arg1, expr * arg2, bool hi_div0, expr_ref & result);
br_status mk_bv_srem_core(expr * arg1, expr * arg2, bool hi_div0, expr_ref & result);
@ -185,6 +189,38 @@ public:
bool hi_div0() const { return m_hi_div0; }
bv_util & get_util() { return m_util; }
#define MK_BV_BINARY(OP) \
expr_ref OP(expr* a, expr* b) { \
expr_ref result(m()); \
if (BR_FAILED == OP(a, b, result)) \
result = m_util.OP(a, b); \
return result; \
} \
expr_ref mk_zero_extend(unsigned n, expr * arg) {
expr_ref result(m());
if (BR_FAILED == mk_zero_extend(n, arg, result))
result = m_util.mk_zero_extend(n, arg);
return result;
}
MK_BV_BINARY(mk_bv_urem);
MK_BV_BINARY(mk_ule);
MK_BV_BINARY(mk_bv_add);
MK_BV_BINARY(mk_bv_mul);
MK_BV_BINARY(mk_bv_sub);
expr_ref mk_bv2int(expr* a) {
expr_ref result(m());
if (BR_FAILED == mk_bv2int(a, result))
result = m_util.mk_bv2int(a);
return result;
}
};
#endif

View file

@ -23,6 +23,7 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr
switch(f->get_decl_kind()) {
case OP_DT_CONSTRUCTOR: return BR_FAILED;
case OP_DT_RECOGNISER:
case OP_DT_IS:
//
// simplify is_cons(cons(x,y)) -> true
// simplify is_cons(nil) -> false
@ -47,11 +48,11 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr
func_decl * c_decl = a->get_decl();
if (c_decl != m_util.get_accessor_constructor(f))
return BR_FAILED;
ptr_vector<func_decl> const * acc = m_util.get_constructor_accessors(c_decl);
SASSERT(acc && acc->size() == a->get_num_args());
unsigned num = acc->size();
ptr_vector<func_decl> const & acc = *m_util.get_constructor_accessors(c_decl);
SASSERT(acc.size() == a->get_num_args());
unsigned num = acc.size();
for (unsigned i = 0; i < num; ++i) {
if (f == (*acc)[i]) {
if (f == acc[i]) {
// found it.
result = a->get_arg(i);
return BR_DONE;
@ -70,13 +71,13 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr
result = a;
return BR_DONE;
}
ptr_vector<func_decl> const * acc = m_util.get_constructor_accessors(c_decl);
SASSERT(acc && acc->size() == a->get_num_args());
unsigned num = acc->size();
ptr_vector<func_decl> const & acc = *m_util.get_constructor_accessors(c_decl);
SASSERT(acc.size() == a->get_num_args());
unsigned num = acc.size();
ptr_buffer<expr> new_args;
for (unsigned i = 0; i < num; ++i) {
if (f == (*acc)[i]) {
if (f == acc[i]) {
new_args.push_back(args[1]);
}
else {

View file

@ -0,0 +1,203 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
elim_bounds.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-06-28.
Revision History:
--*/
#ifndef ELIM_BOUNDS_H_
#define ELIM_BOUNDS_H_
#include "ast/used_vars.h"
#include "util/obj_hashtable.h"
#include "ast/rewriter/var_subst.h"
#include "ast/rewriter/elim_bounds.h"
#include "ast/ast_pp.h"
elim_bounds_cfg::elim_bounds_cfg(ast_manager & m):
m(m),
m_util(m) {
}
/**
\brief Find bounds of the form
(<= x k)
(<= (+ x (* -1 y)) k)
(<= (+ x (* -1 t)) k)
(<= (+ t (* -1 x)) k)
x and y are a bound variables, t is a ground term and k is a numeral
It also detects >=, and the atom can be negated.
*/
bool elim_bounds_cfg::is_bound(expr * n, var * & lower, var * & upper) {
upper = 0;
lower = 0;
bool neg = false;
if (m.is_not(n)) {
n = to_app(n)->get_arg(0);
neg = true;
}
expr* l = 0, *r = 0;
bool le = false;
if (m_util.is_le(n, l, r) && m_util.is_numeral(r)) {
n = l;
le = true;
}
else if (m_util.is_ge(n, l, r) && m_util.is_numeral(r)) {
n = l;
le = false;
}
else {
return false;
}
if (neg)
le = !le;
if (is_var(n)) {
upper = to_var(n);
}
else if (m_util.is_add(n, l, r)) {
expr * arg1 = l;
expr * arg2 = r;
if (is_var(arg1))
upper = to_var(arg1);
else if (!is_ground(arg1))
return false;
rational k;
bool is_int;
if (m_util.is_mul(arg2) && m_util.is_numeral(to_app(arg2)->get_arg(0), k, is_int) && k.is_minus_one()) {
arg2 = to_app(arg2)->get_arg(1);
if (is_var(arg2))
lower = to_var(arg2);
else if (!is_ground(arg2))
return false; // not supported
}
else {
return false; // not supported
}
}
else {
return false;
}
if (!le)
std::swap(upper, lower);
return true;
}
bool elim_bounds_cfg::is_bound(expr * n) {
var * lower, * upper;
return is_bound(n, lower, upper);
}
bool elim_bounds_cfg::reduce_quantifier(quantifier * q,
expr * n,
expr * const * new_patterns,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
if (!q->is_forall()) {
return false;
}
unsigned num_vars = q->get_num_decls();
ptr_buffer<expr> atoms;
if (m.is_or(n))
atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args());
else
atoms.push_back(n);
used_vars used_vars;
// collect non-candidates
for (expr * a : atoms) {
if (!is_bound(a))
used_vars.process(a);
}
if (used_vars.uses_all_vars(q->get_num_decls())) {
return false;
}
// collect candidates
obj_hashtable<var> lowers;
obj_hashtable<var> uppers;
obj_hashtable<var> candidate_set;
ptr_buffer<var> candidates;
#define ADD_CANDIDATE(V) if (!lowers.contains(V) && !uppers.contains(V)) { candidate_set.insert(V); candidates.push_back(V); }
for (expr * a : atoms) {
var * lower = 0;
var * upper = 0;
if (is_bound(a, lower, upper)) {
if (lower != 0 && !used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) {
ADD_CANDIDATE(lower);
lowers.insert(lower);
}
if (upper != 0 && !used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) {
ADD_CANDIDATE(upper);
uppers.insert(upper);
}
}
}
TRACE("elim_bounds", tout << "candidates:\n"; for (unsigned i = 0; i < candidates.size(); i++) tout << mk_pp(candidates[i], m) << "\n";);
// remove candidates that have lower and upper bounds
for (var * v : candidates) {
if (lowers.contains(v) && uppers.contains(v))
candidate_set.erase(v);
}
TRACE("elim_bounds", tout << "candidates after filter:\n"; for (unsigned i = 0; i < candidates.size(); i++) tout << mk_pp(candidates[i], m) << "\n";);
if (candidate_set.empty()) {
return false;
}
// remove bounds that contain variables in candidate_set
unsigned j = 0;
for (unsigned i = 0; i < atoms.size(); ++i) {
expr * a = atoms[i];
var * lower = 0;
var * upper = 0;
if (is_bound(a, lower, upper) && ((lower != 0 && candidate_set.contains(lower)) || (upper != 0 && candidate_set.contains(upper))))
continue;
atoms[j] = a;
j++;
}
if (j == atoms.size()) {
return false;
}
atoms.resize(j);
expr * new_body = 0;
switch (atoms.size()) {
case 0:
result = m.mk_false();
result_pr = m.mk_rewrite(q, result);
TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";);
return true;
case 1:
new_body = atoms[0];
break;
default:
new_body = m.mk_or(atoms.size(), atoms.c_ptr());
break;
}
quantifier_ref new_q(m);
new_q = m.update_quantifier(q, new_body);
elim_unused_vars(m, new_q, params_ref(), result);
result_pr = m.mk_rewrite(q, result);
TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";);
return true;
}
#endif /* ELIM_BOUNDS_H_ */

View file

@ -3,7 +3,7 @@ Copyright (c) 2006 Microsoft Corporation
Module Name:
elim_bounds.h
elim_bounds2.h
Abstract:
@ -16,12 +16,12 @@ Author:
Revision History:
--*/
#ifndef ELIM_BOUNDS_H_
#define ELIM_BOUNDS_H_
#ifndef ELIM_BOUNDS2_H_
#define ELIM_BOUNDS2_H_
#include "ast/ast.h"
#include "ast/arith_decl_plugin.h"
#include "ast/simplifier/simplifier.h"
#include "ast/rewriter/rewriter.h"
/**
\brief Functor for eliminating irrelevant bounds in quantified formulas.
@ -39,31 +39,39 @@ Revision History:
\remark This operation is subsumed by Fourier-Motzkin elimination.
*/
class elim_bounds {
ast_manager & m_manager;
class elim_bounds_cfg : public default_rewriter_cfg {
ast_manager & m;
arith_util m_util;
bool is_bound(expr * n, var * & lower, var * & upper);
bool is_bound(expr * n);
public:
elim_bounds(ast_manager & m);
void operator()(quantifier * q, expr_ref & r);
elim_bounds_cfg(ast_manager & m);
bool reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr);
};
/**
\brief Functor for applying elim_bounds in all
\brief Functor for applying elim_bounds2 in all
universal quantifiers in an expression.
Assumption: the formula was already skolemized.
*/
class elim_bounds_star : public simplifier {
class elim_bounds_rw : public rewriter_tpl<elim_bounds_cfg> {
protected:
elim_bounds m_elim;
virtual bool visit_quantifier(quantifier * q);
virtual void reduce1_quantifier(quantifier * q);
elim_bounds_cfg m_cfg;
public:
elim_bounds_star(ast_manager & m):simplifier(m), m_elim(m) { enable_ac_support(false); }
virtual ~elim_bounds_star() {}
elim_bounds_rw(ast_manager & m):
rewriter_tpl<elim_bounds_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m)
{}
virtual ~elim_bounds_rw() {}
};
#endif /* ELIM_BOUNDS_H_ */
#endif /* ELIM_BOUNDS2_H_ */

View file

@ -16,7 +16,7 @@ Author:
Revision History:
--*/
#include "ast/simplifier/inj_axiom.h"
#include "ast/rewriter/inj_axiom.h"
#include "ast/ast_pp.h"
#include "ast/ast_ll_pp.h"
#include "ast/has_free_vars.h"
@ -29,18 +29,15 @@ Revision History:
*/
bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result) {
expr * n = q->get_expr();
if (q->is_forall() && m.is_or(n) && to_app(n)->get_num_args() == 2) {
expr * arg1 = to_app(n)->get_arg(0);
expr * arg2 = to_app(n)->get_arg(1);
expr* arg1 = 0, * arg2 = 0, *narg = 0;
expr* app1 = 0, * app2 = 0;
expr* var1 = 0, * var2 = 0;
if (q->is_forall() && m.is_or(n, arg1, arg2)) {
if (m.is_not(arg2))
std::swap(arg1, arg2);
if (m.is_not(arg1) &&
m.is_eq(to_app(arg1)->get_arg(0)) &&
m.is_eq(arg2)) {
expr * app1 = to_app(to_app(arg1)->get_arg(0))->get_arg(0);
expr * app2 = to_app(to_app(arg1)->get_arg(0))->get_arg(1);
expr * var1 = to_app(arg2)->get_arg(0);
expr * var2 = to_app(arg2)->get_arg(1);
if (m.is_not(arg1, narg) &&
m.is_eq(narg, app1, app2) &&
m.is_eq(arg2, var1, var2)) {
if (is_app(app1) &&
is_app(app2) &&
to_app(app1)->get_decl() == to_app(app2)->get_decl() &&

View file

@ -3,7 +3,7 @@ Copyright (c) 2006 Microsoft Corporation
Module Name:
maximise_ac_sharing.cpp
maximize_ac_sharing.cpp
Abstract:
@ -17,33 +17,26 @@ Revision History:
--*/
#include "ast/simplifier/maximise_ac_sharing.h"
#include "ast/rewriter/maximize_ac_sharing.h"
#include "ast/ast_pp.h"
#include "ast/simplifier/basic_simplifier_plugin.h"
maximise_ac_sharing::ac_plugin::ac_plugin(symbol const & fname, ast_manager & m, maximise_ac_sharing & owner):
simplifier_plugin(fname, m),
m_owner(owner) {
}
void maximise_ac_sharing::ac_plugin::register_kind(decl_kind k) {
void maximize_ac_sharing::register_kind(decl_kind k) {
m_kinds.push_back(k);
}
maximise_ac_sharing::ac_plugin::~ac_plugin() {
}
bool maximise_ac_sharing::ac_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
br_status maximize_ac_sharing::reduce_app(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result, proof_ref& result_pr) {
decl_kind k = f->get_kind();
if (!f->is_associative())
return false;
return BR_FAILED;
if (num_args <= 2)
return false;
return BR_FAILED;
if (std::find(m_kinds.begin(), m_kinds.end(), k) == m_kinds.end())
return false;
return BR_FAILED;
ptr_buffer<expr, 128> _args;
expr * numeral = 0;
if (m_owner.is_numeral(args[0])) {
if (is_numeral(args[0])) {
numeral = args[0];
for (unsigned i = 1; i < num_args; i++)
_args.push_back(args[i]);
@ -58,14 +51,14 @@ bool maximise_ac_sharing::ac_plugin::reduce(func_decl * f, unsigned num_args, ex
#define MAX_NUM_ARGS_FOR_OPT 128
// Try to reuse already created circuits.
TRACE("ac_sharing_detail", tout << "args: "; for (unsigned i = 0; i < num_args; i++) tout << mk_pp(_args[i], m_manager) << "\n";);
TRACE("ac_sharing_detail", tout << "args: "; for (unsigned i = 0; i < num_args; i++) tout << mk_pp(_args[i], m) << "\n";);
try_to_reuse:
if (num_args > 1 && num_args < MAX_NUM_ARGS_FOR_OPT) {
for (unsigned i = 0; i < num_args - 1; i++) {
for (unsigned j = i + 1; j < num_args; j++) {
if (m_owner.contains(f, _args[i], _args[j])) {
if (contains(f, _args[i], _args[j])) {
TRACE("ac_sharing_detail", tout << "reusing args: " << i << " " << j << "\n";);
_args[i] = m_manager.mk_app(f, _args[i], _args[j]);
_args[i] = m.mk_app(f, _args[i], _args[j]);
SASSERT(num_args > 1);
for (unsigned w = j; w < num_args - 1; w++) {
_args[w] = _args[w+1];
@ -87,8 +80,8 @@ bool maximise_ac_sharing::ac_plugin::reduce(func_decl * f, unsigned num_args, ex
_args[j] = _args[i];
}
else {
m_owner.insert(f, _args[i], _args[i+1]);
_args[j] = m_manager.mk_app(f, _args[i], _args[i+1]);
insert(f, _args[i], _args[i+1]);
_args[j] = m.mk_app(f, _args[i], _args[i+1]);
}
}
num_args = j;
@ -97,54 +90,47 @@ bool maximise_ac_sharing::ac_plugin::reduce(func_decl * f, unsigned num_args, ex
result = _args[0];
}
else {
result = m_manager.mk_app(f, numeral, _args[0]);
result = m.mk_app(f, numeral, _args[0]);
}
TRACE("ac_sharing_detail", tout << "result: " << mk_pp(result, m_manager) << "\n";);
return true;
TRACE("ac_sharing_detail", tout << "result: " << mk_pp(result, m) << "\n";);
return BR_DONE;
}
}
UNREACHABLE();
return false;
return BR_FAILED;
}
bool maximise_ac_sharing::contains(func_decl * f, expr * arg1, expr * arg2) {
bool maximize_ac_sharing::contains(func_decl * f, expr * arg1, expr * arg2) {
entry e(f, arg1, arg2);
return m_cache.contains(&e);
}
void maximise_ac_sharing::insert(func_decl * f, expr * arg1, expr * arg2) {
void maximize_ac_sharing::insert(func_decl * f, expr * arg1, expr * arg2) {
entry * e = new (m_region) entry(f, arg1, arg2);
m_entries.push_back(e);
m_cache.insert(e);
m_manager.inc_ref(arg1);
m_manager.inc_ref(arg2);
m.inc_ref(arg1);
m.inc_ref(arg2);
}
maximise_ac_sharing::maximise_ac_sharing(ast_manager & m):
m_manager(m),
m_simplifier(m),
maximize_ac_sharing::maximize_ac_sharing(ast_manager & m):
m(m),
m_init(false) {
basic_simplifier_plugin* basic_simp = alloc(basic_simplifier_plugin,m);
m_simplifier.register_plugin(basic_simp);
}
maximise_ac_sharing::~maximise_ac_sharing() {
maximize_ac_sharing::~maximize_ac_sharing() {
restore_entries(0);
}
void maximise_ac_sharing::operator()(expr * s, expr_ref & r, proof_ref & p) {
init();
m_simplifier.operator()(s, r, p);
}
void maximise_ac_sharing::push_scope() {
void maximize_ac_sharing::push_scope() {
init();
m_scopes.push_back(m_entries.size());
m_region.push_scope();
}
void maximise_ac_sharing::pop_scope(unsigned num_scopes) {
void maximize_ac_sharing::pop_scope(unsigned num_scopes) {
SASSERT(num_scopes <= m_scopes.size());
unsigned new_lvl = m_scopes.size() - num_scopes;
unsigned old_lim = m_scopes[new_lvl];
@ -153,40 +139,37 @@ void maximise_ac_sharing::pop_scope(unsigned num_scopes) {
m_scopes.shrink(new_lvl);
}
void maximise_ac_sharing::restore_entries(unsigned old_lim) {
void maximize_ac_sharing::restore_entries(unsigned old_lim) {
unsigned i = m_entries.size();
while (i != old_lim) {
--i;
entry * e = m_entries[i];
m_manager.dec_ref(e->m_arg1);
m_manager.dec_ref(e->m_arg2);
m.dec_ref(e->m_arg1);
m.dec_ref(e->m_arg2);
}
m_entries.shrink(old_lim);
}
void maximise_ac_sharing::reset() {
void maximize_ac_sharing::reset() {
restore_entries(0);
m_entries.reset();
m_cache.reset();
m_simplifier.reset();
m_region.reset();
m_scopes.reset();
}
void maximise_bv_sharing::init_core() {
maximise_ac_sharing::ac_plugin * p = alloc(maximise_ac_sharing::ac_plugin, symbol("bv"), get_manager(), *this);
p->register_kind(OP_BADD);
p->register_kind(OP_BMUL);
p->register_kind(OP_BOR);
p->register_kind(OP_BAND);
register_plugin(p);
void maximize_bv_sharing::init_core() {
register_kind(OP_BADD);
register_kind(OP_BMUL);
register_kind(OP_BOR);
register_kind(OP_BAND);
}
bool maximise_bv_sharing::is_numeral(expr * n) const {
bool maximize_bv_sharing::is_numeral(expr * n) const {
return m_util.is_numeral(n);
}
maximise_bv_sharing::maximise_bv_sharing(ast_manager & m):
maximise_ac_sharing(m),
maximize_bv_sharing::maximize_bv_sharing(ast_manager & m):
maximize_ac_sharing(m),
m_util(m) {
}

View file

@ -3,7 +3,7 @@ Copyright (c) 2006 Microsoft Corporation
Module Name:
maximise_ac_sharing.h
maximize_ac_sharing.h
Abstract:
@ -16,17 +16,17 @@ Author:
Revision History:
--*/
#ifndef MAXIMISE_AC_SHARING_H_
#define MAXIMISE_AC_SHARING_H_
#ifndef MAXIMIZE_AC_SHARING_H_
#define MAXIMIZE_AC_SHARING_H_
#include "ast/simplifier/simplifier.h"
#include "util/hashtable.h"
#include "ast/bv_decl_plugin.h"
#include "util/region.h"
#include "ast/bv_decl_plugin.h"
#include "ast/rewriter/rewriter.h"
/**
\brief Functor used to maximise the amount of shared terms in an expression.
The idea is to rewrite AC terms to maximise sharing.
\brief Functor used to maximize the amount of shared terms in an expression.
The idea is to rewrite AC terms to maximize sharing.
Example:
(f (bvadd a (bvadd b c)) (bvadd a (bvadd b d)))
@ -35,10 +35,10 @@ Revision History:
(f (bvadd (bvadd a b) c) (bvadd (bvadd a b) d))
\warning This class uses an opportunistic heuristic to maximise sharing.
\warning This class uses an opportunistic heuristic to maximize sharing.
There is no guarantee that the optimal expression will be produced.
*/
class maximise_ac_sharing {
class maximize_ac_sharing : public default_rewriter_cfg {
struct entry {
func_decl * m_decl;
@ -67,26 +67,16 @@ class maximise_ac_sharing {
typedef ptr_hashtable<entry, obj_ptr_hash<entry>, deref_eq<entry> > cache;
protected:
class ac_plugin : public simplifier_plugin {
maximise_ac_sharing & m_owner;
svector<decl_kind> m_kinds; //!< kinds to be processed
public:
ac_plugin(symbol const & fname, ast_manager & m, maximise_ac_sharing & owner);
void register_kind(decl_kind k);
virtual ~ac_plugin();
virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
};
friend class ac_plugin;
void register_kind(decl_kind k);
private:
ast_manager & m_manager;
simplifier m_simplifier;
ast_manager & m;
bool m_init;
region m_region;
cache m_cache;
ptr_vector<entry> m_entries;
unsigned_vector m_scopes;
svector<decl_kind> m_kinds; //!< kinds to be processed
bool contains(func_decl * f, expr * arg1, expr * arg2);
void insert(func_decl * f, expr * arg1, expr * arg2);
@ -100,25 +90,36 @@ private:
protected:
virtual void init_core() = 0;
virtual bool is_numeral(expr * n) const = 0;
void register_plugin(ac_plugin * p) { m_simplifier.register_plugin(p); }
public:
maximise_ac_sharing(ast_manager & m);
virtual ~maximise_ac_sharing();
void operator()(expr * s, expr_ref & r, proof_ref & p);
maximize_ac_sharing(ast_manager & m);
virtual ~maximize_ac_sharing();
void push_scope();
void pop_scope(unsigned num_scopes);
void reset();
ast_manager & get_manager() { return m_manager; }
br_status reduce_app(func_decl* f, unsigned n, expr * const* args, expr_ref& result, proof_ref& result_pr);
};
class maximise_bv_sharing : public maximise_ac_sharing {
class maximize_bv_sharing : public maximize_ac_sharing {
bv_util m_util;
protected:
virtual void init_core();
virtual bool is_numeral(expr * n) const;
public:
maximise_bv_sharing(ast_manager & m);
maximize_bv_sharing(ast_manager & m);
};
#endif /* MAXIMISE_AC_SHARING_H_ */
class maximize_bv_sharing_rw : public rewriter_tpl<maximize_bv_sharing> {
maximize_bv_sharing m_cfg;
public:
maximize_bv_sharing_rw(ast_manager& m):
rewriter_tpl<maximize_bv_sharing>(m, m.proofs_enabled(), m_cfg),
m_cfg(m)
{}
void push_scope() { m_cfg.push_scope(); }
void pop_scope(unsigned n) { m_cfg.pop_scope(n); }
void reset() { m_cfg.reset(); }
};
#endif /* MAXIMIZE_AC_SHARING_H_ */

View file

@ -36,10 +36,10 @@ protected:
bool m_sort_sums;
bool m_hoist_mul;
bool m_hoist_cmul;
bool m_ast_order;
bool is_numeral(expr * n) const { return Config::is_numeral(n); }
bool is_numeral(expr * n, numeral & r) const { return Config::is_numeral(n, r); }
bool is_zero(expr * n) const { return Config::is_zero(n); }
bool is_minus_one(expr * n) const { return Config::is_minus_one(n); }
void normalize(numeral & c) { Config::normalize(c, m_curr_sort); }
app * mk_numeral(numeral const & r) { return Config::mk_numeral(r, m_curr_sort); }
@ -49,7 +49,6 @@ protected:
decl_kind power_decl_kind() const { return Config::power_decl_kind(); }
bool is_power(expr * t) const { return is_app_of(t, get_fid(), power_decl_kind()); }
expr * get_power_body(expr * t, rational & k);
struct mon_pw_lt; // functor used to sort monomial elements when use_power() == true
expr * mk_mul_app(unsigned num_args, expr * const * args);
expr * mk_mul_app(numeral const & c, expr * arg);
@ -86,6 +85,14 @@ protected:
bool is_mul(expr * t, numeral & c, expr * & pp);
void hoist_cmul(expr_ref_buffer & args);
class mon_lt {
poly_rewriter& rw;
int ordinal(expr* e) const;
public:
mon_lt(poly_rewriter& rw): rw(rw) {}
bool operator()(expr* e1, expr * e2) const;
};
public:
poly_rewriter(ast_manager & m, params_ref const & p = params_ref()):
Config(m),
@ -111,6 +118,10 @@ public:
bool is_mul(expr * n) const { return is_app_of(n, get_fid(), mul_decl_kind()); }
bool is_add(func_decl * f) const { return is_decl_of(f, get_fid(), add_decl_kind()); }
bool is_mul(func_decl * f) const { return is_decl_of(f, get_fid(), mul_decl_kind()); }
bool is_times_minus_one(expr * n, expr*& r) const;
bool is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t);
bool is_zero(expr* e) const;
br_status mk_mul_core(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args > 0);

View file

@ -18,6 +18,7 @@ Notes:
--*/
#include "ast/rewriter/poly_rewriter.h"
#include "ast/rewriter/poly_rewriter_params.hpp"
#include "ast/rewriter/arith_rewriter_params.hpp"
#include "ast/ast_lt.h"
#include "ast/ast_ll_pp.h"
#include "ast/ast_smt2_pp.h"
@ -33,6 +34,8 @@ void poly_rewriter<Config>::updt_params(params_ref const & _p) {
m_som_blowup = p.som_blowup();
if (!m_flat) m_som = false;
if (m_som) m_hoist_mul = false;
arith_rewriter_params ap(_p);
m_ast_order = !ap.arith_ineq_lhs();
}
template<typename Config>
@ -64,6 +67,13 @@ expr * poly_rewriter<Config>::get_power_body(expr * t, rational & k) {
return t;
}
template<typename Config>
bool poly_rewriter<Config>::is_zero(expr* e) const {
rational v;
return is_numeral(e, v) && v.is_zero();
}
template<typename Config>
expr * poly_rewriter<Config>::mk_mul_app(unsigned num_args, expr * const * args) {
switch (num_args) {
@ -118,6 +128,9 @@ expr * poly_rewriter<Config>::mk_mul_app(numeral const & c, expr * arg) {
if (c.is_one()) {
return arg;
}
else if (is_zero(arg)) {
return arg;
}
else {
expr * new_args[2] = { mk_numeral(c), arg };
return mk_mul_app(2, new_args);
@ -181,21 +194,9 @@ br_status poly_rewriter<Config>::mk_flat_mul_core(unsigned num_args, expr * cons
}
template<typename Config>
struct poly_rewriter<Config>::mon_pw_lt {
poly_rewriter<Config> & m_owner;
mon_pw_lt(poly_rewriter<Config> & o):m_owner(o) {}
bool operator()(expr * n1, expr * n2) const {
rational k;
return lt(m_owner.get_power_body(n1, k),
m_owner.get_power_body(n2, k));
}
};
template<typename Config>
br_status poly_rewriter<Config>::mk_nflat_mul_core(unsigned num_args, expr * const * args, expr_ref & result) {
mon_lt lt(*this);
SASSERT(num_args >= 2);
// cheap case
numeral a;
@ -310,11 +311,8 @@ br_status poly_rewriter<Config>::mk_nflat_mul_core(unsigned num_args, expr * con
if (ordered && num_coeffs == 0 && !use_power())
return BR_FAILED;
if (!ordered) {
if (use_power())
std::sort(new_args.begin(), new_args.end(), mon_pw_lt(*this));
else
std::sort(new_args.begin(), new_args.end(), ast_to_lt());
TRACE("poly_rewriter",
std::sort(new_args.begin(), new_args.end(), lt);
TRACE("poly_rewriter",
tout << "after sorting:\n";
for (unsigned i = 0; i < new_args.size(); i++) {
if (i > 0)
@ -488,8 +486,45 @@ void poly_rewriter<Config>::hoist_cmul(expr_ref_buffer & args) {
args.resize(j);
}
template<typename Config>
bool poly_rewriter<Config>::mon_lt::operator()(expr* e1, expr * e2) const {
if (rw.m_ast_order)
return lt(e1,e2);
return ordinal(e1) < ordinal(e2);
}
inline bool is_essentially_var(expr * n, family_id fid) {
SASSERT(is_var(n) || is_app(n));
return is_var(n) || to_app(n)->get_family_id() != fid;
}
template<typename Config>
int poly_rewriter<Config>::mon_lt::ordinal(expr* e) const {
rational k;
if (is_essentially_var(e, rw.get_fid())) {
return e->get_id();
}
else if (rw.is_mul(e)) {
if (rw.is_numeral(to_app(e)->get_arg(0)))
return to_app(e)->get_arg(1)->get_id();
else
return e->get_id();
}
else if (rw.is_numeral(e)) {
return -1;
}
else if (rw.use_power() && rw.is_power(e) && rw.is_numeral(to_app(e)->get_arg(1), k) && k > rational(1)) {
return to_app(e)->get_arg(0)->get_id();
}
else {
return e->get_id();
}
}
template<typename Config>
br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * const * args, expr_ref & result) {
mon_lt lt(*this);
SASSERT(num_args >= 2);
numeral c;
unsigned num_coeffs = 0;
@ -498,22 +533,22 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con
expr_fast_mark2 multiple; // multiple.is_marked(power_product) if power_product occurs more than once
bool has_multiple = false;
expr * prev = 0;
bool ordered = true;
bool ordered = true;
for (unsigned i = 0; i < num_args; i++) {
expr * arg = args[i];
if (is_numeral(arg, a)) {
num_coeffs++;
c += a;
ordered = !m_sort_sums || i == 0;
}
else {
// arg is not a numeral
if (m_sort_sums && ordered) {
if (prev != 0 && lt(arg, prev))
ordered = false;
prev = arg;
}
else if (m_sort_sums && ordered) {
if (prev != 0 && lt(arg, prev))
ordered = false;
prev = arg;
}
arg = get_power_product(arg);
if (visited.is_marked(arg)) {
multiple.mark(arg);
@ -525,8 +560,8 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con
}
normalize(c);
SASSERT(m_sort_sums || ordered);
TRACE("sort_sums",
tout << "ordered: " << ordered << "\n";
TRACE("rewriter",
tout << "ordered: " << ordered << " sort sums: " << m_sort_sums << "\n";
for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m()) << "\n";);
if (has_multiple) {
@ -579,13 +614,14 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con
hoist_cmul(new_args);
}
else if (m_sort_sums) {
TRACE("sort_sums_bug", tout << "new_args.size(): " << new_args.size() << "\n";);
TRACE("rewriter_bug", tout << "new_args.size(): " << new_args.size() << "\n";);
if (c.is_zero())
std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), ast_to_lt());
std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), mon_lt(*this));
else
std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), ast_to_lt());
std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), mon_lt(*this));
}
result = mk_add_app(new_args.size(), new_args.c_ptr());
TRACE("rewriter", tout << result << "\n";);
if (hoist_multiplication(result)) {
return BR_REWRITE_FULL;
}
@ -613,10 +649,10 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con
}
else if (!ordered) {
if (c.is_zero())
std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), ast_to_lt());
std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), lt);
else
std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), ast_to_lt());
}
std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), lt);
}
result = mk_add_app(new_args.size(), new_args.c_ptr());
if (hoist_multiplication(result)) {
return BR_REWRITE_FULL;
@ -654,6 +690,7 @@ br_status poly_rewriter<Config>::mk_sub(unsigned num_args, expr * const * args,
ptr_buffer<expr> new_args;
new_args.push_back(args[0]);
for (unsigned i = 1; i < num_args; i++) {
if (is_zero(args[i])) continue;
expr * aux_args[2] = { minus_one, args[i] };
new_args.push_back(mk_mul_app(2, aux_args));
}
@ -669,6 +706,7 @@ br_status poly_rewriter<Config>::mk_sub(unsigned num_args, expr * const * args,
template<typename Config>
br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool move, expr_ref & lhs_result, expr_ref & rhs_result) {
set_curr_sort(m().get_sort(lhs));
mon_lt lt(*this);
unsigned lhs_sz;
expr * const * lhs_monomials = get_monomials(lhs, lhs_sz);
unsigned rhs_sz;
@ -693,8 +731,10 @@ br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool m
}
}
if (move && num_coeffs == 0 && is_numeral(rhs))
if (move && num_coeffs == 0 && is_numeral(rhs)) {
TRACE("mk_le_bug", tout << "no coeffs\n";);
return BR_FAILED;
}
for (unsigned i = 0; i < rhs_sz; i++) {
expr * arg = rhs_monomials[i];
@ -712,15 +752,17 @@ br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool m
}
normalize(c);
if (!has_multiple && num_coeffs <= 1) {
if (move) {
if (is_numeral(rhs))
if (is_numeral(rhs)) {
return BR_FAILED;
}
}
else {
if (num_coeffs == 0 || is_numeral(rhs))
if (num_coeffs == 0 || is_numeral(rhs)) {
return BR_FAILED;
}
}
}
@ -811,7 +853,7 @@ br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool m
if (move) {
if (m_sort_sums) {
// + 1 to skip coefficient
std::sort(new_lhs_monomials.begin() + 1, new_lhs_monomials.end(), ast_to_lt());
std::sort(new_lhs_monomials.begin() + 1, new_lhs_monomials.end(), lt);
}
c_at_rhs = true;
}
@ -836,6 +878,7 @@ br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool m
new_lhs_monomials[0] = insert_c_lhs ? mk_numeral(c) : NULL;
lhs_result = mk_add_app(new_lhs_monomials.size() - lhs_offset, new_lhs_monomials.c_ptr() + lhs_offset);
rhs_result = mk_add_app(new_rhs_monomials.size() - rhs_offset, new_rhs_monomials.c_ptr() + rhs_offset);
TRACE("mk_le_bug", tout << lhs_result << " " << rhs_result << "\n";);
return BR_DONE;
}
@ -931,3 +974,63 @@ expr* poly_rewriter<Config>::merge_muls(expr* x, expr* y) {
m1[k] = mk_add_app(2, args);
return mk_mul_app(k+1, m1.c_ptr());
}
template<typename Config>
bool poly_rewriter<Config>::is_times_minus_one(expr * n, expr* & r) const {
if (is_mul(n) && to_app(n)->get_num_args() == 2 && is_minus_one(to_app(n)->get_arg(0))) {
r = to_app(n)->get_arg(1);
return true;
}
return false;
}
/**
\brief Return true if n is can be put into the form (+ v t) or (+ (- v) t)
\c inv = true will contain true if (- v) is found, and false otherwise.
*/
template<typename Config>
bool poly_rewriter<Config>::is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) {
if (!is_add(n) || is_ground(n))
return false;
ptr_buffer<expr> args;
v = 0;
expr * curr = to_app(n);
bool stop = false;
inv = false;
while (!stop) {
expr * arg;
expr * neg_arg;
if (is_add(curr)) {
arg = to_app(curr)->get_arg(0);
curr = to_app(curr)->get_arg(1);
}
else {
arg = curr;
stop = true;
}
if (is_ground(arg)) {
TRACE("model_checker_bug", tout << "pushing:\n" << mk_pp(arg, m()) << "\n";);
args.push_back(arg);
}
else if (is_var(arg)) {
if (v != 0)
return false; // already found variable
v = to_var(arg);
}
else if (is_times_minus_one(arg, neg_arg) && is_var(neg_arg)) {
if (v != 0)
return false; // already found variable
v = to_var(neg_arg);
inv = true;
}
else {
return false; // non ground term.
}
}
if (v == 0)
return false; // did not find variable
SASSERT(!args.empty());
mk_add(args.size(), args.c_ptr(), t);
return true;
}

View file

@ -16,14 +16,14 @@ Author:
Revision History:
--*/
#include "ast/simplifier/pull_ite_tree.h"
#include "ast/rewriter/pull_ite_tree.h"
#include "ast/recurse_expr_def.h"
#include "ast/for_each_expr.h"
#include "ast/ast_pp.h"
pull_ite_tree::pull_ite_tree(ast_manager & m, simplifier & s):
pull_ite_tree::pull_ite_tree(ast_manager & m):
m_manager(m),
m_simplifier(s),
m_rewriter(m),
m_cache(m) {
}
@ -64,7 +64,7 @@ void pull_ite_tree::reduce(expr * n) {
get_cached(e_old, e, e_pr);
expr_ref r(m_manager);
expr * args[3] = {c, t, e};
m_simplifier.mk_app(to_app(n)->get_decl(), 3, args, r);
r = m_rewriter.mk_app(to_app(n)->get_decl(), 3, args);
if (!m_manager.proofs_enabled()) {
// expr * r = m_manager.mk_ite(c, t, e);
cache_result(n, r, 0);
@ -117,7 +117,7 @@ void pull_ite_tree::reduce(expr * n) {
else {
expr_ref r(m_manager);
m_args[m_arg_idx] = n;
m_simplifier.mk_app(m_p, m_args.size(), m_args.c_ptr(), r);
r = m_rewriter.mk_app(m_p, m_args.size(), m_args.c_ptr());
if (!m_manager.proofs_enabled()) {
// expr * r = m_manager.mk_app(m_p, m_args.size(), m_args.c_ptr());
cache_result(n, r, 0);
@ -179,23 +179,31 @@ void pull_ite_tree::operator()(app * n, app_ref & r, proof_ref & pr) {
m_todo.reset();
}
pull_ite_tree_star::pull_ite_tree_star(ast_manager & m, simplifier & s):
simplifier(m),
m_proc(m, s) {
borrow_plugins(s);
pull_ite_tree_cfg::pull_ite_tree_cfg(ast_manager & m):
m(m),
m_trail(m),
m_proc(m) {
}
bool pull_ite_tree_star::get_subst(expr * n, expr_ref & r, proof_ref & p) {
bool pull_ite_tree_cfg::get_subst(expr * n, expr* & r, proof* & p) {
if (is_app(n) && is_target(to_app(n))) {
app_ref tmp(m);
m_proc(to_app(n), tmp, p);
r = tmp;
return true;
proof_ref pr(m);
m_proc(to_app(n), tmp, pr);
if (tmp != n) {
r = tmp;
p = pr;
m_trail.push_back(r);
m_trail.push_back(p);
return true;
}
}
return false;
}
bool pull_cheap_ite_tree_star::is_target(app * n) const {
bool pull_cheap_ite_tree_cfg::is_target(app * n) const {
bool r =
n->get_num_args() == 2 &&
n->get_family_id() != null_family_id &&

View file

@ -20,10 +20,11 @@ Revision History:
#define PULL_ITE_TREE_H_
#include "ast/ast.h"
#include "ast/simplifier/simplifier.h"
#include "ast/rewriter/rewriter.h"
#include "ast/rewriter/th_rewriter.h"
#include "ast/expr_map.h"
#include "ast/recurse_expr.h"
#include "util/obj_hashtable.h"
#include "ast/expr_map.h"
/**
\brief Functor for applying the following transformation
@ -34,7 +35,7 @@ Revision History:
*/
class pull_ite_tree {
ast_manager & m_manager;
simplifier & m_simplifier;
th_rewriter m_rewriter;
func_decl * m_p;
ptr_vector<expr> m_args;
unsigned m_arg_idx; //!< position of the ite argument
@ -56,7 +57,7 @@ class pull_ite_tree {
return m_manager.mk_app(m_p, m_args.size(), m_args.c_ptr());
}
public:
pull_ite_tree(ast_manager & m, simplifier & s);
pull_ite_tree(ast_manager & m);
/**
\brief Apply the transformation above if n contains an ite-expression.
Store the result in r. If n does not contain an ite-expression, then
@ -71,14 +72,16 @@ public:
\brief Functor for applying the pull_ite_tree on subexpressions n that
satisfy the is_target virtual predicate.
*/
class pull_ite_tree_star : public simplifier {
class pull_ite_tree_cfg : public default_rewriter_cfg {
protected:
ast_manager& m;
expr_ref_vector m_trail;
pull_ite_tree m_proc;
virtual bool get_subst(expr * n, expr_ref & r, proof_ref & p);
public:
pull_ite_tree_star(ast_manager & m, simplifier & s);
virtual ~pull_ite_tree_star() { release_plugins(); }
pull_ite_tree_cfg(ast_manager & m);
virtual ~pull_ite_tree_cfg() {}
virtual bool is_target(app * n) const = 0;
bool get_subst(expr * n, expr* & r, proof* & p);
};
/**
@ -90,12 +93,21 @@ public:
- ite is an ite-term expression
- v is a value
*/
class pull_cheap_ite_tree_star : public pull_ite_tree_star {
class pull_cheap_ite_tree_cfg : public pull_ite_tree_cfg {
public:
pull_cheap_ite_tree_star(ast_manager & m, simplifier & s):pull_ite_tree_star(m, s) {}
virtual ~pull_cheap_ite_tree_star() {}
pull_cheap_ite_tree_cfg(ast_manager & m):pull_ite_tree_cfg(m) {}
virtual ~pull_cheap_ite_tree_cfg() {}
virtual bool is_target(app * n) const;
};
class pull_cheap_ite_tree_rw : public rewriter_tpl<pull_cheap_ite_tree_cfg> {
pull_cheap_ite_tree_cfg m_cfg;
public:
pull_cheap_ite_tree_rw(ast_manager& m):
rewriter_tpl<pull_cheap_ite_tree_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m)
{}
};
#endif /* PULL_ITE_TREE_H_ */

View file

@ -0,0 +1,91 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
push_app_ite.cpp
Abstract:
TODO: Write a better ite lifter
Author:
Leonardo de Moura (leonardo) 2008-05-14.
Revision History:
--*/
#include "ast/rewriter/push_app_ite.h"
#include "ast/ast_pp.h"
static int has_ite_arg(ast_manager& m, unsigned num_args, expr * const * args) {
for (unsigned i = 0; i < num_args; i++)
if (m.is_ite(args[i]))
return i;
return -1;
}
/**
\brief Default (conservative) implementation. Return true if there one and only one ite-term argument.
*/
bool push_app_ite_cfg::is_target(func_decl * decl, unsigned num_args, expr * const * args) {
if (m.is_ite(decl))
return false;
bool found_ite = false;
for (unsigned i = 0; i < num_args; i++) {
if (m.is_ite(args[i]) && !m.is_bool(args[i])) {
if (found_ite) {
if (m_conservative)
return false;
}
else {
found_ite = true;
}
}
}
CTRACE("push_app_ite", found_ite, tout << "found target for push app ite:\n";
tout << decl->get_name();
for (unsigned i = 0; i < num_args; i++) tout << " " << mk_pp(args[i], m);
tout << "\n";);
return found_ite;
}
br_status push_app_ite_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
if (!is_target(f, num, args)) {
return BR_FAILED;
}
int ite_arg_idx = has_ite_arg(m, num, args);
if (ite_arg_idx < 0) {
return BR_FAILED;
}
app * ite = to_app(args[ite_arg_idx]);
expr * c = 0, * t = 0, * e = 0;
VERIFY(m.is_ite(ite, c, t, e));
expr ** args_prime = const_cast<expr**>(args);
expr * old = args_prime[ite_arg_idx];
args_prime[ite_arg_idx] = t;
expr_ref t_new(m.mk_app(f, num, args_prime), m);
args_prime[ite_arg_idx] = e;
expr_ref e_new(m.mk_app(f, num, args_prime), m);
args_prime[ite_arg_idx] = old;
result = m.mk_ite(c, t_new, e_new);
TRACE("push_app_ite", tout << result << "\n";);
if (m.proofs_enabled()) {
result_pr = m.mk_rewrite(m.mk_app(f, num, args), result);
}
return BR_REWRITE2;
}
bool ng_push_app_ite_cfg::is_target(func_decl * decl, unsigned num_args, expr * const * args) {
bool r = push_app_ite_cfg::is_target(decl, num_args, args);
if (!r)
return false;
for (unsigned i = 0; i < num_args; i++)
if (!is_ground(args[i]))
return true;
return false;
}

View file

@ -0,0 +1,74 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
push_app_ite.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-05-14.
Revision History:
--*/
#ifndef PUSH_APP_ITE_H_
#define PUSH_APP_ITE_H_
#include "ast/ast.h"
#include "ast/rewriter/rewriter.h"
/**
\brief Functor for applying the following transformation:
(f s (ite c t1 t2)) ==> (ite c (f s t1) (f s t2))
*/
struct push_app_ite_cfg : public default_rewriter_cfg {
ast_manager& m;
bool m_conservative;
virtual bool is_target(func_decl * decl, unsigned num_args, expr * const * args);
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr);
push_app_ite_cfg(ast_manager& m, bool conservative = true): m(m), m_conservative(conservative) {}
bool rewrite_patterns() const { return false; }
};
/**
\brief Variation of push_app_ite that applies the transformation on nonground terms only.
\remark This functor uses the app::is_ground method. This method is not
completly precise, for instance, any term containing a quantifier is marked as non ground.
*/
class ng_push_app_ite_cfg : public push_app_ite_cfg {
protected:
virtual bool is_target(func_decl * decl, unsigned num_args, expr * const * args);
public:
ng_push_app_ite_cfg(ast_manager& m, bool conservative = true): push_app_ite_cfg(m, conservative) {}
virtual ~ng_push_app_ite_cfg() {}
};
struct push_app_ite_rw : public rewriter_tpl<push_app_ite_cfg> {
push_app_ite_cfg m_cfg;
public:
push_app_ite_rw(ast_manager& m, bool conservative = true):
rewriter_tpl<push_app_ite_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m, conservative)
{}
};
struct ng_push_app_ite_rw : public rewriter_tpl<ng_push_app_ite_cfg> {
ng_push_app_ite_cfg m_cfg;
public:
ng_push_app_ite_rw(ast_manager& m, bool conservative = true):
rewriter_tpl<ng_push_app_ite_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m, conservative)
{}
};
#endif /* PUSH_APP_ITE_H_ */

View file

@ -18,6 +18,7 @@ Notes:
--*/
#include "ast/rewriter/rewriter.h"
#include "ast/ast_smt2_pp.h"
#include "ast/ast_ll_pp.h"
template<typename Config>
template<bool ProofGen>
@ -259,10 +260,10 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
}
br_status st = m_cfg.reduce_app(f, new_num_args, new_args, m_r, m_pr2);
SASSERT(st != BR_DONE || m().get_sort(m_r) == m().get_sort(t));
TRACE("reduce_app",
tout << mk_ismt2_pp(t, m()) << "\n";
CTRACE("reduce_app", st != BR_FAILED,
tout << mk_bounded_pp(t, m()) << "\n";
tout << "st: " << st;
if (m_r) tout << " --->\n" << mk_ismt2_pp(m_r, m());
if (m_r) tout << " --->\n" << mk_bounded_pp(m_r, m());
tout << "\n";);
if (st != BR_FAILED) {
result_stack().shrink(fr.m_spos);
@ -496,6 +497,7 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
expr * const * new_pats;
expr * const * new_no_pats;
if (rewrite_patterns()) {
TRACE("reduce_quantifier_bug", tout << "rewrite patterns\n";);
new_pats = it + 1;
new_no_pats = new_pats + q->get_num_patterns();
}
@ -518,7 +520,7 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
}
else {
expr_ref tmp(m());
TRACE("reduce_quantifier_bug", tout << mk_ismt2_pp(q, m()) << " " << mk_ismt2_pp(new_body, m()) << "\n";);
if (!m_cfg.reduce_quantifier(q, new_body, new_pats, new_no_pats, m_r, m_pr)) {
if (fr.m_new_child) {
m_r = m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_body);

View file

@ -9,5 +9,6 @@ def_module_params('rewriter',
("pull_cheap_ite", BOOL, False, "pull if-then-else terms when cheap."),
("bv_ineq_consistency_test_max", UINT, 0, "max size of conjunctions on which to perform consistency test based on inequalities on bitvectors."),
("cache_all", BOOL, False, "cache all intermediate results."),
("rewrite_patterns", BOOL, False, "rewrite patterns."),
("ignore_patterns_on_ground_qbody", BOOL, True, "ignores patterns on quantifiers that don't mention their bound variables.")))

View file

@ -26,6 +26,7 @@ Notes:
#include "math/automata/automaton.h"
#include "ast/well_sorted.h"
#include "ast/rewriter/var_subst.h"
#include "ast/rewriter/bool_rewriter.h"
#include "math/automata/symbolic_automata_def.h"
@ -102,7 +103,6 @@ public:
return sym_expr::mk_pred(fml, x->get_sort());
}
}
sort* s = x->get_sort();
if (m.is_bool(s)) s = y->get_sort();
var_ref v(m.mk_var(0, s), m);
@ -112,7 +112,10 @@ public:
return y;
}
if (m.is_true(fml2)) return x;
expr_ref fml(m.mk_and(fml1, fml2), m);
if (fml1 == fml2) return x;
bool_rewriter br(m);
expr_ref fml(m);
br.mk_and(fml1, fml2, fml);
return sym_expr::mk_pred(fml, x->get_sort());
}
virtual T mk_or(T x, T y) {
@ -120,12 +123,15 @@ public:
x->get_char() == y->get_char()) {
return x;
}
if (x == y) return x;
var_ref v(m.mk_var(0, x->get_sort()), m);
expr_ref fml1 = x->accept(v);
expr_ref fml2 = y->accept(v);
if (m.is_false(fml1)) return y;
if (m.is_false(fml2)) return x;
expr_ref fml(m.mk_or(fml1, fml2), m);
bool_rewriter br(m);
expr_ref fml(m);
br.mk_or(fml1, fml2, fml);
return sym_expr::mk_pred(fml, x->get_sort());
}
@ -197,10 +203,10 @@ void re2automaton::set_solver(expr_solver* solver) {
eautomaton* re2automaton::operator()(expr* e) {
eautomaton* r = re2aut(e);
if (r) {
display_expr1 disp(m);
if (r) {
r->compress();
TRACE("seq", r->display(tout, disp););
bool_rewriter br(m);
TRACE("seq", display_expr1 disp(m); r->display(tout, disp););
}
return r;
}

View file

@ -55,6 +55,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
bool m_push_ite_arith;
bool m_push_ite_bv;
bool m_ignore_patterns_on_ground_qbody;
bool m_rewrite_patterns;
// substitution support
expr_dependency_ref m_used_dependencies; // set of dependencies of used substitutions
@ -72,6 +73,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
m_push_ite_arith = p.push_ite_arith();
m_push_ite_bv = p.push_ite_bv();
m_ignore_patterns_on_ground_qbody = p.ignore_patterns_on_ground_qbody();
m_rewrite_patterns = p.rewrite_patterns();
}
void updt_params(params_ref const & p) {
@ -99,7 +101,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
return false;
}
bool rewrite_patterns() const { return false; }
bool rewrite_patterns() const { return m_rewrite_patterns; }
bool cache_all_results() const { return m_cache_all; }
@ -734,6 +736,7 @@ ast_manager & th_rewriter::m() const {
void th_rewriter::updt_params(params_ref const & p) {
m_params = p;
m_imp->cfg().updt_params(p);
IF_VERBOSE(10, verbose_stream() << p << "\n";);
}
void th_rewriter::get_param_descrs(param_descrs & r) {

View file

@ -1,29 +0,0 @@
z3_add_component(simplifier
SOURCES
arith_simplifier_params.cpp
arith_simplifier_plugin.cpp
array_simplifier_params.cpp
array_simplifier_plugin.cpp
basic_simplifier_plugin.cpp
bit2int.cpp
bv_elim.cpp
bv_simplifier_params.cpp
bv_simplifier_plugin.cpp
datatype_simplifier_plugin.cpp
elim_bounds.cpp
fpa_simplifier_plugin.cpp
inj_axiom.cpp
maximise_ac_sharing.cpp
poly_simplifier_plugin.cpp
pull_ite_tree.cpp
push_app_ite.cpp
seq_simplifier_plugin.cpp
simplifier.cpp
simplifier_plugin.cpp
COMPONENT_DEPENDENCIES
rewriter
PYG_FILES
arith_simplifier_params_helper.pyg
array_simplifier_params_helper.pyg
bv_simplifier_params_helper.pyg
)

View file

@ -1,2 +0,0 @@
Simplifier module is now obsolete.
It is still being used in many places, but we will eventually replace all occurrences with the new rewriter module.

View file

@ -1,33 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
arith_simplifier_params.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2012-12-02.
Revision History:
--*/
#include "ast/simplifier/arith_simplifier_params.h"
#include "ast/simplifier/arith_simplifier_params_helper.hpp"
void arith_simplifier_params::updt_params(params_ref const & _p) {
arith_simplifier_params_helper p(_p);
m_arith_expand_eqs = p.arith_expand_eqs();
m_arith_process_all_eqs = p.arith_process_all_eqs();
}
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
void arith_simplifier_params::display(std::ostream & out) const {
DISPLAY_PARAM(m_arith_expand_eqs);
DISPLAY_PARAM(m_arith_process_all_eqs);
}

View file

@ -1,38 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
arith_simplifier_params.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-05-09.
Revision History:
--*/
#ifndef ARITH_SIMPLIFIER_PARAMS_H_
#define ARITH_SIMPLIFIER_PARAMS_H_
#include "util/params.h"
struct arith_simplifier_params {
bool m_arith_expand_eqs;
bool m_arith_process_all_eqs;
arith_simplifier_params(params_ref const & p = params_ref()) {
updt_params(p);
}
void updt_params(params_ref const & _p);
void display(std::ostream & out) const;
};
#endif /* ARITH_SIMPLIFIER_PARAMS_H_ */

View file

@ -1,7 +0,0 @@
def_module_params(class_name='arith_simplifier_params_helper',
module_name="old_simplify", # Parameters will be in the old_simplify module
description="old simplification (stack) still used in the smt module",
export=True,
params=(
('arith.expand_eqs', BOOL, False, 'expand equalities into two inequalities'),
('arith.process_all_eqs', BOOL, False, 'put all equations in the form (= t c), where c is a numeral')))

View file

@ -1,468 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
arith_simplifier_plugin.cpp
Abstract:
Simplifier for the arithmetic family.
Author:
Leonardo (leonardo) 2008-01-08
--*/
#include "ast/simplifier/arith_simplifier_plugin.h"
#include "ast/ast_pp.h"
#include "ast/ast_ll_pp.h"
#include "ast/ast_smt2_pp.h"
arith_simplifier_plugin::~arith_simplifier_plugin() {
}
arith_simplifier_plugin::arith_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, arith_simplifier_params & p):
poly_simplifier_plugin(symbol("arith"), m, OP_ADD, OP_MUL, OP_UMINUS, OP_SUB, OP_NUM),
m_params(p),
m_util(m),
m_bsimp(b),
m_int_zero(m),
m_real_zero(m) {
m_int_zero = m_util.mk_numeral(rational(0), true);
m_real_zero = m_util.mk_numeral(rational(0), false);
}
/**
\brief Return true if the first monomial of t is negative.
*/
bool arith_simplifier_plugin::is_neg_poly(expr * t) const {
if (m_util.is_add(t)) {
t = to_app(t)->get_arg(0);
}
if (m_util.is_mul(t)) {
t = to_app(t)->get_arg(0);
rational r;
if (is_numeral(t, r))
return r.is_neg();
}
return false;
}
void arith_simplifier_plugin::get_monomial_gcd(expr_ref_vector& monomials, numeral& g) {
g = numeral::zero();
numeral n;
for (unsigned i = 0; !g.is_one() && i < monomials.size(); ++i) {
expr* e = monomials[i].get();
if (is_numeral(e, n)) {
g = gcd(abs(n), g);
}
else if (is_mul(e) && is_numeral(to_app(e)->get_arg(0), n)) {
g = gcd(abs(n), g);
}
else {
g = numeral::one();
return;
}
}
if (g.is_zero()) {
g = numeral::one();
}
}
void arith_simplifier_plugin::div_monomial(expr_ref_vector& monomials, numeral const& g) {
numeral n;
for (unsigned i = 0; i < monomials.size(); ++i) {
expr* e = monomials[i].get();
if (is_numeral(e, n)) {
SASSERT((n/g).is_int());
monomials[i] = mk_numeral(n/g);
}
else if (is_mul(e) && is_numeral(to_app(e)->get_arg(0), n)) {
SASSERT((n/g).is_int());
monomials[i] = mk_mul(n/g, to_app(e)->get_arg(1));
}
else {
UNREACHABLE();
}
}
}
void arith_simplifier_plugin::gcd_reduce_monomial(expr_ref_vector& monomials, numeral& k) {
numeral g, n;
get_monomial_gcd(monomials, g);
g = gcd(abs(k), g);
if (g.is_one()) {
return;
}
SASSERT(g.is_pos());
k = k / g;
div_monomial(monomials, g);
}
template<arith_simplifier_plugin::op_kind Kind>
void arith_simplifier_plugin::mk_le_ge_eq_core(expr * arg1, expr * arg2, expr_ref & result) {
set_curr_sort(arg1);
bool is_int = m_curr_sort->get_decl_kind() == INT_SORT;
expr_ref_vector monomials(m_manager);
rational k;
TRACE("arith_eq_bug", tout << mk_ismt2_pp(arg1, m_manager) << "\n" << mk_ismt2_pp(arg2, m_manager) << "\n";);
process_sum_of_monomials(false, arg1, monomials, k);
process_sum_of_monomials(true, arg2, monomials, k);
k.neg();
if (is_int) {
numeral g;
get_monomial_gcd(monomials, g);
if (!g.is_one()) {
div_monomial(monomials, g);
switch(Kind) {
case LE:
//
// g*monmials' <= k
// <=>
// monomials' <= floor(k/g)
//
k = floor(k/g);
break;
case GE:
//
// g*monmials' >= k
// <=>
// monomials' >= ceil(k/g)
//
k = ceil(k/g);
break;
case EQ:
k = k/g;
if (!k.is_int()) {
result = m_manager.mk_false();
return;
}
break;
}
}
}
expr_ref lhs(m_manager);
mk_sum_of_monomials(monomials, lhs);
if (m_util.is_numeral(lhs)) {
SASSERT(lhs == mk_zero());
if (( Kind == LE && numeral::zero() <= k) ||
( Kind == GE && numeral::zero() >= k) ||
( Kind == EQ && numeral::zero() == k))
result = m_manager.mk_true();
else
result = m_manager.mk_false();
}
else {
if (is_neg_poly(lhs)) {
expr_ref neg_lhs(m_manager);
mk_uminus(lhs, neg_lhs);
lhs = neg_lhs;
k.neg();
expr * rhs = m_util.mk_numeral(k, is_int);
switch (Kind) {
case LE:
result = m_util.mk_ge(lhs, rhs);
break;
case GE:
result = m_util.mk_le(lhs, rhs);
break;
case EQ:
result = m_manager.mk_eq(lhs, rhs);
break;
}
}
else {
expr * rhs = m_util.mk_numeral(k, is_int);
switch (Kind) {
case LE:
result = m_util.mk_le(lhs, rhs);
break;
case GE:
result = m_util.mk_ge(lhs, rhs);
break;
case EQ:
result = m_manager.mk_eq(lhs, rhs);
break;
}
}
}
}
void arith_simplifier_plugin::mk_arith_eq(expr * arg1, expr * arg2, expr_ref & result) {
mk_le_ge_eq_core<EQ>(arg1, arg2, result);
}
void arith_simplifier_plugin::mk_le(expr * arg1, expr * arg2, expr_ref & result) {
mk_le_ge_eq_core<LE>(arg1, arg2, result);
}
void arith_simplifier_plugin::mk_ge(expr * arg1, expr * arg2, expr_ref & result) {
mk_le_ge_eq_core<GE>(arg1, arg2, result);
}
void arith_simplifier_plugin::mk_lt(expr * arg1, expr * arg2, expr_ref & result) {
expr_ref tmp(m_manager);
mk_le(arg2, arg1, tmp);
m_bsimp.mk_not(tmp, result);
}
void arith_simplifier_plugin::mk_gt(expr * arg1, expr * arg2, expr_ref & result) {
expr_ref tmp(m_manager);
mk_le(arg1, arg2, tmp);
m_bsimp.mk_not(tmp, result);
}
void arith_simplifier_plugin::gcd_normalize(numeral & coeff, expr_ref& term) {
if (!abs(coeff).is_one()) {
set_curr_sort(term);
SASSERT(m_curr_sort->get_decl_kind() == INT_SORT);
expr_ref_vector monomials(m_manager);
rational k;
monomials.push_back(mk_numeral(numeral(coeff), true));
process_sum_of_monomials(false, term, monomials, k);
gcd_reduce_monomial(monomials, k);
numeral coeff1;
if (!is_numeral(monomials[0].get(), coeff1)) {
UNREACHABLE();
}
if (coeff1 == coeff) {
return;
}
monomials[0] = mk_numeral(k, true);
coeff = coeff1;
mk_sum_of_monomials(monomials, term);
}
}
void arith_simplifier_plugin::mk_div(expr * arg1, expr * arg2, expr_ref & result) {
set_curr_sort(arg1);
numeral v1, v2;
bool is_int;
if (m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) {
SASSERT(!is_int);
if (m_util.is_numeral(arg1, v1, is_int))
result = m_util.mk_numeral(v1/v2, false);
else {
numeral k(1);
k /= v2;
expr_ref inv_arg2(m_util.mk_numeral(k, false), m_manager);
mk_mul(inv_arg2, arg1, result);
}
}
else
result = m_util.mk_div(arg1, arg2);
}
void arith_simplifier_plugin::mk_idiv(expr * arg1, expr * arg2, expr_ref & result) {
set_curr_sort(arg1);
numeral v1, v2;
bool is_int;
if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero())
result = m_util.mk_numeral(div(v1, v2), is_int);
else
result = m_util.mk_idiv(arg1, arg2);
}
void arith_simplifier_plugin::prop_mod_const(expr * e, unsigned depth, numeral const& k, expr_ref& result) {
SASSERT(m_util.is_int(e));
SASSERT(k.is_int() && k.is_pos());
numeral n;
bool is_int;
if (depth == 0) {
result = e;
}
else if (is_add(e) || is_mul(e)) {
expr_ref_vector args(m_manager);
expr_ref tmp(m_manager);
app* a = to_app(e);
for (unsigned i = 0; i < a->get_num_args(); ++i) {
prop_mod_const(a->get_arg(i), depth - 1, k, tmp);
args.push_back(tmp);
}
reduce(a->get_decl(), args.size(), args.c_ptr(), result);
}
else if (m_util.is_numeral(e, n, is_int) && is_int) {
result = mk_numeral(mod(n, k), true);
}
else {
result = e;
}
}
void arith_simplifier_plugin::mk_mod(expr * arg1, expr * arg2, expr_ref & result) {
set_curr_sort(arg1);
numeral v1, v2;
bool is_int;
if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) {
result = m_util.mk_numeral(mod(v1, v2), is_int);
}
else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_one()) {
result = m_util.mk_numeral(numeral(0), true);
}
else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_pos()) {
expr_ref tmp(m_manager);
prop_mod_const(arg1, 5, v2, tmp);
result = m_util.mk_mod(tmp, arg2);
}
else {
result = m_util.mk_mod(arg1, arg2);
}
}
void arith_simplifier_plugin::mk_rem(expr * arg1, expr * arg2, expr_ref & result) {
set_curr_sort(arg1);
numeral v1, v2;
bool is_int;
if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) {
numeral m = mod(v1, v2);
//
// rem(v1,v2) = if v2 >= 0 then mod(v1,v2) else -mod(v1,v2)
//
if (v2.is_neg()) {
m.neg();
}
result = m_util.mk_numeral(m, is_int);
}
else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_one()) {
result = m_util.mk_numeral(numeral(0), true);
}
else if (m_util.is_numeral(arg2, v2, is_int) && is_int && !v2.is_zero()) {
expr_ref tmp(m_manager);
prop_mod_const(arg1, 5, v2, tmp);
result = m_util.mk_mod(tmp, arg2);
if (v2.is_neg()) {
result = m_util.mk_uminus(result);
}
}
else {
result = m_util.mk_rem(arg1, arg2);
}
}
void arith_simplifier_plugin::mk_to_real(expr * arg, expr_ref & result) {
numeral v;
if (m_util.is_numeral(arg, v))
result = m_util.mk_numeral(v, false);
else
result = m_util.mk_to_real(arg);
}
void arith_simplifier_plugin::mk_to_int(expr * arg, expr_ref & result) {
numeral v;
if (m_util.is_numeral(arg, v))
result = m_util.mk_numeral(floor(v), true);
else if (m_util.is_to_real(arg))
result = to_app(arg)->get_arg(0);
else
result = m_util.mk_to_int(arg);
}
void arith_simplifier_plugin::mk_is_int(expr * arg, expr_ref & result) {
numeral v;
if (m_util.is_numeral(arg, v))
result = v.is_int()?m_manager.mk_true():m_manager.mk_false();
else if (m_util.is_to_real(arg))
result = m_manager.mk_true();
else
result = m_util.mk_is_int(arg);
}
bool arith_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
set_reduce_invoked();
SASSERT(f->get_family_id() == m_fid);
TRACE("arith_simplifier_plugin", tout << mk_pp(f, m_manager) << "\n";
for (unsigned i = 0; i < num_args; i++) tout << mk_pp(args[i], m_manager) << "\n";);
arith_op_kind k = static_cast<arith_op_kind>(f->get_decl_kind());
switch (k) {
case OP_NUM: return false;
case OP_LE: if (m_presimp) return false; SASSERT(num_args == 2); mk_le(args[0], args[1], result); break;
case OP_GE: if (m_presimp) return false; SASSERT(num_args == 2); mk_ge(args[0], args[1], result); break;
case OP_LT: if (m_presimp) return false; SASSERT(num_args == 2); mk_lt(args[0], args[1], result); break;
case OP_GT: if (m_presimp) return false; SASSERT(num_args == 2); mk_gt(args[0], args[1], result); break;
case OP_ADD: mk_add(num_args, args, result); break;
case OP_SUB: mk_sub(num_args, args, result); break;
case OP_UMINUS: SASSERT(num_args == 1); mk_uminus(args[0], result); break;
case OP_MUL:
mk_mul(num_args, args, result);
TRACE("arith_simplifier_plugin", tout << mk_pp(result, m_manager) << "\n";);
break;
case OP_DIV: SASSERT(num_args == 2); mk_div(args[0], args[1], result); break;
case OP_IDIV: SASSERT(num_args == 2); mk_idiv(args[0], args[1], result); break;
case OP_REM: SASSERT(num_args == 2); mk_rem(args[0], args[1], result); break;
case OP_MOD: SASSERT(num_args == 2); mk_mod(args[0], args[1], result); break;
case OP_TO_REAL: SASSERT(num_args == 1); mk_to_real(args[0], result); break;
case OP_TO_INT: SASSERT(num_args == 1); mk_to_int(args[0], result); break;
case OP_IS_INT: SASSERT(num_args == 1); mk_is_int(args[0], result); break;
case OP_POWER: SASSERT(num_args == 2); mk_power(args[0], args[1], result); break;
case OP_ABS: SASSERT(num_args == 1); mk_abs(args[0], result); break;
case OP_IRRATIONAL_ALGEBRAIC_NUM: return false;
default:
return false;
}
TRACE("arith_simplifier_plugin", tout << mk_pp(result.get(), m_manager) << "\n";);
return true;
}
void arith_simplifier_plugin::mk_power(expr* x, expr* y, expr_ref& result) {
rational a, b;
if (is_numeral(y, b) && b.is_one()) {
result = x;
return;
}
if (is_numeral(x, a) && is_numeral(y, b) && b.is_unsigned()) {
if (b.is_zero() && !a.is_zero()) {
result = m_util.mk_numeral(rational(1), m_manager.get_sort(x));
return;
}
if (!b.is_zero()) {
result = m_util.mk_numeral(power(a, b.get_unsigned()), m_manager.get_sort(x));
return;
}
}
result = m_util.mk_power(x, y);
}
void arith_simplifier_plugin::mk_abs(expr * arg, expr_ref & result) {
expr_ref c(m_manager);
expr_ref m_arg(m_manager);
mk_uminus(arg, m_arg);
mk_ge(arg, m_util.mk_numeral(rational(0), m_util.is_int(arg)), c);
m_bsimp.mk_ite(c, arg, m_arg, result);
}
bool arith_simplifier_plugin::is_arith_term(expr * n) const {
return n->get_kind() == AST_APP && to_app(n)->get_family_id() == m_fid;
}
bool arith_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) {
TRACE("reduce_eq_bug", tout << mk_ismt2_pp(lhs, m_manager) << "\n" << mk_ismt2_pp(rhs, m_manager) << "\n";);
set_reduce_invoked();
if (m_presimp) {
return false;
}
if (m_params.m_arith_expand_eqs) {
expr_ref le(m_manager), ge(m_manager);
mk_le_ge_eq_core<LE>(lhs, rhs, le);
mk_le_ge_eq_core<GE>(lhs, rhs, ge);
m_bsimp.mk_and(le, ge, result);
return true;
}
if (m_params.m_arith_process_all_eqs || is_arith_term(lhs) || is_arith_term(rhs)) {
mk_arith_eq(lhs, rhs, result);
return true;
}
return false;
}

View file

@ -1,97 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
arith_simplifier_plugin.h
Abstract:
Simplifier for the arithmetic family.
Author:
Leonardo (leonardo) 2008-01-08
--*/
#ifndef ARITH_SIMPLIFIER_PLUGIN_H_
#define ARITH_SIMPLIFIER_PLUGIN_H_
#include "ast/simplifier/basic_simplifier_plugin.h"
#include "ast/simplifier/poly_simplifier_plugin.h"
#include "ast/arith_decl_plugin.h"
#include "ast/simplifier/arith_simplifier_params.h"
/**
\brief Simplifier for the arith family.
*/
class arith_simplifier_plugin : public poly_simplifier_plugin {
public:
enum op_kind {
LE, GE, EQ
};
protected:
arith_simplifier_params & m_params;
arith_util m_util;
basic_simplifier_plugin & m_bsimp;
expr_ref m_int_zero;
expr_ref m_real_zero;
bool is_neg_poly(expr * t) const;
template<op_kind k>
void mk_le_ge_eq_core(expr * arg1, expr * arg2, expr_ref & result);
void prop_mod_const(expr * e, unsigned depth, numeral const& k, expr_ref& result);
void gcd_reduce_monomial(expr_ref_vector& monomials, numeral& k);
void div_monomial(expr_ref_vector& monomials, numeral const& g);
void get_monomial_gcd(expr_ref_vector& monomials, numeral& g);
public:
arith_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, arith_simplifier_params & p);
~arith_simplifier_plugin();
arith_util & get_arith_util() { return m_util; }
virtual numeral norm(const numeral & n) { return n; }
virtual bool is_numeral(expr * n, rational & val) const { bool f; return m_util.is_numeral(n, val, f); }
bool is_numeral(expr * n) const { return m_util.is_numeral(n); }
virtual bool is_minus_one(expr * n) const { numeral tmp; return is_numeral(n, tmp) && tmp.is_minus_one(); }
virtual expr * get_zero(sort * s) const { return m_util.is_int(s) ? m_int_zero.get() : m_real_zero.get(); }
virtual app * mk_numeral(numeral const & n) { return m_util.mk_numeral(n, m_curr_sort->get_decl_kind() == INT_SORT); }
app * mk_numeral(numeral const & n, bool is_int) { return m_util.mk_numeral(n, is_int); }
bool is_int_sort(sort const * s) const { return m_util.is_int(s); }
bool is_real_sort(sort const * s) const { return m_util.is_real(s); }
bool is_arith_sort(sort const * s) const { return is_int_sort(s) || is_real_sort(s); }
bool is_int(expr const * n) const { return m_util.is_int(n); }
bool is_le(expr const * n) const { return m_util.is_le(n); }
bool is_ge(expr const * n) const { return m_util.is_ge(n); }
virtual bool is_le_ge(expr * n) const { return is_le(n) || is_ge(n); }
void mk_le(expr * arg1, expr * arg2, expr_ref & result);
void mk_ge(expr * arg1, expr * arg2, expr_ref & result);
void mk_lt(expr * arg1, expr * arg2, expr_ref & result);
void mk_gt(expr * arg1, expr * arg2, expr_ref & result);
void mk_arith_eq(expr * arg1, expr * arg2, expr_ref & result);
void mk_div(expr * arg1, expr * arg2, expr_ref & result);
void mk_idiv(expr * arg1, expr * arg2, expr_ref & result);
void mk_mod(expr * arg1, expr * arg2, expr_ref & result);
void mk_rem(expr * arg1, expr * arg2, expr_ref & result);
void mk_to_real(expr * arg, expr_ref & result);
void mk_to_int(expr * arg, expr_ref & result);
void mk_is_int(expr * arg, expr_ref & result);
void mk_power(expr* x, expr* y, expr_ref& result);
void mk_abs(expr * arg, expr_ref & result);
virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result);
bool is_arith_term(expr * n) const;
void gcd_normalize(numeral & coeff, expr_ref& term);
};
#endif /* ARITH_SIMPLIFIER_PLUGIN_H_ */

View file

@ -1,26 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
array_simplifier_params.cpp
Abstract:
This file was created during code reorg.
Author:
Leonardo de Moura (leonardo) 2012-12-02.
Revision History:
--*/
#include "ast/simplifier/array_simplifier_params.h"
#include "ast/simplifier/array_simplifier_params_helper.hpp"
void array_simplifier_params::updt_params(params_ref const & _p) {
array_simplifier_params_helper p(_p);
m_array_canonize_simplify = p.array_canonize();
m_array_simplify = p.array_simplify();
}

View file

@ -1,36 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
array_simplifier_params.h
Abstract:
This file was created during code reorg.
Author:
Leonardo de Moura (leonardo) 2012-12-02.
Revision History:
--*/
#ifndef ARRAY_SIMPLIFIER_PARAMS_H_
#define ARRAY_SIMPLIFIER_PARAMS_H_
#include "util/params.h"
struct array_simplifier_params {
bool m_array_canonize_simplify;
bool m_array_simplify; // temporary hack for disabling array simplifier plugin.
array_simplifier_params(params_ref const & p = params_ref()) {
updt_params(p);
}
void updt_params(params_ref const & _p);
};
#endif /* ARITH_SIMPLIFIER_PARAMS_H_ */

View file

@ -1,6 +0,0 @@
def_module_params(class_name='array_simplifier_params_helper',
module_name="old_simplify", # Parameters will be in the old_simplify module
export=True,
params=(
('array.canonize', BOOL, False, 'normalize array terms into normal form during simplification'),
('array.simplify', BOOL, True, 'enable/disable array simplifications')))

View file

@ -1,877 +0,0 @@
/*++
Copyright (c) 2008 Microsoft Corporation
Module Name:
array_simplifier_plugin.cpp
Abstract:
<abstract>
Author:
Nikolaj Bjorner (nbjorner) 2008-05-05
Revision History:
Notes TODO:
Examine quadratic cost of simplification vs. model-based procedure.
Parameterize cache replacement strategy.
Some parameters are hard-wired.
--*/
#include "ast/simplifier/array_simplifier_plugin.h"
#include "ast/ast_ll_pp.h"
#include "ast/ast_pp.h"
array_simplifier_plugin::array_simplifier_plugin(
ast_manager & m,
basic_simplifier_plugin& s,
simplifier& simp,
array_simplifier_params const& p) :
simplifier_plugin(symbol("array"),m),
m_util(m),
m_simp(s),
m_simplifier(simp),
m_params(p),
m_store_cache_size(0)
{}
array_simplifier_plugin::~array_simplifier_plugin() {
select_cache::iterator it = m_select_cache.begin();
select_cache::iterator end = m_select_cache.end();
for ( ; it != end; ++it) {
m_manager.dec_array_ref(it->m_key->size(), it->m_key->c_ptr());
m_manager.dec_ref(it->m_value);
dealloc(it->m_key);
}
store_cache::iterator it2 = m_store_cache.begin();
store_cache::iterator end2 = m_store_cache.end();
for (; it2 != end2; ++it2) {
m_manager.dec_ref(it->m_value);
dealloc(it->m_key);
}
}
bool array_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
if (!m_params.m_array_simplify)
return false;
set_reduce_invoked();
if (m_presimp)
return false;
#if Z3DEBUG
for (unsigned i = 0; i < num_args && i < f->get_arity(); ++i) {
SASSERT(m_manager.get_sort(args[i]) == f->get_domain(i));
}
#endif
TRACE("array_simplifier", {
tout << mk_pp(f, m_manager) << " ";
for (unsigned i = 0; i < num_args; ++i) {
tout << mk_pp(args[i], m_manager) << " ";
}
tout << "\n";
}
);
SASSERT(f->get_family_id() == m_fid);
switch(f->get_decl_kind()) {
case OP_SELECT:
mk_select(num_args, args, result);
break;
case OP_STORE:
mk_store(f, num_args, args, result);
break;
case OP_SET_UNION: {
sort* s = f->get_range();
expr_ref empty(m_manager);
mk_empty_set(s, empty);
switch(num_args) {
case 0:
result = empty;
break;
case 1:
result = args[0];
break;
default: {
result = args[0];
func_decl* f_or = m_manager.mk_or_decl();
for (unsigned i = 1; i < num_args; ++i) {
mk_map(f_or, result, args[i], result);
}
break;
}
}
break;
}
case OP_SET_INTERSECT: {
expr_ref full(m_manager);
mk_full_set(f->get_range(), full);
switch(num_args) {
case 0:
result = full;
break;
case 1:
result = args[0];
break;
default: {
result = args[0];
func_decl* f_and = m_manager.mk_and_decl();
for (unsigned i = 1; i < num_args; ++i) {
mk_map(f_and, result, args[i], result);
}
break;
}
}
TRACE("array_simplifier", tout << "sort " << mk_pp(result.get(), m_manager) << "\n";);
break;
}
case OP_SET_SUBSET: {
SASSERT(num_args == 2);
expr_ref diff(m_manager), emp(m_manager);
mk_set_difference(num_args, args, diff);
mk_empty_set(m_manager.get_sort(args[0]), emp);
m_simp.mk_eq(diff.get(), emp.get(), result);
break;
}
case OP_SET_COMPLEMENT: {
SASSERT(num_args == 1);
func_decl* f_not = m_manager.mk_not_decl();
mk_map(f_not, args[0], result);
break;
}
case OP_SET_DIFFERENCE: {
SASSERT(num_args == 2);
expr_ref r1(m_manager);
mk_map(m_manager.mk_not_decl(), args[1], r1);
mk_map(m_manager.mk_and_decl(), args[0], r1, result);
break;
}
case OP_ARRAY_MAP: {
SASSERT(f->get_num_parameters() == 1);
SASSERT(f->get_parameter(0).is_ast());
SASSERT(is_func_decl(f->get_parameter(0).get_ast()));
//
// map_d (store a j v) = (store (map_f a) v (d v))
//
if (num_args == 1 && is_store(args[0])) {
app* store_expr = to_app(args[0]);
unsigned num_args = store_expr->get_num_args();
SASSERT(num_args >= 3);
parameter p = f->get_parameter(0);
func_decl* d = to_func_decl(p.get_ast());
expr* a = store_expr->get_arg(0);
expr* v = store_expr->get_arg(num_args-1);
// expr*const* args = store_expr->get_args()+1;
expr_ref r1(m_manager), r2(m_manager);
ptr_vector<expr> new_args;
reduce(f, 1, &a, r1);
m_simplifier.mk_app(d, 1, &v, r2);
new_args.push_back(r1);
for (unsigned i = 1; i + 1 < num_args; ++i) {
new_args.push_back(store_expr->get_arg(i));
}
new_args.push_back(r2);
mk_store(store_expr->get_decl(), num_args, new_args.c_ptr(), result);
break;
}
//
// map_d (store a j v) (store b j w) = (store (map_f a b) j (d v w))
//
if (num_args > 1 && same_store(num_args, args)) {
app* store_expr1 = to_app(args[0]);
unsigned num_indices = store_expr1->get_num_args();
SASSERT(num_indices >= 3);
parameter p = f->get_parameter(0);
func_decl* d = to_func_decl(p.get_ast());
ptr_vector<expr> arrays;
ptr_vector<expr> values;
for (unsigned i = 0; i < num_args; ++i) {
arrays.push_back(to_app(args[i])->get_arg(0));
values.push_back(to_app(args[i])->get_arg(num_indices-1));
}
expr_ref r1(m_manager), r2(m_manager);
reduce(f, arrays.size(), arrays.c_ptr(), r1);
m_simplifier.mk_app(d, values.size(), values.c_ptr(), r2);
ptr_vector<expr> new_args;
new_args.push_back(r1);
for (unsigned i = 1; i + 1 < num_indices; ++i) {
new_args.push_back(store_expr1->get_arg(i));
}
new_args.push_back(r2);
mk_store(store_expr1->get_decl(), new_args.size(), new_args.c_ptr(), result);
break;
}
//
// map_d (const v) = (const (d v))
//
if (num_args == 1 && is_const_array(args[0])) {
app* const_expr = to_app(args[0]);
SASSERT(const_expr->get_num_args() == 1);
parameter p = f->get_parameter(0);
func_decl* d = to_func_decl(p.get_ast());
expr* v = const_expr->get_arg(0);
expr_ref r1(m_manager);
m_simplifier.mk_app(d, 1, &v, r1);
expr* arg = r1.get();
parameter param(f->get_range());
result = m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, &param, 1, &arg);
break;
}
//
// map_d (const v) (const w) = (const (d v w))
//
if (num_args > 1 && all_const_array(num_args, args)) {
parameter p = f->get_parameter(0);
func_decl* d = to_func_decl(p.get_ast());
ptr_vector<expr> values;
for (unsigned i = 0; i < num_args; ++i) {
values.push_back(to_app(args[i])->get_arg(0));
}
expr_ref r1(m_manager);
m_simplifier.mk_app(d, values.size(), values.c_ptr(), r1);
expr* arg = r1.get();
parameter param(f->get_range());
result = m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, &param, 1, &arg);
break;
}
result = m_manager.mk_app(f, num_args, args);
break;
}
default:
result = m_manager.mk_app(f, num_args, args);
break;
}
TRACE("array_simplifier",
tout << mk_pp(result.get(), m_manager) << "\n";);
return true;
}
bool array_simplifier_plugin::same_store(unsigned num_args, expr* const* args) const {
if (num_args == 0) {
return true;
}
if (!is_store(args[0])) {
return false;
}
SASSERT(to_app(args[0])->get_num_args() >= 3);
unsigned num_indices = to_app(args[0])->get_num_args() - 2;
for (unsigned i = 1; i < num_args; ++i) {
if (!is_store(args[i])) {
return false;
}
for (unsigned j = 1; j < num_indices + 1; ++j) {
if (to_app(args[0])->get_arg(j) != to_app(args[i])->get_arg(j)) {
return false;
}
}
}
return true;
}
bool array_simplifier_plugin::all_const_array(unsigned num_args, expr* const* args) const {
bool is_const = true;
for (unsigned i = 0; is_const && i < num_args; ++i) {
is_const = is_const_array(args[i]);
}
return is_const;
}
bool array_simplifier_plugin::all_values(unsigned num_args, expr* const* args) const {
for (unsigned i = 0; i < num_args; ++i) {
if (!m_manager.is_unique_value(args[i])) {
return false;
}
}
return true;
}
bool array_simplifier_plugin::lex_lt(unsigned num_args, expr* const* args1, expr* const* args2) {
for (unsigned i = 0; i < num_args; ++i) {
TRACE("array_simplifier",
tout << mk_pp(args1[i], m_manager) << "\n";
tout << mk_pp(args2[i], m_manager) << "\n";
tout << args1[i]->get_id() << " " << args2[i]->get_id() << "\n";
);
if (args1[i]->get_id() < args2[i]->get_id()) return true;
if (args1[i]->get_id() > args2[i]->get_id()) return false;
}
return false;
}
void array_simplifier_plugin::get_stores(expr* n, unsigned& arity, expr*& m, ptr_vector<expr*const>& stores) {
while (is_store(n)) {
app* a = to_app(n);
SASSERT(a->get_num_args() > 2);
arity = a->get_num_args()-2;
n = a->get_arg(0);
stores.push_back(a->get_args()+1);
}
m = n;
}
lbool array_simplifier_plugin::eq_default(expr* def, unsigned arity, unsigned num_st, expr*const* const* st) {
bool all_diseq = m_manager.is_unique_value(def) && num_st > 0;
bool all_eq = true;
for (unsigned i = 0; i < num_st; ++i) {
all_eq &= (st[i][arity] == def);
all_diseq &= m_manager.is_unique_value(st[i][arity]) && (st[i][arity] != def);
TRACE("array_simplifier", tout << m_manager.is_unique_value(st[i][arity]) << " " << mk_pp(st[i][arity], m_manager) << "\n";);
}
if (all_eq) {
return l_true;
}
if (all_diseq) {
return l_false;
}
return l_undef;
}
bool array_simplifier_plugin::insert_table(expr* def, unsigned arity, unsigned num_st, expr*const* const* st, arg_table& table) {
for (unsigned i = 0; i < num_st; ++i ) {
for (unsigned j = 0; j < arity; ++j) {
if (!m_manager.is_unique_value(st[i][j])) {
return false;
}
}
TRACE("array_simplifier", tout << "inserting: ";
for (unsigned j = 0; j < arity; ++j) {
tout << mk_pp(st[i][j], m_manager) << " ";
}
tout << " |-> " << mk_pp(def, m_manager) << "\n";
);
args_entry e(arity, st[i]);
table.insert_if_not_there(e);
}
return true;
}
lbool array_simplifier_plugin::eq_stores(expr* def, unsigned arity, unsigned num_st1, expr*const* const* st1, unsigned num_st2, expr*const* const* st2) {
if (num_st1 == 0) {
return eq_default(def, arity, num_st2, st2);
}
if (num_st2 == 0) {
return eq_default(def, arity, num_st1, st1);
}
arg_table table1, table2;
if (!insert_table(def, arity, num_st1, st1, table1)) {
return l_undef;
}
if (!insert_table(def, arity, num_st2, st2, table2)) {
return l_undef;
}
arg_table::iterator it = table1.begin();
arg_table::iterator end = table1.end();
for (; it != end; ++it) {
args_entry const & e1 = *it;
args_entry e2;
expr* v1 = e1.m_args[arity];
if (table2.find(e1, e2)) {
expr* v2 = e2.m_args[arity];
if (v1 == v2) {
table2.erase(e1);
continue;
}
if (m_manager.is_unique_value(v1) && m_manager.is_unique_value(v2)) {
return l_false;
}
return l_undef;
}
else if (m_manager.is_unique_value(v1) && m_manager.is_unique_value(def) && v1 != def) {
return l_false;
}
}
it = table2.begin();
end = table2.end();
for (; it != end; ++it) {
args_entry const & e = *it;
expr* v = e.m_args[arity];
if (m_manager.is_unique_value(v) && m_manager.is_unique_value(def) && v != def) {
return l_false;
}
}
if (!table2.empty() || !table1.empty()) {
return l_undef;
}
return l_true;
}
bool array_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) {
set_reduce_invoked();
expr* c1, *c2;
ptr_vector<expr*const> st1, st2;
unsigned arity1 = 0;
unsigned arity2 = 0;
get_stores(lhs, arity1, c1, st1);
get_stores(rhs, arity2, c2, st2);
if (arity1 == arity2 && is_const_array(c1) && is_const_array(c2)) {
c1 = to_app(c1)->get_arg(0);
c2 = to_app(c2)->get_arg(0);
if (c1 == c2) {
lbool eq = eq_stores(c1, arity2, st1.size(), st1.c_ptr(), st2.size(), st2.c_ptr());
TRACE("array_simplifier",
tout << mk_pp(lhs, m_manager) << " = "
<< mk_pp(rhs, m_manager) << " := " << eq << "\n";
tout << "arity: " << arity1 << "\n";);
switch(eq) {
case l_false:
result = m_manager.mk_false();
return true;
case l_true:
result = m_manager.mk_true();
return true;
default:
return false;
}
}
else if (m_manager.is_unique_value(c1) && m_manager.is_unique_value(c2)) {
result = m_manager.mk_false();
return true;
}
}
return false;
}
bool array_simplifier_plugin::reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result) {
set_reduce_invoked();
return false;
}
array_simplifier_plugin::const_select_result
array_simplifier_plugin::mk_select_const(expr* m, app* index, expr_ref& result) {
store_info* info = 0;
expr* r = 0, *a = 0;
if (!is_store(m)) {
return NOT_CACHED;
}
if (!m_store_cache.find(m, info)) {
return NOT_CACHED;
}
if (info->m_map.find(index, r)) {
result = r;
return FOUND_VALUE;
}
a = info->m_default.get();
//
// Unfold and cache the store while searching for value of index.
//
while (is_store(a) && m_manager.is_unique_value(to_app(a)->get_arg(1))) {
app* b = to_app(a);
app* c = to_app(b->get_arg(1));
if (!info->m_map.contains(c)) {
info->m_map.insert(c, b->get_arg(2));
m_manager.inc_ref(b->get_arg(2));
++m_store_cache_size;
}
a = b->get_arg(0);
info->m_default = a;
if (c == index) {
result = b->get_arg(2);
return FOUND_VALUE;
}
}
result = info->m_default.get();
return FOUND_DEFAULT;
}
void array_simplifier_plugin::cache_store(unsigned num_stores, expr* store_term)
{
if (num_stores <= m_const_store_threshold) {
return;
}
prune_store_cache();
if (!m_store_cache.contains(store_term)) {
store_info * info = alloc(store_info, m_manager, store_term);
m_manager.inc_ref(store_term);
m_store_cache.insert(store_term, info);
TRACE("cache_store", tout << m_store_cache.size() << "\n";);
++m_store_cache_size;
}
}
void array_simplifier_plugin::cache_select(unsigned num_args, expr * const * args, expr * result) {
ptr_vector<expr> * entry = alloc(ptr_vector<expr>);
entry->append(num_args, const_cast<expr**>(args));
const select_cache::key_data & kd = m_select_cache.insert_if_not_there(entry, result);
if (kd.m_key != entry) {
dealloc(entry);
return;
}
m_manager.inc_array_ref(num_args, args);
m_manager.inc_ref(result);
TRACE("cache_select", tout << m_select_cache.size() << "\n";);
}
void array_simplifier_plugin::prune_select_cache() {
if (m_select_cache.size() > m_select_cache_max_size) {
flush_select_cache();
}
}
void array_simplifier_plugin::prune_store_cache() {
if (m_store_cache_size > m_store_cache_max_size) {
flush_store_cache();
}
}
void array_simplifier_plugin::flush_select_cache() {
select_cache::iterator it = m_select_cache.begin();
select_cache::iterator end = m_select_cache.end();
for (; it != end; ++it) {
ptr_vector<expr> * e = (*it).m_key;
m_manager.dec_array_ref(e->size(), e->begin());
m_manager.dec_ref((*it).m_value);
dealloc(e);
}
m_select_cache.reset();
}
void array_simplifier_plugin::flush_store_cache() {
store_cache::iterator it = m_store_cache.begin();
store_cache::iterator end = m_store_cache.end();
for (; it != end; ++it) {
m_manager.dec_ref((*it).m_key);
const_map::iterator mit = (*it).m_value->m_map.begin();
const_map::iterator mend = (*it).m_value->m_map.end();
for (; mit != mend; ++mit) {
m_manager.dec_ref((*mit).m_value);
}
dealloc((*it).m_value);
}
m_store_cache.reset();
m_store_cache_size = 0;
}
void array_simplifier_plugin::flush_caches() {
flush_select_cache();
flush_store_cache();
}
void array_simplifier_plugin::mk_set_difference(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args == 2);
result = m_manager.mk_app(m_fid, OP_SET_DIFFERENCE, 0, 0, num_args, args);
}
void array_simplifier_plugin::mk_empty_set(sort* ty, expr_ref & result) {
parameter param(ty);
expr* args[1] = { m_manager.mk_false() };
result = m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, &param, 1, args);
}
void array_simplifier_plugin::mk_full_set(sort* ty, expr_ref & result) {
parameter param(ty);
expr* args[1] = { m_manager.mk_true() };
result = m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, &param, 1, args);
}
bool array_simplifier_plugin::same_args(unsigned num_args, expr * const * args1, expr * const * args2) {
for (unsigned i = 0; i < num_args; ++i) {
if (args1[i] != args2[i]) {
return false;
}
}
return true;
}
void array_simplifier_plugin::mk_store(func_decl* f, unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args >= 3);
expr* arg0 = args[0];
expr* argn = args[num_args-1];
//
// store(store(a,i,v),i,w) = store(a,i,w)
//
if (is_store(arg0) &&
same_args(num_args-2, args+1, to_app(arg0)->get_args()+1)) {
expr_ref_buffer new_args(m_manager);
new_args.push_back(to_app(arg0)->get_arg(0));
for (unsigned i = 1; i < num_args; ++i) {
new_args.push_back(args[i]);
}
reduce(f, num_args, new_args.c_ptr(), result);
TRACE("array_simplifier", tout << mk_pp(result.get(), m_manager) << "\n";);
return;
}
//
// store(const(v),i,v) = const(v)
//
if (is_const_array(arg0) &&
to_app(arg0)->get_arg(0) == args[num_args-1]) {
result = arg0;
TRACE("array_simplifier", tout << mk_pp(result.get(), m_manager) << "\n";);
return;
}
//
// store(a, i, select(a, i)) = a
//
if (is_select(argn) &&
(to_app(argn)->get_num_args() == num_args - 1) &&
same_args(num_args-1, args, to_app(argn)->get_args())) {
TRACE("dummy_store", tout << "dummy store simplified mk_store(\n";
for (unsigned i = 0; i < num_args; i++) ast_ll_pp(tout, m_manager, args[i]);
tout << ") =====>\n";
ast_ll_pp(tout, m_manager, arg0););
result = arg0;
TRACE("array_simplifier", tout << mk_pp(result.get(), m_manager) << "\n";);
return;
}
//
// store(store(a,i,v),j,w) -> store(store(a,j,w),i,v)
// if i, j are values, i->get_id() < j->get_id()
//
if (m_params.m_array_canonize_simplify &&
is_store(arg0) &&
all_values(num_args-2, args+1) &&
all_values(num_args-2, to_app(arg0)->get_args()+1) &&
lex_lt(num_args-2, args+1, to_app(arg0)->get_args()+1)) {
expr* const* args2 = to_app(arg0)->get_args();
expr_ref_buffer new_args(m_manager);
new_args.push_back(args2[0]);
for (unsigned i = 1; i < num_args; ++i) {
new_args.push_back(args[i]);
}
reduce(f, num_args, new_args.c_ptr(), result);
new_args.reset();
new_args.push_back(result);
for (unsigned i = 1; i < num_args; ++i) {
new_args.push_back(args2[i]);
}
result = m_manager.mk_app(m_fid, OP_STORE, num_args, new_args.c_ptr());
TRACE("array_simplifier", tout << mk_pp(result.get(), m_manager) << "\n";);
return;
}
result = m_manager.mk_app(m_fid, OP_STORE, num_args, args);
TRACE("array_simplifier", tout << "default: " << mk_pp(result.get(), m_manager) << "\n";);
}
void array_simplifier_plugin::mk_select_as_array(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(is_as_array(args[0]));
func_decl * f = get_as_array_func_decl(to_app(args[0]));
result = m_manager.mk_app(f, num_args - 1, args+1);
}
void array_simplifier_plugin::mk_select_as_array_tree(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(is_as_array_tree(args[0]));
SASSERT(m_manager.is_ite(args[0]));
ptr_buffer<app, 32> todo;
obj_map<app, app *> cache;
app_ref_buffer trail(m_manager);
todo.push_back(to_app(args[0]));
while (!todo.empty()) {
app * curr = todo.back();
SASSERT(m_manager.is_ite(curr));
expr * branches[2] = {0, 0};
bool visited = true;
for (unsigned i = 0; i < 2; i++) {
expr * arg = curr->get_arg(i+1);
if (is_as_array(arg)) {
branches[i] = m_manager.mk_app(get_as_array_func_decl(to_app(arg)), num_args - 1, args+1);
}
else {
SASSERT(m_manager.is_ite(arg));
app * new_arg = 0;
if (!cache.find(to_app(arg), new_arg)) {
todo.push_back(to_app(arg));
visited = false;
}
else {
branches[i] = new_arg;
}
}
}
if (visited) {
todo.pop_back();
app * new_curr = m_manager.mk_ite(curr->get_arg(0), branches[0], branches[1]);
trail.push_back(new_curr);
cache.insert(curr, new_curr);
}
}
SASSERT(cache.contains(to_app(args[0])));
app * r = 0;
cache.find(to_app(args[0]), r);
result = r;
}
void array_simplifier_plugin::mk_select(unsigned num_args, expr * const * args, expr_ref & result) {
expr * r = 0;
if (is_as_array(args[0])) {
mk_select_as_array(num_args, args, result);
return;
}
if (is_as_array_tree(args[0])) {
mk_select_as_array_tree(num_args, args, result);
return;
}
bool is_const_select = num_args == 2 && m_manager.is_unique_value(args[1]);
app* const_index = is_const_select?to_app(args[1]):0;
unsigned num_const_stores = 0;
expr_ref tmp(m_manager);
expr* args2[2];
if (is_const_select) {
switch(mk_select_const(args[0], const_index, tmp)) {
case NOT_CACHED:
break;
case FOUND_VALUE:
TRACE("mk_select", tout << "found value\n"; ast_ll_pp(tout, m_manager, tmp.get()); );
result = tmp.get();
// value of select is stored under result.
return;
case FOUND_DEFAULT:
args2[0] = tmp.get();
args2[1] = args[1];
args = args2;
is_const_select = false;
break;
}
}
SASSERT(num_args > 0);
ptr_vector<expr> & entry = m_tmp2;
entry.reset();
entry.append(num_args, args);
expr * entry0 = entry[0];
SASSERT(m_todo.empty());
m_todo.push_back(entry0);
while (!m_todo.empty()) {
expr * m = m_todo.back();
TRACE("array_simplifier", tout << mk_bounded_pp(m, m_manager) << "\n";);
if (is_store(m)) {
expr * nested_array = to_app(m)->get_arg(0);
expr * else_branch = 0;
entry[0] = nested_array;
if (is_const_select) {
if (m_manager.is_unique_value(to_app(m)->get_arg(1))) {
app* const_index2 = to_app(to_app(m)->get_arg(1));
//
// we found the value, all other stores are different.
// there is no need to recurse.
//
if (const_index == const_index2) {
result = to_app(m)->get_arg(2);
cache_store(num_const_stores, args[0]);
m_todo.reset();
return;
}
++num_const_stores;
}
else {
is_const_select = false;
}
}
if (m_select_cache.find(&entry, else_branch)) {
expr_ref_buffer eqs(m_manager);
for (unsigned i = 1; i < num_args ; ++i) {
expr * a = args[i];
expr * b = to_app(m)->get_arg(i);
expr_ref eq(m_manager);
m_simp.mk_eq(a, b, eq);
eqs.push_back(eq.get());
}
expr_ref cond(m_manager);
m_simp.mk_and(eqs.size(), eqs.c_ptr(), cond);
expr * then_branch = to_app(m)->get_arg(num_args);
if (m_manager.is_true(cond.get())) {
result = then_branch;
}
else if (m_manager.is_false(cond.get())) {
result = else_branch;
}
else {
m_simp.mk_ite(cond.get(), then_branch, else_branch, result);
}
entry[0] = m;
cache_select(entry.size(), entry.c_ptr(), result.get());
m_todo.pop_back();
}
else {
m_todo.push_back(nested_array);
}
}
else if (is_const_array(m)) {
entry[0] = m;
cache_select(entry.size(), entry.c_ptr(), to_app(m)->get_arg(0));
m_todo.pop_back();
}
else {
entry[0] = m;
TRACE("array_simplifier", {
for (unsigned i = 0; i < entry.size(); ++i) {
tout << mk_bounded_pp(entry[i], m_manager) << ": "
<< mk_bounded_pp(m_manager.get_sort(entry[i]), m_manager) << "\n";
}}
);
r = m_manager.mk_app(m_fid, OP_SELECT, 0, 0, entry.size(), entry.c_ptr());
cache_select(entry.size(), entry.c_ptr(), r);
m_todo.pop_back();
}
}
cache_store(num_const_stores, args[0]);
entry[0] = entry0;
#ifdef Z3DEBUG
bool f =
#endif
m_select_cache.find(&entry, r);
SASSERT(f);
result = r;
prune_select_cache();
prune_store_cache();
TRACE("mk_select",
for (unsigned i = 0; i < num_args; i++) {
ast_ll_pp(tout, m_manager, args[i]); tout << "\n";
};
tout << "is_store: " << is_store(args[0]) << "\n";
ast_ll_pp(tout, m_manager, r););
}
void array_simplifier_plugin::mk_map(func_decl* f, expr* a, expr* b, expr_ref& result) {
expr* exprs[2] = { a, b };
parameter param(f);
result = m_manager.mk_app(m_fid, OP_ARRAY_MAP, 1, &param, 2, exprs );
}
void array_simplifier_plugin::mk_map(func_decl* f, expr* a, expr_ref& result) {
parameter param(f);
result = m_manager.mk_app(m_fid, OP_ARRAY_MAP, 1, &param, 1, &a );
}

View file

@ -1,154 +0,0 @@
/*++
Copyright (c) 2008 Microsoft Corporation
Module Name:
array_simplifier_plugin.h
Abstract:
<abstract>
Author:
Nikolaj Bjorner (nbjorner) 2008-05-05
Revision History:
--*/
#ifndef ARRAY_SIMPLIFIER_PLUGIN_H_
#define ARRAY_SIMPLIFIER_PLUGIN_H_
#include "ast/ast.h"
#include "util/map.h"
#include "ast/array_decl_plugin.h"
#include "ast/simplifier/simplifier_plugin.h"
#include "ast/simplifier/basic_simplifier_plugin.h"
#include "ast/simplifier/array_simplifier_params.h"
#include "ast/simplifier/simplifier.h"
#include "util/obj_hashtable.h"
#include "util/lbool.h"
class array_simplifier_plugin : public simplifier_plugin {
typedef ptr_vector<expr> entry;
struct entry_hash_proc {
unsigned operator()(ptr_vector<expr> * entry) const {
return get_exprs_hash(entry->size(), entry->begin(), 0xbeef1010);
}
};
struct entry_eq_proc {
bool operator()(ptr_vector<expr> * entry1, ptr_vector<expr> * entry2) const {
if (entry1->size() != entry2->size()) return false;
return compare_arrays(entry1->begin(), entry2->begin(), entry1->size());
}
};
typedef map<entry *, expr *, entry_hash_proc, entry_eq_proc> select_cache;
struct args_entry {
unsigned m_arity;
expr* const* m_args;
args_entry(unsigned a, expr* const* args) : m_arity(a), m_args(args) {}
args_entry() : m_arity(0), m_args(0) {}
};
struct args_entry_hash_proc {
unsigned operator()(args_entry const& e) const {
return get_exprs_hash(e.m_arity, e.m_args, 0xbeef1010);
}
};
struct args_entry_eq_proc {
bool operator()(args_entry const& e1, args_entry const& e2) const {
if (e1.m_arity != e2.m_arity) return false;
return compare_arrays(e1.m_args, e2.m_args, e1.m_arity);
}
};
typedef hashtable<args_entry, args_entry_hash_proc, args_entry_eq_proc> arg_table;
array_util m_util;
basic_simplifier_plugin& m_simp;
simplifier& m_simplifier;
array_simplifier_params const& m_params;
select_cache m_select_cache;
ptr_vector<expr> m_tmp;
ptr_vector<expr> m_tmp2;
ptr_vector<expr> m_todo;
static const unsigned m_select_cache_max_size = 100000;
typedef obj_map<expr, expr*> const_map;
class store_info {
store_info();
store_info(store_info const&);
public:
const_map m_map;
expr_ref m_default;
store_info(ast_manager& m, expr* d): m_default(d, m) {}
};
typedef obj_map<expr, store_info*> store_cache;
store_cache m_store_cache;
unsigned m_store_cache_size;
static const unsigned m_store_cache_max_size = 10000;
static const unsigned m_const_store_threshold = 5;
enum const_select_result {
NOT_CACHED,
FOUND_DEFAULT,
FOUND_VALUE
};
public:
array_simplifier_plugin(ast_manager & m, basic_simplifier_plugin& s, simplifier& simp, array_simplifier_params const& p);
virtual ~array_simplifier_plugin();
virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result);
virtual bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result);
virtual void flush_caches();
private:
bool is_select(expr* n) const { return m_util.is_select(n); }
bool is_store(expr * n) const { return m_util.is_store(n); }
bool is_const_array(expr * n) const { return m_util.is_const(n); }
bool is_as_array(expr * n) const { return m_util.is_as_array(n); }
bool is_as_array_tree(expr * n) { return m_util.is_as_array_tree(n); }
func_decl * get_as_array_func_decl(app * n) const { return m_util.get_as_array_func_decl(n); }
void mk_select_as_array(unsigned num_args, expr * const * args, expr_ref & result);
void mk_select_as_array_tree(unsigned num_args, expr * const * args, expr_ref & result);
bool is_enumerated(expr* n, expr_ref& c, ptr_vector<expr>& keys, ptr_vector<expr>& vals);
const_select_result mk_select_const(expr* m, app* index, expr_ref& result);
void cache_store(unsigned num_stores, expr* nested_store);
void cache_select(unsigned num_args, expr * const * args, expr * result);
void prune_select_cache();
void prune_store_cache();
void flush_select_cache();
void flush_store_cache();
void mk_set_difference(unsigned num_args, expr * const * args, expr_ref & result);
void mk_empty_set(sort* ty, expr_ref & result);
void mk_full_set(sort* ty, expr_ref & result);
void mk_select(unsigned num_args, expr * const * args, expr_ref & result);
void mk_store(func_decl* f, unsigned num_args, expr * const * args, expr_ref & result);
void mk_map(func_decl* f, expr* a, expr* b, expr_ref & result);
void mk_map(func_decl* f, expr* a, expr_ref & result);
bool same_args(unsigned num_args, expr * const * args1, expr * const * args2);
void get_stores(expr* n, unsigned& arity, expr*& m, ptr_vector<expr*const>& stores);
lbool eq_default(expr* def, unsigned arity, unsigned num_st, expr*const* const* st);
bool insert_table(expr* def, unsigned arity, unsigned num_st, expr*const* const* st, arg_table& table);
lbool eq_stores(expr* def, unsigned arity, unsigned num_st1, expr*const* const* st1, unsigned num_st2, expr*const* const* st2);
bool same_store(unsigned num_args, expr* const* args) const;
bool all_const_array(unsigned num_args, expr* const* args) const;
bool all_values(unsigned num_args, expr* const* args) const;
bool lex_lt(unsigned num_args, expr* const* args1, expr* const* args2);
};
#endif /* ARRAY_SIMPLIFIER_PLUGIN_H_ */

View file

@ -1,77 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
base_simplifier.h
Abstract:
Base class for expression simplifier functors.
Author:
Leonardo (leonardo) 2008-01-11
Notes:
--*/
#ifndef BASE_SIMPLIFIER_H_
#define BASE_SIMPLIFIER_H_
#include "ast/expr_map.h"
#include "ast/ast_pp.h"
/**
\brief Implements basic functionality used by expression simplifiers.
*/
class base_simplifier {
protected:
ast_manager & m;
expr_map m_cache;
ptr_vector<expr> m_todo;
void cache_result(expr * n, expr * r, proof * p) {
m_cache.insert(n, r, p);
CTRACE("simplifier", !is_rewrite_proof(n, r, p),
tout << mk_pp(n, m) << "\n";
tout << mk_pp(r, m) << "\n";
tout << mk_pp(p, m) << "\n";);
TRACE("cache", tout << mk_pp(n, m) << " -> " << mk_pp(r, m) << "\n";);
SASSERT(is_rewrite_proof(n, r, p));
}
void reset_cache() { m_cache.reset(); }
void flush_cache() { m_cache.flush(); }
void get_cached(expr * n, expr * & r, proof * & p) const { m_cache.get(n, r, p); }
void reinitialize() { m_cache.set_store_proofs(m.fine_grain_proofs()); }
void visit(expr * n, bool & visited) {
if (!is_cached(n)) {
m_todo.push_back(n);
visited = false;
}
}
public:
base_simplifier(ast_manager & m):
m(m),
m_cache(m, m.fine_grain_proofs()) {
}
bool is_cached(expr * n) const { return m_cache.contains(n); }
ast_manager & get_manager() { return m; }
bool is_rewrite_proof(expr* n, expr* r, proof* p) {
if (p &&
!m.is_undef_proof(p) &&
!(m.has_fact(p) &&
(m.is_eq(m.get_fact(p)) || m.is_oeq(m.get_fact(p)) || m.is_iff(m.get_fact(p))) &&
to_app(m.get_fact(p))->get_arg(0) == n &&
to_app(m.get_fact(p))->get_arg(1) == r)) return false;
return (!m.fine_grain_proofs() || p || (n == r));
}
};
#endif /* BASE_SIMPLIFIER_H_ */

View file

@ -1,147 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
basic_simplifier_plugin.cpp
Abstract:
Simplifier for the basic family.
Author:
Leonardo (leonardo) 2008-01-07
--*/
#include "ast/simplifier/basic_simplifier_plugin.h"
#include "ast/ast_ll_pp.h"
#include "ast/rewriter/bool_rewriter.h"
basic_simplifier_plugin::basic_simplifier_plugin(ast_manager & m):
simplifier_plugin(symbol("basic"), m),
m_rewriter(alloc(bool_rewriter, m)) {
}
basic_simplifier_plugin::~basic_simplifier_plugin() {
dealloc(m_rewriter);
}
bool basic_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
set_reduce_invoked();
SASSERT(f->get_family_id() == m_manager.get_basic_family_id());
basic_op_kind k = static_cast<basic_op_kind>(f->get_decl_kind());
switch (k) {
case OP_FALSE:
case OP_TRUE:
return false;
case OP_EQ:
SASSERT(num_args == 2);
mk_eq(args[0], args[1], result);
return true;
case OP_DISTINCT:
mk_distinct(num_args, args, result);
return true;
case OP_ITE:
SASSERT(num_args == 3);
mk_ite(args[0], args[1], args[2], result);
return true;
case OP_AND:
mk_and(num_args, args, result);
return true;
case OP_OR:
mk_or(num_args, args, result);
return true;
case OP_IMPLIES:
mk_implies(args[0], args[1], result);
return true;
case OP_IFF:
mk_iff(args[0], args[1], result);
return true;
case OP_XOR:
switch (num_args) {
case 0: result = m_manager.mk_true(); break;
case 1: result = args[0]; break;
case 2: mk_xor(args[0], args[1], result); break;
default: UNREACHABLE(); break;
}
return true;
case OP_NOT:
SASSERT(num_args == 1);
mk_not(args[0], result);
return true;
default:
UNREACHABLE();
return false;
}
}
/**
\brief Return true if \c rhs is of the form (ite c t1 t2) and are_distinct(lhs, t1) and are_distinct(lhs, t2).
*/
static bool is_lhs_diseq_rhs_ite_branches(ast_manager & m, expr * lhs, expr * rhs) {
return m.is_ite(rhs) && m.are_distinct(lhs, to_app(rhs)->get_arg(1)) && m.are_distinct(lhs, to_app(rhs)->get_arg(2));
}
/**
\brief Return true if \c rhs is of the form (ite c t1 t2) and lhs = t1 && are_distinct(lhs, t2)
*/
static bool is_lhs_eq_rhs_ite_then(ast_manager & m, expr * lhs, expr * rhs) {
return m.is_ite(rhs) && lhs == to_app(rhs)->get_arg(1) && m.are_distinct(lhs, to_app(rhs)->get_arg(2));
}
/**
\brief Return true if \c rhs is of the form (ite c t1 t2) and are_distinct(lhs,t1) && lhs = t2
*/
static bool is_lhs_eq_rhs_ite_else(ast_manager & m, expr * lhs, expr * rhs) {
return m.is_ite(rhs) && lhs == to_app(rhs)->get_arg(2) && m.are_distinct(lhs, to_app(rhs)->get_arg(1));
}
void basic_simplifier_plugin::mk_eq(expr * lhs, expr * rhs, expr_ref & result) {
// (= t1 (ite C t2 t3)) --> false if are_distinct(t1, t2) && are_distinct(t1, t3)
if (is_lhs_diseq_rhs_ite_branches(m_manager, lhs, rhs) || is_lhs_diseq_rhs_ite_branches(m_manager, rhs, lhs)) {
result = m_manager.mk_false();
}
// (= t1 (ite C t2 t3)) --> C if t1 = t2 && are_distinct(t1, t3)
else if (is_lhs_eq_rhs_ite_then(m_manager, lhs, rhs)) {
result = to_app(rhs)->get_arg(0);
}
// (= t1 (ite C t2 t3)) --> C if t1 = t2 && are_distinct(t1, t3)
else if (is_lhs_eq_rhs_ite_then(m_manager, rhs, lhs)) {
result = to_app(lhs)->get_arg(0);
}
// (= t1 (ite C t2 t3)) --> (not C) if t1 = t3 && are_distinct(t1, t2)
else if (is_lhs_eq_rhs_ite_else(m_manager, lhs, rhs)) {
mk_not(to_app(rhs)->get_arg(0), result);
}
// (= t1 (ite C t2 t3)) --> (not C) if t1 = t3 && are_distinct(t1, t2)
else if (is_lhs_eq_rhs_ite_else(m_manager, rhs, lhs)) {
mk_not(to_app(lhs)->get_arg(0), result);
}
else {
m_rewriter->mk_eq(lhs, rhs, result);
}
}
bool basic_simplifier_plugin::eliminate_and() const { return m_rewriter->elim_and(); }
void basic_simplifier_plugin::set_eliminate_and(bool f) { m_rewriter->set_elim_and(f); }
void basic_simplifier_plugin::mk_iff(expr * lhs, expr * rhs, expr_ref & result) { mk_eq(lhs, rhs, result); }
void basic_simplifier_plugin::mk_xor(expr * lhs, expr * rhs, expr_ref & result) { m_rewriter->mk_xor(lhs, rhs, result); }
void basic_simplifier_plugin::mk_implies(expr * lhs, expr * rhs, expr_ref & result) { m_rewriter->mk_implies(lhs, rhs, result); }
void basic_simplifier_plugin::mk_ite(expr * c, expr * t, expr * e, expr_ref & result) { m_rewriter->mk_ite(c, t, e, result); }
void basic_simplifier_plugin::mk_and(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_and(num_args, args, result); }
void basic_simplifier_plugin::mk_or(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_or(num_args, args, result); }
void basic_simplifier_plugin::mk_and(expr * arg1, expr * arg2, expr_ref & result) { m_rewriter->mk_and(arg1, arg2, result); }
void basic_simplifier_plugin::mk_or(expr * arg1, expr * arg2, expr_ref & result) { m_rewriter->mk_or(arg1, arg2, result); }
void basic_simplifier_plugin::mk_and(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { m_rewriter->mk_and(arg1, arg2, arg3, result); }
void basic_simplifier_plugin::mk_or(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { m_rewriter->mk_or(arg1, arg2, arg3, result); }
void basic_simplifier_plugin::mk_nand(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_nand(num_args, args, result); }
void basic_simplifier_plugin::mk_nor(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_nor(num_args, args, result); }
void basic_simplifier_plugin::mk_nand(expr * arg1, expr * arg2, expr_ref & result) { m_rewriter->mk_nand(arg1, arg2, result); }
void basic_simplifier_plugin::mk_nor(expr * arg1, expr * arg2, expr_ref & result) { m_rewriter->mk_nor(arg1, arg2, result); }
void basic_simplifier_plugin::mk_distinct(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_distinct(num_args, args, result); }
void basic_simplifier_plugin::mk_not(expr * n, expr_ref & result) { m_rewriter->mk_not(n, result); }
void basic_simplifier_plugin::enable_ac_support(bool flag) {
m_rewriter->set_flat(flag);
}

View file

@ -1,78 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
basic_simplifier_plugin.h
Abstract:
Simplifier for the basic family.
Author:
Leonardo (leonardo) 2008-01-07
--*/
#ifndef BASIC_SIMPLIFIER_PLUGIN_H_
#define BASIC_SIMPLIFIER_PLUGIN_H_
#include "ast/simplifier/simplifier_plugin.h"
class bool_rewriter;
/**
\brief Simplifier for the basic family.
*/
class basic_simplifier_plugin : public simplifier_plugin {
bool_rewriter * m_rewriter;
public:
basic_simplifier_plugin(ast_manager & m);
virtual ~basic_simplifier_plugin();
bool_rewriter & get_rewriter() { return *m_rewriter; }
bool eliminate_and() const;
void set_eliminate_and(bool f);
void mk_eq(expr * lhs, expr * rhs, expr_ref & result);
void mk_iff(expr * lhs, expr * rhs, expr_ref & result);
void mk_xor(expr * lhs, expr * rhs, expr_ref & result);
void mk_implies(expr * lhs, expr * rhs, expr_ref & result);
void mk_ite(expr * c, expr * t, expr * e, expr_ref & result);
void mk_and(unsigned num_args, expr * const * args, expr_ref & result);
void mk_or(unsigned num_args, expr * const * args, expr_ref & result);
void mk_and(expr * arg1, expr * arg2, expr_ref & result);
void mk_or(expr * arg1, expr * arg2, expr_ref & result);
void mk_and(expr * arg1, expr * arg2, expr * arg3, expr_ref & result);
void mk_or(expr * arg1, expr * arg2, expr * arg3, expr_ref & result);
void mk_nand(unsigned num_args, expr * const * args, expr_ref & result);
void mk_nor(unsigned num_args, expr * const * args, expr_ref & result);
void mk_nand(expr * arg1, expr * arg2, expr_ref & result);
void mk_nor(expr * arg1, expr * arg2, expr_ref & result);
void mk_distinct(unsigned num_args, expr * const * args, expr_ref & result);
void mk_not(expr * n, expr_ref & result);
virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
virtual void enable_ac_support(bool flag);
};
/**
\brief Functor that compares expressions, but puts the expressions e and f(e) close to each other, where
f is in family m_fid, and has kind m_dkind;
*/
struct expr_lt_proc {
family_id m_fid;
decl_kind m_dkind;
expr_lt_proc(family_id fid = null_family_id, decl_kind k = null_decl_kind):m_fid(fid), m_dkind(k) {}
unsigned get_id(expr * n) const {
if (m_fid != null_family_id && is_app_of(n, m_fid, m_dkind))
return (to_app(n)->get_arg(0)->get_id() << 1) + 1;
else
return n->get_id() << 1;
}
bool operator()(expr * n1, expr * n2) const {
return get_id(n1) < get_id(n2);
}
};
#endif /* BASIC_SIMPLIFIER_PLUGIN_H_ */

View file

@ -1,119 +0,0 @@
/*++
Copyright (c) 2015 Microsoft Corporation
--*/
#include "ast/simplifier/bv_elim.h"
#include "ast/bv_decl_plugin.h"
#include "ast/rewriter/var_subst.h"
#include <sstream>
void bv_elim::elim(quantifier* q, quantifier_ref& r) {
svector<symbol> names, _names;
sort_ref_buffer sorts(m_manager), _sorts(m_manager);
expr_ref_buffer pats(m_manager);
expr_ref_buffer no_pats(m_manager);
expr_ref_buffer subst_map(m_manager), _subst_map(m_manager);
var_subst subst(m_manager);
bv_util bv(m_manager);
expr_ref new_body(m_manager);
expr* old_body = q->get_expr();
unsigned num_decls = q->get_num_decls();
family_id bfid = m_manager.mk_family_id("bv");
//
// Traverse sequence of bound variables to eliminate
// bit-vecctor variables and replace them by
// Booleans.
//
unsigned var_idx = 0;
for (unsigned i = num_decls; i > 0; ) {
--i;
sort* s = q->get_decl_sort(i);
symbol nm = q->get_decl_name(i);
if (bv.is_bv_sort(s)) {
// convert n-bit bit-vector variable into sequence of n-Booleans.
unsigned num_bits = bv.get_bv_size(s);
expr_ref_buffer args(m_manager);
expr_ref bv(m_manager);
for (unsigned j = 0; j < num_bits; ++j) {
std::ostringstream new_name;
new_name << nm.str();
new_name << "_";
new_name << j;
var* v = m_manager.mk_var(var_idx++, m_manager.mk_bool_sort());
args.push_back(v);
_sorts.push_back(m_manager.mk_bool_sort());
_names.push_back(symbol(new_name.str().c_str()));
}
bv = m_manager.mk_app(bfid, OP_MKBV, 0, 0, args.size(), args.c_ptr());
_subst_map.push_back(bv.get());
}
else {
_subst_map.push_back(m_manager.mk_var(var_idx++, s));
_sorts.push_back(s);
_names.push_back(nm);
}
}
//
// reverse the vectors.
//
SASSERT(_names.size() == _sorts.size());
for (unsigned i = _names.size(); i > 0; ) {
--i;
names.push_back(_names[i]);
sorts.push_back(_sorts[i]);
}
for (unsigned i = _subst_map.size(); i > 0; ) {
--i;
subst_map.push_back(_subst_map[i]);
}
expr* const* sub = subst_map.c_ptr();
unsigned sub_size = subst_map.size();
subst(old_body, sub_size, sub, new_body);
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
expr_ref pat(m_manager);
subst(q->get_pattern(j), sub_size, sub, pat);
pats.push_back(pat);
}
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
expr_ref nopat(m_manager);
subst(q->get_no_pattern(j), sub_size, sub, nopat);
no_pats.push_back(nopat);
}
r = m_manager.mk_quantifier(true,
names.size(),
sorts.c_ptr(),
names.c_ptr(),
new_body.get(),
q->get_weight(),
q->get_qid(),
q->get_skid(),
pats.size(), pats.c_ptr(),
no_pats.size(), no_pats.c_ptr());
}
bool bv_elim_star::visit_quantifier(quantifier* q) {
// behave like destructive resolution, do not recurse.
return true;
}
void bv_elim_star::reduce1_quantifier(quantifier* q) {
quantifier_ref r(m);
proof_ref pr(m);
m_bv_elim.elim(q, r);
if (m.fine_grain_proofs()) {
pr = m.mk_rewrite(q, r.get());
}
else {
pr = 0;
}
cache_result(q, r, pr);
}

View file

@ -1,45 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
bv_elim.h
Abstract:
Eliminate bit-vectors variables from clauses, by
replacing them by bound Boolean variables.
Author:
Nikolaj Bjorner (nbjorner) 2008-12-16.
Revision History:
--*/
#ifndef BV_ELIM_H_
#define BV_ELIM_H_
#include "ast/ast.h"
#include "ast/simplifier/simplifier.h"
class bv_elim {
ast_manager& m_manager;
public:
bv_elim(ast_manager& m) : m_manager(m) {};
void elim(quantifier* q, quantifier_ref& r);
};
class bv_elim_star : public simplifier {
protected:
bv_elim m_bv_elim;
virtual bool visit_quantifier(quantifier* q);
virtual void reduce1_quantifier(quantifier* q);
public:
bv_elim_star(ast_manager& m) : simplifier(m), m_bv_elim(m) { enable_ac_support(false); }
virtual ~bv_elim_star() {}
};
#endif /* BV_ELIM_H_ */

View file

@ -1,36 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
bv_simplifier_params.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2012-12-02.
Revision History:
--*/
#include "ast/simplifier/bv_simplifier_params.h"
#include "ast/simplifier/bv_simplifier_params_helper.hpp"
#include "ast/rewriter/bv_rewriter_params.hpp"
void bv_simplifier_params::updt_params(params_ref const & _p) {
bv_simplifier_params_helper p(_p);
bv_rewriter_params rp(_p);
m_hi_div0 = rp.hi_div0();
m_bv2int_distribute = p.bv_bv2int_distribute();
}
#define DISPLAY_PARAM(X) out << #X"=" << X << std::endl;
void bv_simplifier_params::display(std::ostream & out) const {
DISPLAY_PARAM(m_hi_div0);
DISPLAY_PARAM(m_bv2int_distribute);
}

View file

@ -1,38 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
bv_simplifier_params.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-10-10.
Revision History:
--*/
#ifndef BV_SIMPLIFIER_PARAMS_H_
#define BV_SIMPLIFIER_PARAMS_H_
#include "util/params.h"
struct bv_simplifier_params {
bool m_hi_div0; //!< if true, uses the hardware interpretation for div0, mod0, ... if false, div0, mod0, ... are considered uninterpreted.
bool m_bv2int_distribute; //!< if true allows downward propagation of bv2int.
bv_simplifier_params(params_ref const & p = params_ref()) {
updt_params(p);
}
void updt_params(params_ref const & _p);
void display(std::ostream & out) const;
};
#endif /* BV_SIMPLIFIER_PARAMS_H_ */

View file

@ -1,4 +0,0 @@
def_module_params(class_name='bv_simplifier_params_helper',
module_name="old_simplify", # Parameters will be in the old_simplify module
export=True,
params=(('bv.bv2int_distribute', BOOL, True, 'if true, then int2bv is distributed over arithmetical operators'),))

File diff suppressed because it is too large Load diff

View file

@ -1,187 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
bv_simplifier_plugin.h
Abstract:
Simplifier for the bv family.
Author:
Leonardo (leonardo) 2008-01-08
--*/
#ifndef BV_SIMPLIFIER_PLUGIN_H_
#define BV_SIMPLIFIER_PLUGIN_H_
#include "ast/simplifier/basic_simplifier_plugin.h"
#include "ast/simplifier/poly_simplifier_plugin.h"
#include "ast/bv_decl_plugin.h"
#include "util/map.h"
#include "ast/simplifier/bv_simplifier_params.h"
#include "ast/arith_decl_plugin.h"
/**
\brief Simplifier for the bv family.
*/
class bv_simplifier_plugin : public poly_simplifier_plugin {
typedef rational numeral;
struct extract_entry {
unsigned m_high;
unsigned m_low;
expr * m_arg;
extract_entry():m_high(0), m_low(0), m_arg(0) {}
extract_entry(unsigned h, unsigned l, expr * n):m_high(h), m_low(l), m_arg(n) {}
unsigned hash() const {
unsigned a = m_high;
unsigned b = m_low;
unsigned c = m_arg->get_id();
mix(a,b,c);
return c;
}
bool operator==(const extract_entry & e) const {
return m_high == e.m_high && m_low == e.m_low && m_arg == e.m_arg;
}
struct hash_proc {
unsigned operator()(extract_entry const& e) const { return e.hash(); }
};
struct eq_proc {
bool operator()(extract_entry const& a, extract_entry const& b) const { return a == b; }
};
};
typedef map<extract_entry, expr *, extract_entry::hash_proc , extract_entry::eq_proc > extract_cache;
protected:
ast_manager& m_manager;
bv_util m_util;
arith_util m_arith;
basic_simplifier_plugin & m_bsimp;
bv_simplifier_params & m_params;
expr_ref_vector m_zeros;
extract_cache m_extract_cache;
unsigned_vector m_lows, m_highs;
ptr_vector<expr> m_extract_args;
rational mk_bv_and(numeral const& a0, numeral const& b0, unsigned sz);
rational mk_bv_or(numeral const& a0, numeral const& b0, unsigned sz);
rational mk_bv_xor(numeral const& a0, numeral const& b0, unsigned sz);
rational mk_bv_not(numeral const& a0, unsigned sz);
rational num(expr* e);
bool has_sign_bit(numeral const& n, unsigned bv_size) { return m_util.has_sign_bit(n, bv_size); }
bool shift_shift(bv_op_kind k, expr* arg1, expr* arg2, expr_ref& result);
void bit2bool_simplify(unsigned idx, expr* e, expr_ref& result);
void mk_add_concat(expr_ref& result);
bool is_zero_bit(expr* x, unsigned idx);
void mk_bv_rotate_left_core(unsigned shift, numeral r, unsigned bv_size, expr_ref& result);
void mk_bv_rotate_right_core(unsigned shift, numeral r, unsigned bv_size, expr_ref& result);
public:
bv_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, bv_simplifier_params & p);
virtual ~bv_simplifier_plugin();
// simplifier_plugin:
virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result);
virtual bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result);
virtual void flush_caches();
// poly_simplifier_plugin
virtual rational norm(const rational & n);
virtual bool is_numeral(expr * n, rational & val) const;
bool is_numeral(expr * n) const { return m_util.is_numeral(n); }
virtual bool is_minus_one(expr * n) const { return is_minus_one_core(n); }
virtual expr * get_zero(sort * s) const;
virtual app * mk_numeral(rational const & n);
bool is_bv(expr * n) const { return m_util.is_bv(n); }
bool is_bv_sort(sort * s) const { return m_util.is_bv_sort(s); }
bool is_le(expr * n) const { return m_util.is_bv_ule(n) || m_util.is_bv_sle(n); }
// REMARK: simplified bv expressions are never of the form a >= b.
virtual bool is_le_ge(expr * n) const { return is_le(n); }
uint64 to_uint64(const numeral & n, unsigned bv_size);
rational norm(rational const& n, unsigned bv_size, bool is_signed) { return m_util.norm(n, bv_size, is_signed); }
unsigned get_bv_size(expr const * n) { return get_bv_size(m_manager.get_sort(n)); }
unsigned get_bv_size(sort const * s) { return m_util.get_bv_size(s); }
void mk_leq_core(bool is_signed, expr * arg1, expr * arg2, expr_ref & result);
void mk_ule(expr* a, expr* b, expr_ref& result);
void mk_ult(expr* a, expr* b, expr_ref& result);
void mk_sle(expr* a, expr* b, expr_ref& result);
void mk_slt(expr* a, expr* b, expr_ref& result);
void mk_bv_and(unsigned num_args, expr * const* args, expr_ref & result);
void mk_bv_or(unsigned num_args, expr * const* args, expr_ref & result);
void mk_bv_xor(unsigned num_args, expr * const* args, expr_ref & result);
void mk_bv_not(expr * arg, expr_ref & result);
void mk_extract(unsigned hi,unsigned lo, expr* bv, expr_ref& result);
void mk_extract_core(unsigned high, unsigned low, expr * arg, expr_ref& result);
void cache_extract(unsigned h, unsigned l, expr * arg, expr * result);
expr* get_cached_extract(unsigned h, unsigned l, expr * arg);
bool lookup_mk_extract(unsigned high, unsigned low, expr * arg, expr_ref& result);
bool try_mk_extract(unsigned high, unsigned low, expr * arg, expr_ref& result);
void mk_bv_eq(expr* a1, expr* a2, expr_ref& result);
void mk_eq_core(expr * arg1, expr * arg2, expr_ref & result);
void mk_args_eq_numeral(app * app, expr * n, expr_ref & result);
void mk_concat(unsigned num_args, expr * const * args, expr_ref & result);
void mk_concat(expr * arg1, expr * arg2, expr_ref & result) {
expr * args[2] = { arg1, arg2 };
mk_concat(2, args, result);
}
void mk_zeroext(unsigned n, expr * arg, expr_ref & result);
void mk_repeat(unsigned n, expr * arg, expr_ref & result);
void mk_sign_extend(unsigned n, expr * arg, expr_ref & result);
void mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result);
void mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result);
void mk_bv_ashr(expr* arg1, expr* arg2, expr_ref& result);
void mk_bv_smod(expr* arg1, expr* arg2, expr_ref& result);
void mk_bv_urem(expr * arg1, expr * arg2, expr_ref & result);
void mk_bv_srem(expr* arg1, expr* arg2, expr_ref& result);
void mk_bv_udiv(expr* arg1, expr* arg2, expr_ref& result);
void mk_bv_sdiv(expr* arg1, expr* arg2, expr_ref& result);
void mk_bv_smod_i(expr* arg1, expr* arg2, expr_ref& result);
void mk_bv_urem_i(expr * arg1, expr * arg2, expr_ref & result);
void mk_bv_srem_i(expr* arg1, expr* arg2, expr_ref& result);
void mk_bv_udiv_i(expr* arg1, expr* arg2, expr_ref& result);
void mk_bv_sdiv_i(expr* arg1, expr* arg2, expr_ref& result);
void mk_bv_nand(unsigned num_args, expr* const* args, expr_ref& result);
void mk_bv_nor(unsigned num_args, expr* const* args, expr_ref& result);
void mk_bv_xnor(unsigned num_args, expr* const* args, expr_ref& result);
void mk_bv_rotate_right(func_decl* f, expr* arg, expr_ref& result);
void mk_bv_rotate_left(func_decl* f, expr* arg, expr_ref& result);
void mk_bv_ext_rotate_right(expr* arg1, expr* arg2, expr_ref& result);
void mk_bv_ext_rotate_left(expr* arg1, expr* arg2, expr_ref& result);
void mk_bv_redor(expr* arg, expr_ref& result);
void mk_bv_redand(expr* arg, expr_ref& result);
void mk_bv_comp(expr* arg1, expr* arg2, expr_ref& result);
bool are_numerals(unsigned num_args, expr * const* args, unsigned& bv_size);
app * mk_numeral(rational const & n, unsigned bv_size);
app * mk_numeral(uint64 n, unsigned bv_size) { return mk_numeral(numeral(n, numeral::ui64()), bv_size); }
app* mk_bv0(unsigned bv_size) { return m_util.mk_numeral(numeral(0), bv_size); }
rational mk_allone(unsigned bv_size) { return rational::power_of_two(bv_size) - numeral(1); }
bool is_minus_one_core(expr * arg) const;
bool is_x_minus_one(expr * arg, expr * & x);
void mk_int2bv(expr * arg, sort* range, expr_ref & result);
void mk_bv2int(expr * arg, sort* range, expr_ref & result);
uint64 n64(expr* e);
bool is_mul_no_overflow(expr* e);
bool is_add_no_overflow(expr* e);
unsigned num_leading_zero_bits(expr* e);
};
#endif /* BV_SIMPLIFIER_PLUGIN_H_ */

View file

@ -1,115 +0,0 @@
/*++
Copyright (c) 2008 Microsoft Corporation
Module Name:
datatype_simplifier_plugin.cpp
Abstract:
Simplifier for algebraic datatypes.
Author:
nbjorner 2008-11-6
--*/
#include "ast/simplifier/datatype_simplifier_plugin.h"
datatype_simplifier_plugin::datatype_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b):
simplifier_plugin(symbol("datatype"), m),
m_util(m),
m_bsimp(b) {
}
datatype_simplifier_plugin::~datatype_simplifier_plugin() {
}
bool datatype_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
set_reduce_invoked();
SASSERT(f->get_family_id() == get_family_id());
switch(f->get_decl_kind()) {
case OP_DT_CONSTRUCTOR: {
return false;
}
case OP_DT_RECOGNISER: {
//
// simplify is_cons(cons(x,y)) -> true
// simplify is_cons(nil) -> false
//
SASSERT(num_args == 1);
if (!is_app_of(args[0], get_family_id(), OP_DT_CONSTRUCTOR)) {
return false;
}
app* a = to_app(args[0]);
func_decl* f1 = a->get_decl();
func_decl* f2 = m_util.get_recognizer_constructor(f);
if (f1 == f2) {
result = m_manager.mk_true();
}
else {
result = m_manager.mk_false();
}
return true;
}
case OP_DT_ACCESSOR: {
//
// simplify head(cons(x,y)) -> x
//
SASSERT(num_args == 1);
if (!is_app_of(args[0], get_family_id(), OP_DT_CONSTRUCTOR)) {
return false;
}
app* a = to_app(args[0]);
func_decl* f1 = a->get_decl();
func_decl* f2 = m_util.get_accessor_constructor(f);
if (f1 != f2) {
return false;
}
ptr_vector<func_decl> const* acc = m_util.get_constructor_accessors(f1);
SASSERT(acc && acc->size() == a->get_num_args());
for (unsigned i = 0; i < acc->size(); ++i) {
if (f == (*acc)[i]) {
// found it.
result = a->get_arg(i);
return true;
}
}
UNREACHABLE();
}
case OP_DT_UPDATE_FIELD:
return false;
default:
UNREACHABLE();
}
return false;
}
bool datatype_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) {
set_reduce_invoked();
if (is_app_of(lhs, get_family_id(), OP_DT_CONSTRUCTOR) &&
is_app_of(rhs, get_family_id(), OP_DT_CONSTRUCTOR)) {
app* a = to_app(lhs);
app* b = to_app(rhs);
if (a->get_decl() != b->get_decl()) {
result = m_manager.mk_false();
return true;
}
expr_ref_vector eqs(m_manager);
for (unsigned i = 0; i < a->get_num_args(); ++i) {
m_bsimp.mk_eq(a->get_arg(i),b->get_arg(i), result);
eqs.push_back(result);
}
m_bsimp.mk_and(eqs.size(), eqs.c_ptr(), result);
return true;
}
// TBD: occurs check, constructor check.
return false;
}

View file

@ -1,42 +0,0 @@
/*++
Copyright (c) 2008 Microsoft Corporation
Module Name:
datatype_simplifier_plugin.h
Abstract:
Simplifier for algebraic datatypes.
Author:
nbjorner 2008-11-6
--*/
#ifndef DATATYPE_SIMPLIFIER_PLUGIN_H_
#define DATATYPE_SIMPLIFIER_PLUGIN_H_
#include "ast/simplifier/basic_simplifier_plugin.h"
#include "ast/datatype_decl_plugin.h"
/**
\brief Simplifier for the arith family.
*/
class datatype_simplifier_plugin : public simplifier_plugin {
datatype_util m_util;
basic_simplifier_plugin & m_bsimp;
public:
datatype_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b);
~datatype_simplifier_plugin();
virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result);
};
#endif /* DATATYPE_SIMPLIFIER_PLUGIN_H_ */

View file

@ -1,224 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
elim_bounds.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-06-28.
Revision History:
--*/
#include "ast/simplifier/elim_bounds.h"
#include "ast/used_vars.h"
#include "util/obj_hashtable.h"
#include "ast/rewriter/var_subst.h"
#include "ast/ast_pp.h"
elim_bounds::elim_bounds(ast_manager & m):
m_manager(m),
m_util(m) {
}
/**
\brief Find bounds of the form
(<= x k)
(<= (+ x (* -1 y)) k)
(<= (+ x (* -1 t)) k)
(<= (+ t (* -1 x)) k)
x and y are a bound variables, t is a ground term and k is a numeral
It also detects >=, and the atom can be negated.
*/
bool elim_bounds::is_bound(expr * n, var * & lower, var * & upper) {
upper = 0;
lower = 0;
bool neg = false;
if (m_manager.is_not(n)) {
n = to_app(n)->get_arg(0);
neg = true;
}
bool le = false;
if (m_util.is_le(n)) {
SASSERT(m_util.is_numeral(to_app(n)->get_arg(1)));
n = to_app(n)->get_arg(0);
le = true;
}
else if (m_util.is_ge(n)) {
SASSERT(m_util.is_numeral(to_app(n)->get_arg(1)));
n = to_app(n)->get_arg(0);
le = false;
}
else {
return false;
}
if (neg)
le = !le;
if (is_var(n)) {
upper = to_var(n);
}
else if (m_util.is_add(n) && to_app(n)->get_num_args() == 2) {
expr * arg1 = to_app(n)->get_arg(0);
expr * arg2 = to_app(n)->get_arg(1);
if (is_var(arg1))
upper = to_var(arg1);
else if (!is_ground(arg1))
return false;
rational k;
bool is_int;
if (m_util.is_mul(arg2) && m_util.is_numeral(to_app(arg2)->get_arg(0), k, is_int) && k.is_minus_one()) {
arg2 = to_app(arg2)->get_arg(1);
if (is_var(arg2))
lower = to_var(arg2);
else if (!is_ground(arg2))
return false; // not supported
}
else {
return false; // not supported
}
}
else {
return false;
}
if (!le)
std::swap(upper, lower);
return true;
}
bool elim_bounds::is_bound(expr * n) {
var * lower, * upper;
return is_bound(n, lower, upper);
}
void elim_bounds::operator()(quantifier * q, expr_ref & r) {
if (!q->is_forall()) {
r = q;
return;
}
expr * n = q->get_expr();
unsigned num_vars = q->get_num_decls();
ptr_buffer<expr> atoms;
if (m_manager.is_or(n))
atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args());
else
atoms.push_back(n);
used_vars m_used_vars;
// collect non-candidates
unsigned sz = atoms.size();
for (unsigned i = 0; i < sz; i++) {
expr * a = atoms[i];
if (!is_bound(a))
m_used_vars.process(a);
}
if (m_used_vars.uses_all_vars(q->get_num_decls())) {
r = q;
return;
}
// collect candidates
obj_hashtable<var> m_lowers;
obj_hashtable<var> m_uppers;
obj_hashtable<var> m_candidate_set;
ptr_buffer<var> m_candidates;
#define ADD_CANDIDATE(V) if (!m_lowers.contains(V) && !m_uppers.contains(V)) { m_candidate_set.insert(V); m_candidates.push_back(V); }
for (unsigned i = 0; i < sz; i++) {
expr * a = atoms[i];
var * lower = 0;
var * upper = 0;
if (is_bound(a, lower, upper)) {
if (lower != 0 && !m_used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) {
ADD_CANDIDATE(lower);
m_lowers.insert(lower);
}
if (upper != 0 && !m_used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) {
ADD_CANDIDATE(upper);
m_uppers.insert(upper);
}
}
}
TRACE("elim_bounds", tout << "candidates:\n"; for (unsigned i = 0; i < m_candidates.size(); i++) tout << mk_pp(m_candidates[i], m_manager) << "\n";);
// remove candidates that have lower and upper bounds
for (unsigned i = 0; i < m_candidates.size(); i++) {
var * v = m_candidates[i];
if (m_lowers.contains(v) && m_uppers.contains(v))
m_candidate_set.erase(v);
}
TRACE("elim_bounds", tout << "candidates after filter:\n"; for (unsigned i = 0; i < m_candidates.size(); i++) tout << mk_pp(m_candidates[i], m_manager) << "\n";);
if (m_candidate_set.empty()) {
r = q;
return;
}
// remove bounds that contain variables in m_candidate_set
unsigned j = 0;
for (unsigned i = 0; i < sz; i++) {
expr * a = atoms[i];
var * lower = 0;
var * upper = 0;
if (is_bound(a, lower, upper) && ((lower != 0 && m_candidate_set.contains(lower)) || (upper != 0 && m_candidate_set.contains(upper))))
continue;
atoms[j] = a;
j++;
}
atoms.resize(j);
expr * new_body = 0;
switch (atoms.size()) {
case 0:
r = m_manager.mk_false();
TRACE("elim_bounds", tout << mk_pp(q, m_manager) << "\n" << mk_pp(r, m_manager) << "\n";);
return;
case 1:
new_body = atoms[0];
break;
default:
new_body = m_manager.mk_or(atoms.size(), atoms.c_ptr());
break;
}
quantifier_ref new_q(m_manager);
new_q = m_manager.update_quantifier(q, new_body);
elim_unused_vars(m_manager, new_q, params_ref(), r);
TRACE("elim_bounds", tout << mk_pp(q, m_manager) << "\n" << mk_pp(r, m_manager) << "\n";);
}
bool elim_bounds_star::visit_quantifier(quantifier * q) {
if (!q->is_forall() || q->get_num_patterns() != 0)
return true;
bool visited = true;
visit(q->get_expr(), visited);
return visited;
}
void elim_bounds_star::reduce1_quantifier(quantifier * q) {
if (!q->is_forall() || q->get_num_patterns() != 0) {
cache_result(q, q, 0);
return;
}
quantifier_ref new_q(m);
expr * new_body = 0;
proof * new_pr;
get_cached(q->get_expr(), new_body, new_pr);
new_q = m.update_quantifier(q, new_body);
expr_ref r(m);
m_elim(new_q, r);
if (q == r.get()) {
cache_result(q, q, 0);
return;
}
proof_ref pr(m);
if (m.fine_grain_proofs())
pr = m.mk_rewrite(q, r); // TODO: improve justification
cache_result(q, r, pr);
}

View file

@ -1,39 +0,0 @@
/*++
Copyright (c) 2015 Microsoft Corporation
Module Name:
fpa_simplifier_plugin.cpp
Abstract:
Simplifier for the floating-point theory
Author:
Christoph (cwinter) 2015-01-14
--*/
#include "ast/simplifier/fpa_simplifier_plugin.h"
fpa_simplifier_plugin::fpa_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b) :
simplifier_plugin(symbol("fpa"), m),
m_util(m),
m_rw(m) {}
fpa_simplifier_plugin::~fpa_simplifier_plugin() {}
bool fpa_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
set_reduce_invoked();
SASSERT(f->get_family_id() == get_family_id());
return m_rw.mk_app_core(f, num_args, args, result) != BR_FAILED;
}
bool fpa_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) {
set_reduce_invoked();
return m_rw.mk_eq_core(lhs, rhs, result) != BR_FAILED;
}

View file

@ -1,39 +0,0 @@
/*++
Copyright (c) 2015 Microsoft Corporation
Module Name:
fpa_simplifier_plugin.h
Abstract:
Simplifier for the floating-point theory
Author:
Christoph (cwinter) 2015-01-14
--*/
#ifndef FPA_SIMPLIFIER_PLUGIN_H_
#define FPA_SIMPLIFIER_PLUGIN_H_
#include "ast/simplifier/basic_simplifier_plugin.h"
#include "ast/fpa_decl_plugin.h"
#include "ast/rewriter/fpa_rewriter.h"
class fpa_simplifier_plugin : public simplifier_plugin {
fpa_util m_util;
fpa_rewriter m_rw;
public:
fpa_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b);
~fpa_simplifier_plugin();
virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result);
};
#endif /* FPA_SIMPLIFIER_PLUGIN_H_ */

View file

@ -1,835 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
poly_simplifier_plugin.cpp
Abstract:
Abstract class for families that have polynomials.
Author:
Leonardo (leonardo) 2008-01-08
--*/
#include "ast/simplifier/poly_simplifier_plugin.h"
#include "ast/ast_pp.h"
#include "ast/ast_util.h"
#include "ast/ast_smt2_pp.h"
#include "ast/ast_ll_pp.h"
poly_simplifier_plugin::poly_simplifier_plugin(symbol const & fname, ast_manager & m, decl_kind add, decl_kind mul, decl_kind uminus, decl_kind sub,
decl_kind num):
simplifier_plugin(fname, m),
m_ADD(add),
m_MUL(mul),
m_SUB(sub),
m_UMINUS(uminus),
m_NUM(num),
m_curr_sort(0),
m_curr_sort_zero(0) {
}
expr * poly_simplifier_plugin::mk_add(unsigned num_args, expr * const * args) {
SASSERT(num_args > 0);
#ifdef Z3DEBUG
// check for incorrect use of mk_add
for (unsigned i = 0; i < num_args; i++) {
SASSERT(!is_zero(args[i]));
}
#endif
if (num_args == 1)
return args[0];
else
return m_manager.mk_app(m_fid, m_ADD, num_args, args);
}
expr * poly_simplifier_plugin::mk_mul(unsigned num_args, expr * const * args) {
SASSERT(num_args > 0);
#ifdef Z3DEBUG
// check for incorrect use of mk_mul
set_curr_sort(args[0]);
SASSERT(!is_zero(args[0]));
numeral k;
for (unsigned i = 0; i < num_args; i++) {
SASSERT(!is_numeral(args[i], k) || !k.is_one());
SASSERT(i == 0 || !is_numeral(args[i]));
}
#endif
if (num_args == 1)
return args[0];
else if (num_args == 2)
return m_manager.mk_app(m_fid, m_MUL, args[0], args[1]);
else if (is_numeral(args[0]))
return m_manager.mk_app(m_fid, m_MUL, args[0], m_manager.mk_app(m_fid, m_MUL, num_args - 1, args+1));
else
return m_manager.mk_app(m_fid, m_MUL, num_args, args);
}
expr * poly_simplifier_plugin::mk_mul(numeral const & c, expr * body) {
numeral c_prime, d;
c_prime = norm(c);
if (c_prime.is_zero())
return 0;
if (body == 0)
return mk_numeral(c_prime);
if (c_prime.is_one())
return body;
if (is_numeral(body, d)) {
c_prime = norm(c_prime*d);
if (c_prime.is_zero())
return 0;
return mk_numeral(c_prime);
}
set_curr_sort(body);
expr * args[2] = { mk_numeral(c_prime), body };
return mk_mul(2, args);
}
/**
\brief Traverse args, and copy the non-numeral exprs to result, and accumulate the
value of the numerals in k.
*/
void poly_simplifier_plugin::process_monomial(unsigned num_args, expr * const * args, numeral & k, ptr_buffer<expr> & result) {
rational v;
for (unsigned i = 0; i < num_args; i++) {
expr * arg = args[i];
if (is_numeral(arg, v))
k *= v;
else
result.push_back(arg);
}
}
#ifdef Z3DEBUG
/**
\brief Return true if m is a wellformed monomial.
*/
bool poly_simplifier_plugin::wf_monomial(expr * m) const {
SASSERT(!is_add(m));
if (is_mul(m)) {
app * curr = to_app(m);
expr * pp = 0;
if (is_numeral(curr->get_arg(0)))
pp = curr->get_arg(1);
else
pp = curr;
if (is_mul(pp)) {
for (unsigned i = 0; i < to_app(pp)->get_num_args(); i++) {
expr * arg = to_app(pp)->get_arg(i);
CTRACE("wf_monomial_bug", is_mul(arg),
tout << "m: " << mk_ismt2_pp(m, m_manager) << "\n";
tout << "pp: " << mk_ismt2_pp(pp, m_manager) << "\n";
tout << "arg: " << mk_ismt2_pp(arg, m_manager) << "\n";
tout << "i: " << i << "\n";
);
SASSERT(!is_mul(arg));
SASSERT(!is_numeral(arg));
}
}
}
return true;
}
/**
\brief Return true if m is a wellformed polynomial.
*/
bool poly_simplifier_plugin::wf_polynomial(expr * m) const {
if (is_add(m)) {
for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) {
expr * arg = to_app(m)->get_arg(i);
SASSERT(!is_add(arg));
SASSERT(wf_monomial(arg));
}
}
else if (is_mul(m)) {
SASSERT(wf_monomial(m));
}
return true;
}
#endif
/**
\brief Functor used to sort the elements of a monomial.
Force numeric constants to be in the beginning.
*/
struct monomial_element_lt_proc {
poly_simplifier_plugin & m_plugin;
monomial_element_lt_proc(poly_simplifier_plugin & p):m_plugin(p) {}
bool operator()(expr * m1, expr * m2) const {
SASSERT(!m_plugin.is_numeral(m1) || !m_plugin.is_numeral(m2));
if (m_plugin.is_numeral(m1))
return true;
if (m_plugin.is_numeral(m2))
return false;
return m1->get_id() < m2->get_id();
}
};
/**
\brief Create a monomial (* args).
*/
void poly_simplifier_plugin::mk_monomial(unsigned num_args, expr * * args, expr_ref & result) {
switch(num_args) {
case 0:
result = mk_one();
break;
case 1:
result = args[0];
break;
default:
std::stable_sort(args, args + num_args, monomial_element_lt_proc(*this));
result = mk_mul(num_args, args);
SASSERT(wf_monomial(result));
break;
}
}
/**
\brief Return the body of the monomial. That is, the monomial without a coefficient.
Examples: (* 2 (* x y)) ==> (* x y)
(* x x) ==> (* x x)
x ==> x
10 ==> 10
*/
expr * poly_simplifier_plugin::get_monomial_body(expr * m) {
TRACE("get_monomial_body_bug", tout << mk_pp(m, m_manager) << "\n";);
SASSERT(wf_monomial(m));
if (!is_mul(m))
return m;
if (is_numeral(to_app(m)->get_arg(0)))
return to_app(m)->get_arg(1);
return m;
}
inline bool is_essentially_var(expr * n, family_id fid) {
SASSERT(is_var(n) || is_app(n));
return is_var(n) || to_app(n)->get_family_id() != fid;
}
/**
\brief Hack for ordering monomials.
We want an order << where
- (* c1 m1) << (* c2 m2) when m1->get_id() < m2->get_id(), and c1 and c2 are numerals.
- c << m when c is a numeral, and m is not.
So, this method returns -1 for numerals, and the id of the body of the monomial
*/
int poly_simplifier_plugin::get_monomial_body_order(expr * m) {
if (is_essentially_var(m, m_fid)) {
return m->get_id();
}
else if (is_mul(m)) {
if (is_numeral(to_app(m)->get_arg(0)))
return to_app(m)->get_arg(1)->get_id();
else
return m->get_id();
}
else if (is_numeral(m)) {
return -1;
}
else {
return m->get_id();
}
}
void poly_simplifier_plugin::get_monomial_coeff(expr * m, numeral & result) {
SASSERT(!is_numeral(m));
SASSERT(wf_monomial(m));
if (!is_mul(m))
result = numeral::one();
else if (is_numeral(to_app(m)->get_arg(0), result))
return;
else
result = numeral::one();
}
/**
\brief Return true if n1 and n2 can be written as k1 * t and k2 * t, where k1 and
k2 are numerals, or n1 and n2 are both numerals.
*/
bool poly_simplifier_plugin::eq_monomials_modulo_k(expr * n1, expr * n2) {
bool is_num1 = is_numeral(n1);
bool is_num2 = is_numeral(n2);
if (is_num1 != is_num2)
return false;
if (is_num1 && is_num2)
return true;
return get_monomial_body(n1) == get_monomial_body(n2);
}
/**
\brief Return (k1 + k2) * t (or (k1 - k2) * t when inv = true), where n1 = k1 * t, and n2 = k2 * t
Return false if the monomials cancel each other.
*/
bool poly_simplifier_plugin::merge_monomials(bool inv, expr * n1, expr * n2, expr_ref & result) {
numeral k1;
numeral k2;
bool is_num1 = is_numeral(n1, k1);
bool is_num2 = is_numeral(n2, k2);
SASSERT(is_num1 == is_num2);
if (!is_num1 && !is_num2) {
get_monomial_coeff(n1, k1);
get_monomial_coeff(n2, k2);
SASSERT(eq_monomials_modulo_k(n1, n2));
}
if (inv)
k1 -= k2;
else
k1 += k2;
if (k1.is_zero())
return false;
if (is_num1 && is_num2) {
result = mk_numeral(k1);
}
else {
expr * b = get_monomial_body(n1);
if (k1.is_one())
result = b;
else
result = m_manager.mk_app(m_fid, m_MUL, mk_numeral(k1), b);
}
TRACE("merge_monomials", tout << mk_pp(n1, m_manager) << "\n" << mk_pp(n2, m_manager) << "\n" << mk_pp(result, m_manager) << "\n";);
return true;
}
/**
\brief Return a monomial equivalent to -n.
*/
void poly_simplifier_plugin::inv_monomial(expr * n, expr_ref & result) {
set_curr_sort(n);
SASSERT(wf_monomial(n));
rational v;
SASSERT(n != 0);
TRACE("inv_monomial_bug", tout << "n:\n" << mk_ismt2_pp(n, m_manager) << "\n";);
if (is_numeral(n, v)) {
TRACE("inv_monomial_bug", tout << "is numeral\n";);
v.neg();
result = mk_numeral(v);
}
else {
TRACE("inv_monomial_bug", tout << "is not numeral\n";);
numeral k;
get_monomial_coeff(n, k);
expr * b = get_monomial_body(n);
k.neg();
if (k.is_one())
result = b;
else
result = m_manager.mk_app(m_fid, m_MUL, mk_numeral(k), b);
}
}
/**
\brief Add a monomial n to result.
*/
template<bool Inv>
void poly_simplifier_plugin::add_monomial_core(expr * n, expr_ref_vector & result) {
if (is_zero(n))
return;
if (Inv) {
expr_ref n_prime(m_manager);
inv_monomial(n, n_prime);
result.push_back(n_prime);
}
else {
result.push_back(n);
}
}
void poly_simplifier_plugin::add_monomial(bool inv, expr * n, expr_ref_vector & result) {
if (inv)
add_monomial_core<true>(n, result);
else
add_monomial_core<false>(n, result);
}
/**
\brief Copy the monomials in n to result. The monomials are inverted if inv is true.
Equivalent monomials are merged.
*/
template<bool Inv>
void poly_simplifier_plugin::process_sum_of_monomials_core(expr * n, expr_ref_vector & result) {
SASSERT(wf_polynomial(n));
if (is_add(n)) {
for (unsigned i = 0; i < to_app(n)->get_num_args(); i++)
add_monomial_core<Inv>(to_app(n)->get_arg(i), result);
}
else {
add_monomial_core<Inv>(n, result);
}
}
void poly_simplifier_plugin::process_sum_of_monomials(bool inv, expr * n, expr_ref_vector & result) {
if (inv)
process_sum_of_monomials_core<true>(n, result);
else
process_sum_of_monomials_core<false>(n, result);
}
/**
\brief Copy the (non-numeral) monomials in n to result. The monomials are inverted if inv is true.
Equivalent monomials are merged. The constant (numeral) monomials are accumulated in k.
*/
void poly_simplifier_plugin::process_sum_of_monomials(bool inv, expr * n, expr_ref_vector & result, numeral & k) {
SASSERT(wf_polynomial(n));
numeral val;
if (is_add(n)) {
for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) {
expr * arg = to_app(n)->get_arg(i);
if (is_numeral(arg, val)) {
k += inv ? -val : val;
}
else {
add_monomial(inv, arg, result);
}
}
}
else if (is_numeral(n, val)) {
k += inv ? -val : val;
}
else {
add_monomial(inv, n, result);
}
}
/**
\brief Functor used to sort monomials.
Force numeric constants to be in the beginning of a polynomial.
*/
struct monomial_lt_proc {
poly_simplifier_plugin & m_plugin;
monomial_lt_proc(poly_simplifier_plugin & p):m_plugin(p) {}
bool operator()(expr * m1, expr * m2) const {
return m_plugin.get_monomial_body_order(m1) < m_plugin.get_monomial_body_order(m2);
}
};
void poly_simplifier_plugin::mk_sum_of_monomials_core(unsigned sz, expr ** ms, expr_ref & result) {
switch (sz) {
case 0:
result = mk_zero();
break;
case 1:
result = ms[0];
break;
default:
result = mk_add(sz, ms);
break;
}
}
/**
\brief Return true if m is essentially a variable, or is of the form (* c x),
where c is a numeral and x is essentially a variable.
Store the "variable" in x.
*/
bool poly_simplifier_plugin::is_simple_monomial(expr * m, expr * & x) {
if (is_essentially_var(m, m_fid)) {
x = m;
return true;
}
if (is_app(m) && to_app(m)->get_num_args() == 2) {
expr * arg1 = to_app(m)->get_arg(0);
expr * arg2 = to_app(m)->get_arg(1);
if (is_numeral(arg1) && is_essentially_var(arg2, m_fid)) {
x = arg2;
return true;
}
}
return false;
}
/**
\brief Return true if all monomials are simple, and each "variable" occurs only once.
The method assumes the monomials were sorted using monomial_lt_proc.
*/
bool poly_simplifier_plugin::is_simple_sum_of_monomials(expr_ref_vector & monomials) {
expr * last_var = 0;
expr * curr_var = 0;
unsigned size = monomials.size();
for (unsigned i = 0; i < size; i++) {
expr * m = monomials.get(i);
if (!is_simple_monomial(m, curr_var))
return false;
if (curr_var == last_var)
return false;
last_var = curr_var;
}
return true;
}
/**
\brief Store in result the sum of the given monomials.
*/
void poly_simplifier_plugin::mk_sum_of_monomials(expr_ref_vector & monomials, expr_ref & result) {
switch (monomials.size()) {
case 0:
result = mk_zero();
break;
case 1:
result = monomials.get(0);
break;
default: {
TRACE("mk_sum_sort", tout << "before\n"; for (unsigned i = 0; i < monomials.size(); i++) tout << mk_ll_pp(monomials.get(i), m_manager) << "\n";);
std::stable_sort(monomials.c_ptr(), monomials.c_ptr() + monomials.size(), monomial_lt_proc(*this));
TRACE("mk_sum_sort", tout << "after\n"; for (unsigned i = 0; i < monomials.size(); i++) tout << mk_ll_pp(monomials.get(i), m_manager) << "\n";);
if (is_simple_sum_of_monomials(monomials)) {
mk_sum_of_monomials_core(monomials.size(), monomials.c_ptr(), result);
return;
}
ptr_buffer<expr> new_monomials;
expr * last_body = 0;
numeral last_coeff;
numeral coeff;
unsigned sz = monomials.size();
for (unsigned i = 0; i < sz; i++) {
expr * m = monomials.get(i);
expr * body = 0;
if (!is_numeral(m, coeff)) {
body = get_monomial_body(m);
get_monomial_coeff(m, coeff);
}
if (last_body == body) {
last_coeff += coeff;
continue;
}
expr * new_m = mk_mul(last_coeff, last_body);
if (new_m)
new_monomials.push_back(new_m);
last_body = body;
last_coeff = coeff;
}
expr * new_m = mk_mul(last_coeff, last_body);
if (new_m)
new_monomials.push_back(new_m);
TRACE("mk_sum", for (unsigned i = 0; i < monomials.size(); i++) tout << mk_pp(monomials.get(i), m_manager) << "\n";
tout << "======>\n";
for (unsigned i = 0; i < new_monomials.size(); i++) tout << mk_pp(new_monomials.get(i), m_manager) << "\n";);
mk_sum_of_monomials_core(new_monomials.size(), new_monomials.c_ptr(), result);
break;
} }
}
/**
\brief Auxiliary template for mk_add_core
*/
template<bool Inv>
void poly_simplifier_plugin::mk_add_core_core(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args >= 2);
expr_ref_vector monomials(m_manager);
process_sum_of_monomials_core<false>(args[0], monomials);
for (unsigned i = 1; i < num_args; i++) {
process_sum_of_monomials_core<Inv>(args[i], monomials);
}
TRACE("mk_add_core_bug",
for (unsigned i = 0; i < monomials.size(); i++) {
SASSERT(monomials.get(i) != 0);
tout << mk_ismt2_pp(monomials.get(i), m_manager) << "\n";
});
mk_sum_of_monomials(monomials, result);
}
/**
\brief Return a sum of monomials. The method assume that each arg in args is a sum of monomials.
If inv is true, then all but the first argument in args are inverted.
*/
void poly_simplifier_plugin::mk_add_core(bool inv, unsigned num_args, expr * const * args, expr_ref & result) {
TRACE("mk_add_core_bug",
for (unsigned i = 0; i < num_args; i++) {
SASSERT(args[i] != 0);
tout << mk_ismt2_pp(args[i], m_manager) << "\n";
});
switch (num_args) {
case 0:
result = mk_zero();
break;
case 1:
result = args[0];
break;
default:
if (inv)
mk_add_core_core<true>(num_args, args, result);
else
mk_add_core_core<false>(num_args, args, result);
break;
}
}
void poly_simplifier_plugin::mk_add(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args > 0);
set_curr_sort(args[0]);
mk_add_core(false, num_args, args, result);
}
void poly_simplifier_plugin::mk_add(expr * arg1, expr * arg2, expr_ref & result) {
expr * args[2] = { arg1, arg2 };
mk_add(2, args, result);
}
void poly_simplifier_plugin::mk_sub(unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(num_args > 0);
set_curr_sort(args[0]);
mk_add_core(true, num_args, args, result);
}
void poly_simplifier_plugin::mk_sub(expr * arg1, expr * arg2, expr_ref & result) {
expr * args[2] = { arg1, arg2 };
mk_sub(2, args, result);
}
void poly_simplifier_plugin::mk_uminus(expr * arg, expr_ref & result) {
set_curr_sort(arg);
rational v;
if (is_numeral(arg, v)) {
v.neg();
result = mk_numeral(v);
}
else {
expr_ref zero(mk_zero(), m_manager);
mk_sub(zero.get(), arg, result);
}
}
/**
\brief Add monomial n to result, the coeff of n is stored in k.
*/
void poly_simplifier_plugin::append_to_monomial(expr * n, numeral & k, ptr_buffer<expr> & result) {
SASSERT(wf_monomial(n));
rational val;
if (is_numeral(n, val)) {
k *= val;
return;
}
get_monomial_coeff(n, val);
k *= val;
n = get_monomial_body(n);
unsigned hd = result.size();
result.push_back(n);
while (hd < result.size()) {
n = result[hd];
if (is_mul(n)) {
result[hd] = result.back();
result.pop_back();
for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) {
result.push_back(to_app(n)->get_arg(i));
}
}
else if (is_numeral(n, val)) {
k *= val;
result[hd] = result.back();
result.pop_back();
}
else {
++hd;
}
}
}
/**
\brief Return a sum of monomials that is equivalent to (* args[0] ... args[num_args-1]).
This method assumes that each arg[i] is a sum of monomials.
*/
void poly_simplifier_plugin::mk_mul(unsigned num_args, expr * const * args, expr_ref & result) {
if (num_args == 1) {
result = args[0];
return;
}
rational val;
if (num_args == 2 && is_numeral(args[0], val) && is_essentially_var(args[1], m_fid)) {
if (val.is_one())
result = args[1];
else if (val.is_zero())
result = args[0];
else
result = mk_mul(num_args, args);
return;
}
if (num_args == 2 && is_essentially_var(args[0], m_fid) && is_numeral(args[1], val)) {
if (val.is_one())
result = args[0];
else if (val.is_zero())
result = args[1];
else {
expr * inv_args[2] = { args[1], args[0] };
result = mk_mul(2, inv_args);
}
return;
}
TRACE("mk_mul_bug",
for (unsigned i = 0; i < num_args; i++) {
tout << mk_pp(args[i], m_manager) << "\n";
});
set_curr_sort(args[0]);
buffer<unsigned> szs;
buffer<unsigned> it;
vector<ptr_vector<expr> > sums;
for (unsigned i = 0; i < num_args; i ++) {
it.push_back(0);
expr * arg = args[i];
SASSERT(wf_polynomial(arg));
sums.push_back(ptr_vector<expr>());
ptr_vector<expr> & v = sums.back();
if (is_add(arg)) {
v.append(to_app(arg)->get_num_args(), to_app(arg)->get_args());
}
else {
v.push_back(arg);
}
szs.push_back(v.size());
}
expr_ref_vector monomials(m_manager);
do {
rational k(1);
ptr_buffer<expr> m;
for (unsigned i = 0; i < num_args; i++) {
ptr_vector<expr> & v = sums[i];
expr * arg = v[it[i]];
TRACE("mk_mul_bug", tout << "k: " << k << " arg: " << mk_pp(arg, m_manager) << "\n";);
append_to_monomial(arg, k, m);
TRACE("mk_mul_bug", tout << "after k: " << k << "\n";);
}
expr_ref num(m_manager);
if (!k.is_zero() && !k.is_one()) {
num = mk_numeral(k);
m.push_back(num);
// bit-vectors can normalize
// to 1 during
// internalization.
if (is_numeral(num, k) && k.is_one()) {
m.pop_back();
}
}
if (!k.is_zero()) {
expr_ref new_monomial(m_manager);
TRACE("mk_mul_bug",
for (unsigned i = 0; i < m.size(); i++) {
tout << mk_pp(m[i], m_manager) << "\n";
});
mk_monomial(m.size(), m.c_ptr(), new_monomial);
TRACE("mk_mul_bug", tout << "new_monomial:\n" << mk_pp(new_monomial, m_manager) << "\n";);
add_monomial_core<false>(new_monomial, monomials);
}
}
while (product_iterator_next(szs.size(), szs.c_ptr(), it.c_ptr()));
mk_sum_of_monomials(monomials, result);
}
void poly_simplifier_plugin::mk_mul(expr * arg1, expr * arg2, expr_ref & result) {
expr * args[2] = { arg1, arg2 };
mk_mul(2, args, result);
}
bool poly_simplifier_plugin::reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result) {
set_reduce_invoked();
unsigned i = 0;
for (; i < num_args; i++)
if (!is_numeral(args[i]))
break;
if (i == num_args) {
// all arguments are numerals
// check if arguments are different...
ptr_buffer<expr> buffer;
buffer.append(num_args, args);
std::sort(buffer.begin(), buffer.end(), ast_lt_proc());
for (unsigned i = 0; i < num_args; i++) {
if (i > 0 && buffer[i] == buffer[i-1]) {
result = m_manager.mk_false();
return true;
}
}
result = m_manager.mk_true();
return true;
}
return false;
}
bool poly_simplifier_plugin::reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result) {
set_reduce_invoked();
if (is_decl_of(f, m_fid, m_ADD)) {
SASSERT(num_args > 0);
set_curr_sort(args[0]);
expr_ref_buffer args1(m_manager);
for (unsigned i = 0; i < num_args; ++i) {
expr * arg = args[i];
rational m = norm(mults[i]);
if (m.is_zero()) {
// skip
}
else if (m.is_one()) {
args1.push_back(arg);
}
else {
expr_ref k(m_manager);
k = mk_numeral(m);
expr_ref new_arg(m_manager);
mk_mul(k, args[i], new_arg);
args1.push_back(new_arg);
}
}
if (args1.empty()) {
result = mk_zero();
}
else {
mk_add(args1.size(), args1.c_ptr(), result);
}
return true;
}
else {
return simplifier_plugin::reduce(f, num_args, mults, args, result);
}
}
/**
\brief Return true if n is can be put into the form (+ v t) or (+ (- v) t)
\c inv = true will contain true if (- v) is found, and false otherwise.
*/
bool poly_simplifier_plugin::is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) {
if (!is_add(n) || is_ground(n))
return false;
ptr_buffer<expr> args;
v = 0;
expr * curr = to_app(n);
bool stop = false;
inv = false;
while (!stop) {
expr * arg;
expr * neg_arg;
if (is_add(curr)) {
arg = to_app(curr)->get_arg(0);
curr = to_app(curr)->get_arg(1);
}
else {
arg = curr;
stop = true;
}
if (is_ground(arg)) {
TRACE("model_checker_bug", tout << "pushing:\n" << mk_pp(arg, m_manager) << "\n";);
args.push_back(arg);
}
else if (is_var(arg)) {
if (v != 0)
return false; // already found variable
v = to_var(arg);
}
else if (is_times_minus_one(arg, neg_arg) && is_var(neg_arg)) {
if (v != 0)
return false; // already found variable
v = to_var(neg_arg);
inv = true;
}
else {
return false; // non ground term.
}
}
if (v == 0)
return false; // did not find variable
SASSERT(!args.empty());
mk_add(args.size(), args.c_ptr(), t);
return true;
}

View file

@ -1,155 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
poly_simplifier_plugin.h
Abstract:
Abstract class for families that have polynomials.
Author:
Leonardo (leonardo) 2008-01-08
--*/
#ifndef POLY_SIMPLIFIER_PLUGIN_H_
#define POLY_SIMPLIFIER_PLUGIN_H_
#include "ast/simplifier/simplifier_plugin.h"
/**
\brief Abstract class that provides simplification functions for polynomials.
*/
class poly_simplifier_plugin : public simplifier_plugin {
protected:
typedef rational numeral;
decl_kind m_ADD;
decl_kind m_MUL;
decl_kind m_SUB;
decl_kind m_UMINUS;
decl_kind m_NUM;
sort * m_curr_sort;
expr * m_curr_sort_zero;
expr * mk_add(unsigned num_args, expr * const * args);
expr * mk_add(expr * arg1, expr * arg2) { expr * args[2] = { arg1, arg2 }; return mk_add(2, args); }
expr * mk_mul(unsigned num_args, expr * const * args);
expr * mk_mul(expr * arg1, expr * arg2) { expr * args[2] = { arg1, arg2 }; return mk_mul(2, args); }
// expr * mk_sub(unsigned num_args, expr * const * args) { return m_manager.mk_app(m_fid, m_SUB, num_args, args); }
expr * mk_uminus(expr * arg) { return m_manager.mk_app(m_fid, m_UMINUS, arg); }
void process_monomial(unsigned num_args, expr * const * args, numeral & k, ptr_buffer<expr> & result);
void mk_monomial(unsigned num_args, expr * * args, expr_ref & result);
bool eq_monomials_modulo_k(expr * n1, expr * n2);
bool merge_monomials(bool inv, expr * n1, expr * n2, expr_ref & result);
template<bool Inv>
void add_monomial_core(expr * n, expr_ref_vector & result);
void add_monomial(bool inv, expr * n, expr_ref_vector & result);
template<bool Inv>
void process_sum_of_monomials_core(expr * n, expr_ref_vector & result);
void process_sum_of_monomials(bool inv, expr * n, expr_ref_vector & result);
void process_sum_of_monomials(bool inv, expr * n, expr_ref_vector & result, numeral & k);
void mk_sum_of_monomials(expr_ref_vector & monomials, expr_ref & result);
template<bool Inv>
void mk_add_core_core(unsigned num_args, expr * const * args, expr_ref & result);
void mk_add_core(bool inv, unsigned num_args, expr * const * args, expr_ref & result);
void append_to_monomial(expr * n, numeral & k, ptr_buffer<expr> & result);
expr * mk_mul(numeral const & c, expr * body);
void mk_sum_of_monomials_core(unsigned sz, expr ** ms, expr_ref & result);
bool is_simple_sum_of_monomials(expr_ref_vector & monomials);
bool is_simple_monomial(expr * m, expr * & x);
public:
poly_simplifier_plugin(symbol const & fname, ast_manager & m, decl_kind add, decl_kind mul, decl_kind uminus, decl_kind sub, decl_kind num);
virtual ~poly_simplifier_plugin() {}
/**
\brief Return true if the given expression is a numeral, and store its value in \c val.
*/
virtual bool is_numeral(expr * n, numeral & val) const = 0;
bool is_numeral(expr * n) const { return is_app_of(n, m_fid, m_NUM); }
bool is_zero(expr * n) const {
SASSERT(m_curr_sort_zero != 0);
SASSERT(m_manager.get_sort(n) == m_manager.get_sort(m_curr_sort_zero));
return n == m_curr_sort_zero;
}
bool is_zero_safe(expr * n) {
set_curr_sort(m_manager.get_sort(n));
return is_zero(n);
}
virtual bool is_minus_one(expr * n) const = 0;
virtual expr * get_zero(sort * s) const = 0;
/**
\brief Return true if n is of the form (* -1 r)
*/
bool is_times_minus_one(expr * n, expr * & r) const {
if (is_mul(n) && to_app(n)->get_num_args() == 2 && is_minus_one(to_app(n)->get_arg(0))) {
r = to_app(n)->get_arg(1);
return true;
}
return false;
}
/**
\brief Return true if n is of the form: a <= b or a >= b.
*/
virtual bool is_le_ge(expr * n) const = 0;
/**
\brief Return a constant representing the giving numeral and sort m_curr_sort.
*/
virtual app * mk_numeral(numeral const & n) = 0;
app * mk_zero() { return mk_numeral(numeral::zero()); }
app * mk_one() { return mk_numeral(numeral::one()); }
app * mk_minus_one() { return mk_numeral(numeral::minus_one()); }
/**
\brief Normalize the given numeral with respect to m_curr_sort
*/
virtual numeral norm(numeral const & n) = 0;
void set_curr_sort(sort * s) {
if (s != m_curr_sort) {
// avoid virtual function call
m_curr_sort = s;
m_curr_sort_zero = get_zero(m_curr_sort);
}
}
void set_curr_sort(expr * n) { set_curr_sort(m_manager.get_sort(n)); }
bool is_add(expr const * n) const { return is_app_of(n, m_fid, m_ADD); }
bool is_mul(expr const * n) const { return is_app_of(n, m_fid, m_MUL); }
void mk_add(unsigned num_args, expr * const * args, expr_ref & result);
void mk_add(expr * arg1, expr * arg2, expr_ref & result);
void mk_sub(unsigned num_args, expr * const * args, expr_ref & result);
void mk_sub(expr * arg1, expr * arg2, expr_ref & result);
void mk_uminus(expr * arg, expr_ref & result);
void mk_mul(unsigned num_args, expr * const * args, expr_ref & result);
void mk_mul(expr * arg1, expr * arg2, expr_ref & result);
virtual bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result);
virtual bool reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result);
virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
return simplifier_plugin::reduce(f, num_args, args, result);
}
expr * get_monomial_body(expr * m);
int get_monomial_body_order(expr * m);
void get_monomial_coeff(expr * m, numeral & result);
void inv_monomial(expr * n, expr_ref & result);
bool is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t);
#ifdef Z3DEBUG
bool wf_monomial(expr * m) const;
bool wf_polynomial(expr * m) const;
#endif
};
#endif /* POLY_SIMPLIFIER_PLUGIN_H_ */

View file

@ -1,220 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
push_app_ite.cpp
Abstract:
TODO: Write a better ite lifter
Author:
Leonardo de Moura (leonardo) 2008-05-14.
Revision History:
--*/
#include "ast/simplifier/push_app_ite.h"
#include "ast/ast_pp.h"
push_app_ite::push_app_ite(simplifier & s, bool conservative):
simplifier(s.get_manager()),
m_conservative(conservative) {
borrow_plugins(s);
}
push_app_ite::~push_app_ite() {
// the plugins were borrowed. So, release ownership.
m_plugins.release();
}
int push_app_ite::has_ite_arg(unsigned num_args, expr * const * args) {
for (unsigned i = 0; i < num_args; i++)
if (m.is_ite(args[i]))
return i;
return -1;
}
void push_app_ite::apply(func_decl * decl, unsigned num_args, expr * const * args, expr_ref & r) {
TRACE("push_app_ite", tout << "pushing app...\n";);
int ite_arg_idx = has_ite_arg(num_args, args);
if (ite_arg_idx < 0) {
mk_app(decl, num_args, args, r);
return;
}
app * ite = to_app(args[ite_arg_idx]);
expr * c = ite->get_arg(0);
expr * t = ite->get_arg(1);
expr * e = ite->get_arg(2);
expr ** args_prime = const_cast<expr**>(args);
expr * old = args_prime[ite_arg_idx];
args_prime[ite_arg_idx] = t;
expr_ref t_new(m);
apply(decl, num_args, args_prime, t_new);
args_prime[ite_arg_idx] = e;
expr_ref e_new(m);
apply(decl, num_args, args_prime, e_new);
args_prime[ite_arg_idx] = old;
expr * new_args[3] = { c, t_new, e_new };
mk_app(ite->get_decl(), 3, new_args, r);
}
/**
\brief Default (conservative) implementation. Return true if there one and only one ite-term argument.
*/
bool push_app_ite::is_target(func_decl * decl, unsigned num_args, expr * const * args) {
if (m.is_ite(decl))
return false;
bool found_ite = false;
for (unsigned i = 0; i < num_args; i++) {
if (m.is_ite(args[i]) && !m.is_bool(args[i])) {
if (found_ite) {
if (m_conservative)
return false;
}
else {
found_ite = true;
}
}
}
CTRACE("push_app_ite", found_ite, tout << "found target for push app ite:\n";
tout << decl->get_name();
for (unsigned i = 0; i < num_args; i++) tout << " " << mk_pp(args[i], m);
tout << "\n";);
return found_ite;
}
void push_app_ite::operator()(expr * s, expr_ref & r, proof_ref & p) {
expr * result;
proof * result_proof;
reduce_core(s);
get_cached(s, result, result_proof);
r = result;
switch (m.proof_mode()) {
case PGM_DISABLED:
p = m.mk_undef_proof();
break;
case PGM_COARSE:
if (result == s)
p = m.mk_reflexivity(s);
else
p = m.mk_rewrite_star(s, result, 0, 0);
break;
case PGM_FINE:
if (result == s)
p = m.mk_reflexivity(s);
else
p = result_proof;
break;
}
}
void push_app_ite::reduce_core(expr * n) {
if (!is_cached(n)) {
unsigned sz = m_todo.size();
m_todo.push_back(n);
while (m_todo.size() != sz) {
expr * n = m_todo.back();
if (is_cached(n))
m_todo.pop_back();
else if (visit_children(n)) {
m_todo.pop_back();
reduce1(n);
}
}
}
}
bool push_app_ite::visit_children(expr * n) {
bool visited = true;
unsigned j;
switch(n->get_kind()) {
case AST_VAR:
return true;
case AST_APP:
j = to_app(n)->get_num_args();
while (j > 0) {
--j;
visit(to_app(n)->get_arg(j), visited);
}
return visited;
case AST_QUANTIFIER:
visit(to_quantifier(n)->get_expr(), visited);
return visited;
default:
UNREACHABLE();
return true;
}
}
void push_app_ite::reduce1(expr * n) {
switch (n->get_kind()) {
case AST_VAR:
cache_result(n, n, 0);
break;
case AST_APP:
reduce1_app(to_app(n));
break;
case AST_QUANTIFIER:
reduce1_quantifier(to_quantifier(n));
break;
default:
UNREACHABLE();
}
}
void push_app_ite::reduce1_app(app * n) {
m_args.reset();
func_decl * decl = n->get_decl();
proof_ref p1(m);
get_args(n, m_args, p1);
expr_ref r(m);
if (is_target(decl, m_args.size(), m_args.c_ptr()))
apply(decl, m_args.size(), m_args.c_ptr(), r);
else
mk_app(decl, m_args.size(), m_args.c_ptr(), r);
if (!m.fine_grain_proofs())
cache_result(n, r, 0);
else {
expr * s = m.mk_app(decl, m_args.size(), m_args.c_ptr());
proof * p;
if (n == r)
p = 0;
else if (r != s)
p = m.mk_transitivity(p1, m.mk_rewrite(s, r));
else
p = p1;
cache_result(n, r, p);
}
}
void push_app_ite::reduce1_quantifier(quantifier * q) {
expr * new_body;
proof * new_body_pr;
get_cached(q->get_expr(), new_body, new_body_pr);
quantifier * new_q = m.update_quantifier(q, new_body);
proof * p = q == new_q ? 0 : m.mk_quant_intro(q, new_q, new_body_pr);
cache_result(q, new_q, p);
}
bool ng_push_app_ite::is_target(func_decl * decl, unsigned num_args, expr * const * args) {
bool r = push_app_ite::is_target(decl, num_args, args);
if (!r)
return false;
for (unsigned i = 0; i < num_args; i++)
if (!is_ground(args[i]))
return true;
return false;
}
ng_push_app_ite::ng_push_app_ite(simplifier & s, bool conservative):
push_app_ite(s, conservative) {
}

View file

@ -1,63 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
push_app_ite.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-05-14.
Revision History:
--*/
#ifndef PUSH_APP_ITE_H_
#define PUSH_APP_ITE_H_
#include "ast/ast.h"
#include "ast/simplifier/simplifier.h"
/**
\brief Functor for applying the following transformation:
(f s (ite c t1 t2)) ==> (ite c (f s t1) (f s t2))
*/
class push_app_ite : public simplifier {
protected:
bool m_conservative;
int has_ite_arg(unsigned num_args, expr * const * args);
void apply(func_decl * decl, unsigned num_args, expr * const * args, expr_ref & result);
virtual bool is_target(func_decl * decl, unsigned num_args, expr * const * args);
void reduce_core(expr * n);
bool visit_children(expr * n);
void reduce1(expr * n);
void reduce1_app(app * n);
void reduce1_quantifier(quantifier * q);
public:
push_app_ite(simplifier & s, bool conservative = true);
virtual ~push_app_ite();
void operator()(expr * s, expr_ref & r, proof_ref & p);
};
/**
\brief Variation of push_app_ite that applies the transformation on nonground terms only.
\remark This functor uses the app::is_ground method. This method is not
completly precise, for instance, any term containing a quantifier is marked as non ground.
*/
class ng_push_app_ite : public push_app_ite {
protected:
virtual bool is_target(func_decl * decl, unsigned num_args, expr * const * args);
public:
ng_push_app_ite(simplifier & s, bool conservative = true);
virtual ~ng_push_app_ite() {}
};
#endif /* PUSH_APP_ITE_H_ */

View file

@ -1,39 +0,0 @@
/*++
Copyright (c) 2016 Microsoft Corporation
Module Name:
seq_simplifier_plugin.cpp
Abstract:
Simplifier for the theory of sequences
Author:
Nikolaj Bjorner (nbjorner) 2016-02-05
--*/
#include "ast/simplifier/seq_simplifier_plugin.h"
seq_simplifier_plugin::seq_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b) :
simplifier_plugin(symbol("seq"), m),
m_util(m),
m_rw(m) {}
seq_simplifier_plugin::~seq_simplifier_plugin() {}
bool seq_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
set_reduce_invoked();
SASSERT(f->get_family_id() == get_family_id());
return m_rw.mk_app_core(f, num_args, args, result) != BR_FAILED;
}
bool seq_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) {
set_reduce_invoked();
return m_rw.mk_eq_core(lhs, rhs, result) != BR_FAILED;
}

View file

@ -1,39 +0,0 @@
/*++
Copyright (c) 2016 Microsoft Corporation
Module Name:
seq_simplifier_plugin.h
Abstract:
Simplifier for the sequence theory
Author:
Nikolaj Bjorner (nbjorner) 2016-02-05
--*/
#ifndef SEQ_SIMPLIFIER_PLUGIN_H_
#define SEQ_SIMPLIFIER_PLUGIN_H_
#include "ast/simplifier/basic_simplifier_plugin.h"
#include "ast/seq_decl_plugin.h"
#include "ast/rewriter/seq_rewriter.h"
class seq_simplifier_plugin : public simplifier_plugin {
seq_util m_util;
seq_rewriter m_rw;
public:
seq_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b);
~seq_simplifier_plugin();
virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result);
};
#endif /* SEQ_SIMPLIFIER_PLUGIN_H_ */

View file

@ -1,967 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
simplifier.cpp
Abstract:
Expression simplifier.
Author:
Leonardo (leonardo) 2008-01-03
Notes:
--*/
#include "ast/simplifier/simplifier.h"
#include "ast/rewriter/var_subst.h"
#include "ast/ast_ll_pp.h"
#include "ast/ast_pp.h"
#include "ast/well_sorted.h"
#include "ast/ast_smt_pp.h"
simplifier::simplifier(ast_manager & m):
base_simplifier(m),
m_proofs(m),
m_subst_proofs(m),
m_need_reset(false),
m_use_oeq(false),
m_visited_quantifier(false),
m_ac_support(true) {
}
void simplifier::register_plugin(plugin * p) {
m_plugins.register_plugin(p);
}
simplifier::~simplifier() {
flush_cache();
}
void simplifier::enable_ac_support(bool flag) {
m_ac_support = flag;
ptr_vector<plugin>::const_iterator it = m_plugins.begin();
ptr_vector<plugin>::const_iterator end = m_plugins.end();
for (; it != end; ++it) {
if (*it != 0)
(*it)->enable_ac_support(flag);
}
}
/**
\brief External interface for the simplifier.
A client will invoke operator()(s, r, p) to simplify s.
The result is stored in r.
When proof generation is enabled, a proof for the equivalence (or equisatisfiability)
of s and r is stored in p.
When proof generation is disabled, this method stores the "undefined proof" object in p.
*/
void simplifier::operator()(expr * s, expr_ref & r, proof_ref & p) {
m_need_reset = true;
reinitialize();
expr * s_orig = s;
(void)s_orig;
expr * old_s;
expr * result;
proof * result_proof;
switch (m.proof_mode()) {
case PGM_DISABLED: // proof generation is disabled.
reduce_core(s);
// after executing reduce_core, the result of the simplification is in the cache
get_cached(s, result, result_proof);
r = result;
p = m.mk_undef_proof();
break;
case PGM_COARSE: // coarse proofs... in this case, we do not produce a step by step (fine grain) proof to show the equivalence (or equisatisfiability) of s an r.
m_subst_proofs.reset(); // m_subst_proofs is an auxiliary vector that is used to justify substitutions. See comment on method get_subst.
reduce_core(s);
get_cached(s, result, result_proof);
r = result;
if (result == s)
p = m.mk_reflexivity(s);
else {
remove_duplicates(m_subst_proofs);
p = m.mk_rewrite_star(s, result, m_subst_proofs.size(), m_subst_proofs.c_ptr());
}
break;
case PGM_FINE: // fine grain proofs... in this mode, every proof step (or most of them) is described.
m_proofs.reset();
old_s = 0;
// keep simplyfing until no further simplifications are possible.
while (s != old_s) {
TRACE("simplifier", tout << "simplification pass... " << s->get_id() << "\n";);
TRACE("simplifier_loop", tout << mk_ll_pp(s, m) << "\n";);
reduce_core(s);
get_cached(s, result, result_proof);
SASSERT(is_rewrite_proof(s, result, result_proof));
if (result_proof != 0) {
m_proofs.push_back(result_proof);
}
old_s = s;
s = result;
}
SASSERT(s != 0);
r = s;
p = m_proofs.empty() ? m.mk_reflexivity(s) : m.mk_transitivity(m_proofs.size(), m_proofs.c_ptr());
SASSERT(is_rewrite_proof(s_orig, r, p));
break;
default:
UNREACHABLE();
}
}
void simplifier::flush_cache() {
m_cache.flush();
ptr_vector<plugin>::const_iterator it = m_plugins.begin();
ptr_vector<plugin>::const_iterator end = m_plugins.end();
for (; it != end; ++it) {
if (*it != 0) {
(*it)->flush_caches();
}
}
}
bool simplifier::get_subst(expr * n, expr_ref & r, proof_ref & p) {
return false;
}
void simplifier::reduce_core(expr * n1) {
if (!is_cached(n1)) {
// We do not assume m_todo is empty... So, we store the current size of the todo-stack.
unsigned sz = m_todo.size();
m_todo.push_back(n1);
while (m_todo.size() != sz) {
expr * n = m_todo.back();
if (is_cached(n))
m_todo.pop_back();
else if (visit_children(n)) {
// if all children were already simplified, then remove n from the todo stack and apply a
// simplification step to it.
m_todo.pop_back();
reduce1(n);
}
if (m.canceled()) {
cache_result(n1, n1, 0);
break;
}
}
}
}
/**
\brief Return true if all children of n have been already simplified.
*/
bool simplifier::visit_children(expr * n) {
switch(n->get_kind()) {
case AST_VAR:
return true;
case AST_APP:
// The simplifier has support for flattening AC (associative-commutative) operators.
// The method ast_manager::mk_app is used to create the flat version of an AC operator.
// In Z3 1.x, we used multi-ary operators. This creates problems for the superposition engine.
// So, starting at Z3 2.x, only boolean operators can be multi-ary.
// Example:
// (and (and a b) (and c d)) --> (and a b c d)
// (+ (+ a b) (+ c d)) --> (+ a (+ b (+ c d)))
// Remark: The flattening is only applied if m_ac_support is true.
if (m_ac_support && to_app(n)->get_decl()->is_associative() && to_app(n)->get_decl()->is_commutative())
return visit_ac(to_app(n));
else {
bool visited = true;
unsigned j = to_app(n)->get_num_args();
while (j > 0) {
--j;
visit(to_app(n)->get_arg(j), visited);
}
return visited;
}
case AST_QUANTIFIER:
return visit_quantifier(to_quantifier(n));
default:
UNREACHABLE();
return true;
}
}
/**
\brief Visit the children of n assuming it is an AC (associative-commutative) operator.
For example, if n is of the form (+ (+ a b) (+ c d)), this method
will return true if the nodes a, b, c and d have been already simplified.
The nodes (+ a b) and (+ c d) are not really checked.
*/
bool simplifier::visit_ac(app * n) {
bool visited = true;
func_decl * decl = n->get_decl();
SASSERT(m_ac_support);
SASSERT(decl->is_associative());
SASSERT(decl->is_commutative());
m_ac_marked.reset();
ptr_buffer<app> todo;
todo.push_back(n);
while (!todo.empty()) {
app * n = todo.back();
todo.pop_back();
if (m_ac_mark.is_marked(n))
continue;
m_ac_mark.mark(n, true);
m_ac_marked.push_back(n);
SASSERT(n->get_decl() == decl);
unsigned i = n->get_num_args();
while (i > 0) {
--i;
expr * arg = n->get_arg(i);
if (is_app_of(arg, decl))
todo.push_back(to_app(arg));
else
visit(arg, visited);
}
}
ptr_vector<expr>::const_iterator it = m_ac_marked.begin();
ptr_vector<expr>::const_iterator end = m_ac_marked.end();
for (; it != end; ++it)
m_ac_mark.mark(*it, false);
return visited;
}
bool simplifier::visit_quantifier(quantifier * n) {
m_visited_quantifier = true;
bool visited = true;
unsigned j = to_quantifier(n)->get_num_patterns();
while (j > 0) {
--j;
visit(to_quantifier(n)->get_pattern(j), visited);
}
j = to_quantifier(n)->get_num_no_patterns();
while (j > 0) {
--j;
visit(to_quantifier(n)->get_no_pattern(j), visited);
}
visit(to_quantifier(n)->get_expr(), visited);
return visited;
}
/**
\brief Simplify n and store the result in the cache.
*/
void simplifier::reduce1(expr * n) {
switch (n->get_kind()) {
case AST_VAR:
cache_result(n, n, 0);
break;
case AST_APP:
reduce1_app(to_app(n));
break;
case AST_QUANTIFIER:
reduce1_quantifier(to_quantifier(n));
break;
default:
UNREACHABLE();
}
}
/**
\brief Simplify the given application using the cached values,
associativity flattening, the given substitution, and family/theory
specific simplifications via plugins.
*/
void simplifier::reduce1_app(app * n) {
expr_ref r(m);
proof_ref p(m);
TRACE("reduce", tout << "reducing...\n" << mk_pp(n, m) << "\n";);
if (get_subst(n, r, p)) {
TRACE("reduce", tout << "applying substitution...\n";);
cache_result(n, r, p);
return;
}
func_decl * decl = n->get_decl();
if (m_ac_support && decl->is_associative() && decl->is_commutative())
reduce1_ac_app_core(n);
else
reduce1_app_core(n);
}
void simplifier::reduce1_app_core(app * n) {
m_args.reset();
func_decl * decl = n->get_decl();
proof_ref p1(m);
// Stores the new arguments of n in m_args.
// Let n be of the form
// (decl arg_0 ... arg_{n-1})
// then
// m_args contains [arg_0', ..., arg_{n-1}'],
// where arg_i' is the simplification of arg_i
// and
// p1 is a proof for
// (decl arg_0 ... arg_{n-1}) is equivalente/equisatisfiable to (decl arg_0' ... arg_{n-1}')
// p1 is built using the congruence proof step and the proofs for arg_0' ... arg_{n-1}'.
// Of course, p1 is 0 if proofs are not enabled or coarse grain proofs are used.
bool has_new_args = get_args(n, m_args, p1);
// The following if implements a simple trick.
// If none of the arguments have been simplified, and n is not a theory symbol,
// Then no simplification is possible, and we can cache the result of the simplification of n as n.
if (has_new_args || decl->get_family_id() != null_family_id) {
expr_ref r(m);
TRACE("reduce", tout << "reduce1_app\n"; for(unsigned i = 0; i < m_args.size(); i++) tout << mk_ll_pp(m_args[i], m););
// the method mk_app invokes get_subst and plugins to simplify
// (decl arg_0' ... arg_{n-1}')
mk_app(decl, m_args.size(), m_args.c_ptr(), r);
if (!m.fine_grain_proofs()) {
cache_result(n, r, 0);
}
else {
expr * s = m.mk_app(decl, m_args.size(), m_args.c_ptr());
proof * p;
if (n == r)
p = 0;
else if (r != s)
// we use a "theory rewrite generic proof" to justify the step
// s = (decl arg_0' ... arg_{n-1}') --> r
p = m.mk_transitivity(p1, m.mk_rewrite(s, r));
else
p = p1;
cache_result(n, r, p);
}
}
else {
cache_result(n, n, 0);
}
}
bool is_ac_list(app * n, ptr_vector<expr> & args) {
args.reset();
func_decl * f = n->get_decl();
app * curr = n;
while (true) {
if (curr->get_num_args() != 2)
return false;
expr * arg1 = curr->get_arg(0);
if (is_app_of(arg1, f))
return false;
args.push_back(arg1);
expr * arg2 = curr->get_arg(1);
if (!is_app_of(arg2, f)) {
args.push_back(arg2);
return true;
}
curr = to_app(arg2);
}
}
bool is_ac_vector(app * n) {
func_decl * f = n->get_decl();
unsigned num_args = n->get_num_args();
for (unsigned i = 0; i < num_args; i++) {
if (is_app_of(n->get_arg(i), f))
return false;
}
return true;
}
void simplifier::reduce1_ac_app_core(app * n) {
app_ref n_c(m);
proof_ref p1(m);
mk_ac_congruent_term(n, n_c, p1);
TRACE("ac", tout << "expr:\n" << mk_pp(n, m) << "\ncongruent term:\n" << mk_pp(n_c, m) << "\n";);
expr_ref r(m);
func_decl * decl = n->get_decl();
family_id fid = decl->get_family_id();
plugin * p = get_plugin(fid);
if (is_ac_vector(n_c)) {
if (p != 0 && p->reduce(decl, n_c->get_num_args(), n_c->get_args(), r)) {
// done...
}
else {
r = n_c;
}
}
else if (is_ac_list(n_c, m_args)) {
// m_args contains the arguments...
if (p != 0 && p->reduce(decl, m_args.size(), m_args.c_ptr(), r)) {
// done...
}
else {
r = m.mk_app(decl, m_args.size(), m_args.c_ptr());
}
}
else {
m_args.reset();
m_mults.reset();
get_ac_args(n_c, m_args, m_mults);
TRACE("ac", tout << "AC args:\n";
for (unsigned i = 0; i < m_args.size(); i++) {
tout << mk_pp(m_args[i], m) << " * " << m_mults[i] << "\n";
});
if (p != 0 && p->reduce(decl, m_args.size(), m_mults.c_ptr(), m_args.c_ptr(), r)) {
// done...
}
else {
ptr_buffer<expr> new_args;
expand_args(m_args.size(), m_mults.c_ptr(), m_args.c_ptr(), new_args);
r = m.mk_app(decl, new_args.size(), new_args.c_ptr());
}
}
TRACE("ac", tout << "AC result:\n" << mk_pp(r, m) << "\n";);
if (!m.fine_grain_proofs()) {
cache_result(n, r, 0);
}
else {
proof * p;
if (n == r.get())
p = 0;
else if (r.get() != n_c.get())
p = m.mk_transitivity(p1, m.mk_rewrite(n_c, r));
else
p = p1;
cache_result(n, r, p);
}
}
static unsigned g_rewrite_lemma_id = 0;
void simplifier::dump_rewrite_lemma(func_decl * decl, unsigned num_args, expr * const * args, expr* result) {
expr_ref arg(m);
arg = m.mk_app(decl, num_args, args);
if (arg.get() != result) {
char buffer[128];
#ifdef _WINDOWS
sprintf_s(buffer, ARRAYSIZE(buffer), "lemma_%d.smt", g_rewrite_lemma_id);
#else
sprintf(buffer, "rewrite_lemma_%d.smt", g_rewrite_lemma_id);
#endif
ast_smt_pp pp(m);
pp.set_benchmark_name("rewrite_lemma");
pp.set_status("unsat");
expr_ref n(m);
n = m.mk_not(m.mk_eq(arg.get(), result));
std::ofstream out(buffer);
pp.display(out, n);
out.close();
++g_rewrite_lemma_id;
}
}
/**
\brief Return in \c result an expression \c e equivalent to <tt>(f args[0] ... args[num_args - 1])</tt>, and
store in \c pr a proof for <tt>(= (f args[0] ... args[num_args - 1]) e)</tt>
If e is identical to (f args[0] ... args[num_args - 1]), then pr is set to 0.
*/
void simplifier::mk_app(func_decl * decl, unsigned num_args, expr * const * args, expr_ref & result) {
m_need_reset = true;
if (m.is_eq(decl)) {
sort * s = m.get_sort(args[0]);
plugin * p = get_plugin(s->get_family_id());
if (p != 0 && p->reduce_eq(args[0], args[1], result))
return;
}
else if (m.is_distinct(decl)) {
sort * s = m.get_sort(args[0]);
plugin * p = get_plugin(s->get_family_id());
if (p != 0 && p->reduce_distinct(num_args, args, result))
return;
}
family_id fid = decl->get_family_id();
plugin * p = get_plugin(fid);
if (p != 0 && p->reduce(decl, num_args, args, result)) {
//uncomment this line if you want to trace rewrites as lemmas:
//dump_rewrite_lemma(decl, num_args, args, result.get());
return;
}
result = m.mk_app(decl, num_args, args);
}
/**
\brief Create a term congruence to n (f a[0] ... a[num_args-1]) using the
cached values for the a[i]'s. Store the result in r, and the proof for (= n r) in p.
If n and r are identical, then set p to 0.
*/
void simplifier::mk_congruent_term(app * n, app_ref & r, proof_ref & p) {
bool has_new_args = false;
ptr_vector<expr> args;
ptr_vector<proof> proofs;
unsigned num = n->get_num_args();
for (unsigned j = 0; j < num; j++) {
expr * arg = n->get_arg(j);
expr * new_arg;
proof * arg_proof;
get_cached(arg, new_arg, arg_proof);
CTRACE("simplifier_bug", (arg != new_arg) != (arg_proof != 0),
tout << mk_ll_pp(arg, m) << "\n---->\n" << mk_ll_pp(new_arg, m) << "\n";
tout << "#" << arg->get_id() << " #" << new_arg->get_id() << "\n";
tout << arg << " " << new_arg << "\n";);
if (arg != new_arg) {
has_new_args = true;
proofs.push_back(arg_proof);
SASSERT(arg_proof);
}
else {
SASSERT(arg_proof == 0);
}
args.push_back(new_arg);
}
if (has_new_args) {
r = m.mk_app(n->get_decl(), args.size(), args.c_ptr());
if (m_use_oeq)
p = m.mk_oeq_congruence(n, r, proofs.size(), proofs.c_ptr());
else
p = m.mk_congruence(n, r, proofs.size(), proofs.c_ptr());
}
else {
r = n;
p = 0;
}
}
/**
\brief Store the new arguments of \c n in result. Store in p a proof for
(= n (f result[0] ... result[num_args - 1])), where f is the function symbol of n.
If there are no new arguments or fine grain proofs are disabled, then p is set to 0.
Return true there are new arguments.
*/
bool simplifier::get_args(app * n, ptr_vector<expr> & result, proof_ref & p) {
bool has_new_args = false;
unsigned num = n->get_num_args();
if (m.fine_grain_proofs()) {
app_ref r(m);
mk_congruent_term(n, r, p);
result.append(r->get_num_args(), r->get_args());
SASSERT(n->get_num_args() == result.size());
has_new_args = r != n;
}
else {
p = 0;
for (unsigned j = 0; j < num; j++) {
expr * arg = n->get_arg(j);
expr * new_arg;
proof * arg_proof;
get_cached(arg, new_arg, arg_proof);
if (arg != new_arg) {
has_new_args = true;
}
result.push_back(new_arg);
}
}
return has_new_args;
}
/**
\brief Create a term congruence to n (where n is an expression such as: (f (f a_1 a_2) (f a_3 (f a_4 a_5))) using the
cached values for the a_i's. Store the result in r, and the proof for (= n r) in p.
If n and r are identical, then set p to 0.
*/
void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) {
SASSERT(m_ac_support);
func_decl * f = n->get_decl();
m_ac_cache.reset();
m_ac_pr_cache.reset();
ptr_buffer<app> todo;
ptr_buffer<expr> new_args;
ptr_buffer<proof> new_arg_prs;
todo.push_back(n);
while (!todo.empty()) {
app * curr = todo.back();
if (m_ac_cache.contains(curr)) {
todo.pop_back();
continue;
}
bool visited = true;
bool has_new_arg = false;
new_args.reset();
new_arg_prs.reset();
unsigned num_args = curr->get_num_args();
for (unsigned j = 0; j < num_args; j ++) {
expr * arg = curr->get_arg(j);
if (is_app_of(arg, f)) {
app * new_arg = 0;
if (m_ac_cache.find(to_app(arg), new_arg)) {
SASSERT(new_arg != 0);
new_args.push_back(new_arg);
if (arg != new_arg) {
TRACE("ac", tout << mk_pp(arg, m) << " -> " << mk_pp(new_arg, m) << "\n";);
has_new_arg = true;
}
if (m.fine_grain_proofs()) {
proof * pr = 0;
m_ac_pr_cache.find(to_app(arg), pr);
if (pr != 0)
new_arg_prs.push_back(pr);
}
}
else {
visited = false;
todo.push_back(to_app(arg));
}
}
else {
expr * new_arg = 0;
proof * pr;
get_cached(arg, new_arg, pr);
new_args.push_back(new_arg);
if (arg != new_arg) {
TRACE("ac", tout << "cached: " << mk_pp(arg, m) << " -> " << mk_pp(new_arg, m) << "\n";);
has_new_arg = true;
}
if (m.fine_grain_proofs() && pr != 0)
new_arg_prs.push_back(pr);
}
}
if (visited) {
SASSERT(new_args.size() == curr->get_num_args());
todo.pop_back();
if (!has_new_arg) {
m_ac_cache.insert(curr, curr);
if (m.fine_grain_proofs())
m_ac_pr_cache.insert(curr, 0);
}
else {
app * new_curr = m.mk_app(f, new_args.size(), new_args.c_ptr());
m_ac_cache.insert(curr, new_curr);
TRACE("ac", tout << mk_pp(curr, m) << " -> " << mk_pp(new_curr, m) << "\n";);
if (m.fine_grain_proofs()) {
proof * p = m.mk_congruence(curr, new_curr, new_arg_prs.size(), new_arg_prs.c_ptr());
m_ac_pr_cache.insert(curr, p);
}
}
}
}
SASSERT(m_ac_cache.contains(n));
app * new_n = 0;
m_ac_cache.find(n, new_n);
r = new_n;
if (m.fine_grain_proofs()) {
proof * new_pr = 0;
m_ac_pr_cache.find(n, new_pr);
p = new_pr;
}
}
#define White 0
#define Grey 1
#define Black 2
#ifdef Z3DEBUG
static int get_color(obj_map<expr, int> & colors, expr * n) {
obj_map<expr, int>::obj_map_entry * entry = colors.insert_if_not_there2(n, White);
return entry->get_data().m_value;
}
#endif
static bool visit_ac_children(func_decl * f, expr * n, obj_map<expr, int> & colors, ptr_buffer<expr> & todo, ptr_buffer<expr> & result) {
if (is_app_of(n, f)) {
unsigned num_args = to_app(n)->get_num_args();
bool visited = true;
// Put the arguments in 'result' in reverse order.
// Reason: preserve the original order of the arguments in the final result.
// Remark: get_ac_args will traverse 'result' backwards.
for (unsigned i = 0; i < num_args; i++) {
expr * arg = to_app(n)->get_arg(i);
obj_map<expr, int>::obj_map_entry * entry = colors.insert_if_not_there2(arg, White);
if (entry->get_data().m_value == White) {
todo.push_back(arg);
visited = false;
}
}
return visited;
}
else {
return true;
}
}
void simplifier::ac_top_sort(app * n, ptr_buffer<expr> & result) {
ptr_buffer<expr> todo;
func_decl * f = n->get_decl();
obj_map<expr, int> & colors = m_colors;
colors.reset();
todo.push_back(n);
while (!todo.empty()) {
expr * curr = todo.back();
int color;
obj_map<expr, int>::obj_map_entry * entry = colors.insert_if_not_there2(curr, White);
SASSERT(entry);
color = entry->get_data().m_value;
switch (color) {
case White:
// Remark: entry becomes invalid if an element is inserted into the hashtable.
// So, I must set Grey before executing visit_ac_children.
entry->get_data().m_value = Grey;
SASSERT(get_color(colors, curr) == Grey);
if (visit_ac_children(f, curr, colors, todo, result)) {
// If visit_ac_children succeeded, then the hashtable was not modified,
// and entry is still valid.
SASSERT(todo.back() == curr);
entry->get_data().m_value = Black;
SASSERT(get_color(colors, curr) == Black);
result.push_back(curr);
todo.pop_back();
}
break;
case Grey:
SASSERT(visit_ac_children(f, curr, colors, todo, result));
SASSERT(entry);
entry->get_data().m_value = Black;
SASSERT(get_color(colors, curr) == Black);
result.push_back(curr);
SASSERT(todo.back() == curr);
todo.pop_back();
break;
case Black:
todo.pop_back();
break;
default:
UNREACHABLE();
}
}
}
void simplifier::get_ac_args(app * n, ptr_vector<expr> & args, vector<rational> & mults) {
SASSERT(m_ac_support);
ptr_buffer<expr> sorted_exprs;
ac_top_sort(n, sorted_exprs);
SASSERT(!sorted_exprs.empty());
SASSERT(sorted_exprs[sorted_exprs.size()-1] == n);
TRACE("ac", tout << mk_ll_pp(n, m, true, false) << "#" << n->get_id() << "\nsorted expressions...\n";
for (unsigned i = 0; i < sorted_exprs.size(); i++) {
tout << "#" << sorted_exprs[i]->get_id() << " ";
}
tout << "\n";);
m_ac_mults.reset();
m_ac_mults.insert(n, rational(1));
func_decl * decl = n->get_decl();
unsigned j = sorted_exprs.size();
while (j > 0) {
--j;
expr * curr = sorted_exprs[j];
rational mult;
m_ac_mults.find(curr, mult);
SASSERT(!mult.is_zero());
if (is_app_of(curr, decl)) {
unsigned num_args = to_app(curr)->get_num_args();
for (unsigned i = 0; i < num_args; i++) {
expr * arg = to_app(curr)->get_arg(i);
rational zero;
obj_map<expr, rational>::obj_map_entry * entry = m_ac_mults.insert_if_not_there2(arg, zero);
entry->get_data().m_value += mult;
}
}
else {
args.push_back(curr);
mults.push_back(mult);
}
}
}
void simplifier::reduce1_quantifier(quantifier * q) {
expr * new_body;
proof * new_body_pr;
SASSERT(is_well_sorted(m, q));
get_cached(q->get_expr(), new_body, new_body_pr);
quantifier_ref q1(m);
proof * p1 = 0;
if (is_quantifier(new_body) &&
to_quantifier(new_body)->is_forall() == q->is_forall() &&
!to_quantifier(q)->has_patterns() &&
!to_quantifier(new_body)->has_patterns()) {
quantifier * nested_q = to_quantifier(new_body);
ptr_buffer<sort> sorts;
buffer<symbol> names;
sorts.append(q->get_num_decls(), q->get_decl_sorts());
names.append(q->get_num_decls(), q->get_decl_names());
sorts.append(nested_q->get_num_decls(), nested_q->get_decl_sorts());
names.append(nested_q->get_num_decls(), nested_q->get_decl_names());
q1 = m.mk_quantifier(q->is_forall(),
sorts.size(),
sorts.c_ptr(),
names.c_ptr(),
nested_q->get_expr(),
std::min(q->get_weight(), nested_q->get_weight()),
q->get_qid(),
q->get_skid(),
0, 0, 0, 0);
SASSERT(is_well_sorted(m, q1));
if (m.fine_grain_proofs()) {
quantifier * q0 = m.update_quantifier(q, new_body);
proof * p0 = q == q0 ? 0 : m.mk_quant_intro(q, q0, new_body_pr);
p1 = m.mk_pull_quant(q0, q1);
p1 = m.mk_transitivity(p0, p1);
}
}
else {
ptr_buffer<expr> new_patterns;
ptr_buffer<expr> new_no_patterns;
expr * new_pattern;
proof * new_pattern_pr;
// Remark: we can ignore the proofs for the patterns.
unsigned num = q->get_num_patterns();
for (unsigned i = 0; i < num; i++) {
get_cached(q->get_pattern(i), new_pattern, new_pattern_pr);
if (m.is_pattern(new_pattern)) {
new_patterns.push_back(new_pattern);
}
}
num = q->get_num_no_patterns();
for (unsigned i = 0; i < num; i++) {
get_cached(q->get_no_pattern(i), new_pattern, new_pattern_pr);
new_no_patterns.push_back(new_pattern);
}
remove_duplicates(new_patterns);
remove_duplicates(new_no_patterns);
q1 = m.mk_quantifier(q->is_forall(),
q->get_num_decls(),
q->get_decl_sorts(),
q->get_decl_names(),
new_body,
q->get_weight(),
q->get_qid(),
q->get_skid(),
new_patterns.size(),
new_patterns.c_ptr(),
new_no_patterns.size(),
new_no_patterns.c_ptr());
SASSERT(is_well_sorted(m, q1));
TRACE("simplifier", tout << mk_pp(q, m) << "\n" << mk_pp(q1, m) << "\n";);
if (m.fine_grain_proofs()) {
if (q != q1 && !new_body_pr) {
new_body_pr = m.mk_rewrite(q->get_expr(), new_body);
}
p1 = q == q1 ? 0 : m.mk_quant_intro(q, q1, new_body_pr);
}
}
expr_ref r(m);
elim_unused_vars(m, q1, params_ref(), r);
proof * pr = 0;
if (m.fine_grain_proofs()) {
proof * p2 = 0;
if (q1.get() != r.get())
p2 = m.mk_elim_unused_vars(q1, r);
pr = m.mk_transitivity(p1, p2);
}
cache_result(q, r, pr);
}
/**
\see release_plugins
*/
void simplifier::borrow_plugins(simplifier const & s) {
ptr_vector<plugin>::const_iterator it = s.begin_plugins();
ptr_vector<plugin>::const_iterator end = s.end_plugins();
for (; it != end; ++it)
register_plugin(*it);
}
/**
\brief Make the simplifier behave as a pre-simplifier: No AC, and plugins are marked in pre-simplification mode.
*/
void simplifier::enable_presimp() {
enable_ac_support(false);
ptr_vector<plugin>::const_iterator it = begin_plugins();
ptr_vector<plugin>::const_iterator end = end_plugins();
for (; it != end; ++it)
(*it)->enable_presimp(true);
}
/**
\brief This method should be invoked if the plugins of this simplifier were borrowed from a different simplifier.
*/
void simplifier::release_plugins() {
m_plugins.release();
}
void subst_simplifier::set_subst_map(expr_map * s) {
flush_cache();
m_subst_map = s;
}
bool subst_simplifier::get_subst(expr * n, expr_ref & r, proof_ref & p) {
if (m_subst_map && m_subst_map->contains(n)) {
expr * _r;
proof * _p = 0;
m_subst_map->get(n, _r, _p);
r = _r;
p = _p;
if (m.coarse_grain_proofs())
m_subst_proofs.push_back(p);
return true;
}
return false;
}
static void push_core(ast_manager & m, expr * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs) {
SASSERT(pr == 0 || m.is_undef_proof(pr) || e == m.get_fact(pr));
TRACE("preprocessor",
tout << mk_pp(e, m) << "\n";
if (pr) tout << mk_ll_pp(pr, m) << "\n\n";);
if (m.is_true(e))
return;
result.push_back(e);
if (m.proofs_enabled())
result_prs.push_back(pr);
}
static void push_and(ast_manager & m, app * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs) {
unsigned num = e->get_num_args();
TRACE("push_and", tout << mk_pp(e, m) << "\n";);
for (unsigned i = 0; i < num; i++)
push_assertion(m, e->get_arg(i), m.mk_and_elim(pr, i), result, result_prs);
}
static void push_not_or(ast_manager & m, app * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs) {
unsigned num = e->get_num_args();
TRACE("push_not_or", tout << mk_pp(e, m) << "\n";);
for (unsigned i = 0; i < num; i++) {
expr * child = e->get_arg(i);
if (m.is_not(child)) {
expr * not_child = to_app(child)->get_arg(0);
push_assertion(m, not_child, m.mk_not_or_elim(pr, i), result, result_prs);
}
else {
expr_ref not_child(m);
not_child = m.mk_not(child);
push_assertion(m, not_child, m.mk_not_or_elim(pr, i), result, result_prs);
}
}
}
void push_assertion(ast_manager & m, expr * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs) {
CTRACE("push_assertion", !(pr == 0 || m.is_undef_proof(pr) || m.get_fact(pr) == e),
tout << mk_pp(e, m) << "\n" << mk_pp(m.get_fact(pr), m) << "\n";);
SASSERT(pr == 0 || m.is_undef_proof(pr) || m.get_fact(pr) == e);
if (m.is_and(e))
push_and(m, to_app(e), pr, result, result_prs);
else if (m.is_not(e) && m.is_or(to_app(e)->get_arg(0)))
push_not_or(m, to_app(to_app(e)->get_arg(0)), pr, result, result_prs);
else
push_core(m, e, pr, result, result_prs);
}

View file

@ -1,232 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
simplifier.h
Abstract:
Generic expression simplifier with support for theory specific "plugins".
Author:
Leonardo (leonardo) 2008-01-03
Notes:
--*/
#ifndef SIMPLIFIER_H_
#define SIMPLIFIER_H_
#include "ast/simplifier/base_simplifier.h"
#include "ast/simplifier/simplifier_plugin.h"
#include "util/plugin_manager.h"
#include "ast/ast_util.h"
#include "util/obj_hashtable.h"
/**
\brief Local simplifier.
Proof production can be enabled/disabled.
The simplifier can also apply substitutions during the
simplification. A substitution is a mapping from expression
to expression+proof, where for each entry e_1->(e_2,p) p is
a proof for (= e_1 e_2).
The simplifier can also generate coarse grain proofs. In a coarse
proof, local rewrite steps are omitted, and only the substitutions
used are tracked.
Example:
Consider the expression (+ a b), and the substitution b->(0, p)
When fine grain proofs are enabled, the simplifier will produce the
following proof
Assume the id of the proof object p is $0. Note that p is a proof for (= b 0).
$1: [reflexivity] |- (= a a)
$2: [congruence] $1 $0 |- (= (+ a b) (+ a 0))
$3: [plus-0] |- (= (+ a 0) a)
$4: [transitivity] $2 $3 |- (= (+ a b) a)
When coarse grain proofs are enabled, the simplifier produces the following
proof:
$1: [simplifier] $0 |- (= (+ a b) a)
*/
class simplifier : public base_simplifier {
protected:
typedef simplifier_plugin plugin;
plugin_manager<plugin> m_plugins;
ptr_vector<expr> m_args;
vector<rational> m_mults;
ptr_vector<expr> m_args2;
proof_ref_vector m_proofs; // auxiliary vector for implementing exhaustive simplification.
proof_ref_vector m_subst_proofs; // in coarse grain proof generation mode, this vector tracks the justification for substitutions (see method get_subst).
bool m_need_reset;
bool m_use_oeq;
bool m_visited_quantifier; //!< true, if the simplifier found a quantifier
bool m_ac_support;
expr_mark m_ac_mark;
ptr_vector<expr> m_ac_marked;
obj_map<app, app *> m_ac_cache; // temporary cache for ac
obj_map<app, proof *> m_ac_pr_cache; // temporary cache for ac
obj_map<expr, int> m_colors; // temporary cache for topological sort.
obj_map<expr, rational> m_ac_mults;
/*
Simplifier uses an idiom for rewriting ASTs without using recursive calls.
- It uses a cache (field m_cache in base_simplifier) and a todo-stack (field m_todo in base_simplifier).
- The cache is a mapping from AST to (AST + Proof). An entry [n -> (n',pr)] is used to store the fact
that n and n' are equivalent and pr is a proof for that. If proofs are disabled, then pr is 0.
We say n' is the result of the simplification of n.
Note: Some simplifications do not preserve equivalence, but equisatisfiability.
For saving space, we use pr = 0 also to represent the reflexivity proof [n -> (n, 0)].
- The simplifier can be extended using plugin (subclasses of the class simplifier_plugin).
Each theory has a family ID. All operators (func_decls) and sorts from a given theory have
the same family_id. Given an application (object of the class app), we use the method
get_family_id() to obtain the family id of the operator in this application.
The simplifier uses plugin to apply theory specific simplifications. The basic idea is:
whenever an AST with family_id X is found, invoke the plugin for this family_id.
A simplifier_plugin implements the following API:
1) bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result)
This method is invoked when the simplifier is trying to reduce/simplify an application
of the form (f args[0] ... args[num_args - 1]), and f has a family_id associated with
the plugin. The plugin may return false to indicate it could not simplify this application.
If it returns true (success), the result should be stored in the argument result.
2) bool reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result);
This method is a similar to the previous one, and it is used to handle associative operators.
A plugin does not need to implement this method, the default implementation will use the previous one.
The arguments mults indicates the multiplicity of every argument in args.
For example, suppose this reduce is invoked with the arguments (f, 2, [3, 2], [a, b], result).
This represents the application (f a a a b b).
Some theory simplifiers may have efficient ways to encode this multiplicity. For example,
the arithmetic solver, if f is "+", the multiplicity can be encoded using "*".
This optimization is used because some benchmarks can create term that are very huge when
flattened. One "real" example (that motivated this optimization) is:
let a1 = x1 + x1
let a2 = a1 + a1
...
let an = a{n-1} + a{n-1}
an
In this example, n was 32, so after AC flattening, we had an application
(+ x1 ... x1) with 2^32 arguments. Using the simple reduce would produce a stack overflow.
This class uses a topological sort for computing the multiplicities efficiently.
So, the field m_colors is used to implement the topological sort.
3) bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result)
This method is invoked when the sort of lhs and rhs has a family_id associated with the plugin.
This method allows theory specific simplifications such as:
(= (+ a b) b) --> (= a 0)
Assuming n1 is a reference to (+ a b) and n2 to b, the simplifier would invoke
reduce_eq(n1, n2, result)
Like reduce, false can be returned if a simplification could not be applied.
And if true is returned, then the result is stored in the argument result.
4) bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result)
It is similar to reduce_eq, but it used for theory specific simplifications for
(distinct args[0] ... args[num_args-1])
Example:
(distinct 0 1 ... n) --> true
- The idiom used in this class is implemented in the methdo reduce_core.
See reduce_core for more details. The basic idea is:
1) Get the next ast to be simplified from the todo-stack.
2) If it is already cached, then do nothing. That is, this expression was already simplified.
3) Otherwise, check whether all arguments already have been simplified (method visit_children).
3a) The arguments that have not been simplified are added to the todo-stack by visit_children.
In this case visit_children will return false.
3b) If all arguments have already been simplified, then invoke reduce1 to perform a reduction/simplification
step. The cache is updated with the result.
- After invoking reduce_core(n), the cache contains an entry [n -> (n', pr)].
*/
void flush_cache();
/**
\brief This method can be redefined in subclasses of simplifier to implement substitutions.
It returns true if n should be substituted by r, where the substitution is justified by the
proof p. The field m_subst_proofs is used to store these justifications when coarse proofs are used (PGM_COARSE).
This method is redefined in the class subst_simplifier. It is used in asserted_formulas
for implementing constant elimination. For example, if asserted_formulas contains the atoms
(= a (+ b 1)) (p a c), then the constant "a" can be eliminated. This is achieved by set (+ b 1) as
a substitution for "a".
*/
virtual bool get_subst(expr * n, expr_ref & r, proof_ref & p);
void reduce_core(expr * n);
bool visit_children(expr * n);
bool visit_ac(app * n);
virtual bool visit_quantifier(quantifier * q);
void reduce1(expr * n);
void reduce1_app(app * n);
void reduce1_app_core(app * n);
void reduce1_ac_app_core(app * n);
void mk_congruent_term(app * n, app_ref & r, proof_ref & p);
void mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p);
bool get_args(app * n, ptr_vector<expr> & result, proof_ref & p);
void get_ac_args(app * n, ptr_vector<expr> & args, vector<rational> & mults);
virtual void reduce1_quantifier(quantifier * q);
void dump_rewrite_lemma(func_decl * decl, unsigned num_args, expr * const * args, expr* result);
void ac_top_sort(app * n, ptr_buffer<expr> & result);
public:
simplifier(ast_manager & manager);
virtual ~simplifier();
void enable_ac_support(bool flag);
/**
\brief Simplify the expression \c s. Store the result in \c r, and a proof that <tt>(= s r)</tt> in \c p.
*/
void operator()(expr * s, expr_ref & r, proof_ref & p);
void reset() { if (m_need_reset) { flush_cache(); m_need_reset = false; } }
bool visited_quantifier() const { return m_visited_quantifier; }
void mk_app(func_decl * decl, unsigned num_args, expr * const * args, expr_ref & r);
void cache_result(expr * n, expr * r, proof * p) { m_need_reset = true; base_simplifier::cache_result(n, r, p); }
void register_plugin(plugin * p);
ptr_vector<plugin>::const_iterator begin_plugins() const { return m_plugins.begin(); }
ptr_vector<plugin>::const_iterator end_plugins() const { return m_plugins.end(); }
plugin * get_plugin(family_id fid) const { return m_plugins.get_plugin(fid); }
ast_manager & get_manager() { return m; }
void borrow_plugins(simplifier const & s);
void release_plugins();
void enable_presimp();
};
class subst_simplifier : public simplifier {
protected:
expr_map * m_subst_map;
virtual bool get_subst(expr * n, expr_ref & r, proof_ref & p);
public:
subst_simplifier(ast_manager & manager):simplifier(manager), m_subst_map(0) {}
void set_subst_map(expr_map * s);
};
void push_assertion(ast_manager & m, expr * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs);
#endif

View file

@ -1,46 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
simplifier_plugin.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-12-29.
Revision History:
--*/
#include "ast/simplifier/simplifier_plugin.h"
/**
\brief Copy every args[i] mult[i] times to new_args.
*/
void expand_args(unsigned num_args, rational const * mults, expr * const * args, ptr_buffer<expr> & new_args) {
for (unsigned i = 0; i < num_args; i++) {
rational const & c = mults[i];
SASSERT(c.is_int());
rational j(0);
while (j < c) {
new_args.push_back(args[i]);
j++;
}
}
}
bool simplifier_plugin::reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result) {
set_reduce_invoked();
if (f->is_idempotent()) {
return reduce(f, num_args, args, result);
}
else {
ptr_buffer<expr> new_args;
expand_args(num_args, mults, args, new_args);
return reduce(f, new_args.size(), new_args.c_ptr(), result);
}
}

View file

@ -1,94 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
simplifier_plugin.h
Abstract:
Expression simplifier plugin interface.
Author:
Leonardo (leonardo) 2008-01-03
--*/
#ifndef SIMPLIFIER_PLUGIN_H_
#define SIMPLIFIER_PLUGIN_H_
#include "ast/ast.h"
class simplifier;
void expand_args(unsigned num_args, rational const * mults, expr * const * args, ptr_buffer<expr> & new_args);
/**
\brief Abstract simplifier for the operators in a given family.
*/
class simplifier_plugin {
protected:
ast_manager & m_manager;
family_id m_fid;
bool m_presimp; // true if simplifier is performing pre-simplification...
bool m_reduce_invoked; // true if one of the reduce methods were invoked.
void set_reduce_invoked() { m_reduce_invoked = true; }
public:
simplifier_plugin(symbol const & fname, ast_manager & m):m_manager(m), m_fid(m.mk_family_id(fname)), m_presimp(false), m_reduce_invoked(false) {}
bool reduce_invoked() const { return m_reduce_invoked; }
virtual ~simplifier_plugin() {}
virtual simplifier_plugin * mk_fresh() {
UNREACHABLE();
return 0;
}
/**
\brief Return in \c result an expression \c e equivalent to <tt>(f args[0] ... args[num_args - 1])</tt>.
Return true if succeeded.
*/
virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { set_reduce_invoked(); return false; }
/**
\brief Return in \c result an expression \c e equivalent to <tt>(f args[0] ... args[0] ... args[num_args - 1])</tt>.
Where each args[i] occurs mults[i] times.
Return true if succeeded.
*/
virtual bool reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result);
/**
\brief Return in \c result an expression \c e equivalent to <tt>(= lhs rhs)</tt>.
Return true if succeeded.
*/
virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { set_reduce_invoked(); return false; }
/**
\brief Return in \c result an expression \c e equivalent to <tt>(distinct args[0] ... args[num_args-1])</tt>.
Return true if succeeded.
*/
virtual bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result) { set_reduce_invoked(); return false; }
family_id get_family_id() const { return m_fid; }
/**
\brief Simplifiers may maintain local caches. These caches must be flushed when this method is invoked.
*/
virtual void flush_caches() { /* do nothing */ }
ast_manager & get_manager() { return m_manager; }
void enable_presimp(bool flag) { m_presimp = flag; }
virtual void enable_ac_support(bool flag) {}
};
#endif

View file

@ -145,18 +145,19 @@ bool static_features::is_diff_atom(expr const * e) const {
return true;
if (!is_numeral(rhs))
return false;
// lhs can be 'x' or '(+ x (* -1 y))'
// lhs can be 'x' or '(+ x (* -1 y))' or '(+ (* -1 x) y)'
if (!is_arith_expr(lhs))
return true;
expr* arg1, *arg2;
if (!m_autil.is_add(lhs, arg1, arg2))
return false;
// x
if (is_arith_expr(arg1))
return false;
// arg2: (* -1 y)
expr* m1, *m2;
return m_autil.is_mul(arg2, m1, m2) && is_minus_one(m1) && !is_arith_expr(m2);
if (!is_arith_expr(arg1) && m_autil.is_mul(arg2, m1, m2) && is_minus_one(m1) && !is_arith_expr(m2))
return true;
if (!is_arith_expr(arg2) && m_autil.is_mul(arg1, m1, m2) && is_minus_one(m1) && !is_arith_expr(m2))
return true;
return false;
}
bool static_features::is_gate(expr const * e) const {

Some files were not shown because too many files have changed in this diff Show more