diff --git a/examples/c++/example.cpp b/examples/c++/example.cpp index 2d7d051c5..035d032bc 100644 --- a/examples/c++/example.cpp +++ b/examples/c++/example.cpp @@ -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"; diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 64dd93faa..923b948a6 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -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') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3df33aac9..277335ce9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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) diff --git a/src/api/api_context.cpp b/src/api/api_context.cpp index c99d3f0c8..1e3f7a0a4 100644 --- a/src/api/api_context.cpp +++ b/src/api/api_context.cpp @@ -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() { diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index 851d96a4e..d667a7428 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -45,13 +45,13 @@ extern "C" { ptr_vector 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 const * decls = dt_util.get_datatype_constructors(tuple); - func_decl* decl = (*decls)[0]; + ptr_vector 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 const * accs = dt_util.get_constructor_accessors(decl); - if (!accs) { - SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); - } - ptr_vector const & _accs = *accs; + ptr_vector 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 const * decls = dt_util.get_datatype_constructors(e); - SASSERT(decls && decls->size() == n); + ptr_vector 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 const* acc = data_util.get_constructor_accessors(cnstrs[1]); - SASSERT(acc); - SASSERT(acc->size() == 2); - f = (*acc)[0]; + ptr_vector 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 const* acc = data_util.get_constructor_accessors(cnstrs[1]); - SASSERT(acc); - SASSERT(acc->size() == 2); - f = (*acc)[1]; + ptr_vector 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 const* accs = data_util.get_constructor_accessors(f); - if (!accs && num_fields > 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); - return; - } + ptr_vector 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 constrs; for (unsigned i = 0; i < num_constructors; ++i) { constructor* cn = reinterpret_cast(constructors[i]); ptr_vector 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 const* cnstrs = data_util.get_datatype_constructors(s); + ptr_vector const& cnstrs = *data_util.get_datatype_constructors(s); for (unsigned i = 0; i < num_constructors; ++i) { constructor* cn = reinterpret_cast(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 datas; for (unsigned i = 0; i < num_sorts; ++i) { constructor_list* cl = reinterpret_cast(constructor_lists[i]); - datas.push_back(mk_datatype_decl(c,sort_names[i], cl->size(), reinterpret_cast(cl->c_ptr()))); + datas.push_back(mk_datatype_decl(c, sort_names[i], cl->size(), reinterpret_cast(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_lists[i]); - ptr_vector const* cnstrs = data_util.get_datatype_constructors(s); + ptr_vector 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 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 const * decls = dt_util.get_datatype_constructors(_t); - if (!decls || idx >= decls->size()) { + ptr_vector 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 const * decls = dt_util.get_datatype_constructors(_t); - if (!decls || idx >= decls->size()) { + ptr_vector 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 const * decls = dt_util.get_datatype_constructors(_t); - if (!decls || idx_c >= decls->size()) { + ptr_vector 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 const * accs = dt_util.get_constructor_accessors(decl); - SASSERT(accs && accs->size() == decl->get_arity()); - if (!accs || accs->size() <= idx_a) { + ptr_vector 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 const * decls = dt_util.get_datatype_constructors(tuple); - if (!decls || decls->size() != 1) { + ptr_vector const & decls = *dt_util.get_datatype_constructors(tuple); + if (decls.size() != 1) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - ptr_vector const * accs = dt_util.get_constructor_accessors((*decls)[0]); - if (!accs) { - return 0; - } - return accs->size(); + ptr_vector 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 const * decls = dt_util.get_datatype_constructors(tuple); - if (!decls || decls->size() != 1) { + ptr_vector const & decls = *dt_util.get_datatype_constructors(tuple); + if (decls.size() != 1) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector 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 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); diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 1452a037e..39af03190 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -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] diff --git a/src/ast/array_decl_plugin.cpp b/src/ast/array_decl_plugin.cpp index 6296d344a..cb016e263 100644 --- a/src/ast/array_decl_plugin.cpp +++ b/src/ast/array_decl_plugin.cpp @@ -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++) { diff --git a/src/ast/array_decl_plugin.h b/src/ast/array_decl_plugin.h index 0febb82a4..0704fe56a 100644 --- a/src/ast/array_decl_plugin.h +++ b/src/ast/array_decl_plugin.h @@ -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 { diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 5c0abf6b8..bb81c1eba 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -188,18 +188,14 @@ decl_info::decl_info(decl_info const& other) : void decl_info::init_eh(ast_manager & m) { - vector::iterator it = m_parameters.begin(); - vector::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::iterator it = m_parameters.begin(); - vector::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::iterator it = m_sort_names.begin(); - svector::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::iterator it = m_plugins.begin(); - ptr_vector::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 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(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 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(); diff --git a/src/ast/ast.h b/src/ast/ast.h index e6beec7e6..4eb43d30b 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -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_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_ */ diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index a38f7cd1a..abb4ae959 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -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 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 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); diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 9ebfdfbef..906fd054b 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -21,17 +21,17 @@ Revision History: #include #include +#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 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 const* decls; - ptr_vector rec_sorts; + SASSERT(util.is_datatype(s)); - rec_sorts.push_back(s); - mark.mark(s, true); + sort_ref_vector ps(m_manager); + ptr_vector 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 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) { diff --git a/src/ast/ast_translation.cpp b/src/ast/ast_translation.cpp index 0c56b6de6..1bce4bcbe 100644 --- a/src/ast/ast_translation.cpp +++ b/src/ast/ast_translation.cpp @@ -37,11 +37,9 @@ void ast_translation::cleanup() { } void ast_translation::reset_cache() { - obj_map::iterator it = m_cache.begin(); - obj_map::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(); } diff --git a/src/ast/bv_decl_plugin.cpp b/src/ast/bv_decl_plugin.cpp index 4632b6604..b5c79f662 100644 --- a/src/ast/bv_decl_plugin.cpp +++ b/src/ast/bv_decl_plugin.cpp @@ -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(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(bv_size)) }; return m_manager.mk_app(get_fid(), OP_BV_NUM, 2, p, 0, 0); diff --git a/src/ast/bv_decl_plugin.h b/src/ast/bv_decl_plugin.h index 5e533cd98..a4ea7af80 100644 --- a/src/ast/bv_decl_plugin.h +++ b/src/ast/bv_decl_plugin.h @@ -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 { diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index f86668ea8..566487e60 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2006 Microsoft Corporation +Copyright (c) 2017 Microsoft Corporation Module Name: @@ -11,320 +11,703 @@ Abstract: Author: - Leonardo de Moura (leonardo) 2008-01-10. + Nikolaj Bjorner (nbjorner) 2017-9-1 Revision History: --*/ -#include "ast/datatype_decl_plugin.h" + #include "util/warning.h" +#include "ast/array_decl_plugin.h" +#include "ast/datatype_decl_plugin.h" #include "ast/ast_smt2_pp.h" +#include "ast/ast_translation.h" -/** - \brief Auxiliary class used to declare inductive datatypes. -*/ -class accessor_decl { - symbol m_name; - type_ref m_type; -public: - accessor_decl(const symbol & n, type_ref r):m_name(n), m_type(r) {} - symbol const & get_name() const { return m_name; } - type_ref const & get_type() const { return m_type; } -}; +namespace datatype { -accessor_decl * mk_accessor_decl(symbol const & n, type_ref const & t) { - return alloc(accessor_decl, n, t); -} - -void del_accessor_decl(accessor_decl * d) { - dealloc(d); -} - -void del_accessor_decls(unsigned num, accessor_decl * const * as) { - for (unsigned i = 0; i < num; i++) - del_accessor_decl(as[i]); -} - -/** - \brief Auxiliary class used to declare inductive datatypes. -*/ -class constructor_decl { - symbol m_name; - symbol m_recogniser_name; - ptr_vector m_accessors; -public: - constructor_decl(const symbol & n, const symbol & r, unsigned num_accessors, accessor_decl * const * accessors): - m_name(n), m_recogniser_name(r), m_accessors(num_accessors, accessors) {} - ~constructor_decl() { - std::for_each(m_accessors.begin(), m_accessors.end(), delete_proc()); - } - symbol const & get_name() const { return m_name; } - symbol const & get_recognizer_name() const { return m_recogniser_name; } - ptr_vector const & get_accessors() const { return m_accessors; } -}; - -constructor_decl * mk_constructor_decl(symbol const & n, symbol const & r, unsigned num_accessors, accessor_decl * const * accessors) { - return alloc(constructor_decl, n, r, num_accessors, accessors); -} - -void del_constructor_decl(constructor_decl * d) { - dealloc(d); -} - -void del_constructor_decls(unsigned num, constructor_decl * const * cs) { - for (unsigned i = 0; i < num; i++) - del_constructor_decl(cs[i]); -} - -/** - \brief Auxiliary class used to declare inductive datatypes. -*/ -class datatype_decl { - symbol m_name; - ptr_vector m_constructors; -public: - datatype_decl(const symbol & n, unsigned num_constructors, constructor_decl * const * constructors): - m_name(n), m_constructors(num_constructors, constructors) { - } - ~datatype_decl() { - std::for_each(m_constructors.begin(), m_constructors.end(), delete_proc()); - } - symbol const & get_name() const { return m_name; } - ptr_vector const & get_constructors() const { return m_constructors; } -}; - -datatype_decl * mk_datatype_decl(symbol const & n, unsigned num_constructors, constructor_decl * const * cs) { - return alloc(datatype_decl, n, num_constructors, cs); -} - -void del_datatype_decl(datatype_decl * d) { - dealloc(d); -} - -void del_datatype_decls(unsigned num, datatype_decl * const * ds) { - for (unsigned i = 0; i < num; i++) - del_datatype_decl(ds[i]); -} - -typedef buffer bool_buffer; - -struct invalid_datatype {}; - -static parameter const & read(unsigned num_parameters, parameter const * parameters, unsigned idx, bool_buffer & read_pos) { - if (idx >= num_parameters) { - throw invalid_datatype(); - } - if (idx >= read_pos.size()) { - read_pos.resize(idx+1, false); - } - read_pos[idx] = true; - return parameters[idx]; -} - -static int read_int(unsigned num_parameters, parameter const * parameters, unsigned idx, bool_buffer & read_pos) { - const parameter & r = read(num_parameters, parameters, idx, read_pos); - if (!r.is_int()) { - TRACE("datatype", tout << "expected integer parameter at position " << idx << " got: " << r << "\n";); - throw invalid_datatype(); - } - return r.get_int(); -} - -static symbol read_symbol(unsigned num_parameters, parameter const * parameters, unsigned idx, bool_buffer & read_pos) { - parameter const & r = read(num_parameters, parameters, idx, read_pos); - if (!r.is_symbol()) { - TRACE("datatype", tout << "expected symol parameter at position " << idx << " got: " << r << "\n";); - throw invalid_datatype(); - } - return r.get_symbol(); -} - -static sort* read_sort(unsigned num_parameters, parameter const * parameters, unsigned idx, bool_buffer & read_pos) { - parameter const & r = read(num_parameters, parameters, idx, read_pos); - if (!r.is_ast()) { - TRACE("datatype", tout << "expected ast parameter at position " << idx << " got: " << r << "\n";); - throw invalid_datatype(); - } - ast* a = r.get_ast(); - if (!is_sort(a)) { - throw invalid_datatype(); - } - return to_sort(a); -} - -enum status { - WHITE, - GRAY, - BLACK -}; - -/** - \brief Return true if the inductive datatype is recursive. - Pre-condition: The given argument constains the parameters of an inductive datatype. -*/ -static bool is_recursive_datatype(parameter const * parameters) { - unsigned num_types = parameters[0].get_int(); - unsigned top_tid = parameters[1].get_int(); - buffer already_found(num_types, WHITE); - buffer todo; - todo.push_back(top_tid); - while (!todo.empty()) { - unsigned tid = todo.back(); - if (already_found[tid] == BLACK) { - todo.pop_back(); - continue; + void accessor::fix_range(sort_ref_vector const& dts) { + if (!m_range) { + m_range = dts[m_index]; } - already_found[tid] = GRAY; - unsigned o = datatype_decl_plugin::constructor_offset(parameters, tid); // constructor offset - unsigned num_constructors = parameters[o].get_int(); - bool can_process = true; - for (unsigned s = 1; s <= num_constructors; s++) { - unsigned k_i = parameters[o + s].get_int(); - unsigned num_accessors = parameters[k_i + 2].get_int(); - for (unsigned r = 0; r < num_accessors; r++) { - parameter const & a_type = parameters[k_i + 4 + 2*r]; - if (a_type.is_int()) { - unsigned tid_prime = a_type.get_int(); - switch (already_found[tid_prime]) { - case WHITE: - todo.push_back(tid_prime); - can_process = false; - break; - case GRAY: - // type is recursive - return true; - case BLACK: - break; + } + + func_decl_ref accessor::instantiate(sort_ref_vector const& ps) const { + ast_manager& m = ps.get_manager(); + unsigned n = ps.size(); + SASSERT(m_range); + SASSERT(n == get_def().params().size()); + sort_ref range(m.substitute(m_range, n, get_def().params().c_ptr(), ps.c_ptr()), m); + sort_ref src(get_def().instantiate(ps)); + sort* srcs[1] = { src.get() }; + parameter pas[2] = { parameter(name()), parameter(get_constructor().name()) }; + return func_decl_ref(m.mk_func_decl(u().get_family_id(), OP_DT_ACCESSOR, 2, pas, 1, srcs, range), m); + } + + func_decl_ref accessor::instantiate(sort* dt) const { + sort_ref_vector sorts = get_def().u().datatype_params(dt); + return instantiate(sorts); + } + + def const& accessor::get_def() const { return m_constructor->get_def(); } + util& accessor::u() const { return m_constructor->u(); } + accessor* accessor::translate(ast_translation& tr) { + return alloc(accessor, tr.to(), name(), to_sort(tr(m_range.get()))); + } + + constructor::~constructor() { + for (accessor* a : m_accessors) dealloc(a); + m_accessors.reset(); + } + util& constructor::u() const { return m_def->u(); } + + func_decl_ref constructor::instantiate(sort_ref_vector const& ps) const { + ast_manager& m = ps.get_manager(); + sort_ref_vector domain(m); + for (accessor const* a : accessors()) { + domain.push_back(a->instantiate(ps)->get_range()); + } + sort_ref range = get_def().instantiate(ps); + parameter pas[1] = { parameter(name()) }; + return func_decl_ref(m.mk_func_decl(u().get_family_id(), OP_DT_CONSTRUCTOR, 1, pas, domain.size(), domain.c_ptr(), range), m); + } + + func_decl_ref constructor::instantiate(sort* dt) const { + sort_ref_vector sorts = get_def().u().datatype_params(dt); + return instantiate(sorts); + } + + constructor* constructor::translate(ast_translation& tr) { + constructor* result = alloc(constructor, m_name, m_recognizer); + for (accessor* a : *this) { + result->add(a->translate(tr)); + } + return result; + } + + + sort_ref def::instantiate(sort_ref_vector const& sorts) const { + sort_ref s(m); + TRACE("datatype", tout << "instantiate " << m_name << "\n";); + if (!m_sort) { + vector ps; + ps.push_back(parameter(m_name)); + for (sort * s : m_params) ps.push_back(parameter(s)); + m_sort = m.mk_sort(u().get_family_id(), DATATYPE_SORT, ps.size(), ps.c_ptr()); + } + if (sorts.empty()) { + return m_sort; + } + return sort_ref(m.substitute(m_sort, sorts.size(), m_params.c_ptr(), sorts.c_ptr()), m); + } + + def* def::translate(ast_translation& tr, util& u) { + SASSERT(&u.get_manager() == &tr.to()); + sort_ref_vector ps(tr.to()); + for (sort* p : m_params) { + ps.push_back(to_sort(tr(p))); + } + def* result = alloc(def, tr.to(), u, m_name, m_class_id, ps.size(), ps.c_ptr()); + for (constructor* c : *this) { + result->add(c->translate(tr)); + } + if (m_sort) result->m_sort = to_sort(tr(m_sort.get())); + return result; + } + + enum status { + GRAY, + BLACK + }; + + namespace param_size { + size* size::mk_offset(sort_size const& s) { return alloc(offset, s); } + size* size::mk_param(sort_ref& p) { return alloc(sparam, p); } + size* size::mk_plus(size* a1, size* a2) { return alloc(plus, a1, a2); } + size* size::mk_times(size* a1, size* a2) { return alloc(times, a1, a2); } + size* size::mk_times(ptr_vector& szs) { + if (szs.empty()) return mk_offset(sort_size(1)); + if (szs.size() == 1) return szs[0]; + size* r = szs[0]; + for (unsigned i = 1; i < szs.size(); ++i) { + r = mk_times(r, szs[i]); + } + return r; + } + size* size::mk_plus(ptr_vector& szs) { + if (szs.empty()) return mk_offset(sort_size(0)); + if (szs.size() == 1) return szs[0]; + size* r = szs[0]; + for (unsigned i = 1; i < szs.size(); ++i) { + r = mk_plus(r, szs[i]); + } + return r; + } + size* size::mk_power(size* a1, size* a2) { return alloc(power, a1, a2); } + } + + namespace decl { + + plugin::~plugin() { + finalize(); + } + + void plugin::finalize() { + for (auto& kv : m_defs) { + dealloc(kv.m_value); + } + m_defs.reset(); + m_util = 0; // force deletion + } + + util & plugin::u() const { + SASSERT(m_manager); + SASSERT(m_family_id != null_family_id); + if (m_util.get() == 0) { + m_util = alloc(util, *m_manager); + } + return *(m_util.get()); + } + + void plugin::inherit(decl_plugin* other_p, ast_translation& tr) { + plugin* p = dynamic_cast(other_p); + svector names; + ptr_vector new_defs; + SASSERT(p); + for (auto& kv : p->m_defs) { + def* d = kv.m_value; + if (!m_defs.contains(kv.m_key)) { + names.push_back(kv.m_key); + new_defs.push_back(d->translate(tr, u())); + } + } + for (def* d : new_defs) + m_defs.insert(d->name(), d); + m_class_id = m_defs.size(); + u().compute_datatype_size_functions(names); + } + + + struct invalid_datatype {}; + + sort * plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { + try { + if (k != DATATYPE_SORT) { + TRACE("datatype", tout << "invalid kind parameter to datatype\n";); + throw invalid_datatype(); + } + if (num_parameters < 1) { + TRACE("datatype", tout << "at least one parameter expected to datatype declaration\n";); + throw invalid_datatype(); + } + parameter const & name = parameters[0]; + if (!name.is_symbol()) { + TRACE("datatype", tout << "expected symol parameter at position " << 0 << " got: " << name << "\n";); + throw invalid_datatype(); + } + for (unsigned i = 1; i < num_parameters; ++i) { + parameter const& s = parameters[i]; + if (!s.is_ast() || !is_sort(s.get_ast())) { + TRACE("datatype", tout << "expected sort parameter at position " << i << " got: " << s << "\n";); + throw invalid_datatype(); + } + } + + sort* s = m_manager->mk_sort(name.get_symbol(), + sort_info(m_family_id, k, num_parameters, parameters, true)); + def* d = 0; + if (m_defs.find(s->get_name(), d) && d->sort_size()) { + obj_map S; + for (unsigned i = 0; i + 1 < num_parameters; ++i) { + sort* r = to_sort(parameters[i + 1].get_ast()); + S.insert(d->params()[i], r->get_num_elements()); + } + sort_size ts = d->sort_size()->eval(S); + TRACE("datatype", tout << name << " has size " << ts << "\n";); + s->set_num_elements(ts); + } + else { + TRACE("datatype", tout << "not setting size for " << name << "\n";); + } + return s; + } + catch (invalid_datatype) { + m_manager->raise_exception("invalid datatype"); + return 0; + } + } + + func_decl * plugin::mk_update_field( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) { + decl_kind k = OP_DT_UPDATE_FIELD; + ast_manager& m = *m_manager; + + if (num_parameters != 1 || !parameters[0].is_ast()) { + m.raise_exception("invalid parameters for datatype field update"); + return 0; + } + if (arity != 2) { + m.raise_exception("invalid number of arguments for datatype field update"); + return 0; + } + func_decl* acc = 0; + if (is_func_decl(parameters[0].get_ast())) { + acc = to_func_decl(parameters[0].get_ast()); + } + if (acc && !u().is_accessor(acc)) { + acc = 0; + } + if (!acc) { + m.raise_exception("datatype field update requires a datatype accessor as the second argument"); + return 0; + } + sort* dom = acc->get_domain(0); + sort* rng = acc->get_range(); + if (dom != domain[0]) { + m.raise_exception("first argument to field update should be a data-type"); + return 0; + } + if (rng != domain[1]) { + std::ostringstream buffer; + buffer << "second argument to field update should be " << mk_ismt2_pp(rng, m) + << " instead of " << mk_ismt2_pp(domain[1], m); + m.raise_exception(buffer.str().c_str()); + return 0; + } + range = domain[0]; + func_decl_info info(m_family_id, k, num_parameters, parameters); + return m.mk_func_decl(symbol("update-field"), arity, domain, range, info); + } + +#define VALIDATE_PARAM(_pred_) if (!(_pred_)) m_manager->raise_exception("invalid parameter to datatype function " #_pred_); + + func_decl * decl::plugin::mk_constructor(unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) { + ast_manager& m = *m_manager; + VALIDATE_PARAM(num_parameters == 1 && parameters[0].is_symbol() && range && u().is_datatype(range)); + // we blindly trust other conditions are met, including domain types. + symbol name = parameters[0].get_symbol(); + func_decl_info info(m_family_id, OP_DT_CONSTRUCTOR, num_parameters, parameters); + info.m_private_parameters = true; + return m.mk_func_decl(name, arity, domain, range, info); + } + + func_decl * decl::plugin::mk_recognizer(unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort *) { + ast_manager& m = *m_manager; + VALIDATE_PARAM(arity == 1 && num_parameters == 2 && parameters[1].is_symbol() && parameters[0].is_ast() && is_func_decl(parameters[0].get_ast())); + VALIDATE_PARAM(u().is_datatype(domain[0])); + // blindly trust that parameter is a constructor + sort* range = m_manager->mk_bool_sort(); + func_decl_info info(m_family_id, OP_DT_RECOGNISER, num_parameters, parameters); + info.m_private_parameters = true; + return m.mk_func_decl(symbol(parameters[1].get_symbol()), arity, domain, range, info); + } + + func_decl * decl::plugin::mk_is(unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort *) { + ast_manager& m = *m_manager; + VALIDATE_PARAM(arity == 1 && num_parameters == 1 && parameters[0].is_ast() && is_func_decl(parameters[0].get_ast())); + VALIDATE_PARAM(u().is_datatype(domain[0])); + // blindly trust that parameter is a constructor + sort* range = m_manager->mk_bool_sort(); + func_decl_info info(m_family_id, OP_DT_IS, num_parameters, parameters); + info.m_private_parameters = true; + return m.mk_func_decl(symbol("is"), arity, domain, range, info); + } + + func_decl * decl::plugin::mk_accessor(unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) + { + ast_manager& m = *m_manager; + VALIDATE_PARAM(arity == 1 && num_parameters == 2 && parameters[0].is_symbol() && parameters[1].is_symbol()); + VALIDATE_PARAM(u().is_datatype(domain[0])); + SASSERT(range); + func_decl_info info(m_family_id, OP_DT_ACCESSOR, num_parameters, parameters); + info.m_private_parameters = true; + symbol name = parameters[0].get_symbol(); + return m.mk_func_decl(name, arity, domain, range, info); + } + + func_decl * decl::plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) { + switch (k) { + case OP_DT_CONSTRUCTOR: + return mk_constructor(num_parameters, parameters, arity, domain, range); + case OP_DT_RECOGNISER: + return mk_recognizer(num_parameters, parameters, arity, domain, range); + case OP_DT_IS: + return mk_is(num_parameters, parameters, arity, domain, range); + case OP_DT_ACCESSOR: + return mk_accessor(num_parameters, parameters, arity, domain, range); + case OP_DT_UPDATE_FIELD: + return mk_update_field(num_parameters, parameters, arity, domain, range); + default: + m_manager->raise_exception("invalid datatype operator kind"); + return 0; + } + } + + def* plugin::mk(symbol const& name, unsigned n, sort * const * params) { + ast_manager& m = *m_manager; + return alloc(def, m, u(), name, m_class_id, n, params); + } + + + void plugin::end_def_block() { + ast_manager& m = *m_manager; + + sort_ref_vector sorts(m); + for (symbol const& s : m_def_block) { + def const& d = *m_defs[s]; + sort_ref_vector ps(m); + sorts.push_back(d.instantiate(ps)); + } + for (symbol const& s : m_def_block) { + def& d = *m_defs[s]; + for (constructor* c : d) { + for (accessor* a : *c) { + a->fix_range(sorts); } } } - } - if (can_process) { - already_found[tid] = BLACK; - todo.pop_back(); - } - } - return false; -} + if (!u().is_well_founded(sorts.size(), sorts.c_ptr())) { + m_manager->raise_exception("datatype is not well-founded"); + } -/** - \brief Return the size of the inductive datatype. - Pre-condition: The given argument constains the parameters of an inductive datatype. -*/ -static sort_size get_datatype_size(parameter const * parameters) { - unsigned num_types = parameters[0].get_int(); - unsigned top_tid = parameters[1].get_int(); - buffer szs(num_types, sort_size()); - buffer already_found(num_types, WHITE); - buffer todo; - todo.push_back(top_tid); - while (!todo.empty()) { - unsigned tid = todo.back(); - if (already_found[tid] == BLACK) { - todo.pop_back(); - continue; - } - already_found[tid] = GRAY; - unsigned o = datatype_decl_plugin::constructor_offset(parameters, tid); - unsigned num_constructors = parameters[o].get_int(); - bool is_very_big = false; - bool can_process = true; - for (unsigned s = 1; s <= num_constructors; s++) { - unsigned k_i = parameters[o+s].get_int(); - unsigned num_accessors = parameters[k_i+2].get_int(); - for (unsigned r = 0; r < num_accessors; r++) { - parameter const & a_type = parameters[k_i+4 + 2*r]; - if (a_type.is_int()) { - int tid_prime = a_type.get_int(); - switch (already_found[tid_prime]) { - case WHITE: - todo.push_back(tid_prime); - can_process = false; - break; - case GRAY: - // type is recursive - return sort_size(); - case BLACK: - break; - } - } - else { - SASSERT(a_type.is_ast()); - sort * ty = to_sort(a_type.get_ast()); - if (ty->is_infinite()) { - // type is infinite - return sort_size(); - } - else if (ty->is_very_big()) { - is_very_big = true; - } - } + u().compute_datatype_size_functions(m_def_block); + for (symbol const& s : m_def_block) { + sort_ref_vector ps(m); + m_defs[s]->instantiate(ps); } } - if (can_process) { - todo.pop_back(); - already_found[tid] = BLACK; - if (is_very_big) { - szs[tid] = sort_size::mk_very_big(); + + bool plugin::mk_datatypes(unsigned num_datatypes, def * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_sorts) { + begin_def_block(); + for (unsigned i = 0; i < num_datatypes; ++i) { + def* d = 0; + TRACE("datatype", tout << "declaring " << datatypes[i]->name() << "\n";); + if (m_defs.find(datatypes[i]->name(), d)) { + TRACE("datatype", tout << "delete previous version for " << datatypes[i]->name() << "\n";); + dealloc(d); + } + m_defs.insert(datatypes[i]->name(), datatypes[i]); + m_def_block.push_back(datatypes[i]->name()); + } + end_def_block(); + sort_ref_vector ps(*m_manager); + for (symbol const& s : m_def_block) { + new_sorts.push_back(m_defs[s]->instantiate(ps)); + } + return true; + } + + void plugin::remove(symbol const& s) { + def* d = 0; + if (m_defs.find(s, d)) dealloc(d); + m_defs.remove(s); + } + + bool plugin::is_value_visit(expr * arg, ptr_buffer & todo) const { + if (!is_app(arg)) + return false; + family_id fid = to_app(arg)->get_family_id(); + if (fid == m_family_id) { + if (!u().is_constructor(to_app(arg))) + return false; + if (to_app(arg)->get_num_args() == 0) + return true; + todo.push_back(to_app(arg)); + return true; } else { - // the type is not infinite nor the number of elements is infinite... - // computing the number of elements - rational num; - for (unsigned s = 1; s <= num_constructors; s++) { - unsigned k_i = parameters[o+s].get_int(); - unsigned num_accessors = parameters[k_i+2].get_int(); - rational c_num(1); - for (unsigned r = 0; r < num_accessors; r++) { - parameter const & a_type = parameters[k_i+4 + 2*r]; - if (a_type.is_int()) { - int tid_prime = a_type.get_int(); - SASSERT(!szs[tid_prime].is_infinite() && !szs[tid_prime].is_very_big()); - c_num *= rational(szs[tid_prime].size(),rational::ui64()); - } - else { - SASSERT(a_type.is_ast()); - sort * ty = to_sort(a_type.get_ast()); - SASSERT(!ty->is_infinite() && !ty->is_very_big()); - c_num *= rational(ty->get_num_elements().size(), rational::ui64()); - } - } - num += c_num; - } - szs[tid] = sort_size(num); + return m_manager->is_value(arg); + } + } + + bool plugin::is_value(app * e) const { + TRACE("dt_is_value", tout << "checking\n" << mk_ismt2_pp(e, *m_manager) << "\n";); + if (!u().is_constructor(e)) + return false; + if (e->get_num_args() == 0) + return true; + // REMARK: if the following check is too expensive, we should + // cache the values in the decl::plugin. + ptr_buffer todo; + // potentially expensive check for common sub-expressions. + for (expr* arg : *e) { + if (!is_value_visit(arg, todo)) { + TRACE("dt_is_value", tout << "not-value:\n" << mk_ismt2_pp(arg, *m_manager) << "\n";); + return false; + } + } + while (!todo.empty()) { + app * curr = todo.back(); + SASSERT(u().is_constructor(curr)); + todo.pop_back(); + for (expr* arg : *curr) { + if (!is_value_visit(arg, todo)) { + TRACE("dt_is_value", tout << "not-value:\n" << mk_ismt2_pp(arg, *m_manager) << "\n";); + return false; + } + } + } + return true; + } + + void plugin::get_op_names(svector & op_names, symbol const & logic) { + op_names.push_back(builtin_name("is", OP_DT_IS)); + if (logic == symbol::null) { + op_names.push_back(builtin_name("update-field", OP_DT_UPDATE_FIELD)); } } - } - return szs[top_tid]; -} -/** - \brief Return true if the inductive datatype is well-founded. - Pre-condition: The given argument constains the parameters of an inductive datatype. -*/ -static bool is_well_founded(parameter const * parameters) { - unsigned num_types = parameters[0].get_int(); - buffer well_founded(num_types, false); - unsigned num_well_founded = 0; - bool changed; - do { - changed = false; - for (unsigned tid = 0; tid < num_types; tid++) { - if (!well_founded[tid]) { - unsigned o = datatype_decl_plugin::constructor_offset(parameters, tid); // constructor offset - unsigned num_constructors = parameters[o].get_int(); - for (unsigned s = 1; s <= num_constructors; s++) { - unsigned k_i = parameters[o + s].get_int(); - unsigned num_accessors = parameters[k_i + 2].get_int(); - unsigned r = 0; - for (; r < num_accessors; r++) { - parameter const & a_type = parameters[k_i + 4 + 2*r]; - if (a_type.is_int() && !well_founded[a_type.get_int()]) { + expr * plugin::get_some_value(sort * s) { + SASSERT(u().is_datatype(s)); + func_decl * c = u().get_non_rec_constructor(s); + ptr_buffer args; + for (unsigned i = 0; i < c->get_arity(); i++) { + args.push_back(m_manager->get_some_value(c->get_domain(i))); + } + return m_manager->mk_app(c, args.size(), args.c_ptr()); + } + + bool plugin::is_fully_interp(sort * s) const { + return u().is_fully_interp(s); + } + } + + sort_ref_vector util::datatype_params(sort * s) const { + SASSERT(is_datatype(s)); + sort_ref_vector result(m); + for (unsigned i = 1; i < s->get_num_parameters(); ++i) { + result.push_back(to_sort(s->get_parameter(i).get_ast())); + } + return result; + } + + + bool util::is_fully_interp(sort * s) const { + SASSERT(is_datatype(s)); + bool fi = true; + return fi; + if (m_is_fully_interp.find(s, fi)) { + return fi; + } + unsigned sz = m_fully_interp_trail.size(); + m_is_fully_interp.insert(s, true); + def const& d = get_def(s); + bool is_interp = true; + m_fully_interp_trail.push_back(s); + for (constructor const* c : d) { + for (accessor const* a : *c) { + func_decl_ref ac = a->instantiate(s); + sort* r = ac->get_range(); + if (!m.is_fully_interp(r)) { + is_interp = false; + break; + } + } + if (!is_interp) break; + } + for (unsigned i = sz; i < m_fully_interp_trail.size(); ++i) { + m_is_fully_interp.remove(m_fully_interp_trail[i]); + } + m_fully_interp_trail.shrink(sz); + m_is_fully_interp.insert(s, is_interp); + m_asts.push_back(s); + return true; + } + + /** + \brief Return true if the inductive datatype is recursive. + */ + bool util::is_recursive_core(sort* s) const { + obj_map already_found; + ptr_vector todo, subsorts; + todo.push_back(s); + status st; + while (!todo.empty()) { + s = todo.back(); + if (already_found.find(s, st) && st == BLACK) { + todo.pop_back(); + continue; + } + already_found.insert(s, GRAY); + def const& d = get_def(s); + bool can_process = true; + for (constructor const* c : d) { + for (accessor const* a : *c) { + sort* d = a->range(); + // check if d is a datatype sort + subsorts.reset(); + get_subsorts(d, subsorts); + for (sort * s2 : subsorts) { + if (is_datatype(s2)) { + if (already_found.find(s2, st)) { + // type is recursive + if (st == GRAY) return true; + } + else { + todo.push_back(s2); + can_process = false; + } + } + } + } + } + if (can_process) { + already_found.insert(s, BLACK); + todo.pop_back(); + } + } + return false; + } + + unsigned util::get_datatype_num_parameter_sorts(sort * ty) { + SASSERT(ty->get_num_parameters() >= 1); + return ty->get_num_parameters() - 1; + } + + sort* util::get_datatype_parameter_sort(sort * ty, unsigned idx) { + SASSERT(idx < get_datatype_num_parameter_sorts(ty)); + return to_sort(ty->get_parameter(idx+1).get_ast()); + } + + param_size::size* util::get_sort_size(sort_ref_vector const& params, sort* s) { + if (params.empty()) { + return param_size::size::mk_offset(s->get_num_elements()); + } + if (is_datatype(s)) { + param_size::size* sz; + obj_map S; + unsigned n = get_datatype_num_parameter_sorts(s); + for (unsigned i = 0; i < n; ++i) { + sort* ps = get_datatype_parameter_sort(s, i); + sz = get_sort_size(params, ps); + sz->inc_ref(); + S.insert(ps, sz); + } + def & d = get_def(s->get_name()); + sz = d.sort_size()->subst(S); + for (auto & kv : S) { + kv.m_value->dec_ref(); + } + return sz; + } + array_util autil(m); + if (autil.is_array(s)) { + unsigned n = get_array_arity(s); + ptr_vector szs; + for (unsigned i = 0; i < n; ++i) { + szs.push_back(get_sort_size(params, get_array_domain(s, i))); + } + param_size::size* sz1 = param_size::size::mk_times(szs); + param_size::size* sz2 = get_sort_size(params, get_array_range(s)); + return param_size::size::mk_power(sz2, sz1); + } + for (sort* p : params) { + if (s == p) { + sort_ref sr(s, m); + return param_size::size::mk_param(sr); + } + } + return param_size::size::mk_offset(s->get_num_elements()); + } + + bool util::is_declared(sort* s) const { + return m_plugin->is_declared(s); + } + + void util::compute_datatype_size_functions(svector const& names) { + map already_found; + map szs; + + svector todo(names); + status st; + while (!todo.empty()) { + symbol s = todo.back(); + TRACE("datatype", tout << "Sort size for " << s << "\n";); + + if (already_found.find(s, st) && st == BLACK) { + todo.pop_back(); + continue; + } + already_found.insert(s, GRAY); + bool is_infinite = false; + bool can_process = true; + def& d = get_def(s); + for (constructor const* c : d) { + for (accessor const* a : *c) { + sort* r = a->range(); + if (is_datatype(r)) { + symbol s2 = r->get_name(); + if (already_found.find(s2, st)) { + // type is infinite + if (st == GRAY) { + is_infinite = true; + } + } + else if (names.contains(s2)) { + todo.push_back(s2); + can_process = false; + } + } + } + } + if (!can_process) { + continue; + } + todo.pop_back(); + already_found.insert(s, BLACK); + if (is_infinite) { + d.set_sort_size(param_size::size::mk_offset(sort_size::mk_infinite())); + continue; + } + + ptr_vector s_add; + for (constructor const* c : d) { + ptr_vector s_mul; + for (accessor const* a : *c) { + s_mul.push_back(get_sort_size(d.params(), a->range())); + } + s_add.push_back(param_size::size::mk_times(s_mul)); + } + d.set_sort_size(param_size::size::mk_plus(s_add)); + } + } + + + /** + \brief Return true if the inductive datatype is well-founded. + Pre-condition: The given argument constains the parameters of an inductive datatype. + */ + bool util::is_well_founded(unsigned num_types, sort* const* sorts) { + buffer well_founded(num_types, false); + obj_map sort2id; + for (unsigned i = 0; i < num_types; ++i) { + sort2id.insert(sorts[i], i); + } + unsigned num_well_founded = 0, id = 0; + bool changed; + do { + changed = false; + for (unsigned tid = 0; tid < num_types; tid++) { + if (well_founded[tid]) { + continue; + } + sort* s = sorts[tid]; + def const& d = get_def(s); + for (constructor const* c : d) { + bool found_nonwf = false; + for (accessor const* a : *c) { + if (sort2id.find(a->range(), id) && !well_founded[id]) { + found_nonwf = true; break; } } - if (r == num_accessors) { + if (!found_nonwf) { changed = true; well_founded[tid] = true; num_well_founded++; @@ -332,761 +715,358 @@ static bool is_well_founded(parameter const * parameters) { } } } - } - } while(changed && num_well_founded < num_types); - unsigned tid = parameters[1].get_int(); - return well_founded[tid]; -} - -datatype_decl_plugin::~datatype_decl_plugin() { - SASSERT(m_util.get() == 0); -} - -void datatype_decl_plugin::finalize() { - m_util = 0; // force deletion -} - -datatype_util & datatype_decl_plugin::get_util() const { - SASSERT(m_manager); - if (m_util.get() == 0) { - m_util = alloc(datatype_util, *m_manager); + } + while(changed && num_well_founded < num_types); + return num_well_founded == num_types; } - return *(m_util.get()); -} - -sort * datatype_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { - try { - if (k != DATATYPE_SORT) { - throw invalid_datatype(); - } - buffer found; - unsigned num_types = read_int(num_parameters, parameters, 0, found); - if (num_types == 0) { - throw invalid_datatype(); - } - unsigned tid = read_int(num_parameters, parameters, 1, found); - unsigned num_sort_params = read_int(num_parameters, parameters, 2, found); - for (unsigned j = 0; j < num_sort_params; ++j) { - read_sort(num_parameters, parameters, 3 + j, found); - } - unsigned c_offset = constructor_offset(parameters); - for (unsigned j = 0; j < num_types; j++) { - read_symbol(num_parameters, parameters, c_offset + 2*j, found); // type name - unsigned o = read_int(num_parameters, parameters, c_offset + 2*j + 1, found); - unsigned num_constructors = read_int(num_parameters, parameters, o, found); - if (num_constructors == 0) { - throw invalid_datatype(); + def const& util::get_def(sort* s) const { + return m_plugin->get_def(s); + } + + void util::get_subsorts(sort* s, ptr_vector& sorts) const { + sorts.push_back(s); + for (unsigned i = 0; i < s->get_num_parameters(); ++i) { + parameter const& p = s->get_parameter(i); + if (p.is_ast() && is_sort(p.get_ast())) { + get_subsorts(to_sort(p.get_ast()), sorts); } - for (unsigned s = 1; s <= num_constructors; s++) { - unsigned k_i = read_int(num_parameters, parameters, o + s, found); - read_symbol(num_parameters, parameters, k_i, found); // constructor name - read_symbol(num_parameters, parameters, k_i + 1, found); // recognizer name - unsigned num_accessors = read_int(num_parameters, parameters, k_i + 2, found); - unsigned first_accessor = k_i+3; - for (unsigned r = 0; r < num_accessors; r++) { - read_symbol(num_parameters, parameters, first_accessor + 2*r, found); // accessor name - parameter const & a_type = read(num_parameters, parameters, first_accessor + 2*r + 1, found); // accessort type - if (!a_type.is_int() && !a_type.is_ast()) { - throw invalid_datatype(); - } - if (a_type.is_ast() && !is_sort(a_type.get_ast())) { - throw invalid_datatype(); - } + } + } + + + util::util(ast_manager & m): + m(m), + m_family_id(m.mk_family_id("datatype")), + m_asts(m), + m_start(0) { + m_plugin = dynamic_cast(m.get_plugin(m_family_id)); + SASSERT(m_plugin); + } + + util::~util() { + std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc >()); + } + + ptr_vector const * util::get_datatype_constructors(sort * ty) { + SASSERT(is_datatype(ty)); + ptr_vector * r = 0; + if (m_datatype2constructors.find(ty, r)) + return r; + r = alloc(ptr_vector); + m_asts.push_back(ty); + m_vectors.push_back(r); + m_datatype2constructors.insert(ty, r); + def const& d = get_def(ty); + for (constructor const* c : d) { + func_decl_ref f = c->instantiate(ty); + m_asts.push_back(f); + r->push_back(f); + } + return r; + } + + ptr_vector const * util::get_constructor_accessors(func_decl * con) { + SASSERT(is_constructor(con)); + ptr_vector * res = 0; + if (m_constructor2accessors.find(con, res)) { + return res; + } + res = alloc(ptr_vector); + m_asts.push_back(con); + m_vectors.push_back(res); + m_constructor2accessors.insert(con, res); + sort * datatype = con->get_range(); + def const& d = get_def(datatype); + for (constructor const* c : d) { + if (c->name() == con->get_name()) { + for (accessor const* a : *c) { + func_decl_ref fn = a->instantiate(datatype); + res->push_back(fn); + m_asts.push_back(fn); } + break; } } - // check if there is no garbage - if (found.size() != num_parameters || std::find(found.begin(), found.end(), false) != found.end()) { - throw invalid_datatype(); - } + return res; + } - if (!is_well_founded(parameters)) { - m_manager->raise_exception("datatype is not well-founded"); - return 0; - } - - // compute datatype size - sort_size ts = get_datatype_size(parameters); - symbol const & tname = parameters[c_offset + 2*tid].get_symbol(); - return m_manager->mk_sort(tname, - sort_info(m_family_id, k, ts, num_parameters, parameters, true)); - } - catch (invalid_datatype) { - m_manager->raise_exception("invalid datatype"); - return 0; - } -} - -static sort * get_other_datatype(ast_manager & m, family_id datatype_fid, sort * source_datatype, unsigned tid) { - SASSERT(source_datatype->get_family_id() == datatype_fid); - SASSERT(source_datatype->get_decl_kind() == DATATYPE_SORT); - if (tid == static_cast(source_datatype->get_parameter(1).get_int())) { - return source_datatype; - } - buffer p; - unsigned n = source_datatype->get_num_parameters(); - for (unsigned i = 0; i < n; i++) { - p.push_back(source_datatype->get_parameter(i)); - } - p[1] = parameter(tid); - return m.mk_sort(datatype_fid, DATATYPE_SORT, n, p.c_ptr()); -} - -static sort * get_type(ast_manager & m, family_id datatype_fid, sort * source_datatype, parameter const & p) { - SASSERT(p.is_ast() || p.is_int()); - if (p.is_ast()) { - return to_sort(p.get_ast()); - } - else { - return get_other_datatype(m, datatype_fid, source_datatype, p.get_int()); - } -} - -func_decl * datatype_decl_plugin::mk_update_field( - unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - decl_kind k = OP_DT_UPDATE_FIELD; - ast_manager& m = *m_manager; - - if (num_parameters != 1 || !parameters[0].is_ast()) { - m.raise_exception("invalid parameters for datatype field update"); - return 0; - } - if (arity != 2) { - m.raise_exception("invalid number of arguments for datatype field update"); - return 0; - } - func_decl* acc = 0; - if (is_func_decl(parameters[0].get_ast())) { - acc = to_func_decl(parameters[0].get_ast()); - } - if (acc && !get_util().is_accessor(acc)) { - acc = 0; - } - if (!acc) { - m.raise_exception("datatype field update requires a datatype accessor as the second argument"); - return 0; - } - sort* dom = acc->get_domain(0); - sort* rng = acc->get_range(); - if (dom != domain[0]) { - m.raise_exception("first argument to field update should be a data-type"); - return 0; - } - if (rng != domain[1]) { - std::ostringstream buffer; - buffer << "second argument to field update should be " << mk_ismt2_pp(rng, m) - << " instead of " << mk_ismt2_pp(domain[1], m); - m.raise_exception(buffer.str().c_str()); - return 0; - } - range = domain[0]; - func_decl_info info(m_family_id, k, num_parameters, parameters); - return m.mk_func_decl(symbol("update-field"), arity, domain, range, info); -} - -func_decl * datatype_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range) { - - if (k == OP_DT_UPDATE_FIELD) { - return mk_update_field(num_parameters, parameters, arity, domain, range); - } - if (num_parameters < 2 || !parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) { - m_manager->raise_exception("invalid parameters for datatype operator"); - return 0; - } - sort * datatype = to_sort(parameters[0].get_ast()); - if (datatype->get_family_id() != m_family_id || - datatype->get_decl_kind() != DATATYPE_SORT) { - m_manager->raise_exception("invalid parameters for datatype operator"); - return 0; - } - for (unsigned i = 1; i < num_parameters; i++) { - if (!parameters[i].is_int()) { - m_manager->raise_exception("invalid parameters for datatype operator"); - return 0; - } - } - unsigned c_idx = parameters[1].get_int(); - unsigned tid = datatype->get_parameter(1).get_int(); - unsigned o = datatype_decl_plugin::constructor_offset(datatype, tid); - unsigned num_constructors = datatype->get_parameter(o).get_int(); - if (c_idx >= num_constructors) { - m_manager->raise_exception("invalid parameters for datatype operator"); - return 0; - } - unsigned k_i = datatype->get_parameter(o + 1 + c_idx).get_int(); - - switch (k) { - case OP_DT_CONSTRUCTOR: - if (num_parameters != 2) { - m_manager->raise_exception("invalid parameters for datatype constructor"); - return 0; - } - else { - symbol c_name = datatype->get_parameter(k_i).get_symbol(); - unsigned num_accessors = datatype->get_parameter(k_i + 2).get_int(); - if (num_accessors != arity) { - m_manager->raise_exception("invalid domain size for datatype constructor"); - return 0; + func_decl * util::get_constructor_recognizer(func_decl * con) { + SASSERT(is_constructor(con)); + func_decl * d = 0; + if (m_constructor2recognizer.find(con, d)) + return d; + sort * datatype = con->get_range(); + def const& dd = get_def(datatype); + symbol r; + for (constructor const* c : dd) { + if (c->name() == con->get_name()) { + r = c->recognizer(); } + } + parameter ps[2] = { parameter(con), parameter(r) }; + d = m.mk_func_decl(m_family_id, OP_DT_RECOGNISER, 2, ps, 1, &datatype); + SASSERT(d); + m_asts.push_back(con); + m_asts.push_back(d); + m_constructor2recognizer.insert(con, d); + return d; + } - // - // the reference count to domain could be 0. - // we need to ensure that creating a temporary - // copy of the same type causes a free. - // - sort_ref_vector domain_check(*m_manager); + func_decl * util::get_recognizer_constructor(func_decl * recognizer) const { + SASSERT(is_recognizer(recognizer)); + return to_func_decl(recognizer->get_parameter(0).get_ast()); + } - for (unsigned r = 0; r < num_accessors; r++) { - sort_ref ty(*m_manager); - ty = get_type(*m_manager, m_family_id, datatype, datatype->get_parameter(k_i + 4 + 2*r)); - domain_check.push_back(ty); - if (ty != domain[r]) { - m_manager->raise_exception("invalid domain for datatype constructor"); - return 0; + bool util::is_recursive(sort * ty) { + SASSERT(is_datatype(ty)); + bool r = false; + if (!m_is_recursive.find(ty, r)) { + r = is_recursive_core(ty); + m_is_recursive.insert(ty, r); + m_asts.push_back(ty); + } + return r; + } + + bool util::is_enum_sort(sort* s) { + if (!is_datatype(s)) { + return false; + } + bool r = false; + if (m_is_enum.find(s, r)) + return r; + ptr_vector const& cnstrs = *get_datatype_constructors(s); + r = true; + for (unsigned i = 0; r && i < cnstrs.size(); ++i) { + r = cnstrs[i]->get_arity() == 0; + } + m_is_enum.insert(s, r); + m_asts.push_back(s); + return r; + } + + func_decl * util::get_accessor_constructor(func_decl * accessor) { + SASSERT(is_accessor(accessor)); + func_decl * r = 0; + if (m_accessor2constructor.find(accessor, r)) + return r; + sort * datatype = accessor->get_domain(0); + symbol c_id = accessor->get_parameter(1).get_symbol(); + def const& d = get_def(datatype); + func_decl_ref fn(m); + for (constructor const* c : d) { + if (c->name() == c_id) { + fn = c->instantiate(datatype); + break; + } + } + r = fn; + m_accessor2constructor.insert(accessor, r); + m_asts.push_back(accessor); + m_asts.push_back(r); + return r; + } + + + void util::reset() { + m_datatype2constructors.reset(); + m_datatype2nonrec_constructor.reset(); + m_constructor2accessors.reset(); + m_constructor2recognizer.reset(); + m_recognizer2constructor.reset(); + m_accessor2constructor.reset(); + m_is_recursive.reset(); + m_is_enum.reset(); + std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc >()); + m_vectors.reset(); + m_asts.reset(); + ++m_start; + } + + + /** + \brief Return a constructor mk(T_1, ... T_n) + where each T_i is not a datatype or it is a datatype that contains + a constructor that will not contain directly or indirectly an element of the given sort. + */ + func_decl * util::get_non_rec_constructor(sort * ty) { + SASSERT(is_datatype(ty)); + func_decl * r = 0; + if (m_datatype2nonrec_constructor.find(ty, r)) + return r; + r = 0; + ptr_vector forbidden_set; + forbidden_set.push_back(ty); + TRACE("util_bug", tout << "invoke get-non-rec: " << sort_ref(ty, m) << "\n";); + r = get_non_rec_constructor_core(ty, forbidden_set); + SASSERT(forbidden_set.back() == ty); + SASSERT(r); + m_asts.push_back(ty); + m_asts.push_back(r); + m_datatype2nonrec_constructor.insert(ty, r); + return r; + } + + /** + \brief Return a constructor mk(T_1, ..., T_n) where + each T_i is not a datatype or it is a datatype t not in forbidden_set, + and get_non_rec_constructor_core(T_i, forbidden_set union { T_i }) + */ + func_decl * util::get_non_rec_constructor_core(sort * ty, ptr_vector & forbidden_set) { + // We must select a constructor c(T_1, ..., T_n):T such that + // 1) T_i's are not recursive + // If there is no such constructor, then we select one that + // 2) each type T_i is not recursive or contains a constructor that does not depend on T + + ptr_vector const& constructors = *get_datatype_constructors(ty); + unsigned sz = constructors.size(); + TRACE("util_bug", tout << "get-non-rec constructor: " << sort_ref(ty, m) << "\n"; + tout << "forbidden: "; + for (sort* s : forbidden_set) tout << sort_ref(s, m) << " "; + tout << "\n"; + tout << "constructors: " << sz << "\n"; + for (func_decl* f : constructors) tout << func_decl_ref(f, m) << "\n"; + ); + // step 1) + unsigned start = ++m_start; + for (unsigned j = 0; j < sz; ++j) { + func_decl * c = constructors[(j + start) % sz]; + TRACE("util_bug", tout << "checking " << sort_ref(ty, m) << ": " << func_decl_ref(c, m) << "\n";); + unsigned num_args = c->get_arity(); + unsigned i = 0; + for (; i < num_args && !is_datatype(c->get_domain(i)); i++); + if (i == num_args) { + TRACE("util_bug", tout << "found non-rec " << func_decl_ref(c, m) << "\n";); + return c; + } + } + // step 2) + for (unsigned j = 0; j < sz; ++j) { + func_decl * c = constructors[(j + start) % sz]; + TRACE("util_bug", tout << "non_rec_constructor c: " << j << " " << func_decl_ref(c, m) << "\n";); + unsigned num_args = c->get_arity(); + unsigned i = 0; + for (; i < num_args; i++) { + sort * T_i = c->get_domain(i); + TRACE("util_bug", tout << "c: " << i << " " << sort_ref(T_i, m) << "\n";); + if (!is_datatype(T_i)) { + TRACE("util_bug", tout << sort_ref(T_i, m) << " is not a datatype\n";); + continue; } + if (std::find(forbidden_set.begin(), forbidden_set.end(), T_i) != forbidden_set.end()) { + TRACE("util_bug", tout << sort_ref(T_i, m) << " is in forbidden_set\n";); + break; + } + forbidden_set.push_back(T_i); + func_decl * nested_c = get_non_rec_constructor_core(T_i, forbidden_set); + SASSERT(forbidden_set.back() == T_i); + forbidden_set.pop_back(); + if (nested_c == 0) + break; + TRACE("util_bug", tout << "nested_c: " << nested_c->get_name() << "\n";); + } + if (i == num_args) + return c; + } + return 0; + } + unsigned util::get_constructor_idx(func_decl * f) const { + unsigned idx = 0; + def const& d = get_def(f->get_range()); + for (constructor* c : d) { + if (c->name() == f->get_name()) { + return idx; } - func_decl_info info(m_family_id, k, num_parameters, parameters); - info.m_private_parameters = true; - SASSERT(info.private_parameters()); - return m_manager->mk_func_decl(c_name, arity, domain, datatype, info); + ++idx; } - case OP_DT_RECOGNISER: - if (num_parameters != 2 || arity != 1 || domain[0] != datatype) { - m_manager->raise_exception("invalid parameters for datatype recogniser"); - return 0; - } - else { - symbol r_name = datatype->get_parameter(k_i + 1).get_symbol(); - sort * b = m_manager->mk_bool_sort(); - func_decl_info info(m_family_id, k, num_parameters, parameters); - info.m_private_parameters = true; - SASSERT(info.private_parameters()); - return m_manager->mk_func_decl(r_name, arity, domain, b, info); - } - case OP_DT_ACCESSOR: - if (num_parameters != 3 || arity != 1 || domain[0] != datatype) { - m_manager->raise_exception("invalid parameters for datatype accessor"); - return 0; - } - else { - unsigned a_idx = parameters[2].get_int(); - unsigned num_accessors = datatype->get_parameter(k_i + 2).get_int(); - if (a_idx >= num_accessors) { - m_manager->raise_exception("invalid datatype accessor"); - return 0; - } - symbol a_name = datatype->get_parameter(k_i + 3 + 2*a_idx).get_symbol(); - sort * a_type = get_type(*m_manager, m_family_id, datatype, datatype->get_parameter(k_i + 4 + 2*a_idx)); - func_decl_info info(m_family_id, k, num_parameters, parameters); - info.m_private_parameters = true; - SASSERT(info.private_parameters()); - return m_manager->mk_func_decl(a_name, arity, domain, a_type, info); - } - break; - case OP_DT_UPDATE_FIELD: UNREACHABLE(); return 0; - default: - m_manager->raise_exception("invalid datatype operator kind"); - return 0; } -} -bool datatype_decl_plugin::mk_datatypes(unsigned num_datatypes, datatype_decl * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_types) { - buffer p; - p.push_back(parameter(num_datatypes)); - p.push_back(parameter(-1)); - p.push_back(parameter(num_params)); - for (unsigned i = 0; i < num_params; ++i) { - p.push_back(parameter(sort_params[i])); + unsigned util::get_recognizer_constructor_idx(func_decl * f) const { + return get_constructor_idx(get_recognizer_constructor(f)); } - - unsigned c_offset = constructor_offset(p.c_ptr()); - for (unsigned i = 0; i < num_datatypes; i++) { - p.push_back(parameter(datatypes[i]->get_name())); - p.push_back(parameter(-1)); // offset is unknown at this point - } - for (unsigned i = 0; i < num_datatypes; i++) { - p[c_offset + 1 + 2*i] = parameter(p.size()); // save offset to constructor table - ptr_vector const & constructors = datatypes[i]->get_constructors(); - unsigned num_constructors = constructors.size(); - p.push_back(parameter(num_constructors)); - for (unsigned j = 0; j < num_constructors; j++) { - p.push_back(parameter(-1)); // offset is unknown at this point + + /** + \brief Two datatype sorts s1 and s2 are siblings if they were + defined together in the same mutually recursive definition. + */ + bool util::are_siblings(sort * s1, sort * s2) { + if (!is_datatype(s1) || !is_datatype(s2)) { + return s1 == s2; + } + else { + return get_def(s1).id() == get_def(s2).id(); } } - for (unsigned i = 0; i < num_datatypes; i++) { - unsigned o = constructor_offset(p.c_ptr(), i); - ptr_vector const & constructors = datatypes[i]->get_constructors(); - unsigned num_constructors = constructors.size(); - for (unsigned j = 0; j < num_constructors; j++) { - p[o+1+j] = parameter(p.size()); // save offset to constructor definition - constructor_decl * c = constructors[j]; - p.push_back(parameter(c->get_name())); - p.push_back(parameter(c->get_recognizer_name())); - ptr_vector const & accessors = c->get_accessors(); - unsigned num_accessors = accessors.size(); - p.push_back(parameter(num_accessors)); - for (unsigned k = 0; k < num_accessors; k++) { - accessor_decl * a = accessors[k]; - p.push_back(parameter(a->get_name())); - type_ref const & ty = a->get_type(); - if (ty.is_idx()) { - if (static_cast(ty.get_idx()) >= num_datatypes) { - TRACE("datatype", tout << "Index out of bounds: " << ty.get_idx() << "\n";); - return false; + + unsigned util::get_datatype_num_constructors(sort * ty) { + def const& d = get_def(ty->get_name()); + return d.constructors().size(); + } + + void util::get_defs(sort* s0, ptr_vector& defs) { + svector mark; + ptr_buffer todo; + todo.push_back(s0); + mark.push_back(s0->get_name()); + while (!todo.empty()) { + sort* s = todo.back(); + todo.pop_back(); + defs.push_back(&m_plugin->get_def(s->get_name())); + def const& d = get_def(s); + for (constructor* c : d) { + for (accessor* a : *c) { + sort* s = a->range(); + if (are_siblings(s0, s) && !mark.contains(s->get_name())) { + mark.push_back(s->get_name()); + todo.push_back(s); } - p.push_back(parameter(ty.get_idx())); - } - else { - p.push_back(parameter(ty.get_sort())); } } } } - for (unsigned i = 0; i < num_datatypes; i++) { - p[1] = parameter(i); - TRACE("datatype", tout << "new datatype parameters:\n"; - for (unsigned j = 0; j < p.size(); j++) { - tout << "p[" << j << "] -> " << p[j] << "\n"; - }); - sort * ty = mk_sort(DATATYPE_SORT, p.size(), p.c_ptr()); - if (ty == 0) { - TRACE("datatype", tout << "Failed to create datatype sort from parameters\n";); - return false; - } - new_types.push_back(ty); - } - return true; -} -expr * datatype_decl_plugin::get_some_value(sort * s) { - SASSERT(s->is_sort_of(m_family_id, DATATYPE_SORT)); - datatype_util & util = get_util(); - func_decl * c = util.get_non_rec_constructor(s); - ptr_buffer args; - for (unsigned i = 0; i < c->get_arity(); i++) { - args.push_back(m_manager->get_some_value(c->get_domain(i))); - } - return m_manager->mk_app(c, args.size(), args.c_ptr()); -} + void util::display_datatype(sort *s0, std::ostream& out) { + ast_mark mark; + ptr_buffer todo; + SASSERT(is_datatype(s0)); + out << s0->get_name() << " where\n"; + todo.push_back(s0); + mark.mark(s0, true); + while (!todo.empty()) { + sort* s = todo.back(); + todo.pop_back(); + out << s->get_name() << " =\n"; -bool datatype_decl_plugin::is_fully_interp(sort const * s) const { - SASSERT(s->is_sort_of(m_family_id, DATATYPE_SORT)); - parameter const * parameters = s->get_parameters(); - unsigned num_types = parameters[0].get_int(); - for (unsigned tid = 0; tid < num_types; tid++) { - unsigned o = datatype_decl_plugin::constructor_offset(s, tid); - unsigned num_constructors = parameters[o].get_int(); - for (unsigned si = 1; si <= num_constructors; si++) { - unsigned k_i = parameters[o + si].get_int(); - unsigned num_accessors = parameters[k_i + 2].get_int(); - unsigned r = 0; - for (; r < num_accessors; r++) { - parameter const & a_type = parameters[k_i + 4 + 2*r]; - if (a_type.is_int()) - continue; - SASSERT(a_type.is_ast()); - sort * arg_s = to_sort(a_type.get_ast()); - if (!m_manager->is_fully_interp(arg_s)) - return false; - } - } - } - return true; -} - -bool datatype_decl_plugin::is_value_visit(expr * arg, ptr_buffer & todo) const { - if (!is_app(arg)) - return false; - family_id fid = to_app(arg)->get_family_id(); - if (fid == m_family_id) { - if (!get_util().is_constructor(to_app(arg))) - return false; - if (to_app(arg)->get_num_args() == 0) - return true; - todo.push_back(to_app(arg)); - return true; - } - else { - return m_manager->is_value(arg); - } -} - -unsigned datatype_decl_plugin::constructor_offset(sort const* s) { - return constructor_offset(s->get_parameters()); -} - -unsigned datatype_decl_plugin::constructor_offset(parameter const& p) { - return 3 + p.get_int(); -} - -unsigned datatype_decl_plugin::constructor_offset(parameter const* ps) { - return constructor_offset(ps[2]); -} - -unsigned datatype_decl_plugin::constructor_offset(sort const* s, unsigned tid) { - unsigned c_offset = constructor_offset(s->get_parameters()); - return s->get_parameter(c_offset + 1 + 2*tid).get_int(); -} - -unsigned datatype_decl_plugin::constructor_offset(parameter const* ps, unsigned tid) { - unsigned c_offset = constructor_offset(ps[2]); - return ps[c_offset + 1 + 2*tid].get_int(); -} - -bool datatype_decl_plugin::is_value(app * e) const { - TRACE("dt_is_value", tout << "checking\n" << mk_ismt2_pp(e, *m_manager) << "\n";); - if (!get_util().is_constructor(e)) - return false; - if (e->get_num_args() == 0) - return true; - // REMARK: if the following check is too expensive, we should - // cache the values in the datatype_decl_plugin. - ptr_buffer todo; - // potentially expensive check for common sub-expressions. - for (unsigned i = 0; i < e->get_num_args(); i++) { - if (!is_value_visit(e->get_arg(i), todo)) { - TRACE("dt_is_value", tout << "not-value:\n" << mk_ismt2_pp(e->get_arg(i), *m_manager) << "\n";); - return false; - } - } - while (!todo.empty()) { - app * curr = todo.back(); - SASSERT(get_util().is_constructor(curr)); - todo.pop_back(); - for (unsigned i = 0; i < curr->get_num_args(); i++) { - if (!is_value_visit(curr->get_arg(i), todo)) { - TRACE("dt_is_value", tout << "not-value:\n" << mk_ismt2_pp(curr->get_arg(i), *m_manager) << "\n";); - return false; - } - } - } - return true; -} - -void datatype_decl_plugin::get_op_names(svector & op_names, symbol const & logic) { - if (logic == symbol::null) { - op_names.push_back(builtin_name("update-field", OP_DT_UPDATE_FIELD)); - } -} - - -datatype_util::datatype_util(ast_manager & m): - m_manager(m), - m_family_id(m.mk_family_id("datatype")), - m_asts(m), - m_start(0) { -} - -datatype_util::~datatype_util() { - std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc >()); -} - -func_decl * datatype_util::get_constructor(sort * ty, unsigned c_id) { - unsigned tid = ty->get_parameter(1).get_int(); - unsigned o = datatype_decl_plugin::constructor_offset(ty, tid); - unsigned k_i = ty->get_parameter(o + c_id + 1).get_int(); - unsigned num_accessors = ty->get_parameter(k_i + 2).get_int(); - parameter p[2] = { parameter(ty), parameter(c_id) }; - ptr_buffer domain; - for (unsigned r = 0; r < num_accessors; r++) { - domain.push_back(get_type(m_manager, m_family_id, ty, ty->get_parameter(k_i + 4 + 2*r))); - } - func_decl * d = m_manager.mk_func_decl(m_family_id, OP_DT_CONSTRUCTOR, 2, p, domain.size(), domain.c_ptr()); - SASSERT(d); - return d; -} - -ptr_vector const * datatype_util::get_datatype_constructors(sort * ty) { - SASSERT(is_datatype(ty)); - ptr_vector * r = 0; - if (m_datatype2constructors.find(ty, r)) - return r; - r = alloc(ptr_vector); - m_asts.push_back(ty); - m_vectors.push_back(r); - m_datatype2constructors.insert(ty, r); - unsigned tid = ty->get_parameter(1).get_int(); - unsigned o = datatype_decl_plugin::constructor_offset(ty, tid); - unsigned num_constructors = ty->get_parameter(o).get_int(); - for (unsigned c_id = 0; c_id < num_constructors; c_id++) { - func_decl * c = get_constructor(ty, c_id); - m_asts.push_back(c); - r->push_back(c); - } - return r; -} - -/** - \brief Return a constructor mk(T_1, ... T_n) - where each T_i is not a datatype or it is a datatype that contains - a constructor that will not contain directly or indirectly an element of the given sort. -*/ -func_decl * datatype_util::get_non_rec_constructor(sort * ty) { - SASSERT(is_datatype(ty)); - func_decl * r = 0; - if (m_datatype2nonrec_constructor.find(ty, r)) - return r; - r = 0; - ptr_vector forbidden_set; - forbidden_set.push_back(ty); - r = get_non_rec_constructor_core(ty, forbidden_set); - SASSERT(forbidden_set.back() == ty); - SASSERT(r); - m_asts.push_back(ty); - m_asts.push_back(r); - m_datatype2nonrec_constructor.insert(ty, r); - return r; -} - -/** - \brief Return a constructor mk(T_1, ..., T_n) where - each T_i is not a datatype or it is a datatype t not in forbidden_set, - and get_non_rec_constructor_core(T_i, forbidden_set union { T_i }) -*/ -func_decl * datatype_util::get_non_rec_constructor_core(sort * ty, ptr_vector & forbidden_set) { - // We must select a constructor c(T_1, ..., T_n):T such that - // 1) T_i's are not recursive - // If there is no such constructor, then we select one that - // 2) each type T_i is not recursive or contains a constructor that does not depend on T - ptr_vector const * constructors = get_datatype_constructors(ty); - // step 1) - unsigned sz = constructors->size(); - unsigned start = ++m_start; - for (unsigned j = 0; j < sz; ++j) { - func_decl * c = (*constructors)[(j + start) % sz]; - unsigned num_args = c->get_arity(); - unsigned i = 0; - for (; i < num_args; i++) { - sort * T_i = c->get_domain(i); - if (is_datatype(T_i)) - break; - } - if (i == num_args) - return c; - } - // step 2) - for (unsigned j = 0; j < sz; ++j) { - func_decl * c = (*constructors)[(j + start) % sz]; - TRACE("datatype_util_bug", tout << "non_rec_constructor c: " << c->get_name() << "\n";); - unsigned num_args = c->get_arity(); - unsigned i = 0; - for (; i < num_args; i++) { - sort * T_i = c->get_domain(i); - TRACE("datatype_util_bug", tout << "c: " << c->get_name() << " i: " << i << " T_i: " << T_i->get_name() << "\n";); - if (!is_datatype(T_i)) { - TRACE("datatype_util_bug", tout << "T_i is not a datatype\n";); - continue; - } - if (std::find(forbidden_set.begin(), forbidden_set.end(), T_i) != forbidden_set.end()) { - TRACE("datatype_util_bug", tout << "T_i is in forbidden_set\n";); - break; - } - forbidden_set.push_back(T_i); - func_decl * nested_c = get_non_rec_constructor_core(T_i, forbidden_set); - SASSERT(forbidden_set.back() == T_i); - forbidden_set.pop_back(); - TRACE("datatype_util_bug", tout << "nested_c: " << nested_c->get_name() << "\n";); - if (nested_c == 0) - break; - } - if (i == num_args) - return c; - } - return 0; -} - -func_decl * datatype_util::get_constructor_recognizer(func_decl * constructor) { - SASSERT(is_constructor(constructor)); - func_decl * d = 0; - if (m_constructor2recognizer.find(constructor, d)) - return d; - sort * datatype = constructor->get_range(); - d = m_manager.mk_func_decl(m_family_id, OP_DT_RECOGNISER, 2, constructor->get_parameters(), 1, &datatype); - SASSERT(d); - m_asts.push_back(constructor); - m_asts.push_back(d); - m_constructor2recognizer.insert(constructor, d); - return d; -} - -ptr_vector const * datatype_util::get_constructor_accessors(func_decl * constructor) { - SASSERT(is_constructor(constructor)); - ptr_vector * res = 0; - if (m_constructor2accessors.find(constructor, res)) - return res; - res = alloc(ptr_vector); - m_asts.push_back(constructor); - m_vectors.push_back(res); - m_constructor2accessors.insert(constructor, res); - unsigned c_id = constructor->get_parameter(1).get_int(); - sort * datatype = constructor->get_range(); - unsigned tid = datatype->get_parameter(1).get_int(); - unsigned o = datatype_decl_plugin::constructor_offset(datatype, tid); - unsigned k_i = datatype->get_parameter(o + c_id + 1).get_int(); - unsigned num_accessors = datatype->get_parameter(k_i+2).get_int(); - parameter p[3] = { parameter(datatype), parameter(c_id), parameter(-1) }; - for (unsigned r = 0; r < num_accessors; r++) { - p[2] = parameter(r); - func_decl * d = m_manager.mk_func_decl(m_family_id, OP_DT_ACCESSOR, 3, p, 1, &datatype); - SASSERT(d); - m_asts.push_back(d); - res->push_back(d); - } - return res; -} - -func_decl * datatype_util::get_accessor_constructor(func_decl * accessor) { - SASSERT(is_accessor(accessor)); - func_decl * r = 0; - if (m_accessor2constructor.find(accessor, r)) - return r; - sort * datatype = to_sort(accessor->get_parameter(0).get_ast()); - unsigned c_id = accessor->get_parameter(1).get_int(); - r = get_constructor(datatype, c_id); - m_accessor2constructor.insert(accessor, r); - m_asts.push_back(accessor); - m_asts.push_back(r); - return r; -} - -func_decl * datatype_util::get_recognizer_constructor(func_decl * recognizer) { - SASSERT(is_recognizer(recognizer)); - func_decl * r = 0; - if (m_recognizer2constructor.find(recognizer, r)) - return r; - sort * datatype = to_sort(recognizer->get_parameter(0).get_ast()); - unsigned c_id = recognizer->get_parameter(1).get_int(); - r = get_constructor(datatype, c_id); - m_recognizer2constructor.insert(recognizer, r); - m_asts.push_back(recognizer); - m_asts.push_back(r); - return r; -} - -bool datatype_util::is_recursive(sort * ty) { - SASSERT(is_datatype(ty)); - bool r = false; - if (m_is_recursive.find(ty, r)) - return r; - r = is_recursive_datatype(ty->get_parameters()); - m_is_recursive.insert(ty, r); - m_asts.push_back(ty); - return r; -} - - -bool datatype_util::is_enum_sort(sort* s) { - if (!is_datatype(s)) { - return false; - } - bool r = false; - if (m_is_enum.find(s, r)) - return r; - ptr_vector const& cnstrs = *get_datatype_constructors(s); - r = true; - for (unsigned i = 0; r && i < cnstrs.size(); ++i) { - r = cnstrs[i]->get_arity() == 0; - } - m_is_enum.insert(s, r); - m_asts.push_back(s); - return r; -} - - -void datatype_util::reset() { - m_datatype2constructors.reset(); - m_datatype2nonrec_constructor.reset(); - m_constructor2accessors.reset(); - m_constructor2recognizer.reset(); - m_recognizer2constructor.reset(); - m_accessor2constructor.reset(); - m_is_recursive.reset(); - m_is_enum.reset(); - std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc >()); - m_vectors.reset(); - m_asts.reset(); - ++m_start; -} - -/** - \brief Two datatype sorts s1 and s2 are siblings if they were - defined together in the same mutually recursive definition. -*/ -bool datatype_util::are_siblings(sort * s1, sort * s2) { - SASSERT(is_datatype(s1)); - SASSERT(is_datatype(s2)); - if (s1 == s2) - return true; - if (s1->get_num_parameters() != s2->get_num_parameters()) - return false; - unsigned num_params = s1->get_num_parameters(); - if (s1->get_parameter(0) != s2->get_parameter(0)) - return false; - // position 1 contains the IDX of the datatype in a mutually recursive definition. - for (unsigned i = 2; i < num_params; i++) { - if (s1->get_parameter(i) != s2->get_parameter(i)) - return false; - } - return true; -} - -void datatype_util::display_datatype(sort *s0, std::ostream& strm) { - ast_mark mark; - ptr_buffer todo; - SASSERT(is_datatype(s0)); - strm << s0->get_name() << " where\n"; - todo.push_back(s0); - mark.mark(s0, true); - while (!todo.empty()) { - sort* s = todo.back(); - todo.pop_back(); - strm << s->get_name() << " =\n"; - - ptr_vector const * cnstrs = get_datatype_constructors(s); - for (unsigned i = 0; i < cnstrs->size(); ++i) { - func_decl* cns = (*cnstrs)[i]; - func_decl* rec = get_constructor_recognizer(cns); - strm << " " << cns->get_name() << " :: " << rec->get_name() << " :: "; - ptr_vector const * accs = get_constructor_accessors(cns); - for (unsigned j = 0; j < accs->size(); ++j) { - func_decl* acc = (*accs)[j]; - sort* s1 = acc->get_range(); - strm << "(" << acc->get_name() << ": " << s1->get_name() << ") "; - if (is_datatype(s1) && are_siblings(s1, s0) && !mark.is_marked(s1)) { + ptr_vector const& cnstrs = *get_datatype_constructors(s); + for (unsigned i = 0; i < cnstrs.size(); ++i) { + func_decl* cns = cnstrs[i]; + func_decl* rec = get_constructor_recognizer(cns); + out << " " << cns->get_name() << " :: " << rec->get_name() << " :: "; + ptr_vector const & accs = *get_constructor_accessors(cns); + for (unsigned j = 0; j < accs.size(); ++j) { + func_decl* acc = accs[j]; + sort* s1 = acc->get_range(); + out << "(" << acc->get_name() << ": " << s1->get_name() << ") "; + if (is_datatype(s1) && are_siblings(s1, s0) && !mark.is_marked(s1)) { mark.mark(s1, true); todo.push_back(s1); - } + } + } + out << "\n"; } - strm << "\n"; } } - } -bool datatype_util::is_func_decl(datatype_op_kind k, unsigned num_params, parameter const* params, func_decl* f) { - bool eq = - f->get_decl_kind() == k && - f->get_family_id() == m_family_id && - f->get_num_parameters() == num_params; - for (unsigned i = 0; eq && i < num_params; ++i) { - eq = params[i] == f->get_parameter(i); +datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_params, sort*const* params, unsigned num_constructors, constructor_decl * const * cs) { + datatype::decl::plugin* p = u.get_plugin(); + datatype::def* d = p->mk(n, num_params, params); + for (unsigned i = 0; i < num_constructors; ++i) { + d->add(cs[i]); } - return eq; + return d; } - -bool datatype_util::is_constructor_of(unsigned num_params, parameter const* params, func_decl* f) { - return - num_params == 2 && - m_family_id == f->get_family_id() && - OP_DT_CONSTRUCTOR == f->get_decl_kind() && - 2 == f->get_num_parameters() && - params[0] == f->get_parameter(0) && - params[1] == f->get_parameter(1); -} - diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 3d008ad9c..515ca6e20 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -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 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 const& accessors() const { return m_accessors; } + ptr_vector::const_iterator begin() const { return m_accessors.begin(); } + ptr_vector::const_iterator end() const { return m_accessors.end(); } + ptr_vector::iterator begin() { return m_accessors.begin(); } + ptr_vector::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& szs); + static size* mk_times(ptr_vector& szs); + static size* mk_power(size* a1, size* a2); + + virtual size* subst(obj_map& S) = 0; + virtual sort_size eval(obj_map 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& S) { return this; } + virtual sort_size eval(obj_map 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& S) { return mk_plus(m_arg1->subst(S), m_arg2->subst(S)); } + virtual sort_size eval(obj_map 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& S) { return mk_times(m_arg1->subst(S), m_arg2->subst(S)); } + virtual sort_size eval(obj_map 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& S) { return mk_power(m_arg1->subst(S), m_arg2->subst(S)); } + virtual sort_size eval(obj_map 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(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& S) { return S[m_param]; } + virtual sort_size eval(obj_map 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 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 const& constructors() const { return m_constructors; } + ptr_vector::const_iterator begin() const { return m_constructors.begin(); } + ptr_vector::const_iterator end() const { return m_constructors.end(); } + ptr_vector::iterator begin() { return m_constructors.begin(); } + ptr_vector::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 m_util; + map m_defs; + svector 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 & 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 & 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 *> m_datatype2constructors; + obj_map m_datatype2nonrec_constructor; + obj_map *> m_constructor2accessors; + obj_map m_constructor2recognizer; + obj_map m_recognizer2constructor; + obj_map m_accessor2constructor; + obj_map m_is_recursive; + obj_map m_is_enum; + mutable obj_map m_is_fully_interp; + mutable ast_ref_vector m_asts; + ptr_vector > m_vectors; + unsigned m_start; + mutable ptr_vector m_fully_interp_trail; + + func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector & 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 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& 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 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 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& 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 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 & 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 & 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 *> m_datatype2constructors; - obj_map m_datatype2nonrec_constructor; - obj_map *> m_constructor2accessors; - obj_map m_constructor2recognizer; - obj_map m_recognizer2constructor; - obj_map m_accessor2constructor; - obj_map m_is_recursive; - obj_map m_is_enum; - ast_ref_vector m_asts; - ptr_vector > m_vectors; - unsigned m_start; - - func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector & 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 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 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_ */ - diff --git a/src/ast/expr_substitution.h b/src/ast/expr_substitution.h index d209ab6b4..d360356eb 100644 --- a/src/ast/expr_substitution.h +++ b/src/ast/expr_substitution.h @@ -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 diff --git a/src/ast/fpa/CMakeLists.txt b/src/ast/fpa/CMakeLists.txt index 4a9506d16..2a6d0763c 100644 --- a/src/ast/fpa/CMakeLists.txt +++ b/src/ast/fpa/CMakeLists.txt @@ -5,7 +5,7 @@ z3_add_component(fpa fpa2bv_rewriter.cpp COMPONENT_DEPENDENCIES ast - simplifier + rewriter model util PYG_FILES diff --git a/src/ast/fpa/fpa2bv_converter.h b/src/ast/fpa/fpa2bv_converter.h index 19a52dd23..1e3e5d9b3 100644 --- a/src/ast/fpa/fpa2bv_converter.h +++ b/src/ast/fpa/fpa2bv_converter.h @@ -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; diff --git a/src/ast/justified_expr.h b/src/ast/justified_expr.h new file mode 100644 index 000000000..8aa961686 --- /dev/null +++ b/src/ast/justified_expr.h @@ -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 diff --git a/src/ast/macros/CMakeLists.txt b/src/ast/macros/CMakeLists.txt index ca38b4759..ec6d7e26c 100644 --- a/src/ast/macros/CMakeLists.txt +++ b/src/ast/macros/CMakeLists.txt @@ -5,5 +5,5 @@ z3_add_component(macros macro_util.cpp quasi_macros.cpp COMPONENT_DEPENDENCIES - simplifier + rewriter ) diff --git a/src/ast/macros/macro_finder.cpp b/src/ast/macros/macro_finder.cpp index 90e64fb0a..ed067f331 100644 --- a/src/ast/macros/macro_finder.cpp +++ b/src/ast/macros/macro_finder.cpp @@ -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& 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& 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& 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& new_fmls) { + TRACE("macro_finder", tout << "processing macros...\n";); + vector _new_fmls; + if (expand_macros(n, fmls, _new_fmls)) { + while (true) { + vector 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); +} + + diff --git a/src/ast/macros/macro_finder.h b/src/ast/macros/macro_finder.h index 996d613e8..2dd72a27f 100644 --- a/src/ast/macros/macro_finder.h +++ b/src/ast/macros/macro_finder.h @@ -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& 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& 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& new_fmls); }; #endif /* MACRO_FINDER_H_ */ diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index 0f16545d4..855cae107 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -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 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 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_expander_cfg m_cfg; + + macro_expander_rw(ast_manager& m, macro_manager& mm): + rewriter_tpl(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 { diff --git a/src/ast/macros/macro_manager.h b/src/ast/macros/macro_manager.h index 111027f73..0205fb891 100644 --- a/src/ast/macros/macro_manager.h +++ b/src/ast/macros/macro_manager.h @@ -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 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 const & get_forbidden_set() const { return m_forbidden_set; } diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index 35f2fbcfb..1ab54d0b5 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -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(this)->m_arith_simp = static_cast(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(this)->m_bv_simp = static_cast(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; } diff --git a/src/ast/macros/macro_util.h b/src/ast/macros/macro_util.h index d76f2f0d3..3ab00df2a 100644 --- a/src/ast/macros/macro_util.h +++ b/src/ast/macros/macro_util.h @@ -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 * 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 * 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 diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index 6206d0311..7d5e7c3db 100644 --- a/src/ast/macros/quasi_macros.cpp +++ b/src/ast/macros/quasi_macros.cpp @@ -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& 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& 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; + } +} diff --git a/src/ast/macros/quasi_macros.h b/src/ast/macros/quasi_macros.h index 50fa04af4..1b1483a90 100644 --- a/src/ast/macros/quasi_macros.h +++ b/src/ast/macros/quasi_macros.h @@ -20,9 +20,9 @@ Revision History: #define QUASI_MACROS_H_ #include +#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 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& 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& 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 diff --git a/src/ast/pattern/CMakeLists.txt b/src/ast/pattern/CMakeLists.txt index 6e8301afc..5531bb29b 100644 --- a/src/ast/pattern/CMakeLists.txt +++ b/src/ast/pattern/CMakeLists.txt @@ -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 diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index d97c2f094..6a91dd85e 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -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 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()); 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 & result) { +void pattern_inference_cfg::filter_looping_patterns(ptr_vector & 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 & 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 const & patterns, ptr_vector & result) { - ptr_vector::const_iterator it = patterns.begin(); - ptr_vector::const_iterator end = patterns.end(); - for (; it != end; ++it) { - app * curr = *it; +void pattern_inference_cfg::filter_bigger_patterns(ptr_vector const & patterns, ptr_vector & 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 const & candidate_patterns, +void pattern_inference_cfg::candidates2unary_patterns(ptr_vector const & candidate_patterns, ptr_vector & remaining_candidate_patterns, app_ref_buffer & result) { - ptr_vector::const_iterator it = candidate_patterns.begin(); - ptr_vector::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 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 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()); m_pre_patterns.reset(); } -#ifdef _TRACE -static void dump_app_vector(std::ostream & out, ptr_vector const & v, ast_manager & m) { - ptr_vector::const_iterator it = v.begin(); - ptr_vector::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 & candidate_patterns, app_ref_buffer & result) { +bool pattern_inference_cfg::has_preferred_patterns(ptr_vector & candidate_patterns, app_ref_buffer & result) { if (m_preferred.empty()) return false; bool found = false; - ptr_vector::const_iterator it = candidate_patterns.begin(); - ptr_vector::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 & 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 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 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(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 l1(m_nested_arith_only, false); // try to find a non-nested arith pattern flet 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(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 const & v, ast_manager & m) { - ptr_vector::const_iterator it = v.begin(); - ptr_vector::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(m, m.proofs_enabled(), m_cfg), + m_cfg(m, params) +{} diff --git a/src/ast/pattern/pattern_inference.h b/src/ast/pattern/pattern_inference.h index a138d1033..905662477 100644 --- a/src/ast/pattern/pattern_inference.h +++ b/src/ast/pattern/pattern_inference.h @@ -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 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 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, default_eq > 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 const & patterns, ptr_vector & result); class contains_subpattern { - pattern_inference & m_owner; + pattern_inference_cfg & m_owner; nat_set m_already_processed; ptr_vector 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 m_cfg; +public: + pattern_inference_rw(ast_manager& m, pattern_inference_params & params); +}; + #endif /* PATTERN_INFERENCE_H_ */ diff --git a/src/ast/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index abf09ff0c..57924b48a 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -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 diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index fc9b1ac1d..631e1d8f3 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -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) { diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index de849dbd7..1bef9a964 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -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 { 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 { 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); diff --git a/src/ast/rewriter/arith_rewriter_params.pyg b/src/ast/rewriter/arith_rewriter_params.pyg index 8a41d838d..c7374105a 100644 --- a/src/ast/rewriter/arith_rewriter_params.pyg +++ b/src/ast/rewriter/arith_rewriter_params.pyg @@ -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)))."))) diff --git a/src/ast/simplifier/bit2int.cpp b/src/ast/rewriter/bit2int.cpp similarity index 87% rename from src/ast/simplifier/bit2int.cpp rename to src/ast/rewriter/bit2int.cpp index 6f7dd1cbe..257740412 100644 --- a/src/ast/simplifier/bit2int.cpp +++ b/src/ast/rewriter/bit2int.cpp @@ -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); } diff --git a/src/ast/simplifier/bit2int.h b/src/ast/rewriter/bit2int.h similarity index 90% rename from src/ast/simplifier/bit2int.h rename to src/ast/rewriter/bit2int.h index 84ae1f4a4..fe15d1ec5 100644 --- a/src/ast/simplifier/bit2int.h +++ b/src/ast/rewriter/bit2int.h @@ -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); }; diff --git a/src/ast/rewriter/bit_blaster/CMakeLists.txt b/src/ast/rewriter/bit_blaster/CMakeLists.txt index 9eea1558e..c8985a051 100644 --- a/src/ast/rewriter/bit_blaster/CMakeLists.txt +++ b/src/ast/rewriter/bit_blaster/CMakeLists.txt @@ -4,5 +4,4 @@ z3_add_component(bit_blaster bit_blaster_rewriter.cpp COMPONENT_DEPENDENCIES rewriter - simplifier ) diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp index 44fccb49e..6e99cb23e 100644 --- a/src/ast/rewriter/bool_rewriter.cpp +++ b/src/ast/rewriter/bool_rewriter.cpp @@ -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 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; diff --git a/src/ast/rewriter/bv_elim.cpp b/src/ast/rewriter/bv_elim.cpp new file mode 100644 index 000000000..270d7deb8 --- /dev/null +++ b/src/ast/rewriter/bv_elim.cpp @@ -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 + +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 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; +} diff --git a/src/ast/rewriter/bv_elim.h b/src/ast/rewriter/bv_elim.h new file mode 100644 index 000000000..6468cb8b9 --- /dev/null +++ b/src/ast/rewriter/bv_elim.h @@ -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 { +protected: + bv_elim_cfg m_cfg; +public: + bv_elim_rw(ast_manager & m): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m) + {} +}; + +#endif /* BV_ELIM_H_ */ + diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index edd601c9c..ce35300ca 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -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; diff --git a/src/ast/rewriter/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index 1109251e0..205ebbf8e 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -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(UINT_MAX); } + public: bv_rewriter_core(ast_manager & m):m_util(m) {} }; @@ -98,17 +99,20 @@ class bv_rewriter : public poly_rewriter { 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 diff --git a/src/ast/rewriter/datatype_rewriter.cpp b/src/ast/rewriter/datatype_rewriter.cpp index d38c9e476..f0a95929b 100644 --- a/src/ast/rewriter/datatype_rewriter.cpp +++ b/src/ast/rewriter/datatype_rewriter.cpp @@ -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 const * acc = m_util.get_constructor_accessors(c_decl); - SASSERT(acc && acc->size() == a->get_num_args()); - unsigned num = acc->size(); + ptr_vector 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 const * acc = m_util.get_constructor_accessors(c_decl); - SASSERT(acc && acc->size() == a->get_num_args()); - unsigned num = acc->size(); + ptr_vector const & acc = *m_util.get_constructor_accessors(c_decl); + SASSERT(acc.size() == a->get_num_args()); + unsigned num = acc.size(); ptr_buffer new_args; for (unsigned i = 0; i < num; ++i) { - if (f == (*acc)[i]) { + if (f == acc[i]) { new_args.push_back(args[1]); } else { diff --git a/src/ast/rewriter/elim_bounds.cpp b/src/ast/rewriter/elim_bounds.cpp new file mode 100644 index 000000000..d3240e511 --- /dev/null +++ b/src/ast/rewriter/elim_bounds.cpp @@ -0,0 +1,203 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + elim_bounds.cpp + +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 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 lowers; + obj_hashtable uppers; + obj_hashtable candidate_set; + ptr_buffer 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_ */ diff --git a/src/ast/simplifier/elim_bounds.h b/src/ast/rewriter/elim_bounds.h similarity index 53% rename from src/ast/simplifier/elim_bounds.h rename to src/ast/rewriter/elim_bounds.h index d4da953a8..e0bba4e60 100644 --- a/src/ast/simplifier/elim_bounds.h +++ b/src/ast/rewriter/elim_bounds.h @@ -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 { 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(m, m.proofs_enabled(), m_cfg), + m_cfg(m) + {} + + virtual ~elim_bounds_rw() {} }; -#endif /* ELIM_BOUNDS_H_ */ +#endif /* ELIM_BOUNDS2_H_ */ diff --git a/src/ast/simplifier/inj_axiom.cpp b/src/ast/rewriter/inj_axiom.cpp similarity index 90% rename from src/ast/simplifier/inj_axiom.cpp rename to src/ast/rewriter/inj_axiom.cpp index 2aa828ffa..d322f3228 100644 --- a/src/ast/simplifier/inj_axiom.cpp +++ b/src/ast/rewriter/inj_axiom.cpp @@ -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() && diff --git a/src/ast/simplifier/inj_axiom.h b/src/ast/rewriter/inj_axiom.h similarity index 100% rename from src/ast/simplifier/inj_axiom.h rename to src/ast/rewriter/inj_axiom.h diff --git a/src/ast/simplifier/maximise_ac_sharing.cpp b/src/ast/rewriter/maximize_ac_sharing.cpp similarity index 55% rename from src/ast/simplifier/maximise_ac_sharing.cpp rename to src/ast/rewriter/maximize_ac_sharing.cpp index 93e5a43f0..b560132db 100644 --- a/src/ast/simplifier/maximise_ac_sharing.cpp +++ b/src/ast/rewriter/maximize_ac_sharing.cpp @@ -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 _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) { } diff --git a/src/ast/simplifier/maximise_ac_sharing.h b/src/ast/rewriter/maximize_ac_sharing.h similarity index 64% rename from src/ast/simplifier/maximise_ac_sharing.h rename to src/ast/rewriter/maximize_ac_sharing.h index cf488e20d..c0ee0d09f 100644 --- a/src/ast/simplifier/maximise_ac_sharing.h +++ b/src/ast/rewriter/maximize_ac_sharing.h @@ -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, deref_eq > cache; protected: - class ac_plugin : public simplifier_plugin { - maximise_ac_sharing & m_owner; - svector 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 m_entries; unsigned_vector m_scopes; + svector 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 m_cfg; +public: + maximize_bv_sharing_rw(ast_manager& m): + rewriter_tpl(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_ */ diff --git a/src/ast/rewriter/poly_rewriter.h b/src/ast/rewriter/poly_rewriter.h index 5d38e4b10..23743399e 100644 --- a/src/ast/rewriter/poly_rewriter.h +++ b/src/ast/rewriter/poly_rewriter.h @@ -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); diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index 5e2e39722..39c4a1078 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -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::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 @@ -64,6 +67,13 @@ expr * poly_rewriter::get_power_body(expr * t, rational & k) { return t; } +template +bool poly_rewriter::is_zero(expr* e) const { + rational v; + return is_numeral(e, v) && v.is_zero(); +} + + template expr * poly_rewriter::mk_mul_app(unsigned num_args, expr * const * args) { switch (num_args) { @@ -118,6 +128,9 @@ expr * poly_rewriter::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::mk_flat_mul_core(unsigned num_args, expr * cons } -template -struct poly_rewriter::mon_pw_lt { - poly_rewriter & m_owner; - mon_pw_lt(poly_rewriter & 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 br_status poly_rewriter::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::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::hoist_cmul(expr_ref_buffer & args) { args.resize(j); } +template +bool poly_rewriter::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 +int poly_rewriter::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 br_status poly_rewriter::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::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::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::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::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::mk_sub(unsigned num_args, expr * const * args, ptr_buffer 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::mk_sub(unsigned num_args, expr * const * args, template br_status poly_rewriter::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::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::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::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::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::merge_muls(expr* x, expr* y) { m1[k] = mk_add_app(2, args); return mk_mul_app(k+1, m1.c_ptr()); } + +template +bool poly_rewriter::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 +bool poly_rewriter::is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) { + if (!is_add(n) || is_ground(n)) + return false; + + ptr_buffer 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; +} diff --git a/src/ast/simplifier/pull_ite_tree.cpp b/src/ast/rewriter/pull_ite_tree.cpp similarity index 89% rename from src/ast/simplifier/pull_ite_tree.cpp rename to src/ast/rewriter/pull_ite_tree.cpp index 072bbd12c..651744bf9 100644 --- a/src/ast/simplifier/pull_ite_tree.cpp +++ b/src/ast/rewriter/pull_ite_tree.cpp @@ -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 && diff --git a/src/ast/simplifier/pull_ite_tree.h b/src/ast/rewriter/pull_ite_tree.h similarity index 73% rename from src/ast/simplifier/pull_ite_tree.h rename to src/ast/rewriter/pull_ite_tree.h index bc4a0bb68..3ff0a716d 100644 --- a/src/ast/simplifier/pull_ite_tree.h +++ b/src/ast/rewriter/pull_ite_tree.h @@ -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 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 m_cfg; +public: + pull_cheap_ite_tree_rw(ast_manager& m): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m) + {} +}; + #endif /* PULL_ITE_TREE_H_ */ diff --git a/src/ast/rewriter/push_app_ite.cpp b/src/ast/rewriter/push_app_ite.cpp new file mode 100644 index 000000000..f3df4d711 --- /dev/null +++ b/src/ast/rewriter/push_app_ite.cpp @@ -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(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; +} diff --git a/src/ast/rewriter/push_app_ite.h b/src/ast/rewriter/push_app_ite.h new file mode 100644 index 000000000..ae06aad30 --- /dev/null +++ b/src/ast/rewriter/push_app_ite.h @@ -0,0 +1,74 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + push_app_ite.h + +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 m_cfg; +public: + push_app_ite_rw(ast_manager& m, bool conservative = true): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m, conservative) + {} +}; + +struct ng_push_app_ite_rw : public rewriter_tpl { + ng_push_app_ite_cfg m_cfg; +public: + ng_push_app_ite_rw(ast_manager& m, bool conservative = true): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m, conservative) + {} +}; + + +#endif /* PUSH_APP_ITE_H_ */ + diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 163118d17..42f268379 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -18,6 +18,7 @@ Notes: --*/ #include "ast/rewriter/rewriter.h" #include "ast/ast_smt2_pp.h" +#include "ast/ast_ll_pp.h" template template @@ -259,10 +260,10 @@ void rewriter_tpl::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::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::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); diff --git a/src/ast/rewriter/rewriter_params.pyg b/src/ast/rewriter/rewriter_params.pyg index 06500086a..18bb29e56 100644 --- a/src/ast/rewriter/rewriter_params.pyg +++ b/src/ast/rewriter/rewriter_params.pyg @@ -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."))) diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 96a98e472..13cb52df1 100644 --- a/src/ast/rewriter/seq_rewriter.cpp +++ b/src/ast/rewriter/seq_rewriter.cpp @@ -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; } diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 764fa8eef..dd431bf85 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -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) { diff --git a/src/ast/simplifier/CMakeLists.txt b/src/ast/simplifier/CMakeLists.txt deleted file mode 100644 index 9575c5c89..000000000 --- a/src/ast/simplifier/CMakeLists.txt +++ /dev/null @@ -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 -) diff --git a/src/ast/simplifier/README b/src/ast/simplifier/README deleted file mode 100644 index 4725d9de9..000000000 --- a/src/ast/simplifier/README +++ /dev/null @@ -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. diff --git a/src/ast/simplifier/arith_simplifier_params.cpp b/src/ast/simplifier/arith_simplifier_params.cpp deleted file mode 100644 index 73bbbaa1a..000000000 --- a/src/ast/simplifier/arith_simplifier_params.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - arith_simplifier_params.cpp - -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); -} \ No newline at end of file diff --git a/src/ast/simplifier/arith_simplifier_params.h b/src/ast/simplifier/arith_simplifier_params.h deleted file mode 100644 index 8a4150099..000000000 --- a/src/ast/simplifier/arith_simplifier_params.h +++ /dev/null @@ -1,38 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - arith_simplifier_params.h - -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_ */ - diff --git a/src/ast/simplifier/arith_simplifier_params_helper.pyg b/src/ast/simplifier/arith_simplifier_params_helper.pyg deleted file mode 100644 index 49a7cf3d2..000000000 --- a/src/ast/simplifier/arith_simplifier_params_helper.pyg +++ /dev/null @@ -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'))) diff --git a/src/ast/simplifier/arith_simplifier_plugin.cpp b/src/ast/simplifier/arith_simplifier_plugin.cpp deleted file mode 100644 index d604ba2ff..000000000 --- a/src/ast/simplifier/arith_simplifier_plugin.cpp +++ /dev/null @@ -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 -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(arg1, arg2, result); -} - -void arith_simplifier_plugin::mk_le(expr * arg1, expr * arg2, expr_ref & result) { - mk_le_ge_eq_core(arg1, arg2, result); -} - -void arith_simplifier_plugin::mk_ge(expr * arg1, expr * arg2, expr_ref & result) { - mk_le_ge_eq_core(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(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(lhs, rhs, le); - mk_le_ge_eq_core(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; -} - - - diff --git a/src/ast/simplifier/arith_simplifier_plugin.h b/src/ast/simplifier/arith_simplifier_plugin.h deleted file mode 100644 index 4f3a6add0..000000000 --- a/src/ast/simplifier/arith_simplifier_plugin.h +++ /dev/null @@ -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 - 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_ */ diff --git a/src/ast/simplifier/array_simplifier_params.cpp b/src/ast/simplifier/array_simplifier_params.cpp deleted file mode 100644 index ff7dba25f..000000000 --- a/src/ast/simplifier/array_simplifier_params.cpp +++ /dev/null @@ -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(); -} diff --git a/src/ast/simplifier/array_simplifier_params.h b/src/ast/simplifier/array_simplifier_params.h deleted file mode 100644 index 559e3de54..000000000 --- a/src/ast/simplifier/array_simplifier_params.h +++ /dev/null @@ -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_ */ - diff --git a/src/ast/simplifier/array_simplifier_params_helper.pyg b/src/ast/simplifier/array_simplifier_params_helper.pyg deleted file mode 100644 index 93c184c23..000000000 --- a/src/ast/simplifier/array_simplifier_params_helper.pyg +++ /dev/null @@ -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'))) diff --git a/src/ast/simplifier/array_simplifier_plugin.cpp b/src/ast/simplifier/array_simplifier_plugin.cpp deleted file mode 100644 index 754daab69..000000000 --- a/src/ast/simplifier/array_simplifier_plugin.cpp +++ /dev/null @@ -1,877 +0,0 @@ -/*++ -Copyright (c) 2008 Microsoft Corporation - -Module Name: - - array_simplifier_plugin.cpp - -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 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 arrays; - ptr_vector 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 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, ¶m, 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 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, ¶m, 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& 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 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 * entry = alloc(ptr_vector); - entry->append(num_args, const_cast(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 * 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, ¶m, 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, ¶m, 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 todo; - obj_map 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 & 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, ¶m, 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, ¶m, 1, &a ); -} - - diff --git a/src/ast/simplifier/array_simplifier_plugin.h b/src/ast/simplifier/array_simplifier_plugin.h deleted file mode 100644 index 62eb5e5ff..000000000 --- a/src/ast/simplifier/array_simplifier_plugin.h +++ /dev/null @@ -1,154 +0,0 @@ -/*++ -Copyright (c) 2008 Microsoft Corporation - -Module Name: - - array_simplifier_plugin.h - -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 entry; - - struct entry_hash_proc { - unsigned operator()(ptr_vector * entry) const { - return get_exprs_hash(entry->size(), entry->begin(), 0xbeef1010); - } - }; - - struct entry_eq_proc { - bool operator()(ptr_vector * entry1, ptr_vector * entry2) const { - if (entry1->size() != entry2->size()) return false; - return compare_arrays(entry1->begin(), entry2->begin(), entry1->size()); - } - }; - - typedef map 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 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 m_tmp; - ptr_vector m_tmp2; - ptr_vector m_todo; - static const unsigned m_select_cache_max_size = 100000; - typedef obj_map 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 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& keys, ptr_vector& 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& 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_ */ - diff --git a/src/ast/simplifier/base_simplifier.h b/src/ast/simplifier/base_simplifier.h deleted file mode 100644 index 87c372636..000000000 --- a/src/ast/simplifier/base_simplifier.h +++ /dev/null @@ -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 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_ */ diff --git a/src/ast/simplifier/basic_simplifier_plugin.cpp b/src/ast/simplifier/basic_simplifier_plugin.cpp deleted file mode 100644 index be51bc291..000000000 --- a/src/ast/simplifier/basic_simplifier_plugin.cpp +++ /dev/null @@ -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(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); -} diff --git a/src/ast/simplifier/basic_simplifier_plugin.h b/src/ast/simplifier/basic_simplifier_plugin.h deleted file mode 100644 index f28a19b56..000000000 --- a/src/ast/simplifier/basic_simplifier_plugin.h +++ /dev/null @@ -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_ */ diff --git a/src/ast/simplifier/bv_elim.cpp b/src/ast/simplifier/bv_elim.cpp deleted file mode 100644 index 1875e333b..000000000 --- a/src/ast/simplifier/bv_elim.cpp +++ /dev/null @@ -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 - -void bv_elim::elim(quantifier* q, quantifier_ref& r) { - - svector 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); -} diff --git a/src/ast/simplifier/bv_elim.h b/src/ast/simplifier/bv_elim.h deleted file mode 100644 index 2b8a4778a..000000000 --- a/src/ast/simplifier/bv_elim.h +++ /dev/null @@ -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_ */ - diff --git a/src/ast/simplifier/bv_simplifier_params.cpp b/src/ast/simplifier/bv_simplifier_params.cpp deleted file mode 100644 index 4c6b4a5fa..000000000 --- a/src/ast/simplifier/bv_simplifier_params.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - bv_simplifier_params.cpp - -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); -} \ No newline at end of file diff --git a/src/ast/simplifier/bv_simplifier_params.h b/src/ast/simplifier/bv_simplifier_params.h deleted file mode 100644 index 8c0792203..000000000 --- a/src/ast/simplifier/bv_simplifier_params.h +++ /dev/null @@ -1,38 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - bv_simplifier_params.h - -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_ */ - diff --git a/src/ast/simplifier/bv_simplifier_params_helper.pyg b/src/ast/simplifier/bv_simplifier_params_helper.pyg deleted file mode 100644 index 6bcf83207..000000000 --- a/src/ast/simplifier/bv_simplifier_params_helper.pyg +++ /dev/null @@ -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'),)) diff --git a/src/ast/simplifier/bv_simplifier_plugin.cpp b/src/ast/simplifier/bv_simplifier_plugin.cpp deleted file mode 100644 index c23d2e748..000000000 --- a/src/ast/simplifier/bv_simplifier_plugin.cpp +++ /dev/null @@ -1,2261 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - bv_simplifier_plugin.cpp - -Abstract: - - Simplifier for the bv family. - -Author: - - Leonardo (leonardo) 2008-01-08 - Nikolaj Bjorner (nbjorner) 2008-01-05 - ---*/ -#include "ast/simplifier/bv_simplifier_plugin.h" -#include "ast/ast_ll_pp.h" -#include "ast/ast_pp.h" -#include "ast/arith_decl_plugin.h" -#include "util/obj_hashtable.h" -#include "ast/ast_util.h" - -bv_simplifier_plugin::~bv_simplifier_plugin() { - flush_caches(); -} - -bv_simplifier_plugin::bv_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, bv_simplifier_params & p): - poly_simplifier_plugin(symbol("bv"), m, OP_BADD, OP_BMUL, OP_BNEG, OP_BSUB, OP_BV_NUM), - m_manager(m), - m_util(m), - m_arith(m), - m_bsimp(b), - m_params(p), - m_zeros(m) { -} - -rational bv_simplifier_plugin::norm(const numeral & n) { - unsigned bv_size = get_bv_size(m_curr_sort); - return norm(n, bv_size, false); -} - - -bool bv_simplifier_plugin::is_numeral(expr * n, rational & val) const { - unsigned bv_size; - return m_util.is_numeral(n, val, bv_size); -} - -expr * bv_simplifier_plugin::get_zero(sort * s) const { - bv_simplifier_plugin * _this = const_cast(this); - unsigned bv_size = _this->get_bv_size(s); - if (bv_size >= m_zeros.size()) - _this->m_zeros.resize(bv_size+1); - if (m_zeros.get(bv_size) == 0) - _this->m_zeros.set(bv_size, _this->m_util.mk_numeral(rational(0), s)); - return m_zeros.get(bv_size); -} - -bool bv_simplifier_plugin::are_numerals(unsigned num_args, expr * const* args, unsigned& bv_size) { - numeral r; - if (num_args == 0) { - return false; - } - for (unsigned i = 0; i < num_args; ++i) { - if (!m_util.is_numeral(args[i], r, bv_size)) { - return false; - } - } - return true; -} - -app * bv_simplifier_plugin::mk_numeral(numeral const & n) { - unsigned bv_size = get_bv_size(m_curr_sort); - return mk_numeral(n, bv_size); -} - -app * bv_simplifier_plugin::mk_numeral(numeral const& n, unsigned bv_size) { - numeral r = mod(n, rational::power_of_two(bv_size)); - SASSERT(!r.is_neg()); - SASSERT(r < rational::power_of_two(bv_size)); - return m_util.mk_numeral(r, bv_size); -} - -bool bv_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); - - bv_op_kind k = static_cast(f->get_decl_kind()); - switch (k) { - case OP_BV_NUM: SASSERT(num_args == 0); result = mk_numeral(f->get_parameter(0).get_rational(), f->get_parameter(1).get_int()); break; - case OP_BIT0: SASSERT(num_args == 0); result = mk_numeral(0, 1); break; - case OP_BIT1: SASSERT(num_args == 0); result = mk_numeral(1, 1); break; - case OP_BADD: SASSERT(num_args > 0); - mk_add(num_args, args, result); - TRACE("bv_add_bug", - for (unsigned i = 0; i < num_args; i++) tout << mk_bounded_pp(args[i], m_manager, 10) << "\n"; - tout << mk_bounded_pp(result, m_manager, 10) << "\n";); - mk_add_concat(result); - break; - case OP_BSUB: SASSERT(num_args > 0); mk_sub(num_args, args, result); break; - case OP_BNEG: SASSERT(num_args == 1); mk_uminus(args[0], result); break; - case OP_BMUL: SASSERT(num_args > 0); mk_mul(num_args, args, result); break; - case OP_ULEQ: if (m_presimp) return false; SASSERT(num_args == 2); mk_ule(args[0], args[1], result); break; - case OP_UGEQ: if (m_presimp) return false; SASSERT(num_args == 2); mk_ule(args[1], args[0], result); break; - case OP_ULT: if (m_presimp) return false; SASSERT(num_args == 2); mk_ult(args[0], args[1], result); break; - case OP_UGT: if (m_presimp) return false; SASSERT(num_args == 2); mk_ult(args[1], args[0], result); break; - case OP_SLEQ: if (m_presimp) return false; SASSERT(num_args == 2); mk_sle(args[0], args[1], result); break; - case OP_SGEQ: if (m_presimp) return false; SASSERT(num_args == 2); mk_sle(args[1], args[0], result); break; - case OP_SLT: if (m_presimp) return false; SASSERT(num_args == 2); mk_slt(args[0], args[1], result); break; - case OP_SGT: if (m_presimp) return false; SASSERT(num_args == 2); mk_slt(args[1], args[0], result); break; - case OP_BAND: SASSERT(num_args > 0); mk_bv_and(num_args, args, result); break; - case OP_BOR: SASSERT(num_args > 0); mk_bv_or(num_args, args, result); break; - case OP_BNOT: SASSERT(num_args == 1); mk_bv_not(args[0], result); break; - case OP_BXOR: SASSERT(num_args > 0); mk_bv_xor(num_args, args, result); break; - case OP_CONCAT: SASSERT(num_args > 0); mk_concat(num_args, args, result); break; - case OP_ZERO_EXT: - SASSERT(num_args == 1); SASSERT(f->get_num_parameters() == 1); - mk_zeroext(f->get_parameter(0).get_int(), args[0], result); - break; - case OP_EXTRACT: - SASSERT(num_args == 1); SASSERT(f->get_num_parameters() == 2); - mk_extract(f->get_parameter(0).get_int(), f->get_parameter(1).get_int(), args[0], result); - break; - case OP_REPEAT: - SASSERT(num_args == 1); SASSERT(f->get_num_parameters() == 1); - mk_repeat(f->get_parameter(0).get_int(), args[0], result); - break; - case OP_BUREM: - SASSERT(num_args == 2); - mk_bv_urem(args[0], args[1], result); - break; - case OP_SIGN_EXT: - SASSERT(num_args == 1); SASSERT(f->get_num_parameters() == 1); - mk_sign_extend(f->get_parameter(0).get_int(), args[0], result); - break; - case OP_BSHL: SASSERT(num_args == 2); mk_bv_shl(args[0], args[1], result); break; - case OP_BLSHR: SASSERT(num_args == 2); mk_bv_lshr(args[0], args[1], result); break; - case OP_INT2BV: SASSERT(num_args == 1); mk_int2bv(args[0], f->get_range(), result); break; - case OP_BV2INT: SASSERT(num_args == 1); mk_bv2int(args[0], f->get_range(), result); break; - case OP_BSDIV: SASSERT(num_args == 2); mk_bv_sdiv(args[0], args[1], result); break; - case OP_BUDIV: SASSERT(num_args == 2); mk_bv_udiv(args[0], args[1], result); break; - case OP_BSREM: SASSERT(num_args == 2); mk_bv_srem(args[0], args[1], result); break; - case OP_BSMOD: SASSERT(num_args == 2); mk_bv_smod(args[0], args[1], result); break; - case OP_BNAND: SASSERT(num_args > 0); mk_bv_nand(num_args, args, result); break; - case OP_BNOR: SASSERT(num_args > 0); mk_bv_nor(num_args, args, result); break; - case OP_BXNOR: SASSERT(num_args > 0); mk_bv_xnor(num_args, args, result); break; - case OP_ROTATE_LEFT: SASSERT(num_args == 1); mk_bv_rotate_left(f, args[0], result); break; - case OP_ROTATE_RIGHT: SASSERT(num_args == 1); mk_bv_rotate_right(f, args[0], result); break; - case OP_EXT_ROTATE_LEFT: SASSERT(num_args == 2); mk_bv_ext_rotate_left(args[0], args[1], result); break; - case OP_EXT_ROTATE_RIGHT: SASSERT(num_args == 2); mk_bv_ext_rotate_right(args[0], args[1], result); break; - case OP_BREDOR: SASSERT(num_args == 1); mk_bv_redor(args[0], result); break; - case OP_BREDAND: SASSERT(num_args == 1); mk_bv_redand(args[0], result); break; - case OP_BCOMP: SASSERT(num_args == 2); mk_bv_comp(args[0], args[1], result); break; - case OP_BASHR: SASSERT(num_args == 2); mk_bv_ashr(args[0], args[1], result); break; - case OP_BSDIV_I: SASSERT(num_args == 2); mk_bv_sdiv_i(args[0], args[1], result); break; - case OP_BUDIV_I: SASSERT(num_args == 2); mk_bv_udiv_i(args[0], args[1], result); break; - case OP_BSREM_I: SASSERT(num_args == 2); mk_bv_srem_i(args[0], args[1], result); break; - case OP_BUREM_I: SASSERT(num_args == 2); mk_bv_urem_i(args[0], args[1], result); break; - case OP_BSMOD_I: SASSERT(num_args == 2); mk_bv_smod_i(args[0], args[1], result); break; - case OP_BSDIV0: - case OP_BUDIV0: - case OP_BSREM0: - case OP_BUREM0: - case OP_BSMOD0: - case OP_BIT2BOOL: - case OP_CARRY: - case OP_XOR3: - case OP_MKBV: - case OP_BUMUL_NO_OVFL: - case OP_BSMUL_NO_OVFL: - case OP_BSMUL_NO_UDFL: - result = m_manager.mk_app(f, num_args, args); - break; - default: - UNREACHABLE(); - break; - } - SASSERT(result.get()); - - TRACE("bv_simplifier", - tout << mk_pp(f, m_manager) << "\n"; - for (unsigned i = 0; i < num_args; ++i) { - tout << mk_pp(args[i], m_manager) << " "; - } - tout << "\n"; - tout << mk_pp(result.get(), m_manager) << "\n"; - ); - - return true; -} - -bool bv_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { - set_reduce_invoked(); - - if (m_presimp) - return false; - expr_ref tmp(m_manager); - tmp = m_manager.mk_eq(lhs,rhs); - mk_bv_eq(lhs, rhs, result); - return result.get() != tmp.get(); -} - -bool bv_simplifier_plugin::reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - - return false; -} - -void bv_simplifier_plugin::flush_caches() { - TRACE("extract_cache", tout << "flushing extract cache...\n";); - extract_cache::iterator it = m_extract_cache.begin(); - extract_cache::iterator end = m_extract_cache.end(); - for (; it != end; ++it) { - extract_entry & e = (*it).m_key; - m_manager.dec_ref(e.m_arg); - m_manager.dec_ref((*it).m_value); - } - m_extract_cache.reset(); -} - - -inline uint64 bv_simplifier_plugin::to_uint64(const numeral & n, unsigned bv_size) { - SASSERT(bv_size <= 64); - numeral tmp = n; - if (tmp.is_neg()) { - tmp = mod(tmp, rational::power_of_two(bv_size)); - } - SASSERT(tmp.is_nonneg()); - SASSERT(tmp.is_uint64()); - return tmp.get_uint64(); -} - -#define MK_BV_OP(_oper_,_binop_) \ -rational bv_simplifier_plugin::mk_bv_ ## _oper_(numeral const& a0, numeral const& b0, unsigned sz) { \ - rational r(0), a(a0), b(b0); \ - numeral p64 = rational::power_of_two(64); \ - numeral mul(1); \ - while (sz > 0) { \ - numeral a1 = a % p64; \ - numeral b1 = b % p64; \ - uint64 u = a1.get_uint64() _binop_ b1.get_uint64(); \ - if (sz < 64) { \ - uint64 mask = shift_left(1ull,(uint64)sz) - 1ull; \ - u = mask & u; \ - } \ - r += mul*rational(u,rational::ui64()); \ - mul *= p64; \ - a = div(a, p64); \ - b = div(b, p64); \ - sz -= (sz<64)?sz:64; \ - } \ - return r; \ -} - -MK_BV_OP(and,&) -MK_BV_OP(or,|) -MK_BV_OP(xor,^) - -rational bv_simplifier_plugin::mk_bv_not(numeral const& a0, unsigned sz) { - rational r(0), a(a0), mul(1); - numeral p64 = rational::power_of_two(64); - while (sz > 0) { - numeral a1 = a % p64; - uint64 u = ~a1.get_uint64(); - if (sz < 64) { - uint64 mask = shift_left(1ull,(uint64)sz) - 1ull; - u = mask & u; - } - r += mul*rational(u,rational::ui64()); - mul *= p64; - a = div(a, p64); - sz -= (64get_num_args() == 2) { - // - // c <=_u (concat 0 a) <=> c[u:l] = 0 && c[l-1:0] <=_u a - // - app* app = to_app(arg2); - expr * arg2_1 = app->get_arg(0); - expr * arg2_2 = app->get_arg(1); - if (m_util.is_zero(arg2_1)) { - unsigned sz1 = get_bv_size(arg2_1); - unsigned sz2 = get_bv_size(arg2_2); - - expr_ref tmp1(m_manager); - expr_ref tmp2(m_manager); - mk_extract(sz2 + sz1 - 1, sz2, arg1, tmp1); - mk_extract(sz2 - 1, 0, arg1, tmp2); - - expr_ref eq(m_manager); - expr_ref zero(m_manager); - zero = mk_bv0(sz1); - mk_bv_eq(tmp1.get(), zero, eq); - - expr_ref ineq(m_manager); - ineq = m_util.mk_ule(tmp2.get(), arg2_2); - - m_bsimp.mk_and(eq.get(), ineq.get(), result); - return; - } - } - - // - // TODO: - // Others: - // - // k <=_s (concat 0 a) <=> (k[u:l] = 0 && k[l-1:0] <=_u a) || k[u:u] = bv1 - // - // (concat 0 a) <=_s k <=> k[u:u] = bv0 && (k[u:l] != 0 || a <=_u k[l-1:0]) - // - // (concat 0 a) <=_u k <=> k[u:l] != 0 || a <=_u k[l-1:0] - // - - result = m_manager.mk_app(m_fid, k, arg1, arg2); -} - -void bv_simplifier_plugin::mk_extract(unsigned high, unsigned low, expr* arg, expr_ref& result) { - - unsigned arg_sz = get_bv_size(arg); - unsigned sz = high - low + 1; - TRACE("bv_simplifier_plugin", tout << "mk_extract [" << high << ":" << low << "]\n"; - tout << "arg_sz: " << arg_sz << " sz: " << sz << "\n"; - tout << "arg:\n"; - ast_ll_pp(tout, m_manager, arg);); - - if (arg_sz == sz) { - result = arg; - } - else { - mk_extract_core(high, low, arg, result); - } - if (m_extract_cache.size() > (1 << 12)) { - flush_caches(); - } - - TRACE("bv_simplifier_plugin", tout << "mk_extract [" << high << ":" << low << "]\n"; - tout << "arg_sz: " << arg_sz << " sz: " << sz << "\n"; - tout << "arg:\n"; - ast_ll_pp(tout, m_manager, arg); - tout << "=====================>\n"; - ast_ll_pp(tout, m_manager, result.get());); -} - - -void bv_simplifier_plugin::cache_extract(unsigned h, unsigned l, expr * arg, expr * result) { - m_manager.inc_ref(arg); - m_manager.inc_ref(result); - m_extract_cache.insert(extract_entry(h, l, arg), result); -} - -expr* bv_simplifier_plugin::get_cached_extract(unsigned h, unsigned l, expr * arg) { - expr * result = 0; - if (m_extract_cache.find(extract_entry(h, l, arg), result)) { - return result; - } - return 0; -} - - -void bv_simplifier_plugin::mk_extract_core(unsigned high, unsigned low, expr * arg, expr_ref& result) { - - if (!lookup_mk_extract(high, low, arg, result)) { - while (!m_extract_args.empty()) { - unsigned low2 = m_lows.back(); - unsigned high2 = m_highs.back(); - expr* arg2 = m_extract_args.back(); - if (try_mk_extract(high2, low2, arg2, result)) { - if (!m_extract_cache.contains(extract_entry(high2, low2, arg2))) { - cache_extract(high2, low2, arg2, result.get()); - } - m_lows.pop_back(); - m_highs.pop_back(); - m_extract_args.pop_back(); - } - } - if (!lookup_mk_extract(high, low, arg, result)) { - UNREACHABLE(); - } - } -} - - -bool bv_simplifier_plugin::lookup_mk_extract(unsigned high, unsigned low, expr * arg, expr_ref& result) { - expr* cached_result = get_cached_extract(high, low, arg); - if (cached_result) { - result = cached_result; - return true; - } - - m_extract_args.push_back(arg); - m_lows.push_back(low); - m_highs.push_back(high); - return false; -} - - -bool bv_simplifier_plugin::try_mk_extract(unsigned high, unsigned low, expr * arg, expr_ref& result) { - - SASSERT(low <= high); - unsigned arg_sz = get_bv_size(arg); - unsigned sz = high - low + 1; - numeral r; - unsigned num_bits; - - if (arg_sz == sz) { - result = arg; - return true; - } - - expr* cached_result = get_cached_extract(high, low, arg); - if (cached_result) { - result = cached_result; - return true; - } - - if (!is_app(arg)) { - result = m_util.mk_extract(high, low, arg); - return true; - } - app* a = to_app(arg); - - if (m_util.is_numeral(a, r, num_bits)) { - if (r.is_neg()) { - r = mod(r, rational::power_of_two(sz)); - } - SASSERT(r.is_nonneg()); - if (r.is_uint64()) { - uint64 u = r.get_uint64(); - uint64 e = shift_right(u, low) & (shift_left(1ull, sz) - 1ull); - TRACE("mk_extract_bug", tout << u << "[" << high << ":" << low << "] " << e << " (u >> low): " << shift_right(u, low) << " (1ull << sz): " - << shift_left(1ull, sz) << " ((1ull << sz) - 1ull)" << (shift_left(1ull, sz) - 1ull) << "\n";); - result = mk_numeral(numeral(e, numeral::ui64()), sz); - return true; - } - result = mk_numeral(div(r, rational::power_of_two(low)), sz); - return true; - } - // (extract[high:low] (extract[high2:low2] x)) == (extract[high+low2 : low+low2] x) - else if (is_app_of(a, m_fid, OP_EXTRACT)) { - expr * x = a->get_arg(0); - unsigned low2 = a->get_decl()->get_parameter(1).get_int(); - return lookup_mk_extract(high + low2, low + low2, x, result); - } - // - // (extract[hi:lo] (bvXshr A c:bv[n])) -> (extract[hi+c:lo+c] A) - // if c < n, c <= lo <= hi < n - c - // - else if ((is_app_of(a, m_fid, OP_BASHR) || is_app_of(a, m_fid, OP_BLSHR)) && - is_numeral(a->get_arg(1), r) && r.is_unsigned()) { - unsigned c = r.get_unsigned(); - unsigned bv_size = get_bv_size(a); - if (c < bv_size && c <= low && high < bv_size - c) { - return lookup_mk_extract(high+c, low+c, a->get_arg(0), result); - } - } - // (concat a_0 ... a_{n-1}) - // Remark: the least significant bits are stored in a_{n-1} - else if (is_app_of(a, m_fid, OP_CONCAT)) { - expr_ref_buffer new_args(m_manager); - unsigned i = a->get_num_args(); - // look for first argument - while (i > 0) { - --i; - expr * a_i = a->get_arg(i); - unsigned a_sz = get_bv_size(a_i); - TRACE("extract_bug", tout << "FIRST a_sz: " << a_sz << " high: " << high << " low: " << low << "\n" << - mk_pp(a_i, m_manager) << "\n";); - if (a_sz <= low) { - low -= a_sz; - high -= a_sz; - } - else { - // found first argument - if (a_sz <= high) { - expr_ref new_arg(m_manager); - if (!lookup_mk_extract(a_sz - 1, low, a_i, new_arg)) { - return false; - } - new_args.push_back(new_arg.get()); - unsigned num_consumed_bytes = a_sz - low; - // I have to apply extract[sz - num_consumed_bytes - 1, 0] on the rest of concat - high = (sz - num_consumed_bytes - 1); - break; - } - else { - return lookup_mk_extract(high, low, a_i, result); - } - } - } - TRACE("extract_bug", tout << " high: " << high << " low: " << low << "\n";); - - // look for remaining arguments - while (i > 0) { - --i; - expr * a_i = a->get_arg(i); - unsigned a_sz = get_bv_size(a_i); - TRACE("extract_bug", tout << "SECOND a_sz: " << a_sz << " high: " << high << " " << - mk_pp( a_i, m_manager) << "\n";); - if (a_sz <= high) { - high -= a_sz; - new_args.push_back(a_i); - } - else { - // found last argument - expr_ref new_arg(m_manager); - if (!lookup_mk_extract(high, 0, a_i, new_arg)) { - return false; - } - new_args.push_back(new_arg.get()); - // The arguments in new_args are in reverse order. - ptr_buffer rev_new_args; - unsigned i = new_args.size(); - while (i > 0) { - --i; - rev_new_args.push_back(new_args[i]); - } - mk_concat(rev_new_args.size(), rev_new_args.c_ptr(), result); - return true; - } - } - UNREACHABLE(); - } - else if (is_app_of(a, m_fid, OP_SIGN_EXT)) { - SASSERT(a->get_num_args() == 1); - unsigned bv_size = get_bv_size(a->get_arg(0)); - if (high < bv_size) { - return lookup_mk_extract(high, low, a->get_arg(0), result); - } - } - else if (is_app_of(a, m_fid, OP_BAND) || - is_app_of(a, m_fid, OP_BOR) || - is_app_of(a, m_fid, OP_BXOR) || - is_app_of(a, m_fid, OP_BNOR) || - is_app_of(a, m_fid, OP_BNAND) || - is_app_of(a, m_fid, OP_BNOT) || - (low == 0 && is_app_of(a, m_fid, OP_BADD)) || - (low == 0 && is_app_of(a, m_fid, OP_BMUL)) || - (low == 0 && is_app_of(a, m_fid, OP_BSUB))) { - expr_ref_buffer new_args(m_manager); - bool all_found = true; - for (unsigned i = 0; i < a->get_num_args(); ++i) { - expr_ref new_arg(m_manager); - if (!lookup_mk_extract(high, low, a->get_arg(i), new_arg)) { - all_found = false; - } - new_args.push_back(new_arg.get()); - } - if (!all_found) { - return false; - } - // We should not use mk_app because it does not guarantee that the result would be in simplified form. - // result = m_manager.mk_app(m_fid, a->get_decl_kind(), new_args.size(), new_args.c_ptr()); - if (is_app_of(a, m_fid, OP_BAND)) - mk_bv_and(new_args.size(), new_args.c_ptr(), result); - else if (is_app_of(a, m_fid, OP_BOR)) - mk_bv_or(new_args.size(), new_args.c_ptr(), result); - else if (is_app_of(a, m_fid, OP_BXOR)) - mk_bv_xor(new_args.size(), new_args.c_ptr(), result); - else if (is_app_of(a, m_fid, OP_BNOR)) - mk_bv_nor(new_args.size(), new_args.c_ptr(), result); - else if (is_app_of(a, m_fid, OP_BNAND)) - mk_bv_nand(new_args.size(), new_args.c_ptr(), result); - else if (is_app_of(a, m_fid, OP_BNOT)) { - SASSERT(new_args.size() == 1); - mk_bv_not(new_args[0], result); - } - else if (is_app_of(a, m_fid, OP_BADD)) - mk_add(new_args.size(), new_args.c_ptr(), result); - else if (is_app_of(a, m_fid, OP_BMUL)) - mk_mul(new_args.size(), new_args.c_ptr(), result); - else if (is_app_of(a, m_fid, OP_BSUB)) - mk_sub(new_args.size(), new_args.c_ptr(), result); - else { - UNREACHABLE(); - } - return true; - } - else if (m_manager.is_ite(a)) { - expr_ref then_b(m_manager), else_b(m_manager); - bool ok = lookup_mk_extract(high, low, a->get_arg(1), then_b); - ok = lookup_mk_extract(high, low, a->get_arg(2), else_b) && ok; - if (ok) { - m_bsimp.mk_ite(a->get_arg(0), then_b.get(), else_b.get(), result); - } - return ok; - } - result = m_util.mk_extract(high, low, arg); - return true; -} - -/** - \brief Let f be the operator fid:k. Then, this function - store in result the flat args of n. If n is not an f application, then store n in result. - - Example: if n is (f (f a b) (f c (f d e))), then a b c d e are stored in result. -*/ -template -void get_assoc_args(family_id fid, decl_kind k, expr * n, T & result) { - ptr_buffer todo; - todo.push_back(n); - while (!todo.empty()) { - expr * n = todo.back(); - todo.pop_back(); - if (is_app_of(n, fid, k)) { - app * app = to_app(n); - unsigned i = app->get_num_args(); - while (i > 0) { - --i; - todo.push_back(app->get_arg(i)); - } - } - else { - result.push_back(n); - } - } -} - -/** - \brief Similar to get_assoc_args, but the arguments are stored in reverse - other in result. -*/ -template -void get_inv_assoc_args(family_id fid, decl_kind k, expr * n, T & result) { - ptr_buffer todo; - todo.push_back(n); - while (!todo.empty()) { - expr * n = todo.back(); - todo.pop_back(); - if (is_app_of(n, fid, k)) { - app * app = to_app(n); - unsigned num = app->get_num_args(); - for (unsigned i = 0; i < num; i++) - todo.push_back(app->get_arg(i)); - } - else { - result.push_back(n); - } - } -} - -void bv_simplifier_plugin::mk_bv_eq(expr* a1, expr* a2, expr_ref& result) { - - rational val1; - rational val2; - bool is_num1 = is_numeral(a1, val1); - bool is_num2 = is_numeral(a2, val2); - if (is_num1 && is_num2 && val1 != val2) { - result = m_manager.mk_false(); - return; - } - - if (!m_util.is_concat(a1) && !is_num1) { - mk_eq_core(a1, a2, result); - return; - } - if (!m_util.is_concat(a2) && !is_num2) { - mk_eq_core(a1, a2, result); - return; - } - - ptr_buffer args1, args2; - get_inv_assoc_args(m_fid, OP_CONCAT, a1, args1); - get_inv_assoc_args(m_fid, OP_CONCAT, a2, args2); - TRACE("mk_bv_eq_concat", tout << mk_ll_pp(a1, m_manager) << "\n" << mk_ll_pp(a2, m_manager) << "\n"; - tout << "args1:\n"; - for (unsigned i = 0; i < args1.size(); i++) tout << mk_ll_pp(args1[i], m_manager) << "\n"; - tout << "args2:\n"; - for (unsigned i = 0; i < args2.size(); i++) tout << mk_ll_pp(args2[i], m_manager) << "\n";); - - - - expr_ref lhs(m_manager), rhs(m_manager), eq(m_manager); - expr_ref_buffer eqs(m_manager); - unsigned low1 = 0, low2 = 0; - ptr_buffer::iterator it1 = args1.begin(); - ptr_buffer::iterator end1 = args1.end(); - ptr_buffer::iterator it2 = args2.begin(); - ptr_buffer::iterator end2 = args2.end(); - - while (it1 != end1 && it2 != end2) { - SASSERT(it1 != end1); - SASSERT(it2 != end2); - expr * arg1 = *it1; - expr * arg2 = *it2; - TRACE("expr_bv_util", tout << "low1: " << low1 << " low2: " << low2 << "\n"; - tout << mk_pp(arg1, m_manager) << "\n"; - tout << mk_pp(arg2, m_manager) << "\n";); - unsigned sz1 = get_bv_size(arg1); - unsigned sz2 = get_bv_size(arg2); - SASSERT(low1 < sz1 && low2 < sz2); - unsigned rsz1 = sz1 - low1; - unsigned rsz2 = sz2 - low2; - TRACE("expr_bv_util", tout << "rsz1: " << rsz1 << " rsz2: " << rsz2 << "\n"; - tout << mk_pp(arg1, m_manager) << "\n"; - tout << mk_pp(arg2, m_manager) << "\n";); - - if (rsz1 == rsz2) { - mk_extract(sz1 - 1, low1, arg1, lhs); - mk_extract(sz2 - 1, low2, arg2, rhs); - low1 = 0; - low2 = 0; - ++it1; - ++it2; - } - else if (rsz1 < rsz2) { - mk_extract(sz1 - 1, low1, arg1, lhs); - mk_extract(rsz1 + low2 - 1, low2, arg2, rhs); - low1 = 0; - low2 += rsz1; - ++it1; - } - else { - mk_extract(rsz2 + low1 - 1, low1, arg1, lhs); - mk_extract(sz2 - 1, low2, arg2, rhs); - low1 += rsz2; - low2 = 0; - ++it2; - } - mk_eq_core(lhs.get(), rhs.get(), eq); - eqs.push_back(eq.get()); - } - m_bsimp.mk_and(eqs.size(), eqs.c_ptr(), result); -} - -void bv_simplifier_plugin::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) { - TRACE("mk_eq_core", ast_ll_pp(tout, m_manager, arg1 ); ast_ll_pp(tout, m_manager, arg2);); - if (arg1 == arg2) { - result = m_manager.mk_true(); - return; - } - if ((m_util.is_bv_and(arg1) && m_util.is_allone(arg2)) || (m_util.is_bv_or(arg1) && m_util.is_zero(arg2))) { - mk_args_eq_numeral(to_app(arg1), arg2, result); - return; - } - if ((m_util.is_bv_and(arg2) && m_util.is_allone(arg1)) || (m_util.is_bv_or(arg2) && m_util.is_zero(arg1))) { - mk_args_eq_numeral(to_app(arg2), arg1, result); - return; - } - -#if 1 - rational r; - unsigned num_bits = 0; - if (m_util.is_numeral(arg2, r, num_bits)) { - std::swap(arg1, arg2); - } - - if (m_util.is_numeral(arg1, r, num_bits) && - (m_util.is_bv_and(arg2) || m_util.is_bv_or(arg2) || m_util.is_bv_not(arg2))) { - rational two(2); - expr_ref tmp(m_manager); - expr_ref_vector tmps(m_manager); - for (unsigned i = 0; i < num_bits; ++i) { - bool is_neg = (r % two).is_zero(); - bit2bool_simplify(i, arg2, tmp); - if (is_neg) { - expr_ref tmp2(m_manager); - m_bsimp.mk_not(tmp, tmp2); - tmp = tmp2; - } - tmps.push_back(tmp); - r = div(r, two); - } - m_bsimp.mk_and(tmps.size(), tmps.c_ptr(), result); - TRACE("mk_eq_bb", - tout << mk_pp(arg1, m_manager) << "\n"; - tout << mk_pp(arg2, m_manager) << "\n"; - tout << mk_pp(result, m_manager) << "\n";); - return; - } -#endif - - if (!m_util.is_bv_add(arg1) && !m_util.is_bv_add(arg2) && - !m_util.is_bv_mul(arg1) && !m_util.is_bv_mul(arg2)) { - m_bsimp.mk_eq(arg1, arg2, result); - return; - } - - set_curr_sort(arg1); - expr_ref_vector args1(m_manager); - expr_ref_vector args2(m_manager); - get_assoc_args(m_fid, OP_BADD, arg1, args1); - get_assoc_args(m_fid, OP_BADD, arg2, args2); - TRACE("mk_eq_core", - tout << mk_pp(arg1, m_manager) << "\n" << mk_pp(arg2, m_manager) << "\n"; - tout << args1.size() << " " << args2.size() << "\n";); - - unsigned idx2 = 0; - while (idx2 < args2.size()) { - expr * m2 = args2.get(idx2); - unsigned sz1 = args1.size(); - unsigned idx1 = 0; - for (; idx1 < sz1; ++idx1) { - expr * m1 = args1.get(idx1); - if (eq_monomials_modulo_k(m1, m2)) { - expr_ref tmp(m_manager); - if (merge_monomials(true, m1, m2, tmp)) { - args1.set(idx1, tmp.get()); - } - else { - // the monomial cancelled each other. - args1.erase(idx1); - } - break; - } - } - if (idx1 == sz1) { - ++idx2; - } - else { - args2.erase(idx2); - } - } - - expr_ref lhs(m_manager); - expr_ref rhs(m_manager); - mk_sum_of_monomials(args1, lhs); - mk_sum_of_monomials(args2, rhs); - m_bsimp.mk_eq(lhs.get(), rhs.get(), result); -} - -void bv_simplifier_plugin::mk_args_eq_numeral(app * app, expr * n, expr_ref & result) { - expr_ref_buffer eqs(m_manager); - expr_ref eq(m_manager); - unsigned num = app->get_num_args(); - for (unsigned i = 0; i < num; i++) { - mk_bv_eq(app->get_arg(i), n, eq); - eqs.push_back(eq.get()); - } - m_bsimp.mk_and(eqs.size(), eqs.c_ptr(), result); -} - -void bv_simplifier_plugin::mk_concat(unsigned num_args, expr * const * args, expr_ref & result) { - TRACE("bv_simplifier_plugin", tout << "mk_concat:\n"; - for (unsigned i = 0; i < num_args; i++) ast_ll_pp(tout, m_manager, args[i]);); - unsigned shift = 0; - numeral val(0), arg_val; - for (unsigned i = num_args; i > 0; ) { - --i; - expr * arg = args[i]; - if (is_numeral(arg, arg_val)) { - arg_val *= rational::power_of_two(shift); - val += arg_val; - shift += get_bv_size(arg); - TRACE("bv_simplifier_plugin", - tout << "val: " << val << " arg_val: " << arg_val << " shift: " << shift << "\n";); - } - else { - // one of the arguments is not a number - result = m_manager.mk_app(m_fid, OP_CONCAT, num_args, args); - return; - } - } - - // all arguments are numerals - result = mk_numeral(val, shift); -} - -void bv_simplifier_plugin::mk_bv_and(unsigned num_args, expr * const* args, expr_ref & result) { - ptr_buffer flat_args; - for (unsigned i = 0; i < num_args; ++i) { - flat_args.push_back(args[i]); - } - // expr_lt_proc is a total order on expressions. - std::sort(flat_args.begin(), flat_args.end(), expr_lt_proc(m_fid, OP_BNOT)); - SASSERT(num_args > 0); - - unsigned bv_size = get_bv_size(args[0]); - - numeral allone = mk_allone(bv_size); - numeral val; - - uint64 unit = bv_size <= 64 ? to_uint64(numeral(-1), bv_size) : 0; - numeral n_unit(allone); - - expr * prev = 0; - ptr_buffer::iterator it = flat_args.begin(); - ptr_buffer::iterator it2 = it; - ptr_buffer::iterator end = flat_args.end(); - for (; it != end; ++it) { - expr* n = *it; - if (prev && - ((is_app_of(n, m_fid, OP_BNOT) && to_app(n)->get_arg(0) == prev) || - (is_app_of(prev, m_fid, OP_BNOT) && to_app(prev)->get_arg(0) == n))) { - result = mk_bv0(bv_size); - return; - } - else if (bv_size <= 64 && is_numeral(n, val)) { - unit &= to_uint64(val, bv_size); - if (unit == 0) { - result = mk_bv0(bv_size); - return; - } - } - else if (bv_size > 64 && is_numeral(n, val)) { - n_unit = mk_bv_and(val, n_unit, bv_size); - if (n_unit.is_zero()) { - result = mk_bv0(bv_size); - return; - } - } - else if (!prev || prev != n) { - *it2 = n; - prev = *it2; - ++it2; - } - } - - if (bv_size <= 64) { - n_unit = numeral(unit, numeral::ui64()); - } - - flat_args.set_end(it2); - if (n_unit != allone) { - flat_args.push_back(mk_numeral(n_unit, bv_size)); - } - - unsigned sz = flat_args.size(); - switch(sz) { - case 0: - result = mk_numeral(n_unit, bv_size); - break; - case 1: - result = flat_args.back(); - break; - default: - result = mk_list_assoc_app(m_manager, m_fid, OP_BAND, sz, flat_args.c_ptr()); - break; - } -} - -void bv_simplifier_plugin::mk_bv_or(unsigned num_args, expr * const* args, expr_ref & result) { -#if 0 - // Transformations for SAGE - // (bvor (concat 0 x) (concat y 0)) ==> (concat y x) - // (bvor (concat x 0) (concat 0 y)) ==> (concat x y) - if (num_args == 2 && - m_util.is_concat(args[0]) && - m_util.is_concat(args[1]) && - to_app(args[0])->get_num_args() == 2 && - to_app(args[1])->get_num_args() == 2) { - expr * x1 = to_app(args[0])->get_arg(0); - expr * x2 = to_app(args[0])->get_arg(1); - expr * y1 = to_app(args[1])->get_arg(0); - expr * y2 = to_app(args[1])->get_arg(1); - if (get_bv_size(x1) == get_bv_size(y1) && - get_bv_size(x2) == get_bv_size(y2)) { - if (m_util.is_zero(x1) && m_util.is_zero(y2)) { - // (bvor (concat 0 x) (concat y 0)) ==> (concat y x) - mk_concat(y1, x2, result); - return; - } - if (m_util.is_zero(x2) && m_util.is_zero(y1)) { - // (bvor (concat x 0) (concat 0 y)) ==> (concat x y) - mk_concat(x1, y2, result); - return; - } - } - } - // Investigate why it did not work. -#endif - - ptr_buffer flat_args; - for (unsigned i = 0; i < num_args; ++i) { - flat_args.push_back(args[i]); - } - std::sort(flat_args.begin(), flat_args.end(), expr_lt_proc(m_fid, OP_BNOT)); - SASSERT(num_args > 0); - - unsigned bv_size = get_bv_size(args[0]), sz; - numeral allone = mk_allone(bv_size); - numeral val; - - uint64 unit = 0; - numeral n_unit(0); - - expr * prev = 0; - ptr_buffer::iterator it = flat_args.begin(); - ptr_buffer::iterator it2 = it; - ptr_buffer::iterator end = flat_args.end(); - for (; it != end; ++it) { - expr* n = *it; - if (prev && - ((is_app_of(n, m_fid, OP_BNOT) && to_app(n)->get_arg(0) == prev) || - (is_app_of(prev, m_fid, OP_BNOT) && to_app(prev)->get_arg(0) == n))) { - result = mk_numeral(allone, bv_size); - return; - } - else if (bv_size <= 64 && is_numeral(n, val)) { - unit |= to_uint64(val, bv_size); - } - else if (bv_size > 64 && is_numeral(n, val)) { - n_unit = mk_bv_or(val, n_unit, bv_size); - } - else if (!prev || prev != n) { - *it2 = n; - prev = *it2; - ++it2; - } - } - - if (bv_size <= 64) { - n_unit = numeral(unit, numeral::ui64()); - } - - if (allone == n_unit) { - result = mk_numeral(allone, bv_size); - return; - } - - flat_args.set_end(it2); - if (!n_unit.is_zero()) { - flat_args.push_back(mk_numeral(n_unit, bv_size)); - } - - sz = flat_args.size(); - switch(sz) { - case 0: - result = mk_numeral(n_unit, bv_size); - break; - case 1: - result = flat_args.back(); - break; - default: - result = mk_list_assoc_app(m_manager, m_fid, OP_BOR, sz, flat_args.c_ptr()); - break; - } -} - -void bv_simplifier_plugin::mk_bv_xor(unsigned num_args, expr * const * args, expr_ref & result) { - ptr_buffer flat_args; - for (unsigned i = 0; i < num_args; ++i) { - flat_args.push_back(args[i]); - } - std::sort(flat_args.begin(), flat_args.end(), expr_lt_proc()); - SASSERT(num_args > 0); - - unsigned bv_size = get_bv_size(args[0]); - numeral val; - - uint64 unit = 0; - numeral n_unit(0); - - expr * prev = 0; - ptr_buffer::iterator it = flat_args.begin(); - ptr_buffer::iterator it2 = it; - ptr_buffer::iterator end = flat_args.end(); - for (; it != end; ++it) { - if (bv_size <= 64 && is_numeral(*it, val)) { - uint64 u = to_uint64(val, bv_size); - unit = u ^ unit; - } - else if (bv_size > 64 && is_numeral(*it, val)) { - n_unit = mk_bv_xor(n_unit, val, bv_size); - } - else if (prev != 0 && prev == *it) { - --it2; // remove prev - prev = 0; - } - else { - *it2 = *it; - prev = *it2; - ++it2; - } - } - flat_args.set_end(it2); - - if (bv_size <= 64) { - n_unit = numeral(numeral(unit,numeral::ui64())); - } - - if (!n_unit.is_zero()) { - flat_args.push_back(mk_numeral(n_unit, bv_size)); - } - - unsigned sz = flat_args.size(); - switch(sz) { - case 0: - result = mk_numeral(n_unit, bv_size); - break; - case 1: - result = flat_args.back(); - break; - default: - result = mk_list_assoc_app(m_manager, m_fid, OP_BXOR, flat_args.size(), flat_args.c_ptr()); - break; - } -} - -void bv_simplifier_plugin::mk_bv_not(expr * arg, expr_ref & result) { - numeral val; - unsigned bv_size; - if (m_util.is_numeral(arg, val, bv_size)) { - if (bv_size <= 64) { - uint64 l = bv_size; - uint64 mask = shift_left(1ull,l) - 1ull; - uint64 u = val.get_uint64(); - u = mask & (~u); - result = mk_numeral(numeral(u, numeral::ui64()), bv_size); - TRACE("bv_not_bug", - tout << l << " " << mask << " " << u << "\n"; - tout << mk_pp(arg, m_manager) << "\n" << mk_pp(result, m_manager) << "\n";); - } - else { - numeral r = mk_bv_not(val, bv_size); - result = mk_numeral(r, bv_size); - TRACE("bv_not_bug", - tout << mk_pp(arg, m_manager) << "\n" << mk_pp(result, m_manager) << "\n";); - } - } - else if (is_app_of(arg, m_fid, OP_BNOT)) { - result = to_app(arg)->get_arg(0); - } - else { - result = m_manager.mk_app(m_fid, OP_BNOT, arg); - } -} - -void bv_simplifier_plugin::mk_zeroext(unsigned n, expr * arg, expr_ref & result) { - if (n == 0) { - result = arg; - } - else { - expr_ref zero(m_manager); - zero = mk_bv0(n); - mk_concat(zero.get(), arg, result); - } -} - -void bv_simplifier_plugin::mk_repeat(unsigned n, expr * arg, expr_ref & result) { - ptr_buffer args; - for (unsigned i = 0; i < n; i++) { - args.push_back(arg); - } - mk_concat(args.size(), args.c_ptr(), result); -} - -bool bv_simplifier_plugin::is_minus_one_core(expr * arg) const { - numeral r; - unsigned bv_size; - if (m_util.is_numeral(arg, r, bv_size)) { - numeral minus_one(-1); - minus_one = mod(minus_one, rational::power_of_two(bv_size)); - return r == minus_one; - } - return false; -} - -bool bv_simplifier_plugin::is_x_minus_one(expr * arg, expr * & x) { - if (is_add(arg) && to_app(arg)->get_num_args() == 2) { - if (is_minus_one_core(to_app(arg)->get_arg(0))) { - x = to_app(arg)->get_arg(1); - return true; - } - if (is_minus_one_core(to_app(arg)->get_arg(1))) { - x = to_app(arg)->get_arg(0); - return true; - } - } - return false; -} - -void bv_simplifier_plugin::mk_bv_urem(expr * arg1, expr * arg2, expr_ref & result) { - numeral r1, r2; - unsigned bv_size; - bool is_num1 = m_util.is_numeral(arg1, r1, bv_size); - bool is_num2 = m_util.is_numeral(arg2, r2, bv_size); - bv_size = get_bv_size(arg1); - - if (is_num2 && r2.is_zero() && !m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BUREM0, arg1); - return; - } - - if (is_num1 && is_num2 && !r2.is_zero()) { - SASSERT(r1.is_nonneg() && r2.is_pos()); - r1 %= r2; - result = mk_numeral(r1, bv_size); - return; - } - - if (!m_params.m_hi_div0) { - // TODO: implement the optimization in this branch for the case the hardware interpretation is used for (x urem 0) - // urem(0, x) ==> ite(x = 0, urem0(x), 0) - if (is_num1 && r1.is_zero()) { - expr * zero = arg1; - expr_ref urem0(m_manager), eq0(m_manager); - urem0 = m_manager.mk_app(m_fid, OP_BUREM0, 1, &zero); - m_bsimp.mk_eq(arg2, zero, eq0); - m_bsimp.mk_ite(eq0.get(), urem0.get(), zero, result); - TRACE("urem", - tout << "urem:\n"; - ast_ll_pp(tout, m_manager, arg1); ast_ll_pp(tout, m_manager, arg2); - tout << "result:\n"; ast_ll_pp(tout, m_manager, result.get());); - return; - } - - // urem(x - 1, x) ==> ite(x = 0, urem0(x-1), x - 1) ==> ite(x = 0, urem0(-1), x - 1) - expr * x; - if (is_x_minus_one(arg1, x) && x == arg2) { - expr * x_minus_1 = arg1; - expr_ref zero(m_manager); - zero = mk_bv0(bv_size); - expr_ref minus_one(m_manager), urem0(m_manager), eq0(m_manager); - minus_one = mk_numeral(numeral::minus_one(), bv_size); - expr * minus_1 = minus_one.get(); - urem0 = m_manager.mk_app(m_fid, OP_BUREM0, 1, &minus_1); - m_bsimp.mk_eq(arg2, zero.get(), eq0); - m_bsimp.mk_ite(eq0.get(), urem0.get(), x_minus_1, result); - TRACE("urem", - tout << "urem:\n"; - ast_ll_pp(tout, m_manager, arg1); ast_ll_pp(tout, m_manager, arg2); - tout << "result:\n"; ast_ll_pp(tout, m_manager, result.get());); - return; - } - } - - if (is_num2 || m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BUREM_I, arg1, arg2); - } - else { - bv_size = get_bv_size(arg2); - result = m_manager.mk_ite(m_manager.mk_eq(arg2, mk_numeral(0, bv_size)), - m_manager.mk_app(m_fid, OP_BUREM0, arg1), - m_manager.mk_app(m_fid, OP_BUREM_I, arg1, arg2)); - } -} - -void bv_simplifier_plugin::mk_sign_extend(unsigned n, expr * arg, expr_ref & result) { - numeral r; - unsigned bv_size; - if (m_util.is_numeral(arg, r, bv_size)) { - unsigned result_bv_size = bv_size + n; - r = norm(r, bv_size, true); - r = mod(r, rational::power_of_two(result_bv_size)); - result = mk_numeral(r, result_bv_size); - TRACE("mk_sign_extend", tout << "n: " << n << "\n"; - ast_ll_pp(tout, m_manager, arg); tout << "====>\n"; - ast_ll_pp(tout, m_manager, result.get());); - return; - } - parameter param(n); - result = m_manager.mk_app(m_fid, OP_SIGN_EXT, 1, ¶m, 1, &arg); -} - -/** - Implement the following reductions - - (bvashr (bvashr a n1) n2) ==> (bvashr a (+ n1 n2)) - (bvlshr (bvlshr a n1) n2) ==> (bvlshr a (+ n1 n2)) - (bvshl (bvshl a n1) n2) ==> (bvshl a (+ n1 n2)) - when n1 and n2 are numerals. - Remark if (+ n1 n2) is greater than bv_size, we set (+ n1 n2) to bv_size - - Return true if the transformation was applied and the result stored in 'result'. - Return false otherwise. -*/ -bool bv_simplifier_plugin::shift_shift(bv_op_kind k, expr* arg1, expr* arg2, expr_ref& result) { - SASSERT(k == OP_BASHR || k == OP_BSHL || k == OP_BLSHR); - if (!is_app_of(arg1, m_fid, k)) - return false; - expr * a = to_app(arg1)->get_arg(0); - expr * n1 = to_app(arg1)->get_arg(1); - expr * n2 = arg2; - numeral r1, r2; - unsigned bv_size = UINT_MAX; - bool is_num1 = m_util.is_numeral(n1, r1, bv_size); - bool is_num2 = m_util.is_numeral(n2, r2, bv_size); - if (!is_num1 || !is_num2) - return false; - SASSERT(bv_size != UINT_MAX); - numeral r = r1 + r2; - if (r > numeral(bv_size)) - r = numeral(bv_size); - switch (k) { - case OP_BASHR: - mk_bv_ashr(a, m_util.mk_numeral(r, bv_size), result); - break; - case OP_BLSHR: - mk_bv_lshr(a, m_util.mk_numeral(r, bv_size), result); - break; - default: - SASSERT(k == OP_BSHL); - mk_bv_shl(a, m_util.mk_numeral(r, bv_size), result); - break; - } - return true; -} - -void bv_simplifier_plugin::mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result) { - // x << 0 == x - numeral r1, r2; - unsigned bv_size = get_bv_size(arg1); - bool is_num1 = is_numeral(arg1, r1); - bool is_num2 = is_numeral(arg2, r2); - - if (is_num2 && r2.is_zero()) { - result = arg1; - } - else if (is_num2 && r2 >= rational(bv_size)) { - result = mk_numeral(0, bv_size); - } - else if (is_num2 && is_num1 && bv_size <= 64) { - SASSERT(r1.is_uint64() && r2.is_uint64()); - SASSERT(r2.get_uint64() < bv_size); - - uint64 r = shift_left(r1.get_uint64(), r2.get_uint64()); - result = mk_numeral(r, bv_size); - } - else if (is_num1 && is_num2) { - SASSERT(r2 < rational(bv_size)); - SASSERT(r2.is_unsigned()); - result = mk_numeral(r1 * rational::power_of_two(r2.get_unsigned()), bv_size); - } - - // - // (bvshl x k) -> (concat (extract [n-1-k:0] x) bv0:k) - // - else if (is_num2 && r2.is_pos() && r2 < numeral(bv_size)) { - SASSERT(r2.is_unsigned()); - unsigned r = r2.get_unsigned(); - expr_ref tmp1(m_manager); - mk_extract(bv_size - r - 1, 0, arg1, tmp1); - expr_ref zero(m_manager); - zero = mk_bv0(r); - expr* args[2] = { tmp1.get(), zero.get() }; - mk_concat(2, args, result); - } - else if (shift_shift(OP_BSHL, arg1, arg2, result)) { - // done - } - else { - result = m_manager.mk_app(m_fid, OP_BSHL, arg1, arg2); - } - TRACE("mk_bv_shl", - tout << mk_pp(arg1, m_manager) << " << " - << mk_pp(arg2, m_manager) << " = " - << mk_pp(result.get(), m_manager) << "\n";); -} - -void bv_simplifier_plugin::mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result) { - // x >> 0 == x - numeral r1, r2; - unsigned bv_size = get_bv_size(arg1); - bool is_num1 = is_numeral(arg1, r1); - bool is_num2 = is_numeral(arg2, r2); - - if (is_num2 && r2.is_zero()) { - result = arg1; - } - else if (is_num2 && r2 >= rational(bv_size)) { - result = mk_numeral(rational(0), bv_size); - } - else if (is_num1 && is_num2 && bv_size <= 64) { - SASSERT(r1.is_uint64()); - SASSERT(r2.is_uint64()); - uint64 r = shift_right(r1.get_uint64(), r2.get_uint64()); - result = mk_numeral(r, bv_size); - } - else if (is_num1 && is_num2) { - SASSERT(r2.is_unsigned()); - unsigned sh = r2.get_unsigned(); - r1 = div(r1, rational::power_of_two(sh)); - result = mk_numeral(r1, bv_size); - } - // - // (bvlshr x k) -> (concat bv0:k (extract [n-1:k] x)) - // - else if (is_num2 && r2.is_pos() && r2 < numeral(bv_size)) { - SASSERT(r2.is_unsigned()); - unsigned r = r2.get_unsigned(); - expr_ref tmp1(m_manager); - mk_extract(bv_size - 1, r, arg1, tmp1); - expr_ref zero(m_manager); - zero = mk_bv0(r); - expr* args[2] = { zero.get(), tmp1.get() }; - mk_concat(2, args, result); - } - else if (shift_shift(OP_BLSHR, arg1, arg2, result)) { - // done - } - else { - result = m_manager.mk_app(m_fid, OP_BLSHR, arg1, arg2); - } - TRACE("mk_bv_lshr", tout << mk_pp(arg1, m_manager) << " >> " << - mk_pp(arg2, m_manager) << " = " << mk_pp(result.get(), m_manager) << "\n";); - -} - - -void bv_simplifier_plugin::mk_int2bv(expr * arg, sort* range, expr_ref & result) { - numeral val; - bool is_int; - unsigned bv_size = get_bv_size(range); - - if (m_arith.is_numeral(arg, val, is_int)) { - result = mk_numeral(val, bv_size); - } - // (int2bv (bv2int x)) == x - else if (is_app_of(arg, m_fid, OP_BV2INT) && bv_size == get_bv_size(to_app(arg)->get_arg(0))) { - result = to_app(arg)->get_arg(0); - } - else { - parameter parameter(bv_size); - result = m_manager.mk_app(m_fid, OP_INT2BV, 1, ¶meter, 1, &arg); - SASSERT(result.get()); - } -} - -void bv_simplifier_plugin::mk_bv2int(expr * arg, sort* range, expr_ref & result) { - if (!m_params.m_bv2int_distribute) { - parameter parameter(range); - result = m_manager.mk_app(m_fid, OP_BV2INT, 1, ¶meter, 1, &arg); - return; - } - numeral v; - if (is_numeral(arg, v)) { - result = m_arith.mk_numeral(v, true); - } - else if (is_mul_no_overflow(arg)) { - expr_ref tmp1(m_manager), tmp2(m_manager); - mk_bv2int(to_app(arg)->get_arg(0), range, tmp1); - mk_bv2int(to_app(arg)->get_arg(1), range, tmp2); - result = m_arith.mk_mul(tmp1, tmp2); - } - else if (is_add_no_overflow(arg)) { - expr_ref tmp1(m_manager), tmp2(m_manager); - mk_bv2int(to_app(arg)->get_arg(0), range, tmp1); - mk_bv2int(to_app(arg)->get_arg(1), range, tmp2); - result = m_arith.mk_add(tmp1, tmp2); - } - // commented out to reproduce bug in reduction of int2bv/bv2int - else if (m_util.is_concat(arg) && to_app(arg)->get_num_args() > 0) { - expr_ref_vector args(m_manager); - unsigned num_args = to_app(arg)->get_num_args(); - for (unsigned i = 0; i < num_args; ++i) { - expr_ref tmp(m_manager); - mk_bv2int(to_app(arg)->get_arg(i), range, tmp); - args.push_back(tmp); - } - 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_manager); - --i; - tmp = args[i].get(); - tmp = m_arith.mk_mul(m_arith.mk_numeral(power(numeral(2), sz), true), tmp); - args[i] = tmp; - sz += get_bv_size(to_app(arg)->get_arg(i)); - } - result = m_arith.mk_add(args.size(), args.c_ptr()); - } - else { - parameter parameter(range); - result = m_manager.mk_app(m_fid, OP_BV2INT, 1, ¶meter, 1, &arg); - } - SASSERT(m_arith.is_int(m_manager.get_sort(result.get()))); -} - -unsigned bv_simplifier_plugin::num_leading_zero_bits(expr* e) { - numeral v; - unsigned sz = get_bv_size(e); - if (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; -} - -bool bv_simplifier_plugin::is_mul_no_overflow(expr* e) { - if (!is_mul(e)) { - return false; - } - expr* e1 = to_app(e)->get_arg(0); - expr* e2 = to_app(e)->get_arg(1); - unsigned sz = get_bv_size(e1); - unsigned nb1 = num_leading_zero_bits(e1); - unsigned nb2 = num_leading_zero_bits(e2); - return nb1 + nb2 >= sz; -} - -bool bv_simplifier_plugin::is_add_no_overflow(expr* e) { - if (!is_add(e)) { - return false; - } - expr* e1 = to_app(e)->get_arg(0); - expr* e2 = to_app(e)->get_arg(1); - unsigned nb1 = num_leading_zero_bits(e1); - unsigned nb2 = num_leading_zero_bits(e2); - return nb1 > 0 && nb2 > 0; -} - - - -// Macro for generating mk_bv_sdiv_i, mk_bv_udiv_i, mk_bv_srem_i, mk_bv_urem_i and mk_bv_smod_i. -// These are essentially evaluators for the arg1 and arg2 are numerals. -// Q: Why do we need them? -// A: A constant may be eliminated using substitution. Its value is computed using the evaluator. -// Example: Suppose we have the top-level atom (= x (bvsrem_i a b)), and x is eliminated. -#define MK_FIXED_DIV_I(NAME, OP) \ -void bv_simplifier_plugin::NAME##_i(expr * arg1, expr * arg2, expr_ref & result) { \ - numeral r1, r2; \ - unsigned bv_size; \ - bool is_num1 = m_util.is_numeral(arg1, r1, bv_size); \ - bool is_num2 = m_util.is_numeral(arg2, r2, bv_size); \ - if (is_num1 && is_num2 && !r2.is_zero()) { \ - NAME(arg1, arg2, result); \ - } \ - else { \ - result = m_manager.mk_app(m_fid, OP, arg1, arg2); \ - } \ -} - -MK_FIXED_DIV_I(mk_bv_sdiv, OP_BSDIV_I) -MK_FIXED_DIV_I(mk_bv_udiv, OP_BUDIV_I) -MK_FIXED_DIV_I(mk_bv_srem, OP_BSREM_I) -MK_FIXED_DIV_I(mk_bv_urem, OP_BUREM_I) -MK_FIXED_DIV_I(mk_bv_smod, OP_BSMOD_I) - -void bv_simplifier_plugin::mk_bv_sdiv(expr* arg1, expr* arg2, expr_ref& result) { - numeral r1, r2; - unsigned bv_size; - bool is_num1 = m_util.is_numeral(arg1, r1, bv_size); - bool is_num2 = m_util.is_numeral(arg2, r2, bv_size); - - if (is_num2 && r2.is_zero() && !m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BSDIV0, arg1); - } - else if (is_num1 && is_num2 && !r2.is_zero()) { - r1 = norm(r1, bv_size, true); - r2 = norm(r2, bv_size, true); - result = mk_numeral(machine_div(r1, r2), bv_size); - } - else if (is_num2 || m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BSDIV_I, arg1, arg2); - } - else { - bv_size = get_bv_size(arg2); - result = m_manager.mk_ite(m_manager.mk_eq(arg2, mk_numeral(0, bv_size)), - m_manager.mk_app(m_fid, OP_BSDIV0, arg1), - m_manager.mk_app(m_fid, OP_BSDIV_I, arg1, arg2)); - } -} - -void bv_simplifier_plugin::mk_bv_udiv(expr* arg1, expr* arg2, expr_ref& result) { - numeral r1, r2; - unsigned bv_size; - bool is_num1 = m_util.is_numeral(arg1, r1, bv_size); - bool is_num2 = m_util.is_numeral(arg2, r2, bv_size); - - if (is_num2 && r2.is_zero() && !m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BUDIV0, arg1); - } - else if (is_num1 && is_num2 && !r2.is_zero()) { - SASSERT(r1.is_nonneg()); - SASSERT(r2.is_nonneg()); - result = mk_numeral(machine_div(r1, r2), bv_size); - } - else if (is_num2 || m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BUDIV_I, arg1, arg2); - } - else { - bv_size = get_bv_size(arg2); - result = m_manager.mk_ite(m_manager.mk_eq(arg2, mk_numeral(0, bv_size)), - m_manager.mk_app(m_fid, OP_BUDIV0, arg1), - m_manager.mk_app(m_fid, OP_BUDIV_I, arg1, arg2)); - } -} - -void bv_simplifier_plugin::mk_bv_srem(expr* arg1, expr* arg2, expr_ref& result) { - numeral r1, r2; - unsigned bv_size; - bool is_num1 = m_util.is_numeral(arg1, r1, bv_size); - bool is_num2 = m_util.is_numeral(arg2, r2, bv_size); - - if (is_num2 && r2.is_zero() && !m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BSREM0, arg1); - } - else if (is_num1 && is_num2 && !r2.is_zero()) { - r1 = norm(r1, bv_size, true); - r2 = norm(r2, bv_size, true); - result = mk_numeral(r1 % r2, bv_size); - } - else if (is_num2 || m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BSREM_I, arg1, arg2); - } - else { - bv_size = get_bv_size(arg2); - result = m_manager.mk_ite(m_manager.mk_eq(arg2, mk_numeral(0, bv_size)), - m_manager.mk_app(m_fid, OP_BSREM0, arg1), - m_manager.mk_app(m_fid, OP_BSREM_I, arg1, arg2)); - } -} - -void bv_simplifier_plugin::mk_bv_smod(expr* arg1, expr* arg2, expr_ref& result) { - numeral r1, r2; - unsigned bv_size; - bool is_num1 = m_util.is_numeral(arg1, r1, bv_size); - bool is_num2 = m_util.is_numeral(arg2, r2, bv_size); - - if (is_num1) - r1 = m_util.norm(r1, bv_size, true); - if (is_num2) - r2 = m_util.norm(r2, bv_size, true); - - TRACE("bv_simplifier", - tout << mk_pp(arg1, m_manager) << " smod " << mk_pp(arg2, m_manager) << "\n"; - ); - - - if (is_num2 && r2.is_zero()) { - if (!m_params.m_hi_div0) - result = m_manager.mk_app(m_fid, OP_BSMOD0, arg1); - else - result = arg1; - } - else if (is_num1 && is_num2) { - SASSERT(!r2.is_zero()); - numeral abs_r1 = m_util.norm(abs(r1), bv_size); - numeral abs_r2 = m_util.norm(abs(r2), bv_size); - numeral u = m_util.norm(abs_r1 % abs_r2, bv_size); - numeral r; - if (u.is_zero()) - r = u; - else if (r1.is_pos() && r2.is_pos()) - r = u; - else if (r1.is_neg() && r2.is_pos()) - r = m_util.norm(-u + r2, bv_size); - else if (r1.is_pos() && r2.is_neg()) - r = m_util.norm(u + r2, bv_size); - else - r = m_util.norm(-u, bv_size); - result = mk_numeral(r, bv_size); - } - else if (is_num2 || m_params.m_hi_div0) { - result = m_manager.mk_app(m_fid, OP_BSMOD_I, arg1, arg2); - } - else { - bv_size = get_bv_size(arg2); - result = m_manager.mk_ite(m_manager.mk_eq(arg2, mk_numeral(0, bv_size)), - m_manager.mk_app(m_fid, OP_BSMOD0, arg1), - m_manager.mk_app(m_fid, OP_BSMOD_I, arg1, arg2)); - } -} - -uint64 bv_simplifier_plugin::n64(expr* e) { - numeral r; - unsigned bv_size; - if (m_util.is_numeral(e, r, bv_size) && bv_size <= 64) { - return r.get_uint64(); - } - UNREACHABLE(); - return 0; -} - -rational bv_simplifier_plugin::num(expr* e) { - numeral r; - unsigned bv_size; - if (!m_util.is_numeral(e, r, bv_size)) { - UNREACHABLE(); - } - return r; - -} - -void bv_simplifier_plugin::mk_bv_nand(unsigned num_args, expr* const* args, expr_ref& result) { - unsigned bv_size; - if (are_numerals(num_args, args, bv_size)) { - if (bv_size <= 64) { - uint64 r = n64(args[0]); - for (unsigned i = 1; i < num_args; i++) { - r &= n64(args[i]); - } - result = mk_numeral(~r, bv_size); - } - else { - numeral r = num(args[0]); - for (unsigned i = 1; i < num_args; i++) { - r = mk_bv_and(r, num(args[i]), bv_size); - } - result = mk_numeral(mk_bv_not(r, bv_size), bv_size); - } - } - else { - result = m_manager.mk_app(m_fid, OP_BNAND, num_args, args); - } -} - -void bv_simplifier_plugin::mk_bv_nor(unsigned num_args, expr* const* args, expr_ref& result) { - unsigned bv_size; - if (are_numerals(num_args, args, bv_size)) { - if (bv_size <= 64) { - uint64 r = n64(args[0]); - for (unsigned i = 1; i < num_args; i++) { - r |= n64(args[i]); - } - result = mk_numeral(~r, bv_size); - } - else { - numeral r = num(args[0]); - for (unsigned i = 1; i < num_args; i++) { - r = mk_bv_or(r, num(args[i]), bv_size); - } - result = mk_numeral(mk_bv_not(r, bv_size), bv_size); - } - } - else { - result = m_manager.mk_app(m_fid, OP_BNOR, num_args, args); - } -} - -void bv_simplifier_plugin::mk_bv_xnor(unsigned num_args, expr* const* args, expr_ref& result) { - unsigned bv_size; - if (are_numerals(num_args, args, bv_size)) { - if (bv_size <= 64) { - uint64 r = n64(args[0]); - for (unsigned i = 1; i < num_args; i++) { - r ^= n64(args[i]); - } - result = mk_numeral(~r, bv_size); - } - else { - numeral r = num(args[0]); - for (unsigned i = 1; i < num_args; i++) { - r = mk_bv_xor(r, num(args[i]), bv_size); - } - result = mk_numeral(mk_bv_not(r, bv_size), bv_size); - } - } - else { - result = m_manager.mk_app(m_fid, OP_BXNOR, num_args, args); - } -} - -void bv_simplifier_plugin::mk_bv_rotate_left_core(unsigned shift, numeral r, unsigned bv_size, expr_ref& result) { - SASSERT(shift < bv_size); - if (bv_size <= 64) { - uint64 a = r.get_uint64(); - uint64 r = shift_left(a, shift) | shift_right(a, bv_size - shift); - result = mk_numeral(r, bv_size); - } - else { - rational r1 = div(r, rational::power_of_two(bv_size - shift)); // shift right - rational r2 = (r * rational::power_of_two(shift)) % rational::power_of_two(bv_size); // shift left - result = mk_numeral(r1 + r2, bv_size); - } -} - -void bv_simplifier_plugin::mk_bv_rotate_left(func_decl* f, expr* arg, expr_ref& result) { - numeral r; - unsigned bv_size; - SASSERT(f->get_decl_kind() == OP_ROTATE_LEFT); - if (m_util.is_numeral(arg, r, bv_size)) { - unsigned shift = f->get_parameter(0).get_int() % bv_size; - mk_bv_rotate_left_core(shift, r, bv_size, result); - } - else { - result = m_manager.mk_app(f, arg); - } -} - -void bv_simplifier_plugin::mk_bv_rotate_right_core(unsigned shift, numeral r, unsigned bv_size, expr_ref& result) { - SASSERT(shift < bv_size); - if (bv_size <= 64) { - uint64 a = r.get_uint64(); - uint64 r = shift_right(a, shift) | shift_left(a, bv_size - shift); - result = mk_numeral(r, bv_size); - } - else { - rational r1 = div(r, rational::power_of_two(shift)); // shift right - rational r2 = (r * rational::power_of_two(bv_size - shift)) % rational::power_of_two(bv_size); // shift left - result = mk_numeral(r1 + r2, bv_size); - } -} - -void bv_simplifier_plugin::mk_bv_rotate_right(func_decl* f, expr* arg, expr_ref& result) { - numeral r; - unsigned bv_size; - SASSERT(f->get_decl_kind() == OP_ROTATE_RIGHT); - if (m_util.is_numeral(arg, r, bv_size)) { - unsigned shift = f->get_parameter(0).get_int() % bv_size; - mk_bv_rotate_right_core(shift, r, bv_size, result); - } - else { - result = m_manager.mk_app(f, arg); - } -} - -void bv_simplifier_plugin::mk_bv_redor(expr* arg, expr_ref& result) { - if (is_numeral(arg)) { - result = m_util.is_zero(arg)?mk_numeral(0, 1):mk_numeral(1,1); - } - else { - result = m_manager.mk_app(m_fid, OP_BREDOR, arg); - } -} - -void bv_simplifier_plugin::mk_bv_redand(expr* arg, expr_ref& result) { - numeral r; - unsigned bv_size; - if (m_util.is_numeral(arg, r, bv_size)) { - numeral allone = mk_allone(bv_size); - result = mk_numeral((r == allone)?1:0, 1); - } - else { - result = m_manager.mk_app(m_fid, OP_BREDAND, arg); - } -} - -void bv_simplifier_plugin::mk_bv_comp(expr* arg1, expr* arg2, expr_ref& result) { - numeral r1, r2; - if (arg1 == arg2) { - result = mk_numeral(1,1); - } - else if (is_numeral(arg1, r1) && is_numeral(arg2, r2)) { - result = mk_numeral((r1 == r2)?1:0, 1); - } - else { - result = m_manager.mk_app(m_fid, OP_BCOMP, arg1, arg2); - } -} - -void bv_simplifier_plugin::mk_bv_ashr(expr* arg1, expr* arg2, expr_ref& result) { - numeral r1, r2; - unsigned bv_size = get_bv_size(arg1); - bool is_num1 = m_util.is_numeral(arg1, r1, bv_size); - bool is_num2 = m_util.is_numeral(arg2, r2, bv_size); - - if (bv_size == 0) { - result = mk_numeral(rational(0), bv_size); - } - else if (is_num2 && r2.is_zero()) { - result = arg1; - } - else if (bv_size <= 64 && is_num1 && is_num2) { - uint64 n1 = n64(arg1); - uint64 n2_orig = n64(arg2); - uint64 n2 = n2_orig % bv_size; - SASSERT(n2 < bv_size); - uint64 r = shift_right(n1, n2); - bool sign = (n1 & shift_left(1ull, bv_size - 1ull)) != 0; - if (n2_orig > n2) { - if (sign) { - r = shift_left(1ull, bv_size) - 1ull; - } - else { - r = 0; - } - } - else if (sign) { - uint64 allone = shift_left(1ull, bv_size) - 1ull; - uint64 mask = ~(shift_left(1ull, bv_size - n2) - 1ull); - mask &= allone; - r |= mask; - } - result = mk_numeral(r, bv_size); - TRACE("bv", tout << mk_pp(arg1, m_manager) << " >> " - << mk_pp(arg2, m_manager) << " = " - << mk_pp(result.get(), m_manager) << "\n"; - tout << n1 << " >> " << n2 << " = " << r << "\n"; - ); - } - else if (is_num1 && is_num2 && rational(bv_size) <= r2) { - if (has_sign_bit(r1, bv_size)) { - result = mk_numeral(mk_allone(bv_size), bv_size); - } - else { - result = mk_bv0(bv_size); - } - } - else if (is_num1 && is_num2) { - SASSERT(r2 < rational(bv_size)); - bool sign = has_sign_bit(r1, bv_size); - r1 = div(r1, rational::power_of_two(r2.get_unsigned())); - if (sign) { - // pad ones. - rational p(1); - for (unsigned i = 0; i < bv_size; ++i) { - if (r1 < p) { - r1 += p; - } - p *= rational(2); - } - } - result = mk_numeral(r1, bv_size); - - } - else if (shift_shift(OP_BASHR, arg1, arg2, result)) { - // done - } - else { - result = m_manager.mk_app(m_fid, OP_BASHR, arg1, arg2); - } -} - -void bv_simplifier_plugin::mk_bv_ext_rotate_right(expr* arg1, expr* arg2, expr_ref& result) { - numeral r2; - unsigned bv_size; - if (m_util.is_numeral(arg2, r2, bv_size)) { - unsigned shift = static_cast((r2 % numeral(bv_size)).get_uint64() % static_cast(bv_size)); - numeral r1; - if (is_numeral(arg1, r1)) { - mk_bv_rotate_right_core(shift, r1, bv_size, result); - } - else { - parameter p(shift); - result = m_manager.mk_app(m_fid, OP_ROTATE_RIGHT, 1, &p, 1, &arg1); - } - } - else { - result = m_manager.mk_app(m_fid, OP_EXT_ROTATE_RIGHT, arg1, arg2); - } -} - - -void bv_simplifier_plugin::mk_bv_ext_rotate_left(expr* arg1, expr* arg2, expr_ref& result) { - numeral r2; - unsigned bv_size; - if (m_util.is_numeral(arg2, r2, bv_size)) { - unsigned shift = static_cast((r2 % numeral(bv_size)).get_uint64() % static_cast(bv_size)); - numeral r1; - if (is_numeral(arg1, r1)) { - mk_bv_rotate_left_core(shift, r1, bv_size, result); - } - else { - parameter p(shift); - result = m_manager.mk_app(m_fid, OP_ROTATE_LEFT, 1, &p, 1, &arg1); - } - } - else { - result = m_manager.mk_app(m_fid, OP_EXT_ROTATE_LEFT, arg1, arg2); - } -} - -void bv_simplifier_plugin::bit2bool_simplify(unsigned idx, expr* e, expr_ref& result) { - - parameter p(idx); - - ptr_vector todo; - expr_ref_vector pinned(m_manager); - ptr_vector cache; - todo.push_back(e); - expr* e0 = e; - ptr_vector argv; - expr_ref tmp(m_manager); - while (!todo.empty()) { - e = todo.back(); - unsigned e_id = e->get_id(); - if (e_id >= cache.size()) { - cache.resize(e_id+1,0); - } - if (cache[e_id]) { - todo.pop_back(); - continue; - } - if (!m_util.is_numeral(e) && - !m_util.is_bv_and(e) && - !m_util.is_bv_or(e) && - !(is_app_of(e, m_fid, OP_BXOR) && to_app(e)->get_num_args() == 2) && - !m_manager.is_ite(e) && - !m_util.is_concat(e) && - !m_util.is_bv_not(e)) { - expr_ref extr(m_manager); - extr = m_util.mk_extract(idx, idx, e); - cache[e_id] = m_manager.mk_eq(m_util.mk_numeral(1, 1), extr); - pinned.push_back(cache[e_id]); - todo.pop_back(); - continue; - } - app* a = to_app(e); - unsigned sz = a->get_num_args(); - if (m_util.is_concat(e)) { - // look for first argument - unsigned idx1 = idx; - while (sz > 0) { - --sz; - expr * a_i = a->get_arg(sz); - unsigned a_sz = get_bv_size(a_i); - if (a_sz <= idx1) { - idx1 -= a_sz; - } - else { - // idx < a_sz; - bit2bool_simplify(idx1, a_i, tmp); - pinned.push_back(tmp); - cache[e_id] = to_app(tmp); - break; - } - } - todo.pop_back(); - continue; - } - argv.reset(); - for (unsigned i = 0; i < sz; ++i) { - expr* arg_i = a->get_arg(i); - if (i == 0 && m_manager.is_ite(e)) { - argv.push_back(arg_i); - } - else if (cache.size() > arg_i->get_id() && cache[arg_i->get_id()]) { - argv.push_back(cache[arg_i->get_id()]); - } - else { - todo.push_back(arg_i); - } - } - if (sz != argv.size()) { - continue; - } - todo.pop_back(); - rational val; - unsigned num_bits; - if (m_util.is_numeral(e, val, num_bits)) { - rational two(2); - for (unsigned i = 0; i < idx; ++i) { - val = div(val, two); - } - bool is_pos = !(val % two).is_zero(); - tmp = is_pos?m_manager.mk_true():m_manager.mk_false(); - } - else if (m_util.is_bv_and(e)) { - //tmp = m_manager.mk_and(sz, argv.c_ptr()); - m_bsimp.mk_and(sz, argv.c_ptr(), tmp); - pinned.push_back(tmp); - } - else if (m_util.is_bv_or(e)) { - //tmp = m_manager.mk_or(sz, argv.c_ptr()); - m_bsimp.mk_or(sz, argv.c_ptr(), tmp); - pinned.push_back(tmp); - } - else if (m_util.is_bv_not(e)) { - //tmp = m_manager.mk_not(argv[0]); - m_bsimp.mk_not(argv[0], tmp); - pinned.push_back(tmp); - } - else if (is_app_of(e, m_fid, OP_BXOR)) { - SASSERT(argv.size() == 2); - m_bsimp.mk_xor(argv[0], argv[1], tmp); - pinned.push_back(tmp); - } - else if (m_manager.is_ite(e)) { - //tmp = m_manager.mk_ite(argv[0], argv[1], argv[2]); - m_bsimp.mk_ite(argv[0], argv[1], argv[2], tmp); - pinned.push_back(tmp); - } - else { - UNREACHABLE(); - } - cache[e_id] = to_app(tmp); - } - result = cache[e0->get_id()]; -} - - -// replace addition by concatenation. -void bv_simplifier_plugin::mk_add_concat(expr_ref& result) { - if (!m_util.is_bv_add(result)) { - return; - } - app* a = to_app(result); - if (a->get_num_args() != 2) { - return; - } - expr* x = a->get_arg(0); - expr* y = a->get_arg(1); - if (!m_util.is_concat(x)) { - std::swap(x, y); - } - if (!m_util.is_concat(x)) { - return; - } - unsigned sz = m_util.get_bv_size(x); - -#if 0 - // optimzied version. Seems not worth it.. -#define UPDATE_CURR(_curr1, _idx1,_x,_is_num, _i) \ - if (_idx1 >= m_util.get_bv_size(_curr1)) { \ - _curr1 = _x; \ - _idx1 = _i; \ - _is_num = false; \ - } \ - while (m_util.is_concat(_curr1)) { \ - _is_num = false; \ - unsigned num_args = to_app(_curr1)->get_num_args(); \ - while (true) { \ - --num_args; \ - expr* c1 = to_app(_curr1)->get_arg(num_args); \ - unsigned sz1 = m_util.get_bv_size(c1); \ - if (sz1 < _idx1) { \ - _idx1 -= sz1; \ - } \ - else { \ - _curr1 = c1; \ - break; \ - } \ - } \ - } - - unsigned idx1 = 0, idx2 = 0; - expr* curr1 = x, *curr2 = y; - bool is_num1 = false, is_num2 = false; - rational val1, val2; - rational two(2); - for (unsigned i = 0; i < sz; ++i, ++idx1, ++idx2) { - UPDATE_CURR(curr1, idx1, x, is_num1, i); - UPDATE_CURR(curr2, idx2, y, is_num2, i); - if (idx1 == 0 && m_util.is_numeral(curr1, val1, bv_size)) { - is_num1 = true; - } - if (idx2 == 0 && m_util.is_numeral(curr2, val2, bv_size)) { - is_num2 = true; - } - if ((is_num1 && (val1 % two).is_zero()) || - (is_num2 && (val2 % two).is_zero())) { - val1 = div(val1, two); - val2 = div(val2, two); - continue; - } - return; - } - mk_bv_or(2, a->get_args(), result); -#endif - - for (unsigned i = 0; i < sz; ++i) { - if (!is_zero_bit(x,i) && !is_zero_bit(y,i)) { - return; - } - } - mk_bv_or(2, a->get_args(), result); -} - -bool bv_simplifier_plugin::is_zero_bit(expr* x, unsigned idx) { - rational val; - unsigned bv_size; - if (m_util.is_numeral(x, val, bv_size)) { - if (val.is_zero()) { - return true; - } - rational two(2); - while (idx > 0) { - val = div(val, two); - idx--; - } - return (val % two).is_zero(); - } - if (m_util.is_concat(x)) { - unsigned num_args = to_app(x)->get_num_args(); - while (num_args > 0) { - --num_args; - expr* y = to_app(x)->get_arg(num_args); - bv_size = m_util.get_bv_size(y); - if (bv_size <= idx) { - idx -= bv_size; - } - else { - return is_zero_bit(y, idx); - } - } - UNREACHABLE(); - } - - return false; -} diff --git a/src/ast/simplifier/bv_simplifier_plugin.h b/src/ast/simplifier/bv_simplifier_plugin.h deleted file mode 100644 index 7208b6dc8..000000000 --- a/src/ast/simplifier/bv_simplifier_plugin.h +++ /dev/null @@ -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_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 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_ */ diff --git a/src/ast/simplifier/datatype_simplifier_plugin.cpp b/src/ast/simplifier/datatype_simplifier_plugin.cpp deleted file mode 100644 index b665ed101..000000000 --- a/src/ast/simplifier/datatype_simplifier_plugin.cpp +++ /dev/null @@ -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 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; -} - diff --git a/src/ast/simplifier/datatype_simplifier_plugin.h b/src/ast/simplifier/datatype_simplifier_plugin.h deleted file mode 100644 index e976beba7..000000000 --- a/src/ast/simplifier/datatype_simplifier_plugin.h +++ /dev/null @@ -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_ */ diff --git a/src/ast/simplifier/elim_bounds.cpp b/src/ast/simplifier/elim_bounds.cpp deleted file mode 100644 index 738fc3012..000000000 --- a/src/ast/simplifier/elim_bounds.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - elim_bounds.cpp - -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 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 m_lowers; - obj_hashtable m_uppers; - obj_hashtable m_candidate_set; - ptr_buffer 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); -} - diff --git a/src/ast/simplifier/fpa_simplifier_plugin.cpp b/src/ast/simplifier/fpa_simplifier_plugin.cpp deleted file mode 100644 index 2d333c872..000000000 --- a/src/ast/simplifier/fpa_simplifier_plugin.cpp +++ /dev/null @@ -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; -} - diff --git a/src/ast/simplifier/fpa_simplifier_plugin.h b/src/ast/simplifier/fpa_simplifier_plugin.h deleted file mode 100644 index 8c9f8de4e..000000000 --- a/src/ast/simplifier/fpa_simplifier_plugin.h +++ /dev/null @@ -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_ */ diff --git a/src/ast/simplifier/poly_simplifier_plugin.cpp b/src/ast/simplifier/poly_simplifier_plugin.cpp deleted file mode 100644 index 88637d694..000000000 --- a/src/ast/simplifier/poly_simplifier_plugin.cpp +++ /dev/null @@ -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 & 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 -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(n, result); - else - add_monomial_core(n, result); -} - -/** - \brief Copy the monomials in n to result. The monomials are inverted if inv is true. - Equivalent monomials are merged. -*/ -template -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(to_app(n)->get_arg(i), result); - } - else { - add_monomial_core(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(n, result); - else - process_sum_of_monomials_core(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 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 -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(args[0], monomials); - for (unsigned i = 1; i < num_args; i++) { - process_sum_of_monomials_core(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(num_args, args, result); - else - mk_add_core_core(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 & 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 szs; - buffer it; - vector > 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()); - ptr_vector & 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 m; - for (unsigned i = 0; i < num_args; i++) { - ptr_vector & 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(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 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 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; -} diff --git a/src/ast/simplifier/poly_simplifier_plugin.h b/src/ast/simplifier/poly_simplifier_plugin.h deleted file mode 100644 index fe5572b20..000000000 --- a/src/ast/simplifier/poly_simplifier_plugin.h +++ /dev/null @@ -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 & 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 - void add_monomial_core(expr * n, expr_ref_vector & result); - void add_monomial(bool inv, expr * n, expr_ref_vector & result); - template - 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 - 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 & 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_ */ diff --git a/src/ast/simplifier/push_app_ite.cpp b/src/ast/simplifier/push_app_ite.cpp deleted file mode 100644 index 8b56dcd85..000000000 --- a/src/ast/simplifier/push_app_ite.cpp +++ /dev/null @@ -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(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) { -} diff --git a/src/ast/simplifier/push_app_ite.h b/src/ast/simplifier/push_app_ite.h deleted file mode 100644 index 96400b1af..000000000 --- a/src/ast/simplifier/push_app_ite.h +++ /dev/null @@ -1,63 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - push_app_ite.h - -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_ */ - diff --git a/src/ast/simplifier/seq_simplifier_plugin.cpp b/src/ast/simplifier/seq_simplifier_plugin.cpp deleted file mode 100644 index 2125c4f4c..000000000 --- a/src/ast/simplifier/seq_simplifier_plugin.cpp +++ /dev/null @@ -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; -} - diff --git a/src/ast/simplifier/seq_simplifier_plugin.h b/src/ast/simplifier/seq_simplifier_plugin.h deleted file mode 100644 index a37a2209f..000000000 --- a/src/ast/simplifier/seq_simplifier_plugin.h +++ /dev/null @@ -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_ */ diff --git a/src/ast/simplifier/simplifier.cpp b/src/ast/simplifier/simplifier.cpp deleted file mode 100644 index e7f842203..000000000 --- a/src/ast/simplifier/simplifier.cpp +++ /dev/null @@ -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::const_iterator it = m_plugins.begin(); - ptr_vector::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::const_iterator it = m_plugins.begin(); - ptr_vector::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 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::const_iterator it = m_ac_marked.begin(); - ptr_vector::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 & 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 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 (f args[0] ... args[num_args - 1]), and - store in \c pr a proof for (= (f args[0] ... args[num_args - 1]) e) - - 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 args; - ptr_vector 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 & 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 todo; - ptr_buffer new_args; - ptr_buffer 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 & colors, expr * n) { - obj_map::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 & colors, ptr_buffer & todo, ptr_buffer & 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::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 & result) { - ptr_buffer todo; - func_decl * f = n->get_decl(); - obj_map & colors = m_colors; - colors.reset(); - todo.push_back(n); - while (!todo.empty()) { - expr * curr = todo.back(); - int color; - obj_map::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 & args, vector & mults) { - SASSERT(m_ac_support); - ptr_buffer 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::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 sorts; - buffer 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 new_patterns; - ptr_buffer 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::const_iterator it = s.begin_plugins(); - ptr_vector::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::const_iterator it = begin_plugins(); - ptr_vector::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); -} - diff --git a/src/ast/simplifier/simplifier.h b/src/ast/simplifier/simplifier.h deleted file mode 100644 index 5148721f1..000000000 --- a/src/ast/simplifier/simplifier.h +++ /dev/null @@ -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 m_plugins; - ptr_vector m_args; - vector m_mults; - ptr_vector 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 m_ac_marked; - obj_map m_ac_cache; // temporary cache for ac - obj_map m_ac_pr_cache; // temporary cache for ac - obj_map m_colors; // temporary cache for topological sort. - obj_map 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 & result, proof_ref & p); - void get_ac_args(app * n, ptr_vector & args, vector & 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 & 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 (= s r) 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::const_iterator begin_plugins() const { return m_plugins.begin(); } - ptr_vector::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 diff --git a/src/ast/simplifier/simplifier_plugin.cpp b/src/ast/simplifier/simplifier_plugin.cpp deleted file mode 100644 index a62b15131..000000000 --- a/src/ast/simplifier/simplifier_plugin.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - simplifier_plugin.cpp - -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 & 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 new_args; - expand_args(num_args, mults, args, new_args); - return reduce(f, new_args.size(), new_args.c_ptr(), result); - } -} diff --git a/src/ast/simplifier/simplifier_plugin.h b/src/ast/simplifier/simplifier_plugin.h deleted file mode 100644 index 26b5bcd59..000000000 --- a/src/ast/simplifier/simplifier_plugin.h +++ /dev/null @@ -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 & 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 (f args[0] ... args[num_args - 1]). - - 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 (f args[0] ... args[0] ... args[num_args - 1]). - 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 (= lhs rhs). - - 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 (distinct args[0] ... args[num_args-1]). - - 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 diff --git a/src/ast/static_features.cpp b/src/ast/static_features.cpp index 3c8333d02..3db4d02a2 100644 --- a/src/ast/static_features.cpp +++ b/src/ast/static_features.cpp @@ -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 { diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index c81170ba4..21b66febd 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -15,21 +15,21 @@ Author: Notes: --*/ -#include "cmd_context/cmd_context.h" +#include "util/gparams.h" +#include "util/env_params.h" #include "util/version.h" #include "ast/ast_smt_pp.h" #include "ast/ast_smt2_pp.h" #include "ast/ast_pp.h" -#include "model/model_smt2_pp.h" #include "ast/array_decl_plugin.h" #include "ast/pp.h" +#include "ast/well_sorted.h" +#include "ast/pp_params.hpp" +#include "model/model_smt2_pp.h" +#include "cmd_context/cmd_context.h" #include "cmd_context/cmd_util.h" #include "cmd_context/simplify_cmd.h" #include "cmd_context/eval_cmd.h" -#include "util/gparams.h" -#include "util/env_params.h" -#include "ast/well_sorted.h" -#include "ast/pp_params.hpp" class help_cmd : public cmd { svector m_cmds; @@ -79,19 +79,15 @@ public: } // named_cmd_lt is not a total order for commands, but this is irrelevant for Linux x Windows behavior std::sort(cmds.begin(), cmds.end(), named_cmd_lt()); - vector::const_iterator it2 = cmds.begin(); - vector::const_iterator end2 = cmds.end(); - for (; it2 != end2; ++it2) { - display_cmd(ctx, it2->first, it2->second); + for (named_cmd const& nc : cmds) { + display_cmd(ctx, nc.first, nc.second); } } else { - svector::const_iterator it = m_cmds.begin(); - svector::const_iterator end = m_cmds.end(); - for (; it != end; ++it) { - cmd * c = ctx.find_cmd(*it); + for (symbol const& s : m_cmds) { + cmd * c = ctx.find_cmd(s); SASSERT(c); - display_cmd(ctx, *it, c); + display_cmd(ctx, s, c); } } ctx.regular_stream() << "\"\n"; @@ -136,11 +132,10 @@ ATOMIC_CMD(get_assignment_cmd, "get-assignment", "retrieve assignment", { ctx.get_check_sat_result()->get_model(m); ctx.regular_stream() << "("; dictionary const & macros = ctx.get_macros(); - dictionary::iterator it = macros.begin(); - dictionary::iterator end = macros.end(); - for (bool first = true; it != end; ++it) { - symbol const & name = (*it).m_key; - macro_decls const & _m = (*it).m_value; + bool first = true; + for (auto const& kv : macros) { + symbol const & name = kv.m_key; + macro_decls const & _m = kv.m_value; for (auto md : _m) { if (md.m_domain.size() == 0 && ctx.m().is_bool(md.m_body)) { expr_ref val(ctx.m()); @@ -211,14 +206,13 @@ static void print_core(cmd_context& ctx) { ptr_vector core; ctx.get_check_sat_result()->get_unsat_core(core); ctx.regular_stream() << "("; - ptr_vector::const_iterator it = core.begin(); - ptr_vector::const_iterator end = core.end(); - for (bool first = true; it != end; ++it) { + bool first = true; + for (expr* e : core) { if (first) first = false; else ctx.regular_stream() << " "; - ctx.regular_stream() << mk_ismt2_pp(*it, ctx.m()); + ctx.regular_stream() << mk_ismt2_pp(e, ctx.m()); } ctx.regular_stream() << ")" << std::endl; } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index aa2bb0554..c0e1c9f9c 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -18,7 +18,10 @@ Notes: #include #include "util/tptr.h" -#include "cmd_context/cmd_context.h" +#include "util/cancel_eh.h" +#include "util/scoped_ctrl_c.h" +#include "util/dec_ref_util.h" +#include "util/scoped_timer.h" #include "ast/func_decl_dependencies.h" #include "ast/arith_decl_plugin.h" #include "ast/bv_decl_plugin.h" @@ -31,22 +34,19 @@ Notes: #include "ast/rewriter/var_subst.h" #include "ast/pp.h" #include "ast/ast_smt2_pp.h" -#include "cmd_context/basic_cmds.h" -#include "util/cancel_eh.h" -#include "util/scoped_ctrl_c.h" -#include "util/dec_ref_util.h" #include "ast/decl_collector.h" #include "ast/well_sorted.h" -#include "model/model_evaluator.h" #include "ast/for_each_expr.h" -#include "util/scoped_timer.h" -#include "cmd_context/interpolant_cmds.h" +#include "ast/rewriter/th_rewriter.h" +#include "model/model_evaluator.h" #include "model/model_smt2_pp.h" #include "model/model_v2_pp.h" #include "model/model_params.hpp" -#include "ast/rewriter/th_rewriter.h" #include "tactic/tactic_exception.h" #include "solver/smt_logics.h" +#include "cmd_context/basic_cmds.h" +#include "cmd_context/interpolant_cmds.h" +#include "cmd_context/cmd_context.h" func_decls::func_decls(ast_manager & m, func_decl * f): m_decls(TAG(func_decl*, f, 0)) { @@ -61,11 +61,9 @@ void func_decls::finalize(ast_manager & m) { else { TRACE("func_decls", tout << "finalize...\n";); func_decl_set * fs = UNTAG(func_decl_set *, m_decls); - func_decl_set::iterator it = fs->begin(); - func_decl_set::iterator end = fs->end(); - for (; it != end; ++it) { - TRACE("func_decls", tout << "dec_ref of " << (*it)->get_name() << " ref_count: " << (*it)->get_ref_count() << "\n";); - m.dec_ref(*it); + for (func_decl * f : *fs) { + TRACE("func_decls", tout << "dec_ref of " << f->get_name() << " ref_count: " << f->get_ref_count() << "\n";); + m.dec_ref(f); } dealloc(fs); } @@ -161,10 +159,7 @@ bool func_decls::clash(func_decl * f) const { if (GET_TAG(m_decls) == 0) return false; func_decl_set * fs = UNTAG(func_decl_set *, m_decls); - func_decl_set::iterator it = fs->begin(); - func_decl_set::iterator end = fs->end(); - for (; it != end; ++it) { - func_decl * g = *it; + for (func_decl * g : *fs) { if (g == f) continue; if (g->get_arity() != f->get_arity()) @@ -201,10 +196,7 @@ func_decl * func_decls::find(unsigned arity, sort * const * domain, sort * range if (!more_than_one()) return first(); func_decl_set * fs = UNTAG(func_decl_set *, m_decls); - func_decl_set::iterator it = fs->begin(); - func_decl_set::iterator end = fs->end(); - for (; it != end; it++) { - func_decl * f = *it; + for (func_decl * f : *fs) { if (range != 0 && f->get_range() != range) continue; if (f->get_arity() != arity) @@ -607,10 +599,8 @@ void cmd_context::register_builtin_sorts(decl_plugin * p) { svector names; p->get_sort_names(names, m_logic); family_id fid = p->get_family_id(); - svector::const_iterator it = names.begin(); - svector::const_iterator end = names.end(); - for (; it != end; ++it) { - psort_decl * d = pm().mk_psort_builtin_decl((*it).m_name, fid, (*it).m_kind); + for (builtin_name const& n : names) { + psort_decl * d = pm().mk_psort_builtin_decl(n.m_name, fid, n.m_kind); insert(d); } } @@ -619,17 +609,15 @@ void cmd_context::register_builtin_ops(decl_plugin * p) { svector names; p->get_op_names(names, m_logic); family_id fid = p->get_family_id(); - svector::const_iterator it = names.begin(); - svector::const_iterator end = names.end(); - for (; it != end; ++it) { - if (m_builtin_decls.contains((*it).m_name)) { - builtin_decl & d = m_builtin_decls.find((*it).m_name); - builtin_decl * new_d = alloc(builtin_decl, fid, (*it).m_kind, d.m_next); + for (builtin_name const& n : names) { + if (m_builtin_decls.contains(n.m_name)) { + builtin_decl & d = m_builtin_decls.find(n.m_name); + builtin_decl * new_d = alloc(builtin_decl, fid, n.m_kind, d.m_next); d.m_next = new_d; m_extra_builtin_decls.push_back(new_d); } else { - m_builtin_decls.insert((*it).m_name, builtin_decl(fid, (*it).m_kind)); + m_builtin_decls.insert(n.m_name, builtin_decl(fid, n.m_kind)); } } } @@ -686,8 +674,6 @@ bool cmd_context::logic_has_datatype() const { void cmd_context::init_manager_core(bool new_manager) { SASSERT(m_manager != 0); SASSERT(m_pmanager != 0); - m_dt_eh = alloc(dt_eh, *this); - m_pmanager->set_new_datatype_eh(m_dt_eh.get()); if (new_manager) { decl_plugin * basic = m_manager->get_plugin(m_manager->get_basic_family_id()); register_builtin_sorts(basic); @@ -715,16 +701,16 @@ void cmd_context::init_manager_core(bool new_manager) { load_plugin(symbol("seq"), logic_has_seq(), fids); load_plugin(symbol("fpa"), logic_has_fpa(), fids); load_plugin(symbol("pb"), logic_has_pb(), fids); - svector::iterator it = fids.begin(); - svector::iterator end = fids.end(); - for (; it != end; ++it) { - decl_plugin * p = m_manager->get_plugin(*it); + for (family_id fid : fids) { + decl_plugin * p = m_manager->get_plugin(fid); if (p) { register_builtin_sorts(p); register_builtin_ops(p); } } } + m_dt_eh = alloc(dt_eh, *this); + m_pmanager->set_new_datatype_eh(m_dt_eh.get()); if (!has_logic()) { // add list type only if the logic is not specified. // it prevents clashes with builtin types. @@ -1170,11 +1156,8 @@ void cmd_context::erase_object_ref(symbol const & s) { } void cmd_context::reset_func_decls() { - dictionary::iterator it = m_func_decls.begin(); - dictionary::iterator end = m_func_decls.end(); - for (; it != end; ++it) { - func_decls fs = (*it).m_value; - fs.finalize(m()); + for (auto & kv : m_func_decls) { + kv.m_value.finalize(m()); } m_func_decls.reset(); m_func_decls_stack.reset(); @@ -1182,10 +1165,8 @@ void cmd_context::reset_func_decls() { } void cmd_context::reset_psort_decls() { - dictionary::iterator it = m_psort_decls.begin(); - dictionary::iterator end = m_psort_decls.end(); - for (; it != end; ++it) { - psort_decl * p = (*it).m_value; + for (auto & kv : m_psort_decls) { + psort_decl * p = kv.m_value; pm().dec_ref(p); } m_psort_decls.reset(); @@ -1201,19 +1182,14 @@ void cmd_context::reset_macros() { } void cmd_context::reset_cmds() { - dictionary::iterator it = m_cmds.begin(); - dictionary::iterator end = m_cmds.end(); - for (; it != end; ++it) { - cmd * c = (*it).m_value; - c->reset(*this); + for (auto& kv : m_cmds) { + kv.m_value->reset(*this); } } void cmd_context::finalize_cmds() { - dictionary::iterator it = m_cmds.begin(); - dictionary::iterator end = m_cmds.end(); - for (; it != end; ++it) { - cmd * c = (*it).m_value; + for (auto& kv : m_cmds) { + cmd * c = kv.m_value; c->finalize(*this); dealloc(c); } @@ -1226,10 +1202,8 @@ void cmd_context::reset_user_tactics() { } void cmd_context::reset_object_refs() { - dictionary::iterator it = m_object_refs.begin(); - dictionary::iterator end = m_object_refs.end(); - for (; it != end; ++it) { - object_ref * r = (*it).m_value; + for (auto& kv : m_object_refs) { + object_ref * r = kv.m_value; r->dec_ref(*this); } m_object_refs.reset(); @@ -1564,10 +1538,8 @@ void cmd_context::reset_assertions() { mk_solver(); } restore_assertions(0); - svector::iterator it = m_scopes.begin(); - svector::iterator end = m_scopes.end(); - for (; it != end; ++it) { - it->m_assertions_lim = 0; + for (scope& s : m_scopes) { + s.m_assertions_lim = 0; if (m_solver) m_solver->push(); } } @@ -1799,10 +1771,7 @@ void cmd_context::set_solver_factory(solver_factory * f) { mk_solver(); // assert formulas and create scopes in the new solver. unsigned lim = 0; - svector::iterator it = m_scopes.begin(); - svector::iterator end = m_scopes.end(); - for (; it != end; ++it) { - scope & s = *it; + for (scope& s : m_scopes) { for (unsigned i = lim; i < s.m_assertions_lim; i++) { m_solver->assert_expr(m_assertions[i]); } @@ -1839,11 +1808,9 @@ void cmd_context::display_statistics(bool show_total_time, double total_time) { void cmd_context::display_assertions() { if (!m_interactive_mode) throw cmd_exception("command is only available in interactive mode, use command (set-option :interactive-mode true)"); - std::vector::const_iterator it = m_assertion_strings.begin(); - std::vector::const_iterator end = m_assertion_strings.end(); regular_stream() << "("; - for (bool first = true; it != end; ++it) { - std::string const & s = *it; + bool first = true; + for (std::string const& s : m_assertion_strings) { if (first) first = false; else @@ -1919,10 +1886,8 @@ void cmd_context::display(std::ostream & out, func_decl * d, unsigned indent) co } void cmd_context::dump_assertions(std::ostream & out) const { - ptr_vector::const_iterator it = m_assertions.begin(); - ptr_vector::const_iterator end = m_assertions.end(); - for (; it != end; ++it) { - display(out, *it); + for (expr * e : m_assertions) { + display(out, e); out << std::endl; } } @@ -1981,21 +1946,15 @@ cmd_context::dt_eh::~dt_eh() { void cmd_context::dt_eh::operator()(sort * dt, pdecl* pd) { TRACE("new_dt_eh", tout << "new datatype: "; m_owner.pm().display(tout, dt); tout << "\n";); - ptr_vector const * constructors = m_dt_util.get_datatype_constructors(dt); - unsigned num_constructors = constructors->size(); - for (unsigned j = 0; j < num_constructors; j++) { - func_decl * c = constructors->get(j); - m_owner.insert(c); + for (func_decl * c : *m_dt_util.get_datatype_constructors(dt)) { TRACE("new_dt_eh", tout << "new constructor: " << c->get_name() << "\n";); + m_owner.insert(c); func_decl * r = m_dt_util.get_constructor_recognizer(c); m_owner.insert(r); TRACE("new_dt_eh", tout << "new recognizer: " << r->get_name() << "\n";); - ptr_vector const * accessors = m_dt_util.get_constructor_accessors(c); - unsigned num_accessors = accessors->size(); - for (unsigned k = 0; k < num_accessors; k++) { - func_decl * a = accessors->get(k); - m_owner.insert(a); + for (func_decl * a : *m_dt_util.get_constructor_accessors(c)) { TRACE("new_dt_eh", tout << "new accessor: " << a->get_name() << "\n";); + m_owner.insert(a); } } if (m_owner.m_scopes.size() > 0) { diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index f255c8353..7eac1f347 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -39,15 +39,13 @@ public: } else { SASSERT(m_const == 0); - obj_map::iterator it = m_map.begin(); - obj_map::iterator end = m_map.end(); - for (; it != end; ++it) { - m.m().dec_ref((*it).m_key); + for (auto kv : m_map) { + m.m().dec_ref(kv.m_key); if (m_num_params == 1) { - m.m().dec_ref(static_cast((*it).m_value)); + m.m().dec_ref(static_cast(kv.m_value)); } else { - psort_inst_cache * child = static_cast((*it).m_value); + psort_inst_cache * child = static_cast(kv.m_value); child->finalize(m); child->~psort_inst_cache(); m.a().deallocate(sizeof(psort_inst_cache), child); @@ -172,9 +170,10 @@ public: virtual char const * hcons_kind() const { return "psort_var"; } virtual unsigned hcons_hash() const { return hash_u_u(m_num_params, m_idx); } virtual bool hcons_eq(psort const * other) const { - if (other->hcons_kind() != hcons_kind()) - return false; - return get_num_params() == other->get_num_params() && m_idx == static_cast(other)->m_idx; + return + other->hcons_kind() == hcons_kind() && + get_num_params() == other->get_num_params() && + m_idx == static_cast(other)->m_idx; } virtual void display(std::ostream & out) const { out << "s_" << m_idx; @@ -268,8 +267,8 @@ public: psort_decl::psort_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n): pdecl(id, num_params), - m_psort_kind(PSORT_BASE), m_name(n), + m_psort_kind(PSORT_BASE), m_inst_cache(0) { } @@ -294,27 +293,6 @@ sort * psort_decl::find(sort * const * s) { return m_inst_cache->find(s); } -#if 0 -psort_dt_decl::psort_dt_decl(unsigned id, unsigned num_params, pdecl_manager& m, symbol const& n): - psort_decl(id, num_params, m, n) { -} - -void psort_dt_decl::finalize(pdecl_manager& m) { - psort_decl::finalize(m); -} - - -sort * psort_dt_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { - UNREACHABLE(); - return 0; -} - -void psort_dt_decl::display(std::ostream & out) const { - out << get_name() << " " << get_num_params(); -} -#endif - - psort_user_decl::psort_user_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n, psort * p) : psort_decl(id, num_params, m, n), m_def(p) { @@ -367,6 +345,27 @@ void psort_user_decl::display(std::ostream & out) const { out << ")"; } +// ------------------- +// psort_dt_decl + +psort_dt_decl::psort_dt_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n) : + psort_decl(id, num_params, m, n) { + m_psort_kind = PSORT_DT; +} + + +sort * psort_dt_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { + SASSERT(n == m_num_params); + return m.instantiate_datatype(this, m_name, n, s); +} + +void psort_dt_decl::display(std::ostream & out) const { + out << "(datatype-sort " << m_name << ")"; +} + +// ------------------- +// psort_builtin_decl + psort_builtin_decl::psort_builtin_decl(unsigned id, pdecl_manager & m, symbol const & n, family_id fid, decl_kind k): psort_decl(id, PSORT_DECL_VAR_PARAMS, m, n), m_fid(fid), @@ -458,8 +457,8 @@ bool paccessor_decl::fix_missing_refs(dictionary const & symbol2idx, symbol accessor_decl * paccessor_decl::instantiate_decl(pdecl_manager & m, sort * const * s) { switch (m_type.kind()) { - case PTR_REC_REF: return mk_accessor_decl(m_name, type_ref(m_type.get_idx())); - case PTR_PSORT: return mk_accessor_decl(m_name, type_ref(m_type.get_psort()->instantiate(m, s))); + case PTR_REC_REF: return mk_accessor_decl(m.m(), m_name, type_ref(m_type.get_idx())); + case PTR_PSORT: return mk_accessor_decl(m.m(), m_name, type_ref(m_type.get_psort()->instantiate(m, s))); default: // missing refs must have been eliminated. UNREACHABLE(); @@ -488,20 +487,16 @@ void pconstructor_decl::finalize(pdecl_manager & m) { } bool pconstructor_decl::has_missing_refs(symbol & missing) const { - ptr_vector::const_iterator it = m_accessors.begin(); - ptr_vector::const_iterator end = m_accessors.end(); - for (; it != end; ++it) { - if ((*it)->has_missing_refs(missing)) + for (paccessor_decl* a : m_accessors) { + if (a->has_missing_refs(missing)) return true; } return false; } bool pconstructor_decl::fix_missing_refs(dictionary const & symbol2idx, symbol & missing) { - ptr_vector::iterator it = m_accessors.begin(); - ptr_vector::iterator end = m_accessors.end(); - for (; it != end; ++it) { - if (!(*it)->fix_missing_refs(symbol2idx, missing)) + for (paccessor_decl* a : m_accessors) { + if (!a->fix_missing_refs(symbol2idx, missing)) return false; } return true; @@ -509,20 +504,16 @@ bool pconstructor_decl::fix_missing_refs(dictionary const & symbol2idx, sym constructor_decl * pconstructor_decl::instantiate_decl(pdecl_manager & m, sort * const * s) { ptr_buffer as; - ptr_vector::iterator it = m_accessors.begin(); - ptr_vector::iterator end = m_accessors.end(); - for (; it != end; ++it) - as.push_back((*it)->instantiate_decl(m, s)); + for (paccessor_decl* a : m_accessors) + as.push_back(a->instantiate_decl(m, s)); return mk_constructor_decl(m_name, m_recogniser_name, as.size(), as.c_ptr()); } void pconstructor_decl::display(std::ostream & out, pdatatype_decl const * const * dts) const { out << "(" << m_name; - ptr_vector::const_iterator it = m_accessors.begin(); - ptr_vector::const_iterator end = m_accessors.end(); - for (; it != end; ++it) { + for (paccessor_decl* a : m_accessors) { out << " "; - (*it)->display(out, dts); + a->display(out, dts); } out << ")"; } @@ -541,23 +532,17 @@ void pdatatype_decl::finalize(pdecl_manager & m) { } bool pdatatype_decl::has_missing_refs(symbol & missing) const { - ptr_vector::const_iterator it = m_constructors.begin(); - ptr_vector::const_iterator end = m_constructors.end(); - for (; it != end; ++it) { - if ((*it)->has_missing_refs(missing)) + for (auto c : m_constructors) + if (c->has_missing_refs(missing)) return true; - } return false; } bool pdatatype_decl::has_duplicate_accessors(symbol & duplicated) const { hashtable names; - ptr_vector::const_iterator it = m_constructors.begin(); - ptr_vector::const_iterator end = m_constructors.end(); - for (; it != end; ++it) { - ptr_vector const& acc = (*it)->m_accessors; - for (unsigned i = 0; i < acc.size(); ++i) { - symbol const& name = acc[i]->get_name(); + for (auto c : m_constructors) { + for (auto a : c->m_accessors) { + symbol const& name = a->get_name(); if (names.contains(name)) { duplicated = name; return true; @@ -570,10 +555,8 @@ bool pdatatype_decl::has_duplicate_accessors(symbol & duplicated) const { bool pdatatype_decl::fix_missing_refs(dictionary const & symbol2idx, symbol & missing) { - ptr_vector::iterator it = m_constructors.begin(); - ptr_vector::iterator end = m_constructors.end(); - for (; it != end; ++it) { - if (!(*it)->fix_missing_refs(symbol2idx, missing)) + for (auto c : m_constructors) { + if (!c->fix_missing_refs(symbol2idx, missing)) return false; } return true; @@ -581,12 +564,11 @@ bool pdatatype_decl::fix_missing_refs(dictionary const & symbol2idx, symbol datatype_decl * pdatatype_decl::instantiate_decl(pdecl_manager & m, sort * const * s) { ptr_buffer cs; - ptr_vector::iterator it = m_constructors.begin(); - ptr_vector::iterator end = m_constructors.end(); - for (; it != end; ++it) { - cs.push_back((*it)->instantiate_decl(m, s)); + for (auto c : m_constructors) { + cs.push_back(c->instantiate_decl(m, s)); } - return mk_datatype_decl(m_name, cs.size(), cs.c_ptr()); + datatype_util util(m.m()); + return mk_datatype_decl(util, m_name, m_num_params, s, cs.size(), cs.c_ptr()); } struct datatype_decl_buffer { @@ -594,67 +576,86 @@ struct datatype_decl_buffer { ~datatype_decl_buffer() { del_datatype_decls(m_buffer.size(), m_buffer.c_ptr()); } }; + sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { - SASSERT(m_num_params == n); - sort * r = find(s); - if (r) - return r; - if (m_parent != 0) { - if (m_parent->instantiate(m, s)) { - r = find(s); - SASSERT(r); - return r; + sort * r = m.instantiate_datatype(this, m_name, n, s); + datatype_util util(m.m()); + if (r && n > 0 && util.is_declared(r)) { + ast_mark mark; + datatype::def const& d = util.get_def(r); + mark.mark(r, true); + sort_ref_vector params(m.m(), n, s); + for (datatype::constructor* c : d) { + for (datatype::accessor* a : *c) { + sort* rng = a->range(); + if (util.is_datatype(rng) && !mark.is_marked(rng) && m_parent) { + mark.mark(rng, true); + // TBD: search over more than just parents + for (pdatatype_decl* p : *m_parent) { + if (p->get_name() == rng->get_name()) { + ptr_vector ps; + func_decl_ref acc = a->instantiate(params); + for (unsigned j = 0; j < util.get_datatype_num_parameter_sorts(rng); ++j) { + ps.push_back(util.get_datatype_parameter_sort(acc->get_range(), j)); + } + m.instantiate_datatype(p, p->get_name(), ps.size(), ps.c_ptr()); + break; + } + } + } + } } } - else { - datatype_decl_buffer dts; - dts.m_buffer.push_back(instantiate_decl(m, s)); - datatype_decl * d_ptr = dts.m_buffer[0]; - sort_ref_vector sorts(m.m()); - bool is_ok = m.get_dt_plugin()->mk_datatypes(1, &d_ptr, m_num_params, s, sorts); - TRACE("pdatatype_decl", tout << "instantiating " << m_name << " is_ok: " << is_ok << "\n";); - if (is_ok) { - r = sorts.get(0); - cache(m, s, r); - m.save_info(r, this, n, s); - m.notify_new_dt(r, this); - return r; - } - } - return 0; + return r; } + void pdatatype_decl::display(std::ostream & out) const { out << "(declare-datatype " << m_name; display_sort_args(out, m_num_params); - ptr_vector::const_iterator it = m_constructors.begin(); - ptr_vector::const_iterator end = m_constructors.end(); - for (bool first = true; it != end; ++it) { + bool first = true; + for (auto c : m_constructors) { if (!first) out << " "; if (m_parent) { - (*it)->display(out, m_parent->children()); + c->display(out, m_parent->children()); } else { pdatatype_decl const * dts[1] = { this }; - (*it)->display(out, dts); + c->display(out, dts); } first = false; } out << ")"; } +bool pdatatype_decl::commit(pdecl_manager& m) { + TRACE("datatype", tout << m_name << "\n";); + sort_ref_vector ps(m.m()); + for (unsigned i = 0; i < m_num_params; ++i) { + ps.push_back(m.m().mk_uninterpreted_sort(symbol(i), 0, 0)); + } + datatype_decl_buffer dts; + dts.m_buffer.push_back(instantiate_decl(m, ps.c_ptr())); + datatype_decl * d_ptr = dts.m_buffer[0]; + sort_ref_vector sorts(m.m()); + bool is_ok = m.get_dt_plugin()->mk_datatypes(1, &d_ptr, m_num_params, ps.c_ptr(), sorts); + if (is_ok && m_num_params == 0) { + m.notify_new_dt(sorts.get(0), this); + } + return is_ok; +} + + pdatatypes_decl::pdatatypes_decl(unsigned id, unsigned num_params, pdecl_manager & m, unsigned num_datatypes, pdatatype_decl * const * dts): pdecl(id, num_params), m_datatypes(num_datatypes, dts) { m.inc_ref(num_datatypes, dts); - ptr_vector::iterator it = m_datatypes.begin(); - ptr_vector::iterator end = m_datatypes.end(); - for (; it != end; ++it) { - SASSERT((*it)->m_parent == 0); - (*it)->m_parent = this; + for (auto d : m_datatypes) { + SASSERT(d->m_parent == 0); + d->m_parent = this; } } @@ -665,38 +666,67 @@ void pdatatypes_decl::finalize(pdecl_manager & m) { bool pdatatypes_decl::fix_missing_refs(symbol & missing) { TRACE("fix_missing_refs", tout << "pdatatypes_decl::fix_missing_refs\n";); dictionary symbol2idx; - ptr_vector::iterator it = m_datatypes.begin(); - ptr_vector::iterator end = m_datatypes.end(); - for (unsigned idx = 0; it != end; ++it, ++idx) - symbol2idx.insert((*it)->get_name(), idx); - - it = m_datatypes.begin(); - for (unsigned idx = 0; it != end; ++it, ++idx) { - if (!(*it)->fix_missing_refs(symbol2idx, missing)) + int idx = 0; + for (pdatatype_decl* d : m_datatypes) + symbol2idx.insert(d->get_name(), idx++); + for (pdatatype_decl* d : m_datatypes) + if (!d->fix_missing_refs(symbol2idx, missing)) return false; - } return true; } +sort* pdecl_manager::instantiate_datatype(psort_decl* p, symbol const& name, unsigned n, sort * const* s) { + TRACE("datatype", tout << name << " "; for (unsigned i = 0; i < n; ++i) tout << s[i]->get_name() << " "; tout << "\n";); + pdecl_manager& m = *this; + sort * r = p->find(s); + if (r) + return r; + buffer ps; + ps.push_back(parameter(name)); + for (unsigned i = 0; i < n; i++) + ps.push_back(parameter(s[i])); + datatype_util util(m.m()); + r = m.m().mk_sort(util.get_family_id(), DATATYPE_SORT, ps.size(), ps.c_ptr()); + p->cache(m, s, r); + m.save_info(r, p, n, s); + if (n > 0 && util.is_declared(r)) { + bool has_typevar = false; + // crude check .. + for (unsigned i = 0; !has_typevar && i < n; ++i) { + has_typevar = s[i]->get_name().is_numerical(); + } + if (!has_typevar) { + m.notify_new_dt(r, p); + } + } + return r; +} + bool pdatatypes_decl::instantiate(pdecl_manager & m, sort * const * s) { + UNREACHABLE(); + return false; +} + +bool pdatatypes_decl::commit(pdecl_manager& m) { datatype_decl_buffer dts; - ptr_vector::iterator it = m_datatypes.begin(); - ptr_vector::iterator end = m_datatypes.end(); - for (; it != end; ++it) { - dts.m_buffer.push_back((*it)->instantiate_decl(m, s)); + for (pdatatype_decl* d : m_datatypes) { + sort_ref_vector ps(m.m()); + for (unsigned i = 0; i < d->get_num_params(); ++i) { + ps.push_back(m.m().mk_uninterpreted_sort(symbol(i), 0, 0)); + } + dts.m_buffer.push_back(d->instantiate_decl(m, ps.c_ptr())); } sort_ref_vector sorts(m.m()); - bool is_ok = m.get_dt_plugin()->mk_datatypes(dts.m_buffer.size(), dts.m_buffer.c_ptr(), m_num_params, s, sorts); - if (!is_ok) - return false; - it = m_datatypes.begin(); - for (unsigned i = 0; it != end; ++it, ++i) { - sort * new_dt = sorts.get(i); - (*it)->cache(m, s, new_dt); - m.save_info(new_dt, *it, m_num_params, s); - m.notify_new_dt(new_dt, *it); + bool is_ok = m.get_dt_plugin()->mk_datatypes(m_datatypes.size(), dts.m_buffer.c_ptr(), 0, nullptr, sorts); + if (is_ok) { + for (unsigned i = 0; i < m_datatypes.size(); ++i) { + pdatatype_decl* d = m_datatypes[i]; + if (d->get_num_params() == 0) { + m.notify_new_dt(sorts.get(i), this); + } + } } - return true; + return is_ok; } struct pdecl_manager::sort_info { @@ -708,9 +738,7 @@ struct pdecl_manager::sort_info { } virtual ~sort_info() {} virtual unsigned obj_size() const { return sizeof(sort_info); } - virtual void finalize(pdecl_manager & m) { - m.dec_ref(m_decl); - } + virtual void finalize(pdecl_manager & m) { m.dec_ref(m_decl); } virtual void display(std::ostream & out, pdecl_manager const & m) const = 0; virtual format * pp(pdecl_manager const & m) const = 0; }; @@ -810,6 +838,7 @@ void pdecl_manager::init_list() { mk_pconstructor_decl(1, symbol("insert"), symbol("is-insert"), 2, as) }; m_list = mk_pdatatype_decl(1, symbol("List"), 2, cs); inc_ref(m_list); + m_list->commit(*this); } pdecl_manager::pdecl_manager(ast_manager & m): @@ -841,9 +870,8 @@ psort * pdecl_manager::register_psort(psort * n) { psort * r = m_table.insert_if_not_there(n); if (r != n) { del_decl_core(n); - return r; } - return n; + return r; } psort * pdecl_manager::mk_psort_var(unsigned num_params, unsigned vidx) { @@ -862,6 +890,7 @@ pconstructor_decl * pdecl_manager::mk_pconstructor_decl(unsigned num_params, } pdatatype_decl * pdecl_manager::mk_pdatatype_decl(unsigned num_params, symbol const & s, unsigned num, pconstructor_decl * const * cs) { + TRACE("datatype", tout << s << " has " << num_params << " parameters\n";); return new (a().allocate(sizeof(pdatatype_decl))) pdatatype_decl(m_id_gen.mk(), num_params, *this, s, num, cs); } @@ -888,10 +917,10 @@ psort_decl * pdecl_manager::mk_psort_user_decl(unsigned num_params, symbol const return new (a().allocate(sizeof(psort_user_decl))) psort_user_decl(m_id_gen.mk(), num_params, *this, n, def); } +psort_decl * pdecl_manager::mk_psort_dt_decl(unsigned num_params, symbol const & n) { + return new (a().allocate(sizeof(psort_dt_decl))) psort_dt_decl(m_id_gen.mk(), num_params, *this, n); +} -//psort_decl * pdecl_manager::mk_psort_dt_decl(unsigned num_params, symbol const & n) { -// return new (a().allocate(sizeof(psort_dt_decl))) psort_dt_decl(m_id_gen.mk(), num_params, *this, n); -//} psort_decl * pdecl_manager::mk_psort_builtin_decl(symbol const & n, family_id fid, decl_kind k) { return new (a().allocate(sizeof(psort_builtin_decl))) psort_builtin_decl(m_id_gen.mk(), *this, n, fid, k); @@ -968,11 +997,9 @@ void pdecl_manager::save_info(sort * s, psort_decl * d, unsigned num_indices, un } void pdecl_manager::reset_sort_info() { - obj_map::iterator it = m_sort2info.begin(); - obj_map::iterator end = m_sort2info.end(); - for (; it != end; ++it) { - sort * s = (*it).m_key; - sort_info * info = (*it).m_value; + for (auto kv : m_sort2info) { + sort * s = kv.m_key; + sort_info * info = kv.m_value; m().dec_ref(s); unsigned sz = info->obj_size(); info->finalize(*this); diff --git a/src/cmd_context/pdecl.h b/src/cmd_context/pdecl.h index a32a42413..c72020827 100644 --- a/src/cmd_context/pdecl.h +++ b/src/cmd_context/pdecl.h @@ -23,6 +23,7 @@ Revision History: #include "util/obj_hashtable.h" #include "util/dictionary.h" #include "ast/format.h" +#include "ast/datatype_decl_plugin.h" class pdecl_manager; @@ -86,7 +87,7 @@ typedef ptr_hashtable psort_table; #define PSORT_DECL_VAR_PARAMS UINT_MAX -typedef enum { PSORT_BASE = 0, PSORT_USER, PSORT_BUILTIN } psort_decl_kind; +typedef enum { PSORT_BASE = 0, PSORT_USER, PSORT_BUILTIN, PSORT_DT } psort_decl_kind; class psort_decl : public pdecl { protected: @@ -110,6 +111,7 @@ public: virtual void reset_cache(pdecl_manager& m); bool is_user_decl() const { return m_psort_kind == PSORT_USER; } bool is_builtin_decl() const { return m_psort_kind == PSORT_BUILTIN; } + bool is_dt_decl() const { return m_psort_kind == PSORT_DT; } }; class psort_user_decl : public psort_decl { @@ -124,7 +126,7 @@ public: virtual sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s); virtual void display(std::ostream & out) const; }; - + class psort_builtin_decl : public psort_decl { protected: friend class pdecl_manager; @@ -139,24 +141,17 @@ public: virtual void display(std::ostream & out) const; }; -#if 0 class psort_dt_decl : public psort_decl { protected: friend class pdecl_manager; psort_dt_decl(unsigned id, unsigned num_params, pdecl_manager & m, symbol const & n); virtual size_t obj_size() const { return sizeof(psort_dt_decl); } - virtual void finalize(pdecl_manager & m); virtual ~psort_dt_decl() {} public: virtual sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s); virtual void display(std::ostream & out) const; }; -#endif -class datatype_decl_plugin; -class datatype_decl; -class constructor_decl; -class accessor_decl; class pdatatypes_decl; class pdatatype_decl; @@ -246,6 +241,7 @@ public: virtual void display(std::ostream & out) const; bool has_missing_refs(symbol & missing) const; bool has_duplicate_accessors(symbol & repeated) const; + bool commit(pdecl_manager& m); }; /** @@ -263,6 +259,10 @@ class pdatatypes_decl : public pdecl { virtual ~pdatatypes_decl() {} public: pdatatype_decl const * const * children() const { return m_datatypes.c_ptr(); } + pdatatype_decl * const * begin() const { return m_datatypes.begin(); } + pdatatype_decl * const * end() const { return m_datatypes.end(); } + // commit declaration + bool commit(pdecl_manager& m); }; class new_datatype_eh { @@ -305,7 +305,7 @@ public: psort * mk_psort_var(unsigned num_params, unsigned vidx); psort * mk_psort_app(unsigned num_params, psort_decl * d, unsigned num_args, psort * const * args); psort * mk_psort_app(psort_decl * d); - // psort_decl * mk_psort_dt_decl(unsigned num_params, symbol const & n); + psort_decl * mk_psort_dt_decl(unsigned num_params, symbol const & n); psort_decl * mk_psort_user_decl(unsigned num_params, symbol const & n, psort * def); psort_decl * mk_psort_builtin_decl(symbol const & n, family_id fid, decl_kind k); paccessor_decl * mk_paccessor_decl(unsigned num_params, symbol const & s, ptype const & p); @@ -314,6 +314,7 @@ public: pdatatypes_decl * mk_pdatatypes_decl(unsigned num_params, unsigned num, pdatatype_decl * const * dts); pdatatype_decl * mk_plist_decl() { if (!m_list) init_list(); return m_list; } bool fix_missing_refs(pdatatypes_decl * s, symbol & missing) { return s->fix_missing_refs(missing); } + sort * instantiate_datatype(psort_decl* p, symbol const& name, unsigned n, sort * const* s); sort * instantiate(psort * s, unsigned num, sort * const * args); void lazy_dec_ref(pdecl * p) { p->dec_ref(); if (p->get_ref_count() == 0) m_to_delete.push_back(p); } diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index 14c715eca..cbc90c62c 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -258,11 +258,9 @@ public: result->m_core.append(core_elems.size(), core_elems.c_ptr()); if (p.get_bool("print_unsat_core", false)) { ctx.regular_stream() << "(unsat-core"; - ptr_vector::const_iterator it = core_elems.begin(); - ptr_vector::const_iterator end = core_elems.end(); - for (; it != end; ++it) { + for (expr * e : core_elems) { ctx.regular_stream() << " "; - ctx.display(ctx.regular_stream(), *it); + ctx.display(ctx.regular_stream(), e); } ctx.regular_stream() << ")" << std::endl; } diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp index 5eb1eb00d..2fd2d8746 100644 --- a/src/model/model_core.cpp +++ b/src/model/model_core.cpp @@ -19,18 +19,14 @@ Revision History: #include "model/model_core.h" model_core::~model_core() { - decl2expr::iterator it1 = m_interp.begin(); - decl2expr::iterator end1 = m_interp.end(); - for (; it1 != end1; ++it1) { - m_manager.dec_ref(it1->m_key); - m_manager.dec_ref(it1->m_value); + for (auto & kv : m_interp) { + m_manager.dec_ref(kv.m_key); + m_manager.dec_ref(kv.m_value); } - decl2finterp::iterator it2 = m_finterp.begin(); - decl2finterp::iterator end2 = m_finterp.end(); - for (; it2 != end2; ++it2) { - m_manager.dec_ref(it2->m_key); - dealloc(it2->m_value); + for (auto & kv : m_finterp) { + m_manager.dec_ref(kv.m_key); + dealloc(kv.m_value); } } diff --git a/src/muz/base/dl_rule.cpp b/src/muz/base/dl_rule.cpp index 26a5b748e..367795c9b 100644 --- a/src/muz/base/dl_rule.cpp +++ b/src/muz/base/dl_rule.cpp @@ -44,6 +44,7 @@ Revision History: #include "tactic/filter_model_converter.h" #include "ast/scoped_proof.h" #include "ast/datatype_decl_plugin.h" +#include "ast/ast_util.h" namespace datalog { @@ -757,7 +758,7 @@ namespace datalog { ); proof_ref pr(m); - qe::expr_quant_elim_star1 simpl(m, m_ctx.get_fparams()); + qe::simplify_rewriter_star simpl(m); simpl(quant_tail, fixed_tail, pr); } else { diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 0f7914e0c..3368c7640 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -970,7 +970,7 @@ namespace datalog { _name << pred->get_name() << "_" << q->get_name() << j; symbol name(_name.str().c_str()); type_ref tr(idx); - accs.push_back(mk_accessor_decl(name, tr)); + accs.push_back(mk_accessor_decl(m, name, tr)); } std::stringstream _name; _name << pred->get_name() << "_" << i; @@ -979,7 +979,7 @@ namespace datalog { symbol is_name(_name.str().c_str()); cnstrs.push_back(mk_constructor_decl(name, is_name, accs.size(), accs.c_ptr())); } - dts.push_back(mk_datatype_decl(pred->get_name(), cnstrs.size(), cnstrs.c_ptr())); + dts.push_back(mk_datatype_decl(dtu, pred->get_name(), 0, nullptr, cnstrs.size(), cnstrs.c_ptr())); } @@ -1024,10 +1024,10 @@ namespace datalog { _name2 << "get_succ#" << i; ptr_vector accs; type_ref tr(0); - accs.push_back(mk_accessor_decl(name, tr)); + accs.push_back(mk_accessor_decl(m, name, tr)); cnstrs.push_back(mk_constructor_decl(name, is_name, accs.size(), accs.c_ptr())); } - dts.push_back(mk_datatype_decl(symbol("Path"), cnstrs.size(), cnstrs.c_ptr())); + dts.push_back(mk_datatype_decl(dtu, symbol("Path"), 0, nullptr, cnstrs.size(), cnstrs.c_ptr())); VERIFY (dtp->mk_datatypes(dts.size(), dts.c_ptr(), 0, 0, new_sorts)); m_path_sort = new_sorts[0].get(); } @@ -1139,7 +1139,7 @@ namespace datalog { md->eval(path, path); IF_VERBOSE(2, verbose_stream() << mk_pp(trace, m) << "\n"; for (unsigned i = 0; i < b.m_solver.size(); ++i) { - verbose_stream() << mk_pp(b.m_solver.get_formulas()[i], m) << "\n"; + verbose_stream() << mk_pp(b.m_solver.get_formula(i), m) << "\n"; }); scoped_proof _sp(m); proof_ref pr(m); diff --git a/src/muz/pdr/pdr_context.cpp b/src/muz/pdr/pdr_context.cpp index 0190044b1..fd734ea66 100644 --- a/src/muz/pdr/pdr_context.cpp +++ b/src/muz/pdr/pdr_context.cpp @@ -1835,16 +1835,16 @@ namespace pdr { !m_params.pdr_use_convex_interior_generalizer()) { if (classify.is_dl()) { m_fparams.m_arith_mode = AS_DIFF_LOGIC; - m_fparams.m_arith_expand_eqs = true; + m_fparams.m_arith_eq2ineq = true; } else if (classify.is_utvpi()) { IF_VERBOSE(1, verbose_stream() << "UTVPI\n";); m_fparams.m_arith_mode = AS_UTVPI; - m_fparams.m_arith_expand_eqs = true; + m_fparams.m_arith_eq2ineq = true; } else { m_fparams.m_arith_mode = AS_ARITH; - m_fparams.m_arith_expand_eqs = false; + m_fparams.m_arith_eq2ineq = false; } } } diff --git a/src/muz/pdr/pdr_smt_context_manager.cpp b/src/muz/pdr/pdr_smt_context_manager.cpp index e912bd658..b87d1e451 100644 --- a/src/muz/pdr/pdr_smt_context_manager.cpp +++ b/src/muz/pdr/pdr_smt_context_manager.cpp @@ -83,7 +83,7 @@ namespace pdr { { ast_smt_pp pp(m); for (unsigned i = 0; i < m_context.size(); ++i) { - pp.add_assumption(m_context.get_formulas()[i]); + pp.add_assumption(m_context.get_formula(i)); } for (unsigned i = 0; i < assumptions.size(); ++i) { pp.add_assumption(assumptions[i].get()); diff --git a/src/muz/pdr/pdr_util.cpp b/src/muz/pdr/pdr_util.cpp index 42a57214a..19ffdeeec 100644 --- a/src/muz/pdr/pdr_util.cpp +++ b/src/muz/pdr/pdr_util.cpp @@ -22,29 +22,26 @@ Notes: --*/ #include -#include "ast/simplifier/arith_simplifier_plugin.h" +#include "util/util.h" +#include "util/ref_vector.h" #include "ast/array_decl_plugin.h" #include "ast/ast_pp.h" -#include "ast/simplifier/basic_simplifier_plugin.h" -#include "ast/simplifier/bv_simplifier_plugin.h" -#include "ast/rewriter/bool_rewriter.h" -#include "muz/base/dl_util.h" #include "ast/for_each_expr.h" -#include "smt/params/smt_params.h" -#include "model/model.h" -#include "util/ref_vector.h" -#include "ast/rewriter/rewriter.h" -#include "ast/rewriter/rewriter_def.h" -#include "util/util.h" -#include "muz/pdr/pdr_manager.h" -#include "muz/pdr/pdr_util.h" +#include "ast/scoped_proof.h" #include "ast/arith_decl_plugin.h" #include "ast/rewriter/expr_replacer.h" -#include "model/model_smt2_pp.h" +#include "ast/rewriter/bool_rewriter.h" #include "ast/rewriter/poly_rewriter.h" #include "ast/rewriter/poly_rewriter_def.h" #include "ast/rewriter/arith_rewriter.h" -#include "ast/scoped_proof.h" +#include "ast/rewriter/rewriter.h" +#include "ast/rewriter/rewriter_def.h" +#include "smt/params/smt_params.h" +#include "model/model.h" +#include "muz/base/dl_util.h" +#include "muz/pdr/pdr_manager.h" +#include "muz/pdr/pdr_util.h" +#include "model/model_smt2_pp.h" diff --git a/src/muz/pdr/pdr_util.h b/src/muz/pdr/pdr_util.h index fccb0c40f..51f6978ec 100644 --- a/src/muz/pdr/pdr_util.h +++ b/src/muz/pdr/pdr_util.h @@ -22,9 +22,9 @@ Revision History: #include "ast/ast.h" #include "ast/ast_pp.h" +#include "ast/ast_util.h" #include "util/obj_hashtable.h" #include "util/ref_vector.h" -#include "ast/simplifier/simplifier.h" #include "util/trace.h" #include "util/vector.h" #include "ast/arith_decl_plugin.h" diff --git a/src/muz/rel/dl_bound_relation.cpp b/src/muz/rel/dl_bound_relation.cpp index de6c76456..9dc0eb8d5 100644 --- a/src/muz/rel/dl_bound_relation.cpp +++ b/src/muz/rel/dl_bound_relation.cpp @@ -653,7 +653,7 @@ namespace datalog { void bound_relation::to_formula(expr_ref& fml) const { ast_manager& m = get_plugin().get_ast_manager(); arith_util& arith = get_plugin().m_arith; - basic_simplifier_plugin& bsimp = get_plugin().m_bsimp; + bool_rewriter& bsimp = get_plugin().m_bsimp; expr_ref_vector conjs(m); relation_signature const& sig = get_signature(); for (unsigned i = 0; i < sig.size(); ++i) { diff --git a/src/muz/rel/dl_bound_relation.h b/src/muz/rel/dl_bound_relation.h index 456df737b..3dec9d313 100644 --- a/src/muz/rel/dl_bound_relation.h +++ b/src/muz/rel/dl_bound_relation.h @@ -26,7 +26,7 @@ Revision History: #include "muz/rel/dl_vector_relation.h" #include "muz/rel/dl_interval_relation.h" #include "ast/arith_decl_plugin.h" -#include "ast/simplifier/basic_simplifier_plugin.h" +#include "ast/rewriter/bool_rewriter.h" namespace datalog { @@ -44,7 +44,7 @@ namespace datalog { class filter_interpreted_fn; class filter_intersection_fn; arith_util m_arith; - basic_simplifier_plugin m_bsimp; + bool_rewriter m_bsimp; public: bound_relation_plugin(relation_manager& m); virtual bool can_handle_signature(const relation_signature & s); diff --git a/src/muz/rel/dl_interval_relation.h b/src/muz/rel/dl_interval_relation.h index 05334624f..a9cce9802 100644 --- a/src/muz/rel/dl_interval_relation.h +++ b/src/muz/rel/dl_interval_relation.h @@ -20,13 +20,12 @@ Revision History: #define DL_INTERVAL_RELATION_H_ +#include "ast/arith_decl_plugin.h" +#include "smt/old_interval.h" #include "muz/base/dl_context.h" #include "muz/rel/dl_relation_manager.h" #include "muz/rel/dl_base.h" -#include "smt/old_interval.h" #include "muz/rel/dl_vector_relation.h" -#include "ast/arith_decl_plugin.h" -#include "ast/simplifier/basic_simplifier_plugin.h" namespace datalog { diff --git a/src/muz/spacer/spacer_legacy_mbp.cpp b/src/muz/spacer/spacer_legacy_mbp.cpp index fc2fd1fdd..9f03e6d2f 100644 --- a/src/muz/spacer/spacer_legacy_mbp.cpp +++ b/src/muz/spacer/spacer_legacy_mbp.cpp @@ -20,9 +20,6 @@ Notes: #include "ast/array_decl_plugin.h" #include "ast/ast_pp.h" -#include "ast/simplifier/arith_simplifier_plugin.h" -#include "ast/simplifier/basic_simplifier_plugin.h" -#include "ast/simplifier/bv_simplifier_plugin.h" #include "ast/rewriter/bool_rewriter.h" #include "muz/base/dl_util.h" #include "ast/for_each_expr.h" diff --git a/src/muz/spacer/spacer_legacy_mev.cpp b/src/muz/spacer/spacer_legacy_mev.cpp index 69f479836..16e2cc734 100644 --- a/src/muz/spacer/spacer_legacy_mev.cpp +++ b/src/muz/spacer/spacer_legacy_mev.cpp @@ -5,11 +5,8 @@ Copyright (c) 2017 Arie Gurfinkel */ #include -#include "ast/simplifier/arith_simplifier_plugin.h" #include "ast/array_decl_plugin.h" #include "ast/ast_pp.h" -#include "ast/simplifier/basic_simplifier_plugin.h" -#include "ast/simplifier/bv_simplifier_plugin.h" #include "ast/rewriter/bool_rewriter.h" #include "muz/base/dl_util.h" #include "ast/for_each_expr.h" diff --git a/src/muz/spacer/spacer_legacy_mev.h b/src/muz/spacer/spacer_legacy_mev.h index bebf1d0db..ff8f63d1f 100644 --- a/src/muz/spacer/spacer_legacy_mev.h +++ b/src/muz/spacer/spacer_legacy_mev.h @@ -10,7 +10,6 @@ Copyright (c) 2017 Arie Gurfinkel #include "ast/ast_pp.h" #include "util/obj_hashtable.h" #include "util/ref_vector.h" -#include "ast/simplifier/simplifier.h" #include "util/trace.h" #include "util/vector.h" #include "ast/arith_decl_plugin.h" diff --git a/src/muz/spacer/spacer_qe_project.cpp b/src/muz/spacer/spacer_qe_project.cpp index 0eec500e9..8dbf87ca5 100644 --- a/src/muz/spacer/spacer_qe_project.cpp +++ b/src/muz/spacer/spacer_qe_project.cpp @@ -25,6 +25,7 @@ Revision History: #include "ast/ast_pp.h" #include "ast/expr_functors.h" #include "ast/expr_substitution.h" +#include "ast/ast_util.h" #include "ast/rewriter/expr_replacer.h" #include "ast/rewriter/expr_safe_replace.h" diff --git a/src/muz/spacer/spacer_sym_mux.cpp b/src/muz/spacer/spacer_sym_mux.cpp index c311d9990..ee1d3726d 100644 --- a/src/muz/spacer/spacer_sym_mux.cpp +++ b/src/muz/spacer/spacer_sym_mux.cpp @@ -368,6 +368,7 @@ public: app * a = to_app(s); func_decl * sym = a->get_decl(); if (!m_parent.has_index(sym, m_from_idx)) { + (void) m_homogenous; SASSERT(!m_homogenous || !m_parent.is_muxed(sym)); return false; } diff --git a/src/muz/spacer/spacer_util.h b/src/muz/spacer/spacer_util.h index 5bbb84bfb..546b7df5b 100644 --- a/src/muz/spacer/spacer_util.h +++ b/src/muz/spacer/spacer_util.h @@ -26,12 +26,13 @@ Revision History: #include "ast/ast_pp.h" #include "util/obj_hashtable.h" #include "util/ref_vector.h" -#include "ast/simplifier/simplifier.h" #include "util/trace.h" #include "util/vector.h" #include "ast/arith_decl_plugin.h" #include "ast/array_decl_plugin.h" #include "ast/bv_decl_plugin.h" +#include "ast/ast_util.h" +#include "ast/expr_map.h" #include "model/model.h" #include "util/stopwatch.h" diff --git a/src/muz/spacer/spacer_virtual_solver.cpp b/src/muz/spacer/spacer_virtual_solver.cpp index c080fa2c4..ebaef14f0 100644 --- a/src/muz/spacer/spacer_virtual_solver.cpp +++ b/src/muz/spacer/spacer_virtual_solver.cpp @@ -318,7 +318,7 @@ lbool virtual_solver::check_sat_core(unsigned num_assumptions, stopwatch sw2; smt::kernel kernel(m, p); for (unsigned i = 0, sz = m_context.size(); i < sz; ++i) - { kernel.assert_expr(m_context.get_formulas()[i]); } + { kernel.assert_expr(m_context.get_formula(i)); } sw2.start(); kernel.check(num_assumptions, assumptions); sw2.stop(); @@ -450,7 +450,7 @@ void virtual_solver::to_smt2_benchmark(std::ostream &out, for (unsigned i = 0, sz = context.size(); i < sz; ++i) { - asserts.push_back(context.get_formulas()[i]); + asserts.push_back(context.get_formula(i)); pp.collect(asserts.back()); } pp.collect(num_assumptions, assumptions); diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index 7eb2284c0..8986bf506 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -26,6 +26,8 @@ Revision History: #include "muz/transforms/dl_mk_quantifier_instantiation.h" #include "muz/base/dl_context.h" #include "ast/pattern/pattern_inference.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/ast_util.h" namespace datalog { @@ -70,7 +72,7 @@ namespace datalog { if (q->get_num_patterns() == 0) { proof_ref new_pr(m); pattern_inference_params params; - pattern_inference infer(m, params); + pattern_inference_rw infer(m, params); infer(q, qe, new_pr); q = to_quantifier(qe); } diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index f453d9fe2..69b62083f 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -161,7 +161,7 @@ namespace opt { TRACE("opt_verbose", { tout << "context size: " << m_context.size() << "\n"; for (unsigned i = 0; i < m_context.size(); ++i) { - tout << mk_pp(m_context.get_formulas()[i], m_context.m()) << "\n"; + tout << mk_pp(m_context.get_formula(i), m_context.m()) << "\n"; } }); stopwatch w; @@ -330,7 +330,7 @@ namespace opt { expr * opt_solver::get_assertion(unsigned idx) const { SASSERT(idx < get_num_assertions()); - return m_context.get_formulas()[idx]; + return m_context.get_formula(idx); } smt::theory_var opt_solver::add_objective(app* term) { diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 3d895668b..681c3d597 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -16,8 +16,6 @@ Author: Revision History: --*/ -#include "parsers/smt2/smt2parser.h" -#include "parsers/smt2/smt2scanner.h" #include "util/stack.h" #include "ast/datatype_decl_plugin.h" #include "ast/bv_decl_plugin.h" @@ -25,10 +23,12 @@ Revision History: #include "ast/seq_decl_plugin.h" #include "ast/ast_pp.h" #include "ast/well_sorted.h" -#include "parsers/util/pattern_validation.h" #include "ast/rewriter/rewriter.h" #include "ast/has_free_vars.h" #include "ast/ast_smt2_pp.h" +#include "parsers/smt2/smt2parser.h" +#include "parsers/smt2/smt2scanner.h" +#include "parsers/util/pattern_validation.h" #include "parsers/util/parser_params.hpp" #include @@ -617,16 +617,8 @@ namespace smt2 { SASSERT(curr_is_identifier()); symbol id = curr_id(); psort_decl * d = m_ctx.find_psort_decl(id); - int idx = 0; if (d == 0) { - if (m_dt_name2idx.find(id, idx)) { - throw parser_exception("smtlib 2.6 parametric datatype sorts are not supported"); - // unsigned num_params = m_dt_name2arity.find(id); - // d = pm().mk_psort_dt_decl(num_params, id); - } - else { - unknown_sort(id); - } + unknown_sort(id); } next(); void * mem = m_stack.allocate(sizeof(psort_frame)); @@ -885,6 +877,7 @@ namespace smt2 { } else if (sz == 1) { check_missing(new_dt_decls[0], line, pos); + new_dt_decls[0]->commit(pm()); } else { SASSERT(sz > 1); @@ -897,22 +890,20 @@ namespace smt2 { err_msg += "'"; throw parser_exception(err_msg, line, pos); } + dts->commit(pm()); m_ctx.insert_aux_pdecl(dts.get()); } for (unsigned i = 0; i < sz; i++) { pdatatype_decl * d = new_dt_decls[i]; - SASSERT(d != 0); symbol duplicated; check_duplicate(d, line, pos); - m_ctx.insert(d); - if (d->get_num_params() == 0) { - // if datatype is not parametric... then force instantiation to register accessor, recognizers and constructors... - sort_ref s(m()); - s = d->instantiate(pm(), 0, 0); + if (!is_smt2_6) { + // datatypes are inserted up front in SMT2.6 mode, so no need to re-insert them. + m_ctx.insert(d); } - } + } TRACE("declare_datatypes", tout << "i: " << i << " new_dt_decls.size(): " << sz << "\n"; - for (unsigned i = 0; i < sz; i++) tout << new_dt_decls[i]->get_name() << "\n";); + for (unsigned j = 0; j < new_dt_decls.size(); ++j) tout << new_dt_decls[j]->get_name() << "\n";); m_ctx.print_success(); next(); } @@ -940,12 +931,7 @@ namespace smt2 { check_missing(d, line, pos); check_duplicate(d, line, pos); - m_ctx.insert(d); - if (d->get_num_params() == 0) { - // if datatype is not parametric... then force instantiation to register accessor, recognizers and constructors... - sort_ref s(m()); - s = d->instantiate(pm(), 0, 0); - } + d->commit(pm()); check_rparen_next("invalid end of datatype declaration, ')' expected"); m_ctx.print_success(); } @@ -1909,6 +1895,8 @@ namespace smt2 { m_dt_name2idx.insert(dt_name, i); m_dt_name2arity.insert(dt_name, u); m_dt_names.push_back(dt_name); + psort_decl * decl = pm().mk_psort_dt_decl(u, dt_name); + m_ctx.insert(decl); check_rparen("invalid sort declaration, ')' expected"); } else { diff --git a/src/qe/CMakeLists.txt b/src/qe/CMakeLists.txt index 2d2cf9579..2e6052382 100644 --- a/src/qe/CMakeLists.txt +++ b/src/qe/CMakeLists.txt @@ -18,7 +18,6 @@ z3_add_component(qe qe_sat_tactic.cpp qe_tactic.cpp qsat.cpp - vsubst_tactic.cpp COMPONENT_DEPENDENCIES nlsat_tactic nlsat @@ -31,5 +30,4 @@ z3_add_component(qe qe_sat_tactic.h qe_tactic.h qsat.h - vsubst_tactic.h ) diff --git a/src/qe/nlarith_util.cpp b/src/qe/nlarith_util.cpp index 1da5ef52a..4f07b59dd 100644 --- a/src/qe/nlarith_util.cpp +++ b/src/qe/nlarith_util.cpp @@ -11,7 +11,8 @@ Copyright (c) 2015 Microsoft Corporation #include "qe/qe.h" #include "ast/rewriter/expr_replacer.h" #include "ast/rewriter/arith_rewriter.h" -#include "ast/simplifier/arith_simplifier_plugin.h" +#include "ast/rewriter/bool_rewriter.h" +#include "ast/rewriter/th_rewriter.h" #include "ast/expr_functors.h" namespace nlarith { @@ -79,9 +80,8 @@ namespace nlarith { app_ref m_zero; app_ref m_one; smt_params m_params; - basic_simplifier_plugin m_bs; - arith_simplifier_plugin m_rw; - arith_rewriter m_rw1; + bool_rewriter m_bs; + arith_rewriter m_rw; expr_ref_vector m_trail; ast_manager& m() const { return m_manager; } @@ -105,8 +105,7 @@ namespace nlarith { m_enable_linear(false), m_zero(num(0),m), m_one(num(1),m), m_bs(m), - m_rw(m, m_bs, m_params), - m_rw1(m), m_trail(m) { + m_rw(m), m_trail(m) { } // diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index 3e5a9f24f..1f9c89f89 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -444,7 +444,7 @@ namespace qe { div_rewriter_cfg(nlqsat& s): m(s.m), a(s.m), m_zero(a.mk_real(0), m) {} ~div_rewriter_cfg() {} br_status reduce_app(func_decl* f, unsigned sz, expr* const* args, expr_ref& result, proof_ref& pr) { - rational r; + rational r(1); if (is_decl_of(f, a.get_family_id(), OP_DIV) && sz == 2 && (!a.is_numeral(args[1], r) || r.is_zero())) { result = m.mk_fresh_const("div", a.mk_real()); m_divs.push_back(div(m, args[0], args[1], to_app(result))); diff --git a/src/qe/qe.cpp b/src/qe/qe.cpp index 7c7250c40..dd54f4441 100644 --- a/src/qe/qe.cpp +++ b/src/qe/qe.cpp @@ -1310,6 +1310,10 @@ namespace qe { m_s.mk_atom(e, p, result); } + void i_solver_context::collect_statistics(statistics& st) const { + // tbd + } + typedef ref_vector_ptr_hash expr_ref_vector_hash; typedef ref_vector_ptr_eq expr_ref_vector_eq; typedef hashtable clause_table; @@ -2393,6 +2397,7 @@ namespace qe { +#if 0 // ------------------------------------------------ // expr_quant_elim_star1 @@ -2433,13 +2438,7 @@ namespace qe { simplifier(m), m_quant_elim(m, p), m_assumption(m.mk_true()) { } - - void expr_quant_elim_star1::reduce_with_assumption(expr* ctx, expr* fml, expr_ref& result) { - proof_ref pr(m); - m_assumption = ctx; - (*this)(fml, result, pr); - m_assumption = m.mk_true(); - } +#endif void hoist_exists(expr_ref& fml, app_ref_vector& vars) { @@ -2488,6 +2487,7 @@ namespace qe { virtual ~simplify_solver_context() { reset(); } + void solve(expr_ref& fml, app_ref_vector& vars) { init(fml, vars); bool solved = true; @@ -2580,6 +2580,10 @@ namespace qe { m_ctx.updt_params(p); } + void collect_statistics(statistics & st) const { + m_ctx.collect_statistics(st); + } + bool reduce_quantifier( quantifier * old_q, expr * new_body, @@ -2647,6 +2651,10 @@ namespace qe { imp->updt_params(p); } + void simplify_rewriter_cfg::collect_statistics(statistics & st) const { + imp->collect_statistics(st); + } + bool simplify_rewriter_cfg::pre_visit(expr* e) { if (!is_quantifier(e)) return true; quantifier * q = to_quantifier(e); diff --git a/src/qe/qe.h b/src/qe/qe.h index 392bfb03b..b6754b384 100644 --- a/src/qe/qe.h +++ b/src/qe/qe.h @@ -26,7 +26,6 @@ Revision History: #include "util/statistics.h" #include "util/lbool.h" #include "ast/expr_functors.h" -#include "ast/simplifier/simplifier.h" #include "ast/rewriter/rewriter.h" #include "model/model.h" #include "util/params.h" @@ -106,6 +105,9 @@ namespace qe { i_expr_pred& get_is_relevant() { return m_is_relevant; } i_nnf_atom& get_mk_atom() { return m_mk_atom; } + + void collect_statistics(statistics & st) const; + }; class conj_enum { @@ -322,30 +324,6 @@ namespace qe { void init_qe(); }; - class expr_quant_elim_star1 : public simplifier { - protected: - expr_quant_elim m_quant_elim; - expr* m_assumption; - virtual bool visit_quantifier(quantifier * q); - virtual void reduce1_quantifier(quantifier * q); - virtual bool is_target(quantifier * q) const { return q->get_num_patterns() == 0 && q->get_num_no_patterns() == 0; } - public: - expr_quant_elim_star1(ast_manager & m, smt_params const& p); - virtual ~expr_quant_elim_star1() {} - - void collect_statistics(statistics & st) const { - m_quant_elim.collect_statistics(st); - } - - void reduce_with_assumption(expr* ctx, expr* fml, expr_ref& result); - - lbool first_elim(unsigned num_vars, app* const* vars, expr_ref& fml, def_vector& defs) { - return m_quant_elim.first_elim(num_vars, vars, fml, defs); - } - - - }; - void hoist_exists(expr_ref& fml, app_ref_vector& vars); void mk_exists(unsigned num_vars, app* const* vars, expr_ref& fml); @@ -372,6 +350,7 @@ namespace qe { void updt_params(params_ref const& p); + void collect_statistics(statistics & st) const; }; class simplify_rewriter_star : public rewriter_tpl { @@ -382,6 +361,11 @@ namespace qe { m_cfg(m) {} void updt_params(params_ref const& p) { m_cfg.updt_params(p); } + + void collect_statistics(statistics & st) const { + m_cfg.collect_statistics(st); + } + }; }; diff --git a/src/qe/qe_cmd.cpp b/src/qe/qe_cmd.cpp index 553cf4471..3c55c0f49 100644 --- a/src/qe/qe_cmd.cpp +++ b/src/qe/qe_cmd.cpp @@ -44,9 +44,8 @@ public: } virtual void execute(cmd_context & ctx) { - smt_params par; proof_ref pr(ctx.m()); - qe::expr_quant_elim_star1 qe(ctx.m(), par); + qe::simplify_rewriter_star qe(ctx.m()); expr_ref result(ctx.m()); qe(m_target, result, pr); diff --git a/src/qe/qe_datatype_plugin.cpp b/src/qe/qe_datatype_plugin.cpp index 4178c3af3..c3525aa33 100644 --- a/src/qe/qe_datatype_plugin.cpp +++ b/src/qe/qe_datatype_plugin.cpp @@ -626,7 +626,7 @@ namespace qe { // If 'x' does not yet have a recognizer, then branch according to recognizers. // if (!has_recognizer(x, fml, r, c)) { - c = (*m_datatype_util.get_datatype_constructors(s))[vl.get_unsigned()]; + c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned()); r = m_datatype_util.get_constructor_recognizer(c); app* is_c = m.mk_app(r, x); // assert v => r(x) @@ -673,7 +673,7 @@ namespace qe { // Introduce auxiliary variable to eliminate. // if (!has_recognizer(x, fml, r, c)) { - c = (*m_datatype_util.get_datatype_constructors(s))[vl.get_unsigned()]; + c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned()); r = m_datatype_util.get_constructor_recognizer(c); app* is_c = m.mk_app(r, x); fml = m.mk_and(is_c, fml); @@ -774,7 +774,7 @@ namespace qe { return; } - c = (*m_datatype_util.get_datatype_constructors(s))[vl.get_unsigned()]; + c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned()); r = m_datatype_util.get_constructor_recognizer(c); app* is_c = m.mk_app(r, x); @@ -794,7 +794,7 @@ namespace qe { else { SASSERT(vl.is_unsigned()); SASSERT(vl.get_unsigned() < m_datatype_util.get_datatype_num_constructors(s)); - c = (*m_datatype_util.get_datatype_constructors(s))[vl.get_unsigned()]; + c = m_datatype_util.get_datatype_constructors(s)->get(vl.get_unsigned()); } subst_constructor(x, c, fml, def); } diff --git a/src/qe/vsubst_tactic.cpp b/src/qe/vsubst_tactic.cpp deleted file mode 100644 index 6bd8213d6..000000000 --- a/src/qe/vsubst_tactic.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - vsubst_tactic.cpp - -Abstract: - - Check satisfiability of QF_NRA problems using virtual subsititution quantifier-elimination. - -Author: - - Nikolaj (nbjorner) 2011-05-16 - -Notes: - Ported to tactic framework on 2012-02-28 - It was qfnra_vsubst.cpp - - This goal transformation checks satsifiability - of quantifier-free non-linear constraints using - virtual substitutions (applies to second-degree polynomials). - . identify non-linear variables - . use the identified variables as non-linear variables. - . give up if there are non-linear variables under uninterpreted scope. - give up if there are no non-linear variables. - . call quantifier elimination with - - non-linear elimination option. - - get-first-branch option. - . if the first branch is linear, then done. - if the result is unsat, then done. - if the first branch is non-linear then, - check candidate model, - perhaps iterate using rewriting or just give up. - - . helpful facilities: - . linearize_rewriter - a*a*b + a*b = 0 <=> (b+1) = 0 \/ a = 0 \/ b = 0 - . sign analysis: - a*a + b*b + c < 0 => c < 0 - ---*/ -#include "tactic/tactic.h" -#include "qe/qe.h" -#include "ast/arith_decl_plugin.h" -#include "ast/for_each_expr.h" -#include "tactic/extension_model_converter.h" -#include "ast/ast_smt2_pp.h" - -class vsubst_tactic : public tactic { - params_ref m_params; - - class get_var_proc { - arith_util m_arith; - ptr_vector& m_vars; - public: - get_var_proc(ast_manager & m, ptr_vector& vars) : m_arith(m), m_vars(vars) {} - - void operator()(expr* e) { - if (is_app(e)) { - app* a = to_app(e); - if (m_arith.is_real(e) && - a->get_num_args() == 0 && - a->get_family_id() == null_family_id) { - m_vars.push_back(a); - } - } - } - }; - - void get_vars(ast_manager & m, expr* fml, ptr_vector& vars) { - get_var_proc proc(m, vars); - for_each_expr(proc, fml); - } - - void main(goal & s, model_converter_ref & mc, params_ref const & p) { - ast_manager & m = s.m(); - - ptr_vector fs; - for (unsigned i = 0; i < s.size(); ++i) { - fs.push_back(s.form(i)); - } - app_ref f(m.mk_and(fs.size(), fs.c_ptr()), m); - TRACE("vsubst", - s.display(tout); - tout << "goal: " << mk_ismt2_pp(f.get(), m) << "\n";); - ptr_vector vars; - get_vars(m, f.get(), vars); - - if (vars.empty()) { - TRACE("vsubst", tout << "no real variables\n";); - throw tactic_exception("there are no real variables"); - } - - smt_params params; - params.updt_params(p); - params.m_model = false; - flet fl1(params.m_nlquant_elim, true); - flet fl2(params.m_nl_arith_gb, false); - TRACE("quant_elim", tout << "Produce models: " << params.m_model << "\n";); - - qe::expr_quant_elim_star1 qelim(m, params); - expr_ref g(f, m); - qe::def_vector defs(m); - lbool is_sat = qelim.first_elim(vars.size(), vars.c_ptr(), g, defs); - if (is_sat == l_undef) { - TRACE("vsubst", tout << mk_ismt2_pp(g, m) << "\n";); - throw tactic_exception("elimination was not successful"); - } - if (!defs.empty()) { - extension_model_converter * ev = alloc(extension_model_converter, m); - mc = ev; - for (unsigned i = defs.size(); i > 0; ) { - --i; - ev->insert(defs.var(i), defs.def(i)); - } - } - - s.reset(); - // TBD: wasteful as we already know it is sat or unsat. - // TBD: extract model from virtual substitution. - s.assert_expr(g); - - TRACE("qfnra_vsubst", - tout << "v-subst result:\n"; - s.display(tout);); - } - - -public: - vsubst_tactic(params_ref const & p):m_params(p) {} - - virtual tactic * translate(ast_manager & m) { - return alloc(vsubst_tactic, m_params); - } - - virtual ~vsubst_tactic() {} - - virtual void updt_params(params_ref const & p) { - m_params = p; - } - - /** - \brief Check satisfiability of an assertion set of QF_NRA - by using virtual substitutions. - */ - virtual void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) { - SASSERT(g->is_well_sorted()); - fail_if_proof_generation("vsubst", g); - fail_if_unsat_core_generation("vsubst", g); - fail_if_model_generation("vsubst", g); // disable for now due to problems with infinitesimals. - mc = 0; pc = 0; core = 0; result.reset(); - - main(*(g.get()), mc, m_params); - - result.push_back(g.get()); - SASSERT(g->is_well_sorted()); - } - - virtual void cleanup(void) {} -}; - -tactic * mk_vsubst_tactic(ast_manager & m, params_ref const & p) { - return alloc(vsubst_tactic, p); -} diff --git a/src/qe/vsubst_tactic.h b/src/qe/vsubst_tactic.h deleted file mode 100644 index 2f28bda71..000000000 --- a/src/qe/vsubst_tactic.h +++ /dev/null @@ -1,33 +0,0 @@ -/*++ -Copyright (c) 2011 Microsoft Corporation - -Module Name: - - vsubst_tactic.h - -Abstract: - - Check satisfiability of QF_NRA problems using virtual subsititution quantifier-elimination. - -Author: - - Nikolaj (nbjorner) 2011-05-16 - -Notes: - - ---*/ -#ifndef VSUBST_TACTIC_H_ -#define VSUBST_TACTIC_H_ - -#include "util/params.h" -class ast_manager; -class tactic; - -tactic * mk_vsubst_tactic(ast_manager & m, params_ref const & p = params_ref()); -/* - ADD_TACTIC("vsubst", "checks satsifiability of quantifier-free non-linear constraints using virtual substitution.", "mk_vsubst_tactic(m, p)") -*/ - -#endif - diff --git a/src/smt/arith_eq_adapter.cpp b/src/smt/arith_eq_adapter.cpp index 60c109cff..307bdc671 100644 --- a/src/smt/arith_eq_adapter.cpp +++ b/src/smt/arith_eq_adapter.cpp @@ -22,7 +22,6 @@ Revision History: #include "ast/ast_pp.h" #include "ast/ast_ll_pp.h" #include "util/stats.h" -#include "ast/simplifier/simplifier.h" #include "ast/ast_smt2_pp.h" namespace smt { diff --git a/src/smt/arith_eq_adapter.h b/src/smt/arith_eq_adapter.h index f18b2999f..4a8a293e3 100644 --- a/src/smt/arith_eq_adapter.h +++ b/src/smt/arith_eq_adapter.h @@ -23,7 +23,6 @@ Revision History: #include "util/obj_pair_hashtable.h" #include "ast/arith_decl_plugin.h" #include "util/statistics.h" -#include "ast/simplifier/arith_simplifier_plugin.h" namespace smt { diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index d9630c979..c52ad851c 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -21,61 +21,54 @@ Revision History: #include "ast/ast_pp.h" #include "ast/for_each_expr.h" #include "ast/well_sorted.h" -#include "ast/simplifier/arith_simplifier_plugin.h" -#include "ast/simplifier/array_simplifier_plugin.h" -#include "ast/simplifier/datatype_simplifier_plugin.h" -#include "ast/simplifier/fpa_simplifier_plugin.h" -#include "ast/simplifier/seq_simplifier_plugin.h" -#include "ast/simplifier/bv_simplifier_plugin.h" -#include "ast/simplifier/pull_ite_tree.h" -#include "ast/simplifier/push_app_ite.h" -#include "ast/simplifier/bv_elim.h" -#include "ast/simplifier/inj_axiom.h" -#include "ast/simplifier/elim_bounds.h" -#include "ast/simplifier/bit2int.h" -#include "ast/normal_forms/pull_quant.h" +#include "ast/rewriter/rewriter_def.h" #include "ast/normal_forms/nnf.h" #include "ast/pattern/pattern_inference.h" -#include "ast/rewriter/der.h" -#include "ast/rewriter/distribute_forall.h" #include "ast/macros/quasi_macros.h" #include "smt/asserted_formulas.h" -#include "smt/elim_term_ite.h" asserted_formulas::asserted_formulas(ast_manager & m, smt_params & p): m(m), m_params(p), - m_pre_simplifier(m), - m_simplifier(m), + m_rewriter(m), + m_substitution(m), + m_scoped_substitution(m_substitution), m_defined_names(m), m_static_features(m), - m_asserted_formulas(m), - m_asserted_formula_prs(m), - m_asserted_qhead(0), - m_macro_manager(m, m_simplifier), - m_bit2int(m), + m_qhead(0), + m_macro_manager(m), m_bv_sharing(m), - m_inconsistent(false){ + m_inconsistent(false), + m_has_quantifiers(false), + m_reduce_asserted_formulas(*this), + m_distribute_forall(*this), + m_pattern_inference(*this), + m_refine_inj_axiom(*this), + m_max_bv_sharing_fn(*this), + m_elim_term_ite(*this), + m_pull_cheap_ite_trees(*this), + m_pull_nested_quantifiers(*this), + m_elim_bvs_from_quantifiers(*this), + m_cheap_quant_fourier_motzkin(*this), + m_apply_bit2int(*this), + m_lift_ite(*this), + m_ng_lift_ite(*this), + m_find_macros(*this), + m_propagate_values(*this), + m_nnf_cnf(*this), + m_apply_quasi_macros(*this) { - m_bsimp = 0; - m_bvsimp = 0; - arith_simplifier_plugin * arith_simp = 0; - setup_simplifier_plugins(m_simplifier, m_bsimp, arith_simp, m_bvsimp); - SASSERT(m_bsimp != 0); - SASSERT(arith_simp != 0); m_macro_finder = alloc(macro_finder, m, m_macro_manager); - basic_simplifier_plugin * basic_simp = 0; - bv_simplifier_plugin * bv_simp = 0; - setup_simplifier_plugins(m_pre_simplifier, basic_simp, arith_simp, bv_simp); - m_bit2int.set_bv_simplifier(bv_simp); - m_pre_simplifier.enable_presimp(); + m_elim_and = true; + set_eliminate_and(false); + } void asserted_formulas::setup() { switch (m_params.m_lift_ite) { case LI_FULL: - m_params.m_ng_lift_ite = LI_NONE; + m_params.m_ng_lift_ite = LI_NONE; break; case LI_CONSERVATIVE: if (m_params.m_ng_lift_ite == LI_CONSERVATIVE) @@ -84,120 +77,112 @@ void asserted_formulas::setup() { default: break; } - + if (m_params.m_relevancy_lvl == 0) m_params.m_relevancy_lemma = false; } -void asserted_formulas::setup_simplifier_plugins(simplifier & s, basic_simplifier_plugin * & bsimp, arith_simplifier_plugin * & asimp, bv_simplifier_plugin * & bvsimp) { - bsimp = alloc(basic_simplifier_plugin, m); - s.register_plugin(bsimp); - asimp = alloc(arith_simplifier_plugin, m, *bsimp, m_params); - s.register_plugin(asimp); - s.register_plugin(alloc(array_simplifier_plugin, m, *bsimp, s, m_params)); - bvsimp = alloc(bv_simplifier_plugin, m, *bsimp, m_params); - s.register_plugin(bvsimp); - s.register_plugin(alloc(datatype_simplifier_plugin, m, *bsimp)); - s.register_plugin(alloc(fpa_simplifier_plugin, m, *bsimp)); - s.register_plugin(alloc(seq_simplifier_plugin, m, *bsimp)); -} - -void asserted_formulas::init(unsigned num_formulas, expr * const * formulas, proof * const * prs) { - SASSERT(m_asserted_formulas.empty()); - SASSERT(m_asserted_formula_prs.empty()); - SASSERT(!m_inconsistent); - SASSERT(m_scopes.empty()); - m_asserted_formulas.append(num_formulas, formulas); - if (m.proofs_enabled()) - m_asserted_formula_prs.append(num_formulas, prs); -} - -bool asserted_formulas::has_bv() const { - // approaximated answer... assume the formula has bit-vectors if the bv_simplifier_plugin was invoked at least once. - return m_bvsimp->reduce_invoked(); -} asserted_formulas::~asserted_formulas() { } -void asserted_formulas::push_assertion(expr * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs) { +void asserted_formulas::push_assertion(expr * e, proof * pr, vector& result) { if (inconsistent()) { - SASSERT(!result.empty()); return; } - if (m.is_false(e)) - m_inconsistent = true; - ::push_assertion(m, e, pr, result, result_prs); + expr* e1 = 0; + if (m.is_false(e)) { + result.push_back(justified_expr(m, e, pr)); + m_inconsistent = true; + } + else if (m.is_true(e)) { + // skip + } + else if (m.is_and(e)) { + for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) { + expr* arg = to_app(e)->get_arg(i); + proof_ref _pr(m.mk_and_elim(pr, i), m); + push_assertion(arg, _pr, result); + } + } + else if (m.is_not(e, e1) && m.is_or(e1)) { + for (unsigned i = 0; i < to_app(e1)->get_num_args(); ++i) { + expr* arg = to_app(e1)->get_arg(i); + proof_ref _pr(m.mk_not_or_elim(pr, i), m); + expr_ref narg(mk_not(m, arg), m); + push_assertion(narg, _pr, result); + } + } + else { + result.push_back(justified_expr(m, e, pr)); + } } void asserted_formulas::set_eliminate_and(bool flag) { - if (m_bsimp->eliminate_and() == flag) - return; - TRACE("eliminate_and", tout << "flushing cache...\n";); + if (flag == m_elim_and) return; + m_elim_and = flag; + params_ref p; + p.set_bool("pull_cheap_ite", false); + p.set_bool("elim_and", flag); + p.set_bool("arith_ineq_lhs", true); + p.set_bool("sort_sums", true); + p.set_bool("rewrite_patterns", true); + p.set_bool("eq2ineq", m_params.m_arith_eq2ineq); + p.set_bool("gcd_rounding", true); + p.set_bool("expand_select_store", true); + m_rewriter.updt_params(p); flush_cache(); - m_bsimp->set_eliminate_and(flag); } void asserted_formulas::assert_expr(expr * e, proof * _in_pr) { - if (inconsistent()) - return; - if (!m_params.m_preprocess) { - push_assertion(e, _in_pr, m_asserted_formulas, m_asserted_formula_prs); + proof_ref in_pr(_in_pr, m), pr(_in_pr, m); + expr_ref r(e, m); + + if (inconsistent()) return; + + m_has_quantifiers |= ::has_quantifiers(e); + + if (m_params.m_preprocess) { + TRACE("assert_expr_bug", tout << r << "\n";); + set_eliminate_and(false); // do not eliminate and before nnf. + m_rewriter(e, r, pr); + if (m.proofs_enabled()) { + if (e == r) + pr = in_pr; + else + pr = m.mk_modus_ponens(in_pr, pr); + } + TRACE("assert_expr_bug", tout << "after...\n" << r << "\n";); } - proof_ref in_pr(_in_pr, m); - expr_ref r1(m); - proof_ref pr1(m); - expr_ref r2(m); - proof_ref pr2(m); - TRACE("assert_expr_before_simp", tout << mk_ll_pp(e, m) << "\n";); - TRACE("assert_expr_bug", tout << mk_pp(e, m) << "\n";); - if (m_params.m_pre_simplifier) { - m_pre_simplifier(e, r1, pr1); - } - else { - r1 = e; - pr1 = 0; - } - set_eliminate_and(false); // do not eliminate and before nnf. - m_simplifier(r1, r2, pr2); - TRACE("assert_expr_bug", tout << "after...\n" << mk_pp(r1, m) << "\n";); - if (m.proofs_enabled()) { - if (e == r2) - pr2 = in_pr; - else - pr2 = m.mk_modus_ponens(in_pr, m.mk_transitivity(pr1, pr2)); - } - TRACE("assert_expr_after_simp", tout << mk_ll_pp(r1, m) << "\n";); - push_assertion(r2, pr2, m_asserted_formulas, m_asserted_formula_prs); + push_assertion(r, pr, m_formulas); TRACE("asserted_formulas_bug", tout << "after assert_expr\n"; display(tout);); } void asserted_formulas::assert_expr(expr * e) { - if (inconsistent()) - return; assert_expr(e, m.mk_asserted(e)); } -void asserted_formulas::get_assertions(ptr_vector & result) { - result.append(m_asserted_formulas.size(), m_asserted_formulas.c_ptr()); +void asserted_formulas::get_assertions(ptr_vector & result) const { + for (justified_expr const& je : m_formulas) result.push_back(je.get_fml()); } void asserted_formulas::push_scope() { - SASSERT(inconsistent() || m_asserted_qhead == m_asserted_formulas.size() || m.canceled()); - TRACE("asserted_formulas_scopes", tout << "push:\n"; display(tout);); + SASSERT(inconsistent() || m_qhead == m_formulas.size() || m.canceled()); + TRACE("asserted_formulas_scopes", tout << "push:\n"; display(tout);); + m_scoped_substitution.push(); m_scopes.push_back(scope()); - m_macro_manager.push_scope(); scope & s = m_scopes.back(); - s.m_asserted_formulas_lim = m_asserted_formulas.size(); - SASSERT(inconsistent() || s.m_asserted_formulas_lim == m_asserted_qhead || m.canceled()); - s.m_inconsistent_old = m_inconsistent; + s.m_formulas_lim = m_formulas.size(); + SASSERT(inconsistent() || s.m_formulas_lim == m_qhead || m.canceled()); + s.m_inconsistent_old = m_inconsistent; m_defined_names.push(); m_bv_sharing.push_scope(); + m_macro_manager.push_scope(); commit(); } - + void asserted_formulas::pop_scope(unsigned num_scopes) { TRACE("asserted_formulas_scopes", tout << "before pop " << num_scopes << "\n"; display(tout);); m_bv_sharing.pop_scope(num_scopes); @@ -206,10 +191,9 @@ void asserted_formulas::pop_scope(unsigned num_scopes) { scope & s = m_scopes[new_lvl]; m_inconsistent = s.m_inconsistent_old; m_defined_names.pop(num_scopes); - m_asserted_formulas.shrink(s.m_asserted_formulas_lim); - if (m.proofs_enabled()) - m_asserted_formula_prs.shrink(s.m_asserted_formulas_lim); - m_asserted_qhead = s.m_asserted_formulas_lim; + m_scoped_substitution.pop(num_scopes); + m_formulas.shrink(s.m_formulas_lim); + m_qhead = s.m_formulas_lim; m_scopes.shrink(new_lvl); flush_cache(); TRACE("asserted_formulas_scopes", tout << "after pop " << num_scopes << "\n"; display(tout);); @@ -217,125 +201,110 @@ void asserted_formulas::pop_scope(unsigned num_scopes) { void asserted_formulas::reset() { m_defined_names.reset(); - m_asserted_qhead = 0; - m_asserted_formulas.reset(); - m_asserted_formula_prs.reset(); + m_qhead = 0; + m_formulas.reset(); m_macro_manager.reset(); m_bv_sharing.reset(); + m_rewriter.reset(); m_inconsistent = false; } - -#ifdef Z3DEBUG bool asserted_formulas::check_well_sorted() const { - for (unsigned i = 0; i < m_asserted_formulas.size(); i++) { - if (!is_well_sorted(m, m_asserted_formulas.get(i))) return false; + for (justified_expr const& je : m_formulas) { + if (!is_well_sorted(m, je.get_fml())) return false; } return true; } -#endif void asserted_formulas::reduce() { if (inconsistent()) return; - if (canceled()) { + if (canceled()) return; - } - if (m_asserted_qhead == m_asserted_formulas.size()) + if (m_qhead == m_formulas.size()) return; - if (!m_params.m_preprocess) - return; - - if (m_macro_manager.has_macros()) - expand_macros(); + if (!m_params.m_preprocess) + return; + if (m_macro_manager.has_macros()) + invoke(m_find_macros); + TRACE("before_reduce", display(tout);); CASSERT("well_sorted", check_well_sorted()); - - -#define INVOKE(COND, FUNC) if (COND) { FUNC; IF_VERBOSE(10000, verbose_stream() << "total size: " << get_total_size() << "\n";); } TRACE("reduce_step_ll", ast_mark visited; display_ll(tout, visited);); TRACE("reduce_step", display(tout << #FUNC << " ");); CASSERT("well_sorted",check_well_sorted()); if (inconsistent() || canceled()) { TRACE("after_reduce", display(tout);); TRACE("after_reduce_ll", ast_mark visited; display_ll(tout, visited);); return; } - + set_eliminate_and(false); // do not eliminate and before nnf. - INVOKE(m_params.m_propagate_booleans, propagate_booleans()); - INVOKE(m_params.m_propagate_values, propagate_values()); - INVOKE(m_params.m_macro_finder && has_quantifiers(), find_macros()); - INVOKE(m_params.m_nnf_cnf || (m_params.m_mbqi && has_quantifiers()), nnf_cnf()); - INVOKE(m_params.m_eliminate_and, eliminate_and()); - INVOKE(m_params.m_pull_cheap_ite_trees, pull_cheap_ite_trees()); - INVOKE(m_params.m_pull_nested_quantifiers && has_quantifiers(), pull_nested_quantifiers()); - INVOKE(m_params.m_ng_lift_ite != LI_NONE, ng_lift_ite()); - INVOKE(m_params.m_lift_ite != LI_NONE, lift_ite()); - INVOKE(m_params.m_eliminate_term_ite && m_params.m_lift_ite != LI_FULL, eliminate_term_ite()); - INVOKE(m_params.m_refine_inj_axiom && has_quantifiers(), refine_inj_axiom()); - INVOKE(m_params.m_distribute_forall && has_quantifiers(), apply_distribute_forall()); - TRACE("qbv_bug", tout << "after distribute_forall:\n"; display(tout);); - INVOKE(m_params.m_macro_finder && has_quantifiers(), find_macros()); - INVOKE(m_params.m_quasi_macros && has_quantifiers(), apply_quasi_macros()); - INVOKE(m_params.m_simplify_bit2int, apply_bit2int()); - INVOKE(m_params.m_eliminate_bounds && has_quantifiers(), cheap_quant_fourier_motzkin()); - INVOKE(m_params.m_ematching && has_quantifiers(), infer_patterns()); - INVOKE(m_params.m_max_bv_sharing && has_bv(), max_bv_sharing()); - INVOKE(m_params.m_bb_quantifiers, elim_bvs_from_quantifiers()); - // temporary HACK: make sure that arith & bv are list-assoc - // this may destroy some simplification steps such as max_bv_sharing - reduce_asserted_formulas(); - - CASSERT("well_sorted",check_well_sorted()); + if (!invoke(m_propagate_values)) return; + if (!invoke(m_find_macros)) return; + if (!invoke(m_nnf_cnf)) return; + set_eliminate_and(true); + if (!invoke(m_reduce_asserted_formulas)) return; + if (!invoke(m_pull_cheap_ite_trees)) return; + if (!invoke(m_pull_nested_quantifiers)) return; + if (!invoke(m_lift_ite)) return; + if (!invoke(m_ng_lift_ite)) return; + if (!invoke(m_elim_term_ite)) return; + if (!invoke(m_refine_inj_axiom)) return; + if (!invoke(m_distribute_forall)) return; + if (!invoke(m_find_macros)) return; + if (!invoke(m_apply_quasi_macros)) return; + if (!invoke(m_apply_bit2int)) return; + if (!invoke(m_cheap_quant_fourier_motzkin)) return; + if (!invoke(m_pattern_inference)) return; + if (!invoke(m_max_bv_sharing_fn)) return; + if (!invoke(m_elim_bvs_from_quantifiers)) return; + if (!invoke(m_reduce_asserted_formulas)) return; IF_VERBOSE(10, verbose_stream() << "(smt.simplifier-done)\n";); TRACE("after_reduce", display(tout);); TRACE("after_reduce_ll", ast_mark visited; display_ll(tout, visited);); TRACE("macros", m_macro_manager.display(tout);); flush_cache(); + CASSERT("well_sorted",check_well_sorted()); } -void asserted_formulas::eliminate_and() { - IF_IVERBOSE(10, verbose_stream() << "(smt.eliminating-and)\n";); - set_eliminate_and(true); - reduce_asserted_formulas(); - TRACE("after_elim_and", display(tout);); -} unsigned asserted_formulas::get_formulas_last_level() const { if (m_scopes.empty()) { return 0; } else { - return m_scopes.back().m_asserted_formulas_lim; + return m_scopes.back().m_formulas_lim; } } -void asserted_formulas::collect_static_features() { - if (m_params.m_display_features) { - unsigned sz = m_asserted_formulas.size(); - unsigned head = m_asserted_qhead; - while (head < sz) { - expr * f = m_asserted_formulas.get(head); - head++; - m_static_features.collect(f); - } - m_static_features.display_primitive(std::cout); - m_static_features.display(std::cout); +bool asserted_formulas::invoke(simplify_fmls& s) { + if (!s.should_apply()) return true; + IF_VERBOSE(10, verbose_stream() << "(smt." << s.id() << ")\n";); + s(); + IF_VERBOSE(10000, verbose_stream() << "total size: " << get_total_size() << "\n";); + TRACE("reduce_step_ll", ast_mark visited; display_ll(tout, visited);); + CASSERT("well_sorted",check_well_sorted()); + if (inconsistent() || canceled()) { + TRACE("after_reduce", display(tout);); + TRACE("after_reduce_ll", ast_mark visited; display_ll(tout, visited);); + return false; + } + else { + return true; } } void asserted_formulas::display(std::ostream & out) const { out << "asserted formulas:\n"; - for (unsigned i = 0; i < m_asserted_formulas.size(); i++) { - if (i == m_asserted_qhead) + for (unsigned i = 0; i < m_formulas.size(); i++) { + if (i == m_qhead) out << "[HEAD] ==>\n"; - out << mk_pp(m_asserted_formulas.get(i), m) << "\n"; + out << mk_pp(m_formulas[i].get_fml(), m) << "\n"; } out << "inconsistent: " << inconsistent() << "\n"; } void asserted_formulas::display_ll(std::ostream & out, ast_mark & pp_visited) const { - if (!m_asserted_formulas.empty()) { - unsigned sz = m_asserted_formulas.size(); - for (unsigned i = 0; i < sz; i++) - ast_def_ll_pp(out, m, m_asserted_formulas.get(i), pp_visited, true, false); + if (!m_formulas.empty()) { + for (justified_expr const& f : m_formulas) + ast_def_ll_pp(out, m, f.get_fml(), pp_visited, true, false); out << "asserted formulas:\n"; - for (unsigned i = 0; i < sz; i++) - out << "#" << m_asserted_formulas[i]->get_id() << " "; + for (justified_expr const& f : m_formulas) + out << "#" << f.get_fml()->get_id() << " "; out << "\n"; } } @@ -343,112 +312,54 @@ void asserted_formulas::display_ll(std::ostream & out, ast_mark & pp_visited) co void asserted_formulas::collect_statistics(statistics & st) const { } -void asserted_formulas::reduce_asserted_formulas() { - if (inconsistent()) { - return; - } - expr_ref_vector new_exprs(m); - proof_ref_vector new_prs(m); - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); - for (; i < sz && !inconsistent(); i++) { - expr * n = m_asserted_formulas.get(i); - SASSERT(n != 0); - proof * pr = m_asserted_formula_prs.get(i, 0); - expr_ref new_n(m); - proof_ref new_pr(m); - m_simplifier(n, new_n, new_pr); - TRACE("reduce_asserted_formulas", tout << mk_pp(n, m) << " -> " << mk_pp(new_n, m) << "\n";); - if (n == new_n.get()) { - push_assertion(n, pr, new_exprs, new_prs); - } - else { - new_pr = m.mk_modus_ponens(pr, new_pr); - push_assertion(new_n, new_pr, new_exprs, new_prs); - } - if (canceled()) { - return; - } - } - swap_asserted_formulas(new_exprs, new_prs); + +void asserted_formulas::swap_asserted_formulas(vector& formulas) { + SASSERT(!inconsistent() || !formulas.empty()); + m_formulas.shrink(m_qhead); + m_formulas.append(formulas); } -void asserted_formulas::swap_asserted_formulas(expr_ref_vector & new_exprs, proof_ref_vector & new_prs) { - SASSERT(!inconsistent() || !new_exprs.empty()); - m_asserted_formulas.shrink(m_asserted_qhead); - m_asserted_formulas.append(new_exprs); - if (m.proofs_enabled()) { - m_asserted_formula_prs.shrink(m_asserted_qhead); - m_asserted_formula_prs.append(new_prs); - } -} void asserted_formulas::find_macros_core() { - expr_ref_vector new_exprs(m); - proof_ref_vector new_prs(m); - unsigned sz = m_asserted_formulas.size(); - expr_dependency_ref_vector new_deps(m); - m_macro_finder->operator()(sz - m_asserted_qhead, - m_asserted_formulas.c_ptr() + m_asserted_qhead, - m_asserted_formula_prs.c_ptr() + m_asserted_qhead, - 0, // 0 == No dependency tracking - new_exprs, new_prs, new_deps); - swap_asserted_formulas(new_exprs, new_prs); + vector new_fmls; + unsigned sz = m_formulas.size(); + (*m_macro_finder)(sz - m_qhead, m_formulas.c_ptr() + m_qhead, new_fmls); + swap_asserted_formulas(new_fmls); reduce_and_solve(); } -void asserted_formulas::find_macros() { - IF_IVERBOSE(10, verbose_stream() << "(smt.find-macros)\n";); - TRACE("before_find_macros", display(tout);); - find_macros_core(); - TRACE("after_find_macros", display(tout);); -} - -void asserted_formulas::expand_macros() { - IF_IVERBOSE(10, verbose_stream() << "(smt.expand-macros)\n";); - find_macros_core(); -} - void asserted_formulas::apply_quasi_macros() { - IF_IVERBOSE(10, verbose_stream() << "(smt.find-quasi-macros)\n";); TRACE("before_quasi_macros", display(tout);); - expr_ref_vector new_exprs(m); - proof_ref_vector new_prs(m); - quasi_macros proc(m, m_macro_manager, m_simplifier); - expr_dependency_ref_vector new_deps(m); - while (proc(m_asserted_formulas.size() - m_asserted_qhead, - m_asserted_formulas.c_ptr() + m_asserted_qhead, - m_asserted_formula_prs.c_ptr() + m_asserted_qhead, - 0, // 0 == No dependency tracking - new_exprs, new_prs, new_deps)) { - swap_asserted_formulas(new_exprs, new_prs); - new_exprs.reset(); - new_prs.reset(); + vector new_fmls; + quasi_macros proc(m, m_macro_manager); + while (proc(m_formulas.size() - m_qhead, + m_formulas.c_ptr() + m_qhead, + new_fmls)) { + swap_asserted_formulas(new_fmls); + new_fmls.reset(); } TRACE("after_quasi_macros", display(tout);); reduce_and_solve(); } void asserted_formulas::nnf_cnf() { - IF_IVERBOSE(10, verbose_stream() << "(smt.nnf)\n";); nnf apply_nnf(m, m_defined_names); - expr_ref_vector new_exprs(m); - proof_ref_vector new_prs(m); + vector new_fmls; expr_ref_vector push_todo(m); proof_ref_vector push_todo_prs(m); - - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); + + unsigned i = m_qhead; + unsigned sz = m_formulas.size(); TRACE("nnf_bug", tout << "i: " << i << " sz: " << sz << "\n";); for (; i < sz; i++) { - expr * n = m_asserted_formulas.get(i); + expr * n = m_formulas[i].get_fml(); TRACE("nnf_bug", tout << "processing:\n" << mk_pp(n, m) << "\n";); - proof * pr = m_asserted_formula_prs.get(i, 0); + proof * pr = m_formulas[i].get_proof(); expr_ref r1(m); proof_ref pr1(m); - CASSERT("well_sorted",is_well_sorted(m, n)); push_todo.reset(); push_todo_prs.reset(); + CASSERT("well_sorted", is_well_sorted(m, n)); apply_nnf(n, push_todo, push_todo_prs, r1, pr1); CASSERT("well_sorted",is_well_sorted(m, r1)); pr = m.mk_modus_ponens(pr, pr1); @@ -461,417 +372,258 @@ void asserted_formulas::nnf_cnf() { unsigned sz2 = push_todo.size(); for (unsigned k = 0; k < sz2; k++) { expr * n = push_todo.get(k); - proof * pr = 0; - m_simplifier(n, r1, pr1); + pr = 0; + m_rewriter(n, r1, pr1); CASSERT("well_sorted",is_well_sorted(m, r1)); if (canceled()) { return; - } - + } if (m.proofs_enabled()) pr = m.mk_modus_ponens(push_todo_prs.get(k), pr1); - else - pr = 0; - push_assertion(r1, pr, new_exprs, new_prs); + push_assertion(r1, pr, new_fmls); } } - swap_asserted_formulas(new_exprs, new_prs); + swap_asserted_formulas(new_fmls); } -#define MK_SIMPLE_SIMPLIFIER(NAME, FUNCTOR_DEF, LABEL, MSG) \ -void asserted_formulas::NAME() { \ - IF_IVERBOSE(10, verbose_stream() << "(smt." << MSG << ")\n";); \ - TRACE(LABEL, tout << "before:\n"; display(tout);); \ - FUNCTOR_DEF; \ - expr_ref_vector new_exprs(m); \ - proof_ref_vector new_prs(m); \ - unsigned i = m_asserted_qhead; \ - unsigned sz = m_asserted_formulas.size(); \ - for (; i < sz; i++) { \ - expr * n = m_asserted_formulas.get(i); \ - proof * pr = m_asserted_formula_prs.get(i, 0); \ - expr_ref new_n(m); \ - functor(n, new_n); \ - TRACE("simplifier_simple_step", tout << mk_pp(n, m) << "\n" << mk_pp(new_n, m) << "\n";); \ - if (n == new_n.get()) { \ - push_assertion(n, pr, new_exprs, new_prs); \ - } \ - else if (m.proofs_enabled()) { \ - proof_ref new_pr(m); \ - new_pr = m.mk_rewrite_star(n, new_n, 0, 0); \ - new_pr = m.mk_modus_ponens(pr, new_pr); \ - push_assertion(new_n, new_pr, new_exprs, new_prs); \ - } \ - else { \ - push_assertion(new_n, 0, new_exprs, new_prs); \ - } \ - } \ - swap_asserted_formulas(new_exprs, new_prs); \ - TRACE(LABEL, display(tout);); \ - reduce_and_solve(); \ - TRACE(LABEL, display(tout);); \ +void asserted_formulas::simplify_fmls::operator()() { + vector new_fmls; + unsigned sz = af.m_formulas.size(); + for (unsigned i = af.m_qhead; i < sz; i++) { + auto& j = af.m_formulas[i]; + expr_ref result(m); + proof_ref result_pr(m); + simplify(j, result, result_pr); + if (m.proofs_enabled()) { + if (!result_pr) result_pr = m.mk_rewrite(j.get_fml(), result); + result_pr = m.mk_modus_ponens(j.get_proof(), result_pr); + } + if (j.get_fml() == result) { + new_fmls.push_back(j); + } + else { + af.push_assertion(result, result_pr, new_fmls); + } + if (af.canceled()) return; + } + af.swap_asserted_formulas(new_fmls); + TRACE("asserted_formulas", af.display(tout);); + post_op(); } -MK_SIMPLE_SIMPLIFIER(apply_distribute_forall, distribute_forall functor(m), "distribute_forall", "distribute-forall"); void asserted_formulas::reduce_and_solve() { IF_IVERBOSE(10, verbose_stream() << "(smt.reducing)\n";); flush_cache(); // collect garbage - reduce_asserted_formulas(); + m_reduce_asserted_formulas(); } -void asserted_formulas::infer_patterns() { - IF_IVERBOSE(10, verbose_stream() << "(smt.pattern-inference)\n";); - TRACE("before_pattern_inference", display(tout);); - pattern_inference infer(m, m_params); - expr_ref_vector new_exprs(m); - proof_ref_vector new_prs(m); - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); - for (; i < sz; i++) { - expr * n = m_asserted_formulas.get(i); - proof * pr = m_asserted_formula_prs.get(i, 0); - expr_ref new_n(m); - proof_ref new_pr(m); - infer(n, new_n, new_pr); - if (n == new_n.get()) { - push_assertion(n, pr, new_exprs, new_prs); - } - else if (m.proofs_enabled()) { - new_pr = m.mk_modus_ponens(pr, new_pr); - push_assertion(new_n, new_pr, new_exprs, new_prs); - } - else { - push_assertion(new_n, 0, new_exprs, new_prs); - } - } - swap_asserted_formulas(new_exprs, new_prs); - TRACE("after_pattern_inference", display(tout);); -} void asserted_formulas::commit() { - commit(m_asserted_formulas.size()); + commit(m_formulas.size()); } void asserted_formulas::commit(unsigned new_qhead) { - m_macro_manager.mark_forbidden(new_qhead - m_asserted_qhead, m_asserted_formulas.c_ptr() + m_asserted_qhead); - m_asserted_qhead = new_qhead; -} - -void asserted_formulas::eliminate_term_ite() { - IF_IVERBOSE(10, verbose_stream() << "(smt.eliminating-ite-term)\n";); - TRACE("before_elim_term_ite", display(tout);); - elim_term_ite elim(m, m_defined_names); - expr_ref_vector new_exprs(m); - proof_ref_vector new_prs(m); - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); - for (; i < sz; i++) { - expr * n = m_asserted_formulas.get(i); - proof * pr = m_asserted_formula_prs.get(i, 0); - expr_ref new_n(m); - proof_ref new_pr(m); - elim(n, new_exprs, new_prs, new_n, new_pr); - SASSERT(new_n.get() != 0); - DEBUG_CODE({ - for (unsigned i = 0; i < new_exprs.size(); i++) { - SASSERT(new_exprs.get(i) != 0); - } - }); - if (n == new_n.get()) { - push_assertion(n, pr, new_exprs, new_prs); - } - else if (m.proofs_enabled()) { - new_pr = m.mk_modus_ponens(pr, new_pr); - push_assertion(new_n, new_pr, new_exprs, new_prs); - } - else { - push_assertion(new_n, 0, new_exprs, new_prs); - } + m_macro_manager.mark_forbidden(new_qhead - m_qhead, m_formulas.c_ptr() + m_qhead); + m_expr2depth.reset(); + for (unsigned i = m_qhead; i < new_qhead; ++i) { + justified_expr const& j = m_formulas[i]; + update_substitution(j.get_fml(), j.get_proof()); } - swap_asserted_formulas(new_exprs, new_prs); - TRACE("after_elim_term_ite", display(tout);); - reduce_and_solve(); - TRACE("after_elim_term_ite", display(tout);); + m_qhead = new_qhead; } void asserted_formulas::propagate_values() { - IF_IVERBOSE(10, verbose_stream() << "(smt.constant-propagation)\n";); - TRACE("propagate_values", tout << "before:\n"; display(tout);); flush_cache(); - bool found = false; - // Separate the formulas in two sets: C and R - // C is a set which contains formulas of the form - // { x = n }, where x is a variable and n a numeral. - // R contains the rest. - // - // - new_exprs1 is the set C - // - new_exprs2 is the set R - // - // The loop also updates the m_cache. It adds the entries x -> n to it. - expr_ref_vector new_exprs1(m); - proof_ref_vector new_prs1(m); - expr_ref_vector new_exprs2(m); - proof_ref_vector new_prs2(m); - unsigned sz = m_asserted_formulas.size(); - for (unsigned i = 0; i < sz; i++) { - expr_ref n(m_asserted_formulas.get(i), m); - proof_ref pr(m_asserted_formula_prs.get(i, 0), m); - TRACE("simplifier", tout << mk_pp(n, m) << "\n";); - expr* lhs, *rhs; - if (m.is_eq(n, lhs, rhs) && - (m.is_value(lhs) || m.is_value(rhs))) { - if (m.is_value(lhs)) { - std::swap(lhs, rhs); - n = m.mk_eq(lhs, rhs); - pr = m.mk_symmetry(pr); + + unsigned num_prop = 0; + unsigned num_iterations = 0; + while (!inconsistent() && ++num_iterations < 2) { + m_expr2depth.reset(); + m_scoped_substitution.push(); + unsigned prop = num_prop; + TRACE("propagate_values", tout << "before:\n"; display(tout);); + unsigned i = m_qhead; + unsigned sz = m_formulas.size(); + for (; i < sz; i++) { + prop += propagate_values(i); + } + flush_cache(); + m_scoped_substitution.pop(1); + m_expr2depth.reset(); + m_scoped_substitution.push(); + TRACE("propagate_values", tout << "middle:\n"; display(tout);); + i = sz; + while (i > m_qhead) { + --i; + prop += propagate_values(i); + } + m_scoped_substitution.pop(1); + flush_cache(); + TRACE("propagate_values", tout << "after:\n"; display(tout);); + if (num_prop == prop) { + break; + } + num_prop = prop; + } + if (num_prop > 0) + m_reduce_asserted_formulas(); +} + +unsigned asserted_formulas::propagate_values(unsigned i) { + expr_ref n(m_formulas[i].get_fml(), m); + expr_ref new_n(m); + proof_ref new_pr(m); + m_rewriter(n, new_n, new_pr); + if (m.proofs_enabled()) { + proof * pr = m_formulas[i].get_proof(); + new_pr = m.mk_modus_ponens(pr, new_pr); + } + justified_expr j(m, new_n, new_pr); + m_formulas[i] = j; + if (m_formulas[i].get_fml() != new_n) { + std::cout << "NOT updated\n"; + } + if (m.is_false(j.get_fml())) { + m_inconsistent = true; + } + update_substitution(new_n, new_pr); + return n != new_n ? 1 : 0; +} + +void asserted_formulas::update_substitution(expr* n, proof* pr) { + expr* lhs, *rhs, *n1; + if (is_ground(n) && (m.is_eq(n, lhs, rhs) || m.is_iff(n, lhs, rhs))) { + compute_depth(lhs); + compute_depth(rhs); + if (is_gt(lhs, rhs)) { + TRACE("propagate_values", tout << "insert " << mk_pp(lhs, m) << " -> " << mk_pp(rhs, m) << "\n";); + m_scoped_substitution.insert(lhs, rhs, pr); + return; + } + if (is_gt(rhs, lhs)) { + TRACE("propagate_values", tout << "insert " << mk_pp(rhs, m) << " -> " << mk_pp(lhs, m) << "\n";); + m_scoped_substitution.insert(rhs, lhs, m.mk_symmetry(pr)); + return; + } + TRACE("propagate_values", tout << "incompatible " << mk_pp(n, m) << "\n";); + } + if (m.is_not(n, n1)) { + m_scoped_substitution.insert(n1, m.mk_false(), m.mk_iff_false(pr)); + } + else { + m_scoped_substitution.insert(n, m.mk_true(), m.mk_iff_true(pr)); + } +} + +/** + \brief implement a Knuth-Bendix ordering on expressions. +*/ + +bool asserted_formulas::is_gt(expr* lhs, expr* rhs) { + if (lhs == rhs) { + return false; + } + // values are always less in ordering than non-values. + bool v1 = m.is_value(lhs); + bool v2 = m.is_value(rhs); + if (!v1 && v2) { + return true; + } + if (v1 && !v2) { + return false; + } + SASSERT(is_ground(lhs) && is_ground(rhs)); + if (depth(lhs) > depth(rhs)) { + return true; + } + if (depth(lhs) == depth(rhs) && is_app(lhs) && is_app(rhs)) { + app* l = to_app(lhs); + app* r = to_app(rhs); + if (l->get_decl()->get_id() != r->get_decl()->get_id()) { + return l->get_decl()->get_id() > r->get_decl()->get_id(); + } + if (l->get_num_args() != r->get_num_args()) { + return l->get_num_args() > r->get_num_args(); + } + for (unsigned i = 0; i < l->get_num_args(); ++i) { + if (l->get_arg(i) != r->get_arg(i)) { + return is_gt(l->get_arg(i), r->get_arg(i)); } - if (!m.is_value(lhs) && !m_simplifier.is_cached(lhs)) { - if (i >= m_asserted_qhead) { - new_exprs1.push_back(n); - if (m.proofs_enabled()) - new_prs1.push_back(pr); + } + UNREACHABLE(); + } + + return false; +} + +void asserted_formulas::compute_depth(expr* e) { + ptr_vector todo; + todo.push_back(e); + while (!todo.empty()) { + e = todo.back(); + unsigned d = 0; + if (m_expr2depth.contains(e)) { + todo.pop_back(); + continue; + } + if (is_app(e)) { + app* a = to_app(e); + bool visited = true; + for (expr* arg : *a) { + unsigned d1 = 0; + if (m_expr2depth.find(arg, d1)) { + d = std::max(d, d1); } - TRACE("propagate_values", tout << "found:\n" << mk_pp(lhs, m) << "\n->\n" << mk_pp(rhs, m) << "\n"; - if (pr) tout << "proof: " << mk_pp(pr, m) << "\n";); - m_simplifier.cache_result(lhs, rhs, pr); - found = true; + else { + visited = false; + todo.push_back(arg); + } + } + if (!visited) { continue; } } - if (i >= m_asserted_qhead) { - new_exprs2.push_back(n); - if (m.proofs_enabled()) - new_prs2.push_back(pr); - } + todo.pop_back(); + m_expr2depth.insert(e, d + 1); } - TRACE("propagate_values", tout << "found: " << found << "\n" << new_exprs2 << "\n";); - // If C is not empty, then reduce R using the updated simplifier cache with entries - // x -> n for each constraint 'x = n' in C. - if (found) { - unsigned sz = new_exprs2.size(); - for (unsigned i = 0; i < sz; i++) { - expr * n = new_exprs2.get(i); - proof * pr = new_prs2.get(i, 0); - expr_ref new_n(m); - proof_ref new_pr(m); - m_simplifier(n, new_n, new_pr); - TRACE("propagate_values", tout << mk_pp(n, m) << " -> " << new_n << "\n";); - if (n == new_n.get()) { - push_assertion(n, pr, new_exprs1, new_prs1); - } - else { - new_pr = m.mk_modus_ponens(pr, new_pr); - push_assertion(new_n, new_pr, new_exprs1, new_prs1); - } - } - swap_asserted_formulas(new_exprs1, new_prs1); - // IMPORTANT: the cache MUST be flushed. This guarantees that all entries - // x->n will be removed from m_cache. If we don't do that, the next transformation - // may simplify constraints in C using these entries, and the variables x in C - // will be (silently) eliminated, and models produced by Z3 will not contain them. - flush_cache(); - } - TRACE("propagate_values", tout << "after:\n"; display(tout);); } -void asserted_formulas::propagate_booleans() { - bool cont = true; - bool modified = false; - flush_cache(); - while (cont) { - TRACE("propagate_booleans", tout << "before:\n"; display(tout);); - IF_IVERBOSE(10, verbose_stream() << "(smt.propagate-booleans)\n";); - cont = false; - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); -#define PROCESS() { \ - expr * n = m_asserted_formulas.get(i); \ - proof * pr = m_asserted_formula_prs.get(i, 0); \ - expr_ref new_n(m); \ - proof_ref new_pr(m); \ - m_simplifier(n, new_n, new_pr); \ - m_asserted_formulas.set(i, new_n); \ - if (m.proofs_enabled()) { \ - new_pr = m.mk_modus_ponens(pr, new_pr); \ - m_asserted_formula_prs.set(i, new_pr); \ - } \ - if (n != new_n) { \ - cont = true; \ - modified = true; \ - } \ - if (m.is_not(new_n)) \ - m_simplifier.cache_result(to_app(new_n)->get_arg(0), m.mk_false(), m.mk_iff_false(new_pr)); \ - else \ - m_simplifier.cache_result(new_n, m.mk_true(), m.mk_iff_true(new_pr)); \ - } - for (; i < sz; i++) { - PROCESS(); - } - flush_cache(); - TRACE("propagate_booleans", tout << "middle:\n"; display(tout);); - i = sz; - while (i > m_asserted_qhead) { - --i; - PROCESS(); - } - flush_cache(); - TRACE("propagate_booleans", tout << "after:\n"; display(tout);); - } - if (modified) - reduce_asserted_formulas(); -} - -#define MK_SIMPLIFIER(NAME, FUNCTOR, TAG, MSG, REDUCE) \ - bool asserted_formulas::NAME() { \ - IF_IVERBOSE(10, verbose_stream() << "(smt." << MSG << ")\n";); \ - TRACE(TAG, ast_mark visited; display_ll(tout, visited);); \ - FUNCTOR; \ - bool changed = false; \ - expr_ref_vector new_exprs(m); \ - proof_ref_vector new_prs(m); \ - unsigned i = m_asserted_qhead; \ - unsigned sz = m_asserted_formulas.size(); \ - for (; i < sz; i++) { \ - expr * n = m_asserted_formulas.get(i); \ - proof * pr = m_asserted_formula_prs.get(i, 0); \ - expr_ref new_n(m); \ - proof_ref new_pr(m); \ - functor(n, new_n, new_pr); \ - if (n == new_n.get()) { \ - push_assertion(n, pr, new_exprs, new_prs); \ - } \ - else if (m.proofs_enabled()) { \ - changed = true; \ - if (!new_pr) new_pr = m.mk_rewrite(n, new_n); \ - new_pr = m.mk_modus_ponens(pr, new_pr); \ - push_assertion(new_n, new_pr, new_exprs, new_prs); \ - } \ - else { \ - changed = true; \ - push_assertion(new_n, 0, new_exprs, new_prs); \ - } \ - } \ - swap_asserted_formulas(new_exprs, new_prs); \ - TRACE(TAG, ast_mark visited; display_ll(tout, visited);); \ - if (changed && REDUCE) { \ - reduce_and_solve(); \ - TRACE(TAG, ast_mark visited; display_ll(tout, visited);); \ - } \ - return changed; \ - } - -MK_SIMPLIFIER(pull_cheap_ite_trees, pull_cheap_ite_tree_star functor(m, m_simplifier), "pull_cheap_ite_trees", "pull-cheap-ite-trees", false); - -MK_SIMPLIFIER(pull_nested_quantifiers, pull_nested_quant functor(m), "pull_nested_quantifiers", "pull-nested-quantifiers", false); - proof * asserted_formulas::get_inconsistency_proof() const { if (!inconsistent()) return 0; if (!m.proofs_enabled()) return 0; - unsigned sz = m_asserted_formulas.size(); - for (unsigned i = 0; i < sz; i++) { - expr * f = m_asserted_formulas.get(i); - if (m.is_false(f)) - return m_asserted_formula_prs.get(i); + for (justified_expr const& j : m_formulas) { + if (m.is_false(j.get_fml())) + return j.get_proof(); } UNREACHABLE(); return 0; } -void asserted_formulas::refine_inj_axiom() { - IF_IVERBOSE(10, verbose_stream() << "(smt.refine-injectivity)\n";); - TRACE("inj_axiom", display(tout);); - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); - for (; i < sz; i++) { - expr * n = m_asserted_formulas.get(i); - proof * pr = m_asserted_formula_prs.get(i, 0); - expr_ref new_n(m); - if (is_quantifier(n) && simplify_inj_axiom(m, to_quantifier(n), new_n)) { - TRACE("inj_axiom", tout << "simplifying...\n" << mk_pp(n, m) << "\n" << mk_pp(new_n, m) << "\n";); - m_asserted_formulas.set(i, new_n); - if (m.proofs_enabled()) { - proof_ref new_pr(m); - new_pr = m.mk_rewrite(n, new_n); - new_pr = m.mk_modus_ponens(pr, new_pr); - m_asserted_formula_prs.set(i, new_pr); - } - } +void asserted_formulas::refine_inj_axiom_fn::simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { + expr* f = j.get_fml(); + if (is_quantifier(f) && simplify_inj_axiom(m, to_quantifier(f), n)) { + TRACE("inj_axiom", tout << "simplifying...\n" << mk_pp(f, m) << "\n" << n << "\n";); + } + else { + n = j.get_fml(); } - TRACE("inj_axiom", display(tout);); } -MK_SIMPLIFIER(apply_bit2int, bit2int& functor = m_bit2int, "bit2int", "propagate-bit-vector-over-integers", true); - -MK_SIMPLIFIER(cheap_quant_fourier_motzkin, elim_bounds_star functor(m), "elim_bounds", "cheap-fourier-motzkin", true); - - - -MK_SIMPLIFIER(elim_bvs_from_quantifiers, bv_elim_star functor(m), "bv_elim", "eliminate-bit-vectors-from-quantifiers", true); - -#define LIFT_ITE(NAME, FUNCTOR, MSG) \ - void asserted_formulas::NAME() { \ - IF_IVERBOSE(10, verbose_stream() << "(smt." << MSG << ")\n";); \ - TRACE("lift_ite", display(tout);); \ - FUNCTOR; \ - unsigned i = m_asserted_qhead; \ - unsigned sz = m_asserted_formulas.size(); \ - for (; i < sz; i++) { \ - expr * n = m_asserted_formulas.get(i); \ - proof * pr = m_asserted_formula_prs.get(i, 0); \ - expr_ref new_n(m); \ - proof_ref new_pr(m); \ - functor(n, new_n, new_pr); \ - TRACE("lift_ite_step", tout << mk_pp(n, m) << "\n";); \ - IF_IVERBOSE(10000, verbose_stream() << "lift before: " << get_num_exprs(n) << ", after: " << get_num_exprs(new_n) << "\n";); \ - m_asserted_formulas.set(i, new_n); \ - if (m.proofs_enabled()) { \ - new_pr = m.mk_modus_ponens(pr, new_pr); \ - m_asserted_formula_prs.set(i, new_pr); \ - } \ - } \ - TRACE("lift_ite", display(tout);); \ - reduce_and_solve(); \ - } - -LIFT_ITE(lift_ite, push_app_ite functor(m_simplifier, m_params.m_lift_ite == LI_CONSERVATIVE), "lifting ite"); -LIFT_ITE(ng_lift_ite, ng_push_app_ite functor(m_simplifier, m_params.m_ng_lift_ite == LI_CONSERVATIVE), "lifting ng ite"); unsigned asserted_formulas::get_total_size() const { expr_mark visited; unsigned r = 0; - unsigned sz = m_asserted_formulas.size(); - for (unsigned i = 0; i < sz; i++) - r += get_num_exprs(m_asserted_formulas.get(i), visited); + for (justified_expr const& j : m_formulas) + r += get_num_exprs(j.get_fml(), visited); return r; } -void asserted_formulas::max_bv_sharing() { - IF_IVERBOSE(10, verbose_stream() << "(smt.maximizing-bv-sharing)\n";); - TRACE("bv_sharing", display(tout);); - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); - for (; i < sz; i++) { - expr * n = m_asserted_formulas.get(i); - proof * pr = m_asserted_formula_prs.get(i, 0); - expr_ref new_n(m); - proof_ref new_pr(m); - m_bv_sharing(n, new_n, new_pr); - m_asserted_formulas.set(i, new_n); - if (m.proofs_enabled()) { - new_pr = m.mk_modus_ponens(pr, new_pr); - m_asserted_formula_prs.set(i, new_pr); - } - } - reduce_asserted_formulas(); - TRACE("bv_sharing", display(tout);); - -} - #ifdef Z3DEBUG void pp(asserted_formulas & f) { f.display(std::cout); } #endif + diff --git a/src/smt/asserted_formulas.h b/src/smt/asserted_formulas.h index f5d43a254..88c9e13a7 100644 --- a/src/smt/asserted_formulas.h +++ b/src/smt/asserted_formulas.h @@ -19,82 +19,207 @@ Revision History: #ifndef ASSERTED_FORMULAS_H_ #define ASSERTED_FORMULAS_H_ -#include "smt/params/smt_params.h" -#include "ast/simplifier/simplifier.h" -#include "ast/simplifier/basic_simplifier_plugin.h" +#include "util/statistics.h" #include "ast/static_features.h" +#include "ast/expr_substitution.h" +#include "ast/rewriter/th_rewriter.h" +#include "ast/rewriter/bit2int.h" +#include "ast/rewriter/maximize_ac_sharing.h" +#include "ast/rewriter/distribute_forall.h" +#include "ast/rewriter/pull_ite_tree.h" +#include "ast/rewriter/push_app_ite.h" +#include "ast/rewriter/inj_axiom.h" +#include "ast/rewriter/bv_elim.h" +#include "ast/rewriter/der.h" +#include "ast/rewriter/elim_bounds.h" #include "ast/macros/macro_manager.h" #include "ast/macros/macro_finder.h" #include "ast/normal_forms/defined_names.h" -#include "ast/simplifier/maximise_ac_sharing.h" -#include "ast/simplifier/bit2int.h" -#include "util/statistics.h" +#include "ast/normal_forms/pull_quant.h" #include "ast/pattern/pattern_inference.h" +#include "smt/params/smt_params.h" +#include "smt/elim_term_ite.h" -class arith_simplifier_plugin; -class bv_simplifier_plugin; class asserted_formulas { - ast_manager & m; - smt_params & m_params; - simplifier m_pre_simplifier; - simplifier m_simplifier; - basic_simplifier_plugin * m_bsimp; - bv_simplifier_plugin * m_bvsimp; - defined_names m_defined_names; - static_features m_static_features; - expr_ref_vector m_asserted_formulas; // formulas asserted by user - proof_ref_vector m_asserted_formula_prs; // proofs for the asserted formulas. - unsigned m_asserted_qhead; - + + ast_manager & m; + smt_params & m_params; + th_rewriter m_rewriter; + expr_substitution m_substitution; + scoped_expr_substitution m_scoped_substitution; + defined_names m_defined_names; + static_features m_static_features; + vector m_formulas; + unsigned m_qhead; + bool m_elim_and; macro_manager m_macro_manager; - scoped_ptr m_macro_finder; - - bit2int m_bit2int; - - maximise_bv_sharing m_bv_sharing; - + scoped_ptr m_macro_finder; + maximize_bv_sharing_rw m_bv_sharing; bool m_inconsistent; - + bool m_has_quantifiers; struct scope { - unsigned m_asserted_formulas_lim; + unsigned m_formulas_lim; bool m_inconsistent_old; }; svector m_scopes; + obj_map m_expr2depth; + + class simplify_fmls { + protected: + asserted_formulas& af; + ast_manager& m; + char const* m_id; + public: + simplify_fmls(asserted_formulas& af, char const* id): af(af), m(af.m), m_id(id) {} + char const* id() const { return m_id; } + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) = 0; + virtual bool should_apply() const { return true;} + virtual void post_op() {} + virtual void operator()(); + }; + + class reduce_asserted_formulas_fn : public simplify_fmls { + public: + reduce_asserted_formulas_fn(asserted_formulas& af): simplify_fmls(af, "reduce-asserted") {} + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { af.m_rewriter(j.get_fml(), n, p); } + }; + + class find_macros_fn : public simplify_fmls { + public: + find_macros_fn(asserted_formulas& af): simplify_fmls(af, "find-macros") {} + virtual void operator()() { af.find_macros_core(); } + virtual bool should_apply() const { return af.m_params.m_macro_finder && af.has_quantifiers(); } + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { UNREACHABLE(); } + }; + + class apply_quasi_macros_fn : public simplify_fmls { + public: + apply_quasi_macros_fn(asserted_formulas& af): simplify_fmls(af, "find-quasi-macros") {} + virtual void operator()() { af.apply_quasi_macros(); } + virtual bool should_apply() const { return af.m_params.m_quasi_macros && af.has_quantifiers(); } + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { UNREACHABLE(); } + }; + + class nnf_cnf_fn : public simplify_fmls { + public: + nnf_cnf_fn(asserted_formulas& af): simplify_fmls(af, "nnf-cnf") {} + virtual void operator()() { af.nnf_cnf(); } + virtual bool should_apply() const { return af.m_params.m_nnf_cnf || (af.m_params.m_mbqi && af.has_quantifiers()); } + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { UNREACHABLE(); } + }; + + class propagate_values_fn : public simplify_fmls { + public: + propagate_values_fn(asserted_formulas& af): simplify_fmls(af, "propagate-values") {} + virtual void operator()() { af.propagate_values(); } + virtual bool should_apply() const { return af.m_params.m_propagate_values; } + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { UNREACHABLE(); } + }; + + class distribute_forall_fn : public simplify_fmls { + distribute_forall m_functor; + public: + distribute_forall_fn(asserted_formulas& af): simplify_fmls(af, "distribute-forall"), m_functor(af.m) {} + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { m_functor(j.get_fml(), n); } + virtual bool should_apply() const { return af.m_params.m_distribute_forall && af.has_quantifiers(); } + virtual void post_op() { af.reduce_and_solve(); TRACE("asserted_formulas", af.display(tout);); } + }; + + class pattern_inference_fn : public simplify_fmls { + pattern_inference_rw m_infer; + public: + pattern_inference_fn(asserted_formulas& af): simplify_fmls(af, "pattern-inference"), m_infer(af.m, af.m_params) {} + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { m_infer(j.get_fml(), n, p); } + virtual bool should_apply() const { return af.m_params.m_ematching && af.has_quantifiers(); } + }; + + class refine_inj_axiom_fn : public simplify_fmls { + public: + refine_inj_axiom_fn(asserted_formulas& af): simplify_fmls(af, "refine-injectivity") {} + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p); + virtual bool should_apply() const { return af.m_params.m_refine_inj_axiom && af.has_quantifiers(); } + }; + + class max_bv_sharing_fn : public simplify_fmls { + public: + max_bv_sharing_fn(asserted_formulas& af): simplify_fmls(af, "maximizing-bv-sharing") {} + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { af.m_bv_sharing(j.get_fml(), n, p); } + virtual bool should_apply() const { return af.m_params.m_max_bv_sharing; } + virtual void post_op() { af.m_reduce_asserted_formulas(); } + }; + + class elim_term_ite_fn : public simplify_fmls { + elim_term_ite_rw m_elim; + public: + elim_term_ite_fn(asserted_formulas& af): simplify_fmls(af, "elim-term-ite"), m_elim(af.m, af.m_defined_names) {} + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { m_elim(j.get_fml(), n, p); } + virtual bool should_apply() const { return af.m_params.m_eliminate_term_ite && af.m_params.m_lift_ite != LI_FULL; } + virtual void post_op() { af.m_formulas.append(m_elim.new_defs()); af.reduce_and_solve(); m_elim.reset(); } + }; + +#define MK_SIMPLIFIERA(NAME, FUNCTOR, MSG, APP, ARG, REDUCE) \ + class NAME : public simplify_fmls { \ + FUNCTOR m_functor; \ + public: \ + NAME(asserted_formulas& af):simplify_fmls(af, MSG), m_functor ARG {} \ + virtual void simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { \ + m_functor(j.get_fml(), n, p); \ + } \ + virtual void post_op() { if (REDUCE) af.reduce_and_solve(); } \ + virtual bool should_apply() const { return APP; } \ + }; \ + +#define MK_SIMPLIFIERF(NAME, FUNCTOR, MSG, APP, REDUCE) MK_SIMPLIFIERA(NAME, FUNCTOR, MSG, APP, (af.m), REDUCE) + + MK_SIMPLIFIERF(pull_cheap_ite_trees, pull_cheap_ite_tree_rw, "pull-cheap-ite-trees", af.m_params.m_pull_cheap_ite_trees, false); + MK_SIMPLIFIERF(pull_nested_quantifiers, pull_nested_quant, "pull-nested-quantifiers", af.m_params.m_pull_nested_quantifiers && af.has_quantifiers(), false); + MK_SIMPLIFIERF(cheap_quant_fourier_motzkin, elim_bounds_rw, "cheap-fourier-motzkin", af.m_params.m_eliminate_bounds && af.has_quantifiers(), true); + MK_SIMPLIFIERF(elim_bvs_from_quantifiers, bv_elim_rw, "eliminate-bit-vectors-from-quantifiers", af.m_params.m_bb_quantifiers, true); + MK_SIMPLIFIERF(apply_bit2int, bit2int, "propagate-bit-vector-over-integers", af.m_params.m_simplify_bit2int, true); + MK_SIMPLIFIERA(lift_ite, push_app_ite_rw, "lift-ite", af.m_params.m_lift_ite != LI_NONE, (af.m, af.m_params.m_lift_ite == LI_CONSERVATIVE), true); + MK_SIMPLIFIERA(ng_lift_ite, ng_push_app_ite_rw, "lift-ite", af.m_params.m_ng_lift_ite != LI_NONE, (af.m, af.m_params.m_ng_lift_ite == LI_CONSERVATIVE), true); + + + reduce_asserted_formulas_fn m_reduce_asserted_formulas; + distribute_forall_fn m_distribute_forall; + pattern_inference_fn m_pattern_inference; + refine_inj_axiom_fn m_refine_inj_axiom; + max_bv_sharing_fn m_max_bv_sharing_fn; + elim_term_ite_fn m_elim_term_ite; + pull_cheap_ite_trees m_pull_cheap_ite_trees; + pull_nested_quantifiers m_pull_nested_quantifiers; + elim_bvs_from_quantifiers m_elim_bvs_from_quantifiers; + cheap_quant_fourier_motzkin m_cheap_quant_fourier_motzkin; + apply_bit2int m_apply_bit2int; + lift_ite m_lift_ite; + ng_lift_ite m_ng_lift_ite; + find_macros_fn m_find_macros; + propagate_values_fn m_propagate_values; + nnf_cnf_fn m_nnf_cnf; + apply_quasi_macros_fn m_apply_quasi_macros; + + bool invoke(simplify_fmls& s); + void swap_asserted_formulas(vector& new_fmls); + void push_assertion(expr * e, proof * pr, vector& result); + bool canceled() { return m.canceled(); } + bool check_well_sorted() const; + unsigned get_total_size() const; - void setup_simplifier_plugins(simplifier & s, basic_simplifier_plugin * & bsimp, arith_simplifier_plugin * & asimp, bv_simplifier_plugin * & bvsimp); - void reduce_asserted_formulas(); - void swap_asserted_formulas(expr_ref_vector & new_exprs, proof_ref_vector & new_prs); void find_macros_core(); - void find_macros(); void expand_macros(); void apply_quasi_macros(); void nnf_cnf(); - void infer_patterns(); - void eliminate_term_ite(); void reduce_and_solve(); - void flush_cache() { m_pre_simplifier.reset(); m_simplifier.reset(); } + void flush_cache() { m_rewriter.reset(); m_rewriter.set_substitution(&m_substitution); } void set_eliminate_and(bool flag); void propagate_values(); - void propagate_booleans(); + unsigned propagate_values(unsigned i); + void update_substitution(expr* n, proof* p); + bool is_gt(expr* lhs, expr* rhs); + void compute_depth(expr* e); + unsigned depth(expr* e) { return m_expr2depth[e]; } bool pull_cheap_ite_trees(); - bool pull_nested_quantifiers(); - void push_assertion(expr * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs); - void eliminate_and(); - void refine_inj_axiom(); - bool cheap_quant_fourier_motzkin(); - void apply_distribute_forall(); - bool apply_bit2int(); - void lift_ite(); - bool elim_bvs_from_quantifiers(); - void ng_lift_ite(); -#ifdef Z3DEBUG - bool check_well_sorted() const; -#endif - unsigned get_total_size() const; - bool has_bv() const; - void max_bv_sharing(); - bool canceled() { return m.canceled(); } void init(unsigned num_formulas, expr * const * formulas, proof * const * prs); @@ -102,6 +227,7 @@ public: asserted_formulas(ast_manager & m, smt_params & p); ~asserted_formulas(); + bool has_quantifiers() const { return m_has_quantifiers; } void setup(); void assert_expr(expr * e, proof * in_pr); void assert_expr(expr * e); @@ -111,26 +237,21 @@ public: bool inconsistent() const { return m_inconsistent; } proof * get_inconsistency_proof() const; void reduce(); - unsigned get_num_formulas() const { return m_asserted_formulas.size(); } + unsigned get_num_formulas() const { return m_formulas.size(); } unsigned get_formulas_last_level() const; - unsigned get_qhead() const { return m_asserted_qhead; } - void commit(); - void commit(unsigned new_qhead); - expr * get_formula(unsigned idx) const { return m_asserted_formulas.get(idx); } - proof * get_formula_proof(unsigned idx) const { return m.proofs_enabled() ? m_asserted_formula_prs.get(idx) : 0; } - expr * const * get_formulas() const { return m_asserted_formulas.c_ptr(); } - proof * const * get_formula_proofs() const { return m_asserted_formula_prs.c_ptr(); } - void register_simplifier_plugin(simplifier_plugin * p) { m_simplifier.register_plugin(p); } - simplifier & get_simplifier() { return m_simplifier; } - void get_assertions(ptr_vector & result); - bool empty() const { return m_asserted_formulas.empty(); } - void collect_static_features(); + unsigned get_qhead() const { return m_qhead; } + void commit(); + void commit(unsigned new_qhead); + expr * get_formula(unsigned idx) const { return m_formulas[idx].get_fml(); } + proof * get_formula_proof(unsigned idx) const { return m_formulas[idx].get_proof(); } + + th_rewriter & get_rewriter() { return m_rewriter; } + void get_assertions(ptr_vector & result) const; + bool empty() const { return m_formulas.empty(); } void display(std::ostream & out) const; void display_ll(std::ostream & out, ast_mark & pp_visited) const; void collect_statistics(statistics & st) const; - // TODO: improve precision of the following method. - bool has_quantifiers() const { return m_simplifier.visited_quantifier(); /* approximation */ } - + // ----------------------------------- // // Macros @@ -141,7 +262,10 @@ public: func_decl * get_macro_func_decl(unsigned i) const { return m_macro_manager.get_macro_func_decl(i); } func_decl * get_macro_interpretation(unsigned i, expr_ref & interp) const { return m_macro_manager.get_macro_interpretation(i, interp); } quantifier * get_macro_quantifier(func_decl * f) const { return m_macro_manager.get_macro_quantifier(f); } - void insert_macro(func_decl * f, quantifier * m, proof * pr, expr_dependency * dep) { m_macro_manager.insert(f, m, pr, dep); } + // auxiliary function used to create a logic context based on a model. + void insert_macro(func_decl * f, quantifier * m, proof * pr) { m_macro_manager.insert(f, m, pr); } + void insert_macro(func_decl * f, quantifier * m, proof * pr, expr_dependency* dep) { m_macro_manager.insert(f, m, pr, dep); } + }; #endif /* ASSERTED_FORMULAS_H_ */ diff --git a/src/smt/elim_term_ite.cpp b/src/smt/elim_term_ite.cpp index b750e6bf5..e8b70fc59 100644 --- a/src/smt/elim_term_ite.cpp +++ b/src/smt/elim_term_ite.cpp @@ -19,142 +19,22 @@ Revision History: #include "smt/elim_term_ite.h" #include "ast/ast_smt2_pp.h" -void elim_term_ite::operator()(expr * n, - expr_ref_vector & new_defs, - proof_ref_vector & new_def_proofs, - expr_ref & r, - proof_ref & pr) { - - m_coarse_proofs.reset(); - m_new_defs = &new_defs; - m_new_def_proofs = &new_def_proofs; - reduce_core(n); - expr * r2; - proof * pr2; - get_cached(n, r2, pr2); - r = r2; - switch (m.proof_mode()) { - case PGM_DISABLED: - pr = m.mk_undef_proof(); - break; - case PGM_COARSE: - remove_duplicates(m_coarse_proofs); - pr = n == r2 ? m.mk_oeq_reflexivity(n) : m.mk_apply_defs(n, r, m_coarse_proofs.size(), m_coarse_proofs.c_ptr()); - break; - case PGM_FINE: - pr = pr2 == 0 ? m.mk_oeq_reflexivity(n) : pr2; - break; +br_status elim_term_ite_cfg::reduce_app(func_decl* f, unsigned n, expr * const* args, expr_ref& result, proof_ref& result_pr) { + if (!m.is_term_ite(f)) { + return BR_FAILED; } - m_coarse_proofs.reset(); + + expr_ref new_def(m); + proof_ref new_def_pr(m); + app_ref r(m.mk_app(f, n, args), m); + app_ref new_r(m); + if (!m_defined_names.mk_name(r, new_def, new_def_pr, new_r, result_pr)) { + return BR_FAILED; + } + result = new_r; + + CTRACE("elim_term_ite_bug", new_def.get() == 0, tout << mk_ismt2_pp(r, m) << "\n";); + m_new_defs.push_back(justified_expr(m, new_def, new_def_pr)); + return BR_DONE; } -void elim_term_ite::reduce_core(expr * n) { - m_todo.reset(); - if (!is_cached(n)) { - m_todo.push_back(n); - while (!m_todo.empty()) { - 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 elim_term_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 elim_term_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 elim_term_ite::reduce1_app(app * n) { - m_args.reset(); - - func_decl * decl = n->get_decl(); - proof_ref p1(m); - get_args(n, m_args, p1); - if (!m.fine_grain_proofs()) - p1 = 0; - - expr_ref r(m); - r = m.mk_app(decl, m_args.size(), m_args.c_ptr()); - if (m.is_term_ite(r)) { - expr_ref new_def(m); - proof_ref new_def_pr(m); - app_ref new_r(m); - proof_ref new_pr(m); - if (m_defined_names.mk_name(r, new_def, new_def_pr, new_r, new_pr)) { - CTRACE("elim_term_ite_bug", new_def.get() == 0, tout << mk_ismt2_pp(r, m) << "\n";); - SASSERT(new_def.get() != 0); - m_new_defs->push_back(new_def); - if (m.fine_grain_proofs()) { - m_new_def_proofs->push_back(new_def_pr); - new_pr = m.mk_transitivity(p1, new_pr); - } - else { - // [Leo] This looks fishy... why do we add 0 into m_coarse_proofs when fine_grain_proofs are disabled? - new_pr = 0; - if (m.proofs_enabled()) - m_coarse_proofs.push_back(new_pr); - } - } - else { - SASSERT(new_def.get() == 0); - if (!m.fine_grain_proofs()) - new_pr = 0; - } - cache_result(n, new_r, new_pr); - } - else { - cache_result(n, r, p1); - } -} - -void elim_term_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_oeq_quant_intro(q, new_q, new_body_pr); - cache_result(q, new_q, p); -} - - - diff --git a/src/smt/elim_term_ite.h b/src/smt/elim_term_ite.h index 2b9c66a64..8e8340dc0 100644 --- a/src/smt/elim_term_ite.h +++ b/src/smt/elim_term_ite.h @@ -19,32 +19,36 @@ Revision History: #ifndef ELIM_TERM_ITE_H_ #define ELIM_TERM_ITE_H_ -#include "ast/simplifier/simplifier.h" #include "ast/normal_forms/defined_names.h" +#include "ast/rewriter/rewriter.h" +#include "ast/justified_expr.h" -class elim_term_ite : public simplifier { - defined_names & m_defined_names; - proof_ref_vector m_coarse_proofs; - expr_ref_vector * m_new_defs; - proof_ref_vector * m_new_def_proofs; - void reduce_core(expr * n); - bool visit_children(expr * n); - void reduce1(expr * n); - void reduce1_app(app * n); - void reduce1_quantifier(quantifier * q); +class elim_term_ite_cfg : public default_rewriter_cfg { + ast_manager& m; + defined_names & m_defined_names; + vector m_new_defs; public: - elim_term_ite(ast_manager & m, defined_names & d):simplifier(m), m_defined_names(d), m_coarse_proofs(m) { - m_use_oeq = true; - enable_ac_support(false); + elim_term_ite_cfg(ast_manager & m, defined_names & d): m(m), m_defined_names(d) { + // TBD enable_ac_support(false); } - virtual ~elim_term_ite() {} - void operator()(expr * n, // [IN] - expr_ref_vector & new_defs, // [OUT] new definitions - proof_ref_vector & new_def_proofs, // [OUT] proofs of the new definitions - expr_ref & r, // [OUT] resultant expression - proof_ref & pr // [OUT] proof for (~ n r) - ); + virtual ~elim_term_ite_cfg() {} + vector const& new_defs() const { return m_new_defs; } + void reset() { m_new_defs.reset(); } + br_status reduce_app(func_decl* f, unsigned n, expr *const* args, expr_ref& result, proof_ref& result_pr); }; +class elim_term_ite_rw : public rewriter_tpl { + elim_term_ite_cfg m_cfg; +public: + elim_term_ite_rw(ast_manager& m, defined_names & dn): + rewriter_tpl(m, m.proofs_enabled(), m_cfg), + m_cfg(m, dn) + {} + vector const& new_defs() const { return m_cfg.new_defs(); } + void reset() { m_cfg.reset(); } +}; + + + #endif /* ELIM_TERM_ITE_H_ */ diff --git a/src/smt/expr_context_simplifier.h b/src/smt/expr_context_simplifier.h index ed15044e7..b412d8646 100644 --- a/src/smt/expr_context_simplifier.h +++ b/src/smt/expr_context_simplifier.h @@ -21,10 +21,10 @@ Revision History: #include "ast/ast.h" #include "util/obj_hashtable.h" -#include "ast/simplifier/basic_simplifier_plugin.h" #include "smt/params/smt_params.h" #include "smt/smt_kernel.h" #include "ast/arith_decl_plugin.h" +#include "ast/rewriter/bool_rewriter.h" class expr_context_simplifier { typedef obj_map context_map; @@ -33,7 +33,7 @@ class expr_context_simplifier { arith_util m_arith; context_map m_context; expr_ref_vector m_trail; - basic_simplifier_plugin m_simp; + bool_rewriter m_simp; expr_mark m_mark; bool m_forward; public: diff --git a/src/smt/params/CMakeLists.txt b/src/smt/params/CMakeLists.txt index 500423dcc..c965f0a62 100644 --- a/src/smt/params/CMakeLists.txt +++ b/src/smt/params/CMakeLists.txt @@ -13,7 +13,6 @@ z3_add_component(smt_params ast bit_blaster pattern - simplifier PYG_FILES smt_params_helper.pyg ) diff --git a/src/smt/params/preprocessor_params.cpp b/src/smt/params/preprocessor_params.cpp index 679cd0f39..93ea794fa 100644 --- a/src/smt/params/preprocessor_params.cpp +++ b/src/smt/params/preprocessor_params.cpp @@ -30,8 +30,6 @@ void preprocessor_params::updt_local_params(params_ref const & _p) { void preprocessor_params::updt_params(params_ref const & p) { pattern_inference_params::updt_params(p); - bv_simplifier_params::updt_params(p); - arith_simplifier_params::updt_params(p); updt_local_params(p); } @@ -40,15 +38,12 @@ void preprocessor_params::updt_params(params_ref const & p) { void preprocessor_params::display(std::ostream & out) const { pattern_inference_params::display(out); bit_blaster_params::display(out); - bv_simplifier_params::display(out); - arith_simplifier_params::display(out); DISPLAY_PARAM(m_lift_ite); DISPLAY_PARAM(m_ng_lift_ite); DISPLAY_PARAM(m_pull_cheap_ite_trees); DISPLAY_PARAM(m_pull_nested_quantifiers); DISPLAY_PARAM(m_eliminate_term_ite); - DISPLAY_PARAM(m_eliminate_and); DISPLAY_PARAM(m_macro_finder); DISPLAY_PARAM(m_propagate_values); DISPLAY_PARAM(m_propagate_booleans); diff --git a/src/smt/params/preprocessor_params.h b/src/smt/params/preprocessor_params.h index c343c55fa..dc16d6244 100644 --- a/src/smt/params/preprocessor_params.h +++ b/src/smt/params/preprocessor_params.h @@ -21,8 +21,6 @@ Revision History: #include "ast/pattern/pattern_inference_params.h" #include "ast/rewriter/bit_blaster/bit_blaster_params.h" -#include "ast/simplifier/bv_simplifier_params.h" -#include "ast/simplifier/arith_simplifier_params.h" enum lift_ite_kind { LI_NONE, @@ -31,15 +29,12 @@ enum lift_ite_kind { }; struct preprocessor_params : public pattern_inference_params, - public bit_blaster_params, - public bv_simplifier_params, - public arith_simplifier_params { + public bit_blaster_params { lift_ite_kind m_lift_ite; lift_ite_kind m_ng_lift_ite; // lift ite for non ground terms bool m_pull_cheap_ite_trees; bool m_pull_nested_quantifiers; bool m_eliminate_term_ite; - bool m_eliminate_and; // represent (and a b) as (not (or (not a) (not b))) bool m_macro_finder; bool m_propagate_values; bool m_propagate_booleans; @@ -62,7 +57,6 @@ public: m_pull_cheap_ite_trees(false), m_pull_nested_quantifiers(false), m_eliminate_term_ite(false), - m_eliminate_and(true), m_macro_finder(false), m_propagate_values(true), m_propagate_booleans(false), // TODO << check peformance diff --git a/src/smt/params/theory_arith_params.cpp b/src/smt/params/theory_arith_params.cpp index 2b5a14493..250848db4 100644 --- a/src/smt/params/theory_arith_params.cpp +++ b/src/smt/params/theory_arith_params.cpp @@ -18,6 +18,7 @@ Revision History: --*/ #include "smt/params/theory_arith_params.h" #include "smt/params/smt_params_helper.hpp" +#include "ast/rewriter/arith_rewriter_params.hpp" void theory_arith_params::updt_params(params_ref const & _p) { smt_params_helper p(_p); @@ -36,12 +37,16 @@ void theory_arith_params::updt_params(params_ref const & _p) { m_arith_bound_prop = static_cast(p.arith_propagation_mode()); m_arith_dump_lemmas = p.arith_dump_lemmas(); m_arith_reflect = p.arith_reflect(); + arith_rewriter_params ap(_p); + m_arith_eq2ineq = ap.eq2ineq(); } #define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; void theory_arith_params::display(std::ostream & out) const { + DISPLAY_PARAM(m_arith_eq2ineq); + DISPLAY_PARAM(m_arith_process_all_eqs); DISPLAY_PARAM(m_arith_mode); DISPLAY_PARAM(m_arith_auto_config_simplex); //!< force simplex solver in auto_config DISPLAY_PARAM(m_arith_blands_rule_threshold); diff --git a/src/smt/params/theory_arith_params.h b/src/smt/params/theory_arith_params.h index d73a67985..1fe7e1163 100644 --- a/src/smt/params/theory_arith_params.h +++ b/src/smt/params/theory_arith_params.h @@ -49,6 +49,8 @@ enum arith_pivot_strategy { }; struct theory_arith_params { + bool m_arith_eq2ineq; + bool m_arith_process_all_eqs; arith_solver_id m_arith_mode; bool m_arith_auto_config_simplex; //!< force simplex solver in auto_config unsigned m_arith_blands_rule_threshold; @@ -108,6 +110,8 @@ struct theory_arith_params { theory_arith_params(params_ref const & p = params_ref()): + m_arith_eq2ineq(false), + m_arith_process_all_eqs(false), m_arith_mode(AS_ARITH), m_arith_auto_config_simplex(false), m_arith_blands_rule_threshold(1000), diff --git a/src/smt/params/theory_array_params.h b/src/smt/params/theory_array_params.h index af3fdebeb..edda4d7cf 100644 --- a/src/smt/params/theory_array_params.h +++ b/src/smt/params/theory_array_params.h @@ -19,7 +19,7 @@ Revision History: #ifndef THEORY_ARRAY_PARAMS_H_ #define THEORY_ARRAY_PARAMS_H_ -#include "ast/simplifier/array_simplifier_params.h" +#include "util/params.h" enum array_solver_id { AR_NO_ARRAY, @@ -28,7 +28,9 @@ enum array_solver_id { AR_FULL }; -struct theory_array_params : public array_simplifier_params { +struct theory_array_params { + bool m_array_canonize_simplify; + bool m_array_simplify; // temporary hack for disabling array simplifier plugin. array_solver_id m_array_mode; bool m_array_weak; bool m_array_extensional; @@ -40,6 +42,8 @@ struct theory_array_params : public array_simplifier_params { unsigned m_array_lazy_ieq_delay; theory_array_params(): + m_array_canonize_simplify(false), + m_array_simplify(true), m_array_mode(AR_FULL), m_array_weak(false), m_array_extensional(true), diff --git a/src/smt/params/theory_bv_params.cpp b/src/smt/params/theory_bv_params.cpp index 4b4808a1f..156fda592 100644 --- a/src/smt/params/theory_bv_params.cpp +++ b/src/smt/params/theory_bv_params.cpp @@ -18,9 +18,12 @@ Revision History: --*/ #include "smt/params/theory_bv_params.h" #include "smt/params/smt_params_helper.hpp" +#include "ast/rewriter/bv_rewriter_params.hpp" void theory_bv_params::updt_params(params_ref const & _p) { smt_params_helper p(_p); + bv_rewriter_params rp(_p); + m_hi_div0 = rp.hi_div0(); m_bv_reflect = p.bv_reflect(); m_bv_enable_int2bv2int = p.bv_enable_int2bv(); } @@ -29,9 +32,10 @@ void theory_bv_params::updt_params(params_ref const & _p) { void theory_bv_params::display(std::ostream & out) const { DISPLAY_PARAM(m_bv_mode); + DISPLAY_PARAM(m_hi_div0); DISPLAY_PARAM(m_bv_reflect); DISPLAY_PARAM(m_bv_lazy_le); DISPLAY_PARAM(m_bv_cc); DISPLAY_PARAM(m_bv_blast_max_size); DISPLAY_PARAM(m_bv_enable_int2bv2int); -} \ No newline at end of file +} diff --git a/src/smt/params/theory_bv_params.h b/src/smt/params/theory_bv_params.h index 52aaa4c9c..e0bff3f17 100644 --- a/src/smt/params/theory_bv_params.h +++ b/src/smt/params/theory_bv_params.h @@ -28,6 +28,7 @@ enum bv_solver_id { struct theory_bv_params { bv_solver_id m_bv_mode; + bool m_hi_div0; //!< if true, uses the hardware interpretation for div0, mod0, ... if false, div0, mod0, ... are considered uninterpreted. bool m_bv_reflect; bool m_bv_lazy_le; bool m_bv_cc; @@ -35,6 +36,7 @@ struct theory_bv_params { bool m_bv_enable_int2bv2int; theory_bv_params(params_ref const & p = params_ref()): m_bv_mode(BS_BLASTER), + m_hi_div0(false), m_bv_reflect(true), m_bv_lazy_le(false), m_bv_cc(false), diff --git a/src/smt/proto_model/CMakeLists.txt b/src/smt/proto_model/CMakeLists.txt index 0539c0fb0..c5f6c4b18 100644 --- a/src/smt/proto_model/CMakeLists.txt +++ b/src/smt/proto_model/CMakeLists.txt @@ -8,6 +8,6 @@ z3_add_component(proto_model value_factory.cpp COMPONENT_DEPENDENCIES model - simplifier + rewriter smt_params ) diff --git a/src/smt/proto_model/datatype_factory.cpp b/src/smt/proto_model/datatype_factory.cpp index d738f2cbd..03f008fe6 100644 --- a/src/smt/proto_model/datatype_factory.cpp +++ b/src/smt/proto_model/datatype_factory.cpp @@ -88,8 +88,8 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) { // Traverse constructors, and try to invoke get_fresh_value of one of the arguments (if the argument is not a sibling datatype of s). // If the argumet is a sibling datatype of s, then // use get_last_fresh_value. - ptr_vector const * constructors = m_util.get_datatype_constructors(s); - for (func_decl * constructor : *constructors) { + ptr_vector const & constructors = *m_util.get_datatype_constructors(s); + for (func_decl * constructor : constructors) { expr_ref_vector args(m_manager); bool found_fresh_arg = false; bool recursive = false; @@ -151,8 +151,8 @@ expr * datatype_factory::get_fresh_value(sort * s) { // Traverse constructors, and try to invoke get_fresh_value of one of the // arguments (if the argument is not a sibling datatype of s). // Two datatypes are siblings if they were defined together in the same mutually recursive definition. - ptr_vector const * constructors = m_util.get_datatype_constructors(s); - for (func_decl * constructor : *constructors) { + ptr_vector const & constructors = *m_util.get_datatype_constructors(s); + for (func_decl * constructor : constructors) { expr_ref_vector args(m_manager); bool found_fresh_arg = false; unsigned num = constructor->get_arity(); @@ -189,8 +189,8 @@ expr * datatype_factory::get_fresh_value(sort * s) { while(true) { ++num_iterations; TRACE("datatype_factory", tout << mk_pp(get_last_fresh_value(s), m_manager) << "\n";); - ptr_vector const * constructors = m_util.get_datatype_constructors(s); - for (func_decl * constructor : *constructors) { + ptr_vector const & constructors = *m_util.get_datatype_constructors(s); + for (func_decl * constructor : constructors) { expr_ref_vector args(m_manager); bool found_sibling = false; unsigned num = constructor->get_arity(); diff --git a/src/smt/proto_model/proto_model.cpp b/src/smt/proto_model/proto_model.cpp index 9b218037e..0a75ff700 100644 --- a/src/smt/proto_model/proto_model.cpp +++ b/src/smt/proto_model/proto_model.cpp @@ -161,8 +161,10 @@ void proto_model::cleanup_func_interp(func_interp * fi, func_decl_set & found_au continue; } func_decl * f = t->get_decl(); - if (m_aux_decls.contains(f)) + if (m_aux_decls.contains(f)) { + TRACE("model_bug", tout << f->get_name() << "\n";); found_aux_fs.insert(f); + } expr_ref new_t(m_manager); new_t = m_rewrite.mk_app(f, args.size(), args.c_ptr()); if (t != new_t.get()) @@ -180,9 +182,7 @@ void proto_model::cleanup_func_interp(func_interp * fi, func_decl_set & found_au } } - if (!cache.find(fi_else, a)) { - UNREACHABLE(); - } + VERIFY(cache.find(fi_else, a)); fi->set_else(a); } @@ -207,8 +207,10 @@ void proto_model::remove_aux_decls_not_in_set(ptr_vector & decls, fun by their interpretations. */ void proto_model::cleanup() { + TRACE("model_bug", model_v2_pp(tout, *this);); func_decl_set found_aux_fs; for (auto const& kv : m_finterp) { + TRACE("model_bug", tout << kv.m_key->get_name() << "\n";); func_interp * fi = kv.m_value; cleanup_func_interp(fi, found_aux_fs); } @@ -365,7 +367,7 @@ void proto_model::complete_partial_funcs() { } model * proto_model::mk_model() { - TRACE("proto_model", tout << "mk_model\n"; model_v2_pp(tout, *this);); + TRACE("proto_model", model_v2_pp(tout << "mk_model\n", *this);); model * m = alloc(model, m_manager); for (auto const& kv : m_interp) { diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index 36a2ce834..f77fde29a 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -227,9 +227,8 @@ namespace smt { TRACE("qi_queue_instance", tout << "new instance:\n" << mk_pp(instance, m_manager) << "\n";); expr_ref s_instance(m_manager); proof_ref pr(m_manager); - simplifier & simp = m_context.get_simplifier(); - simp(instance, s_instance, pr); - TRACE("qi_queue_bug", tout << "new instance after simplification:\n" << mk_pp(s_instance, m_manager) << "\n";); + m_context.get_rewriter()(instance, s_instance, pr); + TRACE("qi_queue_bug", tout << "new instance after simplification:\n" << s_instance << "\n";); if (m_manager.is_true(s_instance)) { TRACE("checker", tout << "reduced to true, before:\n" << mk_ll_pp(instance, m_manager);); diff --git a/src/smt/smt_consequences.cpp b/src/smt/smt_consequences.cpp index 65af3c0bd..0bf2a2939 100644 --- a/src/smt/smt_consequences.cpp +++ b/src/smt/smt_consequences.cpp @@ -16,12 +16,13 @@ Author: Revision History: --*/ -#include "smt/smt_context.h" -#include "ast/ast_util.h" -#include "ast/datatype_decl_plugin.h" -#include "model/model_pp.h" #include "util/max_cliques.h" #include "util/stopwatch.h" +#include "ast/ast_util.h" +#include "ast/ast_pp.h" +#include "ast/datatype_decl_plugin.h" +#include "model/model_pp.h" +#include "smt/smt_context.h" namespace smt { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index b966b8380..eef84f773 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -224,20 +224,6 @@ namespace smt { void context::copy_plugins(context& src, context& dst) { - // copy missing simplifier_plugins - // remark: some simplifier_plugins are automatically created by the asserted_formulas class. - simplifier & src_s = src.get_simplifier(); - simplifier & dst_s = dst.get_simplifier(); - ptr_vector::const_iterator it1 = src_s.begin_plugins(); - ptr_vector::const_iterator end1 = src_s.end_plugins(); - for (; it1 != end1; ++it1) { - simplifier_plugin * p = *it1; - if (dst_s.get_plugin(p->get_family_id()) == 0) { - dst.register_plugin(p->mk_fresh()); - } - SASSERT(dst_s.get_plugin(p->get_family_id()) != 0); - } - // copy theory plugins for (theory* old_th : src.m_theory_set) { theory * new_th = old_th->mk_fresh(&dst); @@ -2845,11 +2831,6 @@ namespace smt { return false; } - void context::register_plugin(simplifier_plugin * s) { - SASSERT(!already_internalized()); - SASSERT(m_scope_lvl == 0); - m_asserted_formulas.register_simplifier_plugin(s); - } #ifdef Z3DEBUG /** diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 85633b7f4..3cc577b29 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -245,8 +245,8 @@ namespace smt { return m_manager; } - simplifier & get_simplifier() { - return m_asserted_formulas.get_simplifier(); + th_rewriter & get_rewriter() { + return m_asserted_formulas.get_rewriter(); } smt_params & get_fparams() { @@ -1467,8 +1467,6 @@ namespace smt { bool set_logic(symbol const& logic) { return m_setup.set_logic(logic); } - void register_plugin(simplifier_plugin * s); - void register_plugin(theory * th); void assert_expr(expr * e); @@ -1540,9 +1538,9 @@ namespace smt { proof * get_asserted_formula_proof(unsigned idx) const { return m_asserted_formulas.get_formula_proof(idx); } - expr * const * get_asserted_formulas() const { return m_asserted_formulas.get_formulas(); } + void get_asserted_formulas(ptr_vector& r) const { m_asserted_formulas.get_assertions(r); } - proof * const * get_asserted_formula_proofs() const { return m_asserted_formulas.get_formula_proofs(); } + //proof * const * get_asserted_formula_proofs() const { return m_asserted_formulas.get_formula_proofs(); } void get_assumptions_core(ptr_vector & result); diff --git a/src/smt/smt_kernel.cpp b/src/smt/smt_kernel.cpp index e4ce30f91..a7948725c 100644 --- a/src/smt/smt_kernel.cpp +++ b/src/smt/smt_kernel.cpp @@ -60,10 +60,10 @@ namespace smt { // m_kernel.display(out); <<< for external users it is just junk // TODO: it will be replaced with assertion_stack.display unsigned num = m_kernel.get_num_asserted_formulas(); - expr * const * fms = m_kernel.get_asserted_formulas(); out << "(kernel"; for (unsigned i = 0; i < num; i++) { - out << "\n " << mk_ismt2_pp(fms[i], m(), 2); + expr* f = m_kernel.get_asserted_formula(i); + out << "\n " << mk_ismt2_pp(f, m(), 2); } out << ")"; } @@ -81,8 +81,12 @@ namespace smt { return m_kernel.get_num_asserted_formulas(); } - expr * const * get_formulas() const { - return m_kernel.get_asserted_formulas(); + void get_formulas(ptr_vector& fmls) const { + m_kernel.get_asserted_formulas(fmls); + } + + expr* get_formula(unsigned i) const { + return m_kernel.get_asserted_formula(i); } void push() { @@ -241,8 +245,8 @@ namespace smt { return m_imp->size(); } - expr * const * kernel::get_formulas() const { - return m_imp->get_formulas(); + expr* kernel::get_formula(unsigned i) const { + return m_imp->get_formula(i); } diff --git a/src/smt/smt_kernel.h b/src/smt/smt_kernel.h index 6ebb8546f..d10cab4f3 100644 --- a/src/smt/smt_kernel.h +++ b/src/smt/smt_kernel.h @@ -85,7 +85,12 @@ namespace smt { /** \brief Return the array of asserted formulas. */ - expr * const * get_formulas() const; + void get_formulas(ptr_vector& r) const; + + /** + \brief return the formula at index idx. + */ + expr* get_formula(unsigned idx) const; /** \brief Create a backtracking point (aka scope level). diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 94a6a7267..0536c200d 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -23,8 +23,6 @@ Revision History: #include "ast/arith_decl_plugin.h" #include "ast/bv_decl_plugin.h" #include "ast/array_decl_plugin.h" -#include "ast/simplifier/arith_simplifier_plugin.h" -#include "ast/simplifier/bv_simplifier_plugin.h" #include "ast/normal_forms/pull_quant.h" #include "ast/rewriter/var_subst.h" #include "ast/for_each_expr.h" @@ -392,9 +390,9 @@ namespace smt { The idea is to create node objects based on the information produced by the quantifier_analyzer. */ class auf_solver : public evaluator { - ast_manager & m_manager; - arith_simplifier_plugin * m_asimp; - bv_simplifier_plugin * m_bvsimp; + ast_manager & m; + arith_util m_arith; + bv_util m_bv; ptr_vector m_nodes; unsigned m_next_node_id; key2node m_uvars; @@ -466,16 +464,16 @@ namespace smt { } public: - auf_solver(ast_manager & m, simplifier & s): - m_manager(m), + auf_solver(ast_manager & m): + m(m), + m_arith(m), + m_bv(m), m_next_node_id(0), m_context(0), m_ks(m), m_model(0), m_eval_cache_range(m), m_new_constraints(0) { - m_asimp = static_cast(s.get_plugin(m.mk_family_id("arith"))); - m_bvsimp = static_cast(s.get_plugin(m.mk_family_id("bv"))); } virtual ~auf_solver() { @@ -487,13 +485,9 @@ namespace smt { SASSERT(m_context==0); m_context = ctx; } - - ast_manager & get_manager() const { return m_manager; } - - arith_simplifier_plugin * get_arith_simp() const { return m_asimp; } - - bv_simplifier_plugin * get_bv_simp() const { return m_bvsimp; } - + + ast_manager & get_manager() const { return m; } + void reset() { flush_nodes(); m_nodes.reset(); @@ -538,7 +532,7 @@ namespace smt { void mk_instantiation_sets() { for (node* curr : m_nodes) { if (curr->is_root()) { - curr->mk_instantiation_set(m_manager); + curr->mk_instantiation_set(m); } } } @@ -554,7 +548,7 @@ namespace smt { for (auto const& kv : elems) { expr * n = kv.m_key; expr * n_val = eval(n, true); - if (!n_val || !m_manager.is_value(n_val)) + if (!n_val || !m.is_value(n_val)) to_delete.push_back(n); } for (expr* e : to_delete) { @@ -568,7 +562,7 @@ namespace smt { display_key2node(out, m_uvars); display_A_f_is(out); for (node* n : m_nodes) { - n->display(out, m_manager); + n->display(out, m); } } @@ -577,14 +571,14 @@ namespace smt { if (m_eval_cache[model_completion].find(n, r)) { return r; } - expr_ref tmp(m_manager); + expr_ref tmp(m); if (!m_model->eval(n, tmp, model_completion)) { r = 0; - TRACE("model_finder", tout << "eval\n" << mk_pp(n, m_manager) << "\n-----> null\n";); + TRACE("model_finder", tout << "eval\n" << mk_pp(n, m) << "\n-----> null\n";); } else { r = tmp; - TRACE("model_finder", tout << "eval\n" << mk_pp(n, m_manager) << "\n----->\n" << mk_pp(r, m_manager) << "\n";); + TRACE("model_finder", tout << "eval\n" << mk_pp(n, m) << "\n----->\n" << mk_pp(r, m) << "\n";); } m_eval_cache[model_completion].insert(n, r); m_eval_cache_range.push_back(r); @@ -636,7 +630,7 @@ namespace smt { SASSERT(t_val != 0); bool found = false; for (expr* v : ex_vals) { - if (!m_manager.are_distinct(t_val, v)) { + if (!m.are_distinct(t_val, v)) { found = true; break; } @@ -651,8 +645,8 @@ namespace smt { bool is_infinite(sort * s) const { // we should not assume that uninterpreted sorts are infinite in benchmarks with quantifiers. - return - !m_manager.is_uninterp(s) && + return + !m.is_uninterp(s) && s->is_infinite(); } @@ -665,7 +659,7 @@ namespace smt { app * r = 0; if (m_sort2k.find(s, r)) return r; - r = m_manager.mk_fresh_const("k", s); + r = m.mk_fresh_const("k", s); m_model->register_aux_decl(r->get_decl()); m_sort2k.insert(s, r); m_ks.push_back(r); @@ -680,7 +674,7 @@ namespace smt { Remark: this method uses get_fresh_value, so it may fail. */ expr * get_k_interp(app * k) { - sort * s = m_manager.get_sort(k); + sort * s = m.get_sort(k); SASSERT(is_infinite(s)); func_decl * k_decl = k->get_decl(); expr * r = m_model->get_const_interp(k_decl); @@ -691,7 +685,7 @@ namespace smt { return 0; m_model->register_decl(k_decl, r); SASSERT(m_model->get_const_interp(k_decl) == r); - TRACE("model_finder", tout << mk_pp(r, m_manager) << "\n";); + TRACE("model_finder", tout << mk_pp(r, m) << "\n";); return r; } @@ -701,18 +695,18 @@ namespace smt { It invokes get_k_interp that may fail. */ bool assert_k_diseq_exceptions(app * k, ptr_vector const & exceptions) { - TRACE("assert_k_diseq_exceptions", tout << "assert_k_diseq_exceptions, " << "k: " << mk_pp(k, m_manager) << "\nexceptions:\n"; - for (expr * e : exceptions) tout << mk_pp(e, m_manager) << "\n";); + TRACE("assert_k_diseq_exceptions", tout << "assert_k_diseq_exceptions, " << "k: " << mk_pp(k, m) << "\nexceptions:\n"; + for (expr * e : exceptions) tout << mk_pp(e, m) << "\n";); expr * k_interp = get_k_interp(k); if (k_interp == 0) return false; for (expr * ex : exceptions) { expr * ex_val = eval(ex, true); - if (!m_manager.are_distinct(k_interp, ex_val)) { + if (!m.are_distinct(k_interp, ex_val)) { SASSERT(m_new_constraints); // This constraint cannot be asserted into m_context during model construction. // We must save it, and assert it during a restart. - m_new_constraints->push_back(m_manager.mk_not(m_manager.mk_eq(k, ex))); + m_new_constraints->push_back(m.mk_not(m.mk_eq(k, ex))); } } return true; @@ -735,7 +729,7 @@ namespace smt { return; } sort * s = n->get_sort(); - TRACE("model_finder", tout << "trying to create k for " << mk_pp(s, m_manager) << ", is_infinite: " << is_infinite(s) << "\n";); + TRACE("model_finder", tout << "trying to create k for " << mk_pp(s, m) << ", is_infinite: " << is_infinite(s) << "\n";); if (is_infinite(s)) { app * k = get_k_for(s); if (assert_k_diseq_exceptions(k, exceptions)) { @@ -758,28 +752,36 @@ namespace smt { void add_mono_exceptions(node * n) { SASSERT(n->is_mono_proj()); sort * s = n->get_sort(); - arith_simplifier_plugin * as = get_arith_simp(); - bv_simplifier_plugin * bs = get_bv_simp(); - bool is_int = as->is_int_sort(s); - bool is_bv = bs->is_bv_sort(s); - if (!is_int && !is_bv) - return; - poly_simplifier_plugin * ps = as; - if (is_bv) - ps = bs; - ps->set_curr_sort(s); - expr_ref one(m_manager); - one = ps->mk_one(); + arith_rewriter arw(m); + bv_rewriter brw(m); ptr_vector const & exceptions = n->get_exceptions(); - for (expr * e : exceptions) { - expr_ref e_plus_1(m_manager); - expr_ref e_minus_1(m_manager); - TRACE("mf_simp_bug", tout << "e:\n" << mk_ismt2_pp(e, m_manager) << "\none:\n" << mk_ismt2_pp(one, m_manager) << "\n";); - ps->mk_add(e, one, e_plus_1); - ps->mk_sub(e, one, e_minus_1); - // Note: exceptions come from quantifiers bodies. So, they have generation 0. - n->insert(e_plus_1, 0); - n->insert(e_minus_1, 0); + expr_ref e_minus_1(m), e_plus_1(m); + if (m_arith.is_int(s)) { + expr_ref one(m_arith.mk_int(1), m); + arith_rewriter arith_rw(m); + for (expr * e : exceptions) { + arith_rw.mk_sub(e, one, e_minus_1); + arith_rw.mk_add(e, one, e_plus_1); + TRACE("mf_simp_bug", tout << "e:\n" << mk_ismt2_pp(e, m) << "\none:\n" << mk_ismt2_pp(one, m) << "\n";); + // Note: exceptions come from quantifiers bodies. So, they have generation 0. + n->insert(e_plus_1, 0); + n->insert(e_minus_1, 0); + } + } + else if (m_bv.is_bv_sort(s)) { + expr_ref one(m_bv.mk_numeral(rational(1), s), m); + bv_rewriter bv_rw(m); + for (expr * e : exceptions) { + bv_rw.mk_add(e, one, e_plus_1); + bv_rw.mk_sub(e, one, e_minus_1); + TRACE("mf_simp_bug", tout << "e:\n" << mk_ismt2_pp(e, m) << "\none:\n" << mk_ismt2_pp(one, m) << "\n";); + // Note: exceptions come from quantifiers bodies. So, they have generation 0. + n->insert(e_plus_1, 0); + n->insert(e_minus_1, 0); + } + } + else { + return; } } @@ -797,16 +799,17 @@ namespace smt { } TRACE("model_finder_bug", tout << "values for the instantiation_set of @" << n->get_id() << "\n"; for (expr * v : values) { - tout << mk_pp(v, m_manager) << "\n"; + tout << mk_pp(v, m) << "\n"; }); } + template struct numeral_lt { - poly_simplifier_plugin * m_p; - numeral_lt(poly_simplifier_plugin * p):m_p(p) {} - bool operator()(expr * e1, expr * e2) { + T& m_util; + numeral_lt(T& a): m_util(a) {} + bool operator()(expr* e1, expr* e2) { rational v1, v2; - if (m_p->is_numeral(e1, v1) && m_p->is_numeral(e2, v2)) { + if (m_util.is_numeral(e1, v1) && m_util.is_numeral(e2, v2)) { return v1 < v2; } else { @@ -815,15 +818,16 @@ namespace smt { } }; + struct signed_bv_lt { - bv_simplifier_plugin * m_bs; + bv_util& m_bv; unsigned m_bv_size; - signed_bv_lt(bv_simplifier_plugin * bs, unsigned sz):m_bs(bs), m_bv_size(sz) {} + signed_bv_lt(bv_util& bv, unsigned sz):m_bv(bv), m_bv_size(sz) {} bool operator()(expr * e1, expr * e2) { rational v1, v2; - if (m_bs->is_numeral(e1, v1) && m_bs->is_numeral(e2, v2)) { - v1 = m_bs->norm(v1, m_bv_size, true); - v2 = m_bs->norm(v2, m_bv_size, true); + if (m_bv.is_numeral(e1, v1) && m_bv.is_numeral(e2, v2)) { + v1 = m_bv.norm(v1, m_bv_size, true); + v2 = m_bv.norm(v2, m_bv_size, true); return v1 < v2; } else { @@ -834,15 +838,14 @@ namespace smt { void sort_values(node * n, ptr_buffer & values) { sort * s = n->get_sort(); - if (get_arith_simp()->is_arith_sort(s)) { - std::sort(values.begin(), values.end(), numeral_lt(get_arith_simp())); + if (m_arith.is_int(s) || m_arith.is_real(s)) { + std::sort(values.begin(), values.end(), numeral_lt(m_arith)); } else if (!n->is_signed_proj()) { - std::sort(values.begin(), values.end(), numeral_lt(get_bv_simp())); + std::sort(values.begin(), values.end(), numeral_lt(m_bv)); } else { - bv_simplifier_plugin * bs = get_bv_simp(); - std::sort(values.begin(), values.end(), signed_bv_lt(bs, bs->get_bv_size(s))); + std::sort(values.begin(), values.end(), signed_bv_lt(m_bv, m_bv.get_bv_size(s))); } } @@ -853,27 +856,25 @@ namespace smt { if (values.empty()) return; sort_values(n, values); sort * s = n->get_sort(); - arith_simplifier_plugin * as = get_arith_simp(); - bv_simplifier_plugin * bs = get_bv_simp(); - bool is_arith = as->is_arith_sort(s); + bool is_arith = m_arith.is_int(s) || m_arith.is_real(s); bool is_signed = n->is_signed_proj(); unsigned sz = values.size(); SASSERT(sz > 0); - func_decl * p = m_manager.mk_fresh_func_decl(1, &s, s); + func_decl * p = m.mk_fresh_func_decl(1, &s, s); expr * pi = values[sz - 1]; - expr_ref var(m_manager); - var = m_manager.mk_var(0, s); + expr_ref var(m); + var = m.mk_var(0, s); for (unsigned i = sz - 1; i >= 1; i--) { - expr_ref c(m_manager); - if (is_arith) - as->mk_lt(var, values[i], c); + expr_ref c(m); + if (is_arith) + c = m_arith.mk_lt(var, values[i]); else if (!is_signed) - bs->mk_ult(var, values[i], c); + c = m.mk_not(m_bv.mk_ule(values[i], var)); else - bs->mk_slt(var, values[i], c); - pi = m_manager.mk_ite(c, values[i-1], pi); + c = m.mk_not(m_bv.mk_sle(values[i], var)); + pi = m.mk_ite(c, values[i-1], pi); } - func_interp * rpi = alloc(func_interp, m_manager, 1); + func_interp * rpi = alloc(func_interp, m, 1); rpi->set_else(pi); m_model->register_aux_decl(p, rpi); n->set_proj(p); @@ -884,8 +885,8 @@ namespace smt { ptr_buffer values; get_instantiation_set_values(n, values); sort * s = n->get_sort(); - func_decl * p = m_manager.mk_fresh_func_decl(1, &s, s); - func_interp * pi = alloc(func_interp, m_manager, 1); + func_decl * p = m.mk_fresh_func_decl(1, &s, s); + func_interp * pi = alloc(func_interp, m, 1); m_model->register_aux_decl(p, pi); if (n->get_else()) { expr * else_val = eval(n->get_else(), true); @@ -916,7 +917,7 @@ namespace smt { if (!r.contains(f)) { func_interp * fi = m_model->get_func_interp(f); if (fi == 0) { - fi = alloc(func_interp, m_manager, f->get_arity()); + fi = alloc(func_interp, m, f->get_arity()); m_model->register_decl(f, fi); SASSERT(fi->is_partial()); } @@ -938,7 +939,7 @@ namespace smt { for (node * n : m_root_nodes) { SASSERT(n->is_root()); sort * s = n->get_sort(); - if (m_manager.is_uninterp(s) && + if (m.is_uninterp(s) && // Making all uninterpreted sorts finite. // n->must_avoid_itself() && !m_model->is_finite(s)) { @@ -962,7 +963,7 @@ namespace smt { // If these module values "leak" inside the logical context, they may affect satisfiability. // sort * ns = n->get_sort(); - if (m_manager.is_fully_interp(ns)) { + if (m.is_fully_interp(ns)) { n->insert(m_model->get_some_value(ns), 0); } else { @@ -973,18 +974,18 @@ namespace smt { sort2elems.insert(n->get_sort(), elems.begin()->m_key); } } - expr_ref_vector trail(m_manager); + expr_ref_vector trail(m); for (unsigned i = 0; i < need_fresh.size(); ++i) { expr * e; node* n = need_fresh[i]; sort* s = n->get_sort(); if (!sort2elems.find(s, e)) { - e = m_manager.mk_fresh_const("elem", s); + e = m.mk_fresh_const("elem", s); trail.push_back(e); sort2elems.insert(s, e); } n->insert(e, 0); - TRACE("model_finder", tout << "fresh constant: " << mk_pp(e, m_manager) << "\n";); + TRACE("model_finder", tout << "fresh constant: " << mk_pp(e, m) << "\n";); } } @@ -1036,14 +1037,14 @@ namespace smt { func_interp * fi = m_model->get_func_interp(f); if (fi->is_constant()) continue; // there is no point in using the projection for fi, since fi is the constant function. - - expr_ref_vector args(m_manager); + + expr_ref_vector args(m); bool has_proj = false; for (unsigned i = 0; i < arity; i++) { - var * v = m_manager.mk_var(i, f->get_domain(i)); + var * v = m.mk_var(i, f->get_domain(i)); func_decl * pi = get_f_i_proj(f, i); if (pi != 0) { - args.push_back(m_manager.mk_app(pi, v)); + args.push_back(m.mk_app(pi, v)); has_proj = true; } else { @@ -1052,11 +1053,11 @@ namespace smt { } if (has_proj) { // f_aux will be assigned to the old interpretation of f. - func_decl * f_aux = m_manager.mk_fresh_func_decl(f->get_name(), symbol::null, arity, f->get_domain(), f->get_range()); - func_interp * new_fi = alloc(func_interp, m_manager, arity); - new_fi->set_else(m_manager.mk_app(f_aux, args.size(), args.c_ptr())); - TRACE("model_finder", tout << "Setting new interpretation for " << f->get_name() << "\n" << - mk_pp(new_fi->get_else(), m_manager) << "\n";); + func_decl * f_aux = m.mk_fresh_func_decl(f->get_name(), symbol::null, arity, f->get_domain(), f->get_range()); + func_interp * new_fi = alloc(func_interp, m, arity); + new_fi->set_else(m.mk_app(f_aux, args.size(), args.c_ptr())); + TRACE("model_finder", tout << "Setting new interpretation for " << f->get_name() << "\n" << + mk_pp(new_fi->get_else(), m) << "\n";); m_model->reregister_decl(f, new_fi, f_aux); } } @@ -1256,21 +1257,22 @@ namespace smt { if (A_f_i == S_j) { // there is no finite fixpoint... we just copy the i-th arguments of A_f_i - m_offset // hope for the best... - arith_simplifier_plugin * as = s.get_arith_simp(); - bv_simplifier_plugin * bs = s.get_bv_simp(); node * S_j = s.get_uvar(q, m_var_j); enode_vector::const_iterator it = ctx->begin_enodes_of(m_f); enode_vector::const_iterator end = ctx->end_enodes_of(m_f); for (; it != end; it++) { enode * n = *it; if (ctx->is_relevant(n)) { + arith_rewriter arith_rw(ctx->get_manager()); + bv_util bv(ctx->get_manager()); + bv_rewriter bv_rw(ctx->get_manager()); enode * e_arg = n->get_arg(m_arg_i); expr * arg = e_arg->get_owner(); expr_ref arg_minus_k(ctx->get_manager()); - if (bs->is_bv(arg)) - bs->mk_sub(arg, m_offset, arg_minus_k); + if (bv.is_bv(arg)) + bv_rw.mk_sub(arg, m_offset, arg_minus_k); else - as->mk_sub(arg, m_offset, arg_minus_k); + arith_rw.mk_sub(arg, m_offset, arg_minus_k); S_j->insert(arg_minus_k, e_arg->get_generation()); } } @@ -1290,20 +1292,32 @@ namespace smt { template void copy_instances(node * from, node * to, auf_solver & s) { - arith_simplifier_plugin * as = s.get_arith_simp(); - bv_simplifier_plugin * bs = s.get_bv_simp(); - poly_simplifier_plugin * ps = as; - if (bs->is_bv_sort(from->get_sort())) - ps = bs; instantiation_set const * from_s = from->get_instantiation_set(); obj_map const & elems_s = from_s->get_elems(); + + arith_rewriter arith_rw(m_offset.get_manager()); + bv_rewriter bv_rw(m_offset.get_manager()); + bool is_bv = bv_util(m_offset.get_manager()).is_bv_sort(from->get_sort()); + for (auto const& kv : elems_s) { expr * n = kv.m_key; expr_ref n_k(m_offset.get_manager()); - if (PLUS) - ps->mk_add(n, m_offset, n_k); - else - ps->mk_sub(n, m_offset, n_k); + if (PLUS) { + if (is_bv) { + bv_rw.mk_add(n, m_offset, n_k); + } + else { + arith_rw.mk_add(n, m_offset, n_k); + } + } + else { + if (is_bv) { + bv_rw.mk_sub(n, m_offset, n_k); + } + else { + arith_rw.mk_sub(n, m_offset, n_k); + } + } to->insert(n_k, kv.m_value); } } @@ -1897,11 +1911,8 @@ namespace smt { m_info->insert_qinfo(qi); } - arith_simplifier_plugin * get_arith_simp() const { return m_mutil.get_arith_simp(); } - bv_simplifier_plugin * get_bv_simp() const { return m_mutil.get_bv_simp(); } - - bool is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) const { - return get_arith_simp()->is_var_plus_ground(n, inv, v, t) || get_bv_simp()->is_var_plus_ground(n, inv, v, t); + bool is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) { + return m_mutil.is_var_plus_ground(n, inv, v, t); } bool is_var_plus_ground(expr * n, var * & v, expr_ref & t) { @@ -1917,10 +1928,7 @@ namespace smt { } bool is_zero(expr * n) const { - if (get_bv_simp()->is_bv(n)) - return get_bv_simp()->is_zero_safe(n); - else - return get_arith_simp()->is_zero_safe(n); + return m_mutil.is_zero_safe(n); } bool is_times_minus_one(expr * n, expr * & arg) const { @@ -1951,7 +1959,7 @@ namespace smt { m_mutil.mk_add(t1, t2, r); } - bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t, bool & inv) const { + bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t, bool & inv) { inv = false; // true if invert the sign TRACE("is_var_and_ground", tout << "is_var_and_ground: " << mk_ismt2_pp(lhs, m_manager) << " " << mk_ismt2_pp(rhs, m_manager) << "\n";); if (is_var(lhs) && is_ground(rhs)) { @@ -1986,12 +1994,12 @@ namespace smt { return false; } - bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t) const { + bool is_var_and_ground(expr * lhs, expr * rhs, var * & v, expr_ref & t) { bool inv; return is_var_and_ground(lhs, rhs, v, t, inv); } - - bool is_x_eq_t_atom(expr * n, var * & v, expr_ref & t) const { + + bool is_x_eq_t_atom(expr * n, var * & v, expr_ref & t) { if (!is_app(n)) return false; if (m_manager.is_eq(n)) @@ -1999,7 +2007,7 @@ namespace smt { return false; } - bool is_var_minus_var(expr * n, var * & v1, var * & v2) const { + bool is_var_minus_var(expr * n, var * & v1, var * & v2) { if (!is_add(n)) return false; expr * arg1 = to_app(n)->get_arg(0); @@ -2018,7 +2026,7 @@ namespace smt { return true; } - bool is_var_and_var(expr * lhs, expr * rhs, var * & v1, var * & v2) const { + bool is_var_and_var(expr * lhs, expr * rhs, var * & v1, var * & v2) { if (is_var(lhs) && is_var(rhs)) { v1 = to_var(lhs); v2 = to_var(rhs); @@ -2029,11 +2037,11 @@ namespace smt { (is_var_minus_var(rhs, v1, v2) && is_zero(lhs)); } - bool is_x_eq_y_atom(expr * n, var * & v1, var * & v2) const { + bool is_x_eq_y_atom(expr * n, var * & v1, var * & v2) { return m_manager.is_eq(n) && is_var_and_var(to_app(n)->get_arg(0), to_app(n)->get_arg(1), v1, v2); } - bool is_x_gle_y_atom(expr * n, var * & v1, var * & v2) const { + bool is_x_gle_y_atom(expr * n, var * & v1, var * & v2) { return is_le_ge(n) && is_var_and_var(to_app(n)->get_arg(0), to_app(n)->get_arg(1), v1, v2); } @@ -2379,11 +2387,11 @@ namespace smt { public: - quantifier_analyzer(model_finder& mf, ast_manager & m, simplifier & s): + quantifier_analyzer(model_finder& mf, ast_manager & m): m_mf(mf), m_manager(m), - m_mutil(m, s), - m_array_util(m), + m_mutil(m), + m_array_util(m), m_arith_util(m), m_bv_util(m), m_info(0) { @@ -3151,12 +3159,12 @@ namespace smt { // model finder // // ----------------------------------- - - model_finder::model_finder(ast_manager & m, simplifier & s): + + model_finder::model_finder(ast_manager & m): m_manager(m), m_context(0), - m_analyzer(alloc(quantifier_analyzer, *this, m, s)), - m_auf_solver(alloc(auf_solver, m, s)), + m_analyzer(alloc(quantifier_analyzer, *this, m)), + m_auf_solver(alloc(auf_solver, m)), m_dependencies(m), m_sm_solver(alloc(simple_macro_solver, m, m_q2info)), m_hint_solver(alloc(hint_solver, m, m_q2info)), diff --git a/src/smt/smt_model_finder.h b/src/smt/smt_model_finder.h index f02640659..2b79ab265 100644 --- a/src/smt/smt_model_finder.h +++ b/src/smt/smt_model_finder.h @@ -48,7 +48,6 @@ Revision History: #include "ast/ast.h" #include "ast/func_decl_dependencies.h" -#include "ast/simplifier/simplifier.h" #include "smt/proto_model/proto_model.h" #include "util/cooperate.h" #include "tactic/tactic_exception.h" @@ -107,7 +106,7 @@ namespace smt { public: - model_finder(ast_manager & m, simplifier & s); + model_finder(ast_manager & m); ~model_finder(); void set_context(context * ctx); diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 49e9083f2..5848fac62 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -17,14 +17,13 @@ Revision History: --*/ +#include "util/ref_util.h" +#include "ast/for_each_expr.h" +#include "ast/ast_pp.h" +#include "ast/ast_smt2_pp.h" #include "smt/smt_context.h" #include "smt/smt_model_generator.h" #include "smt/proto_model/proto_model.h" -#include "util/ref_util.h" -#include "ast/for_each_expr.h" -#include "ast/ast_ll_pp.h" -#include "ast/ast_pp.h" -#include "ast/ast_smt2_pp.h" namespace smt { diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 0492aff23..1d58e2bb3 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -16,6 +16,8 @@ Author: Revision History: --*/ +#include "ast/ast_pp.h" +#include "ast/ast_smt2_pp.h" #include "smt/smt_quantifier.h" #include "smt/smt_context.h" #include "smt/smt_quantifier_stat.h" @@ -24,7 +26,6 @@ Revision History: #include "smt/smt_quick_checker.h" #include "smt/mam.h" #include "smt/qi_queue.h" -#include "ast/ast_smt2_pp.h" namespace smt { @@ -207,10 +208,8 @@ namespace smt { IF_VERBOSE(10, verbose_stream() << "quick checking quantifiers (unsat)...\n";); quick_checker mc(m_context); bool result = true; - ptr_vector::const_iterator it = m_quantifiers.begin(); - ptr_vector::const_iterator end = m_quantifiers.end(); - for (; it != end; ++it) - if (check_quantifier(*it) && mc.instantiate_unsat(*it)) + for (quantifier* q : m_quantifiers) + if (check_quantifier(q) && mc.instantiate_unsat(q)) result = false; if (m_params.m_qi_quick_checker == MC_UNSAT || !result) { m_qi_queue.instantiate(); @@ -219,9 +218,8 @@ namespace smt { // MC_NO_SAT is too expensive (it creates too many irrelevant instances). // we should use MBQI=true instead. IF_VERBOSE(10, verbose_stream() << "quick checking quantifiers (not sat)...\n";); - it = m_quantifiers.begin(); - for (; it != end; ++it) - if (check_quantifier(*it) && mc.instantiate_not_sat(*it)) + for (quantifier* q : m_quantifiers) + if (check_quantifier(q) && mc.instantiate_not_sat(q)) result = false; m_qi_queue.instantiate(); return result; @@ -434,7 +432,7 @@ namespace smt { m_mam = mk_mam(*m_context); m_lazy_mam = mk_mam(*m_context); - m_model_finder = alloc(model_finder, m, m_context->get_simplifier()); + m_model_finder = alloc(model_finder, m); m_model_checker = alloc(model_checker, m, *m_fparams, *(m_model_finder.get())); m_model_finder->set_context(m_context); @@ -496,7 +494,7 @@ namespace smt { if (!m_fparams->m_ematching) { return; } - if (false && m_context->get_manager().is_rec_fun_def(q) && mbqi_enabled(q)) { + if (false && m.is_rec_fun_def(q) && mbqi_enabled(q)) { return; } bool has_unary_pattern = false; @@ -513,20 +511,20 @@ namespace smt { num_eager_multi_patterns++; for (unsigned i = 0, j = 0; i < num_patterns; i++) { app * mp = to_app(q->get_pattern(i)); - SASSERT(m_context->get_manager().is_pattern(mp)); + SASSERT(m.is_pattern(mp)); bool unary = (mp->get_num_args() == 1); if (m.is_rec_fun_def(q) && i > 0) { // add only the first pattern TRACE("quantifier", tout << "skip recursive function body " << mk_ismt2_pp(mp, m) << "\n";); } else if (!unary && j >= num_eager_multi_patterns) { - TRACE("quantifier", tout << "delaying (too many multipatterns):\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n" + TRACE("quantifier", tout << "delaying (too many multipatterns):\n" << mk_ismt2_pp(mp, m) << "\n" << "j: " << j << " unary: " << unary << " m_params.m_qi_max_eager_multipatterns: " << m_fparams->m_qi_max_eager_multipatterns << " num_eager_multi_patterns: " << num_eager_multi_patterns << "\n";); m_lazy_mam->add_pattern(q, mp); } else { - TRACE("quantifier", tout << "adding:\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n";); + TRACE("quantifier", tout << "adding:\n" << mk_ismt2_pp(mp, m) << "\n";); m_mam->add_pattern(q, mp); } if (!unary) diff --git a/src/smt/smt_quick_checker.cpp b/src/smt/smt_quick_checker.cpp index f8744318a..72c28fd7d 100644 --- a/src/smt/smt_quick_checker.cpp +++ b/src/smt/smt_quick_checker.cpp @@ -164,7 +164,6 @@ namespace smt { quick_checker::quick_checker(context & c): m_context(c), m_manager(c.get_manager()), - m_simplifier(c.get_simplifier()), m_collector(c), m_new_exprs(m_manager) { } @@ -411,7 +410,7 @@ namespace smt { } } expr_ref new_expr(m_manager); - m_simplifier.mk_app(to_app(n)->get_decl(), num_args, new_args.c_ptr(), new_expr); + new_expr = m_context.get_rewriter().mk_app(to_app(n)->get_decl(), num_args, new_args.c_ptr()); m_new_exprs.push_back(new_expr); m_canonize_cache.insert(n, new_expr); return new_expr; diff --git a/src/smt/smt_quick_checker.h b/src/smt/smt_quick_checker.h index eb07880f1..21a570c3c 100644 --- a/src/smt/smt_quick_checker.h +++ b/src/smt/smt_quick_checker.h @@ -20,7 +20,7 @@ Revision History: #define SMT_QUICK_CHECKER_H_ #include "ast/ast.h" -#include "ast/simplifier/simplifier.h" +#include "ast/rewriter/th_rewriter.h" #include "util/obj_hashtable.h" namespace smt { @@ -77,7 +77,6 @@ namespace smt { context & m_context; ast_manager & m_manager; - simplifier & m_simplifier; collector m_collector; expr_ref_vector m_new_exprs; vector m_candidate_vectors; diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index a37668c7b..50b49f3b8 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -142,7 +142,9 @@ namespace smt { } else { IF_VERBOSE(100, verbose_stream() << "(smt.collecting-features)\n";); - st.collect(m_context.get_num_asserted_formulas(), m_context.get_asserted_formulas()); + ptr_vector fmls; + m_context.get_asserted_formulas(fmls); + st.collect(fmls.size(), fmls.c_ptr()); IF_VERBOSE(1000, st.display_primitive(verbose_stream());); if (m_logic == "QF_UF") setup_QF_UF(st); @@ -224,7 +226,7 @@ namespace smt { void setup::setup_QF_RDL() { m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_nnf_cnf = false; @@ -264,7 +266,7 @@ namespace smt { TRACE("setup", tout << "setup_QF_RDL(st)\n";); check_no_uninterpreted_functions(st, "QF_RDL"); m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_nnf_cnf = false; @@ -316,7 +318,7 @@ namespace smt { void setup::setup_QF_IDL() { TRACE("setup", tout << "setup_QF_IDL()\n";); m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_arith_small_lemma_size = 30; @@ -334,7 +336,7 @@ namespace smt { TRACE("setup", tout << "setup_QF_IDL(st)\n";); check_no_uninterpreted_functions(st, "QF_IDL"); m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_arith_small_lemma_size = 30; @@ -388,7 +390,7 @@ namespace smt { m_params.m_arith_reflect = false; m_params.m_nnf_cnf = false; m_params.m_arith_eq_bounds = true; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_phase_selection = PS_ALWAYS_FALSE; m_params.m_restart_strategy = RS_GEOMETRIC; m_params.m_restart_factor = 1.5; @@ -404,8 +406,8 @@ namespace smt { m_params.m_arith_reflect = false; m_params.m_nnf_cnf = false; if (st.m_num_uninterpreted_functions == 0) { - m_params.m_arith_expand_eqs = true; - m_params.m_arith_propagate_eqs = false; + m_params.m_arith_eq2ineq = true; + m_params.m_arith_propagate_eqs = false; if (is_dense(st)) { m_params.m_arith_small_lemma_size = 128; m_params.m_lemma_gc_half = true; @@ -438,7 +440,7 @@ namespace smt { void setup::setup_QF_LRA() { TRACE("setup", tout << "setup_QF_LRA(st)\n";); m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_eliminate_term_ite = true; @@ -449,7 +451,7 @@ namespace smt { void setup::setup_QF_LRA(static_features const & st) { check_no_uninterpreted_functions(st, "QF_LRA"); m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_eliminate_term_ite = true; @@ -478,7 +480,7 @@ namespace smt { void setup::setup_QF_LIA() { TRACE("setup", tout << "setup_QF_LIA(st)\n";); m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_nnf_cnf = false; @@ -490,12 +492,12 @@ namespace smt { TRACE("setup", tout << "QF_LIA setup\n";); m_params.m_relevancy_lvl = 0; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_arith_reflect = false; m_params.m_arith_propagate_eqs = false; m_params.m_nnf_cnf = false; if (st.m_max_ite_tree_depth > 50) { - m_params.m_arith_expand_eqs = false; + m_params.m_arith_eq2ineq = false; m_params.m_pull_cheap_ite_trees = true; m_params.m_arith_propagate_eqs = true; m_params.m_relevancy_lvl = 2; @@ -505,7 +507,7 @@ namespace smt { m_params.m_arith_gcd_test = false; m_params.m_arith_branch_cut_ratio = 4; m_params.m_relevancy_lvl = 2; - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; m_params.m_eliminate_term_ite = true; // if (st.m_num_exprs < 5000 && st.m_num_ite_terms < 50) { // safeguard to avoid high memory consumption // TODO: implement analsysis function to decide where lift ite is too expensive. @@ -742,7 +744,9 @@ namespace smt { void setup::setup_arith() { static_features st(m_manager); IF_VERBOSE(100, verbose_stream() << "(smt.collecting-features)\n";); - st.collect(m_context.get_num_asserted_formulas(), m_context.get_asserted_formulas()); + ptr_vector fmls; + m_context.get_asserted_formulas(fmls); + st.collect(fmls.size(), fmls.c_ptr()); IF_VERBOSE(1000, st.display_primitive(verbose_stream());); bool fixnum = st.arith_k_sum_is_small() && m_params.m_arith_fixnum; bool int_only = !st.m_has_rational && !st.m_has_real && m_params.m_arith_int_only; @@ -751,7 +755,7 @@ namespace smt { m_context.register_plugin(alloc(smt::theory_dummy, m_manager.mk_family_id("arith"), "no arithmetic")); break; case AS_DIFF_LOGIC: - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; if (fixnum) { if (int_only) m_context.register_plugin(alloc(smt::theory_fidl, m_manager, m_params)); @@ -766,7 +770,7 @@ namespace smt { } break; case AS_DENSE_DIFF_LOGIC: - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; if (fixnum) { if (int_only) m_context.register_plugin(alloc(smt::theory_dense_si, m_manager, m_params)); @@ -781,7 +785,7 @@ namespace smt { } break; case AS_UTVPI: - m_params.m_arith_expand_eqs = true; + m_params.m_arith_eq2ineq = true; if (int_only) m_context.register_plugin(alloc(smt::theory_iutvpi, m_manager)); else @@ -877,7 +881,9 @@ namespace smt { void setup::setup_unknown() { static_features st(m_manager); - st.collect(m_context.get_num_asserted_formulas(), m_context.get_asserted_formulas()); + ptr_vector fmls; + m_context.get_asserted_formulas(fmls); + st.collect(fmls.size(), fmls.c_ptr()); TRACE("setup", tout << "setup_unknown\n";); setup_arith(); setup_arrays(); diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index ba86f017a..e78c6388e 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -61,15 +61,14 @@ namespace smt { } virtual solver * translate(ast_manager & m, params_ref const & p) { + ast_translation translator(get_manager(), m); + solver * result = alloc(solver, m, p, m_logic); smt::kernel::copy(m_context, result->m_context); - ast_translation translator(get_manager(), m); - obj_map::iterator it = m_name2assertion.begin(); - obj_map::iterator end = m_name2assertion.end(); - for (; it != end; it++) - result->m_name2assertion.insert(translator(it->m_key), - translator(it->m_value)); + for (auto & kv : m_name2assertion) + result->m_name2assertion.insert(translator(kv.m_key), + translator(kv.m_value)); return result; } @@ -216,7 +215,7 @@ namespace smt { virtual expr * get_assertion(unsigned idx) const { SASSERT(idx < get_num_assertions()); - return m_context.get_formulas()[idx]; + return m_context.get_formula(idx); } struct collect_fds_proc { @@ -264,23 +263,20 @@ namespace smt { } void compute_assrtn_fds(ptr_vector & core, vector & assrtn_fds) { - assrtn_fds.resize(m_name2assertion.size()); - obj_map::iterator ait = m_name2assertion.begin(); - obj_map::iterator aend = m_name2assertion.end(); - for (unsigned i = 0; ait != aend; ait++, i++) { - if (core.contains(ait->m_key)) - continue; - collect_fds_proc p(m, assrtn_fds[i]); - expr_fast_mark1 visited; - quick_for_each_expr(p, visited, ait->m_value); + assrtn_fds.resize(m_name2assertion.size()); + unsigned i = 0; + for (auto & kv : m_name2assertion) { + if (!core.contains(kv.m_key)) { + collect_fds_proc p(m, assrtn_fds[i]); + expr_fast_mark1 visited; + quick_for_each_expr(p, visited, kv.m_value); + } + ++i; } } bool fds_intersect(func_decl_set & pattern_fds, func_decl_set & assrtn_fds) { - func_decl_set::iterator it = pattern_fds.begin(); - func_decl_set::iterator end = pattern_fds.end(); - for (; it != end; it++) { - func_decl * fd = *it; + for (func_decl * fd : pattern_fds) { if (assrtn_fds.contains(fd)) return true; } @@ -297,9 +293,8 @@ namespace smt { for (unsigned d = 0; d < m_core_extend_patterns_max_distance; d++) { new_core_literals.reset(); - unsigned sz = core.size(); - for (unsigned i = 0; i < sz; i++) { - expr_ref name(core[i], m); + for (expr* c : core) { + expr_ref name(c, m); SASSERT(m_name2assertion.contains(name)); expr_ref assrtn(m_name2assertion.find(name), m); collect_pattern_fds(assrtn, pattern_fds); @@ -309,12 +304,12 @@ namespace smt { if (assrtn_fds.empty()) compute_assrtn_fds(core, assrtn_fds); - obj_map::iterator ait = m_name2assertion.begin(); - obj_map::iterator aend = m_name2assertion.end(); - for (unsigned i = 0; ait != aend; ait++, i++) { - if (!core.contains(ait->m_key) && + unsigned i = 0; + for (auto & kv : m_name2assertion) { + if (!core.contains(kv.m_key) && fds_intersect(pattern_fds, assrtn_fds[i])) - new_core_literals.push_back(ait->m_key); + new_core_literals.push_back(kv.m_key); + ++i; } } diff --git a/src/smt/tactic/smt_tactic.cpp b/src/smt/tactic/smt_tactic.cpp index f2dc83cfe..57ac7b34b 100644 --- a/src/smt/tactic/smt_tactic.cpp +++ b/src/smt/tactic/smt_tactic.cpp @@ -150,6 +150,7 @@ public: proof_converter_ref & pc, expr_dependency_ref & core) { try { + IF_VERBOSE(10, verbose_stream() << "(smt.tactic start)\n";); mc = 0; pc = 0; core = 0; SASSERT(in->is_well_sorted()); ast_manager & m = in->m(); diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 26b970d30..5f4e58a1b 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -34,7 +34,6 @@ Revision History: #include "util/obj_pair_hashtable.h" #include "smt/old_interval.h" #include "math/grobner/grobner.h" -#include "ast/simplifier/arith_simplifier_plugin.h" #include "smt/arith_eq_solver.h" #include "smt/theory_opt.h" #include "util/uint_set.h" diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index b5e7db310..aa512a2be 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -395,7 +395,7 @@ namespace smt { template theory_var theory_arith::internalize_div(app * n) { - rational r; + rational r(1); if (!m_util.is_numeral(n->get_arg(1), r) || r.is_zero()) found_underspecified_op(n); found_underspecified_op(n); theory_var s = mk_binary_op(n); @@ -421,7 +421,7 @@ namespace smt { template theory_var theory_arith::internalize_mod(app * n) { TRACE("arith_mod", tout << "internalizing...\n" << mk_pp(n, get_manager()) << "\n";); - rational r; + rational r(1); if (!m_util.is_numeral(n->get_arg(1), r) || r.is_zero()) found_underspecified_op(n); theory_var s = mk_binary_op(n); context & ctx = get_context(); @@ -432,7 +432,7 @@ namespace smt { template theory_var theory_arith::internalize_rem(app * n) { - rational r; + rational r(1); if (!m_util.is_numeral(n->get_arg(1), r) || r.is_zero()) found_underspecified_op(n); theory_var s = mk_binary_op(n); context & ctx = get_context(); @@ -446,13 +446,12 @@ namespace smt { void theory_arith::mk_axiom(expr * ante, expr * conseq) { ast_manager & m = get_manager(); context & ctx = get_context(); - simplifier & s = ctx.get_simplifier(); + th_rewriter & s = ctx.get_rewriter(); expr_ref s_ante(m), s_conseq(m); expr* s_conseq_n, * s_ante_n; bool negated; - proof_ref pr(m); - s(ante, s_ante, pr); + s(ante, s_ante); if (ctx.get_cancel_flag()) return; negated = m.is_not(s_ante, s_ante_n); if (negated) s_ante = s_ante_n; @@ -460,7 +459,7 @@ namespace smt { literal l_ante = ctx.get_literal(s_ante); if (negated) l_ante.neg(); - s(conseq, s_conseq, pr); + s(conseq, s_conseq); if (ctx.get_cancel_flag()) return; negated = m.is_not(s_conseq, s_conseq_n); if (negated) s_conseq = s_conseq_n; @@ -1225,7 +1224,8 @@ namespace smt { app * rhs = to_app(n->get_arg(1)); expr * rhs2; if (m_util.is_to_real(rhs, rhs2) && is_app(rhs2)) { rhs = to_app(rhs2); } - if (!m_util.is_numeral(rhs)) { + if (!m_util.is_numeral(rhs)) { + UNREACHABLE(); throw default_exception("malformed atomic constraint"); } theory_var v = internalize_term_core(lhs); diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index d93e062f4..4f15a6156 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -19,12 +19,11 @@ Revision History: #ifndef THEORY_ARITH_INT_H_ #define THEORY_ARITH_INT_H_ -#include "ast/ast_ll_pp.h" -#include "ast/simplifier/arith_simplifier_plugin.h" -#include "ast/well_sorted.h" -#include "math/euclid/euclidean_solver.h" #include "util/numeral_buffer.h" +#include "ast/ast_ll_pp.h" +#include "ast/well_sorted.h" #include "ast/ast_smt2_pp.h" +#include "math/euclid/euclidean_solver.h" namespace smt { @@ -455,9 +454,8 @@ namespace smt { pol = m_util.mk_add(_args.size(), _args.c_ptr()); result = m_util.mk_ge(pol, m_util.mk_numeral(k, all_int)); TRACE("arith_mk_polynomial", tout << "before simplification:\n" << result << "\n";); - simplifier & s = get_context().get_simplifier(); proof_ref pr(m); - s(result, result, pr); + get_context().get_rewriter()(result, result, pr); TRACE("arith_mk_polynomial", tout << "after simplification:\n" << result << "\n";); SASSERT(is_well_sorted(get_manager(), result)); } diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 9649440d2..a04c34706 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -2205,7 +2205,7 @@ namespace smt { args.push_back(monomial2expr(eq->get_monomial(i), is_int)); } context & ctx = get_context(); - simplifier & s = ctx.get_simplifier(); + th_rewriter& s = ctx.get_rewriter(); expr_ref pol(get_manager()); SASSERT(!args.empty()); pol = mk_nary_add(args.size(), args.c_ptr()); diff --git a/src/smt/theory_array.cpp b/src/smt/theory_array.cpp index 17eefb361..18fc9f50b 100644 --- a/src/smt/theory_array.cpp +++ b/src/smt/theory_array.cpp @@ -19,6 +19,7 @@ Revision History: #include "smt/smt_context.h" #include "smt/theory_array.h" #include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" #include "util/stats.h" namespace smt { diff --git a/src/smt/theory_array_full.cpp b/src/smt/theory_array_full.cpp index d5660e325..274f89e8b 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -21,6 +21,7 @@ Revision History: #include "smt/theory_array_full.h" #include "ast/ast_ll_pp.h" #include "ast/ast_pp.h" +#include "ast/ast_util.h" #include "ast/ast_smt2_pp.h" #include "util/stats.h" @@ -515,7 +516,8 @@ namespace smt { expr_ref sel1(m), sel2(m); sel1 = mk_select(args1.size(), args1.c_ptr()); - m_simp->mk_app(f, args2.size(), args2.c_ptr(), sel2); + sel2 = m.mk_app(f, args2.size(), args2.c_ptr()); + ctx.get_rewriter()(sel2); ctx.internalize(sel1, false); ctx.internalize(sel2, false); @@ -536,6 +538,7 @@ namespace smt { SASSERT(is_map(mp)); app* map = mp->get_owner(); + ast_manager& m = get_manager(); context& ctx = get_context(); if (!ctx.add_fingerprint(this, 0, 1, &mp)) { return false; @@ -551,9 +554,9 @@ namespace smt { args2.push_back(mk_default(map->get_arg(i))); } + expr_ref def2(m.mk_app(f, args2.size(), args2.c_ptr()), m); + ctx.get_rewriter()(def2); expr* def1 = mk_default(map); - expr_ref def2(get_manager()); - m_simp->mk_app(f, args2.size(), args2.c_ptr(), def2); ctx.internalize(def1, false); ctx.internalize(def2, false); return try_assign_eq(def1, def2); @@ -722,9 +725,7 @@ namespace smt { } expr_ref eq(m); - simplifier_plugin* p = m_simp->get_plugin(m.get_basic_family_id()); - basic_simplifier_plugin* bp = static_cast(p); - bp->mk_and(eqs.size(), eqs.c_ptr(), eq); + eq = mk_and(eqs); expr* defA = mk_default(store_app->get_arg(0)); def2 = m.mk_ite(eq, store_app->get_arg(num_args-1), defA); #if 0 diff --git a/src/smt/theory_array_full.h b/src/smt/theory_array_full.h index e22d1d0e2..2cad3acbd 100644 --- a/src/smt/theory_array_full.h +++ b/src/smt/theory_array_full.h @@ -20,7 +20,6 @@ Revision History: #define THEORY_ARRAY_FULL_H_ #include "smt/theory_array.h" -#include "ast/simplifier/simplifier.h" #include "ast/ast_trail.h" namespace smt { @@ -37,7 +36,6 @@ namespace smt { ptr_vector m_var_data_full; ast2ast_trailmap m_sort2epsilon; - simplifier* m_simp; obj_pair_map m_eqs; svector m_eqsv; @@ -100,7 +98,6 @@ namespace smt { // the parent class is theory_array. // theory::init(ctx); theory_array::init(ctx); - m_simp = &ctx->get_simplifier(); } }; diff --git a/src/smt/theory_bv.cpp b/src/smt/theory_bv.cpp index 0981ccdbf..ec3913415 100644 --- a/src/smt/theory_bv.cpp +++ b/src/smt/theory_bv.cpp @@ -28,7 +28,6 @@ namespace smt { void theory_bv::init(context * ctx) { theory::init(ctx); - m_simplifier = &(ctx->get_simplifier()); } theory_var theory_bv::mk_var(enode * n) { @@ -300,7 +299,7 @@ namespace smt { void theory_bv::simplify_bit(expr * s, expr_ref & r) { // proof_ref p(get_manager()); // if (get_context().at_base_level()) - // m_simplifier->operator()(s, r, p); + // ctx.get_rewriter()(s, r, p); // else r = s; } @@ -605,8 +604,9 @@ namespace smt { args.push_back(m.mk_ite(b, n, zero)); num *= numeral(2); } - expr_ref sum(m); - arith_simp().mk_add(sz, args.c_ptr(), sum); + expr_ref sum(m_autil.mk_add(sz, args.c_ptr()), m); + arith_rewriter arw(m); + ctx.get_rewriter()(sum); literal l(mk_eq(n, sum, false)); TRACE("bv", tout << mk_pp(n, m) << "\n"; @@ -1366,7 +1366,6 @@ namespace smt { m_params(params), m_util(m), m_autil(m), - m_simplifier(0), m_bb(m, bb_params), m_trail_stack(*this), m_find(*this), diff --git a/src/smt/theory_bv.h b/src/smt/theory_bv.h index 5d2ea8da5..c35078ace 100644 --- a/src/smt/theory_bv.h +++ b/src/smt/theory_bv.h @@ -24,10 +24,7 @@ Revision History: #include "ast/rewriter/bit_blaster/bit_blaster.h" #include "util/trail.h" #include "util/union_find.h" -#include "ast/simplifier/simplifier.h" -#include "ast/simplifier/bv_simplifier_plugin.h" #include "ast/arith_decl_plugin.h" -#include "ast/simplifier/arith_simplifier_plugin.h" #include "smt/proto_model/numeral_factory.h" namespace smt { @@ -112,7 +109,6 @@ namespace smt { theory_bv_params const & m_params; bv_util m_util; arith_util m_autil; - simplifier * m_simplifier; bit_blaster m_bb; th_trail_stack m_trail_stack; th_union_find m_find; @@ -218,12 +214,6 @@ namespace smt { void assign_bit(literal consequent, theory_var v1, theory_var v2, unsigned idx, literal antecedent, bool propagate_eqc); void assert_int2bv_axiom(app* n); void assert_bv2int_axiom(app* n); - arith_simplifier_plugin & arith_simp() const { - SASSERT(m_simplifier != 0); - arith_simplifier_plugin * as = static_cast(m_simplifier->get_plugin(m_autil.get_family_id())); - SASSERT(as != 0); - return *as; - } protected: virtual void init(context * ctx); diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 806d6706b..616314117 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -17,13 +17,13 @@ Revision History: --*/ +#include "util/stats.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_smt2_pp.h" #include "smt/smt_context.h" #include "smt/theory_datatype.h" #include "smt/smt_model_generator.h" -#include "ast/ast_pp.h" -#include "ast/ast_ll_pp.h" -#include "util/stats.h" -#include "ast/ast_smt2_pp.h" namespace smt { @@ -97,12 +97,9 @@ namespace smt { SASSERT(m_util.is_datatype(get_manager().get_sort(n->get_owner()))); ast_manager & m = get_manager(); ptr_vector args; - ptr_vector const * accessors = m_util.get_constructor_accessors(c); - SASSERT(c->get_arity() == accessors->size()); - ptr_vector::const_iterator it = accessors->begin(); - ptr_vector::const_iterator end = accessors->end(); - for (; it != end; ++it) { - func_decl * d = *it; + ptr_vector const & accessors = *m_util.get_constructor_accessors(c); + SASSERT(c->get_arity() == accessors.size()); + for (func_decl * d : accessors) { SASSERT(d->get_arity() == 1); expr * acc = m.mk_app(d, n->get_owner()); args.push_back(acc); @@ -123,15 +120,14 @@ namespace smt { SASSERT(is_constructor(n)); ast_manager & m = get_manager(); func_decl * d = n->get_decl(); - ptr_vector const * accessors = m_util.get_constructor_accessors(d); - SASSERT(n->get_num_args() == accessors->size()); - ptr_vector::const_iterator it = accessors->begin(); - ptr_vector::const_iterator end = accessors->end(); - for (unsigned i = 0; it != end; ++it, ++i) { - func_decl * acc = *it; + ptr_vector const & accessors = *m_util.get_constructor_accessors(d); + SASSERT(n->get_num_args() == accessors.size()); + unsigned i = 0; + for (func_decl * acc : accessors) { app * acc_app = m.mk_app(acc, n->get_owner()); enode * arg = n->get_arg(i); assert_eq_axiom(arg, acc_app, null_literal); + ++i; } } @@ -172,15 +168,12 @@ namespace smt { func_decl * acc = to_func_decl(upd->get_parameter(0).get_ast()); func_decl * con = m_util.get_accessor_constructor(acc); func_decl * rec = m_util.get_constructor_recognizer(con); - ptr_vector const * accessors = m_util.get_constructor_accessors(con); - ptr_vector::const_iterator it = accessors->begin(); - ptr_vector::const_iterator end = accessors->end(); + ptr_vector const & accessors = *m_util.get_constructor_accessors(con); app_ref rec_app(m.mk_app(rec, arg1), m); ctx.internalize(rec_app, false); literal is_con(ctx.get_bool_var(rec_app)); - for (; it != end; ++it) { + for (func_decl* acc1 : accessors) { enode* arg; - func_decl * acc1 = *it; if (acc1 == acc) { arg = n->get_arg(1); } @@ -437,10 +430,7 @@ namespace smt { ctx.set_conflict(ctx.mk_justification(ext_theory_conflict_justification(get_id(), r, 0, 0, m_used_eqs.size(), m_used_eqs.c_ptr()))); TRACE("occurs_check", tout << "occurs_check: true\n"; - enode_pair_vector::const_iterator it = m_used_eqs.begin(); - enode_pair_vector::const_iterator end = m_used_eqs.end(); - for(; it != end; ++it) { - enode_pair const & p = *it; + for (enode_pair const& p : m_used_eqs) { tout << "eq: #" << p.first->get_owner_id() << " #" << p.second->get_owner_id() << "\n"; tout << mk_bounded_pp(p.first->get_owner(), get_manager()) << " " << mk_bounded_pp(p.second->get_owner(), get_manager()) << "\n"; }); @@ -613,11 +603,9 @@ namespace smt { d1->m_constructor = d2->m_constructor; } } - ptr_vector::iterator it = d2->m_recognizers.begin(); - ptr_vector::iterator end = d2->m_recognizers.end(); - for (; it != end; ++it) - if (*it) - add_recognizer(v1, *it); + for (enode* e : d2->m_recognizers) + if (e) + add_recognizer(v1, e); } void theory_datatype::unmerge_eh(theory_var v1, theory_var v2) { @@ -721,8 +709,8 @@ namespace smt { enode * r = d->m_recognizers[unassigned_idx]; literal consequent; if (!r) { - ptr_vector const * constructors = m_util.get_datatype_constructors(dt); - func_decl * rec = m_util.get_constructor_recognizer(constructors->get(unassigned_idx)); + ptr_vector const & constructors = *m_util.get_datatype_constructors(dt); + func_decl * rec = m_util.get_constructor_recognizer(constructors[unassigned_idx]); app * rec_app = get_manager().mk_app(rec, n->get_owner()); ctx.internalize(rec_app, false); consequent = literal(ctx.get_bool_var(rec_app)); @@ -786,9 +774,9 @@ namespace smt { for (unsigned idx = 0; it != end; ++it, ++idx) { enode * curr = *it; if (curr == 0) { - ptr_vector const * constructors = m_util.get_datatype_constructors(s); + ptr_vector const & constructors = *m_util.get_datatype_constructors(s); // found empty slot... - r = m_util.get_constructor_recognizer(constructors->get(idx)); + r = m_util.get_constructor_recognizer(constructors[idx]); break; } else if (!ctx.is_relevant(curr)) { @@ -805,7 +793,7 @@ namespace smt { } SASSERT(r != 0); app * r_app = m.mk_app(r, n->get_owner()); - TRACE("datatype", tout << "creating split: " << mk_bounded_pp(r_app, m) << "\n";); + TRACE("datatype", tout << "creating split: " << mk_pp(r_app, m) << "\n";); ctx.internalize(r_app, false); bool_var bv = ctx.get_bool_var(r_app); ctx.set_true_first_flag(bv); diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h index 342766c04..ad7727a89 100644 --- a/src/smt/theory_dense_diff_logic_def.h +++ b/src/smt/theory_dense_diff_logic_def.h @@ -127,7 +127,7 @@ namespace smt { if (!m_non_diff_logic_exprs) { TRACE("non_diff_logic", tout << "found non diff logic expression:\n" << mk_pp(n, get_manager()) << "\n";); get_context().push_trail(value_trail(m_non_diff_logic_exprs)); - IF_VERBOSE(0, verbose_stream() << "(smt.diff_logic: non-diff logic expression " << mk_pp(n, get_manager()) << ")\n";); + IF_VERBOSE(0, verbose_stream() << "(smt.diff_logic: non-diff logic expression " << mk_pp(n, get_manager()) << ")\n";); m_non_diff_logic_exprs = true; } } @@ -154,6 +154,9 @@ namespace smt { if (m_autil.is_add(lhs) && to_app(lhs)->get_num_args() == 2 && is_times_minus_one(to_app(lhs)->get_arg(1), s)) { t = to_app(to_app(lhs)->get_arg(0)); } + else if (m_autil.is_add(lhs) && to_app(lhs)->get_num_args() == 2 && is_times_minus_one(to_app(lhs)->get_arg(0), s)) { + t = to_app(to_app(lhs)->get_arg(1)); + } else if (m_autil.is_mul(lhs) && to_app(lhs)->get_num_args() == 2 && m_autil.is_minus_one(to_app(lhs)->get_arg(0))) { s = to_app(to_app(lhs)->get_arg(1)); t = mk_zero_for(s); diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index e8edfc7ec..dfd295220 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -385,7 +385,6 @@ namespace smt { { ast_manager & m = get_manager(); context & ctx = get_context(); - simplifier & simp = ctx.get_simplifier(); expr_ref res(m), t(m); proof_ref t_pr(m); @@ -394,7 +393,7 @@ namespace smt { expr_ref_vector::iterator it = m_converter.m_extra_assertions.begin(); expr_ref_vector::iterator end = m_converter.m_extra_assertions.end(); for (; it != end; it++) { - simp(*it, t, t_pr); + ctx.get_rewriter()(*it, t, t_pr); res = m.mk_and(res, t); } m_converter.m_extra_assertions.reset(); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index c5e3ae350..a09005b7e 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -28,6 +28,7 @@ Revision History: #include "util/optional.h" #include "util/lp/lp_params.hpp" #include "util/inf_rational.h" +#include "ast/ast_pp.h" #include "smt/smt_theory.h" #include "smt/smt_context.h" #include "smt/theory_lra.h" diff --git a/src/smt/theory_str.h b/src/smt/theory_str.h index 5837980df..686fcdd57 100644 --- a/src/smt/theory_str.h +++ b/src/smt/theory_str.h @@ -17,13 +17,14 @@ #ifndef _THEORY_STR_H_ #define _THEORY_STR_H_ +#include "util/trail.h" +#include "ast/ast_pp.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/th_rewriter.h" #include "smt/smt_theory.h" #include "smt/params/theory_str_params.h" -#include "util/trail.h" -#include "ast/rewriter/th_rewriter.h" #include "smt/proto_model/value_factory.h" #include "smt/smt_model_generator.h" -#include "ast/arith_decl_plugin.h" #include #include #include diff --git a/src/tactic/bv/elim_small_bv_tactic.cpp b/src/tactic/bv/elim_small_bv_tactic.cpp index c40927179..ab4b3920d 100644 --- a/src/tactic/bv/elim_small_bv_tactic.cpp +++ b/src/tactic/bv/elim_small_bv_tactic.cpp @@ -24,9 +24,7 @@ Revision History: #include "ast/used_vars.h" #include "ast/well_sorted.h" #include "ast/rewriter/var_subst.h" -#include "ast/simplifier/simplifier.h" -#include "ast/simplifier/basic_simplifier_plugin.h" -#include "ast/simplifier/bv_simplifier_plugin.h" +#include "ast/rewriter/th_rewriter.h" #include "tactic/bv/elim_small_bv_tactic.h" @@ -36,7 +34,7 @@ class elim_small_bv_tactic : public tactic { ast_manager & m; params_ref m_params; bv_util m_util; - simplifier m_simp; + th_rewriter m_simp; ref m_mc; goal * m_goal; unsigned m_max_bits; @@ -56,14 +54,6 @@ class elim_small_bv_tactic : public tactic { updt_params(p); m_goal = 0; m_max_steps = UINT_MAX; - - basic_simplifier_plugin * bsimp = alloc(basic_simplifier_plugin, m); - // bsimp->set_eliminate_and(true); - m_simp.register_plugin(bsimp); - - bv_simplifier_params bv_params; - bv_simplifier_plugin * bvsimp = alloc(bv_simplifier_plugin, m, *bsimp, bv_params); - m_simp.register_plugin(bvsimp); } bool max_steps_exceeded(unsigned long long num_steps) const { diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp new file mode 100644 index 000000000..595f8f7c6 --- /dev/null +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -0,0 +1,442 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + dom_simplify_tactic.cpp + +Abstract: + + Dominator-based context simplifer. + +Author: + + Nikolaj and Nuno + +Notes: + +--*/ + + +#include "ast/ast_util.h" +#include "ast/ast_pp.h" +#include "tactic/core/dom_simplify_tactic.h" + + +/** + \brief compute a post-order traversal for e. + Also populate the set of parents +*/ +void expr_dominators::compute_post_order() { + unsigned post_num = 0; + SASSERT(m_post2expr.empty()); + SASSERT(m_expr2post.empty()); + ast_mark mark; + ptr_vector todo; + todo.push_back(m_root); + while (!todo.empty()) { + expr* e = todo.back(); + if (mark.is_marked(e)) { + todo.pop_back(); + continue; + } + if (is_app(e)) { + app* a = to_app(e); + bool done = true; + for (expr* arg : *a) { + if (!mark.is_marked(arg)) { + todo.push_back(arg); + done = false; + } + } + if (done) { + mark.mark(e, true); + m_expr2post.insert(e, post_num++); + m_post2expr.push_back(e); + todo.pop_back(); + for (expr* arg : *a) { + add_edge(m_parents, arg, a); + } + } + } + else { + mark.mark(e, true); + todo.pop_back(); + } + } +} + +expr* expr_dominators::intersect(expr* x, expr * y) { + unsigned n1 = m_expr2post[x]; + unsigned n2 = m_expr2post[y]; + while (n1 != n2) { + if (n1 < n2) { + x = m_doms[x]; + n1 = m_expr2post[x]; + } + else if (n1 > n2) { + y = m_doms[y]; + n2 = m_expr2post[y]; + } + } + SASSERT(x == y); + return x; +} + +void expr_dominators::compute_dominators() { + expr * e = m_root; + SASSERT(m_doms.empty()); + m_doms.insert(e, e); + bool change = true; + while (change) { + change = false; + SASSERT(m_post2expr.back() == e); + for (unsigned i = 0; i < m_post2expr.size() - 1; ++i) { + expr * child = m_post2expr[i]; + ptr_vector const& p = m_parents[child]; + SASSERT(!p.empty()); + expr * new_idom = p[0], * idom2 = 0; + for (unsigned j = 1; j < p.size(); ++j) { + if (m_doms.find(p[j], idom2)) { + new_idom = intersect(new_idom, idom2); + } + } + if (!m_doms.find(child, idom2) || idom2 != new_idom) { + m_doms.insert(child, new_idom); + change = true; + } + } + } +} + +void expr_dominators::extract_tree() { + for (auto const& kv : m_doms) { + add_edge(m_tree, kv.m_value, kv.m_key); + } +} + +void expr_dominators::compile(expr * e) { + reset(); + m_root = e; + compute_post_order(); + compute_dominators(); + extract_tree(); +} + +void expr_dominators::compile(unsigned sz, expr * const* es) { + expr_ref e(m.mk_and(sz, es), m); + compile(e); +} + +void expr_dominators::reset() { + m_expr2post.reset(); + m_post2expr.reset(); + m_parents.reset(); + m_doms.reset(); + m_tree.reset(); + m_root.reset(); +} + + + +// ----------------------- +// dom_simplify_tactic + +tactic * dom_simplify_tactic::translate(ast_manager & m) { + return alloc(dom_simplify_tactic, m, m_simplifier->translate(m), m_params); +} + +void dom_simplify_tactic::operator()( + goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core) { + mc = 0; pc = 0; core = 0; + + tactic_report report("dom-simplify", *in.get()); + simplify_goal(*(in.get())); + in->inc_depth(); + result.push_back(in.get()); + +} + +void dom_simplify_tactic::cleanup() { + m_trail.reset(); + m_args.reset(); + m_args2.reset(); + m_result.reset(); + m_dominators.reset(); +} + +expr_ref dom_simplify_tactic::simplify_ite(app * ite) { + expr_ref r(m); + expr * c = 0, * t = 0, * e = 0; + VERIFY(m.is_ite(ite, c, t, e)); + unsigned old_lvl = scope_level(); + expr_ref new_c = simplify(c); + if (m.is_true(new_c)) { + r = simplify(t); + } + else if (m.is_false(new_c) || !assert_expr(new_c, false)) { + r = simplify(e); + } + else { + expr_ref new_t = simplify(t); + pop(scope_level() - old_lvl); + if (!assert_expr(new_c, true)) { + return new_t; + } + expr_ref new_e = simplify(e); + pop(scope_level() - old_lvl); + if (c == new_c && t == new_t && e == new_e) { + r = ite; + } + else if (new_t == new_e) { + r = new_t; + } + else { + TRACE("tactic", tout << new_c << "\n" << new_t << "\n" << new_e << "\n";); + r = m.mk_ite(new_c, new_t, new_c); + } + } + return r; +} + +expr_ref dom_simplify_tactic::simplify(expr * e0) { + expr_ref r(m); + expr* e = 0; + if (!m_result.find(e0, e)) { + e = e0; + } + + ++m_depth; + if (m_depth > m_max_depth) { + r = e; + } + else if (m.is_ite(e)) { + r = simplify_ite(to_app(e)); + } + else if (m.is_and(e)) { + r = simplify_and(to_app(e)); + } + else if (m.is_or(e)) { + r = simplify_or(to_app(e)); + } + else { + expr_dominators::tree_t const& t = m_dominators.get_tree(); + if (t.contains(e)) { + ptr_vector const& children = t[e]; + for (expr * child : children) { + simplify(child); + } + } + if (is_app(e)) { + m_args.reset(); + for (expr* arg : *to_app(e)) { + m_args.push_back(get_cached(arg)); // TBD is cache really applied to all sub-terms? + } + r = m.mk_app(to_app(e)->get_decl(), m_args.size(), m_args.c_ptr()); + } + else { + r = e; + } + } + (*m_simplifier)(r); + cache(e0, r); + TRACE("simplify", tout << "depth: " << m_depth << " " << mk_pp(e0, m) << " -> " << r << "\n";); + --m_depth; + return r; +} + +expr_ref dom_simplify_tactic::simplify_and_or(bool is_and, app * e) { + expr_ref r(m); + unsigned old_lvl = scope_level(); + m_args.reset(); + for (expr * arg : *e) { + r = simplify(arg); + if (!assert_expr(r, !is_and)) { + r = is_and ? m.mk_false() : m.mk_true(); + } + m_args.push_back(r); + } + pop(scope_level() - old_lvl); + m_args.reverse(); + m_args2.reset(); + for (expr * arg : m_args) { + r = simplify(arg); + if (!assert_expr(r, !is_and)) { + r = is_and ? m.mk_false() : m.mk_true(); + } + m_args2.push_back(r); + } + pop(scope_level() - old_lvl); + m_args2.reverse(); + r = is_and ? mk_and(m_args2) : mk_or(m_args2); + return r; +} + + +void dom_simplify_tactic::init(goal& g) { + expr_ref_vector args(m); + unsigned sz = g.size(); + for (unsigned i = 0; i < sz; ++i) args.push_back(g.form(i)); + expr_ref fml = mk_and(args); + m_result.reset(); + m_trail.reset(); + m_dominators.compile(fml); +} + +void dom_simplify_tactic::simplify_goal(goal& g) { + + SASSERT(scope_level() == 0); + bool change = true; + m_depth = 0; + while (change) { + change = false; + + // go forwards + init(g); + unsigned sz = g.size(); + for (unsigned i = 0; !g.inconsistent() && i < sz; ++i) { + expr_ref r = simplify(g.form(i)); + if (i < sz - 1 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !g.proofs_enabled() && !assert_expr(r, false)) { + r = m.mk_false(); + } + change |= r != g.form(i); + proof* new_pr = 0; + if (g.proofs_enabled()) { + new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(g.form(i), r, 0, 0)); + } + g.update(i, r, new_pr, g.dep(i)); + } + pop(scope_level()); + + // go backwards + init(g); + sz = g.size(); + for (unsigned i = sz; !g.inconsistent() && i > 0; ) { + --i; + expr_ref r = simplify(g.form(i)); + if (i > 0 && !m.is_true(r) && !m.is_false(r) && !g.dep(i) && !g.proofs_enabled() && !assert_expr(r, false)) { + r = m.mk_false(); + } + change |= r != g.form(i); + proof* new_pr = 0; + if (g.proofs_enabled()) { + new_pr = m.mk_modus_ponens(g.pr(i), m.mk_rewrite_star(g.form(i), r, 0, 0)); + } + g.update(i, r, new_pr, g.dep(i)); + } + pop(scope_level()); + } + SASSERT(scope_level() == 0); +} + + +// ---------------------- +// expr_substitution_simplifier + +bool expr_substitution_simplifier::assert_expr(expr * t, bool sign) { + expr* tt; + if (!sign) { + update_substitution(t, 0); + } + else if (m.is_not(t, tt)) { + update_substitution(tt, 0); + } + else { + expr_ref nt(m.mk_not(t), m); + update_substitution(nt, 0); + } + return true; +} + + +bool expr_substitution_simplifier::is_gt(expr* lhs, expr* rhs) { + if (lhs == rhs) { + return false; + } + if (m.is_value(rhs)) { + return true; + } + SASSERT(is_ground(lhs) && is_ground(rhs)); + if (depth(lhs) > depth(rhs)) { + return true; + } + if (depth(lhs) == depth(rhs) && is_app(lhs) && is_app(rhs)) { + app* l = to_app(lhs); + app* r = to_app(rhs); + if (l->get_decl()->get_id() != r->get_decl()->get_id()) { + return l->get_decl()->get_id() > r->get_decl()->get_id(); + } + if (l->get_num_args() != r->get_num_args()) { + return l->get_num_args() > r->get_num_args(); + } + for (unsigned i = 0; i < l->get_num_args(); ++i) { + if (l->get_arg(i) != r->get_arg(i)) { + return is_gt(l->get_arg(i), r->get_arg(i)); + } + } + UNREACHABLE(); + } + + return false; +} + +void expr_substitution_simplifier::update_substitution(expr* n, proof* pr) { + expr* lhs, *rhs, *n1; + if (is_ground(n) && (m.is_eq(n, lhs, rhs) || m.is_iff(n, lhs, rhs))) { + compute_depth(lhs); + compute_depth(rhs); + if (is_gt(lhs, rhs)) { + TRACE("propagate_values", tout << "insert " << mk_pp(lhs, m) << " -> " << mk_pp(rhs, m) << "\n";); + m_scoped_substitution.insert(lhs, rhs, pr); + return; + } + if (is_gt(rhs, lhs)) { + TRACE("propagate_values", tout << "insert " << mk_pp(rhs, m) << " -> " << mk_pp(lhs, m) << "\n";); + m_scoped_substitution.insert(rhs, lhs, m.mk_symmetry(pr)); + return; + } + TRACE("propagate_values", tout << "incompatible " << mk_pp(n, m) << "\n";); + } + if (m.is_not(n, n1)) { + m_scoped_substitution.insert(n1, m.mk_false(), m.mk_iff_false(pr)); + } + else { + m_scoped_substitution.insert(n, m.mk_true(), m.mk_iff_true(pr)); + } +} + +void expr_substitution_simplifier::compute_depth(expr* e) { + ptr_vector todo; + todo.push_back(e); + while (!todo.empty()) { + e = todo.back(); + unsigned d = 0; + if (m_expr2depth.contains(e)) { + todo.pop_back(); + continue; + } + if (is_app(e)) { + app* a = to_app(e); + bool visited = true; + for (expr* arg : *a) { + unsigned d1 = 0; + if (m_expr2depth.find(arg, d1)) { + d = std::max(d, d1); + } + else { + visited = false; + todo.push_back(arg); + } + } + if (!visited) { + continue; + } + } + todo.pop_back(); + m_expr2depth.insert(e, d + 1); + } +} diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h new file mode 100644 index 000000000..2fa79dd1d --- /dev/null +++ b/src/tactic/core/dom_simplify_tactic.h @@ -0,0 +1,163 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + dom_simplify_tactic.cpp + +Abstract: + + Dominator-based context simplifer. + +Author: + + Nikolaj and Nuno + +Notes: + +--*/ + +#ifndef DOM_SIMPLIFY_TACTIC_H_ +#define DOM_SIMPLIFY_TACTIC_H_ + +#include "ast/ast.h" +#include "ast/expr_substitution.h" +#include "tactic/tactic.h" + + +class expr_dominators { +public: + typedef obj_map> tree_t; +private: + ast_manager& m; + expr_ref m_root; + obj_map m_expr2post; // reverse post-order number + ptr_vector m_post2expr; + tree_t m_parents; + obj_map m_doms; + tree_t m_tree; + + void add_edge(tree_t& tree, expr * src, expr* dst) { + tree.insert_if_not_there2(src, ptr_vector())->get_data().m_value.push_back(dst); + } + + void compute_post_order(); + expr* intersect(expr* x, expr * y); + void compute_dominators(); + void extract_tree(); + +public: + expr_dominators(ast_manager& m): m(m), m_root(m) {} + + void compile(expr * e); + void compile(unsigned sz, expr * const* es); + tree_t const& get_tree() { return m_tree; } + void reset(); + +}; + +class dom_simplify_tactic : public tactic { +public: + class simplifier { + public: + virtual ~simplifier() {} + /** + \brief assert_expr performs an implicit push + */ + virtual bool assert_expr(expr * t, bool sign) = 0; + + /** + \brief apply simplification. + */ + virtual void operator()(expr_ref& r) = 0; + + /** + \brief pop scopes accumulated from assertions. + */ + virtual void pop(unsigned num_scopes) = 0; + + virtual simplifier * translate(ast_manager & m); + + }; +private: + ast_manager& m; + simplifier* m_simplifier; + params_ref m_params; + expr_ref_vector m_trail, m_args, m_args2; + obj_map m_result; + expr_dominators m_dominators; + unsigned m_scope_level; + unsigned m_depth; + unsigned m_max_depth; + + expr_ref simplify(expr* t); + expr_ref simplify_ite(app * ite); + expr_ref simplify_and(app * ite) { return simplify_and_or(true, ite); } + expr_ref simplify_or(app * ite) { return simplify_and_or(false, ite); } + expr_ref simplify_and_or(bool is_and, app * ite); + void simplify_goal(goal& g); + + expr_ref get_cached(expr* t) { expr* r = 0; if (!m_result.find(r, r)) r = t; return expr_ref(r, m); } + void cache(expr *t, expr* r) { m_result.insert(t, r); m_trail.push_back(r); } + + unsigned scope_level() { return m_scope_level; } + void pop(unsigned n) { SASSERT(n <= m_scope_level); m_scope_level -= n; m_simplifier->pop(n); } + bool assert_expr(expr* f, bool sign) { m_scope_level++; return m_simplifier->assert_expr(f, sign); } + + void init(goal& g); + +public: + dom_simplify_tactic(ast_manager & m, simplifier* s, params_ref const & p = params_ref()): + m(m), m_simplifier(s), m_params(p), + m_trail(m), m_args(m), m_args2(m), + m_dominators(m), + m_scope_level(0), m_depth(0), m_max_depth(1024) {} + + + virtual ~dom_simplify_tactic() {} + + virtual tactic * translate(ast_manager & m); + virtual void updt_params(params_ref const & p) {} + static void get_param_descrs(param_descrs & r) {} + virtual void collect_param_descrs(param_descrs & r) { get_param_descrs(r); } + + virtual void operator()(goal_ref const & in, + goal_ref_buffer & result, + model_converter_ref & mc, + proof_converter_ref & pc, + expr_dependency_ref & core); + + virtual void cleanup(); +}; + +class expr_substitution_simplifier : public dom_simplify_tactic::simplifier { + ast_manager& m; + expr_substitution m_subst; + scoped_expr_substitution m_scoped_substitution; + obj_map m_expr2depth; + + // move from asserted_formulas to here.. + void compute_depth(expr* e); + bool is_gt(expr* lhs, expr* rhs); + unsigned depth(expr* e) { return m_expr2depth[e]; } + +public: + expr_substitution_simplifier(ast_manager& m): m(m), m_subst(m), m_scoped_substitution(m_subst) {} + virtual ~expr_substitution_simplifier() {} + virtual bool assert_expr(expr * t, bool sign); + + void update_substitution(expr* n, proof* pr); + + virtual void operator()(expr_ref& r) { r = m_scoped_substitution.find(r); } + + virtual void pop(unsigned num_scopes) { m_scoped_substitution.pop(num_scopes); } + + virtual simplifier * translate(ast_manager & m) { + SASSERT(m_subst.empty()); + return alloc(expr_substitution_simplifier, m); + } + + +}; + +#endif diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 73adabb6f..6a38f787e 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -174,11 +174,8 @@ class elim_uncnstr_tactic : public tactic { if (fid == m_dt_util.get_family_id()) { // In the current implementation, I only handle the case where // the datatype has a recursive constructor. - ptr_vector const * constructors = m_dt_util.get_datatype_constructors(s); - ptr_vector::const_iterator it = constructors->begin(); - ptr_vector::const_iterator end = constructors->end(); - for (; it != end; ++it) { - func_decl * constructor = *it; + ptr_vector const & constructors = *m_dt_util.get_datatype_constructors(s); + for (func_decl * constructor : constructors) { unsigned num = constructor->get_arity(); unsigned target = UINT_MAX; for (unsigned i = 0; i < num; i++) { @@ -707,10 +704,10 @@ class elim_uncnstr_tactic : public tactic { app * u; if (!mk_fresh_uncnstr_var_for(f, num, args, u)) return u; - ptr_vector const * accs = m_dt_util.get_constructor_accessors(c); + ptr_vector const & accs = *m_dt_util.get_constructor_accessors(c); ptr_buffer new_args; - for (unsigned i = 0; i < accs->size(); i++) { - if (accs->get(i) == f) + for (unsigned i = 0; i < accs.size(); i++) { + if (accs[i] == f) new_args.push_back(u); else new_args.push_back(m().get_some_value(c->get_domain(i))); @@ -726,9 +723,9 @@ class elim_uncnstr_tactic : public tactic { return u; if (!m_mc) return u; - ptr_vector const * accs = m_dt_util.get_constructor_accessors(f); + ptr_vector const & accs = *m_dt_util.get_constructor_accessors(f); for (unsigned i = 0; i < num; i++) { - add_def(args[i], m().mk_app(accs->get(i), u)); + add_def(args[i], m().mk_app(accs[i], u)); } return u; } diff --git a/src/tactic/ufbv/macro_finder_tactic.cpp b/src/tactic/ufbv/macro_finder_tactic.cpp index bf8e08fb7..3a482f37c 100644 --- a/src/tactic/ufbv/macro_finder_tactic.cpp +++ b/src/tactic/ufbv/macro_finder_tactic.cpp @@ -17,10 +17,6 @@ Notes: --*/ #include "tactic/tactical.h" -#include "ast/simplifier/simplifier.h" -#include "ast/simplifier/basic_simplifier_plugin.h" -#include "ast/simplifier/arith_simplifier_plugin.h" -#include "ast/simplifier/bv_simplifier_plugin.h" #include "ast/macros/macro_manager.h" #include "ast/macros/macro_finder.h" #include "tactic/extension_model_converter.h" @@ -52,19 +48,7 @@ class macro_finder_tactic : public tactic { bool produce_proofs = g->proofs_enabled(); bool unsat_core_enabled = g->unsat_core_enabled(); - - simplifier simp(m_manager); - basic_simplifier_plugin * bsimp = alloc(basic_simplifier_plugin, m_manager); - bsimp->set_eliminate_and(m_elim_and); - simp.register_plugin(bsimp); - arith_simplifier_params a_params; - arith_simplifier_plugin * asimp = alloc(arith_simplifier_plugin, m_manager, *bsimp, a_params); - simp.register_plugin(asimp); - bv_simplifier_params bv_params; - bv_simplifier_plugin * bvsimp = alloc(bv_simplifier_plugin, m_manager, *bsimp, bv_params); - simp.register_plugin(bvsimp); - - macro_manager mm(m_manager, simp); + macro_manager mm(m_manager); macro_finder mf(m_manager, mm); expr_ref_vector forms(m_manager), new_forms(m_manager); diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index c501559a5..925b5a5e3 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -17,10 +17,6 @@ Notes: --*/ #include "tactic/tactical.h" -#include "ast/simplifier/simplifier.h" -#include "ast/simplifier/basic_simplifier_plugin.h" -#include "ast/simplifier/arith_simplifier_plugin.h" -#include "ast/simplifier/bv_simplifier_plugin.h" #include "ast/macros/macro_manager.h" #include "ast/macros/macro_finder.h" #include "tactic/extension_model_converter.h" @@ -50,20 +46,9 @@ class quasi_macros_tactic : public tactic { bool produce_proofs = g->proofs_enabled(); bool produce_unsat_cores = g->unsat_core_enabled(); - - simplifier simp(m_manager); - basic_simplifier_plugin * bsimp = alloc(basic_simplifier_plugin, m_manager); - bsimp->set_eliminate_and(true); - simp.register_plugin(bsimp); - arith_simplifier_params a_params; - arith_simplifier_plugin * asimp = alloc(arith_simplifier_plugin, m_manager, *bsimp, a_params); - simp.register_plugin(asimp); - bv_simplifier_params bv_params; - bv_simplifier_plugin * bvsimp = alloc(bv_simplifier_plugin, m_manager, *bsimp, bv_params); - simp.register_plugin(bvsimp); - - macro_manager mm(m_manager, simp); - quasi_macros qm(m_manager, mm, simp); + + macro_manager mm(m_manager); + quasi_macros qm(m_manager, mm); bool more = true; expr_ref_vector forms(m_manager), new_forms(m_manager); diff --git a/src/tactic/ufbv/ufbv_rewriter.cpp b/src/tactic/ufbv/ufbv_rewriter.cpp index 4f0f5e548..446d1a49c 100644 --- a/src/tactic/ufbv/ufbv_rewriter.cpp +++ b/src/tactic/ufbv/ufbv_rewriter.cpp @@ -20,20 +20,23 @@ Revision History: --*/ +#include "util/uint_set.h" #include "ast/ast_pp.h" -#include "tactic/ufbv/ufbv_rewriter.h" #include "ast/for_each_expr.h" #include "ast/rewriter/var_subst.h" -#include "util/uint_set.h" +#include "tactic/ufbv/ufbv_rewriter.h" -ufbv_rewriter::ufbv_rewriter(ast_manager & m, basic_simplifier_plugin & p): +ufbv_rewriter::ufbv_rewriter(ast_manager & m): m_manager(m), m_match_subst(m), - m_bsimp(p), + m_bsimp(m), m_todo(m), m_rewrite_todo(m), m_rewrite_cache(m), m_new_exprs(m) { + params_ref p; + p.set_bool("elim_and", true); + m_bsimp.updt_params(p); } ufbv_rewriter::~ufbv_rewriter() { @@ -396,7 +399,7 @@ expr * ufbv_rewriter::rewrite(expr * n) { if (f->get_family_id() != m_manager.get_basic_family_id()) na = m_manager.mk_app(f, m_new_args.size(), m_new_args.c_ptr()); else - m_bsimp.reduce(f, m_new_args.size(), m_new_args.c_ptr(), na); + m_bsimp.mk_app(f, m_new_args.size(), m_new_args.c_ptr(), na); TRACE("demodulator_bug", tout << "e:\n" << mk_pp(e, m_manager) << "\nnew_args: \n"; for (unsigned i = 0; i < m_new_args.size(); i++) { tout << mk_pp(m_new_args[i], m_manager) << "\n"; } tout << "=====>\n"; diff --git a/src/tactic/ufbv/ufbv_rewriter.h b/src/tactic/ufbv/ufbv_rewriter.h index d11453836..1e13f4fa4 100644 --- a/src/tactic/ufbv/ufbv_rewriter.h +++ b/src/tactic/ufbv/ufbv_rewriter.h @@ -23,10 +23,10 @@ Revision History: #include "ast/ast.h" #include "ast/substitution/substitution.h" +#include "ast/rewriter/bool_rewriter.h" #include "util/obj_hashtable.h" #include "util/obj_pair_hashtable.h" #include "util/array_map.h" -#include "ast/simplifier/basic_simplifier_plugin.h" /** \brief Apply demodulators as a preprocessing technique. @@ -159,7 +159,7 @@ class ufbv_rewriter { ast_manager & m_manager; match_subst m_match_subst; - basic_simplifier_plugin & m_bsimp; + bool_rewriter m_bsimp; fwd_idx_map m_fwd_idx; back_idx_map m_back_idx; demodulator2lhs_rhs m_demodulator2lhs_rhs; @@ -194,7 +194,7 @@ protected: virtual int is_subset(expr * e1, expr * e2) const; public: - ufbv_rewriter(ast_manager & m, basic_simplifier_plugin & p); + ufbv_rewriter(ast_manager & m); virtual ~ufbv_rewriter(); void operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); diff --git a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp index b4bfabf65..615593317 100644 --- a/src/tactic/ufbv/ufbv_rewriter_tactic.cpp +++ b/src/tactic/ufbv/ufbv_rewriter_tactic.cpp @@ -17,8 +17,6 @@ Notes: --*/ #include "tactic/tactical.h" -#include "ast/simplifier/simplifier.h" -#include "ast/simplifier/basic_simplifier_plugin.h" #include "tactic/ufbv/ufbv_rewriter.h" #include "tactic/ufbv/ufbv_rewriter_tactic.h" @@ -45,9 +43,7 @@ class ufbv_rewriter_tactic : public tactic { bool produce_proofs = g->proofs_enabled(); - basic_simplifier_plugin bsimp(m_manager); - bsimp.set_eliminate_and(true); - ufbv_rewriter dem(m_manager, bsimp); + ufbv_rewriter dem(m_manager); expr_ref_vector forms(m_manager), new_forms(m_manager); proof_ref_vector proofs(m_manager), new_proofs(m_manager); diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index b395c09e6..fbcaec5ef 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -20,7 +20,6 @@ add_executable(test-z3 bits.cpp bit_vector.cpp buffer.cpp - bv_simplifier_plugin.cpp chashtable.cpp check_assumptions.cpp cnf_backbones.cpp diff --git a/src/test/bv_simplifier_plugin.cpp b/src/test/bv_simplifier_plugin.cpp deleted file mode 100644 index 15ca9fac5..000000000 --- a/src/test/bv_simplifier_plugin.cpp +++ /dev/null @@ -1,326 +0,0 @@ - -/*++ -Copyright (c) 2015 Microsoft Corporation - ---*/ - -#include "ast/simplifier/bv_simplifier_plugin.h" -#include "ast/arith_decl_plugin.h" -#include "ast/ast_pp.h" -#include "ast/reg_decl_plugins.h" - -class tst_bv_simplifier_plugin_cls { - class mgr { - public: - mgr(ast_manager& m) { - reg_decl_plugins(m); - } - }; - ast_manager m_manager; - mgr m_mgr; - bv_simplifier_params m_bv_params; - basic_simplifier_plugin m_bsimp; - arith_util m_arith; - bv_simplifier_plugin m_simp; - bv_util m_bv_util; - family_id m_fid; - - void get_num(expr* e, unsigned bv_size, rational& r) { - unsigned bv_size0; - if (!m_bv_util.is_numeral(e, r, bv_size0)) { - UNREACHABLE(); - } - ENSURE(bv_size == bv_size0); - } - - unsigned u32(expr* e) { - rational r; - std::cout << mk_pp(e,m_manager) << "\n"; - get_num(e, 32, r); - return r.get_unsigned(); - } - - unsigned char u8(expr* e) { - rational r; - get_num(e, 8, r); - return static_cast(r.get_unsigned()); - } - int i32(expr* e) { - return static_cast(u32(e)); - } - - uint64 u64(expr* e) { - rational r; - get_num(e, 64, r); - return r.get_uint64(); - } - - int64 i64(expr* e) { - rational r; - get_num(e, 64, r); - if (r >= power(rational(2), 63)) { - r -= power(rational(2), 64); - } - return r.get_int64(); - } - - bool ast2bool(expr* e) { - if (m_manager.is_true(e)) { - return true; - } - if (m_manager.is_false(e)) { - return false; - } - UNREACHABLE(); - return false; - } - - bool bit2bool(expr* e) { - rational r; - get_num(e, 1, r); - return 0 != r.get_unsigned(); - } - - expr* mk_int(unsigned i) { - return m_arith.mk_numeral(rational(i), true); - } - -public: - - tst_bv_simplifier_plugin_cls() : - m_mgr(m_manager), - m_bsimp(m_manager), - m_arith(m_manager), - m_simp(m_manager, m_bsimp, m_bv_params), - m_bv_util(m_manager), - m_fid(0) { - m_fid = m_manager.mk_family_id("bv"); - } - - ~tst_bv_simplifier_plugin_cls() {} - - void test_num(unsigned a) { - expr_ref e(m_manager), e1(m_manager); - app_ref ar(m_manager); - uint64 a64 = static_cast(a); - - e1 = m_bv_util.mk_numeral(rational(a), 32); - expr* const es[1] = { e1.get() }; - - ar = m_manager.mk_app(m_fid, OP_BNEG, e1.get()); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - ENSURE((0-a) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BNOT, e1.get()); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - ENSURE((~a) == u32(e.get())); - - parameter params[2] = { parameter(32), parameter(32) }; - ar = m_manager.mk_app(m_fid, OP_SIGN_EXT, 1, params, 1, es); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - ENSURE(((int64)(int)a) == i64(e.get())); - - ar = m_manager.mk_app(m_fid, OP_ZERO_EXT, 1, params, 1, es); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - ENSURE(((uint64)a) == u64(e.get())); - - params[0] = parameter(7); - params[1] = parameter(0); - ar = m_manager.mk_app(m_fid, OP_EXTRACT, 2, params, 1, es); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - ENSURE(((unsigned char)a) == u8(e.get())); - - params[0] = parameter(2); - ar = m_manager.mk_app(m_fid, OP_REPEAT, 1, params, 1, es); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY(((a64 << 32) | a64) == u64(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BREDOR, e1.get()); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - ENSURE((a != 0) == bit2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BREDAND, e1.get()); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - ENSURE((a == 0xFFFFFFFF) == bit2bool(e.get())); - - params[0] = parameter(8); - - ar = m_manager.mk_app(m_fid, OP_ROTATE_LEFT, 1, params, 1, es); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - ENSURE(((a << 8) | (a >> 24)) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_ROTATE_RIGHT, 1, params, 1, es); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - ENSURE(((a >> 8) | (a << 24)) == u32(e.get())); - - params[0] = parameter(m_manager.mk_sort(m_manager.mk_family_id("arith"), INT_SORT)); - ar = m_manager.mk_app(m_fid, OP_BV2INT, 1, params, 1, es); - expr* es2[1] = { ar.get() }; - params[0] = parameter(32); - ar = m_manager.mk_app(m_fid, OP_INT2BV, 1, params, 1, es2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - ENSURE(a == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BIT0); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY(!bit2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BIT1); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY(bit2bool(e.get())); - - } - - void test_pair(unsigned a, unsigned b) { - - expr_ref e(m_manager), e1(m_manager), e2(m_manager); - app_ref ar(m_manager); - int sa = static_cast(a); - int sb = static_cast(b); - uint64 a64 = static_cast(a); - uint64 b64 = static_cast(b); - - e1 = m_bv_util.mk_numeral(rational(a), 32); - e2 = m_bv_util.mk_numeral(rational(b), 32); - expr* const e1e2[] = { e1.get(), e2.get() }; - - - ar = m_manager.mk_app(m_fid, OP_BADD, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a + b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BSUB, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a - b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BMUL, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a * b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BAND, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a & b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BOR, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a | b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BNOR, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY(~(a | b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BXOR, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a ^ b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BXNOR, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((~(a ^ b)) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BNAND, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((~(a & b)) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_ULEQ, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a <= b) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_UGEQ, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a >= b) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_ULT, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a < b) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_UGT, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a > b) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_SLEQ, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((sa <= sb) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_SGEQ, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((sa >= sb) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_SLT, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((sa < sb) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_SGT, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((sa > sb) == ast2bool(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BSHL, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY(((b>=32)?0:(a << b)) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BLSHR, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY(((b>=32)?0:(a >> b)) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BASHR, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - - std::cout << "compare: " << sa << " >> " << b << " = " << (sa >> b) << " with " << i32(e.get()) << "\n"; - VERIFY(b >= 32 || ((sa >> b) == i32(e.get()))); - - if (b != 0) { - ar = m_manager.mk_app(m_fid, OP_BSDIV, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((sa / sb) == i32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BUDIV, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a / b) == u32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BSREM, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - //VERIFY((sa % sb) == i32(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BUREM, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a % b) == u32(e.get())); - - // TBD: BSMOD. - } - - ar = m_manager.mk_app(m_fid, OP_CONCAT, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY(((a64 << 32) | b64) == u64(e.get())); - - ar = m_manager.mk_app(m_fid, OP_BCOMP, 2, e1e2); - m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e); - VERIFY((a == b) == bit2bool(e.get())); - } - - void test() { - unsigned_vector nums; - nums.push_back(0); - nums.push_back(1); - nums.push_back(-1); - nums.push_back(2); - nums.push_back(31); - nums.push_back(32); - nums.push_back(33); - nums.push_back(435562); - nums.push_back(-43556211); - // TBD add some random numbers. - - - for (unsigned i = 0; i < nums.size(); ++i) { - test_num(nums[i]); - for (unsigned j = 0; j < nums.size(); ++j) { - test_pair(nums[i], nums[j]); - } - } - } -}; - - -void tst_bv_simplifier_plugin() { - tst_bv_simplifier_plugin_cls tst_cls; - tst_cls.test(); -} diff --git a/src/test/ext_numeral.cpp b/src/test/ext_numeral.cpp index 4c82617c9..003aa272f 100644 --- a/src/test/ext_numeral.cpp +++ b/src/test/ext_numeral.cpp @@ -43,13 +43,13 @@ static void FUN_NAME(int a, ext_numeral_kind ak, int b, ext_numeral_kind bk, int scoped_mpq _a(m), _b(m), _c(m); \ m.set(_a, a); \ m.set(_b, b); \ - ext_numeral_kind ck; \ + ext_numeral_kind ck(EN_NUMERAL); \ OP_NAME(m, _a, ak, _b, bk, _c, ck); \ - ENSURE(ck == expected_ck); \ + ENSURE(ck == expected_ck); \ if (expected_ck == EN_NUMERAL) { \ scoped_mpq _expected_c(m); \ m.set(_expected_c, expected_c); \ - ENSURE(m.eq(_c, _expected_c)); \ + ENSURE(m.eq(_c, _expected_c)); \ } \ } diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index 9337dcee3..6d600f594 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -65,9 +65,8 @@ void test2() { constructor_decl* G = mk_constructor_decl(symbol("G"), symbol("is-G"), 0, 0); constructor_decl* B = mk_constructor_decl(symbol("B"), symbol("is-B"), 0, 0); constructor_decl* constrs[3] = { R, G, B }; - datatype_decl * enum_sort = mk_datatype_decl(symbol("RGB"), 3, constrs); - VERIFY(dt.mk_datatypes(1, &enum_sort, 0, 0, new_sorts)); - del_constructor_decls(3, constrs); + datatype_decl * enum_sort = mk_datatype_decl(dtutil, symbol("RGB"), 0, nullptr, 3, constrs); + VERIFY(dt.mk_datatypes(1, &enum_sort, 0, nullptr, new_sorts)); sort* rgb = new_sorts[0].get(); expr_ref x = mk_const(m, "x", rgb), y = mk_const(m, "y", rgb), z = mk_const(m, "z", rgb); diff --git a/src/test/main.cpp b/src/test/main.cpp index 17ac720dc..2c51df601 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -166,7 +166,6 @@ int main(int argc, char ** argv) { TST(timeout); TST(proof_checker); TST(simplifier); - TST(bv_simplifier_plugin); TST(bit_blaster); TST(var_subst); TST(simple_parser); diff --git a/src/test/quant_elim.cpp b/src/test/quant_elim.cpp index fec86d164..3674e6b70 100644 --- a/src/test/quant_elim.cpp +++ b/src/test/quant_elim.cpp @@ -6,12 +6,7 @@ Copyright (c) 2015 Microsoft Corporation #include "ast/ast.h" #include "smt/params/smt_params.h" -#include "ast/simplifier/simplifier.h" #include "qe/qe.h" -#include "ast/simplifier/basic_simplifier_plugin.h" -#include "ast/simplifier/arith_simplifier_plugin.h" -#include "ast/simplifier/array_simplifier_plugin.h" -#include "ast/simplifier/bv_simplifier_plugin.h" #include "ast/ast_pp.h" #include "parsers/smt/smtlib.h" #include "parsers/smt/smtparser.h" @@ -38,7 +33,6 @@ static void test_qe(ast_manager& m, lbool expected_outcome, expr* fml, char cons // enable_trace("after_search"); // enable_trace("bv_bit_prop"); - simplifier simp(m); smt_params params; // params.m_quant_elim = true; diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index 909ea594e..2984e94e2 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -220,7 +220,7 @@ static void test_sorting_eq(unsigned n, unsigned k) { TRACE("pb", unsigned sz = solver.size(); for (unsigned i = 0; i < sz; ++i) { - tout << mk_pp(solver.get_formulas()[i], m) << "\n"; + tout << mk_pp(solver.get_formula(i), m) << "\n"; }); model_ref model; solver.get_model(model); @@ -266,7 +266,7 @@ static void test_sorting_le(unsigned n, unsigned k) { TRACE("pb", unsigned sz = solver.size(); for (unsigned i = 0; i < sz; ++i) { - tout << mk_pp(solver.get_formulas()[i], m) << "\n"; + tout << mk_pp(solver.get_formula(i), m) << "\n"; }); model_ref model; solver.get_model(model); @@ -314,7 +314,7 @@ void test_sorting_ge(unsigned n, unsigned k) { TRACE("pb", unsigned sz = solver.size(); for (unsigned i = 0; i < sz; ++i) { - tout << mk_pp(solver.get_formulas()[i], m) << "\n"; + tout << mk_pp(solver.get_formula(i), m) << "\n"; }); model_ref model; solver.get_model(model); diff --git a/src/util/symbol_table.h b/src/util/symbol_table.h index ea848d991..818cb7584 100644 --- a/src/util/symbol_table.h +++ b/src/util/symbol_table.h @@ -182,29 +182,20 @@ public: } void append(symbol_table const& other) { - typename sym_table::iterator it = other.m_sym_table.begin(); - typename sym_table::iterator end = other.m_sym_table.end(); - - for (; it != end; ++it) { - insert((*it).m_key, (*it).m_data); + for (auto const& kv : other.m_sym_table) { + insert(kv.m_key, kv.m_data); } } void get_range(vector& range) const { - typename sym_table::iterator it = m_sym_table.begin(); - typename sym_table::iterator end = m_sym_table.end(); - - for (; it != end; ++it) { - range.push_back((*it).m_data); + for (auto kv : m_sym_table) { + range.push_back(kv.m_data); } } void get_dom(svector& dom) const { - typename sym_table::iterator it = m_sym_table.begin(); - typename sym_table::iterator end = m_sym_table.end(); - - for (; it != end; ++it) { - dom.push_back((*it).m_key); + for (auto kv : m_sym_table) { + dom.push_back(kv.m_key); } } };