From 392334f779c089deef73bec472d6eb5bca399219 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Tue, 22 Aug 2017 10:44:00 -0700 Subject: [PATCH 01/74] add ability to create and manipulate model objects Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- examples/c++/example.cpp | 2 +- src/api/api_model.cpp | 54 ++++++++++++++++++++++++++++++++++++++++ src/api/c++/z3++.h | 16 ++++++++++++ src/api/z3_api.h | 30 ++++++++++++++++++++++ 4 files changed, 101 insertions(+), 1 deletion(-) 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/src/api/api_model.cpp b/src/api/api_model.cpp index de917650d..1646c691f 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -30,6 +30,17 @@ Revision History: extern "C" { + Z3_model Z3_API Z3_mk_model(Z3_context c) { + Z3_TRY; + LOG_Z3_mk_model(c); + RESET_ERROR_CODE(); + Z3_model_ref * m_ref = alloc(Z3_model_ref, *mk_c(c)); + m_ref->m_model = alloc(model, mk_c(c)->m()); + mk_c(c)->save_object(m_ref); + RETURN_Z3(of_model(m_ref)); + Z3_CATCH_RETURN(0); + } + void Z3_API Z3_model_inc_ref(Z3_context c, Z3_model m) { Z3_TRY; LOG_Z3_model_inc_ref(c, m); @@ -224,6 +235,31 @@ extern "C" { Z3_CATCH_RETURN(0); } + Z3_func_interp Z3_API Z3_add_func_interp(Z3_context c, Z3_model m, Z3_func_decl f, Z3_ast else_val) { + Z3_TRY; + LOG_Z3_add_func_interp(c, m, f, else_val); + RESET_ERROR_CODE(); + func_decl* d = to_func_decl(f); + model* mdl = to_model_ref(m); + Z3_func_interp_ref * f_ref = alloc(Z3_func_interp_ref, *mk_c(c), mdl); + f_ref->m_func_interp = alloc(func_interp, mk_c(c)->m(), d->get_arity()); + mk_c(c)->save_object(f_ref); + mdl->register_decl(d, f_ref->m_func_interp); + f_ref->m_func_interp->set_else(to_expr(else_val)); + RETURN_Z3(of_func_interp(f_ref)); + Z3_CATCH_RETURN(0); + } + + void Z3_API Z3_add_const_interp(Z3_context c, Z3_model m, Z3_func_decl f, Z3_ast a) { + Z3_TRY; + LOG_Z3_add_const_interp(c, m, f, a); + RESET_ERROR_CODE(); + func_decl* d = to_func_decl(f); + model* mdl = to_model_ref(m); + mdl->register_decl(d, to_expr(a)); + Z3_CATCH; + } + void Z3_API Z3_func_interp_inc_ref(Z3_context c, Z3_func_interp f) { Z3_TRY; LOG_Z3_func_interp_inc_ref(c, f); @@ -292,6 +328,24 @@ extern "C" { Z3_CATCH_RETURN(0); } + void Z3_API Z3_add_func_entry(Z3_context c, Z3_func_interp fi, Z3_ast_vector args, Z3_ast value) { + Z3_TRY; + LOG_Z3_add_func_entry(c, fi, args, value); + //CHECK_NON_NULL(fi, void); + //CHECK_NON_NULL(args, void); + //CHECK_NON_NULL(value, void); + func_interp* _fi = to_func_interp_ref(fi); + expr* _value = to_expr(value); + if (to_ast_vector_ref(args).size() != _fi->get_arity()) { + SET_ERROR_CODE(Z3_IOB); + return; + } + // check sorts of value + expr* const* _args = (expr* const*) to_ast_vector_ref(args).c_ptr(); + _fi->insert_entry(_args, _value); + Z3_CATCH; + } + void Z3_API Z3_func_entry_inc_ref(Z3_context c, Z3_func_entry e) { Z3_TRY; LOG_Z3_func_entry_inc_ref(c, e); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 42db6f352..cf1a5070a 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1731,6 +1731,10 @@ namespace z3 { expr else_value() const { Z3_ast r = Z3_func_interp_get_else(ctx(), m_interp); check_error(); return expr(ctx(), r); } unsigned num_entries() const { unsigned r = Z3_func_interp_get_num_entries(ctx(), m_interp); check_error(); return r; } func_entry entry(unsigned i) const { Z3_func_entry e = Z3_func_interp_get_entry(ctx(), m_interp, i); check_error(); return func_entry(ctx(), e); } + void add_entry(expr_vector const& args, expr& value) { + Z3_add_func_entry(ctx(), m_interp, args, value); + check_error(); + } }; class model : public object { @@ -1740,6 +1744,7 @@ namespace z3 { Z3_model_inc_ref(ctx(), m); } public: + model(context & c):object(c) { init(Z3_mk_model(c)); } model(context & c, Z3_model m):object(c) { init(m); } model(model const & s):object(s) { init(s.m_model); } ~model() { Z3_model_dec_ref(ctx(), m_model); } @@ -1795,6 +1800,17 @@ namespace z3 { return 0 != Z3_model_has_interp(ctx(), m_model, f); } + func_interp add_func_interp(func_decl& f, expr& else_val) { + Z3_func_interp r = Z3_add_func_interp(ctx(), m_model, f, else_val); + check_error(); + return func_interp(ctx(), r); + } + + void add_const_interp(func_decl& f, expr& value) { + Z3_add_const_interp(ctx(), m_model, f, value); + check_error(); + } + friend std::ostream & operator<<(std::ostream & out, model const & m); }; inline std::ostream & operator<<(std::ostream & out, model const & m) { out << Z3_model_to_string(m.ctx(), m); return out; } diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 8d53c9255..46c8fbb30 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4680,6 +4680,14 @@ extern "C" { /** @name Models */ /*@{*/ + + /** + \brief Create a fresh model object. It has reference count 0. + + def_API('Z3_mk_model', MODEL, (_in(CONTEXT),)) + */ + Z3_model Z3_API Z3_mk_model(Z3_context c); + /** \brief Increment the reference counter of the given model. @@ -4850,6 +4858,21 @@ extern "C" { */ Z3_func_decl Z3_API Z3_get_as_array_func_decl(Z3_context c, Z3_ast a); + /** + \brief Create a fresh func_interp object, add it to a model for a specified function. + It has reference count 0. + + def_API('Z3_add_func_interp', FUNC_INTERP, (_in(CONTEXT), _in(MODEL), _in(FUNC_DECL), _in(AST))) + */ + Z3_func_interp Z3_API Z3_add_func_interp(Z3_context c, Z3_model m, Z3_func_decl f, Z3_ast else_val); + + /** + \brief Add a constant interpretation. + + def_API('Z3_add_const_interp', VOID, (_in(CONTEXT), _in(MODEL), _in(FUNC_DECL), _in(AST))) + */ + void Z3_API Z3_add_const_interp(Z3_context c, Z3_model m, Z3_func_decl f, Z3_ast a); + /** \brief Increment the reference counter of the given Z3_func_interp object. @@ -4904,6 +4927,13 @@ extern "C" { */ unsigned Z3_API Z3_func_interp_get_arity(Z3_context c, Z3_func_interp f); + /** + \brief add a function entry to a function interpretation. + + def_API('Z3_add_func_entry', VOID, (_in(CONTEXT), _in(FUNC_INTERP), _in(AST_VECTOR), _in(AST))) + */ + void Z3_API Z3_add_func_entry(Z3_context c, Z3_func_interp fi, Z3_ast_vector args, Z3_ast value); + /** \brief Increment the reference counter of the given Z3_func_entry object. From a206362cef8a6dce748f73a14f3aaec8ec14456c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Tue, 22 Aug 2017 11:41:25 -0700 Subject: [PATCH 02/74] add comments addressing some questions #1223 Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/api/z3_api.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 46c8fbb30..bea40f30a 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4862,9 +4862,14 @@ extern "C" { \brief Create a fresh func_interp object, add it to a model for a specified function. It has reference count 0. + \param c context + \param m model + \param f function declaration + \param default_value default value for function interpretation + def_API('Z3_add_func_interp', FUNC_INTERP, (_in(CONTEXT), _in(MODEL), _in(FUNC_DECL), _in(AST))) */ - Z3_func_interp Z3_API Z3_add_func_interp(Z3_context c, Z3_model m, Z3_func_decl f, Z3_ast else_val); + Z3_func_interp Z3_API Z3_add_func_interp(Z3_context c, Z3_model m, Z3_func_decl f, Z3_ast default_value); /** \brief Add a constant interpretation. @@ -4930,6 +4935,15 @@ extern "C" { /** \brief add a function entry to a function interpretation. + \param c logical context + \param fi a function interpregation to be updated. + \param args list of arguments. They should be constant values (such as integers) and be of the same types as the domain of the function. + \param value value of the function when the parameters match args. + + It is assumed that entries added to a function cover disjoint arguments. + If an two entries are added with the same arguments, only the second insertion survives and the + first inserted entry is removed. + def_API('Z3_add_func_entry', VOID, (_in(CONTEXT), _in(FUNC_INTERP), _in(AST_VECTOR), _in(AST))) */ void Z3_API Z3_add_func_entry(Z3_context c, Z3_func_interp fi, Z3_ast_vector args, Z3_ast value); From e2b46257d699b6165c400d8707c1cd4d6d94d95f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Tue, 22 Aug 2017 15:09:34 -0700 Subject: [PATCH 03/74] reducing dependencies on simplifier Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/arith_decl_plugin.h | 18 +- src/ast/bv_decl_plugin.cpp | 10 +- src/ast/bv_decl_plugin.h | 7 +- src/ast/macros/macro_finder.cpp | 20 +- src/ast/macros/macro_finder.h | 3 +- src/ast/macros/macro_manager.cpp | 2 +- src/ast/macros/macro_util.cpp | 85 +++++--- src/ast/macros/macro_util.h | 21 +- src/ast/macros/quasi_macros.cpp | 10 +- src/ast/macros/quasi_macros.h | 7 +- src/ast/rewriter/arith_rewriter.h | 2 +- src/ast/rewriter/poly_rewriter.h | 4 +- src/ast/rewriter/poly_rewriter_def.h | 60 ++++++ src/smt/asserted_formulas.cpp | 2 +- src/smt/smt_model_finder.cpp | 246 ++++++++++++------------ src/smt/smt_model_finder.h | 3 +- src/smt/smt_quantifier.cpp | 2 +- src/tactic/ufbv/quasi_macros_tactic.cpp | 2 +- 18 files changed, 289 insertions(+), 215 deletions(-) diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index a66ddd967..6c2b1c77a 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -389,16 +389,16 @@ public: app * mk_lt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_LT, arg1, arg2); } app * mk_gt(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_GT, arg1, arg2); } - app * mk_add(unsigned num_args, expr * const * args) { return m_manager.mk_app(m_afid, OP_ADD, num_args, args); } - app * mk_add(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2); } - app * mk_add(expr * arg1, expr * arg2, expr* arg3) { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2, arg3); } + app * mk_add(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_ADD, num_args, args); } + app * mk_add(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2); } + app * mk_add(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(m_afid, OP_ADD, arg1, arg2, arg3); } - app * mk_sub(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_SUB, arg1, arg2); } - app * mk_sub(unsigned num_args, expr * const * args) { return m_manager.mk_app(m_afid, OP_SUB, num_args, args); } - app * mk_mul(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2); } - app * mk_mul(expr * arg1, expr * arg2, expr* arg3) { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2, arg3); } - app * mk_mul(unsigned num_args, expr * const * args) { return m_manager.mk_app(m_afid, OP_MUL, num_args, args); } - app * mk_uminus(expr * arg) { return m_manager.mk_app(m_afid, OP_UMINUS, arg); } + app * mk_sub(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_SUB, arg1, arg2); } + app * mk_sub(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_SUB, num_args, args); } + app * mk_mul(expr * arg1, expr * arg2) const { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2); } + app * mk_mul(expr * arg1, expr * arg2, expr* arg3) const { return m_manager.mk_app(m_afid, OP_MUL, arg1, arg2, arg3); } + app * mk_mul(unsigned num_args, expr * const * args) const { return m_manager.mk_app(m_afid, OP_MUL, num_args, args); } + app * mk_uminus(expr * arg) const { return m_manager.mk_app(m_afid, OP_UMINUS, arg); } app * mk_div(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_DIV, arg1, arg2); } app * mk_idiv(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_IDIV, arg1, arg2); } app * mk_rem(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_REM, arg1, arg2); } 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<bv_decl_plugin*>(m.get_plugin(m.mk_family_id("bv"))); } -app * bv_util::mk_numeral(rational const & val, sort* s) { +app * bv_util::mk_numeral(rational const & val, sort* s) const { if (!is_bv_sort(s)) { return 0; } @@ -855,7 +861,7 @@ app * bv_util::mk_numeral(rational const & val, sort* s) { return mk_numeral(val, bv_size); } -app * bv_util::mk_numeral(rational const & val, unsigned bv_size) { +app * bv_util::mk_numeral(rational const & val, unsigned bv_size) const { parameter p1(val); parameter p[2] = { p1, parameter(static_cast<int>(bv_size)) }; return m_manager.mk_app(get_fid(), OP_BV_NUM, 2, p, 0, 0); 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/macros/macro_finder.cpp b/src/ast/macros/macro_finder.cpp index 285c0e5fb..1d441aee7 100644 --- a/src/ast/macros/macro_finder.cpp +++ b/src/ast/macros/macro_finder.cpp @@ -48,14 +48,12 @@ bool macro_finder::is_macro(expr * n, app_ref & head, expr_ref & def) { bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_exprs, proof_ref_vector & new_prs) { 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_manager.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); @@ -66,10 +64,10 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_ex 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); + 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); @@ -88,10 +86,9 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_ex 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_ref new_rhs2(m_autil.mk_add(def, k_app), m_manager); 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))); + expr * body2 = m_manager.mk_app(new_body->get_decl(), k_app, m_autil.mk_int(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); @@ -158,7 +155,8 @@ static void pseudo_predicate_macro2macro(ast_manager & m, app * head, app * t, e macro_finder::macro_finder(ast_manager & m, macro_manager & mm): m_manager(m), m_macro_manager(mm), - m_util(mm.get_util()) { + m_util(mm.get_util()), + m_autil(m) { } macro_finder::~macro_finder() { diff --git a/src/ast/macros/macro_finder.h b/src/ast/macros/macro_finder.h index 7f1b27f0e..5807573ae 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" bool is_macro_head(expr * n, unsigned num_decls); @@ -37,7 +36,7 @@ class macro_finder { ast_manager & m_manager; macro_manager & m_macro_manager; macro_util & m_util; - arith_simplifier_plugin * get_arith_simp() { return m_util.get_arith_simp(); } + arith_util m_autil; bool expand_macros(unsigned num, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); bool is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index bd330a2de..f26a87445 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -28,7 +28,7 @@ Revision History: macro_manager::macro_manager(ast_manager & m, simplifier & s): m_manager(m), m_simplifier(s), - m_util(m, s), + m_util(m), m_decls(m), m_macros(m), m_macro_prs(m), diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index 35f2fbcfb..b7eb9657f 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -29,16 +29,17 @@ 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) { } +#if 0 arith_simplifier_plugin * macro_util::get_arith_simp() const { if (m_arith_simp == 0) { const_cast<macro_util*>(this)->m_arith_simp = static_cast<arith_simplifier_plugin*>(m_simplifier.get_plugin(m_manager.mk_family_id("arith"))); @@ -54,7 +55,7 @@ bv_simplifier_plugin * macro_util::get_bv_simp() const { SASSERT(m_bv_simp != 0); return m_bv_simp; } - +#endif bool macro_util::is_bv(expr * n) const { return m_bv.is_bv(n); @@ -65,32 +66,41 @@ 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 { @@ -98,7 +108,7 @@ void macro_util::mk_sub(expr * t1, expr * t2, expr_ref & r) const { r = m_bv.mk_bv_sub(t1, t2); } else { - get_arith_simp()->mk_sub(t1, t2, r); + r = m_arith.mk_sub(t1, t2); } } @@ -107,18 +117,32 @@ void macro_util::mk_add(expr * t1, expr * t2, expr_ref & r) const { r = m_bv.mk_bv_add(t1, t2); } else { - get_arith_simp()->mk_add(t1, t2, r); + r = m_arith.mk_add(t1, t2); } } 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 +265,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 +295,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 +310,11 @@ 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); + def = m_arith.mk_sub(tmp, rhs); else - as->mk_sub(rhs, tmp, def); + def = m_arith.mk_sub(rhs, tmp); return true; } diff --git a/src/ast/macros/macro_util.h b/src/ast/macros/macro_util.h index d76f2f0d3..91d96cc5e 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; + arith_rewriter m_arith_rw; + bv_rewriter m_bv_rw; obj_hashtable<func_decl> * m_forbidden_set; bool is_forbidden(func_decl * f) const { return m_forbidden_set != 0 && m_forbidden_set->contains(f); } @@ -94,11 +90,9 @@ private: public: - macro_util(ast_manager & m, simplifier & s); + macro_util(ast_manager & m); void set_forbidden_set(obj_hashtable<func_decl> * s) { m_forbidden_set = s; } - arith_simplifier_plugin * get_arith_simp() const; - bv_simplifier_plugin * get_bv_simp() const; bool is_macro_head(expr * n, unsigned num_decls) const; bool is_left_simple_macro(expr * n, unsigned num_decls, app_ref & head, expr_ref & def) const; @@ -113,6 +107,8 @@ public: return is_arith_macro(n, num_decls, head, def, inv); } + bool is_zero_safe(expr * n) const; + bool is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t); bool is_pseudo_head(expr * n, unsigned num_decls, app_ref & head, app_ref & t); bool is_pseudo_predicate_macro(expr * n, app_ref & head, app_ref & t, expr_ref & def); @@ -137,7 +133,6 @@ public: void mk_sub(expr * t1, expr * t2, expr_ref & r) const; void mk_add(expr * t1, expr * t2, expr_ref & r) const; void mk_add(unsigned num_args, expr * const * args, sort * s, expr_ref & r) const; - poly_simplifier_plugin * get_poly_simp_for(sort * s) const; }; #endif diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index b39adde03..822532532 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) { @@ -299,8 +299,8 @@ void quasi_macros::apply_macros(unsigned n, expr * const * exprs, proof * const proof_ref pr(m_manager), ps(m_manager); proof * p = m_manager.proofs_enabled() ? prs[i] : 0; m_macro_manager.expand_macros(exprs[i], p, r, pr); - m_simplifier(r, rs, ps); - new_exprs.push_back(rs); + m_rewriter(r); + new_exprs.push_back(r); new_prs.push_back(ps); } } diff --git a/src/ast/macros/quasi_macros.h b/src/ast/macros/quasi_macros.h index 3a9b6074e..29efe63c7 100644 --- a/src/ast/macros/quasi_macros.h +++ b/src/ast/macros/quasi_macros.h @@ -21,8 +21,7 @@ Revision History: #include<sstream> #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 +31,7 @@ class quasi_macros { ast_manager & m_manager; macro_manager & m_macro_manager; - simplifier & m_simplifier; + th_rewriter m_rewriter; occurrences_map m_occurrences; ptr_vector<expr> m_todo; @@ -57,7 +56,7 @@ class quasi_macros { void apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); public: - quasi_macros(ast_manager & m, macro_manager & mm, simplifier & s); + quasi_macros(ast_manager & m, macro_manager & mm); ~quasi_macros(); /** diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index de849dbd7..5d9fb1d66 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,6 +44,7 @@ protected: decl_kind power_decl_kind() const { return OP_POWER; } public: arith_rewriter_core(ast_manager & m):m_util(m) {} + bool is_zero(expr * n) const { return m_util.is_zero(n); } }; class arith_rewriter : public poly_rewriter<arith_rewriter_core> { diff --git a/src/ast/rewriter/poly_rewriter.h b/src/ast/rewriter/poly_rewriter.h index 5d38e4b10..5269f25a8 100644 --- a/src/ast/rewriter/poly_rewriter.h +++ b/src/ast/rewriter/poly_rewriter.h @@ -39,7 +39,6 @@ protected: 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); } @@ -111,6 +110,9 @@ 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); + 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..a8d115d64 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -931,3 +931,63 @@ expr* poly_rewriter<Config>::merge_muls(expr* x, expr* y) { m1[k] = mk_add_app(2, args); return mk_mul_app(k+1, m1.c_ptr()); } + +template<typename Config> +bool poly_rewriter<Config>::is_times_minus_one(expr * n, expr* & r) const { + if (is_mul(n) && to_app(n)->get_num_args() == 2 && is_minus_one(to_app(n)->get_arg(0))) { + r = to_app(n)->get_arg(1); + return true; + } + return false; +} + +/** + \brief Return true if n is can be put into the form (+ v t) or (+ (- v) t) + \c inv = true will contain true if (- v) is found, and false otherwise. +*/ +template<typename Config> +bool poly_rewriter<Config>::is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) { + if (!is_add(n) || is_ground(n)) + return false; + + ptr_buffer<expr> args; + v = 0; + expr * curr = to_app(n); + bool stop = false; + inv = false; + while (!stop) { + expr * arg; + expr * neg_arg; + if (is_add(curr)) { + arg = to_app(curr)->get_arg(0); + curr = to_app(curr)->get_arg(1); + } + else { + arg = curr; + stop = true; + } + if (is_ground(arg)) { + TRACE("model_checker_bug", tout << "pushing:\n" << mk_pp(arg, m()) << "\n";); + args.push_back(arg); + } + else if (is_var(arg)) { + if (v != 0) + return false; // already found variable + v = to_var(arg); + } + else if (is_times_minus_one(arg, neg_arg) && is_var(neg_arg)) { + if (v != 0) + return false; // already found variable + v = to_var(neg_arg); + inv = true; + } + else { + return false; // non ground term. + } + } + if (v == 0) + return false; // did not find variable + SASSERT(!args.empty()); + mk_add(args.size(), args.c_ptr(), t); + return true; +} diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index cbbb9a6bc..2f55cd704 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -410,7 +410,7 @@ void asserted_formulas::apply_quasi_macros() { 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); + quasi_macros proc(m, m_macro_manager); 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, diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 73d1e9f22..2e6a34557 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<node> 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<arith_simplifier_plugin*>(s.get_plugin(m.mk_family_id("arith"))); - m_bvsimp = static_cast<bv_simplifier_plugin*>(s.get_plugin(m.mk_family_id("bv"))); } virtual ~auf_solver() { @@ -488,12 +486,8 @@ namespace smt { 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; } @@ -652,7 +646,7 @@ 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) && + !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<expr> 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,33 @@ 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<expr> 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); + if (m_arith.is_int(s)) { + expr_ref one(m_arith.mk_int(1), m); + for (expr * e : exceptions) { + expr_ref e_plus_1(m_arith.mk_add(e, one), m); + expr_ref e_minus_1(m_arith.mk_sub(e, one), m); + 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); + for (expr * e : exceptions) { + expr_ref e_plus_1(m_bv.mk_bv_add(e, one), m); + expr_ref e_minus_1(m_bv.mk_bv_sub(e, one), m); + 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 +796,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<class T> 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, v1)) { return v1 < v2; } else { @@ -815,15 +815,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 +835,14 @@ namespace smt { void sort_values(node * n, ptr_buffer<expr> & 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<arith_util>(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<bv_util>(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 +853,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); + expr_ref c(m); if (is_arith) - as->mk_lt(var, values[i], c); + 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 +882,8 @@ namespace smt { ptr_buffer<expr> 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 +914,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 +936,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 +960,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 +971,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";); } } @@ -1037,13 +1035,13 @@ namespace smt { 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 +1050,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())); + 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_manager) << "\n";); + mk_pp(new_fi->get_else(), m) << "\n";); m_model->reregister_decl(f, new_fi, f_aux); } } @@ -1256,21 +1254,21 @@ 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_util arith(ctx->get_manager()); + bv_util bv(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)) + arg_minus_k = bv.mk_bv_sub(arg, m_offset); else - as->mk_sub(arg, m_offset, arg_minus_k); + arg_minus_k = arith.mk_sub(arg, m_offset); S_j->insert(arg_minus_k, e_arg->get_generation()); } } @@ -1290,20 +1288,20 @@ namespace smt { template<bool PLUS> 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<expr, unsigned> const & elems_s = from_s->get_elems(); + + arith_util arith(m_offset.get_manager()); + bv_util bv(m_offset.get_manager()); + bool is_bv = bv.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); + n_k = is_bv ? bv.mk_bv_add(n, m_offset) : arith.mk_add(n, m_offset); else - ps->mk_sub(n, m_offset, n_k); + n_k = is_bv ? bv.mk_bv_sub(n, m_offset) : arith.mk_sub(n, m_offset); to->insert(n_k, kv.m_value); } } @@ -1897,11 +1895,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 +1912,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 +1943,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 +1978,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 +1991,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 +2010,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 +2021,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,10 +2371,10 @@ 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_mutil(m), m_array_util(m), m_arith_util(m), m_bv_util(m), @@ -3152,11 +3144,11 @@ namespace smt { // // ----------------------------------- - 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_quantifier.cpp b/src/smt/smt_quantifier.cpp index 84ed7c8cd..6a2f848d9 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -434,7 +434,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); diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index ab68a2b63..f7312fd2e 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -63,7 +63,7 @@ class quasi_macros_tactic : public tactic { simp.register_plugin(bvsimp); macro_manager mm(m_manager, simp); - quasi_macros qm(m_manager, mm, simp); + quasi_macros qm(m_manager, mm); bool more = true; expr_ref_vector forms(m_manager), new_forms(m_manager); From f7ca7409cec5ce622725a9e35eb3ff935bdc890e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Tue, 22 Aug 2017 17:05:40 -0700 Subject: [PATCH 04/74] fix regressions introduced when modifying macro_util Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/macros/macro_util.cpp | 13 +++++----- src/ast/macros/macro_util.h | 4 +-- src/smt/smt_model_finder.cpp | 48 +++++++++++++++++++++++------------ 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index b7eb9657f..6bc1ee66e 100644 --- a/src/ast/macros/macro_util.cpp +++ b/src/ast/macros/macro_util.cpp @@ -105,19 +105,19 @@ app * macro_util::mk_zero(sort * s) const { 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 { - r = m_arith.mk_sub(t1, t2); + 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 { - r = m_arith.mk_add(t1, t2); + m_arith_rw.mk_add(t1, t2, r); } } @@ -312,9 +312,10 @@ bool macro_util::is_arith_macro(expr * n, unsigned num_decls, app_ref & head, ex expr_ref tmp(m_manager); tmp = m_arith.mk_add(args.size(), args.c_ptr()); if (inv) - def = m_arith.mk_sub(tmp, rhs); + mk_sub(tmp, rhs, def); else - def = m_arith.mk_sub(rhs, tmp); + 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 91d96cc5e..3ab00df2a 100644 --- a/src/ast/macros/macro_util.h +++ b/src/ast/macros/macro_util.h @@ -60,8 +60,8 @@ private: ast_manager & m_manager; bv_util m_bv; arith_util m_arith; - arith_rewriter m_arith_rw; - bv_rewriter m_bv_rw; + mutable arith_rewriter m_arith_rw; + mutable bv_rewriter m_bv_rw; obj_hashtable<func_decl> * m_forbidden_set; bool is_forbidden(func_decl * f) const { return m_forbidden_set != 0 && m_forbidden_set->contains(f); } diff --git a/src/smt/smt_model_finder.cpp b/src/smt/smt_model_finder.cpp index 2e6a34557..f678ee3e7 100644 --- a/src/smt/smt_model_finder.cpp +++ b/src/smt/smt_model_finder.cpp @@ -755,11 +755,13 @@ namespace smt { arith_rewriter arw(m); bv_rewriter brw(m); ptr_vector<expr> const & exceptions = n->get_exceptions(); + 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) { - expr_ref e_plus_1(m_arith.mk_add(e, one), m); - expr_ref e_minus_1(m_arith.mk_sub(e, one), m); + 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); @@ -768,9 +770,10 @@ namespace smt { } 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) { - expr_ref e_plus_1(m_bv.mk_bv_add(e, one), m); - expr_ref e_minus_1(m_bv.mk_bv_sub(e, one), m); + 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); @@ -806,7 +809,7 @@ namespace smt { numeral_lt(T& a): m_util(a) {} bool operator()(expr* e1, expr* e2) { rational v1, v2; - if (m_util.is_numeral(e1, v1) && m_util.is_numeral(e2, v1)) { + if (m_util.is_numeral(e1, v1) && m_util.is_numeral(e2, v2)) { return v1 < v2; } else { @@ -1260,15 +1263,16 @@ namespace smt { for (; it != end; it++) { enode * n = *it; if (ctx->is_relevant(n)) { - arith_util arith(ctx->get_manager()); + 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 (bv.is_bv(arg)) - arg_minus_k = bv.mk_bv_sub(arg, m_offset); + if (bv.is_bv(arg)) + bv_rw.mk_sub(arg, m_offset, arg_minus_k); else - arg_minus_k = arith.mk_sub(arg, m_offset); + arith_rw.mk_sub(arg, m_offset, arg_minus_k); S_j->insert(arg_minus_k, e_arg->get_generation()); } } @@ -1291,17 +1295,29 @@ namespace smt { instantiation_set const * from_s = from->get_instantiation_set(); obj_map<expr, unsigned> const & elems_s = from_s->get_elems(); - arith_util arith(m_offset.get_manager()); - bv_util bv(m_offset.get_manager()); - bool is_bv = bv.is_bv_sort(from->get_sort()); + 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) - n_k = is_bv ? bv.mk_bv_add(n, m_offset) : arith.mk_add(n, m_offset); - else - n_k = is_bv ? bv.mk_bv_sub(n, m_offset) : arith.mk_sub(n, m_offset); + 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); } } From ce04c18a7a8965ffc1642e56779e1e5db9c6d750 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Tue, 22 Aug 2017 22:14:13 -0700 Subject: [PATCH 05/74] trying to get rid of last simplifier dependency in macros Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/fpa/fpa2bv_converter.h | 4 +- src/ast/macros/macro_manager.cpp | 159 ++++++++++++++++++++---- src/ast/macros/macro_manager.h | 14 ++- src/ast/rewriter/poly_rewriter_def.h | 4 + src/muz/pdr/pdr_util.h | 2 +- src/muz/rel/dl_bound_relation.cpp | 2 +- src/muz/rel/dl_bound_relation.h | 3 +- src/smt/asserted_formulas.cpp | 2 +- src/tactic/ufbv/macro_finder_tactic.cpp | 2 +- src/tactic/ufbv/quasi_macros_tactic.cpp | 2 +- 10 files changed, 158 insertions(+), 36 deletions(-) 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/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index f26a87445..70434435b 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -22,12 +22,14 @@ 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), + +macro_manager::macro_manager(ast_manager & m): + m(m), m_util(m), m_decls(m), m_macros(m), @@ -60,12 +62,12 @@ 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_decls.shrink(old_sz); m_macros.shrink(old_sz); - if (m_manager.proofs_enabled()) + if (m.proofs_enabled()) m_macro_prs.shrink(old_sz); } @@ -88,8 +90,8 @@ void macro_manager::reset() { m_deps.reset(); } -bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) { - 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) { + 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)) { @@ -99,7 +101,7 @@ bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) { 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); @@ -108,10 +110,10 @@ bool macro_manager::insert(func_decl * f, quantifier * m, proof * pr) { } // 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); } @@ -152,7 +154,7 @@ void macro_manager::mark_forbidden(unsigned n, expr * const * exprs) { 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)); @@ -177,7 +179,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"; } } @@ -188,12 +190,115 @@ 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): +struct macro_manager::macro_expander_cfg : public default_rewriter_cfg { + ast_manager& m; + macro_manager& mm; + expr_ref_vector m_trail; + + macro_expander_cfg(ast_manager& m, macro_manager& mm): + m(m), + mm(mm), + m_trail(m) + {} + + 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; + } + + 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 < 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; + } + + bool get_subst(expr * _n, expr* & r, proof* & p) { + if (!is_app(_n)) + return false; + app * n = to_app(_n); + quantifier * q = 0; + func_decl * d = n->get_decl(); + TRACE("macro_manager", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";); + if (mm.m_decl2macro.find(d, q)) { + TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";); + app * head = 0; + expr * def = 0; + mm.get_head_def(q, d, head, def); + unsigned num = n->get_num_args(); + SASSERT(head && def); + ptr_buffer<expr> subst_args; + subst_args.resize(num, 0); + for (unsigned i = 0; i < num; i++) { + var * v = to_var(head->get_arg(i)); + SASSERT(v->get_idx() < num); + unsigned nidx = num - v->get_idx() - 1; + SASSERT(subst_args[nidx] == 0); + subst_args[nidx] = n->get_arg(i); + } + var_subst s(m); + expr_ref rr(m); + s(def, num, subst_args.c_ptr(), rr); + m_trail.push_back(rr); + r = rr; + if (m.proofs_enabled()) { + expr_ref instance(m); + s(q->get_expr(), num, subst_args.c_ptr(), instance); + proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr()); + proof * q_pr = 0; + mm.m_decl2macro_pr.find(d, q_pr); + SASSERT(q_pr != 0); + proof * prs[2] = { qi_pr, q_pr }; + p = m.mk_unit_resolution(2, prs); + } + else { + p = 0; + } + return true; + } + return false; + } +}; + +struct macro_manager::macro_expander_rw : public rewriter_tpl<macro_manager::macro_expander_cfg> { + macro_expander_cfg m_cfg; + macro_expander_rw(ast_manager& m, macro_manager& mm): + rewriter_tpl<macro_manager::macro_expander_cfg>(m, m.proofs_enabled(), m_cfg), + m_cfg(m, mm) + {} +}; + +macro_manager::macro_expander::macro_expander(ast_manager & m, macro_manager & mm): simplifier(m), m_macro_manager(mm) { // REMARK: theory simplifier should not be used by macro_expander... @@ -295,20 +400,30 @@ bool macro_manager::macro_expander::get_subst(expr * _n, expr_ref & r, proof_ref void macro_manager::expand_macros(expr * n, proof * pr, expr_ref & r, proof_ref & new_pr) { 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_ref old_n(m); + proof_ref old_pr(m); old_n = n; old_pr = pr; + 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_pr = m.mk_modus_ponens(old_pr, n_eq_r_pr); if (r.get() == old_n.get()) - return; + break; old_n = r; old_pr = new_pr; + 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 a0a42b790..98e242cd8 100644 --- a/src/ast/macros/macro_manager.h +++ b/src/ast/macros/macro_manager.h @@ -19,8 +19,8 @@ Revision History: #ifndef MACRO_MANAGER_H_ #define MACRO_MANAGER_H_ -#include "ast/ast_util.h" #include "util/obj_hashtable.h" +#include "ast/ast_util.h" #include "ast/simplifier/simplifier.h" #include "ast/recurse_expr.h" #include "ast/func_decl_dependencies.h" @@ -36,8 +36,7 @@ Revision History: It has support for backtracking and tagging declarations in an expression as forbidded for being macros. */ class macro_manager { - ast_manager & m_manager; - simplifier & m_simplifier; + ast_manager & m; macro_util m_util; obj_map<func_decl, quantifier *> m_decl2macro; // func-decl -> quantifier @@ -58,21 +57,24 @@ class macro_manager { void restore_decls(unsigned old_sz); void restore_forbidden(unsigned old_sz); + struct macro_expander_cfg; + struct macro_expander_rw; + 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: - macro_expander(ast_manager & m, macro_manager & mm, simplifier & s); + macro_expander(ast_manager & m, macro_manager & mm); ~macro_expander(); }; friend class macro_expander; 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); bool has_macros() const { return !m_macros.empty(); } diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index a8d115d64..6b747756c 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -118,6 +118,9 @@ expr * poly_rewriter<Config>::mk_mul_app(numeral const & c, expr * arg) { if (c.is_one()) { return arg; } + else if (is_zero(arg)) { + return arg; + } else { expr * new_args[2] = { mk_numeral(c), arg }; return mk_mul_app(2, new_args); @@ -654,6 +657,7 @@ br_status poly_rewriter<Config>::mk_sub(unsigned num_args, expr * const * args, ptr_buffer<expr> new_args; new_args.push_back(args[0]); for (unsigned i = 1; i < num_args; i++) { + if (is_zero(args[i])) continue; expr * aux_args[2] = { minus_one, args[i] }; new_args.push_back(mk_mul_app(2, aux_args)); } 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..1678e23b8 100644 --- a/src/muz/rel/dl_bound_relation.h +++ b/src/muz/rel/dl_bound_relation.h @@ -27,6 +27,7 @@ Revision History: #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 +45,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/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 2f55cd704..7eb189ebf 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -52,7 +52,7 @@ asserted_formulas::asserted_formulas(ast_manager & m, smt_params & p): m_asserted_formulas(m), m_asserted_formula_prs(m), m_asserted_qhead(0), - m_macro_manager(m, m_simplifier), + m_macro_manager(m), m_bit2int(m), m_bv_sharing(m), m_inconsistent(false){ diff --git a/src/tactic/ufbv/macro_finder_tactic.cpp b/src/tactic/ufbv/macro_finder_tactic.cpp index 9b1835ff3..b3f258ba7 100644 --- a/src/tactic/ufbv/macro_finder_tactic.cpp +++ b/src/tactic/ufbv/macro_finder_tactic.cpp @@ -64,7 +64,7 @@ class macro_finder_tactic : public tactic { 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 f7312fd2e..8a91bde61 100644 --- a/src/tactic/ufbv/quasi_macros_tactic.cpp +++ b/src/tactic/ufbv/quasi_macros_tactic.cpp @@ -62,7 +62,7 @@ class quasi_macros_tactic : public tactic { 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); quasi_macros qm(m_manager, mm); bool more = true; From e5826b957f97e2c43ad765ef77b127726b7255eb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Wed, 23 Aug 2017 09:01:25 -0700 Subject: [PATCH 06/74] fix build Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/rewriter/poly_rewriter.h | 1 + src/ast/rewriter/poly_rewriter_def.h | 7 +++++++ src/smt/proto_model/proto_model.cpp | 8 ++++---- src/smt/smt_model_generator.cpp | 6 +++--- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/ast/rewriter/poly_rewriter.h b/src/ast/rewriter/poly_rewriter.h index 5269f25a8..8cbc7f864 100644 --- a/src/ast/rewriter/poly_rewriter.h +++ b/src/ast/rewriter/poly_rewriter.h @@ -112,6 +112,7 @@ public: 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) { diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index 6b747756c..731a0538a 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -64,6 +64,13 @@ expr * poly_rewriter<Config>::get_power_body(expr * t, rational & k) { return t; } +template<typename Config> +bool poly_rewriter<Config>::is_zero(expr* e) const { + rational v; + return is_numeral(e, v) && v.is_zero(); +} + + template<typename Config> expr * poly_rewriter<Config>::mk_mul_app(unsigned num_args, expr * const * args) { switch (num_args) { diff --git a/src/smt/proto_model/proto_model.cpp b/src/smt/proto_model/proto_model.cpp index 9b218037e..725c9fc51 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); } diff --git a/src/smt/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 49e9083f2..953afd4b7 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -17,14 +17,14 @@ Revision History: --*/ -#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" +#include "smt/smt_context.h" +#include "smt/smt_model_generator.h" +#include "smt/proto_model/proto_model.h" namespace smt { From 655b3d9c1953b5deef01bcfd9ef523b032e05bc8 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Wed, 23 Aug 2017 12:17:30 -0700 Subject: [PATCH 07/74] removing dependency on simplifier in pattern_inference Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/macros/macro_manager.cpp | 98 --- src/ast/macros/macro_manager.h | 11 - src/ast/pattern/pattern_inference.cpp | 698 ++++++++++++++++-- src/ast/pattern/pattern_inference.h | 211 +++++- .../dl_mk_quantifier_instantiation.cpp | 2 +- src/smt/asserted_formulas.cpp | 3 +- src/smt/proto_model/proto_model.cpp | 4 +- src/smt/smt_model_generator.cpp | 1 - 8 files changed, 861 insertions(+), 167 deletions(-) diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index 70434435b..bff1e7dae 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -298,104 +298,6 @@ struct macro_manager::macro_expander_rw : public rewriter_tpl<macro_manager::mac {} }; -macro_manager::macro_expander::macro_expander(ast_manager & m, macro_manager & mm): - simplifier(m), - m_macro_manager(mm) { - // 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); -} - -macro_manager::macro_expander::~macro_expander() { - // release_plugins(); -} - -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; - } - else { - for (unsigned i = 0; !erase_patterns && i < q->get_num_patterns(); i++) { - if (q->get_pattern(i) != new_q->get_pattern(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)) - erase_patterns = true; - } - } - 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)) - return false; - app * n = to_app(_n); - quantifier * q = 0; - func_decl * d = n->get_decl(); - TRACE("macro_manager_bug", tout << "trying to expand:\n" << mk_pp(n, m) << "\nd:\n" << d->get_name() << "\n";); - if (m_macro_manager.m_decl2macro.find(d, q)) { - TRACE("macro_manager", tout << "expanding: " << mk_pp(n, m) << "\n";); - app * head = 0; - expr * def = 0; - m_macro_manager.get_head_def(q, d, head, def); - unsigned num = n->get_num_args(); - SASSERT(head && def); - ptr_buffer<expr> subst_args; - subst_args.resize(num, 0); - for (unsigned i = 0; i < num; i++) { - var * v = to_var(head->get_arg(i)); - SASSERT(v->get_idx() < num); - unsigned nidx = num - v->get_idx() - 1; - SASSERT(subst_args[nidx] == 0); - subst_args[nidx] = n->get_arg(i); - } - var_subst s(m); - s(def, num, subst_args.c_ptr(), r); - if (m.proofs_enabled()) { - expr_ref instance(m); - s(q->get_expr(), num, subst_args.c_ptr(), instance); - proof * qi_pr = m.mk_quant_inst(m.mk_or(m.mk_not(q), instance), num, subst_args.c_ptr()); - proof * q_pr = 0; - m_macro_manager.m_decl2macro_pr.find(d, q_pr); - SASSERT(q_pr != 0); - proof * prs[2] = { qi_pr, q_pr }; - p = m.mk_unit_resolution(2, prs); - } - else { - p = 0; - } - return true; - } - return false; -} void macro_manager::expand_macros(expr * n, proof * pr, expr_ref & r, proof_ref & new_pr) { if (has_macros()) { diff --git a/src/ast/macros/macro_manager.h b/src/ast/macros/macro_manager.h index 98e242cd8..71864a699 100644 --- a/src/ast/macros/macro_manager.h +++ b/src/ast/macros/macro_manager.h @@ -60,17 +60,6 @@ class macro_manager { struct macro_expander_cfg; struct macro_expander_rw; - 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: - macro_expander(ast_manager & m, macro_manager & mm); - ~macro_expander(); - }; - friend class macro_expander; - public: macro_manager(ast_manager & m); ~macro_manager(); diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index d97c2f094..94a90d829 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,7 +89,7 @@ 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): +pattern_inference_old::pattern_inference_old(ast_manager & m, pattern_inference_params & params): simplifier(m), m_params(params), m_bfid(m.get_basic_family_id()), @@ -105,7 +107,7 @@ pattern_inference::pattern_inference(ast_manager & m, pattern_inference_params & enable_ac_support(false); } -void pattern_inference::collect::operator()(expr * n, unsigned num_bindings) { +void pattern_inference_old::collect::operator()(expr * n, unsigned num_bindings) { SASSERT(m_info.empty()); SASSERT(m_todo.empty()); SASSERT(m_cache.empty()); @@ -125,7 +127,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_old::collect::visit(expr * n, unsigned delta, bool & visited) { entry e(n, delta); if (!m_cache.contains(e)) { m_todo.push_back(e); @@ -133,7 +135,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_old::collect::visit_children(expr * n, unsigned delta) { bool visited = true; unsigned i; switch (n->get_kind()) { @@ -153,13 +155,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_old::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_old::collect::save_candidate(expr * n, unsigned delta) { switch (n->get_kind()) { case AST_VAR: { unsigned idx = to_var(n)->get_idx(); @@ -247,14 +249,14 @@ void pattern_inference::collect::save_candidate(expr * n, unsigned delta) { } -void pattern_inference::collect::reset() { +void pattern_inference_old::collect::reset() { m_cache.reset(); std::for_each(m_info.begin(), m_info.end(), delete_proc<info>()); m_info.reset(); SASSERT(m_todo.empty()); } -void pattern_inference::add_candidate(app * n, uint_set const & free_vars, unsigned size) { +void pattern_inference_old::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 +273,7 @@ void pattern_inference::add_candidate(app * n, uint_set const & free_vars, unsig \brief Copy the non-looping patterns in m_candidates to result when m_params.m_pi_block_loop_patterns = true. Otherwise, copy m_candidates to result. */ -void pattern_inference::filter_looping_patterns(ptr_vector<app> & result) { +void pattern_inference_old::filter_looping_patterns(ptr_vector<app> & result) { unsigned num = m_candidates.size(); for (unsigned i1 = 0; i1 < num; i1++) { app * n1 = m_candidates.get(i1); @@ -310,7 +312,7 @@ void pattern_inference::filter_looping_patterns(ptr_vector<app> & result) { -inline void pattern_inference::contains_subpattern::save(expr * n) { +inline void pattern_inference_old::contains_subpattern::save(expr * n) { unsigned id = n->get_id(); m_already_processed.assure_domain(id); if (!m_already_processed.contains(id)) { @@ -319,7 +321,7 @@ inline void pattern_inference::contains_subpattern::save(expr * n) { } } -bool pattern_inference::contains_subpattern::operator()(expr * n) { +bool pattern_inference_old::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 +362,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_old::contains_subpattern(expr * n) { return m_contains_subpattern(n); } @@ -372,18 +374,15 @@ inline bool pattern_inference::contains_subpattern(expr * n) { Remark: Every pattern p in patterns is also a member of m_pattern_map. */ -void pattern_inference::filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result) { - ptr_vector<app>::const_iterator it = patterns.begin(); - ptr_vector<app>::const_iterator end = patterns.end(); - for (; it != end; ++it) { - app * curr = *it; +void pattern_inference_old::filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result) { + for (app * curr : patterns) { if (!contains_subpattern(curr)) result.push_back(curr); } } -bool pattern_inference::pattern_weight_lt::operator()(expr * n1, expr * n2) const { +bool pattern_inference_old::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 +400,10 @@ bool pattern_inference::pattern_weight_lt::operator()(expr * n1, expr * n2) cons variables, then it is copied to remaining_candidate_patterns. The new patterns are stored in result. */ -void pattern_inference::candidates2unary_patterns(ptr_vector<app> const & candidate_patterns, +void pattern_inference_old::candidates2unary_patterns(ptr_vector<app> const & candidate_patterns, ptr_vector<app> & remaining_candidate_patterns, app_ref_buffer & result) { - ptr_vector<app>::const_iterator it = candidate_patterns.begin(); - ptr_vector<app>::const_iterator end = candidate_patterns.end(); - for (; it != end; ++it) { - app * candidate = *it; + for (app * candidate : candidate_patterns) { expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate); info const & i = e->get_data().m_value; if (i.m_free_vars.num_elems() == m_num_bindings) { @@ -425,7 +421,7 @@ void pattern_inference::candidates2unary_patterns(ptr_vector<app> const & candid // HACK: limit the number of case-splits: #define MAX_SPLITS 32 -void pattern_inference::candidates2multi_patterns(unsigned max_num_patterns, +void pattern_inference_old::candidates2multi_patterns(unsigned max_num_patterns, ptr_vector<app> const & candidate_patterns, app_ref_buffer & result) { SASSERT(!candidate_patterns.empty()); @@ -469,21 +465,19 @@ void pattern_inference::candidates2multi_patterns(unsigned max_num_patterns, } } -void pattern_inference::reset_pre_patterns() { +void pattern_inference_old::reset_pre_patterns() { std::for_each(m_pre_patterns.begin(), m_pre_patterns.end(), delete_proc<pre_pattern>()); m_pre_patterns.reset(); } #ifdef _TRACE static void dump_app_vector(std::ostream & out, ptr_vector<app> const & v, ast_manager & m) { - ptr_vector<app>::const_iterator it = v.begin(); - ptr_vector<app>::const_iterator end = v.end(); - for (; it != end; ++it) - out << mk_pp(*it, m) << "\n"; + for (app * e : v) + out << mk_pp(e, m) << "\n"; } #endif -bool pattern_inference::is_forbidden(app * n) const { +bool pattern_inference_old::is_forbidden(app * n) const { func_decl const * decl = n->get_decl(); if (is_ground(n)) return false; @@ -499,14 +493,11 @@ bool pattern_inference::is_forbidden(app * n) const { return false; } -bool pattern_inference::has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result) { +bool pattern_inference_old::has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result) { if (m_preferred.empty()) return false; bool found = false; - ptr_vector<app>::const_iterator it = candidate_patterns.begin(); - ptr_vector<app>::const_iterator end = candidate_patterns.end(); - for (; it != end; ++it) { - app * candidate = *it; + for (app * candidate : candidate_patterns) { if (m_preferred.contains(to_app(candidate)->get_decl())) { expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate); info const & i = e->get_data().m_value; @@ -521,7 +512,7 @@ bool pattern_inference::has_preferred_patterns(ptr_vector<app> & candidate_patte return found; } -void pattern_inference::mk_patterns(unsigned num_bindings, +void pattern_inference_old::mk_patterns(unsigned num_bindings, expr * n, unsigned num_no_patterns, expr * const * no_patterns, @@ -578,7 +569,7 @@ void pattern_inference::mk_patterns(unsigned num_bindings, #include "ast/pattern/database.h" -void pattern_inference::reduce1_quantifier(quantifier * q) { +void pattern_inference_old::reduce1_quantifier(quantifier * q) { TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";); if (!q->is_forall()) { simplifier::reduce1_quantifier(q); @@ -739,13 +730,626 @@ void pattern_inference::reduce1_quantifier(quantifier * q) { } -#if 0 -// unused -static void dump_expr_vector(std::ostream & out, ptr_vector<expr> const & v, ast_manager & m) { - ptr_vector<expr>::const_iterator it = v.begin(); - ptr_vector<expr>::const_iterator end = v.end(); - for (; it != end; ++it) - out << mk_pp(*it, m) << "\n"; -} -#endif +pattern_inference_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")), + m_le(m), + m_nested_arith_only(true), + m_block_loop_patterns(params.m_pi_block_loop_patterns), + m_candidates(m), + m_pattern_weight_lt(m_candidates_info), + m_collect(m, *this), + m_contains_subpattern(*this), + m_database(m) { + if (params.m_pi_arith == AP_NO) + register_forbidden_family(m_afid); +} + +void pattern_inference_cfg::collect::operator()(expr * n, unsigned num_bindings) { + SASSERT(m_info.empty()); + SASSERT(m_todo.empty()); + SASSERT(m_cache.empty()); + m_num_bindings = num_bindings; + m_todo.push_back(entry(n, 0)); + while (!m_todo.empty()) { + entry & e = m_todo.back(); + n = e.m_node; + unsigned delta = e.m_delta; + TRACE("collect", tout << "processing: " << n->get_id() << " " << delta << " kind: " << n->get_kind() << "\n";); + TRACE("collect_info", tout << mk_pp(n, m) << "\n";); + if (visit_children(n, delta)) { + m_todo.pop_back(); + save_candidate(n, delta); + } + } + reset(); +} + +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); + visited = false; + } +} + +bool pattern_inference_cfg::collect::visit_children(expr * n, unsigned delta) { + bool visited = true; + unsigned i; + switch (n->get_kind()) { + case AST_APP: + i = to_app(n)->get_num_args(); + while (i > 0) { + --i; + visit(to_app(n)->get_arg(i), delta, visited); + } + break; + case AST_QUANTIFIER: + visit(to_quantifier(n)->get_expr(), delta + to_quantifier(n)->get_num_decls(), visited); + break; + default: + break; + } + return visited; +} + +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_cfg::collect::save_candidate(expr * n, unsigned delta) { + switch (n->get_kind()) { + case AST_VAR: { + unsigned idx = to_var(n)->get_idx(); + if (idx >= delta) { + idx = idx - delta; + uint_set free_vars; + if (idx < m_num_bindings) + free_vars.insert(idx); + info * i = 0; + if (delta == 0) + i = alloc(info, m, n, free_vars, 1); + else + i = alloc(info, m, m.mk_var(idx, to_var(n)->get_sort()), free_vars, 1); + save(n, delta, i); + } + else { + save(n, delta, 0); + } + return; + } + case AST_APP: { + app * c = to_app(n); + func_decl * decl = c->get_decl(); + if (m_owner.is_forbidden(c)) { + save(n, delta, 0); + return; + } + + if (c->get_num_args() == 0) { + save(n, delta, alloc(info, m, n, uint_set(), 1)); + return; + } + + ptr_buffer<expr> buffer; + bool changed = false; // false if none of the children is mapped to a node different from itself. + uint_set free_vars; + unsigned size = 1; + unsigned num = c->get_num_args(); + for (unsigned i = 0; i < num; i++) { + expr * child = c->get_arg(i); + info * child_info = 0; +#ifdef Z3DEBUG + bool found = +#endif + m_cache.find(entry(child, delta), child_info); + SASSERT(found); + if (child_info == 0) { + save(n, delta, 0); + return; + } + buffer.push_back(child_info->m_node.get()); + free_vars |= child_info->m_free_vars; + size += child_info->m_size; + if (child != child_info->m_node.get()) + changed = true; + } + + app * new_node = 0; + if (changed) + new_node = m.mk_app(decl, buffer.size(), buffer.c_ptr()); + else + new_node = to_app(n); + save(n, delta, alloc(info, m, new_node, free_vars, size)); + // Remark: arithmetic patterns are only used if they are nested inside other terms. + // That is, we never consider x + 1 as pattern. On the other hand, f(x+1) can be a pattern + // if arithmetic is not in the forbidden list. + // + // Remark: The rule above has an exception. The operators (div, idiv, mod) are allowed to be + // used as patterns even when they are not nested in other terms. The motivation is that + // Z3 currently doesn't implement them (i.e., they are uninterpreted). So, some users add axioms + // stating properties about these operators. + family_id fid = c->get_family_id(); + decl_kind k = c->get_decl_kind(); + 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); + } + return; + } + default: + save(n, delta, 0); + return; + } +} + + +void pattern_inference_cfg::collect::reset() { + m_cache.reset(); + std::for_each(m_info.begin(), m_info.end(), delete_proc<info>()); + m_info.reset(); + SASSERT(m_todo.empty()); +} + +void pattern_inference_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; + } + + if (!m_candidates_info.contains(n)) { + m_candidates_info.insert(n, info(free_vars, size)); + m_candidates.push_back(n); + } +} + + +/** + \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_cfg::filter_looping_patterns(ptr_vector<app> & result) { + unsigned num = m_candidates.size(); + for (unsigned i1 = 0; i1 < num; i1++) { + app * n1 = m_candidates.get(i1); + expr2info::obj_map_entry * e1 = m_candidates_info.find_core(n1); + SASSERT(e1); + uint_set const & s1 = e1->get_data().m_value.m_free_vars; + if (m_block_loop_patterns) { + bool smaller = false; + for (unsigned i2 = 0; i2 < num; i2++) { + if (i1 != i2) { + app * n2 = m_candidates.get(i2); + expr2info::obj_map_entry * e2 = m_candidates_info.find_core(n2); + if (e2) { + uint_set const & s2 = e2->get_data().m_value.m_free_vars; + // Remark: the comparison operator only makes sense if both AST nodes + // contain the same number of variables. + // Example: + // (f X Y) <: (f (g X Z W) Y) + if (s1 == s2 && m_le(m_num_bindings, n1, n2) && !m_le(m_num_bindings, n2, n1)) { + smaller = true; + break; + } + } + } + } + if (!smaller) + result.push_back(n1); + else + m_candidates_info.erase(n1); + } + else { + result.push_back(n1); + } + } +} + + + +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)) { + m_todo.push_back(n); + m_already_processed.insert(id); + } +} + +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); + SASSERT(_e); + uint_set const & s1 = _e->get_data().m_value.m_free_vars; + save(n); + unsigned num; + while (!m_todo.empty()) { + expr * curr = m_todo.back(); + m_todo.pop_back(); + switch (curr->get_kind()) { + case AST_APP: + if (curr != n) { + expr2info::obj_map_entry * e = m_owner.m_candidates_info.find_core(curr); + if (e) { + uint_set const & s2 = e->get_data().m_value.m_free_vars; + SASSERT(s2.subset_of(s1)); + if (s1 == s2) { + TRACE("pattern_inference", tout << mk_pp(n, m_owner.m) << "\nis bigger than\n" << mk_pp(to_app(curr), m_owner.m) << "\n";); + return true; + } + } + } + num = to_app(curr)->get_num_args(); + for (unsigned i = 0; i < num; i++) + save(to_app(curr)->get_arg(i)); + break; + case AST_VAR: + break; + default: + UNREACHABLE(); + } + } + return false; +} + +/** + 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_cfg::contains_subpattern(expr * n) { + return m_contains_subpattern(n); +} + +/** + \brief Copy a pattern p in patterns to result, if there is no + direct/indirect child of p in patterns which contains the same set + of variables. + + Remark: Every pattern p in patterns is also a member of + m_pattern_map. +*/ +void pattern_inference_cfg::filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result) { + for (app * curr : patterns) { + if (!contains_subpattern(curr)) + result.push_back(curr); + } +} + + +bool pattern_inference_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); + SASSERT(e2 != 0); + info const & i1 = e1->get_data().m_value; + info const & i2 = e2->get_data().m_value; + unsigned num_free_vars1 = i1.m_free_vars.num_elems(); + unsigned num_free_vars2 = i2.m_free_vars.num_elems(); + return num_free_vars1 > num_free_vars2 || (num_free_vars1 == num_free_vars2 && i1.m_size < i2.m_size); +} + +/** + \brief Create unary patterns (single expressions that contain all + bound variables). If a candidate does not contain all bound + variables, then it is copied to remaining_candidate_patterns. The + new patterns are stored in result. +*/ +void pattern_inference_cfg::candidates2unary_patterns(ptr_vector<app> const & candidate_patterns, + ptr_vector<app> & remaining_candidate_patterns, + app_ref_buffer & result) { + 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) { + app * new_pattern = m.mk_pattern(candidate); + result.push_back(new_pattern); + } + else { + remaining_candidate_patterns.push_back(candidate); + } + } +} + +// TODO: this code is too inefficient when the number of candidate +// patterns is too big. +// HACK: limit the number of case-splits: +#define MAX_SPLITS 32 + +void pattern_inference_cfg::candidates2multi_patterns(unsigned max_num_patterns, + ptr_vector<app> const & candidate_patterns, + app_ref_buffer & result) { + SASSERT(!candidate_patterns.empty()); + m_pre_patterns.push_back(alloc(pre_pattern)); + unsigned sz = candidate_patterns.size(); + unsigned num_splits = 0; + for (unsigned j = 0; j < m_pre_patterns.size(); j++) { + pre_pattern * curr = m_pre_patterns[j]; + if (curr->m_free_vars.num_elems() == m_num_bindings) { + app * new_pattern = m.mk_pattern(curr->m_exprs.size(), curr->m_exprs.c_ptr()); + result.push_back(new_pattern); + if (result.size() >= max_num_patterns) + return; + } + else if (curr->m_idx < sz) { + app * n = candidate_patterns[curr->m_idx]; + expr2info::obj_map_entry * e = m_candidates_info.find_core(n); + uint_set const & s = e->get_data().m_value.m_free_vars; + if (!s.subset_of(curr->m_free_vars)) { + pre_pattern * new_p = alloc(pre_pattern,*curr); + new_p->m_exprs.push_back(n); + new_p->m_free_vars |= s; + new_p->m_idx++; + m_pre_patterns.push_back(new_p); + + if (num_splits < MAX_SPLITS) { + m_pre_patterns[j] = 0; + curr->m_idx++; + m_pre_patterns.push_back(curr); + num_splits++; + } + } + else { + m_pre_patterns[j] = 0; + curr->m_idx++; + m_pre_patterns.push_back(curr); + } + } + TRACE("pattern_inference", tout << "m_pre_patterns.size(): " << m_pre_patterns.size() << + "\nnum_splits: " << num_splits << "\n";); + } +} + +void pattern_inference_cfg::reset_pre_patterns() { + std::for_each(m_pre_patterns.begin(), m_pre_patterns.end(), delete_proc<pre_pattern>()); + m_pre_patterns.reset(); +} + + +bool pattern_inference_cfg::is_forbidden(app * n) const { + func_decl const * decl = n->get_decl(); + if (is_ground(n)) + return false; + // Remark: skolem constants should not be used in patterns, since they do not + // occur outside of the quantifier. That is, Z3 will never match this kind of + // pattern. + if (m_params.m_pi_avoid_skolems && decl->is_skolem()) { + CTRACE("pattern_inference_skolem", decl->is_skolem(), tout << "ignoring: " << mk_pp(n, m) << "\n";); + return true; + } + if (is_forbidden(decl)) + return true; + return false; +} + +bool pattern_inference_cfg::has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result) { + if (m_preferred.empty()) + return false; + bool found = false; + 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; + if (i.m_free_vars.num_elems() == m_num_bindings) { + TRACE("pattern_inference", tout << "found preferred pattern:\n" << mk_pp(candidate, m) << "\n";); + app * p = m.mk_pattern(candidate); + result.push_back(p); + found = true; + } + } + } + return found; +} + +void pattern_inference_cfg::mk_patterns(unsigned num_bindings, + expr * n, + unsigned num_no_patterns, + expr * const * no_patterns, + app_ref_buffer & result) { + m_num_bindings = num_bindings; + m_num_no_patterns = num_no_patterns; + m_no_patterns = no_patterns; + + m_collect(n, num_bindings); + + TRACE("pattern_inference", + tout << mk_pp(n, m); + tout << "\ncandidates:\n"; + unsigned num = m_candidates.size(); + for (unsigned i = 0; i < num; i++) { + tout << mk_pp(m_candidates.get(i), m) << "\n"; + }); + + if (!m_candidates.empty()) { + m_tmp1.reset(); + filter_looping_patterns(m_tmp1); + TRACE("pattern_inference", + tout << "candidates after removing looping-patterns:\n"; + dump_app_vector(tout, m_tmp1, m);); + SASSERT(!m_tmp1.empty()); + if (!has_preferred_patterns(m_tmp1, result)) { + // continue if there are no preferred patterns + m_tmp2.reset(); + filter_bigger_patterns(m_tmp1, m_tmp2); + SASSERT(!m_tmp2.empty()); + TRACE("pattern_inference", + tout << "candidates after removing bigger patterns:\n"; + dump_app_vector(tout, m_tmp2, m);); + m_tmp1.reset(); + candidates2unary_patterns(m_tmp2, m_tmp1, result); + unsigned num_extra_multi_patterns = m_params.m_pi_max_multi_patterns; + if (result.empty()) + num_extra_multi_patterns++; + if (num_extra_multi_patterns > 0 && !m_tmp1.empty()) { + // m_pattern_weight_lt is not a total order + std::stable_sort(m_tmp1.begin(), m_tmp1.end(), m_pattern_weight_lt); + TRACE("pattern_inference", + tout << "candidates after sorting:\n"; + dump_app_vector(tout, m_tmp1, m);); + candidates2multi_patterns(num_extra_multi_patterns, m_tmp1, result); + } + } + } + + reset_pre_patterns(); + m_candidates_info.reset(); + m_candidates.reset(); +} + + +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()) { + return false; + } + + int weight = q->get_weight(); + + if (m_params.m_pi_use_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)) { + 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";); + 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()); + 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";); + } + if (m.fine_grain_proofs()) + result_pr = m.mk_rewrite(q, new_q); + return true; + } + } + + if (q->get_num_patterns() > 0) { + return false; + } + + if (m_params.m_pi_nopat_weight >= 0) + weight = m_params.m_pi_nopat_weight; + + SASSERT(q->get_num_patterns() == 0); + + if (m_params.m_pi_arith == AP_CONSERVATIVE) + m_forbidden.push_back(m_afid); + + 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() && 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()) { + warning_msg("ignoring nopats annotation because Z3 couldn't find any other pattern (quantifier id: %s)", q->get_qid().str().c_str()); + } + } + } + + if (m_params.m_pi_arith == AP_CONSERVATIVE) { + m_forbidden.pop_back(); + if (new_patterns.empty()) { + flet<bool> l1(m_block_loop_patterns, false); // allow looping patterns + mk_patterns(q->get_num_decls(), new_body, num_no_patterns, new_no_patterns, new_patterns); + if (!new_patterns.empty()) { + weight = std::max(weight, static_cast<int>(m_params.m_pi_arith_weight)); + if (m_params.m_pi_warnings) { + warning_msg("using arith. in pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_ARITH_WEIGHT=<val>).", + q->get_qid().str().c_str(), weight); + } + } + } + } + + if (m_params.m_pi_arith != AP_NO && new_patterns.empty()) { + if (new_patterns.empty()) { + flet<bool> l1(m_nested_arith_only, false); // try to find a non-nested arith pattern + flet<bool> l2(m_block_loop_patterns, false); // allow looping patterns + mk_patterns(q->get_num_decls(), new_body, num_no_patterns, new_no_patterns, new_patterns); + if (!new_patterns.empty()) { + weight = std::max(weight, static_cast<int>(m_params.m_pi_non_nested_arith_weight)); + if (m_params.m_pi_warnings) { + warning_msg("using non nested arith. pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_NON_NESTED_ARITH_WEIGHT=<val>).", + q->get_qid().str().c_str(), weight); + } + // verbose_stream() << mk_pp(q, m) << "\n"; + } + } + } + + 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); + if (m.fine_grain_proofs()) { + 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) { + pull_quant pull(m); + expr_ref new_expr(m); + proof_ref new_pr(m); + pull(new_q, new_expr, new_pr); + 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(result2, new_patterns.size(), (expr**) new_patterns.c_ptr(), result2->get_expr()); + if (m.fine_grain_proofs()) { + 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";); + } + } + } + + if (new_patterns.empty()) { + if (m_params.m_pi_warnings) { + warning_msg("failed to find a pattern for quantifier (quantifier id: %s)", q->get_qid().str().c_str()); + } + TRACE("pi_failed", tout << mk_pp(q, m) << "\n";); + } + + if (new_patterns.empty() && new_body == q->get_expr()) { + 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"; ); + + return true; +} + +pattern_inference_rw::pattern_inference_rw(ast_manager& m, pattern_inference_params & params): + rewriter_tpl<pattern_inference_cfg>(m, m.proofs_enabled(), m_cfg), + m_cfg(m, params) +{} diff --git a/src/ast/pattern/pattern_inference.h b/src/ast/pattern/pattern_inference.h index a138d1033..7b0ec9cfe 100644 --- a/src/ast/pattern/pattern_inference.h +++ b/src/ast/pattern/pattern_inference.h @@ -21,6 +21,7 @@ Revision History: #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 +61,7 @@ public: bool operator()(unsigned num_bindings, expr * p1, expr * p2); }; -class pattern_inference : public simplifier { +class pattern_inference_old : public simplifier { pattern_inference_params & m_params; family_id m_bfid; family_id m_afid; @@ -88,7 +89,7 @@ class pattern_inference : public simplifier { typedef obj_map<expr, info> expr2info; - expr2info m_candidates_info; // candidate -> set of free vars + size + expr2info m_candidates_info; // candidate -> set of free vars + size app_ref_vector m_candidates; ptr_vector<app> m_tmp1; @@ -136,7 +137,7 @@ class pattern_inference : public simplifier { }; ast_manager & m; - pattern_inference & m_owner; + pattern_inference_old & m_owner; family_id m_afid; unsigned m_num_bindings; typedef map<entry, info *, obj_hash<entry>, default_eq<entry> > cache; @@ -150,7 +151,7 @@ class pattern_inference : public simplifier { void save_candidate(expr * n, unsigned delta); void reset(); public: - collect(ast_manager & m, pattern_inference & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {} + collect(ast_manager & m, pattern_inference_old & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {} void operator()(expr * n, unsigned num_bindings); }; @@ -165,12 +166,12 @@ class pattern_inference : public simplifier { void filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result); class contains_subpattern { - pattern_inference & m_owner; + pattern_inference_old & m_owner; nat_set m_already_processed; ptr_vector<expr> m_todo; void save(expr * n); public: - contains_subpattern(pattern_inference & owner): + contains_subpattern(pattern_inference_old & owner): m_owner(owner) {} bool operator()(expr * n); }; @@ -217,7 +218,7 @@ class pattern_inference : public simplifier { virtual void reduce1_quantifier(quantifier * q); public: - pattern_inference(ast_manager & m, pattern_inference_params & params); + pattern_inference_old(ast_manager & m, pattern_inference_params & params); void register_forbidden_family(family_id fid) { SASSERT(fid != m_bfid); @@ -244,5 +245,201 @@ public: bool is_forbidden(app * n) const; }; +class pattern_inference_cfg : public default_rewriter_cfg { + ast_manager& m; + pattern_inference_params & m_params; + family_id m_bfid; + family_id m_afid; + svector<family_id> m_forbidden; + obj_hashtable<func_decl> m_preferred; + smaller_pattern m_le; + unsigned m_num_bindings; + unsigned m_num_no_patterns; + expr * const * m_no_patterns; + bool m_nested_arith_only; + bool m_block_loop_patterns; + + struct info { + uint_set m_free_vars; + unsigned m_size; + info(uint_set const & vars, unsigned size): + m_free_vars(vars), + m_size(size) { + } + info(): + m_free_vars(), + m_size(0) { + } + }; + + typedef obj_map<expr, info> expr2info; + + expr2info m_candidates_info; // candidate -> set of free vars + size + app_ref_vector m_candidates; + + ptr_vector<app> m_tmp1; + ptr_vector<app> m_tmp2; + ptr_vector<app> m_todo; + + // Compare candidates patterns based on their usefulness + // p1 < p2 if + // - p1 has more free variables than p2 + // - p1 and p2 has the same number of free variables, + // and p1 is smaller than p2. + struct pattern_weight_lt { + expr2info & m_candidates_info; + pattern_weight_lt(expr2info & i): + m_candidates_info(i) { + } + bool operator()(expr * n1, expr * n2) const; + }; + + pattern_weight_lt m_pattern_weight_lt; + + // + // Functor for collecting candidates. + // + class collect { + struct entry { + expr * m_node; + unsigned m_delta; + entry():m_node(0), m_delta(0) {} + entry(expr * n, unsigned d):m_node(n), m_delta(d) {} + unsigned hash() const { + return hash_u_u(m_node->get_id(), m_delta); + } + bool operator==(entry const & e) const { + return m_node == e.m_node && m_delta == e.m_delta; + } + }; + + struct info { + expr_ref m_node; + uint_set m_free_vars; + unsigned m_size; + info(ast_manager & m, expr * n, uint_set const & vars, unsigned sz): + m_node(n, m), m_free_vars(vars), m_size(sz) {} + }; + + ast_manager & m; + pattern_inference_cfg & m_owner; + family_id m_afid; + unsigned m_num_bindings; + typedef map<entry, info *, obj_hash<entry>, default_eq<entry> > cache; + cache m_cache; + ptr_vector<info> m_info; + svector<entry> m_todo; + + void visit(expr * n, unsigned delta, bool & visited); + bool visit_children(expr * n, unsigned delta); + void save(expr * n, unsigned delta, info * i); + void save_candidate(expr * n, unsigned delta); + void reset(); + public: + 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); + }; + + collect m_collect; + + void add_candidate(app * n, uint_set const & s, unsigned size); + + void filter_looping_patterns(ptr_vector<app> & result); + + bool has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result); + + void filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result); + + class contains_subpattern { + pattern_inference_cfg & m_owner; + nat_set m_already_processed; + ptr_vector<expr> m_todo; + void save(expr * n); + public: + contains_subpattern(pattern_inference_cfg & owner): + m_owner(owner) {} + bool operator()(expr * n); + }; + + contains_subpattern m_contains_subpattern; + + bool contains_subpattern(expr * n); + + struct pre_pattern { + ptr_vector<app> m_exprs; // elements of the pattern. + uint_set m_free_vars; // set of free variables in m_exprs + unsigned m_idx; // idx of the next candidate to process. + pre_pattern(): + m_idx(0) { + } + }; + + ptr_vector<pre_pattern> m_pre_patterns; + expr_pattern_match m_database; + + void candidates2unary_patterns(ptr_vector<app> const & candidate_patterns, + ptr_vector<app> & remaining_candidate_patterns, + app_ref_buffer & result); + + void candidates2multi_patterns(unsigned max_num_patterns, + ptr_vector<app> const & candidate_patterns, + app_ref_buffer & result); + + void reset_pre_patterns(); + + /** + \brief All minimal unary patterns (i.e., expressions that + contain all bound variables) are copied to result. If there + are unary patterns, then at most num_extra_multi_patterns multi + patterns are created. If there are no unary pattern, then at + most 1 + num_extra_multi_patterns multi_patterns are created. + */ + void mk_patterns(unsigned num_bindings, // IN number of bindings. + expr * n, // IN node where the patterns are going to be extracted. + unsigned num_no_patterns, // IN num. patterns that should not be used. + expr * const * no_patterns, // IN patterns that should not be used. + app_ref_buffer & result); // OUT result + +public: + pattern_inference_cfg(ast_manager & m, pattern_inference_params & params); + + void register_forbidden_family(family_id fid) { + SASSERT(fid != m_bfid); + m_forbidden.push_back(fid); + } + + /** + \brief Register f as a preferred function symbol. The inference algorithm + gives preference to patterns rooted by this kind of function symbol. + */ + void register_preferred(func_decl * f) { + 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 { + family_id fid = decl->get_family_id(); + if (fid == m_bfid && decl->get_decl_kind() != OP_TRUE && decl->get_decl_kind() != OP_FALSE) + return true; + return std::find(m_forbidden.begin(), m_forbidden.end(), fid) != m_forbidden.end(); + } + + bool is_forbidden(app * n) const; +}; + +class pattern_inference_rw : public rewriter_tpl<pattern_inference_cfg> { + pattern_inference_cfg m_cfg; +public: + pattern_inference_rw(ast_manager& m, pattern_inference_params & params); +}; + #endif /* PATTERN_INFERENCE_H_ */ diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index 7eb2284c0..cfb998a32 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -70,7 +70,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_old infer(m, params); infer(q, qe, new_pr); q = to_quantifier(qe); } diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 7eb189ebf..26265a6f8 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -21,6 +21,7 @@ Revision History: #include "ast/ast_pp.h" #include "ast/for_each_expr.h" #include "ast/well_sorted.h" +#include "ast/rewriter/rewriter_def.h" #include "ast/simplifier/arith_simplifier_plugin.h" #include "ast/simplifier/array_simplifier_plugin.h" #include "ast/simplifier/datatype_simplifier_plugin.h" @@ -517,7 +518,7 @@ void asserted_formulas::reduce_and_solve() { 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); + pattern_inference_rw infer(m, m_params); expr_ref_vector new_exprs(m); proof_ref_vector new_prs(m); unsigned i = m_asserted_qhead; diff --git a/src/smt/proto_model/proto_model.cpp b/src/smt/proto_model/proto_model.cpp index 725c9fc51..0a75ff700 100644 --- a/src/smt/proto_model/proto_model.cpp +++ b/src/smt/proto_model/proto_model.cpp @@ -207,8 +207,10 @@ void proto_model::remove_aux_decls_not_in_set(ptr_vector<func_decl> & 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/smt_model_generator.cpp b/src/smt/smt_model_generator.cpp index 953afd4b7..5848fac62 100644 --- a/src/smt/smt_model_generator.cpp +++ b/src/smt/smt_model_generator.cpp @@ -19,7 +19,6 @@ Revision History: #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" #include "smt/smt_context.h" From f062e170373b1e1c3e7344b0b2a6c0bf93c14097 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Wed, 23 Aug 2017 12:30:33 -0700 Subject: [PATCH 08/74] remove simplifier dependencies from ufbv tactics Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/tactic/ufbv/macro_finder_tactic.cpp | 16 ---------------- src/tactic/ufbv/quasi_macros_tactic.cpp | 17 +---------------- src/tactic/ufbv/ufbv_rewriter.cpp | 13 ++++++++----- src/tactic/ufbv/ufbv_rewriter.h | 6 +++--- src/tactic/ufbv/ufbv_rewriter_tactic.cpp | 6 +----- 5 files changed, 13 insertions(+), 45 deletions(-) diff --git a/src/tactic/ufbv/macro_finder_tactic.cpp b/src/tactic/ufbv/macro_finder_tactic.cpp index b3f258ba7..3832339a8 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,18 +48,6 @@ class macro_finder_tactic : public tactic { fail_if_unsat_core_generation("macro-finder", g); bool produce_proofs = g->proofs_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); macro_finder mf(m_manager, mm); diff --git a/src/tactic/ufbv/quasi_macros_tactic.cpp b/src/tactic/ufbv/quasi_macros_tactic.cpp index 8a91bde61..8196dc664 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,18 +46,7 @@ class quasi_macros_tactic : public tactic { fail_if_unsat_core_generation("quasi-macros", g); bool produce_proofs = g->proofs_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); quasi_macros qm(m_manager, mm); bool more = true; 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); From 7dd28781ab5f26703e8bb79ceee79e4c44bdc339 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Wed, 23 Aug 2017 16:33:36 -0700 Subject: [PATCH 09/74] remove simplifier dependencies from cmakelist.txt files Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/fpa/CMakeLists.txt | 2 +- src/ast/macros/CMakeLists.txt | 2 +- src/ast/pattern/CMakeLists.txt | 2 +- src/ast/pattern/pattern_inference.cpp | 19 ++++++++++++------- src/ast/pattern/pattern_inference.h | 2 ++ src/ast/rewriter/bit_blaster/CMakeLists.txt | 1 - src/model/model_core.cpp | 16 ++++++---------- .../dl_mk_quantifier_instantiation.cpp | 2 +- src/smt/proto_model/CMakeLists.txt | 2 +- 9 files changed, 25 insertions(+), 23 deletions(-) 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/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/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 94a90d829..dfeb29ffe 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -89,6 +89,15 @@ bool smaller_pattern::operator()(unsigned num_bindings, expr * p1, expr * p2) { return process(p1, p2); } + +#ifdef _TRACE +static void dump_app_vector(std::ostream & out, ptr_vector<app> const & v, ast_manager & m) { + for (app * e : v) + out << mk_pp(e, m) << "\n"; +} +#endif + +#if 0 pattern_inference_old::pattern_inference_old(ast_manager & m, pattern_inference_params & params): simplifier(m), m_params(params), @@ -470,12 +479,6 @@ void pattern_inference_old::reset_pre_patterns() { m_pre_patterns.reset(); } -#ifdef _TRACE -static void dump_app_vector(std::ostream & out, ptr_vector<app> const & v, ast_manager & m) { - for (app * e : v) - out << mk_pp(e, m) << "\n"; -} -#endif bool pattern_inference_old::is_forbidden(app * n) const { func_decl const * decl = n->get_decl(); @@ -567,7 +570,6 @@ void pattern_inference_old::mk_patterns(unsigned num_bindings, m_candidates.reset(); } -#include "ast/pattern/database.h" void pattern_inference_old::reduce1_quantifier(quantifier * q) { TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";); @@ -729,6 +731,9 @@ void pattern_inference_old::reduce1_quantifier(quantifier * q) { cache_result(q, new_q, pr); } +#endif + +#include "ast/pattern/database.h" pattern_inference_cfg::pattern_inference_cfg(ast_manager & m, pattern_inference_params & params): diff --git a/src/ast/pattern/pattern_inference.h b/src/ast/pattern/pattern_inference.h index 7b0ec9cfe..281c3ff8b 100644 --- a/src/ast/pattern/pattern_inference.h +++ b/src/ast/pattern/pattern_inference.h @@ -61,6 +61,7 @@ public: bool operator()(unsigned num_bindings, expr * p1, expr * p2); }; +#if 0 class pattern_inference_old : public simplifier { pattern_inference_params & m_params; family_id m_bfid; @@ -244,6 +245,7 @@ public: bool is_forbidden(app * n) const; }; +#endif class pattern_inference_cfg : public default_rewriter_cfg { ast_manager& m; 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/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/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index cfb998a32..f32840c49 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -70,7 +70,7 @@ namespace datalog { if (q->get_num_patterns() == 0) { proof_ref new_pr(m); pattern_inference_params params; - pattern_inference_old infer(m, params); + pattern_inference_rw infer(m, params); infer(q, qe, new_pr); q = to_quantifier(qe); } 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 ) From f91496f5fff77ad04647ff3c9f350a8e92a3641c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Wed, 23 Aug 2017 16:56:55 -0700 Subject: [PATCH 10/74] pruning simplifier dependencies Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/simplifier/pull_ite_tree.cpp | 10 +++++----- src/ast/simplifier/pull_ite_tree.h | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ast/simplifier/pull_ite_tree.cpp b/src/ast/simplifier/pull_ite_tree.cpp index 072bbd12c..a092f9649 100644 --- a/src/ast/simplifier/pull_ite_tree.cpp +++ b/src/ast/simplifier/pull_ite_tree.cpp @@ -21,9 +21,9 @@ Revision History: #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); @@ -181,7 +181,7 @@ void pull_ite_tree::operator()(app * n, app_ref & r, proof_ref & pr) { pull_ite_tree_star::pull_ite_tree_star(ast_manager & m, simplifier & s): simplifier(m), - m_proc(m, s) { + m_proc(m) { borrow_plugins(s); } diff --git a/src/ast/simplifier/pull_ite_tree.h b/src/ast/simplifier/pull_ite_tree.h index bc4a0bb68..4b35c124a 100644 --- a/src/ast/simplifier/pull_ite_tree.h +++ b/src/ast/simplifier/pull_ite_tree.h @@ -20,6 +20,7 @@ Revision History: #define PULL_ITE_TREE_H_ #include "ast/ast.h" +#include "ast/rewriter/th_rewriter.h" #include "ast/simplifier/simplifier.h" #include "ast/recurse_expr.h" #include "util/obj_hashtable.h" @@ -34,7 +35,7 @@ Revision History: */ class pull_ite_tree { ast_manager & m_manager; - simplifier & m_simplifier; + th_rewriter m_rewriter; func_decl * m_p; ptr_vector<expr> m_args; unsigned m_arg_idx; //!< position of the ite argument @@ -56,7 +57,7 @@ class pull_ite_tree { return m_manager.mk_app(m_p, m_args.size(), m_args.c_ptr()); } public: - pull_ite_tree(ast_manager & m, simplifier & s); + pull_ite_tree(ast_manager & m); /** \brief Apply the transformation above if n contains an ite-expression. Store the result in r. If n does not contain an ite-expression, then From 8b2d60e3caceb6c6803d653c7e8a48b3b6e587b0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Wed, 23 Aug 2017 17:57:03 -0700 Subject: [PATCH 11/74] using rewrite in push_app_ite Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/simplifier/pull_ite_tree.cpp | 36 +++++++++++++++ src/ast/simplifier/pull_ite_tree.h | 44 ++++++++++++++++++- src/ast/simplifier/push_app_ite.cpp | 65 +++++++++++++++++++++++++++- src/ast/simplifier/push_app_ite.h | 43 +++++++++++++++++- src/smt/asserted_formulas.cpp | 6 +-- 5 files changed, 187 insertions(+), 7 deletions(-) diff --git a/src/ast/simplifier/pull_ite_tree.cpp b/src/ast/simplifier/pull_ite_tree.cpp index a092f9649..c317cafd8 100644 --- a/src/ast/simplifier/pull_ite_tree.cpp +++ b/src/ast/simplifier/pull_ite_tree.cpp @@ -209,5 +209,41 @@ bool pull_cheap_ite_tree_star::is_target(app * n) const { +pull_ite_tree_cfg::pull_ite_tree_cfg(ast_manager & m): + m(m), + m_trail(m), + m_proc(m) { +} + +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); + 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_cfg::is_target(app * n) const { + bool r = + n->get_num_args() == 2 && + n->get_family_id() != null_family_id && + m.is_bool(n) && + (m.is_value(n->get_arg(0)) || m.is_value(n->get_arg(1))) && + (m.is_term_ite(n->get_arg(0)) || m.is_term_ite(n->get_arg(1))); + TRACE("pull_ite_target", tout << mk_pp(n, m) << "\nresult: " << r << "\n";); + return r; +} + + + + diff --git a/src/ast/simplifier/pull_ite_tree.h b/src/ast/simplifier/pull_ite_tree.h index 4b35c124a..37837a3cf 100644 --- a/src/ast/simplifier/pull_ite_tree.h +++ b/src/ast/simplifier/pull_ite_tree.h @@ -20,11 +20,12 @@ Revision History: #define PULL_ITE_TREE_H_ #include "ast/ast.h" +#include "ast/rewriter/rewriter.h" #include "ast/rewriter/th_rewriter.h" #include "ast/simplifier/simplifier.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 @@ -98,5 +99,46 @@ public: virtual bool is_target(app * n) const; }; +/** + \brief Functor for applying the pull_ite_tree on subexpressions n that + satisfy the is_target virtual predicate. +*/ +class pull_ite_tree_cfg : public default_rewriter_cfg { +protected: + ast_manager& m; + expr_ref_vector m_trail; + pull_ite_tree m_proc; +public: + 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); +}; + +/** + \brief Apply pull_ite_tree on predicates of the form + (p ite v) and (p v ite) + + where: + - p is an interpreted predicate + - ite is an ite-term expression + - v is a value +*/ +class pull_cheap_ite_tree_cfg : public pull_ite_tree_cfg { +public: + pull_cheap_ite_tree_cfg(ast_manager & m):pull_ite_tree_cfg(m) {} + virtual ~pull_cheap_ite_tree_cfg() {} + virtual bool is_target(app * n) const; +}; + +class pull_cheap_ite_tree_rw : public rewriter_tpl<pull_cheap_ite_tree_cfg> { + pull_cheap_ite_tree_cfg m_cfg; +public: + pull_cheap_ite_tree_rw(ast_manager& m): + rewriter_tpl<pull_cheap_ite_tree_cfg>(m, m.proofs_enabled(), m_cfg), + m_cfg(m) + {} +}; + #endif /* PULL_ITE_TREE_H_ */ diff --git a/src/ast/simplifier/push_app_ite.cpp b/src/ast/simplifier/push_app_ite.cpp index 8b56dcd85..3d118e4ac 100644 --- a/src/ast/simplifier/push_app_ite.cpp +++ b/src/ast/simplifier/push_app_ite.cpp @@ -32,7 +32,7 @@ push_app_ite::~push_app_ite() { m_plugins.release(); } -int push_app_ite::has_ite_arg(unsigned num_args, expr * const * args) { +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; @@ -41,7 +41,7 @@ int push_app_ite::has_ite_arg(unsigned num_args, expr * const * args) { 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); + int ite_arg_idx = has_ite_arg(m, num_args, args); if (ite_arg_idx < 0) { mk_app(decl, num_args, args, r); return; @@ -218,3 +218,64 @@ bool ng_push_app_ite::is_target(func_decl * decl, unsigned num_args, expr * cons ng_push_app_ite::ng_push_app_ite(simplifier & s, bool conservative): push_app_ite(s, conservative) { } + + +/** + \brief Default (conservative) implementation. Return true if there one and only one ite-term argument. +*/ +bool push_app_ite_cfg::is_target(func_decl * decl, unsigned num_args, expr * const * args) { + if (m.is_ite(decl)) + return false; + bool found_ite = false; + for (unsigned i = 0; i < num_args; i++) { + if (m.is_ite(args[i]) && !m.is_bool(args[i])) { + if (found_ite) { + if (m_conservative) + return false; + } + else { + found_ite = true; + } + } + } + CTRACE("push_app_ite", found_ite, tout << "found target for push app ite:\n"; + tout << decl->get_name(); + for (unsigned i = 0; i < num_args; i++) tout << " " << mk_pp(args[i], m); + tout << "\n";); + return found_ite; +} + +br_status push_app_ite_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) { + if (!is_target(f, num, args)) { + return BR_FAILED; + } + int ite_arg_idx = has_ite_arg(m, num, args); + if (ite_arg_idx < 0) { + return BR_FAILED; + } + app * ite = to_app(args[ite_arg_idx]); + expr * c = 0, * t = 0, * e = 0; + VERIFY(m.is_ite(ite, c, t, e)); + expr ** args_prime = const_cast<expr**>(args); + expr * old = args_prime[ite_arg_idx]; + args_prime[ite_arg_idx] = t; + expr_ref t_new(m.mk_app(f, num, args_prime), m); + args_prime[ite_arg_idx] = e; + expr_ref e_new(m.mk_app(f, num, args_prime), m); + args_prime[ite_arg_idx] = old; + result = m.mk_ite(c, t_new, e_new); + 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/simplifier/push_app_ite.h b/src/ast/simplifier/push_app_ite.h index 96400b1af..4faf853ea 100644 --- a/src/ast/simplifier/push_app_ite.h +++ b/src/ast/simplifier/push_app_ite.h @@ -21,6 +21,7 @@ Revision History: #include "ast/ast.h" #include "ast/simplifier/simplifier.h" +#include "ast/rewriter/rewriter.h" /** \brief Functor for applying the following transformation: @@ -30,7 +31,6 @@ Revision History: 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); @@ -59,5 +59,46 @@ public: virtual ~ng_push_app_ite() {} }; +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) {} +}; + +/** + \brief Variation of push_app_ite that applies the transformation on nonground terms only. + + \remark This functor uses the app::is_ground method. This method is not + completly precise, for instance, any term containing a quantifier is marked as non ground. +*/ +class ng_push_app_ite_cfg : public push_app_ite_cfg { +protected: + virtual bool is_target(func_decl * decl, unsigned num_args, expr * const * args); +public: + ng_push_app_ite_cfg(ast_manager& m, bool conservative = true): push_app_ite_cfg(m, conservative) {} + virtual ~ng_push_app_ite_cfg() {} +}; + +struct push_app_ite_rw : public rewriter_tpl<push_app_ite_cfg> { + push_app_ite_cfg m_cfg; +public: + push_app_ite_rw(ast_manager& m, bool conservative = true): + rewriter_tpl<push_app_ite_cfg>(m, m.proofs_enabled(), m_cfg), + m_cfg(m, conservative) + {} +}; + +struct ng_push_app_ite_rw : public rewriter_tpl<ng_push_app_ite_cfg> { + ng_push_app_ite_cfg m_cfg; +public: + ng_push_app_ite_rw(ast_manager& m, bool conservative = true): + rewriter_tpl<ng_push_app_ite_cfg>(m, m.proofs_enabled(), m_cfg), + m_cfg(m, conservative) + {} +}; + + #endif /* PUSH_APP_ITE_H_ */ diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 26265a6f8..b475ee778 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -755,7 +755,7 @@ void asserted_formulas::propagate_booleans() { 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_cheap_ite_trees, pull_cheap_ite_tree_rw functor(m), "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); @@ -830,8 +830,8 @@ MK_SIMPLIFIER(elim_bvs_from_quantifiers, bv_elim_star functor(m), "bv_elim", "el 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"); +LIFT_ITE(lift_ite, push_app_ite_rw functor(m, m_params.m_lift_ite == LI_CONSERVATIVE), "lifting ite"); +LIFT_ITE(ng_lift_ite, ng_push_app_ite_rw functor(m, m_params.m_ng_lift_ite == LI_CONSERVATIVE), "lifting ng ite"); unsigned asserted_formulas::get_total_size() const { expr_mark visited; From a7bb41fd499556f3d30e50f06fcf4dfb0274d177 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Thu, 24 Aug 2017 09:19:35 -0700 Subject: [PATCH 12/74] fix build issues Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- .../transforms/dl_mk_quantifier_instantiation.cpp | 1 + src/smt/asserted_formulas.cpp | 4 +++- src/smt/asserted_formulas.h | 13 +++++++------ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index f32840c49..74d15bcdf 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -26,6 +26,7 @@ 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" namespace datalog { diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index b475ee778..eac5f7c10 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -56,7 +56,8 @@ asserted_formulas::asserted_formulas(ast_manager & m, smt_params & p): m_macro_manager(m), m_bit2int(m), m_bv_sharing(m), - m_inconsistent(false){ + m_inconsistent(false), + m_has_quantifiers(false) { m_bsimp = 0; m_bvsimp = 0; @@ -143,6 +144,7 @@ void asserted_formulas::set_eliminate_and(bool flag) { void asserted_formulas::assert_expr(expr * e, proof * _in_pr) { if (inconsistent()) return; + m_has_quantifiers |= ::has_quantifiers(e); if (!m_params.m_preprocess) { push_assertion(e, _in_pr, m_asserted_formulas, m_asserted_formula_prs); return; diff --git a/src/smt/asserted_formulas.h b/src/smt/asserted_formulas.h index 093680fd9..eaed4e405 100644 --- a/src/smt/asserted_formulas.h +++ b/src/smt/asserted_formulas.h @@ -19,17 +19,17 @@ Revision History: #ifndef ASSERTED_FORMULAS_H_ #define ASSERTED_FORMULAS_H_ -#include "smt/params/smt_params.h" +#include "util/statistics.h" +#include "ast/static_features.h" #include "ast/simplifier/simplifier.h" #include "ast/simplifier/basic_simplifier_plugin.h" -#include "ast/static_features.h" +#include "ast/simplifier/maximise_ac_sharing.h" +#include "ast/simplifier/bit2int.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/pattern/pattern_inference.h" +#include "smt/params/smt_params.h" class arith_simplifier_plugin; class bv_simplifier_plugin; @@ -55,6 +55,7 @@ class asserted_formulas { maximise_bv_sharing m_bv_sharing; bool m_inconsistent; + bool m_has_quantifiers; struct scope { unsigned m_asserted_formulas_lim; @@ -128,7 +129,7 @@ public: 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 */ } + bool has_quantifiers() const { return m_has_quantifiers; } // ----------------------------------- // From 23d1c0a9a8a7167992e6a823ed3affd93d7f2bc1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Thu, 24 Aug 2017 11:13:01 -0700 Subject: [PATCH 13/74] move pull/push files Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/rewriter/CMakeLists.txt | 2 ++ src/ast/{simplifier => rewriter}/pull_ite_tree.cpp | 2 +- src/ast/{simplifier => rewriter}/pull_ite_tree.h | 0 src/ast/{simplifier => rewriter}/push_app_ite.cpp | 2 +- src/ast/{simplifier => rewriter}/push_app_ite.h | 0 src/ast/simplifier/CMakeLists.txt | 2 -- src/smt/asserted_formulas.cpp | 4 ++-- 7 files changed, 6 insertions(+), 6 deletions(-) rename src/ast/{simplifier => rewriter}/pull_ite_tree.cpp (99%) rename src/ast/{simplifier => rewriter}/pull_ite_tree.h (100%) rename src/ast/{simplifier => rewriter}/push_app_ite.cpp (99%) rename src/ast/{simplifier => rewriter}/push_app_ite.h (100%) diff --git a/src/ast/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index abf09ff0c..72bca53d4 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -19,6 +19,8 @@ z3_add_component(rewriter 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/simplifier/pull_ite_tree.cpp b/src/ast/rewriter/pull_ite_tree.cpp similarity index 99% rename from src/ast/simplifier/pull_ite_tree.cpp rename to src/ast/rewriter/pull_ite_tree.cpp index c317cafd8..bcb672ea7 100644 --- a/src/ast/simplifier/pull_ite_tree.cpp +++ b/src/ast/rewriter/pull_ite_tree.cpp @@ -16,7 +16,7 @@ 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" diff --git a/src/ast/simplifier/pull_ite_tree.h b/src/ast/rewriter/pull_ite_tree.h similarity index 100% rename from src/ast/simplifier/pull_ite_tree.h rename to src/ast/rewriter/pull_ite_tree.h diff --git a/src/ast/simplifier/push_app_ite.cpp b/src/ast/rewriter/push_app_ite.cpp similarity index 99% rename from src/ast/simplifier/push_app_ite.cpp rename to src/ast/rewriter/push_app_ite.cpp index 3d118e4ac..fe6f8b408 100644 --- a/src/ast/simplifier/push_app_ite.cpp +++ b/src/ast/rewriter/push_app_ite.cpp @@ -17,7 +17,7 @@ Author: Revision History: --*/ -#include "ast/simplifier/push_app_ite.h" +#include "ast/rewriter/push_app_ite.h" #include "ast/ast_pp.h" push_app_ite::push_app_ite(simplifier & s, bool conservative): diff --git a/src/ast/simplifier/push_app_ite.h b/src/ast/rewriter/push_app_ite.h similarity index 100% rename from src/ast/simplifier/push_app_ite.h rename to src/ast/rewriter/push_app_ite.h diff --git a/src/ast/simplifier/CMakeLists.txt b/src/ast/simplifier/CMakeLists.txt index 9575c5c89..c5c310c07 100644 --- a/src/ast/simplifier/CMakeLists.txt +++ b/src/ast/simplifier/CMakeLists.txt @@ -15,8 +15,6 @@ z3_add_component(simplifier 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 diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index eac5f7c10..6f1c4cfcc 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -22,14 +22,14 @@ Revision History: #include "ast/for_each_expr.h" #include "ast/well_sorted.h" #include "ast/rewriter/rewriter_def.h" +#include "ast/rewriter/pull_ite_tree.h" +#include "ast/rewriter/push_app_ite.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" From 5141477809cd70c90fa2e33b5ccb50a57f4ea7a1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Thu, 24 Aug 2017 11:16:48 -0700 Subject: [PATCH 14/74] remove dead code Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/rewriter/pull_ite_tree.cpp | 28 ----- src/ast/rewriter/pull_ite_tree.h | 31 ----- src/ast/rewriter/push_app_ite.cpp | 191 ----------------------------- src/ast/rewriter/push_app_ite.h | 31 ----- 4 files changed, 281 deletions(-) diff --git a/src/ast/rewriter/pull_ite_tree.cpp b/src/ast/rewriter/pull_ite_tree.cpp index bcb672ea7..651744bf9 100644 --- a/src/ast/rewriter/pull_ite_tree.cpp +++ b/src/ast/rewriter/pull_ite_tree.cpp @@ -179,34 +179,6 @@ 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) { - borrow_plugins(s); -} - -bool pull_ite_tree_star::get_subst(expr * n, expr_ref & r, proof_ref & 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; - } - return false; -} - -bool pull_cheap_ite_tree_star::is_target(app * n) const { - bool r = - n->get_num_args() == 2 && - n->get_family_id() != null_family_id && - m.is_bool(n) && - (m.is_value(n->get_arg(0)) || m.is_value(n->get_arg(1))) && - (m.is_term_ite(n->get_arg(0)) || m.is_term_ite(n->get_arg(1))); - TRACE("pull_ite_target", tout << mk_pp(n, m) << "\nresult: " << r << "\n";); - return r; -} - - pull_ite_tree_cfg::pull_ite_tree_cfg(ast_manager & m): diff --git a/src/ast/rewriter/pull_ite_tree.h b/src/ast/rewriter/pull_ite_tree.h index 37837a3cf..3ff0a716d 100644 --- a/src/ast/rewriter/pull_ite_tree.h +++ b/src/ast/rewriter/pull_ite_tree.h @@ -22,7 +22,6 @@ Revision History: #include "ast/ast.h" #include "ast/rewriter/rewriter.h" #include "ast/rewriter/th_rewriter.h" -#include "ast/simplifier/simplifier.h" #include "ast/expr_map.h" #include "ast/recurse_expr.h" #include "util/obj_hashtable.h" @@ -69,36 +68,6 @@ public: void operator()(app * n, app_ref & r, proof_ref & pr); }; -/** - \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 { -protected: - 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(); } - virtual bool is_target(app * n) const = 0; -}; - -/** - \brief Apply pull_ite_tree on predicates of the form - (p ite v) and (p v ite) - - where: - - p is an interpreted predicate - - ite is an ite-term expression - - v is a value -*/ -class pull_cheap_ite_tree_star : public pull_ite_tree_star { -public: - pull_cheap_ite_tree_star(ast_manager & m, simplifier & s):pull_ite_tree_star(m, s) {} - virtual ~pull_cheap_ite_tree_star() {} - virtual bool is_target(app * n) const; -}; - /** \brief Functor for applying the pull_ite_tree on subexpressions n that satisfy the is_target virtual predicate. diff --git a/src/ast/rewriter/push_app_ite.cpp b/src/ast/rewriter/push_app_ite.cpp index fe6f8b408..386a4fb27 100644 --- a/src/ast/rewriter/push_app_ite.cpp +++ b/src/ast/rewriter/push_app_ite.cpp @@ -20,17 +20,6 @@ Revision History: #include "ast/rewriter/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(); -} static int has_ite_arg(ast_manager& m, unsigned num_args, expr * const * args) { for (unsigned i = 0; i < num_args; i++) @@ -39,186 +28,6 @@ static int has_ite_arg(ast_manager& m, unsigned num_args, expr * const * args) { 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(m, num_args, args); - if (ite_arg_idx < 0) { - mk_app(decl, num_args, args, r); - return; - } - app * ite = to_app(args[ite_arg_idx]); - expr * c = ite->get_arg(0); - expr * t = ite->get_arg(1); - expr * e = ite->get_arg(2); - expr ** args_prime = const_cast<expr**>(args); - expr * old = args_prime[ite_arg_idx]; - args_prime[ite_arg_idx] = t; - expr_ref t_new(m); - apply(decl, num_args, args_prime, t_new); - args_prime[ite_arg_idx] = e; - expr_ref e_new(m); - apply(decl, num_args, args_prime, e_new); - args_prime[ite_arg_idx] = old; - expr * new_args[3] = { c, t_new, e_new }; - mk_app(ite->get_decl(), 3, new_args, r); -} - -/** - \brief Default (conservative) implementation. Return true if there one and only one ite-term argument. -*/ -bool push_app_ite::is_target(func_decl * decl, unsigned num_args, expr * const * args) { - if (m.is_ite(decl)) - return false; - bool found_ite = false; - for (unsigned i = 0; i < num_args; i++) { - if (m.is_ite(args[i]) && !m.is_bool(args[i])) { - if (found_ite) { - if (m_conservative) - return false; - } - else { - found_ite = true; - } - } - } - CTRACE("push_app_ite", found_ite, tout << "found target for push app ite:\n"; - tout << decl->get_name(); - for (unsigned i = 0; i < num_args; i++) tout << " " << mk_pp(args[i], m); - tout << "\n";); - return found_ite; -} - -void push_app_ite::operator()(expr * s, expr_ref & r, proof_ref & p) { - expr * result; - proof * result_proof; - reduce_core(s); - get_cached(s, result, result_proof); - r = result; - switch (m.proof_mode()) { - case PGM_DISABLED: - p = m.mk_undef_proof(); - break; - case PGM_COARSE: - if (result == s) - p = m.mk_reflexivity(s); - else - p = m.mk_rewrite_star(s, result, 0, 0); - break; - case PGM_FINE: - if (result == s) - p = m.mk_reflexivity(s); - else - p = result_proof; - break; - } -} - -void push_app_ite::reduce_core(expr * n) { - if (!is_cached(n)) { - unsigned sz = m_todo.size(); - m_todo.push_back(n); - while (m_todo.size() != sz) { - expr * n = m_todo.back(); - if (is_cached(n)) - m_todo.pop_back(); - else if (visit_children(n)) { - m_todo.pop_back(); - reduce1(n); - } - } - } -} - -bool push_app_ite::visit_children(expr * n) { - bool visited = true; - unsigned j; - switch(n->get_kind()) { - case AST_VAR: - return true; - case AST_APP: - j = to_app(n)->get_num_args(); - while (j > 0) { - --j; - visit(to_app(n)->get_arg(j), visited); - } - return visited; - case AST_QUANTIFIER: - visit(to_quantifier(n)->get_expr(), visited); - return visited; - default: - UNREACHABLE(); - return true; - } -} - -void push_app_ite::reduce1(expr * n) { - switch (n->get_kind()) { - case AST_VAR: - cache_result(n, n, 0); - break; - case AST_APP: - reduce1_app(to_app(n)); - break; - case AST_QUANTIFIER: - reduce1_quantifier(to_quantifier(n)); - break; - default: - UNREACHABLE(); - } -} - -void push_app_ite::reduce1_app(app * n) { - m_args.reset(); - - func_decl * decl = n->get_decl(); - proof_ref p1(m); - get_args(n, m_args, p1); - - expr_ref r(m); - if (is_target(decl, m_args.size(), m_args.c_ptr())) - apply(decl, m_args.size(), m_args.c_ptr(), r); - else - mk_app(decl, m_args.size(), m_args.c_ptr(), r); - - if (!m.fine_grain_proofs()) - cache_result(n, r, 0); - else { - expr * s = m.mk_app(decl, m_args.size(), m_args.c_ptr()); - proof * p; - if (n == r) - p = 0; - else if (r != s) - p = m.mk_transitivity(p1, m.mk_rewrite(s, r)); - else - p = p1; - cache_result(n, r, p); - } -} - -void push_app_ite::reduce1_quantifier(quantifier * q) { - expr * new_body; - proof * new_body_pr; - get_cached(q->get_expr(), new_body, new_body_pr); - - quantifier * new_q = m.update_quantifier(q, new_body); - proof * p = q == new_q ? 0 : m.mk_quant_intro(q, new_q, new_body_pr); - cache_result(q, new_q, p); -} - -bool ng_push_app_ite::is_target(func_decl * decl, unsigned num_args, expr * const * args) { - bool r = push_app_ite::is_target(decl, num_args, args); - if (!r) - return false; - for (unsigned i = 0; i < num_args; i++) - if (!is_ground(args[i])) - return true; - return false; -} - -ng_push_app_ite::ng_push_app_ite(simplifier & s, bool conservative): - push_app_ite(s, conservative) { -} - /** \brief Default (conservative) implementation. Return true if there one and only one ite-term argument. diff --git a/src/ast/rewriter/push_app_ite.h b/src/ast/rewriter/push_app_ite.h index 4faf853ea..e6c6b6fb2 100644 --- a/src/ast/rewriter/push_app_ite.h +++ b/src/ast/rewriter/push_app_ite.h @@ -20,7 +20,6 @@ Revision History: #define PUSH_APP_ITE_H_ #include "ast/ast.h" -#include "ast/simplifier/simplifier.h" #include "ast/rewriter/rewriter.h" /** @@ -28,36 +27,6 @@ Revision History: (f s (ite c t1 t2)) ==> (ite c (f s t1) (f s t2)) */ -class push_app_ite : public simplifier { -protected: - bool m_conservative; - 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() {} -}; struct push_app_ite_cfg : public default_rewriter_cfg { ast_manager& m; From ebcacaa26d0a14c6d7893a28c154c8683243882b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Fri, 25 Aug 2017 17:44:33 -0700 Subject: [PATCH 15/74] update new assertions Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/ast.h | 36 ++++++++ src/ast/macros/macro_finder.cpp | 141 +++++++++++++++++++++++++++++ src/ast/macros/macro_finder.h | 3 + src/ast/macros/macro_manager.cpp | 8 ++ src/ast/macros/macro_manager.h | 1 + src/ast/macros/quasi_macros.cpp | 62 +++++++++++++ src/ast/macros/quasi_macros.h | 3 + src/ast/rewriter/CMakeLists.txt | 1 + src/ast/simplifier/CMakeLists.txt | 1 - src/ast/simplifier/bv_elim.cpp | 52 +++++------ src/ast/simplifier/bv_elim.h | 4 +- src/ast/simplifier/inj_axiom.cpp | 142 ------------------------------ src/ast/simplifier/inj_axiom.h | 27 ------ src/smt/CMakeLists.txt | 1 + src/smt/asserted_formulas.cpp | 2 +- src/smt/elim_term_ite.cpp | 18 ++++ src/smt/elim_term_ite.h | 28 ++++++ 17 files changed, 331 insertions(+), 199 deletions(-) delete mode 100644 src/ast/simplifier/inj_axiom.cpp delete mode 100644 src/ast/simplifier/inj_axiom.h diff --git a/src/ast/ast.h b/src/ast/ast.h index e6beec7e6..408ca4063 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -2470,6 +2470,42 @@ public: void operator()(AST * n) { m_manager.inc_ref(n); } }; +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) { + m.inc_ref(fml); + m.inc_ref(p); + } + + justified_expr& operator=(justified_expr& other) { + SASSERT(&m == &other.m); + if (this != &other) { + m.dec_ref(m_fml); + m.dec_ref(m_proof); + m_fml = other.get_fml(); + m_proof = other.get_proof(); + m.inc_ref(m_fml); + m.inc_ref(m_proof); + } + return *this; + } + + ~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 /* AST_H_ */ diff --git a/src/ast/macros/macro_finder.cpp b/src/ast/macros/macro_finder.cpp index 1d441aee7..9a8e552fc 100644 --- a/src/ast/macros/macro_finder.cpp +++ b/src/ast/macros/macro_finder.cpp @@ -111,6 +111,71 @@ bool macro_finder::is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_ex return true; } +bool macro_finder::is_arith_macro(expr * n, proof * pr, vector<justified_expr>& new_fmls) { + if (!is_quantifier(n) || !to_quantifier(n)->is_forall()) + return false; + expr * body = to_quantifier(n)->get_expr(); + unsigned num_decls = to_quantifier(n)->get_num_decls(); + + if (!m_autil.is_le(body) && !m_autil.is_ge(body) && !m_manager.is_eq(body)) + return false; + if (!m_autil.is_add(to_app(body)->get_arg(0))) + return false; + app_ref head(m_manager); + expr_ref def(m_manager); + bool inv = false; + if (!m_util.is_arith_macro(body, num_decls, head, def, inv)) + return false; + app_ref new_body(m_manager); + + if (!inv || m_manager.is_eq(body)) + new_body = m_manager.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_manager); + new_q = m_manager.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_manager.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_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_autil.mk_add(def, k_app), m_manager); + expr * body1 = m_manager.mk_eq(head, new_rhs2); + expr * body2 = m_manager.mk_app(new_body->get_decl(), k_app, m_autil.mk_int(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); + proof* pr1 = 0, *pr2 = 0; + if (m_manager.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); + pr1 = m_manager.mk_and_elim(mp, 0); + pr2 = m_manager.mk_and_elim(mp, 1); + } + new_fmls.push_back(justified_expr(m_manager, q1, pr1)); + new_fmls.push_back(justified_expr(m_manager, q2, pr2)); + return true; +} + /** n is of the form: (forall (X) (iff (= (f X) t) def[X])) @@ -152,6 +217,34 @@ static void pseudo_predicate_macro2macro(ast_manager & m, app * head, app * t, e } } +static void pseudo_predicate_macro2macro(ast_manager & m, app * head, app * t, expr * def, quantifier * q, proof * pr, + vector<justified_expr>& new_fmls) { + func_decl * f = head->get_decl(); + func_decl * k = m.mk_fresh_func_decl(f->get_name(), symbol::null, f->get_arity(), f->get_domain(), f->get_range()); + app * k_app = m.mk_app(k, head->get_num_args(), head->get_args()); + app * ite = m.mk_ite(def, t, k_app); + app * body_1 = m.mk_eq(head, ite); + app * body_2 = m.mk_not(m.mk_eq(k_app, t)); + quantifier * q1 = m.update_quantifier(q, body_1); + proof * pr1 = 0, *pr2 = 0; + expr * pats[1] = { m.mk_pattern(k_app) }; + quantifier * q2 = m.update_quantifier(q, 1, pats, body_2); // erase patterns + if (m.proofs_enabled()) { + // r : [rewrite] q ~ q1 & q2 + // pr : q + // mp : [modus_pones pr pr1] q1 & q2 + // pr1 : [and-elim mp] q1 + // pr2 : [and-elim mp] q2 + app * q1q2 = m.mk_and(q1,q2); + proof * r = m.mk_oeq_rewrite(q, q1q2); + proof * mp = m.mk_modus_ponens(pr, r); + pr1 = m.mk_and_elim(mp, 0); + pr2 = m.mk_and_elim(mp, 1); + } + new_fmls.push_back(justified_expr(m, q1, pr1)); + new_fmls.push_back(justified_expr(m, q2, pr2)); +} + macro_finder::macro_finder(ast_manager & m, macro_manager & mm): m_manager(m), m_macro_manager(mm), @@ -216,3 +309,51 @@ void macro_finder::operator()(unsigned num, expr * const * exprs, proof * const } + +bool macro_finder::expand_macros(unsigned num, justified_expr const * fmls, vector<justified_expr>& new_fmls) { + TRACE("macro_finder", tout << "starting expand_macros:\n"; + m_macro_manager.display(tout);); + bool found_new_macro = false; + for (unsigned i = 0; i < num; i++) { + expr * n = fmls[i].get_fml(); + proof * pr = m_manager.proofs_enabled() ? fmls[i].get_proof() : 0; + expr_ref new_n(m_manager), def(m_manager); + proof_ref new_pr(m_manager); + m_macro_manager.expand_macros(n, pr, new_n, new_pr); + app_ref head(m_manager), t(m_manager); + 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_manager, head, t, def, to_quantifier(new_n), new_pr, new_fmls); + found_new_macro = true; + } + else { + new_fmls.push_back(justified_expr(m_manager, new_n, new_pr)); + } + } + return found_new_macro; +} + +void macro_finder::operator()(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls) { + TRACE("macro_finder", tout << "processing macros...\n";); + vector<justified_expr> _new_fmls; + if (expand_macros(n, fmls, _new_fmls)) { + while (true) { + vector<justified_expr> old_fmls; + _new_fmls.swap(old_fmls); + SASSERT(_new_fmls.empty()); + if (!expand_macros(old_fmls.size(), old_fmls.c_ptr(), _new_fmls)) + break; + } + } + new_fmls.append(_new_fmls); +} + + diff --git a/src/ast/macros/macro_finder.h b/src/ast/macros/macro_finder.h index 5807573ae..2bba07306 100644 --- a/src/ast/macros/macro_finder.h +++ b/src/ast/macros/macro_finder.h @@ -38,7 +38,9 @@ class macro_finder { macro_util & m_util; arith_util m_autil; bool expand_macros(unsigned num, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); + bool expand_macros(unsigned n, justified_expr const * fmls, vector<justified_expr>& new_fmls); bool is_arith_macro(expr * n, proof * pr, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); + bool is_arith_macro(expr * n, proof * pr, vector<justified_expr>& new_fmls); bool is_macro(expr * n, app_ref & head, expr_ref & def); bool is_pseudo_head(expr * n, unsigned num_decls, app * & head, app * & t); @@ -48,6 +50,7 @@ public: macro_finder(ast_manager & m, macro_manager & mm); ~macro_finder(); void operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); + void operator()(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls); }; #endif /* MACRO_FINDER_H_ */ diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index bff1e7dae..7a2642fa3 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -152,6 +152,14 @@ 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.is_eq(body) || m.is_iff(body)); diff --git a/src/ast/macros/macro_manager.h b/src/ast/macros/macro_manager.h index 71864a699..58fedf666 100644 --- a/src/ast/macros/macro_manager.h +++ b/src/ast/macros/macro_manager.h @@ -71,6 +71,7 @@ public: void pop_scope(unsigned num_scopes); void reset(); void mark_forbidden(unsigned n, expr * const * exprs); + void mark_forbidden(unsigned n, justified_expr const * exprs); void mark_forbidden(expr * e) { mark_forbidden(1, &e); } bool is_forbidden(func_decl * d) const { return m_forbidden_set.contains(d); } obj_hashtable<func_decl> const & get_forbidden_set() const { return m_forbidden_set; } diff --git a/src/ast/macros/quasi_macros.cpp b/src/ast/macros/quasi_macros.cpp index 822532532..527b9656d 100644 --- a/src/ast/macros/quasi_macros.cpp +++ b/src/ast/macros/quasi_macros.cpp @@ -293,6 +293,44 @@ bool quasi_macros::find_macros(unsigned n, expr * const * exprs) { return res; } +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_ref_vector & new_exprs, proof_ref_vector & new_prs) { for ( unsigned i = 0 ; i < n ; i++ ) { expr_ref r(m_manager), rs(m_manager); @@ -319,3 +357,27 @@ bool quasi_macros::operator()(unsigned n, expr * const * exprs, proof * const * return false; } } + +void quasi_macros::apply_macros(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls) { + for ( unsigned i = 0 ; i < n ; i++ ) { + expr_ref r(m_manager), rs(m_manager); + proof_ref pr(m_manager), ps(m_manager); + proof * p = m_manager.proofs_enabled() ? fmls[i].get_proof() : 0; + m_macro_manager.expand_macros(fmls[i].get_fml(), p, r, pr); + m_rewriter(r); + new_fmls.push_back(justified_expr(m_manager, r, pr)); + } +} + +bool quasi_macros::operator()(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls) { + if (find_macros(n, fmls)) { + apply_macros(n, fmls, new_fmls); + return true; + } else { + // just copy them over + for ( unsigned i = 0 ; i < n ; i++ ) { + new_fmls.push_back(fmls[i]); + } + return false; + } +} diff --git a/src/ast/macros/quasi_macros.h b/src/ast/macros/quasi_macros.h index 29efe63c7..7288ac601 100644 --- a/src/ast/macros/quasi_macros.h +++ b/src/ast/macros/quasi_macros.h @@ -53,7 +53,9 @@ class quasi_macros { void find_occurrences(expr * e); bool find_macros(unsigned n, expr * const * exprs); + bool find_macros(unsigned n, justified_expr const* expr); void apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); + void apply_macros(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls); public: quasi_macros(ast_manager & m, macro_manager & mm); @@ -63,6 +65,7 @@ public: \brief Find pure function macros and apply them. */ bool operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs); + bool operator()(unsigned n, justified_expr const* fmls, vector<justified_expr>& new_fmls); }; #endif diff --git a/src/ast/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index 72bca53d4..c1b99bcae 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -15,6 +15,7 @@ z3_add_component(rewriter expr_safe_replace.cpp factor_rewriter.cpp fpa_rewriter.cpp + inj_axiom.cpp label_rewriter.cpp mk_simplified_app.cpp pb_rewriter.cpp diff --git a/src/ast/simplifier/CMakeLists.txt b/src/ast/simplifier/CMakeLists.txt index c5c310c07..b6fe9b1cd 100644 --- a/src/ast/simplifier/CMakeLists.txt +++ b/src/ast/simplifier/CMakeLists.txt @@ -12,7 +12,6 @@ z3_add_component(simplifier datatype_simplifier_plugin.cpp elim_bounds.cpp fpa_simplifier_plugin.cpp - inj_axiom.cpp maximise_ac_sharing.cpp poly_simplifier_plugin.cpp seq_simplifier_plugin.cpp diff --git a/src/ast/simplifier/bv_elim.cpp b/src/ast/simplifier/bv_elim.cpp index 1875e333b..1c0048a07 100644 --- a/src/ast/simplifier/bv_elim.cpp +++ b/src/ast/simplifier/bv_elim.cpp @@ -12,16 +12,16 @@ Copyright (c) 2015 Microsoft Corporation void bv_elim::elim(quantifier* q, quantifier_ref& r) { svector<symbol> names, _names; - sort_ref_buffer sorts(m_manager), _sorts(m_manager); - expr_ref_buffer pats(m_manager); - expr_ref_buffer no_pats(m_manager); - expr_ref_buffer subst_map(m_manager), _subst_map(m_manager); - var_subst subst(m_manager); - bv_util bv(m_manager); - expr_ref new_body(m_manager); + 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 = q->get_expr(); unsigned num_decls = q->get_num_decls(); - family_id bfid = m_manager.mk_family_id("bv"); + family_id bfid = m.mk_family_id("bv"); // // Traverse sequence of bound variables to eliminate @@ -37,23 +37,23 @@ void bv_elim::elim(quantifier* q, quantifier_ref& r) { 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); + expr_ref_buffer args(m); + expr_ref bv(m); 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()); + var* v = m.mk_var(var_idx++, m.mk_bool_sort()); args.push_back(v); - _sorts.push_back(m_manager.mk_bool_sort()); + _sorts.push_back(m.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()); + 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_manager.mk_var(var_idx++, s)); + _subst_map.push_back(m.mk_var(var_idx++, s)); _sorts.push_back(s); _names.push_back(nm); } @@ -78,26 +78,26 @@ void bv_elim::elim(quantifier* q, quantifier_ref& r) { subst(old_body, sub_size, sub, new_body); for (unsigned j = 0; j < q->get_num_patterns(); j++) { - expr_ref pat(m_manager); + expr_ref pat(m); 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); + expr_ref nopat(m); 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()); + r = 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()); } bool bv_elim_star::visit_quantifier(quantifier* q) { diff --git a/src/ast/simplifier/bv_elim.h b/src/ast/simplifier/bv_elim.h index 2b8a4778a..c027b1a9e 100644 --- a/src/ast/simplifier/bv_elim.h +++ b/src/ast/simplifier/bv_elim.h @@ -24,9 +24,9 @@ Revision History: #include "ast/simplifier/simplifier.h" class bv_elim { - ast_manager& m_manager; + ast_manager& m; public: - bv_elim(ast_manager& m) : m_manager(m) {}; + bv_elim(ast_manager& m) : m(m) {}; void elim(quantifier* q, quantifier_ref& r); }; diff --git a/src/ast/simplifier/inj_axiom.cpp b/src/ast/simplifier/inj_axiom.cpp deleted file mode 100644 index 2aa828ffa..000000000 --- a/src/ast/simplifier/inj_axiom.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - inj_axiom.cpp - -Abstract: - - <abstract> - -Author: - - Leonardo de Moura (leonardo) 2008-06-23. - -Revision History: - ---*/ -#include "ast/simplifier/inj_axiom.h" -#include "ast/ast_pp.h" -#include "ast/ast_ll_pp.h" -#include "ast/has_free_vars.h" -#include "ast/well_sorted.h" - -/** - \brief Little HACK for simplifying injectivity axioms - - \remark It is not covering all possible cases. -*/ -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); - 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 (is_app(app1) && - is_app(app2) && - to_app(app1)->get_decl() == to_app(app2)->get_decl() && - to_app(app1)->get_num_args() == to_app(app2)->get_num_args() && - to_app(app1)->get_family_id() == null_family_id && - to_app(app1)->get_num_args() > 0 && - is_var(var1) && - is_var(var2) && - var1 != var2) { - app * f1 = to_app(app1); - app * f2 = to_app(app2); - bool found_vars = false; - unsigned num = f1->get_num_args(); - unsigned idx = UINT_MAX; - unsigned num_vars = 1; - for (unsigned i = 0; i < num; i++) { - expr * c1 = f1->get_arg(i); - expr * c2 = f2->get_arg(i); - if (!is_var(c1) && !is_uninterp_const(c1)) - return false; - if ((c1 == var1 && c2 == var2) || (c1 == var2 && c2 == var1)) { - if (found_vars) - return false; - found_vars = true; - idx = i; - } - else if (c1 == c2 && c1 != var1 && c1 != var2) { - if (is_var(c1)) { - ++num_vars; - } - } - else { - return false; - } - } - if (found_vars && !has_free_vars(q)) { - TRACE("inj_axiom", - tout << "Cadidate for simplification:\n" << mk_ll_pp(q, m) << mk_pp(app1, m) << "\n" << mk_pp(app2, m) << "\n" << - mk_pp(var1, m) << "\n" << mk_pp(var2, m) << "\nnum_vars: " << num_vars << "\n";); - // Building new (optimized) axiom - func_decl * decl = f1->get_decl(); - unsigned var_idx = 0; - ptr_buffer<expr> f_args, inv_vars; - ptr_buffer<sort> decls; - buffer<symbol> names; - - expr * var = 0; - for (unsigned i = 0; i < num; i++) { - expr * c = f1->get_arg(i); - if (is_var(c)) { - names.push_back(symbol(i)); - sort * s = decl->get_domain(i); - decls.push_back(s); - expr * new_c = m.mk_var(var_idx, s); - var_idx++; - f_args.push_back(new_c); - if (i == idx) { - var = new_c; - } - else { - inv_vars.push_back(new_c); - } - } - else { - SASSERT(is_uninterp_const(c)); - f_args.push_back(c); - } - } - SASSERT(var != 0); - app * f = m.mk_app(decl, f_args.size(), f_args.c_ptr()); - - ptr_vector<sort> domain; - inv_vars.push_back(f); - for (unsigned i = 0; i < inv_vars.size(); ++i) { - domain.push_back(m.get_sort(inv_vars[i])); - } - sort * d = decl->get_domain(idx); - func_decl * inv_decl = m.mk_fresh_func_decl("inj", domain.size(), domain.c_ptr(), d); - - expr * proj = m.mk_app(inv_decl, inv_vars.size(), inv_vars.c_ptr()); - expr * eq = m.mk_eq(proj, var); - expr * p = m.mk_pattern(f); - - // decls are in the wrong order... - // Remark: the sort of the var 0 must be in the last position. - std::reverse(decls.begin(), decls.end()); - - result = m.mk_forall(decls.size(), decls.c_ptr(), names.c_ptr(), eq, - 0, symbol(), symbol(), 1, &p); - TRACE("inj_axiom", tout << "new axiom:\n" << mk_pp(result, m) << "\n";); - SASSERT(is_well_sorted(m, result)); - return true; - } - } - } - } - return false; -} - diff --git a/src/ast/simplifier/inj_axiom.h b/src/ast/simplifier/inj_axiom.h deleted file mode 100644 index a6df16515..000000000 --- a/src/ast/simplifier/inj_axiom.h +++ /dev/null @@ -1,27 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - inj_axiom.h - -Abstract: - - <abstract> - -Author: - - Leonardo de Moura (leonardo) 2008-06-23. - -Revision History: - ---*/ -#ifndef INJ_AXIOM_H_ -#define INJ_AXIOM_H_ - -#include "ast/ast.h" - -bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result); - -#endif /* INJ_AXIOM_H_ */ - diff --git a/src/smt/CMakeLists.txt b/src/smt/CMakeLists.txt index 41890dd05..b117db89b 100644 --- a/src/smt/CMakeLists.txt +++ b/src/smt/CMakeLists.txt @@ -3,6 +3,7 @@ z3_add_component(smt arith_eq_adapter.cpp arith_eq_solver.cpp asserted_formulas.cpp + asserted_formulas_new.cpp cached_var_subst.cpp cost_evaluator.cpp dyn_ack.cpp diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 6f1c4cfcc..8b25e9263 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -24,6 +24,7 @@ Revision History: #include "ast/rewriter/rewriter_def.h" #include "ast/rewriter/pull_ite_tree.h" #include "ast/rewriter/push_app_ite.h" +#include "ast/rewriter/inj_axiom.h" #include "ast/simplifier/arith_simplifier_plugin.h" #include "ast/simplifier/array_simplifier_plugin.h" #include "ast/simplifier/datatype_simplifier_plugin.h" @@ -31,7 +32,6 @@ Revision History: #include "ast/simplifier/seq_simplifier_plugin.h" #include "ast/simplifier/bv_simplifier_plugin.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" diff --git a/src/smt/elim_term_ite.cpp b/src/smt/elim_term_ite.cpp index b750e6bf5..d9cfac775 100644 --- a/src/smt/elim_term_ite.cpp +++ b/src/smt/elim_term_ite.cpp @@ -157,4 +157,22 @@ void elim_term_ite::reduce1_quantifier(quantifier * q) { } +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; + } + + 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; +} diff --git a/src/smt/elim_term_ite.h b/src/smt/elim_term_ite.h index 2b9c66a64..94e5e0346 100644 --- a/src/smt/elim_term_ite.h +++ b/src/smt/elim_term_ite.h @@ -21,6 +21,7 @@ Revision History: #include "ast/simplifier/simplifier.h" #include "ast/normal_forms/defined_names.h" +#include "ast/rewriter/rewriter.h" class elim_term_ite : public simplifier { defined_names & m_defined_names; @@ -46,5 +47,32 @@ public: ); }; + + +class elim_term_ite_cfg : public default_rewriter_cfg { + ast_manager& m; + defined_names & m_defined_names; + vector<justified_expr> m_new_defs; +public: + 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_cfg() {} + vector<justified_expr> const& new_defs() const { return m_new_defs; } + 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> { + elim_term_ite_cfg m_cfg; +public: + elim_term_ite_rw(ast_manager& m, defined_names & dn): + rewriter_tpl<elim_term_ite_cfg>(m, m.proofs_enabled(), m_cfg), + m_cfg(m, dn) + {} + vector<justified_expr> const& new_defs() const { return m_cfg.new_defs(); } +}; + + + #endif /* ELIM_TERM_ITE_H_ */ From 9438ff848fcaa149d0b58639f75c043d2730049f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Fri, 25 Aug 2017 17:44:57 -0700 Subject: [PATCH 16/74] moved files Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/rewriter/inj_axiom.cpp | 139 +++++++++++++++++++++++++++++++++ src/ast/rewriter/inj_axiom.h | 27 +++++++ 2 files changed, 166 insertions(+) create mode 100644 src/ast/rewriter/inj_axiom.cpp create mode 100644 src/ast/rewriter/inj_axiom.h diff --git a/src/ast/rewriter/inj_axiom.cpp b/src/ast/rewriter/inj_axiom.cpp new file mode 100644 index 000000000..d322f3228 --- /dev/null +++ b/src/ast/rewriter/inj_axiom.cpp @@ -0,0 +1,139 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + inj_axiom.cpp + +Abstract: + + <abstract> + +Author: + + Leonardo de Moura (leonardo) 2008-06-23. + +Revision History: + +--*/ +#include "ast/rewriter/inj_axiom.h" +#include "ast/ast_pp.h" +#include "ast/ast_ll_pp.h" +#include "ast/has_free_vars.h" +#include "ast/well_sorted.h" + +/** + \brief Little HACK for simplifying injectivity axioms + + \remark It is not covering all possible cases. +*/ +bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result) { + expr * n = q->get_expr(); + 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, 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() && + to_app(app1)->get_num_args() == to_app(app2)->get_num_args() && + to_app(app1)->get_family_id() == null_family_id && + to_app(app1)->get_num_args() > 0 && + is_var(var1) && + is_var(var2) && + var1 != var2) { + app * f1 = to_app(app1); + app * f2 = to_app(app2); + bool found_vars = false; + unsigned num = f1->get_num_args(); + unsigned idx = UINT_MAX; + unsigned num_vars = 1; + for (unsigned i = 0; i < num; i++) { + expr * c1 = f1->get_arg(i); + expr * c2 = f2->get_arg(i); + if (!is_var(c1) && !is_uninterp_const(c1)) + return false; + if ((c1 == var1 && c2 == var2) || (c1 == var2 && c2 == var1)) { + if (found_vars) + return false; + found_vars = true; + idx = i; + } + else if (c1 == c2 && c1 != var1 && c1 != var2) { + if (is_var(c1)) { + ++num_vars; + } + } + else { + return false; + } + } + if (found_vars && !has_free_vars(q)) { + TRACE("inj_axiom", + tout << "Cadidate for simplification:\n" << mk_ll_pp(q, m) << mk_pp(app1, m) << "\n" << mk_pp(app2, m) << "\n" << + mk_pp(var1, m) << "\n" << mk_pp(var2, m) << "\nnum_vars: " << num_vars << "\n";); + // Building new (optimized) axiom + func_decl * decl = f1->get_decl(); + unsigned var_idx = 0; + ptr_buffer<expr> f_args, inv_vars; + ptr_buffer<sort> decls; + buffer<symbol> names; + + expr * var = 0; + for (unsigned i = 0; i < num; i++) { + expr * c = f1->get_arg(i); + if (is_var(c)) { + names.push_back(symbol(i)); + sort * s = decl->get_domain(i); + decls.push_back(s); + expr * new_c = m.mk_var(var_idx, s); + var_idx++; + f_args.push_back(new_c); + if (i == idx) { + var = new_c; + } + else { + inv_vars.push_back(new_c); + } + } + else { + SASSERT(is_uninterp_const(c)); + f_args.push_back(c); + } + } + SASSERT(var != 0); + app * f = m.mk_app(decl, f_args.size(), f_args.c_ptr()); + + ptr_vector<sort> domain; + inv_vars.push_back(f); + for (unsigned i = 0; i < inv_vars.size(); ++i) { + domain.push_back(m.get_sort(inv_vars[i])); + } + sort * d = decl->get_domain(idx); + func_decl * inv_decl = m.mk_fresh_func_decl("inj", domain.size(), domain.c_ptr(), d); + + expr * proj = m.mk_app(inv_decl, inv_vars.size(), inv_vars.c_ptr()); + expr * eq = m.mk_eq(proj, var); + expr * p = m.mk_pattern(f); + + // decls are in the wrong order... + // Remark: the sort of the var 0 must be in the last position. + std::reverse(decls.begin(), decls.end()); + + result = m.mk_forall(decls.size(), decls.c_ptr(), names.c_ptr(), eq, + 0, symbol(), symbol(), 1, &p); + TRACE("inj_axiom", tout << "new axiom:\n" << mk_pp(result, m) << "\n";); + SASSERT(is_well_sorted(m, result)); + return true; + } + } + } + } + return false; +} + diff --git a/src/ast/rewriter/inj_axiom.h b/src/ast/rewriter/inj_axiom.h new file mode 100644 index 000000000..a6df16515 --- /dev/null +++ b/src/ast/rewriter/inj_axiom.h @@ -0,0 +1,27 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + inj_axiom.h + +Abstract: + + <abstract> + +Author: + + Leonardo de Moura (leonardo) 2008-06-23. + +Revision History: + +--*/ +#ifndef INJ_AXIOM_H_ +#define INJ_AXIOM_H_ + +#include "ast/ast.h" + +bool simplify_inj_axiom(ast_manager & m, quantifier * q, expr_ref & result); + +#endif /* INJ_AXIOM_H_ */ + From ac0bb6a3d062095b5538a870c4e7ec26126932b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Fri, 25 Aug 2017 23:56:09 -0700 Subject: [PATCH 17/74] remove simplify dependencies Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/expr_substitution.h | 33 ++++++++++++ src/ast/rewriter/CMakeLists.txt | 4 ++ src/ast/{simplifier => rewriter}/bit2int.cpp | 55 ++++++++++---------- src/ast/{simplifier => rewriter}/bit2int.h | 7 +-- src/ast/rewriter/bv_rewriter.h | 39 ++++++++++++-- src/ast/simplifier/CMakeLists.txt | 1 - src/smt/asserted_formulas.cpp | 4 +- src/smt/asserted_formulas.h | 2 +- src/smt/elim_term_ite.h | 2 + src/smt/params/preprocessor_params.cpp | 2 +- src/smt/params/preprocessor_params.h | 4 +- 11 files changed, 108 insertions(+), 45 deletions(-) rename src/ast/{simplifier => rewriter}/bit2int.cpp (87%) rename src/ast/{simplifier => rewriter}/bit2int.h (90%) diff --git a/src/ast/expr_substitution.h b/src/ast/expr_substitution.h index d209ab6b4..924481dd8 100644 --- a/src/ast/expr_substitution.h +++ b/src/ast/expr_substitution.h @@ -52,4 +52,37 @@ 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(); } + 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/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index c1b99bcae..804fbcbed 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -3,13 +3,16 @@ z3_add_component(rewriter arith_rewriter.cpp array_rewriter.cpp ast_counter.cpp + bit2int.cpp bool_rewriter.cpp bv_bounds.cpp + bv_elim2.cpp bv_rewriter.cpp datatype_rewriter.cpp der.cpp distribute_forall.cpp dl_rewriter.cpp + elim_bounds2.cpp enum2bv_rewriter.cpp expr_replacer.cpp expr_safe_replace.cpp @@ -17,6 +20,7 @@ z3_add_component(rewriter fpa_rewriter.cpp inj_axiom.cpp label_rewriter.cpp + maximize_ac_sharing.cpp mk_simplified_app.cpp pb_rewriter.cpp pb2bv_rewriter.cpp 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/bv_rewriter.h b/src/ast/rewriter/bv_rewriter.h index 1109251e0..45bd6c264 100644 --- a/src/ast/rewriter/bv_rewriter.h +++ b/src/ast/rewriter/bv_rewriter.h @@ -98,11 +98,10 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> { br_status mk_bv_rotate_right(unsigned n, expr * arg, expr_ref & result); br_status mk_bv_ext_rotate_left(expr * arg1, expr * arg2, expr_ref & result); br_status mk_bv_ext_rotate_right(expr * arg1, expr * arg2, expr_ref & result); + br_status mk_bv_add(expr* a, expr* b, expr_ref& result) { expr* args[2] = { a, b }; return mk_bv_add(2, args, result); } + br_status mk_bv_sub(expr* a, expr* b, expr_ref& result) { expr* args[2] = { a, b }; return mk_sub(2, args, result); } + br_status mk_bv_mul(expr* a, expr* b, expr_ref& result) { expr* args[2] = { a, b }; return mk_bv_mul(2, args, result); } br_status mk_bv_add(unsigned num_args, expr * const * args, expr_ref & result); - br_status mk_bv_add(expr * arg1, expr * arg2, expr_ref & result) { - expr * args[2] = { arg1, arg2 }; - return mk_bv_add(2, args, result); - } br_status mk_bv_mul(unsigned num_args, expr * const * args, expr_ref & result); br_status mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result); br_status mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result); @@ -185,6 +184,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/simplifier/CMakeLists.txt b/src/ast/simplifier/CMakeLists.txt index b6fe9b1cd..52a44595e 100644 --- a/src/ast/simplifier/CMakeLists.txt +++ b/src/ast/simplifier/CMakeLists.txt @@ -5,7 +5,6 @@ z3_add_component(simplifier 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 diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 8b25e9263..f8efcbf4b 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -33,7 +33,6 @@ Revision History: #include "ast/simplifier/bv_simplifier_plugin.h" #include "ast/simplifier/bv_elim.h" #include "ast/simplifier/elim_bounds.h" -#include "ast/simplifier/bit2int.h" #include "ast/normal_forms/pull_quant.h" #include "ast/normal_forms/nnf.h" #include "ast/pattern/pattern_inference.h" @@ -70,7 +69,6 @@ asserted_formulas::asserted_formulas(ast_manager & m, smt_params & p): 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(); } @@ -262,7 +260,7 @@ void asserted_formulas::reduce() { 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_eliminate_and*/ true, 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()); diff --git a/src/smt/asserted_formulas.h b/src/smt/asserted_formulas.h index eaed4e405..fb621000c 100644 --- a/src/smt/asserted_formulas.h +++ b/src/smt/asserted_formulas.h @@ -24,7 +24,7 @@ Revision History: #include "ast/simplifier/simplifier.h" #include "ast/simplifier/basic_simplifier_plugin.h" #include "ast/simplifier/maximise_ac_sharing.h" -#include "ast/simplifier/bit2int.h" +#include "ast/rewriter/bit2int.h" #include "ast/macros/macro_manager.h" #include "ast/macros/macro_finder.h" #include "ast/normal_forms/defined_names.h" diff --git a/src/smt/elim_term_ite.h b/src/smt/elim_term_ite.h index 94e5e0346..106a9f511 100644 --- a/src/smt/elim_term_ite.h +++ b/src/smt/elim_term_ite.h @@ -59,6 +59,7 @@ public: } virtual ~elim_term_ite_cfg() {} vector<justified_expr> 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); }; @@ -70,6 +71,7 @@ public: m_cfg(m, dn) {} vector<justified_expr> const& new_defs() const { return m_cfg.new_defs(); } + void reset() { m_cfg.reset(); } }; diff --git a/src/smt/params/preprocessor_params.cpp b/src/smt/params/preprocessor_params.cpp index 9267dbeba..fcdea850f 100644 --- a/src/smt/params/preprocessor_params.cpp +++ b/src/smt/params/preprocessor_params.cpp @@ -46,7 +46,7 @@ void preprocessor_params::display(std::ostream & out) const { 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_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..fe759417d 100644 --- a/src/smt/params/preprocessor_params.h +++ b/src/smt/params/preprocessor_params.h @@ -39,7 +39,7 @@ struct preprocessor_params : public pattern_inference_params, 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_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 +62,7 @@ public: m_pull_cheap_ite_trees(false), m_pull_nested_quantifiers(false), m_eliminate_term_ite(false), - m_eliminate_and(true), + // m_eliminate_and(true), m_macro_finder(false), m_propagate_values(true), m_propagate_booleans(false), // TODO << check peformance From d3c00181ba526f92c5120b30509839b7eeb30613 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Fri, 25 Aug 2017 23:56:31 -0700 Subject: [PATCH 18/74] remove simplify dependencies Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/rewriter/bv_elim2.cpp | 115 +++++++++++++++++ src/ast/rewriter/bv_elim2.h | 50 ++++++++ src/ast/rewriter/elim_bounds2.cpp | 203 ++++++++++++++++++++++++++++++ src/ast/rewriter/elim_bounds2.h | 77 ++++++++++++ 4 files changed, 445 insertions(+) create mode 100644 src/ast/rewriter/bv_elim2.cpp create mode 100644 src/ast/rewriter/bv_elim2.h create mode 100644 src/ast/rewriter/elim_bounds2.cpp create mode 100644 src/ast/rewriter/elim_bounds2.h diff --git a/src/ast/rewriter/bv_elim2.cpp b/src/ast/rewriter/bv_elim2.cpp new file mode 100644 index 000000000..5b542e59e --- /dev/null +++ b/src/ast/rewriter/bv_elim2.cpp @@ -0,0 +1,115 @@ + +/*++ +Copyright (c) 2015 Microsoft Corporation + +--*/ + +#include "ast/rewriter/bv_elim2.h" +#include "ast/bv_decl_plugin.h" +#include "ast/rewriter/var_subst.h" +#include "ast/rewriter/rewriter_def.h" +#include <sstream> + +bool bv_elim_cfg::reduce_quantifier(quantifier * q, + expr * body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + + + svector<symbol> names, _names; + sort_ref_buffer sorts(m), _sorts(m); + expr_ref_buffer pats(m); + expr_ref_buffer no_pats(m); + expr_ref_buffer subst_map(m), _subst_map(m); + var_subst subst(m); + bv_util bv(m); + expr_ref new_body(m); + expr* old_body = body; + unsigned num_decls = q->get_num_decls(); + family_id bfid = m.mk_family_id("bv"); + + // + // Traverse sequence of bound variables to eliminate + // bit-vecctor variables and replace them by + // Booleans. + // + unsigned var_idx = 0; + bool found = false; + for (unsigned i = num_decls; i > 0; ) { + --i; + sort* s = q->get_decl_sort(i); + symbol nm = q->get_decl_name(i); + + if (bv.is_bv_sort(s)) { + // convert n-bit bit-vector variable into sequence of n-Booleans. + unsigned num_bits = bv.get_bv_size(s); + expr_ref_buffer args(m); + expr_ref bv(m); + found = true; + for (unsigned j = 0; j < num_bits; ++j) { + std::ostringstream new_name; + new_name << nm.str(); + new_name << "_"; + new_name << j; + var* v = m.mk_var(var_idx++, m.mk_bool_sort()); + args.push_back(v); + _sorts.push_back(m.mk_bool_sort()); + _names.push_back(symbol(new_name.str().c_str())); + } + bv = m.mk_app(bfid, OP_MKBV, 0, 0, args.size(), args.c_ptr()); + _subst_map.push_back(bv.get()); + } + else { + _subst_map.push_back(m.mk_var(var_idx++, s)); + _sorts.push_back(s); + _names.push_back(nm); + } + } + if (!found) { + return false; + } + // + // reverse the vectors. + // + SASSERT(_names.size() == _sorts.size()); + for (unsigned i = _names.size(); i > 0; ) { + --i; + names.push_back(_names[i]); + sorts.push_back(_sorts[i]); + } + for (unsigned i = _subst_map.size(); i > 0; ) { + --i; + subst_map.push_back(_subst_map[i]); + } + + expr* const* sub = subst_map.c_ptr(); + unsigned sub_size = subst_map.size(); + + subst(old_body, sub_size, sub, new_body); + + for (unsigned j = 0; j < q->get_num_patterns(); j++) { + expr_ref pat(m); + subst(new_patterns[j], sub_size, sub, pat); + pats.push_back(pat); + } + for (unsigned j = 0; j < q->get_num_no_patterns(); j++) { + expr_ref nopat(m); + subst(new_no_patterns[j], sub_size, sub, nopat); + no_pats.push_back(nopat); + } + + result = m.mk_quantifier(true, + names.size(), + sorts.c_ptr(), + names.c_ptr(), + new_body.get(), + q->get_weight(), + q->get_qid(), + q->get_skid(), + pats.size(), pats.c_ptr(), + no_pats.size(), no_pats.c_ptr()); + result_pr = m.mk_rewrite(q, result); + return true; +} diff --git a/src/ast/rewriter/bv_elim2.h b/src/ast/rewriter/bv_elim2.h new file mode 100644 index 000000000..a4829b207 --- /dev/null +++ b/src/ast/rewriter/bv_elim2.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_ELIM2_H_ +#define BV_ELIM2_H_ + +#include "ast/ast.h" +#include "ast/rewriter/rewriter.h" + +class bv_elim_cfg : public default_rewriter_cfg { + ast_manager& m; +public: + bv_elim_cfg(ast_manager& m) : m(m) {} + + bool reduce_quantifier(quantifier * old_q, + expr * new_body, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr); +}; + +class bv_elim_rw : public rewriter_tpl<bv_elim_cfg> { +protected: + bv_elim_cfg m_cfg; +public: + bv_elim_rw(ast_manager & m): + rewriter_tpl<bv_elim_cfg>(m, m.proofs_enabled(), m_cfg), + m_cfg(m) + {} +}; + +#endif /* BV_ELIM_H_ */ + diff --git a/src/ast/rewriter/elim_bounds2.cpp b/src/ast/rewriter/elim_bounds2.cpp new file mode 100644 index 000000000..9691ade09 --- /dev/null +++ b/src/ast/rewriter/elim_bounds2.cpp @@ -0,0 +1,203 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + elim_bounds2.cpp + +Abstract: + + <abstract> + +Author: + + Leonardo de Moura (leonardo) 2008-06-28. + +Revision History: + +--*/ + +#ifndef ELIM_BOUNDS_H_ +#define ELIM_BOUNDS_H_ + +#include "ast/used_vars.h" +#include "util/obj_hashtable.h" +#include "ast/rewriter/var_subst.h" +#include "ast/rewriter/elim_bounds2.h" +#include "ast/ast_pp.h" + +elim_bounds_cfg::elim_bounds_cfg(ast_manager & m): + m(m), + m_util(m) { +} + +/** + \brief Find bounds of the form + + (<= x k) + (<= (+ x (* -1 y)) k) + (<= (+ x (* -1 t)) k) + (<= (+ t (* -1 x)) k) + + x and y are a bound variables, t is a ground term and k is a numeral + + It also detects >=, and the atom can be negated. +*/ +bool elim_bounds_cfg::is_bound(expr * n, var * & lower, var * & upper) { + upper = 0; + lower = 0; + bool neg = false; + if (m.is_not(n)) { + n = to_app(n)->get_arg(0); + neg = true; + } + + expr* l = 0, *r = 0; + bool le = false; + if (m_util.is_le(n, l, r) && m_util.is_numeral(r)) { + n = l; + le = true; + } + else if (m_util.is_ge(n, l, r) && m_util.is_numeral(r)) { + n = l; + le = false; + } + else { + return false; + } + + if (neg) + le = !le; + + if (is_var(n)) { + upper = to_var(n); + } + else if (m_util.is_add(n, l, r)) { + expr * arg1 = l; + expr * arg2 = r; + if (is_var(arg1)) + upper = to_var(arg1); + else if (!is_ground(arg1)) + return false; + rational k; + bool is_int; + if (m_util.is_mul(arg2) && m_util.is_numeral(to_app(arg2)->get_arg(0), k, is_int) && k.is_minus_one()) { + arg2 = to_app(arg2)->get_arg(1); + if (is_var(arg2)) + lower = to_var(arg2); + else if (!is_ground(arg2)) + return false; // not supported + } + else { + return false; // not supported + } + } + else { + return false; + } + + if (!le) + std::swap(upper, lower); + + return true; +} + +bool elim_bounds_cfg::is_bound(expr * n) { + var * lower, * upper; + return is_bound(n, lower, upper); +} + + +bool elim_bounds_cfg::reduce_quantifier(quantifier * q, + expr * n, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + if (!q->is_forall()) { + return false; + } + unsigned num_vars = q->get_num_decls(); + ptr_buffer<expr> atoms; + if (m.is_or(n)) + atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args()); + else + atoms.push_back(n); + used_vars used_vars; + // collect non-candidates + for (expr * a : atoms) { + if (!is_bound(a)) + used_vars.process(a); + } + if (used_vars.uses_all_vars(q->get_num_decls())) { + return false; + } + // collect candidates + obj_hashtable<var> lowers; + obj_hashtable<var> uppers; + obj_hashtable<var> candidate_set; + ptr_buffer<var> candidates; +#define ADD_CANDIDATE(V) if (!lowers.contains(V) && !uppers.contains(V)) { candidate_set.insert(V); candidates.push_back(V); } + for (expr * a : atoms) { + var * lower = 0; + var * upper = 0; + if (is_bound(a, lower, upper)) { + if (lower != 0 && !used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) { + ADD_CANDIDATE(lower); + lowers.insert(lower); + } + if (upper != 0 && !used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) { + ADD_CANDIDATE(upper); + uppers.insert(upper); + } + } + } + TRACE("elim_bounds", tout << "candidates:\n"; for (unsigned i = 0; i < candidates.size(); i++) tout << mk_pp(candidates[i], m) << "\n";); + // remove candidates that have lower and upper bounds + + for (var * v : candidates) { + if (lowers.contains(v) && uppers.contains(v)) + candidate_set.erase(v); + } + TRACE("elim_bounds", tout << "candidates after filter:\n"; for (unsigned i = 0; i < candidates.size(); i++) tout << mk_pp(candidates[i], m) << "\n";); + if (candidate_set.empty()) { + return false; + } + // remove bounds that contain variables in candidate_set + unsigned j = 0; + for (unsigned i = 0; i < atoms.size(); ++i) { + expr * a = atoms[i]; + var * lower = 0; + var * upper = 0; + if (is_bound(a, lower, upper) && ((lower != 0 && candidate_set.contains(lower)) || (upper != 0 && candidate_set.contains(upper)))) + continue; + atoms[j] = a; + j++; + } + if (j == atoms.size()) { + return false; + } + atoms.resize(j); + expr * new_body = 0; + switch (atoms.size()) { + case 0: + result = m.mk_false(); + result_pr = m.mk_rewrite(q, result); + TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";); + return true; + case 1: + new_body = atoms[0]; + break; + default: + new_body = m.mk_or(atoms.size(), atoms.c_ptr()); + break; + } + quantifier_ref new_q(m); + new_q = m.update_quantifier(q, new_body); + elim_unused_vars(m, new_q, params_ref(), result); + result_pr = m.mk_rewrite(q, result); + TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";); + return true; +} + +#endif /* ELIM_BOUNDS_H_ */ diff --git a/src/ast/rewriter/elim_bounds2.h b/src/ast/rewriter/elim_bounds2.h new file mode 100644 index 000000000..0d3b026cf --- /dev/null +++ b/src/ast/rewriter/elim_bounds2.h @@ -0,0 +1,77 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + elim_bounds2.h + +Abstract: + + <abstract> + +Author: + + Leonardo de Moura (leonardo) 2008-06-28. + +Revision History: + +--*/ +#ifndef ELIM_BOUNDS2_H_ +#define ELIM_BOUNDS2_H_ + +#include "ast/ast.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/rewrite.h" + +/** + \brief Functor for eliminating irrelevant bounds in quantified formulas. + + Example: + (forall (x Int) (y Int) (or (not (>= y x) (not (>= x 0)) (= (select a x) 1)))) + + The bound (>= y x) is irrelevant and can be eliminated. + + This can be easily proved by using Fourier-Motzkin elimination. + + Limitations & Assumptions: + - It assumes the input formula was already simplified. + - It can only handle bounds in the diff-logic fragment. + + \remark This operation is subsumed by Fourier-Motzkin elimination. +*/ +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_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_bounds2 in all + universal quantifiers in an expression. + + Assumption: the formula was already skolemized. +*/ +class elim_bounds_rw : public rewriter_tpl<elim_bounds_cfg> { +protected: + elim_bounds_cfg m_cfg; +public: + elim_bounds_rw(ast_manager & m): + rewriter_tpl<elim_bounds_cfg>(m, m.proofs_enabled(), m_cfg), + m_cfg(m) + {} + + virtual ~elim_bounds_rw() {} +}; + +#endif /* ELIM_BOUNDS2_H_ */ + From b16a4ac4528d4b9399b5eb7b728e22e0df86b1c0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Fri, 25 Aug 2017 23:57:10 -0700 Subject: [PATCH 19/74] remove simplify dependencies Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/rewriter/elim_bounds2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/rewriter/elim_bounds2.h b/src/ast/rewriter/elim_bounds2.h index 0d3b026cf..e0bba4e60 100644 --- a/src/ast/rewriter/elim_bounds2.h +++ b/src/ast/rewriter/elim_bounds2.h @@ -21,7 +21,7 @@ Revision History: #include "ast/ast.h" #include "ast/arith_decl_plugin.h" -#include "ast/rewriter/rewrite.h" +#include "ast/rewriter/rewriter.h" /** \brief Functor for eliminating irrelevant bounds in quantified formulas. From 2897b98ed2b712d0fec4ee84b4776830efed1f7c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 26 Aug 2017 00:37:22 -0700 Subject: [PATCH 20/74] remove simplify dependencies Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/muz/bmc/dl_bmc_engine.cpp | 2 +- src/muz/pdr/pdr_smt_context_manager.cpp | 2 +- src/muz/spacer/spacer_virtual_solver.cpp | 4 ++-- src/opt/opt_solver.cpp | 4 ++-- src/smt/asserted_formulas.cpp | 1 + src/smt/asserted_formulas.h | 5 ++++- src/smt/qi_queue.cpp | 2 +- src/smt/smt_context.cpp | 23 ++--------------------- src/smt/smt_context.h | 14 ++++++-------- src/smt/smt_kernel.cpp | 16 ++++++++++------ src/smt/smt_kernel.h | 7 ++++++- src/smt/smt_quick_checker.cpp | 4 ++-- src/smt/smt_quick_checker.h | 4 ++-- src/smt/smt_setup.cpp | 12 +++++++++--- src/smt/smt_solver.cpp | 2 +- src/smt/theory_arith_core.h | 2 +- src/smt/theory_arith_int.h | 3 +-- src/smt/theory_arith_nl.h | 2 +- src/smt/theory_array_full.cpp | 9 ++++----- src/smt/theory_array_full.h | 3 --- src/smt/theory_bv.cpp | 9 ++++----- src/smt/theory_bv.h | 10 ---------- src/smt/theory_fpa.cpp | 2 +- 23 files changed, 62 insertions(+), 80 deletions(-) diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 0f7914e0c..6d2f88019 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -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_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/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/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/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index f8efcbf4b..3fb20d283 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -47,6 +47,7 @@ asserted_formulas::asserted_formulas(ast_manager & m, smt_params & p): m_params(p), m_pre_simplifier(m), m_simplifier(m), + m_rewriter(m), m_defined_names(m), m_static_features(m), m_asserted_formulas(m), diff --git a/src/smt/asserted_formulas.h b/src/smt/asserted_formulas.h index fb621000c..3c5f424fb 100644 --- a/src/smt/asserted_formulas.h +++ b/src/smt/asserted_formulas.h @@ -30,6 +30,7 @@ Revision History: #include "ast/normal_forms/defined_names.h" #include "ast/pattern/pattern_inference.h" #include "smt/params/smt_params.h" +#include "ast/rewriter/th_rewriter.h" class arith_simplifier_plugin; class bv_simplifier_plugin; @@ -39,6 +40,7 @@ class asserted_formulas { smt_params & m_params; simplifier m_pre_simplifier; simplifier m_simplifier; + th_rewriter m_rewriter; basic_simplifier_plugin * m_bsimp; bv_simplifier_plugin * m_bvsimp; defined_names m_defined_names; @@ -121,7 +123,8 @@ public: proof * const * get_formula_proofs() const { return m_asserted_formula_prs.c_ptr(); } void init(unsigned num_formulas, expr * const * formulas, proof * const * prs); void register_simplifier_plugin(simplifier_plugin * p) { m_simplifier.register_plugin(p); } - simplifier & get_simplifier() { return m_simplifier; } + // simplifier & get_simplifier() { return m_simplifier; } + th_rewriter& get_rewriter() { return m_rewriter; } void get_assertions(ptr_vector<expr> & result); bool empty() const { return m_asserted_formulas.empty(); } void collect_static_features(); diff --git a/src/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index 36a2ce834..8f8e3df7b 100644 --- a/src/smt/qi_queue.cpp +++ b/src/smt/qi_queue.cpp @@ -227,7 +227,7 @@ 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(); + th_rewriter & simp = m_context.get_rewriter(); simp(instance, s_instance, pr); TRACE("qi_queue_bug", tout << "new instance after simplification:\n" << mk_pp(s_instance, m_manager) << "\n";); if (m_manager.is_true(s_instance)) { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index b966b8380..7b92bdd28 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -148,8 +148,8 @@ namespace smt { dst_ctx.set_logic(src_ctx.m_setup.get_logic()); dst_ctx.copy_plugins(src_ctx, dst_ctx); - asserted_formulas& src_af = src_ctx.m_asserted_formulas; - asserted_formulas& dst_af = dst_ctx.m_asserted_formulas; + asserted_formulas_new& src_af = src_ctx.m_asserted_formulas; + asserted_formulas_new& dst_af = dst_ctx.m_asserted_formulas; // Copy asserted formulas. for (unsigned i = 0; i < src_af.get_num_formulas(); ++i) { @@ -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<simplifier_plugin>::const_iterator it1 = src_s.begin_plugins(); - ptr_vector<simplifier_plugin>::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 fecb42700..fbf7cbca3 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -36,7 +36,7 @@ Revision History: #include "smt/smt_case_split_queue.h" #include "smt/smt_almost_cg_table.h" #include "smt/smt_failure.h" -#include "smt/asserted_formulas.h" +#include "smt/asserted_formulas_new.h" #include "smt/smt_types.h" #include "smt/dyn_ack.h" #include "ast/ast_smt_pp.h" @@ -81,7 +81,7 @@ namespace smt { params_ref m_params; setup m_setup; timer m_timer; - asserted_formulas m_asserted_formulas; + asserted_formulas_new m_asserted_formulas; scoped_ptr<quantifier_manager> m_qmanager; scoped_ptr<model_generator> m_model_generator; scoped_ptr<relevancy_propagator> m_relevancy_propagator; @@ -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<expr>& 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<expr> & 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<expr>& 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<expr>& 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_quick_checker.cpp b/src/smt/smt_quick_checker.cpp index f8744318a..773768944 100644 --- a/src/smt/smt_quick_checker.cpp +++ b/src/smt/smt_quick_checker.cpp @@ -164,7 +164,7 @@ namespace smt { quick_checker::quick_checker(context & c): m_context(c), m_manager(c.get_manager()), - m_simplifier(c.get_simplifier()), + m_simplifier(c.get_rewriter()), m_collector(c), m_new_exprs(m_manager) { } @@ -411,7 +411,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_simplifier.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..d07e10921 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,7 @@ namespace smt { context & m_context; ast_manager & m_manager; - simplifier & m_simplifier; + th_rewriter & m_simplifier; collector m_collector; expr_ref_vector m_new_exprs; vector<enode_vector> m_candidate_vectors; diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index a37668c7b..f0c44a574 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<expr> 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); @@ -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<expr> 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; @@ -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<expr> 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..9d86436d9 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -216,7 +216,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 { diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index a30e51133..70355502d 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -442,7 +442,7 @@ namespace smt { void theory_arith<Ext>::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; diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index d93e062f4..fbcc9c11a 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -455,9 +455,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_full.cpp b/src/smt/theory_array_full.cpp index d5660e325..c7a3d7920 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,7 @@ 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 = ctx.get_rewriter().mk_app(f, args2.size(), args2.c_ptr()); ctx.internalize(sel1, false); ctx.internalize(sel2, false); @@ -553,7 +554,7 @@ namespace smt { expr* def1 = mk_default(map); expr_ref def2(get_manager()); - m_simp->mk_app(f, args2.size(), args2.c_ptr(), def2); + def2 = ctx.get_rewriter().mk_app(f, args2.size(), args2.c_ptr()); ctx.internalize(def1, false); ctx.internalize(def2, false); return try_assign_eq(def1, def2); @@ -722,9 +723,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<basic_simplifier_plugin*>(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<var_data_full> m_var_data_full; ast2ast_trailmap<sort,app> m_sort2epsilon; - simplifier* m_simp; obj_pair_map<expr,expr,bool> m_eqs; svector<literal> 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<arith_simplifier_plugin*>(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_fpa.cpp b/src/smt/theory_fpa.cpp index e8edfc7ec..3f246b2c7 100644 --- a/src/smt/theory_fpa.cpp +++ b/src/smt/theory_fpa.cpp @@ -385,7 +385,7 @@ namespace smt { { ast_manager & m = get_manager(); context & ctx = get_context(); - simplifier & simp = ctx.get_simplifier(); + th_rewriter & simp = ctx.get_rewriter(); expr_ref res(m), t(m); proof_ref t_pr(m); From 881f90d17d97f0a545503fb7ed3eb763321aaa37 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 26 Aug 2017 00:48:49 -0700 Subject: [PATCH 21/74] remove simplify dependencies Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/macros/macro_manager.h | 1 - src/ast/pattern/pattern_inference.h | 187 ------------------ .../dl_mk_quantifier_instantiation.cpp | 1 + src/smt/elim_term_ite.h | 3 +- 4 files changed, 2 insertions(+), 190 deletions(-) diff --git a/src/ast/macros/macro_manager.h b/src/ast/macros/macro_manager.h index 58fedf666..87073004c 100644 --- a/src/ast/macros/macro_manager.h +++ b/src/ast/macros/macro_manager.h @@ -21,7 +21,6 @@ Revision History: #include "util/obj_hashtable.h" #include "ast/ast_util.h" -#include "ast/simplifier/simplifier.h" #include "ast/recurse_expr.h" #include "ast/func_decl_dependencies.h" #include "ast/macros/macro_util.h" diff --git a/src/ast/pattern/pattern_inference.h b/src/ast/pattern/pattern_inference.h index 281c3ff8b..905662477 100644 --- a/src/ast/pattern/pattern_inference.h +++ b/src/ast/pattern/pattern_inference.h @@ -20,7 +20,6 @@ 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" @@ -61,192 +60,6 @@ public: bool operator()(unsigned num_bindings, expr * p1, expr * p2); }; -#if 0 -class pattern_inference_old : public simplifier { - pattern_inference_params & m_params; - family_id m_bfid; - family_id m_afid; - svector<family_id> m_forbidden; - obj_hashtable<func_decl> m_preferred; - smaller_pattern m_le; - unsigned m_num_bindings; - unsigned m_num_no_patterns; - expr * const * m_no_patterns; - bool m_nested_arith_only; - bool m_block_loop_patterns; - - struct info { - uint_set m_free_vars; - unsigned m_size; - info(uint_set const & vars, unsigned size): - m_free_vars(vars), - m_size(size) { - } - info(): - m_free_vars(), - m_size(0) { - } - }; - - typedef obj_map<expr, info> expr2info; - - expr2info m_candidates_info; // candidate -> set of free vars + size - app_ref_vector m_candidates; - - ptr_vector<app> m_tmp1; - ptr_vector<app> m_tmp2; - ptr_vector<app> m_todo; - - // Compare candidates patterns based on their usefulness - // p1 < p2 if - // - p1 has more free variables than p2 - // - p1 and p2 has the same number of free variables, - // and p1 is smaller than p2. - struct pattern_weight_lt { - expr2info & m_candidates_info; - pattern_weight_lt(expr2info & i): - m_candidates_info(i) { - } - bool operator()(expr * n1, expr * n2) const; - }; - - pattern_weight_lt m_pattern_weight_lt; - - // - // Functor for collecting candidates. - // - class collect { - struct entry { - expr * m_node; - unsigned m_delta; - entry():m_node(0), m_delta(0) {} - entry(expr * n, unsigned d):m_node(n), m_delta(d) {} - unsigned hash() const { - return hash_u_u(m_node->get_id(), m_delta); - } - bool operator==(entry const & e) const { - return m_node == e.m_node && m_delta == e.m_delta; - } - }; - - struct info { - expr_ref m_node; - uint_set m_free_vars; - unsigned m_size; - info(ast_manager & m, expr * n, uint_set const & vars, unsigned sz): - m_node(n, m), m_free_vars(vars), m_size(sz) {} - }; - - ast_manager & m; - pattern_inference_old & m_owner; - family_id m_afid; - unsigned m_num_bindings; - typedef map<entry, info *, obj_hash<entry>, default_eq<entry> > cache; - cache m_cache; - ptr_vector<info> m_info; - svector<entry> m_todo; - - void visit(expr * n, unsigned delta, bool & visited); - bool visit_children(expr * n, unsigned delta); - void save(expr * n, unsigned delta, info * i); - void save_candidate(expr * n, unsigned delta); - void reset(); - public: - collect(ast_manager & m, pattern_inference_old & o):m(m), m_owner(o), m_afid(m.mk_family_id("arith")) {} - void operator()(expr * n, unsigned num_bindings); - }; - - collect m_collect; - - void add_candidate(app * n, uint_set const & s, unsigned size); - - void filter_looping_patterns(ptr_vector<app> & result); - - bool has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result); - - void filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result); - - class contains_subpattern { - pattern_inference_old & m_owner; - nat_set m_already_processed; - ptr_vector<expr> m_todo; - void save(expr * n); - public: - contains_subpattern(pattern_inference_old & owner): - m_owner(owner) {} - bool operator()(expr * n); - }; - - contains_subpattern m_contains_subpattern; - - bool contains_subpattern(expr * n); - - struct pre_pattern { - ptr_vector<app> m_exprs; // elements of the pattern. - uint_set m_free_vars; // set of free variables in m_exprs - unsigned m_idx; // idx of the next candidate to process. - pre_pattern(): - m_idx(0) { - } - }; - - ptr_vector<pre_pattern> m_pre_patterns; - expr_pattern_match m_database; - - void candidates2unary_patterns(ptr_vector<app> const & candidate_patterns, - ptr_vector<app> & remaining_candidate_patterns, - app_ref_buffer & result); - - void candidates2multi_patterns(unsigned max_num_patterns, - ptr_vector<app> const & candidate_patterns, - app_ref_buffer & result); - - void reset_pre_patterns(); - - /** - \brief All minimal unary patterns (i.e., expressions that - contain all bound variables) are copied to result. If there - are unary patterns, then at most num_extra_multi_patterns multi - patterns are created. If there are no unary pattern, then at - most 1 + num_extra_multi_patterns multi_patterns are created. - */ - void mk_patterns(unsigned num_bindings, // IN number of bindings. - expr * n, // IN node where the patterns are going to be extracted. - unsigned num_no_patterns, // IN num. patterns that should not be used. - 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_old(ast_manager & m, pattern_inference_params & params); - - void register_forbidden_family(family_id fid) { - SASSERT(fid != m_bfid); - m_forbidden.push_back(fid); - } - - /** - \brief Register f as a preferred function symbol. The inference algorithm - gives preference to patterns rooted by this kind of function symbol. - */ - void register_preferred(func_decl * f) { - m_preferred.insert(f); - } - - 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 { - family_id fid = decl->get_family_id(); - if (fid == m_bfid && decl->get_decl_kind() != OP_TRUE && decl->get_decl_kind() != OP_FALSE) - return true; - return std::find(m_forbidden.begin(), m_forbidden.end(), fid) != m_forbidden.end(); - } - - bool is_forbidden(app * n) const; -}; -#endif - class pattern_inference_cfg : public default_rewriter_cfg { ast_manager& m; pattern_inference_params & m_params; diff --git a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp index 74d15bcdf..8986bf506 100644 --- a/src/muz/transforms/dl_mk_quantifier_instantiation.cpp +++ b/src/muz/transforms/dl_mk_quantifier_instantiation.cpp @@ -27,6 +27,7 @@ Revision History: #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 { diff --git a/src/smt/elim_term_ite.h b/src/smt/elim_term_ite.h index 106a9f511..86b9a79e2 100644 --- a/src/smt/elim_term_ite.h +++ b/src/smt/elim_term_ite.h @@ -19,9 +19,9 @@ 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/simplifier/simplifier.h" class elim_term_ite : public simplifier { defined_names & m_defined_names; @@ -48,7 +48,6 @@ public: }; - class elim_term_ite_cfg : public default_rewriter_cfg { ast_manager& m; defined_names & m_defined_names; From 5371315f4c999b3a314a0d0023c1091f51ebc9aa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 26 Aug 2017 00:57:44 -0700 Subject: [PATCH 22/74] remove simplify dependencies Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/muz/spacer/spacer_legacy_mev.cpp | 3 --- src/muz/spacer/spacer_legacy_mev.h | 1 - src/muz/spacer/spacer_util.h | 3 ++- 3 files changed, 2 insertions(+), 5 deletions(-) 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 <sstream> -#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_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" From 14e6b5b50008134a0d92379a69a4d537a7f2b2d0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 26 Aug 2017 01:38:55 -0700 Subject: [PATCH 23/74] mising files Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/rewriter/maximize_ac_sharing.cpp | 175 +++++++++++++++++++++++ src/ast/rewriter/maximize_ac_sharing.h | 125 ++++++++++++++++ 2 files changed, 300 insertions(+) create mode 100644 src/ast/rewriter/maximize_ac_sharing.cpp create mode 100644 src/ast/rewriter/maximize_ac_sharing.h diff --git a/src/ast/rewriter/maximize_ac_sharing.cpp b/src/ast/rewriter/maximize_ac_sharing.cpp new file mode 100644 index 000000000..b560132db --- /dev/null +++ b/src/ast/rewriter/maximize_ac_sharing.cpp @@ -0,0 +1,175 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + maximize_ac_sharing.cpp + +Abstract: + + <abstract> + +Author: + + Leonardo de Moura (leonardo) 2008-10-22. + +Revision History: + +--*/ + +#include "ast/rewriter/maximize_ac_sharing.h" +#include "ast/ast_pp.h" + + +void maximize_ac_sharing::register_kind(decl_kind k) { + m_kinds.push_back(k); +} + + +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 BR_FAILED; + if (num_args <= 2) + return BR_FAILED; + if (std::find(m_kinds.begin(), m_kinds.end(), k) == m_kinds.end()) + return BR_FAILED; + ptr_buffer<expr, 128> _args; + expr * numeral = 0; + if (is_numeral(args[0])) { + numeral = args[0]; + for (unsigned i = 1; i < num_args; i++) + _args.push_back(args[i]); + num_args--; + } + else { + _args.append(num_args, args); + } + + TRACE("ac_sharing_detail", tout << "before-reuse: num_args: " << num_args << "\n";); + +#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) << "\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 (contains(f, _args[i], _args[j])) { + TRACE("ac_sharing_detail", tout << "reusing args: " << i << " " << j << "\n";); + _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]; + } + num_args--; + goto try_to_reuse; + } + } + } + } + + + // Create "tree-like circuit" + while (true) { + TRACE("ac_sharing_detail", tout << "tree-loop: num_args: " << num_args << "\n";); + unsigned j = 0; + for (unsigned i = 0; i < num_args; i += 2, j++) { + if (i == num_args - 1) { + _args[j] = _args[i]; + } + else { + insert(f, _args[i], _args[i+1]); + _args[j] = m.mk_app(f, _args[i], _args[i+1]); + } + } + num_args = j; + if (num_args == 1) { + if (numeral == 0) { + result = _args[0]; + } + else { + result = m.mk_app(f, numeral, _args[0]); + } + TRACE("ac_sharing_detail", tout << "result: " << mk_pp(result, m) << "\n";); + return BR_DONE; + } + } + + UNREACHABLE(); + return BR_FAILED; +} + +bool maximize_ac_sharing::contains(func_decl * f, expr * arg1, expr * arg2) { + entry e(f, arg1, arg2); + return m_cache.contains(&e); +} + +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.inc_ref(arg1); + m.inc_ref(arg2); +} + +maximize_ac_sharing::maximize_ac_sharing(ast_manager & m): + m(m), + m_init(false) { +} + +maximize_ac_sharing::~maximize_ac_sharing() { + restore_entries(0); +} + + +void maximize_ac_sharing::push_scope() { + init(); + m_scopes.push_back(m_entries.size()); + m_region.push_scope(); +} + +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]; + restore_entries(old_lim); + m_region.pop_scope(num_scopes); + m_scopes.shrink(new_lvl); +} + +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.dec_ref(e->m_arg1); + m.dec_ref(e->m_arg2); + } + m_entries.shrink(old_lim); +} + +void maximize_ac_sharing::reset() { + restore_entries(0); + m_entries.reset(); + m_cache.reset(); + m_region.reset(); + m_scopes.reset(); +} + +void maximize_bv_sharing::init_core() { + register_kind(OP_BADD); + register_kind(OP_BMUL); + register_kind(OP_BOR); + register_kind(OP_BAND); +} + +bool maximize_bv_sharing::is_numeral(expr * n) const { + return m_util.is_numeral(n); +} + +maximize_bv_sharing::maximize_bv_sharing(ast_manager & m): + maximize_ac_sharing(m), + m_util(m) { +} diff --git a/src/ast/rewriter/maximize_ac_sharing.h b/src/ast/rewriter/maximize_ac_sharing.h new file mode 100644 index 000000000..c0ee0d09f --- /dev/null +++ b/src/ast/rewriter/maximize_ac_sharing.h @@ -0,0 +1,125 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + maximize_ac_sharing.h + +Abstract: + + <abstract> + +Author: + + Leonardo de Moura (leonardo) 2008-10-22. + +Revision History: + +--*/ +#ifndef MAXIMIZE_AC_SHARING_H_ +#define MAXIMIZE_AC_SHARING_H_ + +#include "util/hashtable.h" +#include "util/region.h" +#include "ast/bv_decl_plugin.h" +#include "ast/rewriter/rewriter.h" + +/** + \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))) + + is rewritten to: + + (f (bvadd (bvadd a b) c) (bvadd (bvadd a b) d)) + + \warning This class uses an opportunistic heuristic to maximize sharing. + There is no guarantee that the optimal expression will be produced. +*/ +class maximize_ac_sharing : public default_rewriter_cfg { + + struct entry { + func_decl * m_decl; + expr * m_arg1; + expr * m_arg2; + + entry(func_decl * d = 0, expr * arg1 = 0, expr * arg2 = 0):m_decl(d), m_arg1(arg1), m_arg2(arg2) { + SASSERT((d == 0 && arg1 == 0 && arg2 == 0) || (d != 0 && arg1 != 0 && arg2 != 0)); + if (arg1->get_id() > arg2->get_id()) + std::swap(m_arg1, m_arg2); + } + + unsigned hash() const { + unsigned a = m_decl->get_id(); + unsigned b = m_arg1->get_id(); + unsigned c = m_arg2->get_id(); + mix(a,b,c); + return c; + } + + bool operator==(entry const & e) const { + return m_decl == e.m_decl && m_arg1 == e.m_arg1 && m_arg2 == e.m_arg2; + } + }; + + typedef ptr_hashtable<entry, obj_ptr_hash<entry>, deref_eq<entry> > cache; + +protected: + void register_kind(decl_kind k); + +private: + ast_manager & m; + bool m_init; + region m_region; + cache m_cache; + ptr_vector<entry> m_entries; + unsigned_vector m_scopes; + svector<decl_kind> m_kinds; //!< kinds to be processed + + bool contains(func_decl * f, expr * arg1, expr * arg2); + void insert(func_decl * f, expr * arg1, expr * arg2); + void restore_entries(unsigned old_lim); + void init() { + if (!m_init) { + init_core(); + m_init = true; + } + } +protected: + virtual void init_core() = 0; + virtual bool is_numeral(expr * n) const = 0; +public: + maximize_ac_sharing(ast_manager & m); + virtual ~maximize_ac_sharing(); + void push_scope(); + void pop_scope(unsigned num_scopes); + void reset(); + br_status reduce_app(func_decl* f, unsigned n, expr * const* args, expr_ref& result, proof_ref& result_pr); + +}; + +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: + maximize_bv_sharing(ast_manager & m); +}; + +class maximize_bv_sharing_rw : public rewriter_tpl<maximize_bv_sharing> { + maximize_bv_sharing m_cfg; +public: + maximize_bv_sharing_rw(ast_manager& m): + rewriter_tpl<maximize_bv_sharing>(m, m.proofs_enabled(), m_cfg), + m_cfg(m) + {} + void push_scope() { m_cfg.push_scope(); } + void pop_scope(unsigned n) { m_cfg.pop_scope(n); } + void reset() { m_cfg.reset(); } +}; + +#endif /* MAXIMIZE_AC_SHARING_H_ */ + From 9b53646a342dd65b5f48a45cad11da81ed5199f6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 26 Aug 2017 01:43:06 -0700 Subject: [PATCH 24/74] mising files Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/smt/asserted_formulas_new.cpp | 619 ++++++++++++++++++++++++++++++ src/smt/asserted_formulas_new.h | 269 +++++++++++++ 2 files changed, 888 insertions(+) create mode 100644 src/smt/asserted_formulas_new.cpp create mode 100644 src/smt/asserted_formulas_new.h diff --git a/src/smt/asserted_formulas_new.cpp b/src/smt/asserted_formulas_new.cpp new file mode 100644 index 000000000..51bba9f7f --- /dev/null +++ b/src/smt/asserted_formulas_new.cpp @@ -0,0 +1,619 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + asserted_formulas_new.cpp + +Abstract: + + <abstract> + +Author: + + Leonardo de Moura (leonardo) 2008-06-11. + +Revision History: + +--*/ +#include "util/warning.h" +#include "ast/ast_ll_pp.h" +#include "ast/ast_pp.h" +#include "ast/for_each_expr.h" +#include "ast/well_sorted.h" +#include "ast/rewriter/rewriter_def.h" +#include "ast/normal_forms/nnf.h" +#include "ast/pattern/pattern_inference.h" +#include "ast/macros/quasi_macros.h" +#include "smt/asserted_formulas_new.h" + +asserted_formulas_new::asserted_formulas_new(ast_manager & m, smt_params & p): + m(m), + m_params(p), + m_rewriter(m), + m_substitution(m), + m_scoped_substitution(m_substitution), + m_defined_names(m), + m_static_features(m), + m_qhead(0), + m_macro_manager(m), + m_bv_sharing(m), + 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_macro_finder = alloc(macro_finder, m, m_macro_manager); +} + +void asserted_formulas_new::setup() { + switch (m_params.m_lift_ite) { + case LI_FULL: + m_params.m_ng_lift_ite = LI_NONE; + break; + case LI_CONSERVATIVE: + if (m_params.m_ng_lift_ite == LI_CONSERVATIVE) + m_params.m_ng_lift_ite = LI_NONE; + break; + default: + break; + } + + if (m_params.m_relevancy_lvl == 0) + m_params.m_relevancy_lemma = false; +} + + +asserted_formulas_new::~asserted_formulas_new() { +} + +void asserted_formulas_new::push_assertion(expr * e, proof * pr, vector<justified_expr>& result) { + if (inconsistent()) { + SASSERT(!result.empty()); + return; + } + 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), *e2; + proof_ref _pr(m.mk_not_or_elim(pr, i), m); + if (m.is_not(arg, e2)) { + push_assertion(e2, _pr, result); + } + else { + expr_ref narg(m.mk_not(arg), m); + push_assertion(narg, _pr, result); + } + } + } + else { + result.push_back(justified_expr(m, e, pr)); + } +} + +void asserted_formulas_new::set_eliminate_and(bool flag) { + params_ref p; + p.set_bool("elim_and", true); + m_rewriter.updt_params(p); + flush_cache(); +} + + +void asserted_formulas_new::assert_expr(expr * e, proof * _in_pr) { + 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";); + } + push_assertion(r, pr, m_formulas); + TRACE("asserted_formulas_bug", tout << "after assert_expr\n"; display(tout);); +} + +void asserted_formulas_new::assert_expr(expr * e) { + if (!inconsistent()) + assert_expr(e, m.mk_asserted(e)); +} + +void asserted_formulas_new::get_assertions(ptr_vector<expr> & result) const { + for (justified_expr const& je : m_formulas) result.push_back(je.get_fml()); +} + +void asserted_formulas_new::push_scope() { + SASSERT(inconsistent() || m_qhead == m_formulas.size() || m.canceled()); + TRACE("asserted_formulas_new_scopes", tout << "push:\n"; display(tout);); + m_scoped_substitution.push(); + m_scopes.push_back(scope()); + scope & s = m_scopes.back(); + 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_new::pop_scope(unsigned num_scopes) { + TRACE("asserted_formulas_new_scopes", tout << "before pop " << num_scopes << "\n"; display(tout);); + m_bv_sharing.pop_scope(num_scopes); + m_macro_manager.pop_scope(num_scopes); + unsigned new_lvl = m_scopes.size() - num_scopes; + scope & s = m_scopes[new_lvl]; + m_inconsistent = s.m_inconsistent_old; + m_defined_names.pop(num_scopes); + 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_new_scopes", tout << "after pop " << num_scopes << "\n"; display(tout);); +} + +void asserted_formulas_new::reset() { + m_defined_names.reset(); + m_qhead = 0; + m_formulas.reset(); + m_macro_manager.reset(); + m_bv_sharing.reset(); + m_rewriter.reset(); + m_inconsistent = false; +} + +bool asserted_formulas_new::check_well_sorted() const { + for (justified_expr const& je : m_formulas) { + if (!is_well_sorted(m, je.get_fml())) return false; + } + return true; +} + +void asserted_formulas_new::reduce() { + if (inconsistent()) + return; + if (canceled()) + return; + if (m_qhead == m_formulas.size()) + return; + if (!m_params.m_preprocess) + return; + if (m_macro_manager.has_macros()) + expand_macros(); + + TRACE("before_reduce", display(tout);); + CASSERT("well_sorted", check_well_sorted()); + + set_eliminate_and(false); // do not eliminate and before nnf. + 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()); +} + + +unsigned asserted_formulas_new::get_formulas_last_level() const { + if (m_scopes.empty()) { + return 0; + } + else { + return m_scopes.back().m_formulas_lim; + } +} + +bool asserted_formulas_new::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_new::display(std::ostream & out) const { + out << "asserted formulas:\n"; + for (unsigned i = 0; i < m_formulas.size(); i++) { + if (i == m_qhead) + out << "[HEAD] ==>\n"; + out << mk_pp(m_formulas[i].get_fml(), m) << "\n"; + } + out << "inconsistent: " << inconsistent() << "\n"; +} + +void asserted_formulas_new::display_ll(std::ostream & out, ast_mark & pp_visited) const { + 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 (justified_expr const& f : m_formulas) + out << "#" << f.get_fml()->get_id() << " "; + out << "\n"; + } +} + +void asserted_formulas_new::collect_statistics(statistics & st) const { +} + + +void asserted_formulas_new::swap_asserted_formulas(vector<justified_expr>& formulas) { + SASSERT(!inconsistent() || !formulas.empty()); + m_formulas.shrink(m_qhead); + m_formulas.append(formulas); +} + +void asserted_formulas_new::find_macros_fn::operator()() { + TRACE("before_find_macros", af.display(tout);); + af.find_macros_core(); + TRACE("after_find_macros", af.display(tout);); +} + +void asserted_formulas_new::find_macros_core() { + vector<justified_expr> 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_new::expand_macros() { + IF_IVERBOSE(10, verbose_stream() << "(smt.expand-macros)\n";); + find_macros_core(); +} + +void asserted_formulas_new::apply_quasi_macros() { + TRACE("before_quasi_macros", display(tout);); + vector<justified_expr> 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_new::nnf_cnf() { + nnf apply_nnf(m, m_defined_names); + vector<justified_expr> new_fmls; + expr_ref_vector push_todo(m); + proof_ref_vector push_todo_prs(m); + + 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_formulas[i].get_fml(); + TRACE("nnf_bug", tout << "processing:\n" << mk_pp(n, m) << "\n";); + proof * pr = m_formulas[i].get_proof(); + expr_ref r1(m); + proof_ref pr1(m); + 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); + push_todo.push_back(r1); + push_todo_prs.push_back(pr); + + if (canceled()) { + return; + } + unsigned sz2 = push_todo.size(); + for (unsigned k = 0; k < sz2; k++) { + expr * n = push_todo.get(k); + 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); + push_assertion(r1, pr, new_fmls); + } + } + swap_asserted_formulas(new_fmls); +} + +void asserted_formulas_new::simplify_fmls::operator()() { + vector<justified_expr> 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(); +} + + +void asserted_formulas_new::reduce_and_solve() { + IF_IVERBOSE(10, verbose_stream() << "(smt.reducing)\n";); + flush_cache(); // collect garbage + m_reduce_asserted_formulas(); +} + + +void asserted_formulas_new::commit() { + commit(m_formulas.size()); +} + +void asserted_formulas_new::commit(unsigned new_qhead) { + 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()); + } + m_qhead = new_qhead; +} + +void asserted_formulas_new::propagate_values() { + TRACE("propagate_values", tout << "before:\n"; display(tout);); + flush_cache(); + + unsigned num_prop = 0; + while (true) { + m_expr2depth.reset(); + m_scoped_substitution.push(); + unsigned prop = num_prop; + TRACE("propagate_values", tout << "before:\n"; display(tout);); + IF_IVERBOSE(10, verbose_stream() << "(smt.propagate-values)\n";); + 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_new::propagate_values(unsigned i) { + expr * n = m_formulas[i].get_fml(); + 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); + } + m_formulas[i] = justified_expr(m, new_n, new_pr); + update_substitution(new_n, new_pr); + return n != new_n ? 1 : 0; +} + +void asserted_formulas_new::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)) { + m_scoped_substitution.insert(lhs, rhs, pr); + return; + } + if (is_gt(rhs, lhs)) { + m_scoped_substitution.insert(rhs, lhs, m.mk_symmetry(pr)); + return; + } + } + 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_new::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 asserted_formulas_new::compute_depth(expr* e) { + ptr_vector<expr> 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); + } +} + +proof * asserted_formulas_new::get_inconsistency_proof() const { + if (!inconsistent()) + return 0; + if (!m.proofs_enabled()) + return 0; + for (justified_expr const& j : m_formulas) { + if (m.is_false(j.get_fml())) + return j.get_proof(); + } + UNREACHABLE(); + return 0; +} + +void asserted_formulas_new::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(); + } +} + + +unsigned asserted_formulas_new::get_total_size() const { + expr_mark visited; + unsigned r = 0; + for (justified_expr const& j : m_formulas) + r += get_num_exprs(j.get_fml(), visited); + return r; +} + +#ifdef Z3DEBUG +void pp(asserted_formulas_new & f) { + f.display(std::cout); +} +#endif + diff --git a/src/smt/asserted_formulas_new.h b/src/smt/asserted_formulas_new.h new file mode 100644 index 000000000..dc51c86ae --- /dev/null +++ b/src/smt/asserted_formulas_new.h @@ -0,0 +1,269 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + asserted_formulas_new.h + +Abstract: + + <abstract> + +Author: + + Leonardo de Moura (leonardo) 2008-06-11. + +Revision History: + +--*/ +#ifndef ASSERTED_FORMULAS_NEW_H_ +#define ASSERTED_FORMULAS_NEW_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_elim2.h" +#include "ast/rewriter/der.h" +#include "ast/rewriter/elim_bounds2.h" +#include "ast/macros/macro_manager.h" +#include "ast/macros/macro_finder.h" +#include "ast/normal_forms/defined_names.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 asserted_formulas_new { + + 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<justified_expr> m_formulas; + unsigned m_qhead; + macro_manager m_macro_manager; + scoped_ptr<macro_finder> m_macro_finder; + maximize_bv_sharing_rw m_bv_sharing; + bool m_inconsistent; + bool m_has_quantifiers; + struct scope { + unsigned m_formulas_lim; + bool m_inconsistent_old; + }; + svector<scope> m_scopes; + obj_map<expr, unsigned> m_expr2depth; + + class simplify_fmls { + protected: + asserted_formulas_new& af; + ast_manager& m; + char const* m_id; + public: + simplify_fmls(asserted_formulas_new& 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_new& 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_new& af): simplify_fmls(af, "find-macros") {} + virtual void operator()(); + 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_new& 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_new& 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_new& 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_new& 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_new& 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_new& 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_new& 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_new& 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_new& 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<justified_expr>& new_fmls); + void push_assertion(expr * e, proof * pr, vector<justified_expr>& result); + bool canceled() { return m.canceled(); } + bool check_well_sorted() const; + unsigned get_total_size() const; + + void find_macros_core(); + void expand_macros(); + void apply_quasi_macros(); + void nnf_cnf(); + void reduce_and_solve(); + void flush_cache() { m_rewriter.reset(); } + void set_eliminate_and(bool flag); + void propagate_values(); + 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(); + +public: + asserted_formulas_new(ast_manager & m, smt_params & p); + ~asserted_formulas_new(); + + bool has_quantifiers() const { return m_has_quantifiers; } + void setup(); + void assert_expr(expr * e, proof * in_pr); + void assert_expr(expr * e); + void reset(); + void push_scope(); + void pop_scope(unsigned num_scopes); + bool inconsistent() const { return m_inconsistent; } + proof * get_inconsistency_proof() const; + void reduce(); + unsigned get_num_formulas() const { return m_formulas.size(); } + unsigned get_formulas_last_level() const; + 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<expr> & 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; + + // ----------------------------------- + // + // Macros + // + // ----------------------------------- + unsigned get_num_macros() const { return m_macro_manager.get_num_macros(); } + unsigned get_first_macro_last_level() const { return m_macro_manager.get_first_macro_last_level(); } + 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); } + // 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_NEW_H_ */ + From e3e965883f562de3ecd91ecfba6dd20c88437438 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 26 Aug 2017 01:55:03 -0700 Subject: [PATCH 25/74] mising files Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/smt/asserted_formulas_new.cpp | 28 +++++----------------------- src/smt/asserted_formulas_new.h | 2 +- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/src/smt/asserted_formulas_new.cpp b/src/smt/asserted_formulas_new.cpp index 51bba9f7f..14c8615a2 100644 --- a/src/smt/asserted_formulas_new.cpp +++ b/src/smt/asserted_formulas_new.cpp @@ -84,7 +84,6 @@ asserted_formulas_new::~asserted_formulas_new() { void asserted_formulas_new::push_assertion(expr * e, proof * pr, vector<justified_expr>& result) { if (inconsistent()) { - SASSERT(!result.empty()); return; } expr* e1 = 0; @@ -106,13 +105,8 @@ void asserted_formulas_new::push_assertion(expr * e, proof * pr, vector<justifie for (unsigned i = 0; i < to_app(e1)->get_num_args(); ++i) { expr* arg = to_app(e1)->get_arg(i), *e2; proof_ref _pr(m.mk_not_or_elim(pr, i), m); - if (m.is_not(arg, e2)) { - push_assertion(e2, _pr, result); - } - else { - expr_ref narg(m.mk_not(arg), m); - push_assertion(narg, _pr, result); - } + expr_ref narg(mk_not(m, arg), m); + push_assertion(narg, _pr, result); } } else { @@ -154,8 +148,7 @@ void asserted_formulas_new::assert_expr(expr * e, proof * _in_pr) { } void asserted_formulas_new::assert_expr(expr * e) { - if (!inconsistent()) - assert_expr(e, m.mk_asserted(e)); + assert_expr(e, m.mk_asserted(e)); } void asserted_formulas_new::get_assertions(ptr_vector<expr> & result) const { @@ -220,8 +213,8 @@ void asserted_formulas_new::reduce() { if (!m_params.m_preprocess) return; if (m_macro_manager.has_macros()) - expand_macros(); - + invoke(m_find_macros); + TRACE("before_reduce", display(tout);); CASSERT("well_sorted", check_well_sorted()); @@ -313,11 +306,6 @@ void asserted_formulas_new::swap_asserted_formulas(vector<justified_expr>& formu m_formulas.append(formulas); } -void asserted_formulas_new::find_macros_fn::operator()() { - TRACE("before_find_macros", af.display(tout);); - af.find_macros_core(); - TRACE("after_find_macros", af.display(tout);); -} void asserted_formulas_new::find_macros_core() { vector<justified_expr> new_fmls; @@ -327,12 +315,6 @@ void asserted_formulas_new::find_macros_core() { reduce_and_solve(); } - -void asserted_formulas_new::expand_macros() { - IF_IVERBOSE(10, verbose_stream() << "(smt.expand-macros)\n";); - find_macros_core(); -} - void asserted_formulas_new::apply_quasi_macros() { TRACE("before_quasi_macros", display(tout);); vector<justified_expr> new_fmls; diff --git a/src/smt/asserted_formulas_new.h b/src/smt/asserted_formulas_new.h index dc51c86ae..60af46dea 100644 --- a/src/smt/asserted_formulas_new.h +++ b/src/smt/asserted_formulas_new.h @@ -87,7 +87,7 @@ class asserted_formulas_new { class find_macros_fn : public simplify_fmls { public: find_macros_fn(asserted_formulas_new& af): simplify_fmls(af, "find-macros") {} - virtual void operator()(); + 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(); } }; From ce3ab6b170151953dde32f3b6f365754f3feb662 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 26 Aug 2017 02:04:59 -0700 Subject: [PATCH 26/74] mising files Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/ast.h | 12 ++++++------ src/smt/asserted_formulas_new.cpp | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ast/ast.h b/src/ast/ast.h index 408ca4063..34ea96653 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -2474,15 +2474,15 @@ 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) { +public: + justified_expr(ast_manager& m, expr* fml, proof* p): + m(m), + m_fml(fml), + m_proof(p) { m.inc_ref(fml); m.inc_ref(p); } - + justified_expr& operator=(justified_expr& other) { SASSERT(&m == &other.m); if (this != &other) { diff --git a/src/smt/asserted_formulas_new.cpp b/src/smt/asserted_formulas_new.cpp index 14c8615a2..39c432b61 100644 --- a/src/smt/asserted_formulas_new.cpp +++ b/src/smt/asserted_formulas_new.cpp @@ -467,7 +467,8 @@ unsigned asserted_formulas_new::propagate_values(unsigned i) { proof * pr = m_formulas[i].get_proof(); new_pr = m.mk_modus_ponens(pr, new_pr); } - m_formulas[i] = justified_expr(m, new_n, new_pr); + justified_expr j(m, new_n, new_pr); + m_formulas[i] = j; update_substitution(new_n, new_pr); return n != new_n ? 1 : 0; } From 2955b0c2efe27ef220e51749647fe9f7e5653836 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 26 Aug 2017 03:05:34 -0700 Subject: [PATCH 27/74] removing more dependencies Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/muz/base/dl_rule.cpp | 3 +- src/muz/spacer/spacer_qe_project.cpp | 1 + src/qe/CMakeLists.txt | 2 - src/qe/nlarith_util.cpp | 11 +- src/qe/qe.cpp | 22 +++- src/qe/qe.h | 34 ++--- src/qe/qe_cmd.cpp | 3 +- src/qe/vsubst_tactic.cpp | 169 ------------------------- src/qe/vsubst_tactic.h | 33 ----- src/smt/CMakeLists.txt | 2 +- src/smt/arith_eq_adapter.cpp | 1 - src/smt/params/CMakeLists.txt | 1 - src/smt/params/preprocessor_params.cpp | 1 - src/smt/params/preprocessor_params.h | 6 +- src/tactic/bv/elim_small_bv_tactic.cpp | 14 +- 15 files changed, 38 insertions(+), 265 deletions(-) delete mode 100644 src/qe/vsubst_tactic.cpp delete mode 100644 src/qe/vsubst_tactic.h 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/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/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/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, ast_manager> expr_ref_vector_hash; typedef ref_vector_ptr_eq<expr, ast_manager> expr_ref_vector_eq; typedef hashtable<expr_ref_vector*, expr_ref_vector_hash, expr_ref_vector_eq> 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<simplify_rewriter_cfg> { @@ -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/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<app>& m_vars; - public: - get_var_proc(ast_manager & m, ptr_vector<app>& 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<app>& 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<expr> 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<app> 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<bool> fl1(params.m_nlquant_elim, true); - flet<bool> 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/CMakeLists.txt b/src/smt/CMakeLists.txt index b117db89b..5c4c6b0b9 100644 --- a/src/smt/CMakeLists.txt +++ b/src/smt/CMakeLists.txt @@ -2,7 +2,7 @@ z3_add_component(smt SOURCES arith_eq_adapter.cpp arith_eq_solver.cpp - asserted_formulas.cpp +## asserted_formulas.cpp asserted_formulas_new.cpp cached_var_subst.cpp cost_evaluator.cpp 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/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 0b621870d..afca0196a 100644 --- a/src/smt/params/preprocessor_params.cpp +++ b/src/smt/params/preprocessor_params.cpp @@ -48,7 +48,6 @@ void preprocessor_params::display(std::ostream & out) const { 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 fe759417d..6f763c0e1 100644 --- a/src/smt/params/preprocessor_params.h +++ b/src/smt/params/preprocessor_params.h @@ -31,15 +31,14 @@ enum lift_ite_kind { }; struct preprocessor_params : public pattern_inference_params, - public bit_blaster_params, - public bv_simplifier_params, + public bit_blaster_params, + public bv_simplifier_params, public arith_simplifier_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 +61,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/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<filter_model_converter> 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 { From 0d5cfe9292d9d9b60a6567c48bb48d5a2aa246a9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 26 Aug 2017 09:23:15 -0700 Subject: [PATCH 28/74] separate out, add copy constructor Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/ast.h | 35 ----------------------- src/ast/justified_expr.h | 52 ++++++++++++++++++++++++++++++++++ src/ast/macros/macro_manager.h | 1 + src/ast/macros/quasi_macros.h | 1 + src/smt/elim_term_ite.h | 2 ++ 5 files changed, 56 insertions(+), 35 deletions(-) create mode 100644 src/ast/justified_expr.h diff --git a/src/ast/ast.h b/src/ast/ast.h index 34ea96653..699268bd0 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -2470,41 +2470,6 @@ public: void operator()(AST * n) { m_manager.inc_ref(n); } }; -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) { - m.inc_ref(fml); - m.inc_ref(p); - } - - justified_expr& operator=(justified_expr& other) { - SASSERT(&m == &other.m); - if (this != &other) { - m.dec_ref(m_fml); - m.dec_ref(m_proof); - m_fml = other.get_fml(); - m_proof = other.get_proof(); - m.inc_ref(m_fml); - m.inc_ref(m_proof); - } - return *this; - } - - ~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 /* AST_H_ */ diff --git a/src/ast/justified_expr.h b/src/ast/justified_expr.h new file mode 100644 index 000000000..49362940d --- /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.dec_ref(m_fml); + m.dec_ref(m_proof); + m_fml = other.get_fml(); + m_proof = other.get_proof(); + m.inc_ref(m_fml); + m.inc_ref(m_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/macro_manager.h b/src/ast/macros/macro_manager.h index 46dfa059d..0205fb891 100644 --- a/src/ast/macros/macro_manager.h +++ b/src/ast/macros/macro_manager.h @@ -21,6 +21,7 @@ Revision History: #include "util/obj_hashtable.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" diff --git a/src/ast/macros/quasi_macros.h b/src/ast/macros/quasi_macros.h index fc7287554..1b1483a90 100644 --- a/src/ast/macros/quasi_macros.h +++ b/src/ast/macros/quasi_macros.h @@ -20,6 +20,7 @@ Revision History: #define QUASI_MACROS_H_ #include<sstream> +#include "ast/justified_expr.h" #include "ast/macros/macro_manager.h" #include "ast/rewriter/th_rewriter.h" diff --git a/src/smt/elim_term_ite.h b/src/smt/elim_term_ite.h index 86b9a79e2..a57ea1dad 100644 --- a/src/smt/elim_term_ite.h +++ b/src/smt/elim_term_ite.h @@ -22,6 +22,8 @@ Revision History: #include "ast/normal_forms/defined_names.h" #include "ast/rewriter/rewriter.h" #include "ast/simplifier/simplifier.h" +#include "ast/justified_expr.h" + class elim_term_ite : public simplifier { defined_names & m_defined_names; From 82a937d1af25f9466556670684ac9283023ef586 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 26 Aug 2017 10:41:25 -0700 Subject: [PATCH 29/74] enforce arithmetic normalization Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/api/api_context.cpp | 3 ++- src/ast/ast_smt2_pp.cpp | 8 ++++---- src/ast/rewriter/arith_rewriter.cpp | 2 +- src/ast/rewriter/poly_rewriter_def.h | 17 +++++++++++++---- src/smt/asserted_formulas_new.cpp | 9 +++++++-- 5 files changed, 27 insertions(+), 12 deletions(-) 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/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 5c3eb93c2..51ccc1e7d 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -1222,15 +1222,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/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 18556b71b..4b00cde45 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -371,7 +371,7 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin (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";); + TRACE("mk_le_bug", tout << "st: " << st << " " << new_arg1 << " " << new_arg2 << "\n";); if (st != BR_FAILED) { arg1 = new_arg1; arg2 = new_arg2; diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index 731a0538a..2a6bd2c50 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -704,8 +704,10 @@ br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool m } } - if (move && num_coeffs == 0 && is_numeral(rhs)) + if (move && num_coeffs == 0 && is_numeral(rhs)) { + TRACE("mk_le_bug", tout << "no coeffs\n";); return BR_FAILED; + } for (unsigned i = 0; i < rhs_sz; i++) { expr * arg = rhs_monomials[i]; @@ -723,15 +725,21 @@ br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool m } normalize(c); - + + TRACE("mk_le_bug", tout << c << "\n";); + if (!has_multiple && num_coeffs <= 1) { if (move) { - if (is_numeral(rhs)) + if (is_numeral(rhs)) { + TRACE("mk_le_bug", tout << "rhs is numeral\n";); return BR_FAILED; + } } else { - if (num_coeffs == 0 || is_numeral(rhs)) + if (num_coeffs == 0 || is_numeral(rhs)) { + TRACE("mk_le_bug", tout << "rhs is numeral or no coeffs\n";); return BR_FAILED; + } } } @@ -847,6 +855,7 @@ br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool m new_lhs_monomials[0] = insert_c_lhs ? mk_numeral(c) : NULL; lhs_result = mk_add_app(new_lhs_monomials.size() - lhs_offset, new_lhs_monomials.c_ptr() + lhs_offset); rhs_result = mk_add_app(new_rhs_monomials.size() - rhs_offset, new_rhs_monomials.c_ptr() + rhs_offset); + TRACE("mk_le_bug", tout << lhs_result << " " << rhs_result << "\n";); return BR_DONE; } diff --git a/src/smt/asserted_formulas_new.cpp b/src/smt/asserted_formulas_new.cpp index 39c432b61..5d4783bf8 100644 --- a/src/smt/asserted_formulas_new.cpp +++ b/src/smt/asserted_formulas_new.cpp @@ -59,6 +59,11 @@ asserted_formulas_new::asserted_formulas_new(ast_manager & m, smt_params & p): m_apply_quasi_macros(*this) { m_macro_finder = alloc(macro_finder, m, m_macro_manager); + + params_ref pa; + pa.set_bool("arith_lhs", true); + m_rewriter.updt_params(pa); + } void asserted_formulas_new::setup() { @@ -103,7 +108,7 @@ void asserted_formulas_new::push_assertion(expr * e, proof * pr, vector<justifie } 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), *e2; + 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); @@ -117,6 +122,7 @@ void asserted_formulas_new::push_assertion(expr * e, proof * pr, vector<justifie void asserted_formulas_new::set_eliminate_and(bool flag) { params_ref p; p.set_bool("elim_and", true); + p.set_bool("arith_lhs", true); m_rewriter.updt_params(p); flush_cache(); } @@ -430,7 +436,6 @@ void asserted_formulas_new::propagate_values() { m_scoped_substitution.push(); unsigned prop = num_prop; TRACE("propagate_values", tout << "before:\n"; display(tout);); - IF_IVERBOSE(10, verbose_stream() << "(smt.propagate-values)\n";); unsigned i = m_qhead; unsigned sz = m_formulas.size(); for (; i < sz; i++) { From bcf229dcfdad8002f73a3a8351609fa9c18c2884 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 26 Aug 2017 11:23:41 -0700 Subject: [PATCH 30/74] removing dependencies on simplifier Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/rewriter/CMakeLists.txt | 4 +- .../rewriter/{bv_elim2.cpp => bv_elim.cpp} | 2 +- src/ast/rewriter/{bv_elim2.h => bv_elim.h} | 4 +- src/ast/rewriter/elim_bounds2.cpp | 203 ---- src/ast/rewriter/elim_bounds2.h | 77 -- src/ast/simplifier/CMakeLists.txt | 32 +- src/smt/CMakeLists.txt | 1 - src/smt/asserted_formulas.cpp | 879 ------------------ src/smt/asserted_formulas.h | 151 --- src/smt/asserted_formulas_new.cpp | 8 +- src/smt/asserted_formulas_new.h | 6 +- src/smt/elim_term_ite.cpp | 138 --- src/smt/elim_term_ite.h | 27 - src/smt/expr_context_simplifier.h | 4 +- src/smt/params/CMakeLists.txt | 1 + src/smt/smt_consequences.cpp | 9 +- src/smt/smt_quantifier.cpp | 3 +- src/smt/theory_array.cpp | 1 + src/smt/theory_lra.cpp | 1 + src/smt/theory_seq.cpp | 3 +- src/smt/theory_str.h | 7 +- src/test/CMakeLists.txt | 1 - src/test/bv_simplifier_plugin.cpp | 326 ------- src/test/main.cpp | 1 - src/test/quant_elim.cpp | 6 - src/test/sorting_network.cpp | 6 +- 26 files changed, 52 insertions(+), 1849 deletions(-) rename src/ast/rewriter/{bv_elim2.cpp => bv_elim.cpp} (99%) rename src/ast/rewriter/{bv_elim2.h => bv_elim.h} (96%) delete mode 100644 src/ast/rewriter/elim_bounds2.cpp delete mode 100644 src/ast/rewriter/elim_bounds2.h delete mode 100644 src/smt/asserted_formulas.cpp delete mode 100644 src/smt/asserted_formulas.h delete mode 100644 src/test/bv_simplifier_plugin.cpp diff --git a/src/ast/rewriter/CMakeLists.txt b/src/ast/rewriter/CMakeLists.txt index 804fbcbed..57924b48a 100644 --- a/src/ast/rewriter/CMakeLists.txt +++ b/src/ast/rewriter/CMakeLists.txt @@ -6,13 +6,13 @@ z3_add_component(rewriter bit2int.cpp bool_rewriter.cpp bv_bounds.cpp - bv_elim2.cpp + bv_elim.cpp bv_rewriter.cpp datatype_rewriter.cpp der.cpp distribute_forall.cpp dl_rewriter.cpp - elim_bounds2.cpp + elim_bounds.cpp enum2bv_rewriter.cpp expr_replacer.cpp expr_safe_replace.cpp diff --git a/src/ast/rewriter/bv_elim2.cpp b/src/ast/rewriter/bv_elim.cpp similarity index 99% rename from src/ast/rewriter/bv_elim2.cpp rename to src/ast/rewriter/bv_elim.cpp index 5b542e59e..270d7deb8 100644 --- a/src/ast/rewriter/bv_elim2.cpp +++ b/src/ast/rewriter/bv_elim.cpp @@ -4,7 +4,7 @@ Copyright (c) 2015 Microsoft Corporation --*/ -#include "ast/rewriter/bv_elim2.h" +#include "ast/rewriter/bv_elim.h" #include "ast/bv_decl_plugin.h" #include "ast/rewriter/var_subst.h" #include "ast/rewriter/rewriter_def.h" diff --git a/src/ast/rewriter/bv_elim2.h b/src/ast/rewriter/bv_elim.h similarity index 96% rename from src/ast/rewriter/bv_elim2.h rename to src/ast/rewriter/bv_elim.h index a4829b207..6468cb8b9 100644 --- a/src/ast/rewriter/bv_elim2.h +++ b/src/ast/rewriter/bv_elim.h @@ -17,8 +17,8 @@ Author: Revision History: --*/ -#ifndef BV_ELIM2_H_ -#define BV_ELIM2_H_ +#ifndef BV_ELIM_H_ +#define BV_ELIM_H_ #include "ast/ast.h" #include "ast/rewriter/rewriter.h" diff --git a/src/ast/rewriter/elim_bounds2.cpp b/src/ast/rewriter/elim_bounds2.cpp deleted file mode 100644 index 9691ade09..000000000 --- a/src/ast/rewriter/elim_bounds2.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - elim_bounds2.cpp - -Abstract: - - <abstract> - -Author: - - Leonardo de Moura (leonardo) 2008-06-28. - -Revision History: - ---*/ - -#ifndef ELIM_BOUNDS_H_ -#define ELIM_BOUNDS_H_ - -#include "ast/used_vars.h" -#include "util/obj_hashtable.h" -#include "ast/rewriter/var_subst.h" -#include "ast/rewriter/elim_bounds2.h" -#include "ast/ast_pp.h" - -elim_bounds_cfg::elim_bounds_cfg(ast_manager & m): - m(m), - m_util(m) { -} - -/** - \brief Find bounds of the form - - (<= x k) - (<= (+ x (* -1 y)) k) - (<= (+ x (* -1 t)) k) - (<= (+ t (* -1 x)) k) - - x and y are a bound variables, t is a ground term and k is a numeral - - It also detects >=, and the atom can be negated. -*/ -bool elim_bounds_cfg::is_bound(expr * n, var * & lower, var * & upper) { - upper = 0; - lower = 0; - bool neg = false; - if (m.is_not(n)) { - n = to_app(n)->get_arg(0); - neg = true; - } - - expr* l = 0, *r = 0; - bool le = false; - if (m_util.is_le(n, l, r) && m_util.is_numeral(r)) { - n = l; - le = true; - } - else if (m_util.is_ge(n, l, r) && m_util.is_numeral(r)) { - n = l; - le = false; - } - else { - return false; - } - - if (neg) - le = !le; - - if (is_var(n)) { - upper = to_var(n); - } - else if (m_util.is_add(n, l, r)) { - expr * arg1 = l; - expr * arg2 = r; - if (is_var(arg1)) - upper = to_var(arg1); - else if (!is_ground(arg1)) - return false; - rational k; - bool is_int; - if (m_util.is_mul(arg2) && m_util.is_numeral(to_app(arg2)->get_arg(0), k, is_int) && k.is_minus_one()) { - arg2 = to_app(arg2)->get_arg(1); - if (is_var(arg2)) - lower = to_var(arg2); - else if (!is_ground(arg2)) - return false; // not supported - } - else { - return false; // not supported - } - } - else { - return false; - } - - if (!le) - std::swap(upper, lower); - - return true; -} - -bool elim_bounds_cfg::is_bound(expr * n) { - var * lower, * upper; - return is_bound(n, lower, upper); -} - - -bool elim_bounds_cfg::reduce_quantifier(quantifier * q, - expr * n, - expr * const * new_patterns, - expr * const * new_no_patterns, - expr_ref & result, - proof_ref & result_pr) { - if (!q->is_forall()) { - return false; - } - unsigned num_vars = q->get_num_decls(); - ptr_buffer<expr> atoms; - if (m.is_or(n)) - atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args()); - else - atoms.push_back(n); - used_vars used_vars; - // collect non-candidates - for (expr * a : atoms) { - if (!is_bound(a)) - used_vars.process(a); - } - if (used_vars.uses_all_vars(q->get_num_decls())) { - return false; - } - // collect candidates - obj_hashtable<var> lowers; - obj_hashtable<var> uppers; - obj_hashtable<var> candidate_set; - ptr_buffer<var> candidates; -#define ADD_CANDIDATE(V) if (!lowers.contains(V) && !uppers.contains(V)) { candidate_set.insert(V); candidates.push_back(V); } - for (expr * a : atoms) { - var * lower = 0; - var * upper = 0; - if (is_bound(a, lower, upper)) { - if (lower != 0 && !used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) { - ADD_CANDIDATE(lower); - lowers.insert(lower); - } - if (upper != 0 && !used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) { - ADD_CANDIDATE(upper); - uppers.insert(upper); - } - } - } - TRACE("elim_bounds", tout << "candidates:\n"; for (unsigned i = 0; i < candidates.size(); i++) tout << mk_pp(candidates[i], m) << "\n";); - // remove candidates that have lower and upper bounds - - for (var * v : candidates) { - if (lowers.contains(v) && uppers.contains(v)) - candidate_set.erase(v); - } - TRACE("elim_bounds", tout << "candidates after filter:\n"; for (unsigned i = 0; i < candidates.size(); i++) tout << mk_pp(candidates[i], m) << "\n";); - if (candidate_set.empty()) { - return false; - } - // remove bounds that contain variables in candidate_set - unsigned j = 0; - for (unsigned i = 0; i < atoms.size(); ++i) { - expr * a = atoms[i]; - var * lower = 0; - var * upper = 0; - if (is_bound(a, lower, upper) && ((lower != 0 && candidate_set.contains(lower)) || (upper != 0 && candidate_set.contains(upper)))) - continue; - atoms[j] = a; - j++; - } - if (j == atoms.size()) { - return false; - } - atoms.resize(j); - expr * new_body = 0; - switch (atoms.size()) { - case 0: - result = m.mk_false(); - result_pr = m.mk_rewrite(q, result); - TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";); - return true; - case 1: - new_body = atoms[0]; - break; - default: - new_body = m.mk_or(atoms.size(), atoms.c_ptr()); - break; - } - quantifier_ref new_q(m); - new_q = m.update_quantifier(q, new_body); - elim_unused_vars(m, new_q, params_ref(), result); - result_pr = m.mk_rewrite(q, result); - TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";); - return true; -} - -#endif /* ELIM_BOUNDS_H_ */ diff --git a/src/ast/rewriter/elim_bounds2.h b/src/ast/rewriter/elim_bounds2.h deleted file mode 100644 index e0bba4e60..000000000 --- a/src/ast/rewriter/elim_bounds2.h +++ /dev/null @@ -1,77 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - elim_bounds2.h - -Abstract: - - <abstract> - -Author: - - Leonardo de Moura (leonardo) 2008-06-28. - -Revision History: - ---*/ -#ifndef ELIM_BOUNDS2_H_ -#define ELIM_BOUNDS2_H_ - -#include "ast/ast.h" -#include "ast/arith_decl_plugin.h" -#include "ast/rewriter/rewriter.h" - -/** - \brief Functor for eliminating irrelevant bounds in quantified formulas. - - Example: - (forall (x Int) (y Int) (or (not (>= y x) (not (>= x 0)) (= (select a x) 1)))) - - The bound (>= y x) is irrelevant and can be eliminated. - - This can be easily proved by using Fourier-Motzkin elimination. - - Limitations & Assumptions: - - It assumes the input formula was already simplified. - - It can only handle bounds in the diff-logic fragment. - - \remark This operation is subsumed by Fourier-Motzkin elimination. -*/ -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_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_bounds2 in all - universal quantifiers in an expression. - - Assumption: the formula was already skolemized. -*/ -class elim_bounds_rw : public rewriter_tpl<elim_bounds_cfg> { -protected: - elim_bounds_cfg m_cfg; -public: - elim_bounds_rw(ast_manager & m): - rewriter_tpl<elim_bounds_cfg>(m, m.proofs_enabled(), m_cfg), - m_cfg(m) - {} - - virtual ~elim_bounds_rw() {} -}; - -#endif /* ELIM_BOUNDS2_H_ */ - diff --git a/src/ast/simplifier/CMakeLists.txt b/src/ast/simplifier/CMakeLists.txt index 52a44595e..649c0486e 100644 --- a/src/ast/simplifier/CMakeLists.txt +++ b/src/ast/simplifier/CMakeLists.txt @@ -1,21 +1,21 @@ 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 - bv_elim.cpp - bv_simplifier_params.cpp - bv_simplifier_plugin.cpp - datatype_simplifier_plugin.cpp - elim_bounds.cpp - fpa_simplifier_plugin.cpp - maximise_ac_sharing.cpp - poly_simplifier_plugin.cpp - seq_simplifier_plugin.cpp - simplifier.cpp - simplifier_plugin.cpp + arith_simplifier_params.cpp +# arith_simplifier_plugin.cpp + array_simplifier_params.cpp +# array_simplifier_plugin.cpp +# basic_simplifier_plugin.cpp +# bv_elim.cpp + bv_simplifier_params.cpp +# bv_simplifier_plugin.cpp +# datatype_simplifier_plugin.cpp +# elim_bounds.cpp +# fpa_simplifier_plugin.cpp +# maximise_ac_sharing.cpp +# poly_simplifier_plugin.cpp +# seq_simplifier_plugin.cpp +# simplifier.cpp +# simplifier_plugin.cpp COMPONENT_DEPENDENCIES rewriter PYG_FILES diff --git a/src/smt/CMakeLists.txt b/src/smt/CMakeLists.txt index 5c4c6b0b9..385d1aaa0 100644 --- a/src/smt/CMakeLists.txt +++ b/src/smt/CMakeLists.txt @@ -2,7 +2,6 @@ z3_add_component(smt SOURCES arith_eq_adapter.cpp arith_eq_solver.cpp -## asserted_formulas.cpp asserted_formulas_new.cpp cached_var_subst.cpp cost_evaluator.cpp diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp deleted file mode 100644 index 44ccd0bf6..000000000 --- a/src/smt/asserted_formulas.cpp +++ /dev/null @@ -1,879 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - asserted_formulas.cpp - -Abstract: - - <abstract> - -Author: - - Leonardo de Moura (leonardo) 2008-06-11. - -Revision History: - ---*/ -#include "util/warning.h" -#include "ast/ast_ll_pp.h" -#include "ast/ast_pp.h" -#include "ast/for_each_expr.h" -#include "ast/well_sorted.h" -#include "ast/rewriter/rewriter_def.h" -#include "ast/rewriter/pull_ite_tree.h" -#include "ast/rewriter/push_app_ite.h" -#include "ast/rewriter/inj_axiom.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/bv_elim.h" -#include "ast/simplifier/elim_bounds.h" -#include "ast/normal_forms/pull_quant.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_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_bit2int(m), - m_bv_sharing(m), - m_inconsistent(false), - m_has_quantifiers(false) { - - 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_pre_simplifier.enable_presimp(); -} - -void asserted_formulas::setup() { - switch (m_params.m_lift_ite) { - case LI_FULL: - m_params.m_ng_lift_ite = LI_NONE; - break; - case LI_CONSERVATIVE: - if (m_params.m_ng_lift_ite == LI_CONSERVATIVE) - m_params.m_ng_lift_ite = LI_NONE; - break; - 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) { - if (inconsistent()) { - SASSERT(!result.empty()); - return; - } - if (m.is_false(e)) - m_inconsistent = true; - ::push_assertion(m, e, pr, result, result_prs); -} - -void asserted_formulas::set_eliminate_and(bool flag) { - if (m_bsimp->eliminate_and() == flag) - return; - TRACE("eliminate_and", tout << "flushing cache...\n";); - flush_cache(); - m_bsimp->set_eliminate_and(flag); -} - - -void asserted_formulas::assert_expr(expr * e, proof * _in_pr) { - if (inconsistent()) - return; - m_has_quantifiers |= ::has_quantifiers(e); - if (!m_params.m_preprocess) { - push_assertion(e, _in_pr, m_asserted_formulas, m_asserted_formula_prs); - return; - } - 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); - 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<expr> & result) { - result.append(m_asserted_formulas.size(), m_asserted_formulas.c_ptr()); -} - -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);); - 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; - m_defined_names.push(); - m_bv_sharing.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); - m_macro_manager.pop_scope(num_scopes); - unsigned new_lvl = m_scopes.size() - 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_scopes.shrink(new_lvl); - flush_cache(); - TRACE("asserted_formulas_scopes", tout << "after pop " << num_scopes << "\n"; display(tout);); -} - -void asserted_formulas::reset() { - m_defined_names.reset(); - m_asserted_qhead = 0; - m_asserted_formulas.reset(); - m_asserted_formula_prs.reset(); - m_macro_manager.reset(); - m_bv_sharing.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; - } - return true; -} -#endif - -void asserted_formulas::reduce() { - if (inconsistent()) - return; - if (canceled()) { - return; - } - if (m_asserted_qhead == m_asserted_formulas.size()) - return; - if (!m_params.m_preprocess) - return; - - if (m_macro_manager.has_macros()) - expand_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*/ true, 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_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(); -} - -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; - } -} - -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); - } -} - -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) - out << "[HEAD] ==>\n"; - out << mk_pp(m_asserted_formulas.get(i), 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); - out << "asserted formulas:\n"; - for (unsigned i = 0; i < sz; i++) - out << "#" << m_asserted_formulas[i]->get_id() << " "; - out << "\n"; - } -} - -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(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); - 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); - expr_dependency_ref_vector new_deps(m); - quasi_macros proc(m, m_macro_manager); - 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(); - new_deps.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); - expr_ref_vector push_todo(m); - proof_ref_vector push_todo_prs(m); - - unsigned i = m_asserted_qhead; - unsigned sz = m_asserted_formulas.size(); - TRACE("nnf_bug", tout << "i: " << i << " sz: " << sz << "\n";); - for (; i < sz; i++) { - expr * n = m_asserted_formulas.get(i); - TRACE("nnf_bug", tout << "processing:\n" << mk_pp(n, m) << "\n";); - proof * pr = m_asserted_formula_prs.get(i, 0); - expr_ref r1(m); - proof_ref pr1(m); - CASSERT("well_sorted",is_well_sorted(m, n)); - push_todo.reset(); - push_todo_prs.reset(); - 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); - push_todo.push_back(r1); - push_todo_prs.push_back(pr); - - if (canceled()) { - return; - } - 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); - 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); - } - } - swap_asserted_formulas(new_exprs, new_prs); -} - -#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);); \ -} - -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(); -} - -void asserted_formulas::infer_patterns() { - IF_IVERBOSE(10, verbose_stream() << "(smt.pattern-inference)\n";); - TRACE("before_pattern_inference", display(tout);); - pattern_inference_rw 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()); -} - -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); - } - } - swap_asserted_formulas(new_exprs, new_prs); - TRACE("after_elim_term_ite", display(tout);); - reduce_and_solve(); - TRACE("after_elim_term_ite", display(tout);); -} - -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); - } - 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); - } - 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; - continue; - } - } - if (i >= m_asserted_qhead) { - new_exprs2.push_back(n); - if (m.proofs_enabled()) - new_prs2.push_back(pr); - } - } - TRACE("propagate_values", tout << "found: " << found << "\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); - 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_rw functor(m), "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); - } - 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); - } - } - } - 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_rw functor(m, m_params.m_lift_ite == LI_CONSERVATIVE), "lifting ite"); -LIFT_ITE(ng_lift_ite, ng_push_app_ite_rw functor(m, 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); - 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 deleted file mode 100644 index 1e15e6300..000000000 --- a/src/smt/asserted_formulas.h +++ /dev/null @@ -1,151 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - asserted_formulas.h - -Abstract: - - <abstract> - -Author: - - Leonardo de Moura (leonardo) 2008-06-11. - -Revision History: - ---*/ -#ifndef ASSERTED_FORMULAS_H_ -#define ASSERTED_FORMULAS_H_ - -#include "util/statistics.h" -#include "ast/static_features.h" -#include "ast/simplifier/simplifier.h" -#include "ast/simplifier/basic_simplifier_plugin.h" -#include "ast/simplifier/maximise_ac_sharing.h" -#include "ast/rewriter/bit2int.h" -#include "ast/macros/macro_manager.h" -#include "ast/macros/macro_finder.h" -#include "ast/normal_forms/defined_names.h" -#include "ast/pattern/pattern_inference.h" -#include "smt/params/smt_params.h" -#include "ast/rewriter/th_rewriter.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; - th_rewriter m_rewriter; - 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; - - macro_manager m_macro_manager; - scoped_ptr<macro_finder> m_macro_finder; - - bit2int m_bit2int; - - maximise_bv_sharing m_bv_sharing; - - bool m_inconsistent; - bool m_has_quantifiers; - - struct scope { - unsigned m_asserted_formulas_lim; - bool m_inconsistent_old; - }; - svector<scope> m_scopes; - - 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 set_eliminate_and(bool flag); - void propagate_values(); - void propagate_booleans(); - 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(); } - -public: - asserted_formulas(ast_manager & m, smt_params & p); - ~asserted_formulas(); - - void setup(); - void assert_expr(expr * e, proof * in_pr); - void assert_expr(expr * e); - void reset(); - void push_scope(); - void pop_scope(unsigned num_scopes); - 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_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 init(unsigned num_formulas, expr * const * formulas, proof * const * prs); - void register_simplifier_plugin(simplifier_plugin * p) { m_simplifier.register_plugin(p); } - // simplifier & get_simplifier() { return m_simplifier; } - th_rewriter& get_rewriter() { return m_rewriter; } - void get_assertions(ptr_vector<expr> & result); - bool empty() const { return m_asserted_formulas.empty(); } - void collect_static_features(); - 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_has_quantifiers; } - - // ----------------------------------- - // - // Macros - // - // ----------------------------------- - unsigned get_num_macros() const { return m_macro_manager.get_num_macros(); } - unsigned get_first_macro_last_level() const { return m_macro_manager.get_first_macro_last_level(); } - 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); } -}; - -#endif /* ASSERTED_FORMULAS_H_ */ - diff --git a/src/smt/asserted_formulas_new.cpp b/src/smt/asserted_formulas_new.cpp index 5d4783bf8..8d16ef2cd 100644 --- a/src/smt/asserted_formulas_new.cpp +++ b/src/smt/asserted_formulas_new.cpp @@ -431,7 +431,7 @@ void asserted_formulas_new::propagate_values() { flush_cache(); unsigned num_prop = 0; - while (true) { + while (!inconsistent()) { m_expr2depth.reset(); m_scoped_substitution.push(); unsigned prop = num_prop; @@ -474,6 +474,9 @@ unsigned asserted_formulas_new::propagate_values(unsigned i) { } justified_expr j(m, new_n, new_pr); m_formulas[i] = j; + if (m.is_false(j.get_fml())) { + m_inconsistent = true; + } update_substitution(new_n, new_pr); return n != new_n ? 1 : 0; } @@ -484,13 +487,16 @@ void asserted_formulas_new::update_substitution(expr* n, proof* pr) { 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)); diff --git a/src/smt/asserted_formulas_new.h b/src/smt/asserted_formulas_new.h index 60af46dea..82f18250d 100644 --- a/src/smt/asserted_formulas_new.h +++ b/src/smt/asserted_formulas_new.h @@ -29,9 +29,9 @@ Revision History: #include "ast/rewriter/pull_ite_tree.h" #include "ast/rewriter/push_app_ite.h" #include "ast/rewriter/inj_axiom.h" -#include "ast/rewriter/bv_elim2.h" +#include "ast/rewriter/bv_elim.h" #include "ast/rewriter/der.h" -#include "ast/rewriter/elim_bounds2.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" @@ -210,7 +210,7 @@ class asserted_formulas_new { void apply_quasi_macros(); void nnf_cnf(); void reduce_and_solve(); - void flush_cache() { m_rewriter.reset(); } + void flush_cache() { m_rewriter.reset(); m_rewriter.set_substitution(&m_substitution); } void set_eliminate_and(bool flag); void propagate_values(); unsigned propagate_values(unsigned i); diff --git a/src/smt/elim_term_ite.cpp b/src/smt/elim_term_ite.cpp index d9cfac775..e8b70fc59 100644 --- a/src/smt/elim_term_ite.cpp +++ b/src/smt/elim_term_ite.cpp @@ -19,144 +19,6 @@ 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; - } - m_coarse_proofs.reset(); -} - -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); -} - - 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; diff --git a/src/smt/elim_term_ite.h b/src/smt/elim_term_ite.h index a57ea1dad..8e8340dc0 100644 --- a/src/smt/elim_term_ite.h +++ b/src/smt/elim_term_ite.h @@ -21,35 +21,8 @@ Revision History: #include "ast/normal_forms/defined_names.h" #include "ast/rewriter/rewriter.h" -#include "ast/simplifier/simplifier.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); -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); - } - 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) - ); -}; - - class elim_term_ite_cfg : public default_rewriter_cfg { ast_manager& m; defined_names & m_defined_names; 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<expr, bool> 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 c965f0a62..500423dcc 100644 --- a/src/smt/params/CMakeLists.txt +++ b/src/smt/params/CMakeLists.txt @@ -13,6 +13,7 @@ z3_add_component(smt_params ast bit_blaster pattern + simplifier PYG_FILES smt_params_helper.pyg ) 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_quantifier.cpp b/src/smt/smt_quantifier.cpp index 6a2f848d9..22004ee78 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 { 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_lra.cpp b/src/smt/theory_lra.cpp index 124fea910..0c09d0403 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_seq.cpp b/src/smt/theory_seq.cpp index c91882dad..8d6d70a79 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -19,11 +19,12 @@ Revision History: --*/ #include <typeinfo> +#include "ast/ast_pp.h" +#include "ast/ast_trail.h" #include "smt/proto_model/value_factory.h" #include "smt/smt_context.h" #include "smt/smt_model_generator.h" #include "smt/theory_seq.h" -#include "ast/ast_trail.h" #include "smt/theory_arith.h" #include "smt/smt_kernel.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<set> #include<stack> #include<vector> 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<unsigned char>(r.get_unsigned()); - } - int i32(expr* e) { - return static_cast<int>(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<uint64>(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<int>(a); - int sb = static_cast<int>(b); - uint64 a64 = static_cast<uint64>(a); - uint64 b64 = static_cast<uint64>(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/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); From 809a4efc6bd2f412027702994b897b96c81beb32 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 26 Aug 2017 11:24:19 -0700 Subject: [PATCH 31/74] removing dependencies on simplifier Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/rewriter/elim_bounds.cpp | 203 +++++++++++++++++++++++++++++++ src/ast/rewriter/elim_bounds.h | 77 ++++++++++++ 2 files changed, 280 insertions(+) create mode 100644 src/ast/rewriter/elim_bounds.cpp create mode 100644 src/ast/rewriter/elim_bounds.h 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: + + <abstract> + +Author: + + Leonardo de Moura (leonardo) 2008-06-28. + +Revision History: + +--*/ + +#ifndef ELIM_BOUNDS_H_ +#define ELIM_BOUNDS_H_ + +#include "ast/used_vars.h" +#include "util/obj_hashtable.h" +#include "ast/rewriter/var_subst.h" +#include "ast/rewriter/elim_bounds.h" +#include "ast/ast_pp.h" + +elim_bounds_cfg::elim_bounds_cfg(ast_manager & m): + m(m), + m_util(m) { +} + +/** + \brief Find bounds of the form + + (<= x k) + (<= (+ x (* -1 y)) k) + (<= (+ x (* -1 t)) k) + (<= (+ t (* -1 x)) k) + + x and y are a bound variables, t is a ground term and k is a numeral + + It also detects >=, and the atom can be negated. +*/ +bool elim_bounds_cfg::is_bound(expr * n, var * & lower, var * & upper) { + upper = 0; + lower = 0; + bool neg = false; + if (m.is_not(n)) { + n = to_app(n)->get_arg(0); + neg = true; + } + + expr* l = 0, *r = 0; + bool le = false; + if (m_util.is_le(n, l, r) && m_util.is_numeral(r)) { + n = l; + le = true; + } + else if (m_util.is_ge(n, l, r) && m_util.is_numeral(r)) { + n = l; + le = false; + } + else { + return false; + } + + if (neg) + le = !le; + + if (is_var(n)) { + upper = to_var(n); + } + else if (m_util.is_add(n, l, r)) { + expr * arg1 = l; + expr * arg2 = r; + if (is_var(arg1)) + upper = to_var(arg1); + else if (!is_ground(arg1)) + return false; + rational k; + bool is_int; + if (m_util.is_mul(arg2) && m_util.is_numeral(to_app(arg2)->get_arg(0), k, is_int) && k.is_minus_one()) { + arg2 = to_app(arg2)->get_arg(1); + if (is_var(arg2)) + lower = to_var(arg2); + else if (!is_ground(arg2)) + return false; // not supported + } + else { + return false; // not supported + } + } + else { + return false; + } + + if (!le) + std::swap(upper, lower); + + return true; +} + +bool elim_bounds_cfg::is_bound(expr * n) { + var * lower, * upper; + return is_bound(n, lower, upper); +} + + +bool elim_bounds_cfg::reduce_quantifier(quantifier * q, + expr * n, + expr * const * new_patterns, + expr * const * new_no_patterns, + expr_ref & result, + proof_ref & result_pr) { + if (!q->is_forall()) { + return false; + } + unsigned num_vars = q->get_num_decls(); + ptr_buffer<expr> atoms; + if (m.is_or(n)) + atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args()); + else + atoms.push_back(n); + used_vars used_vars; + // collect non-candidates + for (expr * a : atoms) { + if (!is_bound(a)) + used_vars.process(a); + } + if (used_vars.uses_all_vars(q->get_num_decls())) { + return false; + } + // collect candidates + obj_hashtable<var> lowers; + obj_hashtable<var> uppers; + obj_hashtable<var> candidate_set; + ptr_buffer<var> candidates; +#define ADD_CANDIDATE(V) if (!lowers.contains(V) && !uppers.contains(V)) { candidate_set.insert(V); candidates.push_back(V); } + for (expr * a : atoms) { + var * lower = 0; + var * upper = 0; + if (is_bound(a, lower, upper)) { + if (lower != 0 && !used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) { + ADD_CANDIDATE(lower); + lowers.insert(lower); + } + if (upper != 0 && !used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) { + ADD_CANDIDATE(upper); + uppers.insert(upper); + } + } + } + TRACE("elim_bounds", tout << "candidates:\n"; for (unsigned i = 0; i < candidates.size(); i++) tout << mk_pp(candidates[i], m) << "\n";); + // remove candidates that have lower and upper bounds + + for (var * v : candidates) { + if (lowers.contains(v) && uppers.contains(v)) + candidate_set.erase(v); + } + TRACE("elim_bounds", tout << "candidates after filter:\n"; for (unsigned i = 0; i < candidates.size(); i++) tout << mk_pp(candidates[i], m) << "\n";); + if (candidate_set.empty()) { + return false; + } + // remove bounds that contain variables in candidate_set + unsigned j = 0; + for (unsigned i = 0; i < atoms.size(); ++i) { + expr * a = atoms[i]; + var * lower = 0; + var * upper = 0; + if (is_bound(a, lower, upper) && ((lower != 0 && candidate_set.contains(lower)) || (upper != 0 && candidate_set.contains(upper)))) + continue; + atoms[j] = a; + j++; + } + if (j == atoms.size()) { + return false; + } + atoms.resize(j); + expr * new_body = 0; + switch (atoms.size()) { + case 0: + result = m.mk_false(); + result_pr = m.mk_rewrite(q, result); + TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";); + return true; + case 1: + new_body = atoms[0]; + break; + default: + new_body = m.mk_or(atoms.size(), atoms.c_ptr()); + break; + } + quantifier_ref new_q(m); + new_q = m.update_quantifier(q, new_body); + elim_unused_vars(m, new_q, params_ref(), result); + result_pr = m.mk_rewrite(q, result); + TRACE("elim_bounds", tout << mk_pp(q, m) << "\n" << result << "\n";); + return true; +} + +#endif /* ELIM_BOUNDS_H_ */ diff --git a/src/ast/rewriter/elim_bounds.h b/src/ast/rewriter/elim_bounds.h new file mode 100644 index 000000000..e0bba4e60 --- /dev/null +++ b/src/ast/rewriter/elim_bounds.h @@ -0,0 +1,77 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + elim_bounds2.h + +Abstract: + + <abstract> + +Author: + + Leonardo de Moura (leonardo) 2008-06-28. + +Revision History: + +--*/ +#ifndef ELIM_BOUNDS2_H_ +#define ELIM_BOUNDS2_H_ + +#include "ast/ast.h" +#include "ast/arith_decl_plugin.h" +#include "ast/rewriter/rewriter.h" + +/** + \brief Functor for eliminating irrelevant bounds in quantified formulas. + + Example: + (forall (x Int) (y Int) (or (not (>= y x) (not (>= x 0)) (= (select a x) 1)))) + + The bound (>= y x) is irrelevant and can be eliminated. + + This can be easily proved by using Fourier-Motzkin elimination. + + Limitations & Assumptions: + - It assumes the input formula was already simplified. + - It can only handle bounds in the diff-logic fragment. + + \remark This operation is subsumed by Fourier-Motzkin elimination. +*/ +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_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_bounds2 in all + universal quantifiers in an expression. + + Assumption: the formula was already skolemized. +*/ +class elim_bounds_rw : public rewriter_tpl<elim_bounds_cfg> { +protected: + elim_bounds_cfg m_cfg; +public: + elim_bounds_rw(ast_manager & m): + rewriter_tpl<elim_bounds_cfg>(m, m.proofs_enabled(), m_cfg), + m_cfg(m) + {} + + virtual ~elim_bounds_rw() {} +}; + +#endif /* ELIM_BOUNDS2_H_ */ + From 2ede4b2c805a97ddd63f0205d4ba5c2940295a5c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 27 Aug 2017 09:31:16 -0700 Subject: [PATCH 32/74] fixes based on regression tests Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/arith_decl_plugin.cpp | 36 ++++---- src/ast/arith_decl_plugin.h | 34 +++---- src/ast/ast.cpp | 1 + src/ast/macros/macro_manager.cpp | 11 ++- src/ast/rewriter/arith_rewriter.cpp | 9 +- src/ast/rewriter/poly_rewriter_def.h | 23 ++--- src/ast/rewriter/push_app_ite.cpp | 1 + src/ast/rewriter/push_app_ite.h | 1 + src/ast/rewriter/rewriter_def.h | 3 +- src/ast/rewriter/rewriter_params.pyg | 1 + src/ast/rewriter/th_rewriter.cpp | 4 +- src/qe/nlqsat.cpp | 12 +-- src/smt/CMakeLists.txt | 2 +- ...formulas_new.cpp => asserted_formulas.cpp} | 88 +++++++++---------- ...ted_formulas_new.h => asserted_formulas.h} | 40 ++++----- src/smt/smt_context.cpp | 4 +- src/smt/smt_context.h | 4 +- src/smt/theory_arith_core.h | 17 ++-- src/smt/theory_array_full.cpp | 8 +- src/smt/theory_lra.cpp | 3 - src/tactic/arith/purify_arith_tactic.cpp | 8 +- 21 files changed, 159 insertions(+), 151 deletions(-) rename src/smt/{asserted_formulas_new.cpp => asserted_formulas.cpp} (86%) rename src/smt/{asserted_formulas_new.h => asserted_formulas.h} (88%) diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp index 01b671c99..0719ebdfa 100644 --- a/src/ast/arith_decl_plugin.cpp +++ b/src/ast/arith_decl_plugin.cpp @@ -178,7 +178,7 @@ void arith_decl_plugin::set_manager(ast_manager * m, family_id id) { MK_AC_OP(m_i_mul_decl, "*", OP_MUL, i); MK_LEFT_ASSOC_OP(m_i_div_decl, "div", OP_IDIV, i); MK_OP(m_i_rem_decl, "rem", OP_REM, i); - MK_OP(m_i_mod_decl, "mod", OP_MOD, i); + //MK_OP(m_i_mod_decl, "mod", OP_MOD, i); MK_UNARY(m_i_uminus_decl, "-", OP_UMINUS, i); m_to_real_decl = m->mk_func_decl(symbol("to_real"), i, r, func_decl_info(id, OP_TO_REAL)); @@ -215,18 +215,18 @@ void arith_decl_plugin::set_manager(ast_manager * m, family_id id) { m_e = m->mk_const(e_decl); m->inc_ref(m_e); - func_decl * z_pw_z_int = m->mk_const_decl(symbol("0^0-int"), i, func_decl_info(id, OP_0_PW_0_INT)); - m_0_pw_0_int = m->mk_const(z_pw_z_int); - m->inc_ref(m_0_pw_0_int); + //func_decl * z_pw_z_int = m->mk_const_decl(symbol("0^0-int"), i, func_decl_info(id, OP_0_PW_0_INT)); + //m_0_pw_0_int = m->mk_const(z_pw_z_int); + //m->inc_ref(m_0_pw_0_int); - func_decl * z_pw_z_real = m->mk_const_decl(symbol("0^0-real"), r, func_decl_info(id, OP_0_PW_0_REAL)); - m_0_pw_0_real = m->mk_const(z_pw_z_real); - m->inc_ref(m_0_pw_0_real); + //func_decl * z_pw_z_real = m->mk_const_decl(symbol("0^0-real"), r, func_decl_info(id, OP_0_PW_0_REAL)); + //m_0_pw_0_real = m->mk_const(z_pw_z_real); + //m->inc_ref(m_0_pw_0_real); MK_OP(m_neg_root_decl, "neg-root", OP_NEG_ROOT, r); - MK_UNARY(m_div_0_decl, "/0", OP_DIV_0, r); - MK_UNARY(m_idiv_0_decl, "div0", OP_IDIV_0, i); - MK_UNARY(m_mod_0_decl, "mod0", OP_MOD_0, i); + //MK_UNARY(m_div_0_decl, "/0", OP_DIV_0, r); + //MK_UNARY(m_idiv_0_decl, "div0", OP_IDIV_0, i); + //MK_UNARY(m_mod_0_decl, "mod0", OP_MOD_0, i); MK_UNARY(m_u_asin_decl, "asin-u", OP_U_ASIN, r); MK_UNARY(m_u_acos_decl, "acos-u", OP_U_ACOS, r); } @@ -392,12 +392,12 @@ inline func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, bool is_real) { case OP_ATANH: return m_atanh_decl; case OP_PI: return m_pi->get_decl(); case OP_E: return m_e->get_decl(); - case OP_0_PW_0_INT: return m_0_pw_0_int->get_decl(); - case OP_0_PW_0_REAL: return m_0_pw_0_real->get_decl(); + //case OP_0_PW_0_INT: return m_0_pw_0_int->get_decl(); + //case OP_0_PW_0_REAL: return m_0_pw_0_real->get_decl(); case OP_NEG_ROOT: return m_neg_root_decl; - case OP_DIV_0: return m_div_0_decl; - case OP_IDIV_0: return m_idiv_0_decl; - case OP_MOD_0: return m_mod_0_decl; + //case OP_DIV_0: return m_div_0_decl; + //case OP_IDIV_0: return m_idiv_0_decl; + //case OP_MOD_0: return m_mod_0_decl; case OP_U_ASIN: return m_u_asin_decl; case OP_U_ACOS: return m_u_acos_decl; default: return 0; @@ -489,9 +489,9 @@ static bool has_real_arg(ast_manager * m, unsigned num_args, expr * const * args static bool is_const_op(decl_kind k) { return k == OP_PI || - k == OP_E || - k == OP_0_PW_0_INT || - k == OP_0_PW_0_REAL; + k == OP_E; + //k == OP_0_PW_0_INT || + //k == OP_0_PW_0_REAL; } func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 6c2b1c77a..0238df3ae 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -70,12 +70,12 @@ enum arith_op_kind { OP_PI, OP_E, // under-specified symbols - OP_0_PW_0_INT, // 0^0 for integers - OP_0_PW_0_REAL, // 0^0 for reals + //OP_0_PW_0_INT, // 0^0 for integers + //OP_0_PW_0_REAL, // 0^0 for reals OP_NEG_ROOT, // x^n when n is even and x is negative - OP_DIV_0, // x/0 - OP_IDIV_0, // x div 0 - OP_MOD_0, // x mod 0 + // OP_DIV_0, // x/0 + // OP_IDIV_0, // x div 0 + // OP_MOD_0, // x mod 0 OP_U_ASIN, // asin(x) for x < -1 or x > 1 OP_U_ACOS, // acos(x) for x < -1 or x > 1 LAST_ARITH_OP @@ -218,12 +218,12 @@ public: return false; switch (f->get_decl_kind()) { - case OP_0_PW_0_INT: - case OP_0_PW_0_REAL: + //case OP_0_PW_0_INT: + //case OP_0_PW_0_REAL: case OP_NEG_ROOT: - case OP_DIV_0: - case OP_IDIV_0: - case OP_MOD_0: + //case OP_DIV_0: + //case OP_IDIV_0: + //case OP_MOD_0: case OP_U_ASIN: case OP_U_ACOS: return true; @@ -276,9 +276,9 @@ public: bool is_uminus(expr const * n) const { return is_app_of(n, m_afid, OP_UMINUS); } bool is_mul(expr const * n) const { return is_app_of(n, m_afid, OP_MUL); } bool is_div(expr const * n) const { return is_app_of(n, m_afid, OP_DIV); } - bool is_div0(expr const * n) const { return is_app_of(n, m_afid, OP_DIV_0); } + //bool is_div0(expr const * n) const { return is_app_of(n, m_afid, OP_DIV_0); } bool is_idiv(expr const * n) const { return is_app_of(n, m_afid, OP_IDIV); } - bool is_idiv0(expr const * n) const { return is_app_of(n, m_afid, OP_IDIV_0); } + //bool is_idiv0(expr const * n) const { return is_app_of(n, m_afid, OP_IDIV_0); } bool is_mod(expr const * n) const { return is_app_of(n, m_afid, OP_MOD); } bool is_rem(expr const * n) const { return is_app_of(n, m_afid, OP_REM); } bool is_to_real(expr const * n) const { return is_app_of(n, m_afid, OP_TO_REAL); } @@ -425,11 +425,11 @@ public: app * mk_pi() { return plugin().mk_pi(); } app * mk_e() { return plugin().mk_e(); } - app * mk_0_pw_0_int() { return plugin().mk_0_pw_0_int(); } - app * mk_0_pw_0_real() { return plugin().mk_0_pw_0_real(); } - app * mk_div0(expr * arg) { return m_manager.mk_app(m_afid, OP_DIV_0, arg); } - app * mk_idiv0(expr * arg) { return m_manager.mk_app(m_afid, OP_IDIV_0, arg); } - app * mk_mod0(expr * arg) { return m_manager.mk_app(m_afid, OP_MOD_0, arg); } + // app * mk_0_pw_0_int() { return plugin().mk_0_pw_0_int(); } + // app * mk_0_pw_0_real() { return plugin().mk_0_pw_0_real(); } + // app * mk_div0(expr * arg) { return m_manager.mk_app(m_afid, OP_DIV_0, arg); } + // app * mk_idiv0(expr * arg) { return m_manager.mk_app(m_afid, OP_IDIV_0, arg); } + // app * mk_mod0(expr * arg) { return m_manager.mk_app(m_afid, OP_MOD_0, arg); } app * mk_neg_root(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_NEG_ROOT, arg1, arg2); } app * mk_u_asin(expr * arg) { return m_manager.mk_app(m_afid, OP_U_ASIN, arg); } app * mk_u_acos(expr * arg) { return m_manager.mk_app(m_afid, OP_U_ACOS, arg); } diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index f347a8e49..029e2d90c 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -2355,6 +2355,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); diff --git a/src/ast/macros/macro_manager.cpp b/src/ast/macros/macro_manager.cpp index b6ee62322..855cae107 100644 --- a/src/ast/macros/macro_manager.cpp +++ b/src/ast/macros/macro_manager.cpp @@ -213,11 +213,13 @@ func_decl * macro_manager::get_macro_interpretation(unsigned i, expr_ref & inter 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_expander_cfg(ast_manager& m, macro_manager& mm): m(m), mm(mm), + m_used_macro_dependencies(m), m_trail(m) {} @@ -297,8 +299,10 @@ struct macro_manager::macro_expander_cfg : public default_rewriter_cfg { p = m.mk_unit_resolution(2, prs); } else { - p = 0; + 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; @@ -307,6 +311,7 @@ struct macro_manager::macro_expander_cfg : public default_rewriter_cfg { struct macro_manager::macro_expander_rw : public rewriter_tpl<macro_manager::macro_expander_cfg> { macro_expander_cfg m_cfg; + macro_expander_rw(ast_manager& m, macro_manager& mm): rewriter_tpl<macro_manager::macro_expander_cfg>(m, m.proofs_enabled(), m_cfg), m_cfg(m, mm) @@ -319,8 +324,10 @@ void macro_manager::expand_macros(expr * n, proof * pr, expr_dependency * dep, e // Expand macros with "real" proof production support (NO rewrite*) 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_rw proc(m, *this); @@ -328,10 +335,12 @@ void macro_manager::expand_macros(expr * n, proof * pr, expr_dependency * dep, e TRACE("macro_manager_bug", tout << "expand_macros:\n" << mk_pp(n, m) << "\n";); proc(old_n, r, n_eq_r_pr); 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()) break; old_n = r; old_pr = new_pr; + old_dep = new_dep; change = true; } // apply th_rewrite to the result. diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 4b00cde45..1f2e9e2e9 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -680,8 +680,9 @@ br_status arith_rewriter::mk_div_core(expr * arg1, expr * arg2, expr_ref & resul if (m_util.is_numeral(arg2, v2, is_int)) { SASSERT(!is_int); if (v2.is_zero()) { - result = m_util.mk_div0(arg1); - return BR_REWRITE1; + return BR_FAILED; + //result = m_util.mk_div0(arg1); + //return BR_REWRITE1; } else if (m_util.is_numeral(arg1, v1, is_int)) { result = m_util.mk_numeral(v1/v2, false); @@ -735,8 +736,8 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu return BR_DONE; } if (m_util.is_numeral(arg2, v2, is_int) && v2.is_zero()) { - result = m_util.mk_idiv0(arg1); - return BR_REWRITE1; + //result = m_util.mk_idiv0(arg1); + //return BR_REWRITE1; } return BR_FAILED; } diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index 2a6bd2c50..85044af08 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -508,22 +508,22 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con expr_fast_mark2 multiple; // multiple.is_marked(power_product) if power_product occurs more than once bool has_multiple = false; expr * prev = 0; - bool ordered = true; + bool ordered = true; for (unsigned i = 0; i < num_args; i++) { expr * arg = args[i]; + if (is_numeral(arg, a)) { num_coeffs++; c += a; + ordered = !m_sort_sums || i == 0; } - else { - // arg is not a numeral - if (m_sort_sums && ordered) { - if (prev != 0 && lt(arg, prev)) - ordered = false; - prev = arg; - } + else if (m_sort_sums && ordered) { + if (prev != 0 && lt(arg, prev)) + ordered = false; + prev = arg; } + arg = get_power_product(arg); if (visited.is_marked(arg)) { multiple.mark(arg); @@ -535,8 +535,8 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con } normalize(c); SASSERT(m_sort_sums || ordered); - TRACE("sort_sums", - tout << "ordered: " << ordered << "\n"; + TRACE("rewriter", + tout << "ordered: " << ordered << " sort sums: " << m_sort_sums << "\n"; for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m()) << "\n";); if (has_multiple) { @@ -589,13 +589,14 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con hoist_cmul(new_args); } else if (m_sort_sums) { - TRACE("sort_sums_bug", tout << "new_args.size(): " << new_args.size() << "\n";); + TRACE("rewriter_bug", tout << "new_args.size(): " << new_args.size() << "\n";); if (c.is_zero()) std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), ast_to_lt()); else std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), ast_to_lt()); } result = mk_add_app(new_args.size(), new_args.c_ptr()); + TRACE("rewriter", tout << result << "\n";); if (hoist_multiplication(result)) { return BR_REWRITE_FULL; } diff --git a/src/ast/rewriter/push_app_ite.cpp b/src/ast/rewriter/push_app_ite.cpp index 386a4fb27..f3df4d711 100644 --- a/src/ast/rewriter/push_app_ite.cpp +++ b/src/ast/rewriter/push_app_ite.cpp @@ -73,6 +73,7 @@ br_status push_app_ite_cfg::reduce_app(func_decl * f, unsigned num, expr * const 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); } diff --git a/src/ast/rewriter/push_app_ite.h b/src/ast/rewriter/push_app_ite.h index e6c6b6fb2..ae06aad30 100644 --- a/src/ast/rewriter/push_app_ite.h +++ b/src/ast/rewriter/push_app_ite.h @@ -34,6 +34,7 @@ struct push_app_ite_cfg : public default_rewriter_cfg { 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; } }; /** diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index 163118d17..c511f00d0 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -496,6 +496,7 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) { expr * const * new_pats; expr * const * new_no_pats; if (rewrite_patterns()) { + TRACE("reduce_quantifier_bug", tout << "rewrite patterns\n";); new_pats = it + 1; new_no_pats = new_pats + q->get_num_patterns(); } @@ -518,7 +519,7 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) { } else { expr_ref tmp(m()); - + TRACE("reduce_quantifier_bug", tout << mk_ismt2_pp(q, m()) << " " << mk_ismt2_pp(new_body, m()) << "\n";); if (!m_cfg.reduce_quantifier(q, new_body, new_pats, new_no_pats, m_r, m_pr)) { if (fr.m_new_child) { m_r = m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_body); 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/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index 764fa8eef..a2ca12b24 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; } diff --git a/src/qe/nlqsat.cpp b/src/qe/nlqsat.cpp index 0f2437982..1f9c89f89 100644 --- a/src/qe/nlqsat.cpp +++ b/src/qe/nlqsat.cpp @@ -444,16 +444,12 @@ 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) { - if (is_decl_of(f, a.get_family_id(), OP_DIV) && sz == 2 && !a.is_numeral(args[1])) { + 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))); return BR_DONE; } - if (is_decl_of(f, a.get_family_id(), OP_DIV_0) && sz == 1 && !a.is_numeral(args[0])) { - result = m.mk_fresh_const("div", a.mk_real()); - m_divs.push_back(div(m, args[0], m_zero, to_app(result))); - return BR_DONE; - } return BR_FAILED; } vector<div> const& divs() const { return m_divs; } @@ -507,10 +503,6 @@ namespace qe { m_has_divs = true; return; } - if (a.is_div0(n) && s.m_mode == qsat_t) { - m_has_divs = true; - return; - } TRACE("qe", tout << "not NRA: " << mk_pp(n, s.m) << "\n";); throw tactic_exception("not NRA"); } diff --git a/src/smt/CMakeLists.txt b/src/smt/CMakeLists.txt index 385d1aaa0..41890dd05 100644 --- a/src/smt/CMakeLists.txt +++ b/src/smt/CMakeLists.txt @@ -2,7 +2,7 @@ z3_add_component(smt SOURCES arith_eq_adapter.cpp arith_eq_solver.cpp - asserted_formulas_new.cpp + asserted_formulas.cpp cached_var_subst.cpp cost_evaluator.cpp dyn_ack.cpp diff --git a/src/smt/asserted_formulas_new.cpp b/src/smt/asserted_formulas.cpp similarity index 86% rename from src/smt/asserted_formulas_new.cpp rename to src/smt/asserted_formulas.cpp index 8d16ef2cd..626588ab3 100644 --- a/src/smt/asserted_formulas_new.cpp +++ b/src/smt/asserted_formulas.cpp @@ -3,7 +3,7 @@ Copyright (c) 2006 Microsoft Corporation Module Name: - asserted_formulas_new.cpp + asserted_formulas.cpp Abstract: @@ -25,9 +25,9 @@ Revision History: #include "ast/normal_forms/nnf.h" #include "ast/pattern/pattern_inference.h" #include "ast/macros/quasi_macros.h" -#include "smt/asserted_formulas_new.h" +#include "smt/asserted_formulas.h" -asserted_formulas_new::asserted_formulas_new(ast_manager & m, smt_params & p): +asserted_formulas::asserted_formulas(ast_manager & m, smt_params & p): m(m), m_params(p), m_rewriter(m), @@ -60,13 +60,11 @@ asserted_formulas_new::asserted_formulas_new(ast_manager & m, smt_params & p): m_macro_finder = alloc(macro_finder, m, m_macro_manager); - params_ref pa; - pa.set_bool("arith_lhs", true); - m_rewriter.updt_params(pa); + set_eliminate_and(false); } -void asserted_formulas_new::setup() { +void asserted_formulas::setup() { switch (m_params.m_lift_ite) { case LI_FULL: m_params.m_ng_lift_ite = LI_NONE; @@ -84,10 +82,10 @@ void asserted_formulas_new::setup() { } -asserted_formulas_new::~asserted_formulas_new() { +asserted_formulas::~asserted_formulas() { } -void asserted_formulas_new::push_assertion(expr * e, proof * pr, vector<justified_expr>& result) { +void asserted_formulas::push_assertion(expr * e, proof * pr, vector<justified_expr>& result) { if (inconsistent()) { return; } @@ -119,16 +117,18 @@ void asserted_formulas_new::push_assertion(expr * e, proof * pr, vector<justifie } } -void asserted_formulas_new::set_eliminate_and(bool flag) { +void asserted_formulas::set_eliminate_and(bool flag) { params_ref p; - p.set_bool("elim_and", true); + p.set_bool("elim_and", flag); p.set_bool("arith_lhs", true); + p.set_bool("sort_sums", true); + p.set_bool("rewrite_patterns", true); m_rewriter.updt_params(p); flush_cache(); } -void asserted_formulas_new::assert_expr(expr * e, proof * _in_pr) { +void asserted_formulas::assert_expr(expr * e, proof * _in_pr) { proof_ref in_pr(_in_pr, m), pr(_in_pr, m); expr_ref r(e, m); @@ -153,17 +153,17 @@ void asserted_formulas_new::assert_expr(expr * e, proof * _in_pr) { TRACE("asserted_formulas_bug", tout << "after assert_expr\n"; display(tout);); } -void asserted_formulas_new::assert_expr(expr * e) { +void asserted_formulas::assert_expr(expr * e) { assert_expr(e, m.mk_asserted(e)); } -void asserted_formulas_new::get_assertions(ptr_vector<expr> & result) const { +void asserted_formulas::get_assertions(ptr_vector<expr> & result) const { for (justified_expr const& je : m_formulas) result.push_back(je.get_fml()); } -void asserted_formulas_new::push_scope() { +void asserted_formulas::push_scope() { SASSERT(inconsistent() || m_qhead == m_formulas.size() || m.canceled()); - TRACE("asserted_formulas_new_scopes", tout << "push:\n"; display(tout);); + TRACE("asserted_formulas_scopes", tout << "push:\n"; display(tout);); m_scoped_substitution.push(); m_scopes.push_back(scope()); scope & s = m_scopes.back(); @@ -176,8 +176,8 @@ void asserted_formulas_new::push_scope() { commit(); } -void asserted_formulas_new::pop_scope(unsigned num_scopes) { - TRACE("asserted_formulas_new_scopes", tout << "before pop " << num_scopes << "\n"; display(tout);); +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); m_macro_manager.pop_scope(num_scopes); unsigned new_lvl = m_scopes.size() - num_scopes; @@ -189,10 +189,10 @@ void asserted_formulas_new::pop_scope(unsigned num_scopes) { m_qhead = s.m_formulas_lim; m_scopes.shrink(new_lvl); flush_cache(); - TRACE("asserted_formulas_new_scopes", tout << "after pop " << num_scopes << "\n"; display(tout);); + TRACE("asserted_formulas_scopes", tout << "after pop " << num_scopes << "\n"; display(tout);); } -void asserted_formulas_new::reset() { +void asserted_formulas::reset() { m_defined_names.reset(); m_qhead = 0; m_formulas.reset(); @@ -202,14 +202,14 @@ void asserted_formulas_new::reset() { m_inconsistent = false; } -bool asserted_formulas_new::check_well_sorted() const { +bool asserted_formulas::check_well_sorted() const { for (justified_expr const& je : m_formulas) { if (!is_well_sorted(m, je.get_fml())) return false; } return true; } -void asserted_formulas_new::reduce() { +void asserted_formulas::reduce() { if (inconsistent()) return; if (canceled()) @@ -255,7 +255,7 @@ void asserted_formulas_new::reduce() { } -unsigned asserted_formulas_new::get_formulas_last_level() const { +unsigned asserted_formulas::get_formulas_last_level() const { if (m_scopes.empty()) { return 0; } @@ -264,7 +264,7 @@ unsigned asserted_formulas_new::get_formulas_last_level() const { } } -bool asserted_formulas_new::invoke(simplify_fmls& s) { +bool asserted_formulas::invoke(simplify_fmls& s) { if (!s.should_apply()) return true; IF_VERBOSE(10, verbose_stream() << "(smt." << s.id() << ")\n";); s(); @@ -281,7 +281,7 @@ bool asserted_formulas_new::invoke(simplify_fmls& s) { } } -void asserted_formulas_new::display(std::ostream & out) const { +void asserted_formulas::display(std::ostream & out) const { out << "asserted formulas:\n"; for (unsigned i = 0; i < m_formulas.size(); i++) { if (i == m_qhead) @@ -291,7 +291,7 @@ void asserted_formulas_new::display(std::ostream & out) const { out << "inconsistent: " << inconsistent() << "\n"; } -void asserted_formulas_new::display_ll(std::ostream & out, ast_mark & pp_visited) const { +void asserted_formulas::display_ll(std::ostream & out, ast_mark & pp_visited) const { if (!m_formulas.empty()) { for (justified_expr const& f : m_formulas) ast_def_ll_pp(out, m, f.get_fml(), pp_visited, true, false); @@ -302,18 +302,18 @@ void asserted_formulas_new::display_ll(std::ostream & out, ast_mark & pp_visited } } -void asserted_formulas_new::collect_statistics(statistics & st) const { +void asserted_formulas::collect_statistics(statistics & st) const { } -void asserted_formulas_new::swap_asserted_formulas(vector<justified_expr>& formulas) { +void asserted_formulas::swap_asserted_formulas(vector<justified_expr>& formulas) { SASSERT(!inconsistent() || !formulas.empty()); m_formulas.shrink(m_qhead); m_formulas.append(formulas); } -void asserted_formulas_new::find_macros_core() { +void asserted_formulas::find_macros_core() { vector<justified_expr> new_fmls; unsigned sz = m_formulas.size(); (*m_macro_finder)(sz - m_qhead, m_formulas.c_ptr() + m_qhead, new_fmls); @@ -321,7 +321,7 @@ void asserted_formulas_new::find_macros_core() { reduce_and_solve(); } -void asserted_formulas_new::apply_quasi_macros() { +void asserted_formulas::apply_quasi_macros() { TRACE("before_quasi_macros", display(tout);); vector<justified_expr> new_fmls; quasi_macros proc(m, m_macro_manager); @@ -335,7 +335,7 @@ void asserted_formulas_new::apply_quasi_macros() { reduce_and_solve(); } -void asserted_formulas_new::nnf_cnf() { +void asserted_formulas::nnf_cnf() { nnf apply_nnf(m, m_defined_names); vector<justified_expr> new_fmls; expr_ref_vector push_todo(m); @@ -379,7 +379,7 @@ void asserted_formulas_new::nnf_cnf() { swap_asserted_formulas(new_fmls); } -void asserted_formulas_new::simplify_fmls::operator()() { +void asserted_formulas::simplify_fmls::operator()() { vector<justified_expr> new_fmls; unsigned sz = af.m_formulas.size(); for (unsigned i = af.m_qhead; i < sz; i++) { @@ -405,18 +405,18 @@ void asserted_formulas_new::simplify_fmls::operator()() { } -void asserted_formulas_new::reduce_and_solve() { +void asserted_formulas::reduce_and_solve() { IF_IVERBOSE(10, verbose_stream() << "(smt.reducing)\n";); flush_cache(); // collect garbage m_reduce_asserted_formulas(); } -void asserted_formulas_new::commit() { +void asserted_formulas::commit() { commit(m_formulas.size()); } -void asserted_formulas_new::commit(unsigned new_qhead) { +void asserted_formulas::commit(unsigned new_qhead) { 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) { @@ -426,7 +426,7 @@ void asserted_formulas_new::commit(unsigned new_qhead) { m_qhead = new_qhead; } -void asserted_formulas_new::propagate_values() { +void asserted_formulas::propagate_values() { TRACE("propagate_values", tout << "before:\n"; display(tout);); flush_cache(); @@ -463,7 +463,7 @@ void asserted_formulas_new::propagate_values() { m_reduce_asserted_formulas(); } -unsigned asserted_formulas_new::propagate_values(unsigned i) { +unsigned asserted_formulas::propagate_values(unsigned i) { expr * n = m_formulas[i].get_fml(); expr_ref new_n(m); proof_ref new_pr(m); @@ -481,7 +481,7 @@ unsigned asserted_formulas_new::propagate_values(unsigned i) { return n != new_n ? 1 : 0; } -void asserted_formulas_new::update_substitution(expr* n, proof* pr) { +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); @@ -510,7 +510,7 @@ void asserted_formulas_new::update_substitution(expr* n, proof* pr) { \brief implement a Knuth-Bendix ordering on expressions. */ -bool asserted_formulas_new::is_gt(expr* lhs, expr* rhs) { +bool asserted_formulas::is_gt(expr* lhs, expr* rhs) { if (lhs == rhs) { return false; } @@ -541,7 +541,7 @@ bool asserted_formulas_new::is_gt(expr* lhs, expr* rhs) { return false; } -void asserted_formulas_new::compute_depth(expr* e) { +void asserted_formulas::compute_depth(expr* e) { ptr_vector<expr> todo; todo.push_back(e); while (!todo.empty()) { @@ -573,7 +573,7 @@ void asserted_formulas_new::compute_depth(expr* e) { } } -proof * asserted_formulas_new::get_inconsistency_proof() const { +proof * asserted_formulas::get_inconsistency_proof() const { if (!inconsistent()) return 0; if (!m.proofs_enabled()) @@ -586,7 +586,7 @@ proof * asserted_formulas_new::get_inconsistency_proof() const { return 0; } -void asserted_formulas_new::refine_inj_axiom_fn::simplify(justified_expr const& j, expr_ref& n, proof_ref& p) { +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";); @@ -597,7 +597,7 @@ void asserted_formulas_new::refine_inj_axiom_fn::simplify(justified_expr const& } -unsigned asserted_formulas_new::get_total_size() const { +unsigned asserted_formulas::get_total_size() const { expr_mark visited; unsigned r = 0; for (justified_expr const& j : m_formulas) @@ -606,7 +606,7 @@ unsigned asserted_formulas_new::get_total_size() const { } #ifdef Z3DEBUG -void pp(asserted_formulas_new & f) { +void pp(asserted_formulas & f) { f.display(std::cout); } #endif diff --git a/src/smt/asserted_formulas_new.h b/src/smt/asserted_formulas.h similarity index 88% rename from src/smt/asserted_formulas_new.h rename to src/smt/asserted_formulas.h index 82f18250d..ea00cb71c 100644 --- a/src/smt/asserted_formulas_new.h +++ b/src/smt/asserted_formulas.h @@ -3,7 +3,7 @@ Copyright (c) 2006 Microsoft Corporation Module Name: - asserted_formulas_new.h + asserted_formulas.h Abstract: @@ -16,8 +16,8 @@ Author: Revision History: --*/ -#ifndef ASSERTED_FORMULAS_NEW_H_ -#define ASSERTED_FORMULAS_NEW_H_ +#ifndef ASSERTED_FORMULAS_H_ +#define ASSERTED_FORMULAS_H_ #include "util/statistics.h" #include "ast/static_features.h" @@ -41,7 +41,7 @@ Revision History: #include "smt/elim_term_ite.h" -class asserted_formulas_new { +class asserted_formulas { ast_manager & m; smt_params & m_params; @@ -66,11 +66,11 @@ class asserted_formulas_new { class simplify_fmls { protected: - asserted_formulas_new& af; + asserted_formulas& af; ast_manager& m; char const* m_id; public: - simplify_fmls(asserted_formulas_new& af, char const* id): af(af), m(af.m), m_id(id) {} + 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;} @@ -80,13 +80,13 @@ class asserted_formulas_new { class reduce_asserted_formulas_fn : public simplify_fmls { public: - reduce_asserted_formulas_fn(asserted_formulas_new& af): simplify_fmls(af, "reduce-asserted") {} + 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_new& af): simplify_fmls(af, "find-macros") {} + 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(); } @@ -94,7 +94,7 @@ class asserted_formulas_new { class apply_quasi_macros_fn : public simplify_fmls { public: - apply_quasi_macros_fn(asserted_formulas_new& af): simplify_fmls(af, "find-quasi-macros") {} + 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(); } @@ -102,7 +102,7 @@ class asserted_formulas_new { class nnf_cnf_fn : public simplify_fmls { public: - nnf_cnf_fn(asserted_formulas_new& af): simplify_fmls(af, "nnf-cnf") {} + 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(); } @@ -110,7 +110,7 @@ class asserted_formulas_new { class propagate_values_fn : public simplify_fmls { public: - propagate_values_fn(asserted_formulas_new& af): simplify_fmls(af, "propagate-values") {} + 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(); } @@ -119,7 +119,7 @@ class asserted_formulas_new { class distribute_forall_fn : public simplify_fmls { distribute_forall m_functor; public: - distribute_forall_fn(asserted_formulas_new& af): simplify_fmls(af, "distribute-forall"), m_functor(af.m) {} + 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);); } @@ -128,21 +128,21 @@ class asserted_formulas_new { class pattern_inference_fn : public simplify_fmls { pattern_inference_rw m_infer; public: - pattern_inference_fn(asserted_formulas_new& af): simplify_fmls(af, "pattern-inference"), m_infer(af.m, af.m_params) {} + 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_new& af): simplify_fmls(af, "refine-injectivity") {} + 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_new& af): simplify_fmls(af, "maximizing-bv-sharing") {} + 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(); } @@ -151,7 +151,7 @@ class asserted_formulas_new { class elim_term_ite_fn : public simplify_fmls { elim_term_ite_rw m_elim; public: - elim_term_ite_fn(asserted_formulas_new& af): simplify_fmls(af, "elim-term-ite"), m_elim(af.m, af.m_defined_names) {} + 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(); } @@ -161,7 +161,7 @@ class asserted_formulas_new { class NAME : public simplify_fmls { \ FUNCTOR m_functor; \ public: \ - NAME(asserted_formulas_new& af):simplify_fmls(af, MSG), m_functor ARG {} \ + 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); \ } \ @@ -221,8 +221,8 @@ class asserted_formulas_new { bool pull_cheap_ite_trees(); public: - asserted_formulas_new(ast_manager & m, smt_params & p); - ~asserted_formulas_new(); + asserted_formulas(ast_manager & m, smt_params & p); + ~asserted_formulas(); bool has_quantifiers() const { return m_has_quantifiers; } void setup(); @@ -265,5 +265,5 @@ public: }; -#endif /* ASSERTED_FORMULAS_NEW_H_ */ +#endif /* ASSERTED_FORMULAS_H_ */ diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 7b92bdd28..eef84f773 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -148,8 +148,8 @@ namespace smt { dst_ctx.set_logic(src_ctx.m_setup.get_logic()); dst_ctx.copy_plugins(src_ctx, dst_ctx); - asserted_formulas_new& src_af = src_ctx.m_asserted_formulas; - asserted_formulas_new& dst_af = dst_ctx.m_asserted_formulas; + asserted_formulas& src_af = src_ctx.m_asserted_formulas; + asserted_formulas& dst_af = dst_ctx.m_asserted_formulas; // Copy asserted formulas. for (unsigned i = 0; i < src_af.get_num_formulas(); ++i) { diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index a6a67702a..3cc577b29 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -36,7 +36,7 @@ Revision History: #include "smt/smt_case_split_queue.h" #include "smt/smt_almost_cg_table.h" #include "smt/smt_failure.h" -#include "smt/asserted_formulas_new.h" +#include "smt/asserted_formulas.h" #include "smt/smt_types.h" #include "smt/dyn_ack.h" #include "ast/ast_smt_pp.h" @@ -81,7 +81,7 @@ namespace smt { params_ref m_params; setup m_setup; timer m_timer; - asserted_formulas_new m_asserted_formulas; + asserted_formulas m_asserted_formulas; scoped_ptr<quantifier_manager> m_qmanager; scoped_ptr<model_generator> m_model_generator; scoped_ptr<relevancy_propagator> m_relevancy_propagator; diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 70355502d..16a49961e 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -395,7 +395,8 @@ namespace smt { template<typename Ext> theory_var theory_arith<Ext>::internalize_div(app * n) { - if (!m_util.is_numeral(n->get_arg(1))) found_underspecified_op(n); + 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); context & ctx = get_context(); @@ -419,7 +420,8 @@ namespace smt { template<typename Ext> theory_var theory_arith<Ext>::internalize_mod(app * n) { TRACE("arith_mod", tout << "internalizing...\n" << mk_pp(n, get_manager()) << "\n";); - if (!m_util.is_numeral(n->get_arg(1))) found_underspecified_op(n); + 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(); if (!ctx.relevancy()) @@ -429,7 +431,8 @@ namespace smt { template<typename Ext> theory_var theory_arith<Ext>::internalize_rem(app * n) { - if (!m_util.is_numeral(n->get_arg(1))) found_underspecified_op(n); + 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(); if (!ctx.relevancy()) { @@ -734,11 +737,6 @@ namespace smt { return internalize_div(n); else if (m_util.is_idiv(n)) return internalize_idiv(n); - else if (is_app_of(n, get_id(), OP_IDIV_0) || is_app_of(n, get_id(), OP_DIV_0)) { - ctx.internalize(n->get_arg(0), false); - enode * e = mk_enode(n); - return mk_var(e); - } else if (m_util.is_mod(n)) return internalize_mod(n); else if (m_util.is_rem(n)) @@ -1226,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_array_full.cpp b/src/smt/theory_array_full.cpp index c7a3d7920..274f89e8b 100644 --- a/src/smt/theory_array_full.cpp +++ b/src/smt/theory_array_full.cpp @@ -516,7 +516,8 @@ namespace smt { expr_ref sel1(m), sel2(m); sel1 = mk_select(args1.size(), args1.c_ptr()); - sel2 = ctx.get_rewriter().mk_app(f, args2.size(), args2.c_ptr()); + sel2 = m.mk_app(f, args2.size(), args2.c_ptr()); + ctx.get_rewriter()(sel2); ctx.internalize(sel1, false); ctx.internalize(sel2, false); @@ -537,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; @@ -552,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()); - def2 = ctx.get_rewriter().mk_app(f, args2.size(), args2.c_ptr()); ctx.internalize(def1, false); ctx.internalize(def2, false); return try_assign_eq(def1, def2); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 0c09d0403..dd044b78a 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -293,9 +293,6 @@ namespace smt { } void found_not_handled(expr* n) { - if (a.is_div0(n)) { - return; - } m_not_handled = n; if (is_app(n) && is_underspecified(to_app(n))) { m_underspecified.push_back(to_app(n)); diff --git a/src/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 0443a51ed..17a69f93e 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -301,7 +301,7 @@ struct purify_arith_proc { if (complete()) { // y != 0 \/ k = div-0(x) push_cnstr(OR(NOT(EQ(y, mk_real_zero())), - EQ(k, u().mk_div0(x)))); + EQ(k, u().mk_div(x, mk_real_zero())))); push_cnstr_pr(result_pr); } } @@ -349,10 +349,10 @@ struct purify_arith_proc { push_cnstr_pr(mod_pr); if (complete()) { - push_cnstr(OR(NOT(EQ(y, zero)), EQ(k1, u().mk_idiv0(x)))); + push_cnstr(OR(NOT(EQ(y, zero)), EQ(k1, u().mk_idiv(x, zero)))); push_cnstr_pr(result_pr); - push_cnstr(OR(NOT(EQ(y, zero)), EQ(k2, u().mk_mod0(x)))); + push_cnstr(OR(NOT(EQ(y, zero)), EQ(k2, u().mk_mod(x, zero)))); push_cnstr_pr(mod_pr); } } @@ -414,7 +414,7 @@ struct purify_arith_proc { // (^ x 0) --> k | x != 0 implies k = 1, x = 0 implies k = 0^0 push_cnstr(OR(EQ(x, zero), EQ(k, one))); push_cnstr_pr(result_pr); - push_cnstr(OR(NOT(EQ(x, zero)), EQ(k, is_int ? u().mk_0_pw_0_int() : u().mk_0_pw_0_real()))); + push_cnstr(OR(NOT(EQ(x, zero)), EQ(k, u().mk_power(zero, zero)))); push_cnstr_pr(result_pr); } else if (!is_int) { From d940516df3c60ca01c69e1569dcfbb3e950f52ec Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 27 Aug 2017 11:01:45 -0700 Subject: [PATCH 33/74] fixes Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/arith_decl_plugin.cpp | 22 +--------------------- src/ast/arith_decl_plugin.h | 24 ------------------------ src/muz/spacer/spacer_sym_mux.cpp | 1 + src/smt/qi_queue.cpp | 5 ++--- src/smt/smt_quick_checker.cpp | 3 +-- src/smt/smt_quick_checker.h | 1 - src/smt/theory_arith_core.h | 5 ++--- src/smt/theory_fpa.cpp | 3 +-- src/tactic/arith/purify_arith_tactic.cpp | 7 ++++--- src/test/ext_numeral.cpp | 6 +++--- 10 files changed, 15 insertions(+), 62 deletions(-) diff --git a/src/ast/arith_decl_plugin.cpp b/src/ast/arith_decl_plugin.cpp index 0719ebdfa..03ee77458 100644 --- a/src/ast/arith_decl_plugin.cpp +++ b/src/ast/arith_decl_plugin.cpp @@ -178,7 +178,7 @@ void arith_decl_plugin::set_manager(ast_manager * m, family_id id) { MK_AC_OP(m_i_mul_decl, "*", OP_MUL, i); MK_LEFT_ASSOC_OP(m_i_div_decl, "div", OP_IDIV, i); MK_OP(m_i_rem_decl, "rem", OP_REM, i); - //MK_OP(m_i_mod_decl, "mod", OP_MOD, i); + MK_OP(m_i_mod_decl, "mod", OP_MOD, i); MK_UNARY(m_i_uminus_decl, "-", OP_UMINUS, i); m_to_real_decl = m->mk_func_decl(symbol("to_real"), i, r, func_decl_info(id, OP_TO_REAL)); @@ -215,18 +215,8 @@ void arith_decl_plugin::set_manager(ast_manager * m, family_id id) { m_e = m->mk_const(e_decl); m->inc_ref(m_e); - //func_decl * z_pw_z_int = m->mk_const_decl(symbol("0^0-int"), i, func_decl_info(id, OP_0_PW_0_INT)); - //m_0_pw_0_int = m->mk_const(z_pw_z_int); - //m->inc_ref(m_0_pw_0_int); - - //func_decl * z_pw_z_real = m->mk_const_decl(symbol("0^0-real"), r, func_decl_info(id, OP_0_PW_0_REAL)); - //m_0_pw_0_real = m->mk_const(z_pw_z_real); - //m->inc_ref(m_0_pw_0_real); MK_OP(m_neg_root_decl, "neg-root", OP_NEG_ROOT, r); - //MK_UNARY(m_div_0_decl, "/0", OP_DIV_0, r); - //MK_UNARY(m_idiv_0_decl, "div0", OP_IDIV_0, i); - //MK_UNARY(m_mod_0_decl, "mod0", OP_MOD_0, i); MK_UNARY(m_u_asin_decl, "asin-u", OP_U_ASIN, r); MK_UNARY(m_u_acos_decl, "acos-u", OP_U_ACOS, r); } @@ -279,12 +269,7 @@ arith_decl_plugin::arith_decl_plugin(): m_atanh_decl(0), m_pi(0), m_e(0), - m_0_pw_0_int(0), - m_0_pw_0_real(0), m_neg_root_decl(0), - m_div_0_decl(0), - m_idiv_0_decl(0), - m_mod_0_decl(0), m_u_asin_decl(0), m_u_acos_decl(0), m_convert_int_numerals_to_real(false) { @@ -339,12 +324,7 @@ void arith_decl_plugin::finalize() { DEC_REF(m_atanh_decl); DEC_REF(m_pi); DEC_REF(m_e); - DEC_REF(m_0_pw_0_int); - DEC_REF(m_0_pw_0_real); DEC_REF(m_neg_root_decl); - DEC_REF(m_div_0_decl); - DEC_REF(m_idiv_0_decl); - DEC_REF(m_mod_0_decl); DEC_REF(m_u_asin_decl); DEC_REF(m_u_acos_decl); m_manager->dec_array_ref(m_small_ints.size(), m_small_ints.c_ptr()); diff --git a/src/ast/arith_decl_plugin.h b/src/ast/arith_decl_plugin.h index 0238df3ae..4b24ea5e6 100644 --- a/src/ast/arith_decl_plugin.h +++ b/src/ast/arith_decl_plugin.h @@ -70,12 +70,7 @@ enum arith_op_kind { OP_PI, OP_E, // under-specified symbols - //OP_0_PW_0_INT, // 0^0 for integers - //OP_0_PW_0_REAL, // 0^0 for reals OP_NEG_ROOT, // x^n when n is even and x is negative - // OP_DIV_0, // x/0 - // OP_IDIV_0, // x div 0 - // OP_MOD_0, // x mod 0 OP_U_ASIN, // asin(x) for x < -1 or x > 1 OP_U_ACOS, // acos(x) for x < -1 or x > 1 LAST_ARITH_OP @@ -141,12 +136,7 @@ protected: app * m_pi; app * m_e; - app * m_0_pw_0_int; - app * m_0_pw_0_real; func_decl * m_neg_root_decl; - func_decl * m_div_0_decl; - func_decl * m_idiv_0_decl; - func_decl * m_mod_0_decl; func_decl * m_u_asin_decl; func_decl * m_u_acos_decl; ptr_vector<app> m_small_ints; @@ -207,10 +197,6 @@ public: app * mk_e() const { return m_e; } - app * mk_0_pw_0_int() const { return m_0_pw_0_int; } - - app * mk_0_pw_0_real() const { return m_0_pw_0_real; } - virtual expr * get_some_value(sort * s); virtual bool is_considered_uninterpreted(func_decl * f) { @@ -218,12 +204,7 @@ public: return false; switch (f->get_decl_kind()) { - //case OP_0_PW_0_INT: - //case OP_0_PW_0_REAL: case OP_NEG_ROOT: - //case OP_DIV_0: - //case OP_IDIV_0: - //case OP_MOD_0: case OP_U_ASIN: case OP_U_ACOS: return true; @@ -425,11 +406,6 @@ public: app * mk_pi() { return plugin().mk_pi(); } app * mk_e() { return plugin().mk_e(); } - // app * mk_0_pw_0_int() { return plugin().mk_0_pw_0_int(); } - // app * mk_0_pw_0_real() { return plugin().mk_0_pw_0_real(); } - // app * mk_div0(expr * arg) { return m_manager.mk_app(m_afid, OP_DIV_0, arg); } - // app * mk_idiv0(expr * arg) { return m_manager.mk_app(m_afid, OP_IDIV_0, arg); } - // app * mk_mod0(expr * arg) { return m_manager.mk_app(m_afid, OP_MOD_0, arg); } app * mk_neg_root(expr * arg1, expr * arg2) { return m_manager.mk_app(m_afid, OP_NEG_ROOT, arg1, arg2); } app * mk_u_asin(expr * arg) { return m_manager.mk_app(m_afid, OP_U_ASIN, arg); } app * mk_u_acos(expr * arg) { return m_manager.mk_app(m_afid, OP_U_ACOS, arg); } 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/smt/qi_queue.cpp b/src/smt/qi_queue.cpp index 8f8e3df7b..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); - th_rewriter & simp = m_context.get_rewriter(); - 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_quick_checker.cpp b/src/smt/smt_quick_checker.cpp index 773768944..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_rewriter()), m_collector(c), m_new_exprs(m_manager) { } @@ -411,7 +410,7 @@ namespace smt { } } expr_ref new_expr(m_manager); - new_expr = m_simplifier.mk_app(to_app(n)->get_decl(), num_args, new_args.c_ptr()); + 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 d07e10921..21a570c3c 100644 --- a/src/smt/smt_quick_checker.h +++ b/src/smt/smt_quick_checker.h @@ -77,7 +77,6 @@ namespace smt { context & m_context; ast_manager & m_manager; - th_rewriter & m_simplifier; collector m_collector; expr_ref_vector m_new_exprs; vector<enode_vector> m_candidate_vectors; diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index 16a49961e..13aba9686 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -449,9 +449,8 @@ namespace smt { 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; @@ -459,7 +458,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; diff --git a/src/smt/theory_fpa.cpp b/src/smt/theory_fpa.cpp index 3f246b2c7..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(); - th_rewriter & simp = ctx.get_rewriter(); 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/tactic/arith/purify_arith_tactic.cpp b/src/tactic/arith/purify_arith_tactic.cpp index 17a69f93e..7e89794ce 100644 --- a/src/tactic/arith/purify_arith_tactic.cpp +++ b/src/tactic/arith/purify_arith_tactic.cpp @@ -297,8 +297,8 @@ struct purify_arith_proc { push_cnstr(OR(EQ(y, mk_real_zero()), EQ(u().mk_mul(y, k), x))); push_cnstr_pr(result_pr); - - if (complete()) { + rational r; + if (complete() && (!u().is_numeral(y, r) || r.is_zero())) { // y != 0 \/ k = div-0(x) push_cnstr(OR(NOT(EQ(y, mk_real_zero())), EQ(k, u().mk_div(x, mk_real_zero())))); @@ -348,7 +348,8 @@ struct purify_arith_proc { push_cnstr(OR(u().mk_ge(y, zero), u().mk_lt(k2, u().mk_mul(u().mk_numeral(rational(-1), true), y)))); push_cnstr_pr(mod_pr); - if (complete()) { + rational r; + if (complete() && (!u().is_numeral(y, r) || r.is_zero())) { push_cnstr(OR(NOT(EQ(y, zero)), EQ(k1, u().mk_idiv(x, zero)))); push_cnstr_pr(result_pr); 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)); \ } \ } From f9dc6385b203621f810c1e44df5ea9facc989b41 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 27 Aug 2017 12:19:24 -0700 Subject: [PATCH 34/74] n/a Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/api/api_model.cpp | 9 +++++++++ src/api/c++/z3++.h | 4 ++++ src/api/z3_api.h | 10 ++++++++++ 3 files changed, 23 insertions(+) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 1646c691f..66002baa0 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -319,6 +319,15 @@ extern "C" { Z3_CATCH_RETURN(0); } + void Z3_API Z3_func_interp_set_else(Z3_context c, Z3_func_interp f, Z3_ast else_value) { + Z3_TRY; + LOG_Z3_func_interp_set_else(c, f, else_value); + RESET_ERROR_CODE(); + // CHECK_NON_NULL(f, 0); + to_func_interp_ref(f)->set_else(to_expr(else_value)); + Z3_CATCH; + } + unsigned Z3_API Z3_func_interp_get_arity(Z3_context c, Z3_func_interp f) { Z3_TRY; LOG_Z3_func_interp_get_arity(c, f); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index cf1a5070a..2f67cb72a 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1735,6 +1735,10 @@ namespace z3 { Z3_add_func_entry(ctx(), m_interp, args, value); check_error(); } + void set_else(expr& value) { + Z3_func_entry_set_else(ctx(), m_interp, value); + check_error(); + } }; class model : public object { diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 2f14c3f2e..045417d38 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4925,6 +4925,16 @@ extern "C" { */ Z3_ast Z3_API Z3_func_interp_get_else(Z3_context c, Z3_func_interp f); + /** + \brief Return the 'else' value of the given function interpretation. + + A function interpretation is represented as a finite map and an 'else' value. + This procedure can be used to update the 'else' value. + + def_API('Z3_func_interp_set_else', VOID, (_in(CONTEXT), _in(FUNC_INTERP), _in(AST))) + */ + void Z3_API Z3_func_interp_set_else(Z3_context c, Z3_func_interp f, Z3_ast else_value); + /** \brief Return the arity (number of arguments) of the given function interpretation. From 03f263b974a8300444a956877940c9967a425b3b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 27 Aug 2017 13:02:59 -0700 Subject: [PATCH 35/74] update names Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/api/api_model.cpp | 4 ++-- src/api/c++/z3++.h | 4 ++-- src/api/z3_api.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/api/api_model.cpp b/src/api/api_model.cpp index 66002baa0..540f014c6 100644 --- a/src/api/api_model.cpp +++ b/src/api/api_model.cpp @@ -337,9 +337,9 @@ extern "C" { Z3_CATCH_RETURN(0); } - void Z3_API Z3_add_func_entry(Z3_context c, Z3_func_interp fi, Z3_ast_vector args, Z3_ast value) { + void Z3_API Z3_func_interp_add_entry(Z3_context c, Z3_func_interp fi, Z3_ast_vector args, Z3_ast value) { Z3_TRY; - LOG_Z3_add_func_entry(c, fi, args, value); + LOG_Z3_func_interp_add_entry(c, fi, args, value); //CHECK_NON_NULL(fi, void); //CHECK_NON_NULL(args, void); //CHECK_NON_NULL(value, void); diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 2f67cb72a..6d8ff3b35 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1732,11 +1732,11 @@ namespace z3 { unsigned num_entries() const { unsigned r = Z3_func_interp_get_num_entries(ctx(), m_interp); check_error(); return r; } func_entry entry(unsigned i) const { Z3_func_entry e = Z3_func_interp_get_entry(ctx(), m_interp, i); check_error(); return func_entry(ctx(), e); } void add_entry(expr_vector const& args, expr& value) { - Z3_add_func_entry(ctx(), m_interp, args, value); + Z3_func_interp_add_entry(ctx(), m_interp, args, value); check_error(); } void set_else(expr& value) { - Z3_func_entry_set_else(ctx(), m_interp, value); + Z3_func_interp_set_else(ctx(), m_interp, value); check_error(); } }; diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 045417d38..bed70cb6c 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -4954,9 +4954,9 @@ extern "C" { If an two entries are added with the same arguments, only the second insertion survives and the first inserted entry is removed. - def_API('Z3_add_func_entry', VOID, (_in(CONTEXT), _in(FUNC_INTERP), _in(AST_VECTOR), _in(AST))) + def_API('Z3_func_interp_add_entry', VOID, (_in(CONTEXT), _in(FUNC_INTERP), _in(AST_VECTOR), _in(AST))) */ - void Z3_API Z3_add_func_entry(Z3_context c, Z3_func_interp fi, Z3_ast_vector args, Z3_ast value); + void Z3_API Z3_func_interp_add_entry(Z3_context c, Z3_func_interp fi, Z3_ast_vector args, Z3_ast value); /** \brief Increment the reference counter of the given Z3_func_entry object. From 9e4b2a67959fa09cbfb7e09abea81c0d88d255af Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Mon, 28 Aug 2017 02:55:50 -0700 Subject: [PATCH 36/74] port simplifications on bv2int Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/rewriter/bv_rewriter.cpp | 79 +++++++++++++++++++++++++++++++- src/ast/rewriter/bv_rewriter.h | 5 ++ 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index edd601c9c..75f931c1d 100644 --- a/src/ast/rewriter/bv_rewriter.cpp +++ b/src/ast/rewriter/bv_rewriter.cpp @@ -1365,13 +1365,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 45bd6c264..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<decl_kind>(UINT_MAX); } + public: bv_rewriter_core(ast_manager & m):m_util(m) {} }; @@ -108,6 +109,10 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> { 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); From f20e95184ee6532d7a538886c46cf6ad02ee9733 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Mon, 28 Aug 2017 13:29:51 -0700 Subject: [PATCH 37/74] remove old_simplify dependencies Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/CMakeLists.txt | 3 - src/ast/simplifier/CMakeLists.txt | 9 +- src/ast/simplifier/array_simplifier_params.h | 6 +- src/ast/simplifier/bv_simplifier_params.cpp | 2 +- src/ast/simplifier/maximise_ac_sharing.cpp | 192 ------------------- src/ast/simplifier/maximise_ac_sharing.h | 124 ------------ src/smt/params/CMakeLists.txt | 1 - src/smt/params/preprocessor_params.cpp | 4 - src/smt/params/preprocessor_params.h | 6 +- src/smt/params/theory_arith_params.cpp | 2 + src/smt/params/theory_arith_params.h | 4 + src/smt/params/theory_array_params.h | 8 +- src/smt/params/theory_bv_params.cpp | 6 +- src/smt/params/theory_bv_params.h | 2 + 14 files changed, 26 insertions(+), 343 deletions(-) delete mode 100644 src/ast/simplifier/maximise_ac_sharing.cpp delete mode 100644 src/ast/simplifier/maximise_ac_sharing.h 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/ast/simplifier/CMakeLists.txt b/src/ast/simplifier/CMakeLists.txt index 649c0486e..37d96b1a5 100644 --- a/src/ast/simplifier/CMakeLists.txt +++ b/src/ast/simplifier/CMakeLists.txt @@ -2,11 +2,11 @@ z3_add_component(simplifier SOURCES arith_simplifier_params.cpp # arith_simplifier_plugin.cpp - array_simplifier_params.cpp +# array_simplifier_params.cpp # array_simplifier_plugin.cpp # basic_simplifier_plugin.cpp # bv_elim.cpp - bv_simplifier_params.cpp +# bv_simplifier_params.cpp # bv_simplifier_plugin.cpp # datatype_simplifier_plugin.cpp # elim_bounds.cpp @@ -18,8 +18,5 @@ z3_add_component(simplifier # 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/array_simplifier_params.h b/src/ast/simplifier/array_simplifier_params.h index 559e3de54..07ead5fd6 100644 --- a/src/ast/simplifier/array_simplifier_params.h +++ b/src/ast/simplifier/array_simplifier_params.h @@ -21,11 +21,9 @@ Revision History: #include "util/params.h" -struct array_simplifier_params { - bool m_array_canonize_simplify; - bool m_array_simplify; // temporary hack for disabling array simplifier plugin. +struct array_simplifier_params1 { - array_simplifier_params(params_ref const & p = params_ref()) { + array_simplifier_params1(params_ref const & p = params_ref()) { updt_params(p); } diff --git a/src/ast/simplifier/bv_simplifier_params.cpp b/src/ast/simplifier/bv_simplifier_params.cpp index 4c6b4a5fa..07f854179 100644 --- a/src/ast/simplifier/bv_simplifier_params.cpp +++ b/src/ast/simplifier/bv_simplifier_params.cpp @@ -33,4 +33,4 @@ void bv_simplifier_params::updt_params(params_ref const & _p) { 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/maximise_ac_sharing.cpp b/src/ast/simplifier/maximise_ac_sharing.cpp deleted file mode 100644 index 93e5a43f0..000000000 --- a/src/ast/simplifier/maximise_ac_sharing.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - maximise_ac_sharing.cpp - -Abstract: - - <abstract> - -Author: - - Leonardo de Moura (leonardo) 2008-10-22. - -Revision History: - ---*/ - -#include "ast/simplifier/maximise_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) { - 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) { - decl_kind k = f->get_kind(); - if (!f->is_associative()) - return false; - if (num_args <= 2) - return false; - if (std::find(m_kinds.begin(), m_kinds.end(), k) == m_kinds.end()) - return false; - ptr_buffer<expr, 128> _args; - expr * numeral = 0; - if (m_owner.is_numeral(args[0])) { - numeral = args[0]; - for (unsigned i = 1; i < num_args; i++) - _args.push_back(args[i]); - num_args--; - } - else { - _args.append(num_args, args); - } - - TRACE("ac_sharing_detail", tout << "before-reuse: num_args: " << num_args << "\n";); - -#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";); - 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])) { - TRACE("ac_sharing_detail", tout << "reusing args: " << i << " " << j << "\n";); - _args[i] = m_manager.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]; - } - num_args--; - goto try_to_reuse; - } - } - } - } - - - // Create "tree-like circuit" - while (true) { - TRACE("ac_sharing_detail", tout << "tree-loop: num_args: " << num_args << "\n";); - unsigned j = 0; - for (unsigned i = 0; i < num_args; i += 2, j++) { - if (i == num_args - 1) { - _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]); - } - } - num_args = j; - if (num_args == 1) { - if (numeral == 0) { - result = _args[0]; - } - else { - result = m_manager.mk_app(f, numeral, _args[0]); - } - TRACE("ac_sharing_detail", tout << "result: " << mk_pp(result, m_manager) << "\n";); - return true; - } - } - - UNREACHABLE(); - return false; -} - -bool maximise_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) { - 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); -} - -maximise_ac_sharing::maximise_ac_sharing(ast_manager & m): - m_manager(m), - m_simplifier(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() { - 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() { - init(); - m_scopes.push_back(m_entries.size()); - m_region.push_scope(); -} - -void maximise_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]; - restore_entries(old_lim); - m_region.pop_scope(num_scopes); - m_scopes.shrink(new_lvl); -} - -void maximise_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_entries.shrink(old_lim); -} - -void maximise_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); -} - -bool maximise_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), - m_util(m) { -} diff --git a/src/ast/simplifier/maximise_ac_sharing.h b/src/ast/simplifier/maximise_ac_sharing.h deleted file mode 100644 index cf488e20d..000000000 --- a/src/ast/simplifier/maximise_ac_sharing.h +++ /dev/null @@ -1,124 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - maximise_ac_sharing.h - -Abstract: - - <abstract> - -Author: - - Leonardo de Moura (leonardo) 2008-10-22. - -Revision History: - ---*/ -#ifndef MAXIMISE_AC_SHARING_H_ -#define MAXIMISE_AC_SHARING_H_ - -#include "ast/simplifier/simplifier.h" -#include "util/hashtable.h" -#include "ast/bv_decl_plugin.h" -#include "util/region.h" - -/** - \brief Functor used to maximise the amount of shared terms in an expression. - The idea is to rewrite AC terms to maximise sharing. - Example: - - (f (bvadd a (bvadd b c)) (bvadd a (bvadd b d))) - - is rewritten to: - - (f (bvadd (bvadd a b) c) (bvadd (bvadd a b) d)) - - \warning This class uses an opportunistic heuristic to maximise sharing. - There is no guarantee that the optimal expression will be produced. -*/ -class maximise_ac_sharing { - - struct entry { - func_decl * m_decl; - expr * m_arg1; - expr * m_arg2; - - entry(func_decl * d = 0, expr * arg1 = 0, expr * arg2 = 0):m_decl(d), m_arg1(arg1), m_arg2(arg2) { - SASSERT((d == 0 && arg1 == 0 && arg2 == 0) || (d != 0 && arg1 != 0 && arg2 != 0)); - if (arg1->get_id() > arg2->get_id()) - std::swap(m_arg1, m_arg2); - } - - unsigned hash() const { - unsigned a = m_decl->get_id(); - unsigned b = m_arg1->get_id(); - unsigned c = m_arg2->get_id(); - mix(a,b,c); - return c; - } - - bool operator==(entry const & e) const { - return m_decl == e.m_decl && m_arg1 == e.m_arg1 && m_arg2 == e.m_arg2; - } - }; - - typedef ptr_hashtable<entry, obj_ptr_hash<entry>, deref_eq<entry> > cache; - -protected: - class ac_plugin : public simplifier_plugin { - maximise_ac_sharing & m_owner; - svector<decl_kind> m_kinds; //!< kinds to be processed - public: - ac_plugin(symbol const & fname, ast_manager & m, maximise_ac_sharing & owner); - void register_kind(decl_kind k); - virtual ~ac_plugin(); - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - }; - - friend class ac_plugin; - -private: - ast_manager & m_manager; - simplifier m_simplifier; - bool m_init; - region m_region; - cache m_cache; - ptr_vector<entry> m_entries; - unsigned_vector m_scopes; - - bool contains(func_decl * f, expr * arg1, expr * arg2); - void insert(func_decl * f, expr * arg1, expr * arg2); - void restore_entries(unsigned old_lim); - void init() { - if (!m_init) { - init_core(); - m_init = true; - } - } -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); - void push_scope(); - void pop_scope(unsigned num_scopes); - void reset(); - ast_manager & get_manager() { return m_manager; } -}; - -class maximise_bv_sharing : public maximise_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); -}; - -#endif /* MAXIMISE_AC_SHARING_H_ */ - 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 afca0196a..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,8 +38,6 @@ 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); diff --git a/src/smt/params/preprocessor_params.h b/src/smt/params/preprocessor_params.h index 6f763c0e1..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,9 +29,7 @@ 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; diff --git a/src/smt/params/theory_arith_params.cpp b/src/smt/params/theory_arith_params.cpp index 2b5a14493..ab80f0c67 100644 --- a/src/smt/params/theory_arith_params.cpp +++ b/src/smt/params/theory_arith_params.cpp @@ -42,6 +42,8 @@ void theory_arith_params::updt_params(params_ref const & _p) { #define DISPLAY_PARAM(X) out << #X"=" << X << std::endl; void theory_arith_params::display(std::ostream & out) const { + DISPLAY_PARAM(m_arith_expand_eqs); + 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..89c4fe46c 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_expand_eqs; + 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_expand_eqs(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), From 597f77cd7766a439d64cff22cc8f1950d00eb450 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Mon, 28 Aug 2017 20:03:31 -0700 Subject: [PATCH 38/74] initial sketch for dominator based simplifiation Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- scripts/mk_project.py | 15 +- src/tactic/core/dom_simplify_tactic.cpp | 348 ++++++++++++++++++++++++ 2 files changed, 354 insertions(+), 9 deletions(-) create mode 100644 src/tactic/core/dom_simplify_tactic.cpp 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/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp new file mode 100644 index 000000000..b4c0b6d82 --- /dev/null +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -0,0 +1,348 @@ +/*++ +Copyright (c) 2017 Microsoft Corporation + +Module Name: + + dom_simplify_tactic.cpp + +Abstract: + + Dominator-based context simplifer. + +Author: + + Nikolaj and Nuno + +Notes: + +--*/ + +#if 0 + +#include "ast/ast.h" + +class expr_dominators { +public: + typedef obj_map<expr, ptr_vector<expr>> tree_t; +private: + ast_manager& m; + expr_ref m_root; + obj_map<unsigned> m_expr2post; // reverse post-order number + ptr_vector<expr> m_post2expr; + tree_t m_parents; + obj_map<expr, expr*> m_doms; + tree_t m_tree; + + void add_edge(tree_t& tree, expr * src, expr* dst) { + tree.insert_if_not_there(src, ptr_vector<expr>()).push_back(dst); + } + + /** + \brief compute a post-order traversal for e. + Also populate the set of parents + */ + void compute_post_order() { + unsigned post_num = 0; + SASSERT(m_post2expr.empty()); + SASSERT(m_expr2post.empty()); + ast_mark mark; + ptr_vector<expr> todo; + todo.push_back(m_root); + while (!todo.empty()) { + expr* e = todo.back(); + if (is_marked(e)) { + todo.pop_back(); + continue; + } + if (is_app(e)) { + app* a = to_app(e); + bool done = true; + for (expr* arg : *a) { + if (!is_marked(arg)) { + todo.push_back(arg); + done = false; + } + } + if (done) { + mark.mark(e); + m_expr2post.insert(e, post_num++); + m_post2expr.push_back(e); + todo.pop_back(); + for (expr* arg : *a) { + add_edge(m_parents, a, arg); + } + } + } + else { + todo.pop_back(); + } + } + } + + expr* intersect(expr* x, expr * y) { + unsigned n1 = m_expr2post[x]; + unsigned n2 = m_expr2post[y]; + while (n1 != n2) { + if (n1 < n2) + n1 = m_doms[n1]; + else if (n1 > n2) + n2 = m_doms[n2]; + } + return n1; + } + + void 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<expr> 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); + } + } + } + } + + void extract_tree() { + for (auto const& kv : m_doms) { + expr * child = kv.m_key; + for (expr * parent : kv.m_value) { + add_edge(m_tree, parent, child); + } + } + } + + void reset() { + m_expr2post.reset(); + m_post2expr.reset(); + m_parents.reset(); + m_doms.reset(); + m_tree.reset(); + m_root.reset(); + } + + +public: + expr_dominators(ast_manager& m): m(m), m_root(m) {} + + void compile(expr * e) { + reset(); + m_root = e; + compute_post_order(); + compute_dominators(); + extract_tree(); + } + + void compile(unsigned sz, expr * const* es) { + expr_ref e(m.mk_and(sz, es), m); + compile(e); + } + + tree_t const& get_tree() { return m_tree; } + +}; + +// goes to header file: + +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; + }; +private: + simplifier& m_simplifier; + params_ref m_params; + expr_ref_vector m_trail; + obj_map<expr, expr*> m_result; + expr_dominators m_dominators; + + 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); + + expr_ref get_cache(expr* t) { 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); } + + void simplify_goal(goal_ref& g); + +public: + dom_simplify_tactic(ast_manager & m, simplifier& s, params_ref const & p = params_ref()); + + virtual tactic * translate(ast_manager & m); + + virtual ~dom_simplify_tactic(); + + 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(); +}; + +// implementation: + +expr_ref dom_simplifier_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 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_simplifier_tactic::simplify(expr * e0) { + expr_ref r(m); + expr* e = 0; + if (!m_result.find(e0, e)) { + e = e0; + } + + 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 { + tree_t const& t = m_dominators.get_tree(); + if (t.contains(e)) { + ptr_vector<expr> 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)); + } + 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); + return r; +} + +expr_ref dom_simplifier_tactic::simplify_or_and(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_simplifier_tactic::simplify_goal(goal& g) { + expr_ref_vector args(m); + expr_ref fml(m); + for (unsigned i = 0; i < sz; ++i) args.push_back(g.form(i)); + fml = mk_and(args); + expr_ref tmp(fml); + // TBD: deal with dependencies. + do { + m_result.reset(); + m_trail.reset(); + m_dominators.compile(fml); +#if 0 + for (unsigned i = 0; i < sz; ++i) { + r = simplify(g.form(i)); + // TBD: simplfy goal as a conjuction ? + // + } +#endif + tmp = fml; + fml = simplify(fml); + } + while (tmp != fml); + //g.reset(); + //g.add(fml); +} + + +#endif From 8d8e4cbc513dd7171fd3e1439f38d4bdeb214b63 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Mon, 28 Aug 2017 20:11:46 -0700 Subject: [PATCH 39/74] fix some basic mistakes in dominator code Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/tactic/core/dom_simplify_tactic.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index b4c0b6d82..3b444ef1a 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -69,7 +69,7 @@ private: m_post2expr.push_back(e); todo.pop_back(); for (expr* arg : *a) { - add_edge(m_parents, a, arg); + add_edge(m_parents, arg, a); } } } @@ -83,12 +83,17 @@ private: unsigned n1 = m_expr2post[x]; unsigned n2 = m_expr2post[y]; while (n1 != n2) { - if (n1 < n2) - n1 = m_doms[n1]; - else if (n1 > n2) - n2 = m_doms[n2]; + if (n1 < n2) { + x = m_doms[x]; + n1 = m_expr2post[x]; + } + else if (n1 > n2) { + y = m_doms[y]; + n2 = m_expr2post[y]; + } } - return n1; + SASSERT(x == y); + return x; } void compute_dominators() { @@ -111,6 +116,7 @@ private: } if (!m_doms.find(child, idom2) || idom2 != new_idom) { m_doms.insert(child, new_idom); + change = true; } } } @@ -118,10 +124,7 @@ private: void extract_tree() { for (auto const& kv : m_doms) { - expr * child = kv.m_key; - for (expr * parent : kv.m_value) { - add_edge(m_tree, parent, child); - } + add_edge(m_tree, kv.m_value, kv.m_key); } } From cf87b6d622d8cb71b4dff4a3cbd034dccbaddcbf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Tue, 29 Aug 2017 09:22:27 -0700 Subject: [PATCH 40/74] remove simplifier files Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/macros/macro_util.cpp | 2 - src/ast/simplifier/CMakeLists.txt | 22 - src/ast/simplifier/README | 2 - .../simplifier/arith_simplifier_params.cpp | 33 - src/ast/simplifier/arith_simplifier_params.h | 38 - .../arith_simplifier_params_helper.pyg | 7 - .../simplifier/arith_simplifier_plugin.cpp | 449 ---- src/ast/simplifier/arith_simplifier_plugin.h | 96 - .../simplifier/array_simplifier_params.cpp | 26 - src/ast/simplifier/array_simplifier_params.h | 34 - .../array_simplifier_params_helper.pyg | 6 - .../simplifier/array_simplifier_plugin.cpp | 877 ------- src/ast/simplifier/array_simplifier_plugin.h | 154 -- src/ast/simplifier/base_simplifier.h | 76 - .../simplifier/basic_simplifier_plugin.cpp | 147 -- src/ast/simplifier/basic_simplifier_plugin.h | 78 - src/ast/simplifier/bv_elim.cpp | 119 - src/ast/simplifier/bv_elim.h | 45 - src/ast/simplifier/bv_simplifier_params.cpp | 36 - src/ast/simplifier/bv_simplifier_params.h | 38 - .../bv_simplifier_params_helper.pyg | 4 - src/ast/simplifier/bv_simplifier_plugin.cpp | 2261 ----------------- src/ast/simplifier/bv_simplifier_plugin.h | 187 -- .../simplifier/datatype_simplifier_plugin.cpp | 115 - .../simplifier/datatype_simplifier_plugin.h | 42 - src/ast/simplifier/elim_bounds.cpp | 224 -- src/ast/simplifier/elim_bounds.h | 69 - src/ast/simplifier/fpa_simplifier_plugin.cpp | 39 - src/ast/simplifier/fpa_simplifier_plugin.h | 39 - src/ast/simplifier/poly_simplifier_plugin.cpp | 835 ------ src/ast/simplifier/poly_simplifier_plugin.h | 155 -- src/ast/simplifier/seq_simplifier_plugin.cpp | 39 - src/ast/simplifier/seq_simplifier_plugin.h | 39 - src/ast/simplifier/simplifier.cpp | 962 ------- src/ast/simplifier/simplifier.h | 232 -- src/ast/simplifier/simplifier_plugin.cpp | 46 - src/ast/simplifier/simplifier_plugin.h | 94 - src/muz/pdr/pdr_util.cpp | 27 +- src/muz/rel/dl_bound_relation.h | 1 - src/muz/rel/dl_interval_relation.h | 5 +- src/muz/spacer/spacer_legacy_mbp.cpp | 3 - src/smt/arith_eq_adapter.h | 1 - src/smt/theory_arith.h | 1 - src/smt/theory_arith_int.h | 7 +- 44 files changed, 17 insertions(+), 7695 deletions(-) delete mode 100644 src/ast/simplifier/CMakeLists.txt delete mode 100644 src/ast/simplifier/README delete mode 100644 src/ast/simplifier/arith_simplifier_params.cpp delete mode 100644 src/ast/simplifier/arith_simplifier_params.h delete mode 100644 src/ast/simplifier/arith_simplifier_params_helper.pyg delete mode 100644 src/ast/simplifier/arith_simplifier_plugin.cpp delete mode 100644 src/ast/simplifier/arith_simplifier_plugin.h delete mode 100644 src/ast/simplifier/array_simplifier_params.cpp delete mode 100644 src/ast/simplifier/array_simplifier_params.h delete mode 100644 src/ast/simplifier/array_simplifier_params_helper.pyg delete mode 100644 src/ast/simplifier/array_simplifier_plugin.cpp delete mode 100644 src/ast/simplifier/array_simplifier_plugin.h delete mode 100644 src/ast/simplifier/base_simplifier.h delete mode 100644 src/ast/simplifier/basic_simplifier_plugin.cpp delete mode 100644 src/ast/simplifier/basic_simplifier_plugin.h delete mode 100644 src/ast/simplifier/bv_elim.cpp delete mode 100644 src/ast/simplifier/bv_elim.h delete mode 100644 src/ast/simplifier/bv_simplifier_params.cpp delete mode 100644 src/ast/simplifier/bv_simplifier_params.h delete mode 100644 src/ast/simplifier/bv_simplifier_params_helper.pyg delete mode 100644 src/ast/simplifier/bv_simplifier_plugin.cpp delete mode 100644 src/ast/simplifier/bv_simplifier_plugin.h delete mode 100644 src/ast/simplifier/datatype_simplifier_plugin.cpp delete mode 100644 src/ast/simplifier/datatype_simplifier_plugin.h delete mode 100644 src/ast/simplifier/elim_bounds.cpp delete mode 100644 src/ast/simplifier/elim_bounds.h delete mode 100644 src/ast/simplifier/fpa_simplifier_plugin.cpp delete mode 100644 src/ast/simplifier/fpa_simplifier_plugin.h delete mode 100644 src/ast/simplifier/poly_simplifier_plugin.cpp delete mode 100644 src/ast/simplifier/poly_simplifier_plugin.h delete mode 100644 src/ast/simplifier/seq_simplifier_plugin.cpp delete mode 100644 src/ast/simplifier/seq_simplifier_plugin.h delete mode 100644 src/ast/simplifier/simplifier.cpp delete mode 100644 src/ast/simplifier/simplifier.h delete mode 100644 src/ast/simplifier/simplifier_plugin.cpp delete mode 100644 src/ast/simplifier/simplifier_plugin.h diff --git a/src/ast/macros/macro_util.cpp b/src/ast/macros/macro_util.cpp index 6bc1ee66e..55c5436e4 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" diff --git a/src/ast/simplifier/CMakeLists.txt b/src/ast/simplifier/CMakeLists.txt deleted file mode 100644 index 37d96b1a5..000000000 --- a/src/ast/simplifier/CMakeLists.txt +++ /dev/null @@ -1,22 +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 -# bv_elim.cpp -# bv_simplifier_params.cpp -# bv_simplifier_plugin.cpp -# datatype_simplifier_plugin.cpp -# elim_bounds.cpp -# fpa_simplifier_plugin.cpp -# maximise_ac_sharing.cpp -# poly_simplifier_plugin.cpp -# seq_simplifier_plugin.cpp -# simplifier.cpp -# simplifier_plugin.cpp - COMPONENT_DEPENDENCIES - rewriter - -) 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: - - <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: - - <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 bfe72b232..000000000 --- a/src/ast/simplifier/arith_simplifier_plugin.cpp +++ /dev/null @@ -1,449 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - arith_simplifier_plugin.cpp - -Abstract: - - Simplifier for the arithmetic family. - -Author: - - Leonardo (leonardo) 2008-01-08 - ---*/ -#include "ast/simplifier/arith_simplifier_plugin.h" -#include "ast/ast_pp.h" -#include "ast/ast_ll_pp.h" -#include "ast/ast_smt2_pp.h" - -arith_simplifier_plugin::~arith_simplifier_plugin() { -} - -arith_simplifier_plugin::arith_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, arith_simplifier_params & p): - poly_simplifier_plugin(symbol("arith"), m, OP_ADD, OP_MUL, OP_UMINUS, OP_SUB, OP_NUM), - m_params(p), - m_util(m), - m_bsimp(b), - m_int_zero(m), - m_real_zero(m) { - m_int_zero = m_util.mk_numeral(rational(0), true); - m_real_zero = m_util.mk_numeral(rational(0), false); -} - -/** - \brief Return true if the first monomial of t is negative. -*/ -bool arith_simplifier_plugin::is_neg_poly(expr * t) const { - if (m_util.is_add(t)) { - t = to_app(t)->get_arg(0); - } - if (m_util.is_mul(t)) { - t = to_app(t)->get_arg(0); - rational r; - if (is_numeral(t, r)) - return r.is_neg(); - } - return false; -} - -void arith_simplifier_plugin::get_monomial_gcd(expr_ref_vector& monomials, numeral& g) { - g = numeral::zero(); - numeral n; - for (unsigned i = 0; !g.is_one() && i < monomials.size(); ++i) { - expr* e = monomials[i].get(); - if (is_numeral(e, n)) { - g = gcd(abs(n), g); - } - else if (is_mul(e) && is_numeral(to_app(e)->get_arg(0), n)) { - g = gcd(abs(n), g); - } - else { - g = numeral::one(); - return; - } - } - if (g.is_zero()) { - g = numeral::one(); - } -} - -void arith_simplifier_plugin::div_monomial(expr_ref_vector& monomials, numeral const& g) { - numeral n; - for (unsigned i = 0; i < monomials.size(); ++i) { - expr* e = monomials[i].get(); - if (is_numeral(e, n)) { - SASSERT((n/g).is_int()); - monomials[i] = mk_numeral(n/g); - } - else if (is_mul(e) && is_numeral(to_app(e)->get_arg(0), n)) { - SASSERT((n/g).is_int()); - monomials[i] = mk_mul(n/g, to_app(e)->get_arg(1)); - } - else { - UNREACHABLE(); - } - } -} - -void arith_simplifier_plugin::gcd_reduce_monomial(expr_ref_vector& monomials, numeral& k) { - numeral g, n; - - get_monomial_gcd(monomials, g); - g = gcd(abs(k), g); - - if (g.is_one()) { - return; - } - SASSERT(g.is_pos()); - - k = k / g; - div_monomial(monomials, g); - -} - -template<arith_simplifier_plugin::op_kind Kind> -void arith_simplifier_plugin::mk_le_ge_eq_core(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - bool is_int = m_curr_sort->get_decl_kind() == INT_SORT; - expr_ref_vector monomials(m_manager); - rational k; - TRACE("arith_eq_bug", tout << mk_ismt2_pp(arg1, m_manager) << "\n" << mk_ismt2_pp(arg2, m_manager) << "\n";); - process_sum_of_monomials(false, arg1, monomials, k); - process_sum_of_monomials(true, arg2, monomials, k); - k.neg(); - if (is_int) { - numeral g; - get_monomial_gcd(monomials, g); - if (!g.is_one()) { - div_monomial(monomials, g); - switch(Kind) { - case LE: - // - // g*monmials' <= k - // <=> - // monomials' <= floor(k/g) - // - k = floor(k/g); - break; - case GE: - // - // g*monmials' >= k - // <=> - // monomials' >= ceil(k/g) - // - k = ceil(k/g); - break; - case EQ: - k = k/g; - if (!k.is_int()) { - result = m_manager.mk_false(); - return; - } - break; - } - } - } - expr_ref lhs(m_manager); - mk_sum_of_monomials(monomials, lhs); - if (m_util.is_numeral(lhs)) { - SASSERT(lhs == mk_zero()); - if (( Kind == LE && numeral::zero() <= k) || - ( Kind == GE && numeral::zero() >= k) || - ( Kind == EQ && numeral::zero() == k)) - result = m_manager.mk_true(); - else - result = m_manager.mk_false(); - } - else { - - if (is_neg_poly(lhs)) { - expr_ref neg_lhs(m_manager); - mk_uminus(lhs, neg_lhs); - lhs = neg_lhs; - k.neg(); - expr * rhs = m_util.mk_numeral(k, is_int); - switch (Kind) { - case LE: - result = m_util.mk_ge(lhs, rhs); - break; - case GE: - result = m_util.mk_le(lhs, rhs); - break; - case EQ: - result = m_manager.mk_eq(lhs, rhs); - break; - } - } - else { - expr * rhs = m_util.mk_numeral(k, is_int); - switch (Kind) { - case LE: - result = m_util.mk_le(lhs, rhs); - break; - case GE: - result = m_util.mk_ge(lhs, rhs); - break; - case EQ: - result = m_manager.mk_eq(lhs, rhs); - break; - } - } - } -} - -void arith_simplifier_plugin::mk_arith_eq(expr * arg1, expr * arg2, expr_ref & result) { - mk_le_ge_eq_core<EQ>(arg1, arg2, result); -} - -void arith_simplifier_plugin::mk_le(expr * arg1, expr * arg2, expr_ref & result) { - mk_le_ge_eq_core<LE>(arg1, arg2, result); -} - -void arith_simplifier_plugin::mk_ge(expr * arg1, expr * arg2, expr_ref & result) { - mk_le_ge_eq_core<GE>(arg1, arg2, result); -} - -void arith_simplifier_plugin::mk_lt(expr * arg1, expr * arg2, expr_ref & result) { - expr_ref tmp(m_manager); - mk_le(arg2, arg1, tmp); - m_bsimp.mk_not(tmp, result); -} - -void arith_simplifier_plugin::mk_gt(expr * arg1, expr * arg2, expr_ref & result) { - expr_ref tmp(m_manager); - mk_le(arg1, arg2, tmp); - m_bsimp.mk_not(tmp, result); -} - -void arith_simplifier_plugin::gcd_normalize(numeral & coeff, expr_ref& term) { - if (!abs(coeff).is_one()) { - set_curr_sort(term); - SASSERT(m_curr_sort->get_decl_kind() == INT_SORT); - expr_ref_vector monomials(m_manager); - rational k; - monomials.push_back(mk_numeral(numeral(coeff), true)); - process_sum_of_monomials(false, term, monomials, k); - gcd_reduce_monomial(monomials, k); - numeral coeff1; - if (!is_numeral(monomials[0].get(), coeff1)) { - UNREACHABLE(); - } - if (coeff1 == coeff) { - return; - } - monomials[0] = mk_numeral(k, true); - coeff = coeff1; - mk_sum_of_monomials(monomials, term); - } -} - - -void arith_simplifier_plugin::mk_div(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) { - SASSERT(!is_int); - if (m_util.is_numeral(arg1, v1, is_int)) - result = m_util.mk_numeral(v1/v2, false); - else { - numeral k(1); - k /= v2; - - expr_ref inv_arg2(m_util.mk_numeral(k, false), m_manager); - mk_mul(inv_arg2, arg1, result); - } - } - else - result = m_util.mk_div(arg1, arg2); -} - -void arith_simplifier_plugin::mk_idiv(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) - result = m_util.mk_numeral(div(v1, v2), is_int); - else - result = m_util.mk_idiv(arg1, arg2); -} - -void arith_simplifier_plugin::prop_mod_const(expr * e, unsigned depth, numeral const& k, expr_ref& result) { - SASSERT(m_util.is_int(e)); - SASSERT(k.is_int() && k.is_pos()); - numeral n; - bool is_int; - - if (depth == 0) { - result = e; - } - else if (is_add(e) || is_mul(e)) { - expr_ref_vector args(m_manager); - expr_ref tmp(m_manager); - app* a = to_app(e); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - prop_mod_const(a->get_arg(i), depth - 1, k, tmp); - args.push_back(tmp); - } - reduce(a->get_decl(), args.size(), args.c_ptr(), result); - } - else if (m_util.is_numeral(e, n, is_int) && is_int) { - result = mk_numeral(mod(n, k), true); - } - else { - result = e; - } -} - -void arith_simplifier_plugin::mk_mod(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) { - result = m_util.mk_numeral(mod(v1, v2), is_int); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_one()) { - result = m_util.mk_numeral(numeral(0), true); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_pos()) { - expr_ref tmp(m_manager); - prop_mod_const(arg1, 5, v2, tmp); - result = m_util.mk_mod(tmp, arg2); - } - else { - result = m_util.mk_mod(arg1, arg2); - } -} - -void arith_simplifier_plugin::mk_rem(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) { - numeral m = mod(v1, v2); - // - // rem(v1,v2) = if v2 >= 0 then mod(v1,v2) else -mod(v1,v2) - // - if (v2.is_neg()) { - m.neg(); - } - result = m_util.mk_numeral(m, is_int); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_one()) { - result = m_util.mk_numeral(numeral(0), true); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && !v2.is_zero()) { - expr_ref tmp(m_manager); - prop_mod_const(arg1, 5, v2, tmp); - result = m_util.mk_mod(tmp, arg2); - if (v2.is_neg()) { - result = m_util.mk_uminus(result); - } - } - else { - result = m_util.mk_rem(arg1, arg2); - } -} - -void arith_simplifier_plugin::mk_to_real(expr * arg, expr_ref & result) { - numeral v; - if (m_util.is_numeral(arg, v)) - result = m_util.mk_numeral(v, false); - else - result = m_util.mk_to_real(arg); -} - -void arith_simplifier_plugin::mk_to_int(expr * arg, expr_ref & result) { - numeral v; - if (m_util.is_numeral(arg, v)) - result = m_util.mk_numeral(floor(v), true); - else if (m_util.is_to_real(arg)) - result = to_app(arg)->get_arg(0); - else - result = m_util.mk_to_int(arg); -} - -void arith_simplifier_plugin::mk_is_int(expr * arg, expr_ref & result) { - numeral v; - if (m_util.is_numeral(arg, v)) - result = v.is_int()?m_manager.mk_true():m_manager.mk_false(); - else if (m_util.is_to_real(arg)) - result = m_manager.mk_true(); - else - result = m_util.mk_is_int(arg); -} - -bool arith_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - SASSERT(f->get_family_id() == m_fid); - TRACE("arith_simplifier_plugin", tout << mk_pp(f, m_manager) << "\n"; - for (unsigned i = 0; i < num_args; i++) tout << mk_pp(args[i], m_manager) << "\n";); - arith_op_kind k = static_cast<arith_op_kind>(f->get_decl_kind()); - switch (k) { - case OP_NUM: return false; - case OP_LE: if (m_presimp) return false; SASSERT(num_args == 2); mk_le(args[0], args[1], result); break; - case OP_GE: if (m_presimp) return false; SASSERT(num_args == 2); mk_ge(args[0], args[1], result); break; - case OP_LT: if (m_presimp) return false; SASSERT(num_args == 2); mk_lt(args[0], args[1], result); break; - case OP_GT: if (m_presimp) return false; SASSERT(num_args == 2); mk_gt(args[0], args[1], result); break; - case OP_ADD: mk_add(num_args, args, result); break; - case OP_SUB: mk_sub(num_args, args, result); break; - case OP_UMINUS: SASSERT(num_args == 1); mk_uminus(args[0], result); break; - case OP_MUL: - mk_mul(num_args, args, result); - TRACE("arith_simplifier_plugin", tout << mk_pp(result, m_manager) << "\n";); - break; - case OP_DIV: SASSERT(num_args == 2); mk_div(args[0], args[1], result); break; - case OP_IDIV: SASSERT(num_args == 2); mk_idiv(args[0], args[1], result); break; - case OP_REM: SASSERT(num_args == 2); mk_rem(args[0], args[1], result); break; - case OP_MOD: SASSERT(num_args == 2); mk_mod(args[0], args[1], result); break; - case OP_TO_REAL: SASSERT(num_args == 1); mk_to_real(args[0], result); break; - case OP_TO_INT: SASSERT(num_args == 1); mk_to_int(args[0], result); break; - case OP_IS_INT: SASSERT(num_args == 1); mk_is_int(args[0], result); break; - case OP_POWER: return false; - 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_abs(expr * arg, expr_ref & result) { - expr_ref c(m_manager); - expr_ref m_arg(m_manager); - mk_uminus(arg, m_arg); - mk_ge(arg, m_util.mk_numeral(rational(0), m_util.is_int(arg)), c); - m_bsimp.mk_ite(c, arg, m_arg, result); -} - -bool arith_simplifier_plugin::is_arith_term(expr * n) const { - return n->get_kind() == AST_APP && to_app(n)->get_family_id() == m_fid; -} - -bool arith_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { - TRACE("reduce_eq_bug", tout << mk_ismt2_pp(lhs, m_manager) << "\n" << mk_ismt2_pp(rhs, m_manager) << "\n";); - set_reduce_invoked(); - if (m_presimp) { - return false; - } - if (m_params.m_arith_expand_eqs) { - expr_ref le(m_manager), ge(m_manager); - mk_le_ge_eq_core<LE>(lhs, rhs, le); - mk_le_ge_eq_core<GE>(lhs, rhs, ge); - m_bsimp.mk_and(le, ge, result); - return true; - } - - if (m_params.m_arith_process_all_eqs || is_arith_term(lhs) || is_arith_term(rhs)) { - mk_arith_eq(lhs, rhs, result); - return true; - } - return false; -} - - - diff --git a/src/ast/simplifier/arith_simplifier_plugin.h b/src/ast/simplifier/arith_simplifier_plugin.h deleted file mode 100644 index 21ab8f6b4..000000000 --- a/src/ast/simplifier/arith_simplifier_plugin.h +++ /dev/null @@ -1,96 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - arith_simplifier_plugin.h - -Abstract: - - Simplifier for the arithmetic family. - -Author: - - Leonardo (leonardo) 2008-01-08 - ---*/ -#ifndef ARITH_SIMPLIFIER_PLUGIN_H_ -#define ARITH_SIMPLIFIER_PLUGIN_H_ - -#include "ast/simplifier/basic_simplifier_plugin.h" -#include "ast/simplifier/poly_simplifier_plugin.h" -#include "ast/arith_decl_plugin.h" -#include "ast/simplifier/arith_simplifier_params.h" - -/** - \brief Simplifier for the arith family. -*/ -class arith_simplifier_plugin : public poly_simplifier_plugin { -public: - enum op_kind { - LE, GE, EQ - }; -protected: - arith_simplifier_params & m_params; - arith_util m_util; - basic_simplifier_plugin & m_bsimp; - expr_ref m_int_zero; - expr_ref m_real_zero; - - bool is_neg_poly(expr * t) const; - - template<op_kind k> - void mk_le_ge_eq_core(expr * arg1, expr * arg2, expr_ref & result); - - void prop_mod_const(expr * e, unsigned depth, numeral const& k, expr_ref& result); - - void gcd_reduce_monomial(expr_ref_vector& monomials, numeral& k); - - void div_monomial(expr_ref_vector& monomials, numeral const& g); - void get_monomial_gcd(expr_ref_vector& monomials, numeral& g); - -public: - arith_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, arith_simplifier_params & p); - ~arith_simplifier_plugin(); - arith_util & get_arith_util() { return m_util; } - virtual numeral norm(const numeral & n) { return n; } - virtual bool is_numeral(expr * n, rational & val) const { bool f; return m_util.is_numeral(n, val, f); } - bool is_numeral(expr * n) const { return m_util.is_numeral(n); } - virtual bool is_minus_one(expr * n) const { numeral tmp; return is_numeral(n, tmp) && tmp.is_minus_one(); } - virtual expr * get_zero(sort * s) const { return m_util.is_int(s) ? m_int_zero.get() : m_real_zero.get(); } - - virtual app * mk_numeral(numeral const & n) { return m_util.mk_numeral(n, m_curr_sort->get_decl_kind() == INT_SORT); } - app * mk_numeral(numeral const & n, bool is_int) { return m_util.mk_numeral(n, is_int); } - bool is_int_sort(sort const * s) const { return m_util.is_int(s); } - bool is_real_sort(sort const * s) const { return m_util.is_real(s); } - bool is_arith_sort(sort const * s) const { return is_int_sort(s) || is_real_sort(s); } - bool is_int(expr const * n) const { return m_util.is_int(n); } - bool is_le(expr const * n) const { return m_util.is_le(n); } - bool is_ge(expr const * n) const { return m_util.is_ge(n); } - - virtual bool is_le_ge(expr * n) const { return is_le(n) || is_ge(n); } - - void mk_le(expr * arg1, expr * arg2, expr_ref & result); - void mk_ge(expr * arg1, expr * arg2, expr_ref & result); - void mk_lt(expr * arg1, expr * arg2, expr_ref & result); - void mk_gt(expr * arg1, expr * arg2, expr_ref & result); - void mk_arith_eq(expr * arg1, expr * arg2, expr_ref & result); - void mk_div(expr * arg1, expr * arg2, expr_ref & result); - void mk_idiv(expr * arg1, expr * arg2, expr_ref & result); - void mk_mod(expr * arg1, expr * arg2, expr_ref & result); - void mk_rem(expr * arg1, expr * arg2, expr_ref & result); - void mk_to_real(expr * arg, expr_ref & result); - void mk_to_int(expr * arg, expr_ref & result); - void mk_is_int(expr * arg, expr_ref & result); - void mk_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 07ead5fd6..000000000 --- a/src/ast/simplifier/array_simplifier_params.h +++ /dev/null @@ -1,34 +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_params1 { - - array_simplifier_params1(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: - - <abstract> - -Author: - - Nikolaj Bjorner (nbjorner) 2008-05-05 - -Revision History: - -Notes TODO: - - Examine quadratic cost of simplification vs. model-based procedure. - - Parameterize cache replacement strategy. - Some parameters are hard-wired. - ---*/ - -#include "ast/simplifier/array_simplifier_plugin.h" -#include "ast/ast_ll_pp.h" -#include "ast/ast_pp.h" - - -array_simplifier_plugin::array_simplifier_plugin( - ast_manager & m, - basic_simplifier_plugin& s, - simplifier& simp, - array_simplifier_params const& p) : - simplifier_plugin(symbol("array"),m), - m_util(m), - m_simp(s), - m_simplifier(simp), - m_params(p), - m_store_cache_size(0) -{} - - -array_simplifier_plugin::~array_simplifier_plugin() { - - select_cache::iterator it = m_select_cache.begin(); - select_cache::iterator end = m_select_cache.end(); - for ( ; it != end; ++it) { - m_manager.dec_array_ref(it->m_key->size(), it->m_key->c_ptr()); - m_manager.dec_ref(it->m_value); - dealloc(it->m_key); - } - - store_cache::iterator it2 = m_store_cache.begin(); - store_cache::iterator end2 = m_store_cache.end(); - for (; it2 != end2; ++it2) { - m_manager.dec_ref(it->m_value); - dealloc(it->m_key); - } -} - - -bool array_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - if (!m_params.m_array_simplify) - return false; - set_reduce_invoked(); - if (m_presimp) - return false; -#if Z3DEBUG - for (unsigned i = 0; i < num_args && i < f->get_arity(); ++i) { - SASSERT(m_manager.get_sort(args[i]) == f->get_domain(i)); - } -#endif - TRACE("array_simplifier", { - tout << mk_pp(f, m_manager) << " "; - for (unsigned i = 0; i < num_args; ++i) { - tout << mk_pp(args[i], m_manager) << " "; - } - tout << "\n"; - } - ); - SASSERT(f->get_family_id() == m_fid); - switch(f->get_decl_kind()) { - case OP_SELECT: - mk_select(num_args, args, result); - break; - case OP_STORE: - mk_store(f, num_args, args, result); - break; - case OP_SET_UNION: { - sort* s = f->get_range(); - expr_ref empty(m_manager); - mk_empty_set(s, empty); - switch(num_args) { - case 0: - result = empty; - break; - case 1: - result = args[0]; - break; - default: { - result = args[0]; - func_decl* f_or = m_manager.mk_or_decl(); - for (unsigned i = 1; i < num_args; ++i) { - mk_map(f_or, result, args[i], result); - } - break; - } - } - break; - } - case OP_SET_INTERSECT: { - expr_ref full(m_manager); - mk_full_set(f->get_range(), full); - switch(num_args) { - case 0: - result = full; - break; - case 1: - result = args[0]; - break; - default: { - result = args[0]; - func_decl* f_and = m_manager.mk_and_decl(); - for (unsigned i = 1; i < num_args; ++i) { - mk_map(f_and, result, args[i], result); - } - break; - } - } - TRACE("array_simplifier", tout << "sort " << mk_pp(result.get(), m_manager) << "\n";); - break; - } - case OP_SET_SUBSET: { - SASSERT(num_args == 2); - expr_ref diff(m_manager), emp(m_manager); - mk_set_difference(num_args, args, diff); - mk_empty_set(m_manager.get_sort(args[0]), emp); - m_simp.mk_eq(diff.get(), emp.get(), result); - break; - } - case OP_SET_COMPLEMENT: { - SASSERT(num_args == 1); - func_decl* f_not = m_manager.mk_not_decl(); - mk_map(f_not, args[0], result); - break; - } - case OP_SET_DIFFERENCE: { - SASSERT(num_args == 2); - expr_ref r1(m_manager); - mk_map(m_manager.mk_not_decl(), args[1], r1); - mk_map(m_manager.mk_and_decl(), args[0], r1, result); - break; - } - case OP_ARRAY_MAP: { - SASSERT(f->get_num_parameters() == 1); - SASSERT(f->get_parameter(0).is_ast()); - SASSERT(is_func_decl(f->get_parameter(0).get_ast())); - // - // map_d (store a j v) = (store (map_f a) v (d v)) - // - if (num_args == 1 && is_store(args[0])) { - app* store_expr = to_app(args[0]); - unsigned num_args = store_expr->get_num_args(); - SASSERT(num_args >= 3); - parameter p = f->get_parameter(0); - func_decl* d = to_func_decl(p.get_ast()); - expr* a = store_expr->get_arg(0); - expr* v = store_expr->get_arg(num_args-1); - // expr*const* args = store_expr->get_args()+1; - expr_ref r1(m_manager), r2(m_manager); - ptr_vector<expr> new_args; - - reduce(f, 1, &a, r1); - m_simplifier.mk_app(d, 1, &v, r2); - new_args.push_back(r1); - for (unsigned i = 1; i + 1 < num_args; ++i) { - new_args.push_back(store_expr->get_arg(i)); - } - new_args.push_back(r2); - mk_store(store_expr->get_decl(), num_args, new_args.c_ptr(), result); - break; - } - - // - // map_d (store a j v) (store b j w) = (store (map_f a b) j (d v w)) - // - if (num_args > 1 && same_store(num_args, args)) { - app* store_expr1 = to_app(args[0]); - unsigned num_indices = store_expr1->get_num_args(); - SASSERT(num_indices >= 3); - parameter p = f->get_parameter(0); - func_decl* d = to_func_decl(p.get_ast()); - ptr_vector<expr> arrays; - ptr_vector<expr> values; - for (unsigned i = 0; i < num_args; ++i) { - arrays.push_back(to_app(args[i])->get_arg(0)); - values.push_back(to_app(args[i])->get_arg(num_indices-1)); - } - - expr_ref r1(m_manager), r2(m_manager); - reduce(f, arrays.size(), arrays.c_ptr(), r1); - m_simplifier.mk_app(d, values.size(), values.c_ptr(), r2); - ptr_vector<expr> new_args; - new_args.push_back(r1); - for (unsigned i = 1; i + 1 < num_indices; ++i) { - new_args.push_back(store_expr1->get_arg(i)); - } - new_args.push_back(r2); - mk_store(store_expr1->get_decl(), new_args.size(), new_args.c_ptr(), result); - break; - } - // - // map_d (const v) = (const (d v)) - // - if (num_args == 1 && is_const_array(args[0])) { - app* const_expr = to_app(args[0]); - SASSERT(const_expr->get_num_args() == 1); - parameter p = f->get_parameter(0); - func_decl* d = to_func_decl(p.get_ast()); - expr* v = const_expr->get_arg(0); - expr_ref r1(m_manager); - - m_simplifier.mk_app(d, 1, &v, r1); - expr* arg = r1.get(); - parameter param(f->get_range()); - result = m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, ¶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<expr> values; - for (unsigned i = 0; i < num_args; ++i) { - values.push_back(to_app(args[i])->get_arg(0)); - } - expr_ref r1(m_manager); - - m_simplifier.mk_app(d, values.size(), values.c_ptr(), r1); - expr* arg = r1.get(); - parameter param(f->get_range()); - result = m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, ¶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<expr*const>& stores) { - while (is_store(n)) { - app* a = to_app(n); - SASSERT(a->get_num_args() > 2); - arity = a->get_num_args()-2; - n = a->get_arg(0); - stores.push_back(a->get_args()+1); - } - m = n; -} - -lbool array_simplifier_plugin::eq_default(expr* def, unsigned arity, unsigned num_st, expr*const* const* st) { - bool all_diseq = m_manager.is_unique_value(def) && num_st > 0; - bool all_eq = true; - for (unsigned i = 0; i < num_st; ++i) { - all_eq &= (st[i][arity] == def); - all_diseq &= m_manager.is_unique_value(st[i][arity]) && (st[i][arity] != def); - TRACE("array_simplifier", tout << m_manager.is_unique_value(st[i][arity]) << " " << mk_pp(st[i][arity], m_manager) << "\n";); - } - if (all_eq) { - return l_true; - } - if (all_diseq) { - return l_false; - } - return l_undef; -} - - -bool array_simplifier_plugin::insert_table(expr* def, unsigned arity, unsigned num_st, expr*const* const* st, arg_table& table) { - for (unsigned i = 0; i < num_st; ++i ) { - for (unsigned j = 0; j < arity; ++j) { - if (!m_manager.is_unique_value(st[i][j])) { - return false; - } - } - TRACE("array_simplifier", tout << "inserting: "; - for (unsigned j = 0; j < arity; ++j) { - tout << mk_pp(st[i][j], m_manager) << " "; - } - tout << " |-> " << mk_pp(def, m_manager) << "\n"; - ); - args_entry e(arity, st[i]); - table.insert_if_not_there(e); - } - return true; -} - - -lbool array_simplifier_plugin::eq_stores(expr* def, unsigned arity, unsigned num_st1, expr*const* const* st1, unsigned num_st2, expr*const* const* st2) { - if (num_st1 == 0) { - return eq_default(def, arity, num_st2, st2); - } - if (num_st2 == 0) { - return eq_default(def, arity, num_st1, st1); - } - arg_table table1, table2; - if (!insert_table(def, arity, num_st1, st1, table1)) { - return l_undef; - } - if (!insert_table(def, arity, num_st2, st2, table2)) { - return l_undef; - } - - arg_table::iterator it = table1.begin(); - arg_table::iterator end = table1.end(); - for (; it != end; ++it) { - args_entry const & e1 = *it; - args_entry e2; - expr* v1 = e1.m_args[arity]; - if (table2.find(e1, e2)) { - expr* v2 = e2.m_args[arity]; - if (v1 == v2) { - table2.erase(e1); - continue; - } - if (m_manager.is_unique_value(v1) && m_manager.is_unique_value(v2)) { - return l_false; - } - return l_undef; - } - else if (m_manager.is_unique_value(v1) && m_manager.is_unique_value(def) && v1 != def) { - return l_false; - } - } - it = table2.begin(); - end = table2.end(); - for (; it != end; ++it) { - args_entry const & e = *it; - expr* v = e.m_args[arity]; - if (m_manager.is_unique_value(v) && m_manager.is_unique_value(def) && v != def) { - return l_false; - } - } - if (!table2.empty() || !table1.empty()) { - return l_undef; - } - return l_true; -} - - -bool array_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { - set_reduce_invoked(); - expr* c1, *c2; - ptr_vector<expr*const> st1, st2; - unsigned arity1 = 0; - unsigned arity2 = 0; - get_stores(lhs, arity1, c1, st1); - get_stores(rhs, arity2, c2, st2); - if (arity1 == arity2 && is_const_array(c1) && is_const_array(c2)) { - c1 = to_app(c1)->get_arg(0); - c2 = to_app(c2)->get_arg(0); - if (c1 == c2) { - lbool eq = eq_stores(c1, arity2, st1.size(), st1.c_ptr(), st2.size(), st2.c_ptr()); - TRACE("array_simplifier", - tout << mk_pp(lhs, m_manager) << " = " - << mk_pp(rhs, m_manager) << " := " << eq << "\n"; - tout << "arity: " << arity1 << "\n";); - switch(eq) { - case l_false: - result = m_manager.mk_false(); - return true; - case l_true: - result = m_manager.mk_true(); - return true; - default: - return false; - } - } - else if (m_manager.is_unique_value(c1) && m_manager.is_unique_value(c2)) { - result = m_manager.mk_false(); - return true; - } - } - return false; -} - -bool array_simplifier_plugin::reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - return false; -} - - -array_simplifier_plugin::const_select_result -array_simplifier_plugin::mk_select_const(expr* m, app* index, expr_ref& result) { - store_info* info = 0; - expr* r = 0, *a = 0; - if (!is_store(m)) { - return NOT_CACHED; - } - if (!m_store_cache.find(m, info)) { - return NOT_CACHED; - } - if (info->m_map.find(index, r)) { - result = r; - return FOUND_VALUE; - } - a = info->m_default.get(); - - // - // Unfold and cache the store while searching for value of index. - // - while (is_store(a) && m_manager.is_unique_value(to_app(a)->get_arg(1))) { - app* b = to_app(a); - app* c = to_app(b->get_arg(1)); - - if (!info->m_map.contains(c)) { - info->m_map.insert(c, b->get_arg(2)); - m_manager.inc_ref(b->get_arg(2)); - ++m_store_cache_size; - } - a = b->get_arg(0); - info->m_default = a; - - if (c == index) { - result = b->get_arg(2); - return FOUND_VALUE; - } - } - result = info->m_default.get(); - return FOUND_DEFAULT; -} - -void array_simplifier_plugin::cache_store(unsigned num_stores, expr* store_term) -{ - if (num_stores <= m_const_store_threshold) { - return; - } - prune_store_cache(); - if (!m_store_cache.contains(store_term)) { - store_info * info = alloc(store_info, m_manager, store_term); - m_manager.inc_ref(store_term); - m_store_cache.insert(store_term, info); - TRACE("cache_store", tout << m_store_cache.size() << "\n";); - ++m_store_cache_size; - } -} - -void array_simplifier_plugin::cache_select(unsigned num_args, expr * const * args, expr * result) { - ptr_vector<expr> * entry = alloc(ptr_vector<expr>); - entry->append(num_args, const_cast<expr**>(args)); - const select_cache::key_data & kd = m_select_cache.insert_if_not_there(entry, result); - if (kd.m_key != entry) { - dealloc(entry); - return; - } - m_manager.inc_array_ref(num_args, args); - m_manager.inc_ref(result); - TRACE("cache_select", tout << m_select_cache.size() << "\n";); -} - - - -void array_simplifier_plugin::prune_select_cache() { - if (m_select_cache.size() > m_select_cache_max_size) { - flush_select_cache(); - } -} - -void array_simplifier_plugin::prune_store_cache() { - if (m_store_cache_size > m_store_cache_max_size) { - flush_store_cache(); - } -} - -void array_simplifier_plugin::flush_select_cache() { - select_cache::iterator it = m_select_cache.begin(); - select_cache::iterator end = m_select_cache.end(); - for (; it != end; ++it) { - ptr_vector<expr> * e = (*it).m_key; - m_manager.dec_array_ref(e->size(), e->begin()); - m_manager.dec_ref((*it).m_value); - dealloc(e); - } - m_select_cache.reset(); -} - -void array_simplifier_plugin::flush_store_cache() { - store_cache::iterator it = m_store_cache.begin(); - store_cache::iterator end = m_store_cache.end(); - for (; it != end; ++it) { - m_manager.dec_ref((*it).m_key); - const_map::iterator mit = (*it).m_value->m_map.begin(); - const_map::iterator mend = (*it).m_value->m_map.end(); - for (; mit != mend; ++mit) { - m_manager.dec_ref((*mit).m_value); - } - dealloc((*it).m_value); - } - m_store_cache.reset(); - m_store_cache_size = 0; -} - - -void array_simplifier_plugin::flush_caches() { - flush_select_cache(); - flush_store_cache(); -} - -void array_simplifier_plugin::mk_set_difference(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(num_args == 2); - result = m_manager.mk_app(m_fid, OP_SET_DIFFERENCE, 0, 0, num_args, args); -} - -void array_simplifier_plugin::mk_empty_set(sort* ty, expr_ref & result) { - parameter param(ty); - expr* args[1] = { m_manager.mk_false() }; - result = m_manager.mk_app(m_fid, OP_CONST_ARRAY, 1, ¶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<app, 32> todo; - obj_map<app, app *> cache; - app_ref_buffer trail(m_manager); - todo.push_back(to_app(args[0])); - while (!todo.empty()) { - app * curr = todo.back(); - SASSERT(m_manager.is_ite(curr)); - expr * branches[2] = {0, 0}; - bool visited = true; - for (unsigned i = 0; i < 2; i++) { - expr * arg = curr->get_arg(i+1); - if (is_as_array(arg)) { - branches[i] = m_manager.mk_app(get_as_array_func_decl(to_app(arg)), num_args - 1, args+1); - } - else { - SASSERT(m_manager.is_ite(arg)); - app * new_arg = 0; - if (!cache.find(to_app(arg), new_arg)) { - todo.push_back(to_app(arg)); - visited = false; - } - else { - branches[i] = new_arg; - } - } - } - if (visited) { - todo.pop_back(); - app * new_curr = m_manager.mk_ite(curr->get_arg(0), branches[0], branches[1]); - trail.push_back(new_curr); - cache.insert(curr, new_curr); - } - } - SASSERT(cache.contains(to_app(args[0]))); - app * r = 0; - cache.find(to_app(args[0]), r); - result = r; -} - -void array_simplifier_plugin::mk_select(unsigned num_args, expr * const * args, expr_ref & result) { - expr * r = 0; - - if (is_as_array(args[0])) { - mk_select_as_array(num_args, args, result); - return; - } - - if (is_as_array_tree(args[0])) { - mk_select_as_array_tree(num_args, args, result); - return; - } - - bool is_const_select = num_args == 2 && m_manager.is_unique_value(args[1]); - app* const_index = is_const_select?to_app(args[1]):0; - unsigned num_const_stores = 0; - expr_ref tmp(m_manager); - expr* args2[2]; - if (is_const_select) { - switch(mk_select_const(args[0], const_index, tmp)) { - case NOT_CACHED: - break; - case FOUND_VALUE: - TRACE("mk_select", tout << "found value\n"; ast_ll_pp(tout, m_manager, tmp.get()); ); - result = tmp.get(); - // value of select is stored under result. - return; - case FOUND_DEFAULT: - args2[0] = tmp.get(); - args2[1] = args[1]; - args = args2; - is_const_select = false; - break; - } - } - - SASSERT(num_args > 0); - ptr_vector<expr> & entry = m_tmp2; - entry.reset(); - entry.append(num_args, args); - expr * entry0 = entry[0]; - SASSERT(m_todo.empty()); - m_todo.push_back(entry0); - while (!m_todo.empty()) { - expr * m = m_todo.back(); - TRACE("array_simplifier", tout << mk_bounded_pp(m, m_manager) << "\n";); - if (is_store(m)) { - expr * nested_array = to_app(m)->get_arg(0); - expr * else_branch = 0; - entry[0] = nested_array; - if (is_const_select) { - if (m_manager.is_unique_value(to_app(m)->get_arg(1))) { - app* const_index2 = to_app(to_app(m)->get_arg(1)); - // - // we found the value, all other stores are different. - // there is no need to recurse. - // - if (const_index == const_index2) { - result = to_app(m)->get_arg(2); - cache_store(num_const_stores, args[0]); - m_todo.reset(); - return; - } - ++num_const_stores; - } - else { - is_const_select = false; - } - } - if (m_select_cache.find(&entry, else_branch)) { - expr_ref_buffer eqs(m_manager); - for (unsigned i = 1; i < num_args ; ++i) { - expr * a = args[i]; - expr * b = to_app(m)->get_arg(i); - expr_ref eq(m_manager); - m_simp.mk_eq(a, b, eq); - eqs.push_back(eq.get()); - } - expr_ref cond(m_manager); - m_simp.mk_and(eqs.size(), eqs.c_ptr(), cond); - expr * then_branch = to_app(m)->get_arg(num_args); - if (m_manager.is_true(cond.get())) { - result = then_branch; - } - else if (m_manager.is_false(cond.get())) { - result = else_branch; - } - else { - m_simp.mk_ite(cond.get(), then_branch, else_branch, result); - } - entry[0] = m; - cache_select(entry.size(), entry.c_ptr(), result.get()); - m_todo.pop_back(); - } - else { - m_todo.push_back(nested_array); - } - } - else if (is_const_array(m)) { - entry[0] = m; - cache_select(entry.size(), entry.c_ptr(), to_app(m)->get_arg(0)); - m_todo.pop_back(); - } - else { - entry[0] = m; - TRACE("array_simplifier", { - for (unsigned i = 0; i < entry.size(); ++i) { - tout << mk_bounded_pp(entry[i], m_manager) << ": " - << mk_bounded_pp(m_manager.get_sort(entry[i]), m_manager) << "\n"; - }} - ); - r = m_manager.mk_app(m_fid, OP_SELECT, 0, 0, entry.size(), entry.c_ptr()); - cache_select(entry.size(), entry.c_ptr(), r); - m_todo.pop_back(); - } - } - cache_store(num_const_stores, args[0]); - entry[0] = entry0; -#ifdef Z3DEBUG - bool f = -#endif - m_select_cache.find(&entry, r); - SASSERT(f); - result = r; - prune_select_cache(); - prune_store_cache(); - TRACE("mk_select", - for (unsigned i = 0; i < num_args; i++) { - ast_ll_pp(tout, m_manager, args[i]); tout << "\n"; - }; - tout << "is_store: " << is_store(args[0]) << "\n"; - ast_ll_pp(tout, m_manager, r);); -} - - -void array_simplifier_plugin::mk_map(func_decl* f, expr* a, expr* b, expr_ref& result) { - expr* exprs[2] = { a, b }; - parameter param(f); - result = m_manager.mk_app(m_fid, OP_ARRAY_MAP, 1, ¶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: - - <abstract> - -Author: - - Nikolaj Bjorner (nbjorner) 2008-05-05 - -Revision History: - ---*/ -#ifndef ARRAY_SIMPLIFIER_PLUGIN_H_ -#define ARRAY_SIMPLIFIER_PLUGIN_H_ - -#include "ast/ast.h" -#include "util/map.h" -#include "ast/array_decl_plugin.h" -#include "ast/simplifier/simplifier_plugin.h" -#include "ast/simplifier/basic_simplifier_plugin.h" -#include "ast/simplifier/array_simplifier_params.h" -#include "ast/simplifier/simplifier.h" -#include "util/obj_hashtable.h" -#include "util/lbool.h" - -class array_simplifier_plugin : public simplifier_plugin { - - typedef ptr_vector<expr> entry; - - struct entry_hash_proc { - unsigned operator()(ptr_vector<expr> * entry) const { - return get_exprs_hash(entry->size(), entry->begin(), 0xbeef1010); - } - }; - - struct entry_eq_proc { - bool operator()(ptr_vector<expr> * entry1, ptr_vector<expr> * entry2) const { - if (entry1->size() != entry2->size()) return false; - return compare_arrays(entry1->begin(), entry2->begin(), entry1->size()); - } - }; - - typedef map<entry *, expr *, entry_hash_proc, entry_eq_proc> select_cache; - - struct args_entry { - unsigned m_arity; - expr* const* m_args; - args_entry(unsigned a, expr* const* args) : m_arity(a), m_args(args) {} - args_entry() : m_arity(0), m_args(0) {} - }; - - struct args_entry_hash_proc { - unsigned operator()(args_entry const& e) const { - return get_exprs_hash(e.m_arity, e.m_args, 0xbeef1010); - } - }; - struct args_entry_eq_proc { - bool operator()(args_entry const& e1, args_entry const& e2) const { - if (e1.m_arity != e2.m_arity) return false; - return compare_arrays(e1.m_args, e2.m_args, e1.m_arity); - } - }; - typedef hashtable<args_entry, args_entry_hash_proc, args_entry_eq_proc> arg_table; - - array_util m_util; - basic_simplifier_plugin& m_simp; - simplifier& m_simplifier; - array_simplifier_params const& m_params; - select_cache m_select_cache; - ptr_vector<expr> m_tmp; - ptr_vector<expr> m_tmp2; - ptr_vector<expr> m_todo; - static const unsigned m_select_cache_max_size = 100000; - typedef obj_map<expr, expr*> const_map; - class store_info { - store_info(); - store_info(store_info const&); - public: - const_map m_map; - expr_ref m_default; - store_info(ast_manager& m, expr* d): m_default(d, m) {} - }; - - typedef obj_map<expr, store_info*> store_cache; - store_cache m_store_cache; - unsigned m_store_cache_size; - static const unsigned m_store_cache_max_size = 10000; - static const unsigned m_const_store_threshold = 5; - enum const_select_result { - NOT_CACHED, - FOUND_DEFAULT, - FOUND_VALUE - }; - - -public: - array_simplifier_plugin(ast_manager & m, basic_simplifier_plugin& s, simplifier& simp, array_simplifier_params const& p); - virtual ~array_simplifier_plugin(); - - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - - virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result); - - virtual bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result); - - virtual void flush_caches(); - -private: - bool is_select(expr* n) const { return m_util.is_select(n); } - bool is_store(expr * n) const { return m_util.is_store(n); } - bool is_const_array(expr * n) const { return m_util.is_const(n); } - bool is_as_array(expr * n) const { return m_util.is_as_array(n); } - bool is_as_array_tree(expr * n) { return m_util.is_as_array_tree(n); } - func_decl * get_as_array_func_decl(app * n) const { return m_util.get_as_array_func_decl(n); } - void mk_select_as_array(unsigned num_args, expr * const * args, expr_ref & result); - void mk_select_as_array_tree(unsigned num_args, expr * const * args, expr_ref & result); - bool is_enumerated(expr* n, expr_ref& c, ptr_vector<expr>& keys, ptr_vector<expr>& vals); - const_select_result mk_select_const(expr* m, app* index, expr_ref& result); - void cache_store(unsigned num_stores, expr* nested_store); - void cache_select(unsigned num_args, expr * const * args, expr * result); - void prune_select_cache(); - void prune_store_cache(); - void flush_select_cache(); - void flush_store_cache(); - void mk_set_difference(unsigned num_args, expr * const * args, expr_ref & result); - void mk_empty_set(sort* ty, expr_ref & result); - void mk_full_set(sort* ty, expr_ref & result); - void mk_select(unsigned num_args, expr * const * args, expr_ref & result); - void mk_store(func_decl* f, unsigned num_args, expr * const * args, expr_ref & result); - void mk_map(func_decl* f, expr* a, expr* b, expr_ref & result); - void mk_map(func_decl* f, expr* a, expr_ref & result); - bool same_args(unsigned num_args, expr * const * args1, expr * const * args2); - - void get_stores(expr* n, unsigned& arity, expr*& m, ptr_vector<expr*const>& stores); - lbool eq_default(expr* def, unsigned arity, unsigned num_st, expr*const* const* st); - bool insert_table(expr* def, unsigned arity, unsigned num_st, expr*const* const* st, arg_table& table); - lbool eq_stores(expr* def, unsigned arity, unsigned num_st1, expr*const* const* st1, unsigned num_st2, expr*const* const* st2); - - bool same_store(unsigned num_args, expr* const* args) const; - bool all_const_array(unsigned num_args, expr* const* args) const; - bool all_values(unsigned num_args, expr* const* args) const; - bool lex_lt(unsigned num_args, expr* const* args1, expr* const* args2); - -}; - - -#endif /* ARRAY_SIMPLIFIER_PLUGIN_H_ */ - diff --git a/src/ast/simplifier/base_simplifier.h b/src/ast/simplifier/base_simplifier.h deleted file mode 100644 index 73a04d605..000000000 --- a/src/ast/simplifier/base_simplifier.h +++ /dev/null @@ -1,76 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - base_simplifier.h - -Abstract: - - Base class for expression simplifier functors. - -Author: - - Leonardo (leonardo) 2008-01-11 - -Notes: - ---*/ -#ifndef BASE_SIMPLIFIER_H_ -#define BASE_SIMPLIFIER_H_ - -#include "ast/expr_map.h" -#include "ast/ast_pp.h" - -/** - \brief Implements basic functionality used by expression simplifiers. -*/ -class base_simplifier { -protected: - ast_manager & m; - expr_map m_cache; - ptr_vector<expr> m_todo; - - void cache_result(expr * n, expr * r, proof * p) { - m_cache.insert(n, r, p); - CTRACE("simplifier", !is_rewrite_proof(n, r, p), - tout << mk_pp(n, m) << "\n"; - tout << mk_pp(r, m) << "\n"; - tout << mk_pp(p, m) << "\n";); - 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<basic_op_kind>(f->get_decl_kind()); - switch (k) { - case OP_FALSE: - case OP_TRUE: - return false; - case OP_EQ: - SASSERT(num_args == 2); - mk_eq(args[0], args[1], result); - return true; - case OP_DISTINCT: - mk_distinct(num_args, args, result); - return true; - case OP_ITE: - SASSERT(num_args == 3); - mk_ite(args[0], args[1], args[2], result); - return true; - case OP_AND: - mk_and(num_args, args, result); - return true; - case OP_OR: - mk_or(num_args, args, result); - return true; - case OP_IMPLIES: - mk_implies(args[0], args[1], result); - return true; - case OP_IFF: - mk_iff(args[0], args[1], result); - return true; - case OP_XOR: - switch (num_args) { - case 0: result = m_manager.mk_true(); break; - case 1: result = args[0]; break; - case 2: mk_xor(args[0], args[1], result); break; - default: UNREACHABLE(); break; - } - return true; - case OP_NOT: - SASSERT(num_args == 1); - mk_not(args[0], result); - return true; - default: - UNREACHABLE(); - return false; - } -} - -/** - \brief Return true if \c rhs is of the form (ite c t1 t2) and are_distinct(lhs, t1) and are_distinct(lhs, t2). -*/ -static bool is_lhs_diseq_rhs_ite_branches(ast_manager & m, expr * lhs, expr * rhs) { - return m.is_ite(rhs) && m.are_distinct(lhs, to_app(rhs)->get_arg(1)) && m.are_distinct(lhs, to_app(rhs)->get_arg(2)); -} - -/** - \brief Return true if \c rhs is of the form (ite c t1 t2) and lhs = t1 && are_distinct(lhs, t2) -*/ -static bool is_lhs_eq_rhs_ite_then(ast_manager & m, expr * lhs, expr * rhs) { - return m.is_ite(rhs) && lhs == to_app(rhs)->get_arg(1) && m.are_distinct(lhs, to_app(rhs)->get_arg(2)); -} - -/** - \brief Return true if \c rhs is of the form (ite c t1 t2) and are_distinct(lhs,t1) && lhs = t2 -*/ -static bool is_lhs_eq_rhs_ite_else(ast_manager & m, expr * lhs, expr * rhs) { - return m.is_ite(rhs) && lhs == to_app(rhs)->get_arg(2) && m.are_distinct(lhs, to_app(rhs)->get_arg(1)); -} - -void basic_simplifier_plugin::mk_eq(expr * lhs, expr * rhs, expr_ref & result) { - // (= t1 (ite C t2 t3)) --> false if are_distinct(t1, t2) && are_distinct(t1, t3) - if (is_lhs_diseq_rhs_ite_branches(m_manager, lhs, rhs) || is_lhs_diseq_rhs_ite_branches(m_manager, rhs, lhs)) { - result = m_manager.mk_false(); - } - // (= t1 (ite C t2 t3)) --> C if t1 = t2 && are_distinct(t1, t3) - else if (is_lhs_eq_rhs_ite_then(m_manager, lhs, rhs)) { - result = to_app(rhs)->get_arg(0); - } - // (= t1 (ite C t2 t3)) --> C if t1 = t2 && are_distinct(t1, t3) - else if (is_lhs_eq_rhs_ite_then(m_manager, rhs, lhs)) { - result = to_app(lhs)->get_arg(0); - } - // (= t1 (ite C t2 t3)) --> (not C) if t1 = t3 && are_distinct(t1, t2) - else if (is_lhs_eq_rhs_ite_else(m_manager, lhs, rhs)) { - mk_not(to_app(rhs)->get_arg(0), result); - } - // (= t1 (ite C t2 t3)) --> (not C) if t1 = t3 && are_distinct(t1, t2) - else if (is_lhs_eq_rhs_ite_else(m_manager, rhs, lhs)) { - mk_not(to_app(lhs)->get_arg(0), result); - } - else { - m_rewriter->mk_eq(lhs, rhs, result); - } -} - -bool basic_simplifier_plugin::eliminate_and() const { return m_rewriter->elim_and(); } -void basic_simplifier_plugin::set_eliminate_and(bool f) { m_rewriter->set_elim_and(f); } -void basic_simplifier_plugin::mk_iff(expr * lhs, expr * rhs, expr_ref & result) { mk_eq(lhs, rhs, result); } -void basic_simplifier_plugin::mk_xor(expr * lhs, expr * rhs, expr_ref & result) { m_rewriter->mk_xor(lhs, rhs, result); } -void basic_simplifier_plugin::mk_implies(expr * lhs, expr * rhs, expr_ref & result) { m_rewriter->mk_implies(lhs, rhs, result); } -void basic_simplifier_plugin::mk_ite(expr * c, expr * t, expr * e, expr_ref & result) { m_rewriter->mk_ite(c, t, e, result); } -void basic_simplifier_plugin::mk_and(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_and(num_args, args, result); } -void basic_simplifier_plugin::mk_or(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_or(num_args, args, result); } -void basic_simplifier_plugin::mk_and(expr * arg1, expr * arg2, expr_ref & result) { m_rewriter->mk_and(arg1, arg2, result); } -void basic_simplifier_plugin::mk_or(expr * arg1, expr * arg2, expr_ref & result) { m_rewriter->mk_or(arg1, arg2, result); } -void basic_simplifier_plugin::mk_and(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { m_rewriter->mk_and(arg1, arg2, arg3, result); } -void basic_simplifier_plugin::mk_or(expr * arg1, expr * arg2, expr * arg3, expr_ref & result) { m_rewriter->mk_or(arg1, arg2, arg3, result); } -void basic_simplifier_plugin::mk_nand(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_nand(num_args, args, result); } -void basic_simplifier_plugin::mk_nor(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_nor(num_args, args, result); } -void basic_simplifier_plugin::mk_nand(expr * arg1, expr * arg2, expr_ref & result) { m_rewriter->mk_nand(arg1, arg2, result); } -void basic_simplifier_plugin::mk_nor(expr * arg1, expr * arg2, expr_ref & result) { m_rewriter->mk_nor(arg1, arg2, result); } -void basic_simplifier_plugin::mk_distinct(unsigned num_args, expr * const * args, expr_ref & result) { m_rewriter->mk_distinct(num_args, args, result); } -void basic_simplifier_plugin::mk_not(expr * n, expr_ref & result) { m_rewriter->mk_not(n, result); } - -void basic_simplifier_plugin::enable_ac_support(bool flag) { - m_rewriter->set_flat(flag); -} 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 1c0048a07..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 <sstream> - -void bv_elim::elim(quantifier* q, quantifier_ref& r) { - - svector<symbol> names, _names; - sort_ref_buffer sorts(m), _sorts(m); - expr_ref_buffer pats(m); - expr_ref_buffer no_pats(m); - expr_ref_buffer subst_map(m), _subst_map(m); - var_subst subst(m); - bv_util bv(m); - expr_ref new_body(m); - expr* old_body = q->get_expr(); - 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; - 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); - 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); - } - } - // - // 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(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); - subst(q->get_no_pattern(j), sub_size, sub, nopat); - no_pats.push_back(nopat); - } - - r = 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()); -} - -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 c027b1a9e..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; -public: - bv_elim(ast_manager& m) : m(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 07f854179..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: - - <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); -} 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: - - <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<bv_simplifier_plugin*>(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<bv_op_kind>(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 -= (64<sz)?64:sz; - } - return r; -} - - -void bv_simplifier_plugin::mk_ule(expr* a, expr* b, expr_ref& result) { - mk_leq_core(false, a, b, result); -} - -void bv_simplifier_plugin::mk_ult(expr* a, expr* b, expr_ref& result) { - expr_ref tmp(m_manager); - mk_leq_core(false, b, a, tmp); - m_bsimp.mk_not(tmp.get(), result); -} - -void bv_simplifier_plugin::mk_sle(expr* a, expr* b, expr_ref& result) { - mk_leq_core(true, a, b, result); -} - -void bv_simplifier_plugin::mk_slt(expr* a, expr* b, expr_ref& result) { - expr_ref tmp(m_manager); - mk_leq_core(true, b, a, tmp); - m_bsimp.mk_not(tmp.get(), result); -} - -void bv_simplifier_plugin::mk_leq_core(bool is_signed, expr * arg1, expr * arg2, expr_ref & result) { - numeral r1, r2, r3; - bool is_num1 = is_numeral(arg1, r1); - bool is_num2 = is_numeral(arg2, r2); - decl_kind k = is_signed ? OP_SLEQ : OP_ULEQ; - unsigned bv_size = get_bv_size(arg1); - - if (is_num1) { - r1 = norm(r1, bv_size, is_signed); - } - if (is_num2) { - r2 = norm(r2, bv_size, is_signed); - } - - if (is_num1 && is_num2) { - result = r1 <= r2 ? m_manager.mk_true() : m_manager.mk_false(); - return; - } - - numeral lower, upper; - - if (is_num1 || is_num2) { - if (is_signed) { - lower = - rational::power_of_two(bv_size - 1); - upper = rational::power_of_two(bv_size - 1) - numeral(1); - } - else { - lower = numeral(0); - upper = rational::power_of_two(bv_size) - numeral(1); - } - } - - if (is_num2) { - if (r2 == lower) { - m_bsimp.mk_eq(arg1, arg2, result); - return; - } - if (r2 == upper) { - result = m_manager.mk_true(); - return; - } - } - - if (is_num1) { - // 0 <= arg2 is true - if (r1 == lower) { - result = m_manager.mk_true(); - return; - } - - // 2^n-1 <= arg2 is arg1 = arg2 - if (r1 == upper) { - m_bsimp.mk_eq(arg1, arg2, result); - return; - } - } - - // - // In general, we can use lexicographic extensions of concat. - // But this does not always turn into savings. - // Only apply the simplification if arg1 is a numeral. - // - if (is_num1 && !is_signed && m_util.is_concat(arg2) && to_app(arg2)->get_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<expr> 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<typename T> -void get_assoc_args(family_id fid, decl_kind k, expr * n, T & result) { - ptr_buffer<expr> 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<typename T> -void get_inv_assoc_args(family_id fid, decl_kind k, expr * n, T & result) { - ptr_buffer<expr> 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<expr> 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<expr>::iterator it1 = args1.begin(); - ptr_buffer<expr>::iterator end1 = args1.end(); - ptr_buffer<expr>::iterator it2 = args2.begin(); - ptr_buffer<expr>::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<expr> 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<expr>::iterator it = flat_args.begin(); - ptr_buffer<expr>::iterator it2 = it; - ptr_buffer<expr>::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<expr> 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<expr>::iterator it = flat_args.begin(); - ptr_buffer<expr>::iterator it2 = it; - ptr_buffer<expr>::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<expr> 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<expr>::iterator it = flat_args.begin(); - ptr_buffer<expr>::iterator it2 = it; - ptr_buffer<expr>::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<expr> 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<unsigned>((r2 % numeral(bv_size)).get_uint64() % static_cast<uint64>(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<unsigned>((r2 % numeral(bv_size)).get_uint64() % static_cast<uint64>(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<expr> todo; - expr_ref_vector pinned(m_manager); - ptr_vector<app> cache; - todo.push_back(e); - expr* e0 = e; - ptr_vector<expr> 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_entry, expr *, extract_entry::hash_proc , extract_entry::eq_proc > extract_cache; - -protected: - ast_manager& m_manager; - bv_util m_util; - arith_util m_arith; - basic_simplifier_plugin & m_bsimp; - bv_simplifier_params & m_params; - expr_ref_vector m_zeros; - extract_cache m_extract_cache; - - unsigned_vector m_lows, m_highs; - ptr_vector<expr> m_extract_args; - - rational mk_bv_and(numeral const& a0, numeral const& b0, unsigned sz); - rational mk_bv_or(numeral const& a0, numeral const& b0, unsigned sz); - rational mk_bv_xor(numeral const& a0, numeral const& b0, unsigned sz); - rational mk_bv_not(numeral const& a0, unsigned sz); - rational num(expr* e); - bool has_sign_bit(numeral const& n, unsigned bv_size) { return m_util.has_sign_bit(n, bv_size); } - - bool shift_shift(bv_op_kind k, expr* arg1, expr* arg2, expr_ref& result); - - void bit2bool_simplify(unsigned idx, expr* e, expr_ref& result); - - void mk_add_concat(expr_ref& result); - bool is_zero_bit(expr* x, unsigned idx); - - void mk_bv_rotate_left_core(unsigned shift, numeral r, unsigned bv_size, expr_ref& result); - void mk_bv_rotate_right_core(unsigned shift, numeral r, unsigned bv_size, expr_ref& result); - -public: - bv_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, bv_simplifier_params & p); - virtual ~bv_simplifier_plugin(); - - - // simplifier_plugin: - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result); - virtual bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result); - virtual void flush_caches(); - - // poly_simplifier_plugin - virtual rational norm(const rational & n); - virtual bool is_numeral(expr * n, rational & val) const; - bool is_numeral(expr * n) const { return m_util.is_numeral(n); } - virtual bool is_minus_one(expr * n) const { return is_minus_one_core(n); } - virtual expr * get_zero(sort * s) const; - virtual app * mk_numeral(rational const & n); - - bool is_bv(expr * n) const { return m_util.is_bv(n); } - bool is_bv_sort(sort * s) const { return m_util.is_bv_sort(s); } - - bool is_le(expr * n) const { return m_util.is_bv_ule(n) || m_util.is_bv_sle(n); } - // REMARK: simplified bv expressions are never of the form a >= b. - virtual bool is_le_ge(expr * n) const { return is_le(n); } - - uint64 to_uint64(const numeral & n, unsigned bv_size); - rational norm(rational const& n, unsigned bv_size, bool is_signed) { return m_util.norm(n, bv_size, is_signed); } - unsigned get_bv_size(expr const * n) { return get_bv_size(m_manager.get_sort(n)); } - unsigned get_bv_size(sort const * s) { return m_util.get_bv_size(s); } - void mk_leq_core(bool is_signed, expr * arg1, expr * arg2, expr_ref & result); - void mk_ule(expr* a, expr* b, expr_ref& result); - void mk_ult(expr* a, expr* b, expr_ref& result); - void mk_sle(expr* a, expr* b, expr_ref& result); - void mk_slt(expr* a, expr* b, expr_ref& result); - void mk_bv_and(unsigned num_args, expr * const* args, expr_ref & result); - void mk_bv_or(unsigned num_args, expr * const* args, expr_ref & result); - void mk_bv_xor(unsigned num_args, expr * const* args, expr_ref & result); - void mk_bv_not(expr * arg, expr_ref & result); - void mk_extract(unsigned hi,unsigned lo, expr* bv, expr_ref& result); - void mk_extract_core(unsigned high, unsigned low, expr * arg, expr_ref& result); - void cache_extract(unsigned h, unsigned l, expr * arg, expr * result); - expr* get_cached_extract(unsigned h, unsigned l, expr * arg); - - bool lookup_mk_extract(unsigned high, unsigned low, expr * arg, expr_ref& result); - bool try_mk_extract(unsigned high, unsigned low, expr * arg, expr_ref& result); - - void mk_bv_eq(expr* a1, expr* a2, expr_ref& result); - void mk_eq_core(expr * arg1, expr * arg2, expr_ref & result); - void mk_args_eq_numeral(app * app, expr * n, expr_ref & result); - - void mk_concat(unsigned num_args, expr * const * args, expr_ref & result); - void mk_concat(expr * arg1, expr * arg2, expr_ref & result) { - expr * args[2] = { arg1, arg2 }; - mk_concat(2, args, result); - } - void mk_zeroext(unsigned n, expr * arg, expr_ref & result); - void mk_repeat(unsigned n, expr * arg, expr_ref & result); - void mk_sign_extend(unsigned n, expr * arg, expr_ref & result); - void mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result); - void mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result); - void mk_bv_ashr(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_smod(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_urem(expr * arg1, expr * arg2, expr_ref & result); - void mk_bv_srem(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_udiv(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_sdiv(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_smod_i(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_urem_i(expr * arg1, expr * arg2, expr_ref & result); - void mk_bv_srem_i(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_udiv_i(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_sdiv_i(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_nand(unsigned num_args, expr* const* args, expr_ref& result); - void mk_bv_nor(unsigned num_args, expr* const* args, expr_ref& result); - void mk_bv_xnor(unsigned num_args, expr* const* args, expr_ref& result); - void mk_bv_rotate_right(func_decl* f, expr* arg, expr_ref& result); - void mk_bv_rotate_left(func_decl* f, expr* arg, expr_ref& result); - void mk_bv_ext_rotate_right(expr* arg1, expr* arg2, expr_ref& result); - void mk_bv_ext_rotate_left(expr* arg1, expr* arg2, expr_ref& result); - - void mk_bv_redor(expr* arg, expr_ref& result); - void mk_bv_redand(expr* arg, expr_ref& result); - void mk_bv_comp(expr* arg1, expr* arg2, expr_ref& result); - - bool are_numerals(unsigned num_args, expr * const* args, unsigned& bv_size); - app * mk_numeral(rational const & n, unsigned bv_size); - app * mk_numeral(uint64 n, unsigned bv_size) { return mk_numeral(numeral(n, numeral::ui64()), bv_size); } - app* mk_bv0(unsigned bv_size) { return m_util.mk_numeral(numeral(0), bv_size); } - rational mk_allone(unsigned bv_size) { return rational::power_of_two(bv_size) - numeral(1); } - bool is_minus_one_core(expr * arg) const; - bool is_x_minus_one(expr * arg, expr * & x); - void mk_int2bv(expr * arg, sort* range, expr_ref & result); - void mk_bv2int(expr * arg, sort* range, expr_ref & result); - uint64 n64(expr* e); - bool is_mul_no_overflow(expr* e); - bool is_add_no_overflow(expr* e); - unsigned num_leading_zero_bits(expr* e); - -}; - -#endif /* BV_SIMPLIFIER_PLUGIN_H_ */ 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<func_decl> const* acc = m_util.get_constructor_accessors(f1); - SASSERT(acc && acc->size() == a->get_num_args()); - for (unsigned i = 0; i < acc->size(); ++i) { - if (f == (*acc)[i]) { - // found it. - result = a->get_arg(i); - return true; - } - } - UNREACHABLE(); - } - case OP_DT_UPDATE_FIELD: - return false; - default: - UNREACHABLE(); - } - - return false; -} - -bool datatype_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { - set_reduce_invoked(); - if (is_app_of(lhs, get_family_id(), OP_DT_CONSTRUCTOR) && - is_app_of(rhs, get_family_id(), OP_DT_CONSTRUCTOR)) { - app* a = to_app(lhs); - app* b = to_app(rhs); - if (a->get_decl() != b->get_decl()) { - result = m_manager.mk_false(); - return true; - } - expr_ref_vector eqs(m_manager); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - m_bsimp.mk_eq(a->get_arg(i),b->get_arg(i), result); - eqs.push_back(result); - } - m_bsimp.mk_and(eqs.size(), eqs.c_ptr(), result); - return true; - } - // TBD: occurs check, constructor check. - - return false; -} - 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: - - <abstract> - -Author: - - Leonardo de Moura (leonardo) 2008-06-28. - -Revision History: - ---*/ -#include "ast/simplifier/elim_bounds.h" -#include "ast/used_vars.h" -#include "util/obj_hashtable.h" -#include "ast/rewriter/var_subst.h" -#include "ast/ast_pp.h" - -elim_bounds::elim_bounds(ast_manager & m): - m_manager(m), - m_util(m) { -} - -/** - \brief Find bounds of the form - - (<= x k) - (<= (+ x (* -1 y)) k) - (<= (+ x (* -1 t)) k) - (<= (+ t (* -1 x)) k) - - x and y are a bound variables, t is a ground term and k is a numeral - - It also detects >=, and the atom can be negated. -*/ -bool elim_bounds::is_bound(expr * n, var * & lower, var * & upper) { - upper = 0; - lower = 0; - bool neg = false; - if (m_manager.is_not(n)) { - n = to_app(n)->get_arg(0); - neg = true; - } - - bool le = false; - if (m_util.is_le(n)) { - SASSERT(m_util.is_numeral(to_app(n)->get_arg(1))); - n = to_app(n)->get_arg(0); - le = true; - } - else if (m_util.is_ge(n)) { - SASSERT(m_util.is_numeral(to_app(n)->get_arg(1))); - n = to_app(n)->get_arg(0); - le = false; - } - else { - return false; - } - - if (neg) - le = !le; - - if (is_var(n)) { - upper = to_var(n); - } - else if (m_util.is_add(n) && to_app(n)->get_num_args() == 2) { - expr * arg1 = to_app(n)->get_arg(0); - expr * arg2 = to_app(n)->get_arg(1); - if (is_var(arg1)) - upper = to_var(arg1); - else if (!is_ground(arg1)) - return false; - rational k; - bool is_int; - if (m_util.is_mul(arg2) && m_util.is_numeral(to_app(arg2)->get_arg(0), k, is_int) && k.is_minus_one()) { - arg2 = to_app(arg2)->get_arg(1); - if (is_var(arg2)) - lower = to_var(arg2); - else if (!is_ground(arg2)) - return false; // not supported - } - else { - return false; // not supported - } - } - else { - return false; - } - - if (!le) - std::swap(upper, lower); - - return true; -} - -bool elim_bounds::is_bound(expr * n) { - var * lower, * upper; - return is_bound(n, lower, upper); -} - -void elim_bounds::operator()(quantifier * q, expr_ref & r) { - if (!q->is_forall()) { - r = q; - return; - } - expr * n = q->get_expr(); - unsigned num_vars = q->get_num_decls(); - ptr_buffer<expr> atoms; - if (m_manager.is_or(n)) - atoms.append(to_app(n)->get_num_args(), to_app(n)->get_args()); - else - atoms.push_back(n); - used_vars m_used_vars; - // collect non-candidates - unsigned sz = atoms.size(); - for (unsigned i = 0; i < sz; i++) { - expr * a = atoms[i]; - if (!is_bound(a)) - m_used_vars.process(a); - } - if (m_used_vars.uses_all_vars(q->get_num_decls())) { - r = q; - return; - } - // collect candidates - obj_hashtable<var> m_lowers; - obj_hashtable<var> m_uppers; - obj_hashtable<var> m_candidate_set; - ptr_buffer<var> m_candidates; -#define ADD_CANDIDATE(V) if (!m_lowers.contains(V) && !m_uppers.contains(V)) { m_candidate_set.insert(V); m_candidates.push_back(V); } - for (unsigned i = 0; i < sz; i++) { - expr * a = atoms[i]; - var * lower = 0; - var * upper = 0; - if (is_bound(a, lower, upper)) { - if (lower != 0 && !m_used_vars.contains(lower->get_idx()) && lower->get_idx() < num_vars) { - ADD_CANDIDATE(lower); - m_lowers.insert(lower); - } - if (upper != 0 && !m_used_vars.contains(upper->get_idx()) && upper->get_idx() < num_vars) { - ADD_CANDIDATE(upper); - m_uppers.insert(upper); - } - } - } - TRACE("elim_bounds", tout << "candidates:\n"; for (unsigned i = 0; i < m_candidates.size(); i++) tout << mk_pp(m_candidates[i], m_manager) << "\n";); - // remove candidates that have lower and upper bounds - for (unsigned i = 0; i < m_candidates.size(); i++) { - var * v = m_candidates[i]; - if (m_lowers.contains(v) && m_uppers.contains(v)) - m_candidate_set.erase(v); - } - TRACE("elim_bounds", tout << "candidates after filter:\n"; for (unsigned i = 0; i < m_candidates.size(); i++) tout << mk_pp(m_candidates[i], m_manager) << "\n";); - if (m_candidate_set.empty()) { - r = q; - return; - } - // remove bounds that contain variables in m_candidate_set - unsigned j = 0; - for (unsigned i = 0; i < sz; i++) { - expr * a = atoms[i]; - var * lower = 0; - var * upper = 0; - if (is_bound(a, lower, upper) && ((lower != 0 && m_candidate_set.contains(lower)) || (upper != 0 && m_candidate_set.contains(upper)))) - continue; - atoms[j] = a; - j++; - } - atoms.resize(j); - expr * new_body = 0; - switch (atoms.size()) { - case 0: - r = m_manager.mk_false(); - TRACE("elim_bounds", tout << mk_pp(q, m_manager) << "\n" << mk_pp(r, m_manager) << "\n";); - return; - case 1: - new_body = atoms[0]; - break; - default: - new_body = m_manager.mk_or(atoms.size(), atoms.c_ptr()); - break; - } - quantifier_ref new_q(m_manager); - new_q = m_manager.update_quantifier(q, new_body); - elim_unused_vars(m_manager, new_q, params_ref(), r); - TRACE("elim_bounds", tout << mk_pp(q, m_manager) << "\n" << mk_pp(r, m_manager) << "\n";); -} - -bool elim_bounds_star::visit_quantifier(quantifier * q) { - if (!q->is_forall() || q->get_num_patterns() != 0) - return true; - bool visited = true; - visit(q->get_expr(), visited); - return visited; -} - -void elim_bounds_star::reduce1_quantifier(quantifier * q) { - if (!q->is_forall() || q->get_num_patterns() != 0) { - cache_result(q, q, 0); - return; - } - quantifier_ref new_q(m); - expr * new_body = 0; - proof * new_pr; - get_cached(q->get_expr(), new_body, new_pr); - new_q = m.update_quantifier(q, new_body); - expr_ref r(m); - m_elim(new_q, r); - if (q == r.get()) { - cache_result(q, q, 0); - return; - } - proof_ref pr(m); - if (m.fine_grain_proofs()) - pr = m.mk_rewrite(q, r); // TODO: improve justification - cache_result(q, r, pr); -} - diff --git a/src/ast/simplifier/elim_bounds.h b/src/ast/simplifier/elim_bounds.h deleted file mode 100644 index d4da953a8..000000000 --- a/src/ast/simplifier/elim_bounds.h +++ /dev/null @@ -1,69 +0,0 @@ -/*++ -Copyright (c) 2006 Microsoft Corporation - -Module Name: - - elim_bounds.h - -Abstract: - - <abstract> - -Author: - - Leonardo de Moura (leonardo) 2008-06-28. - -Revision History: - ---*/ -#ifndef ELIM_BOUNDS_H_ -#define ELIM_BOUNDS_H_ - -#include "ast/ast.h" -#include "ast/arith_decl_plugin.h" -#include "ast/simplifier/simplifier.h" - -/** - \brief Functor for eliminating irrelevant bounds in quantified formulas. - - Example: - (forall (x Int) (y Int) (or (not (>= y x) (not (>= x 0)) (= (select a x) 1)))) - - The bound (>= y x) is irrelevant and can be eliminated. - - This can be easily proved by using Fourier-Motzkin elimination. - - Limitations & Assumptions: - - It assumes the input formula was already simplified. - - It can only handle bounds in the diff-logic fragment. - - \remark This operation is subsumed by Fourier-Motzkin elimination. -*/ -class elim_bounds { - ast_manager & m_manager; - 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); -}; - -/** - \brief Functor for applying elim_bounds in all - universal quantifiers in an expression. - - Assumption: the formula was already skolemized. -*/ -class elim_bounds_star : public simplifier { -protected: - elim_bounds m_elim; - virtual bool visit_quantifier(quantifier * q); - virtual void reduce1_quantifier(quantifier * q); -public: - elim_bounds_star(ast_manager & m):simplifier(m), m_elim(m) { enable_ac_support(false); } - virtual ~elim_bounds_star() {} -}; - -#endif /* ELIM_BOUNDS_H_ */ - 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<expr> & result) { - rational v; - for (unsigned i = 0; i < num_args; i++) { - expr * arg = args[i]; - if (is_numeral(arg, v)) - k *= v; - else - result.push_back(arg); - } -} - -#ifdef Z3DEBUG -/** - \brief Return true if m is a wellformed monomial. -*/ -bool poly_simplifier_plugin::wf_monomial(expr * m) const { - SASSERT(!is_add(m)); - if (is_mul(m)) { - app * curr = to_app(m); - expr * pp = 0; - if (is_numeral(curr->get_arg(0))) - pp = curr->get_arg(1); - else - pp = curr; - if (is_mul(pp)) { - for (unsigned i = 0; i < to_app(pp)->get_num_args(); i++) { - expr * arg = to_app(pp)->get_arg(i); - CTRACE("wf_monomial_bug", is_mul(arg), - tout << "m: " << mk_ismt2_pp(m, m_manager) << "\n"; - tout << "pp: " << mk_ismt2_pp(pp, m_manager) << "\n"; - tout << "arg: " << mk_ismt2_pp(arg, m_manager) << "\n"; - tout << "i: " << i << "\n"; - ); - SASSERT(!is_mul(arg)); - SASSERT(!is_numeral(arg)); - } - } - } - return true; -} - -/** - \brief Return true if m is a wellformed polynomial. -*/ -bool poly_simplifier_plugin::wf_polynomial(expr * m) const { - if (is_add(m)) { - for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { - expr * arg = to_app(m)->get_arg(i); - SASSERT(!is_add(arg)); - SASSERT(wf_monomial(arg)); - } - } - else if (is_mul(m)) { - SASSERT(wf_monomial(m)); - } - return true; -} -#endif - -/** - \brief Functor used to sort the elements of a monomial. - Force numeric constants to be in the beginning. -*/ -struct monomial_element_lt_proc { - poly_simplifier_plugin & m_plugin; - monomial_element_lt_proc(poly_simplifier_plugin & p):m_plugin(p) {} - bool operator()(expr * m1, expr * m2) const { - SASSERT(!m_plugin.is_numeral(m1) || !m_plugin.is_numeral(m2)); - if (m_plugin.is_numeral(m1)) - return true; - if (m_plugin.is_numeral(m2)) - return false; - return m1->get_id() < m2->get_id(); - } -}; - -/** - \brief Create a monomial (* args). -*/ -void poly_simplifier_plugin::mk_monomial(unsigned num_args, expr * * args, expr_ref & result) { - switch(num_args) { - case 0: - result = mk_one(); - break; - case 1: - result = args[0]; - break; - default: - std::stable_sort(args, args + num_args, monomial_element_lt_proc(*this)); - result = mk_mul(num_args, args); - SASSERT(wf_monomial(result)); - break; - } -} - -/** - \brief Return the body of the monomial. That is, the monomial without a coefficient. - Examples: (* 2 (* x y)) ==> (* x y) - (* x x) ==> (* x x) - x ==> x - 10 ==> 10 -*/ -expr * poly_simplifier_plugin::get_monomial_body(expr * m) { - TRACE("get_monomial_body_bug", tout << mk_pp(m, m_manager) << "\n";); - SASSERT(wf_monomial(m)); - if (!is_mul(m)) - return m; - if (is_numeral(to_app(m)->get_arg(0))) - return to_app(m)->get_arg(1); - return m; -} - -inline bool is_essentially_var(expr * n, family_id fid) { - SASSERT(is_var(n) || is_app(n)); - return is_var(n) || to_app(n)->get_family_id() != fid; -} - -/** - \brief Hack for ordering monomials. - We want an order << where - - (* c1 m1) << (* c2 m2) when m1->get_id() < m2->get_id(), and c1 and c2 are numerals. - - c << m when c is a numeral, and m is not. - - So, this method returns -1 for numerals, and the id of the body of the monomial -*/ -int poly_simplifier_plugin::get_monomial_body_order(expr * m) { - if (is_essentially_var(m, m_fid)) { - return m->get_id(); - } - else if (is_mul(m)) { - if (is_numeral(to_app(m)->get_arg(0))) - return to_app(m)->get_arg(1)->get_id(); - else - return m->get_id(); - } - else if (is_numeral(m)) { - return -1; - } - else { - return m->get_id(); - } -} - -void poly_simplifier_plugin::get_monomial_coeff(expr * m, numeral & result) { - SASSERT(!is_numeral(m)); - SASSERT(wf_monomial(m)); - if (!is_mul(m)) - result = numeral::one(); - else if (is_numeral(to_app(m)->get_arg(0), result)) - return; - else - result = numeral::one(); -} - -/** - \brief Return true if n1 and n2 can be written as k1 * t and k2 * t, where k1 and - k2 are numerals, or n1 and n2 are both numerals. -*/ -bool poly_simplifier_plugin::eq_monomials_modulo_k(expr * n1, expr * n2) { - bool is_num1 = is_numeral(n1); - bool is_num2 = is_numeral(n2); - if (is_num1 != is_num2) - return false; - if (is_num1 && is_num2) - return true; - return get_monomial_body(n1) == get_monomial_body(n2); -} - -/** - \brief Return (k1 + k2) * t (or (k1 - k2) * t when inv = true), where n1 = k1 * t, and n2 = k2 * t - Return false if the monomials cancel each other. -*/ -bool poly_simplifier_plugin::merge_monomials(bool inv, expr * n1, expr * n2, expr_ref & result) { - numeral k1; - numeral k2; - bool is_num1 = is_numeral(n1, k1); - bool is_num2 = is_numeral(n2, k2); - SASSERT(is_num1 == is_num2); - if (!is_num1 && !is_num2) { - get_monomial_coeff(n1, k1); - get_monomial_coeff(n2, k2); - SASSERT(eq_monomials_modulo_k(n1, n2)); - } - if (inv) - k1 -= k2; - else - k1 += k2; - if (k1.is_zero()) - return false; - if (is_num1 && is_num2) { - result = mk_numeral(k1); - } - else { - expr * b = get_monomial_body(n1); - if (k1.is_one()) - result = b; - else - result = m_manager.mk_app(m_fid, m_MUL, mk_numeral(k1), b); - } - TRACE("merge_monomials", tout << mk_pp(n1, m_manager) << "\n" << mk_pp(n2, m_manager) << "\n" << mk_pp(result, m_manager) << "\n";); - return true; -} - -/** - \brief Return a monomial equivalent to -n. -*/ -void poly_simplifier_plugin::inv_monomial(expr * n, expr_ref & result) { - set_curr_sort(n); - SASSERT(wf_monomial(n)); - rational v; - SASSERT(n != 0); - TRACE("inv_monomial_bug", tout << "n:\n" << mk_ismt2_pp(n, m_manager) << "\n";); - if (is_numeral(n, v)) { - TRACE("inv_monomial_bug", tout << "is numeral\n";); - v.neg(); - result = mk_numeral(v); - } - else { - TRACE("inv_monomial_bug", tout << "is not numeral\n";); - numeral k; - get_monomial_coeff(n, k); - expr * b = get_monomial_body(n); - k.neg(); - if (k.is_one()) - result = b; - else - result = m_manager.mk_app(m_fid, m_MUL, mk_numeral(k), b); - } -} - -/** - \brief Add a monomial n to result. -*/ -template<bool Inv> -void poly_simplifier_plugin::add_monomial_core(expr * n, expr_ref_vector & result) { - if (is_zero(n)) - return; - if (Inv) { - expr_ref n_prime(m_manager); - inv_monomial(n, n_prime); - result.push_back(n_prime); - } - else { - result.push_back(n); - } -} - -void poly_simplifier_plugin::add_monomial(bool inv, expr * n, expr_ref_vector & result) { - if (inv) - add_monomial_core<true>(n, result); - else - add_monomial_core<false>(n, result); -} - -/** - \brief Copy the monomials in n to result. The monomials are inverted if inv is true. - Equivalent monomials are merged. -*/ -template<bool Inv> -void poly_simplifier_plugin::process_sum_of_monomials_core(expr * n, expr_ref_vector & result) { - SASSERT(wf_polynomial(n)); - if (is_add(n)) { - for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) - add_monomial_core<Inv>(to_app(n)->get_arg(i), result); - } - else { - add_monomial_core<Inv>(n, result); - } -} - -void poly_simplifier_plugin::process_sum_of_monomials(bool inv, expr * n, expr_ref_vector & result) { - if (inv) - process_sum_of_monomials_core<true>(n, result); - else - process_sum_of_monomials_core<false>(n, result); -} - -/** - \brief Copy the (non-numeral) monomials in n to result. The monomials are inverted if inv is true. - Equivalent monomials are merged. The constant (numeral) monomials are accumulated in k. -*/ -void poly_simplifier_plugin::process_sum_of_monomials(bool inv, expr * n, expr_ref_vector & result, numeral & k) { - SASSERT(wf_polynomial(n)); - numeral val; - if (is_add(n)) { - for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) { - expr * arg = to_app(n)->get_arg(i); - if (is_numeral(arg, val)) { - k += inv ? -val : val; - } - else { - add_monomial(inv, arg, result); - } - } - } - else if (is_numeral(n, val)) { - k += inv ? -val : val; - } - else { - add_monomial(inv, n, result); - } -} - -/** - \brief Functor used to sort monomials. - Force numeric constants to be in the beginning of a polynomial. -*/ -struct monomial_lt_proc { - poly_simplifier_plugin & m_plugin; - monomial_lt_proc(poly_simplifier_plugin & p):m_plugin(p) {} - bool operator()(expr * m1, expr * m2) const { - return m_plugin.get_monomial_body_order(m1) < m_plugin.get_monomial_body_order(m2); - } -}; - -void poly_simplifier_plugin::mk_sum_of_monomials_core(unsigned sz, expr ** ms, expr_ref & result) { - switch (sz) { - case 0: - result = mk_zero(); - break; - case 1: - result = ms[0]; - break; - default: - result = mk_add(sz, ms); - break; - } -} - -/** - \brief Return true if m is essentially a variable, or is of the form (* c x), - where c is a numeral and x is essentially a variable. - Store the "variable" in x. -*/ -bool poly_simplifier_plugin::is_simple_monomial(expr * m, expr * & x) { - if (is_essentially_var(m, m_fid)) { - x = m; - return true; - } - if (is_app(m) && to_app(m)->get_num_args() == 2) { - expr * arg1 = to_app(m)->get_arg(0); - expr * arg2 = to_app(m)->get_arg(1); - if (is_numeral(arg1) && is_essentially_var(arg2, m_fid)) { - x = arg2; - return true; - } - } - return false; -} - -/** - \brief Return true if all monomials are simple, and each "variable" occurs only once. - The method assumes the monomials were sorted using monomial_lt_proc. -*/ -bool poly_simplifier_plugin::is_simple_sum_of_monomials(expr_ref_vector & monomials) { - expr * last_var = 0; - expr * curr_var = 0; - unsigned size = monomials.size(); - for (unsigned i = 0; i < size; i++) { - expr * m = monomials.get(i); - if (!is_simple_monomial(m, curr_var)) - return false; - if (curr_var == last_var) - return false; - last_var = curr_var; - } - return true; -} - -/** - \brief Store in result the sum of the given monomials. -*/ -void poly_simplifier_plugin::mk_sum_of_monomials(expr_ref_vector & monomials, expr_ref & result) { - switch (monomials.size()) { - case 0: - result = mk_zero(); - break; - case 1: - result = monomials.get(0); - break; - default: { - TRACE("mk_sum_sort", tout << "before\n"; for (unsigned i = 0; i < monomials.size(); i++) tout << mk_ll_pp(monomials.get(i), m_manager) << "\n";); - std::stable_sort(monomials.c_ptr(), monomials.c_ptr() + monomials.size(), monomial_lt_proc(*this)); - TRACE("mk_sum_sort", tout << "after\n"; for (unsigned i = 0; i < monomials.size(); i++) tout << mk_ll_pp(monomials.get(i), m_manager) << "\n";); - if (is_simple_sum_of_monomials(monomials)) { - mk_sum_of_monomials_core(monomials.size(), monomials.c_ptr(), result); - return; - } - ptr_buffer<expr> new_monomials; - expr * last_body = 0; - numeral last_coeff; - numeral coeff; - unsigned sz = monomials.size(); - for (unsigned i = 0; i < sz; i++) { - expr * m = monomials.get(i); - expr * body = 0; - if (!is_numeral(m, coeff)) { - body = get_monomial_body(m); - get_monomial_coeff(m, coeff); - } - if (last_body == body) { - last_coeff += coeff; - continue; - } - expr * new_m = mk_mul(last_coeff, last_body); - if (new_m) - new_monomials.push_back(new_m); - last_body = body; - last_coeff = coeff; - } - expr * new_m = mk_mul(last_coeff, last_body); - if (new_m) - new_monomials.push_back(new_m); - TRACE("mk_sum", for (unsigned i = 0; i < monomials.size(); i++) tout << mk_pp(monomials.get(i), m_manager) << "\n"; - tout << "======>\n"; - for (unsigned i = 0; i < new_monomials.size(); i++) tout << mk_pp(new_monomials.get(i), m_manager) << "\n";); - mk_sum_of_monomials_core(new_monomials.size(), new_monomials.c_ptr(), result); - break; - } } -} - -/** - \brief Auxiliary template for mk_add_core -*/ -template<bool Inv> -void poly_simplifier_plugin::mk_add_core_core(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(num_args >= 2); - expr_ref_vector monomials(m_manager); - process_sum_of_monomials_core<false>(args[0], monomials); - for (unsigned i = 1; i < num_args; i++) { - process_sum_of_monomials_core<Inv>(args[i], monomials); - } - TRACE("mk_add_core_bug", - for (unsigned i = 0; i < monomials.size(); i++) { - SASSERT(monomials.get(i) != 0); - tout << mk_ismt2_pp(monomials.get(i), m_manager) << "\n"; - }); - mk_sum_of_monomials(monomials, result); -} - -/** - \brief Return a sum of monomials. The method assume that each arg in args is a sum of monomials. - If inv is true, then all but the first argument in args are inverted. -*/ -void poly_simplifier_plugin::mk_add_core(bool inv, unsigned num_args, expr * const * args, expr_ref & result) { - TRACE("mk_add_core_bug", - for (unsigned i = 0; i < num_args; i++) { - SASSERT(args[i] != 0); - tout << mk_ismt2_pp(args[i], m_manager) << "\n"; - }); - switch (num_args) { - case 0: - result = mk_zero(); - break; - case 1: - result = args[0]; - break; - default: - if (inv) - mk_add_core_core<true>(num_args, args, result); - else - mk_add_core_core<false>(num_args, args, result); - break; - } -} - -void poly_simplifier_plugin::mk_add(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(num_args > 0); - set_curr_sort(args[0]); - mk_add_core(false, num_args, args, result); -} - -void poly_simplifier_plugin::mk_add(expr * arg1, expr * arg2, expr_ref & result) { - expr * args[2] = { arg1, arg2 }; - mk_add(2, args, result); -} - -void poly_simplifier_plugin::mk_sub(unsigned num_args, expr * const * args, expr_ref & result) { - SASSERT(num_args > 0); - set_curr_sort(args[0]); - mk_add_core(true, num_args, args, result); -} - -void poly_simplifier_plugin::mk_sub(expr * arg1, expr * arg2, expr_ref & result) { - expr * args[2] = { arg1, arg2 }; - mk_sub(2, args, result); -} - -void poly_simplifier_plugin::mk_uminus(expr * arg, expr_ref & result) { - set_curr_sort(arg); - rational v; - if (is_numeral(arg, v)) { - v.neg(); - result = mk_numeral(v); - } - else { - expr_ref zero(mk_zero(), m_manager); - mk_sub(zero.get(), arg, result); - } -} - -/** - \brief Add monomial n to result, the coeff of n is stored in k. -*/ -void poly_simplifier_plugin::append_to_monomial(expr * n, numeral & k, ptr_buffer<expr> & result) { - SASSERT(wf_monomial(n)); - rational val; - if (is_numeral(n, val)) { - k *= val; - return; - } - get_monomial_coeff(n, val); - k *= val; - n = get_monomial_body(n); - - unsigned hd = result.size(); - result.push_back(n); - while (hd < result.size()) { - n = result[hd]; - if (is_mul(n)) { - result[hd] = result.back(); - result.pop_back(); - for (unsigned i = 0; i < to_app(n)->get_num_args(); i++) { - result.push_back(to_app(n)->get_arg(i)); - } - } - else if (is_numeral(n, val)) { - k *= val; - result[hd] = result.back(); - result.pop_back(); - } - else { - ++hd; - } - } -} - -/** - \brief Return a sum of monomials that is equivalent to (* args[0] ... args[num_args-1]). - This method assumes that each arg[i] is a sum of monomials. -*/ -void poly_simplifier_plugin::mk_mul(unsigned num_args, expr * const * args, expr_ref & result) { - if (num_args == 1) { - result = args[0]; - return; - } - rational val; - if (num_args == 2 && is_numeral(args[0], val) && is_essentially_var(args[1], m_fid)) { - if (val.is_one()) - result = args[1]; - else if (val.is_zero()) - result = args[0]; - else - result = mk_mul(num_args, args); - return; - } - if (num_args == 2 && is_essentially_var(args[0], m_fid) && is_numeral(args[1], val)) { - if (val.is_one()) - result = args[0]; - else if (val.is_zero()) - result = args[1]; - else { - expr * inv_args[2] = { args[1], args[0] }; - result = mk_mul(2, inv_args); - } - return; - } - - TRACE("mk_mul_bug", - for (unsigned i = 0; i < num_args; i++) { - tout << mk_pp(args[i], m_manager) << "\n"; - }); - set_curr_sort(args[0]); - buffer<unsigned> szs; - buffer<unsigned> it; - vector<ptr_vector<expr> > sums; - for (unsigned i = 0; i < num_args; i ++) { - it.push_back(0); - expr * arg = args[i]; - SASSERT(wf_polynomial(arg)); - sums.push_back(ptr_vector<expr>()); - ptr_vector<expr> & v = sums.back(); - if (is_add(arg)) { - v.append(to_app(arg)->get_num_args(), to_app(arg)->get_args()); - } - else { - v.push_back(arg); - } - szs.push_back(v.size()); - } - expr_ref_vector monomials(m_manager); - do { - rational k(1); - ptr_buffer<expr> m; - for (unsigned i = 0; i < num_args; i++) { - ptr_vector<expr> & v = sums[i]; - expr * arg = v[it[i]]; - TRACE("mk_mul_bug", tout << "k: " << k << " arg: " << mk_pp(arg, m_manager) << "\n";); - append_to_monomial(arg, k, m); - TRACE("mk_mul_bug", tout << "after k: " << k << "\n";); - } - expr_ref num(m_manager); - if (!k.is_zero() && !k.is_one()) { - num = mk_numeral(k); - m.push_back(num); - // bit-vectors can normalize - // to 1 during - // internalization. - if (is_numeral(num, k) && k.is_one()) { - m.pop_back(); - } - } - if (!k.is_zero()) { - expr_ref new_monomial(m_manager); - TRACE("mk_mul_bug", - for (unsigned i = 0; i < m.size(); i++) { - tout << mk_pp(m[i], m_manager) << "\n"; - }); - mk_monomial(m.size(), m.c_ptr(), new_monomial); - TRACE("mk_mul_bug", tout << "new_monomial:\n" << mk_pp(new_monomial, m_manager) << "\n";); - add_monomial_core<false>(new_monomial, monomials); - } - } - while (product_iterator_next(szs.size(), szs.c_ptr(), it.c_ptr())); - mk_sum_of_monomials(monomials, result); -} - -void poly_simplifier_plugin::mk_mul(expr * arg1, expr * arg2, expr_ref & result) { - expr * args[2] = { arg1, arg2 }; - mk_mul(2, args, result); -} - -bool poly_simplifier_plugin::reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - unsigned i = 0; - for (; i < num_args; i++) - if (!is_numeral(args[i])) - break; - if (i == num_args) { - // all arguments are numerals - // check if arguments are different... - ptr_buffer<expr> buffer; - buffer.append(num_args, args); - std::sort(buffer.begin(), buffer.end(), ast_lt_proc()); - for (unsigned i = 0; i < num_args; i++) { - if (i > 0 && buffer[i] == buffer[i-1]) { - result = m_manager.mk_false(); - return true; - } - } - result = m_manager.mk_true(); - return true; - } - return false; -} - -bool poly_simplifier_plugin::reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - if (is_decl_of(f, m_fid, m_ADD)) { - SASSERT(num_args > 0); - set_curr_sort(args[0]); - expr_ref_buffer args1(m_manager); - for (unsigned i = 0; i < num_args; ++i) { - expr * arg = args[i]; - rational m = norm(mults[i]); - if (m.is_zero()) { - // skip - } - else if (m.is_one()) { - args1.push_back(arg); - } - else { - expr_ref k(m_manager); - k = mk_numeral(m); - expr_ref new_arg(m_manager); - mk_mul(k, args[i], new_arg); - args1.push_back(new_arg); - } - } - if (args1.empty()) { - result = mk_zero(); - } - else { - mk_add(args1.size(), args1.c_ptr(), result); - } - return true; - } - else { - return simplifier_plugin::reduce(f, num_args, mults, args, result); - } -} - -/** - \brief Return true if n is can be put into the form (+ v t) or (+ (- v) t) - \c inv = true will contain true if (- v) is found, and false otherwise. -*/ -bool poly_simplifier_plugin::is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t) { - if (!is_add(n) || is_ground(n)) - return false; - - ptr_buffer<expr> args; - v = 0; - expr * curr = to_app(n); - bool stop = false; - inv = false; - while (!stop) { - expr * arg; - expr * neg_arg; - if (is_add(curr)) { - arg = to_app(curr)->get_arg(0); - curr = to_app(curr)->get_arg(1); - } - else { - arg = curr; - stop = true; - } - if (is_ground(arg)) { - TRACE("model_checker_bug", tout << "pushing:\n" << mk_pp(arg, m_manager) << "\n";); - args.push_back(arg); - } - else if (is_var(arg)) { - if (v != 0) - return false; // already found variable - v = to_var(arg); - } - else if (is_times_minus_one(arg, neg_arg) && is_var(neg_arg)) { - if (v != 0) - return false; // already found variable - v = to_var(neg_arg); - inv = true; - } - else { - return false; // non ground term. - } - } - if (v == 0) - return false; // did not find variable - SASSERT(!args.empty()); - mk_add(args.size(), args.c_ptr(), t); - return true; -} 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<expr> & result); - void mk_monomial(unsigned num_args, expr * * args, expr_ref & result); - bool eq_monomials_modulo_k(expr * n1, expr * n2); - bool merge_monomials(bool inv, expr * n1, expr * n2, expr_ref & result); - template<bool Inv> - void add_monomial_core(expr * n, expr_ref_vector & result); - void add_monomial(bool inv, expr * n, expr_ref_vector & result); - template<bool Inv> - void process_sum_of_monomials_core(expr * n, expr_ref_vector & result); - void process_sum_of_monomials(bool inv, expr * n, expr_ref_vector & result); - void process_sum_of_monomials(bool inv, expr * n, expr_ref_vector & result, numeral & k); - void mk_sum_of_monomials(expr_ref_vector & monomials, expr_ref & result); - template<bool Inv> - void mk_add_core_core(unsigned num_args, expr * const * args, expr_ref & result); - void mk_add_core(bool inv, unsigned num_args, expr * const * args, expr_ref & result); - void append_to_monomial(expr * n, numeral & k, ptr_buffer<expr> & result); - expr * mk_mul(numeral const & c, expr * body); - void mk_sum_of_monomials_core(unsigned sz, expr ** ms, expr_ref & result); - bool is_simple_sum_of_monomials(expr_ref_vector & monomials); - bool is_simple_monomial(expr * m, expr * & x); - -public: - poly_simplifier_plugin(symbol const & fname, ast_manager & m, decl_kind add, decl_kind mul, decl_kind uminus, decl_kind sub, decl_kind num); - virtual ~poly_simplifier_plugin() {} - - /** - \brief Return true if the given expression is a numeral, and store its value in \c val. - */ - virtual bool is_numeral(expr * n, numeral & val) const = 0; - bool is_numeral(expr * n) const { return is_app_of(n, m_fid, m_NUM); } - bool is_zero(expr * n) const { - SASSERT(m_curr_sort_zero != 0); - SASSERT(m_manager.get_sort(n) == m_manager.get_sort(m_curr_sort_zero)); - return n == m_curr_sort_zero; - } - bool is_zero_safe(expr * n) { - set_curr_sort(m_manager.get_sort(n)); - return is_zero(n); - } - virtual bool is_minus_one(expr * n) const = 0; - virtual expr * get_zero(sort * s) const = 0; - - - /** - \brief Return true if n is of the form (* -1 r) - */ - bool is_times_minus_one(expr * n, expr * & r) const { - if (is_mul(n) && to_app(n)->get_num_args() == 2 && is_minus_one(to_app(n)->get_arg(0))) { - r = to_app(n)->get_arg(1); - return true; - } - return false; - } - - /** - \brief Return true if n is of the form: a <= b or a >= b. - */ - virtual bool is_le_ge(expr * n) const = 0; - - /** - \brief Return a constant representing the giving numeral and sort m_curr_sort. - */ - virtual app * mk_numeral(numeral const & n) = 0; - app * mk_zero() { return mk_numeral(numeral::zero()); } - app * mk_one() { return mk_numeral(numeral::one()); } - app * mk_minus_one() { return mk_numeral(numeral::minus_one()); } - - /** - \brief Normalize the given numeral with respect to m_curr_sort - */ - virtual numeral norm(numeral const & n) = 0; - - void set_curr_sort(sort * s) { - if (s != m_curr_sort) { - // avoid virtual function call - m_curr_sort = s; - m_curr_sort_zero = get_zero(m_curr_sort); - } - } - void set_curr_sort(expr * n) { set_curr_sort(m_manager.get_sort(n)); } - - bool is_add(expr const * n) const { return is_app_of(n, m_fid, m_ADD); } - bool is_mul(expr const * n) const { return is_app_of(n, m_fid, m_MUL); } - void mk_add(unsigned num_args, expr * const * args, expr_ref & result); - void mk_add(expr * arg1, expr * arg2, expr_ref & result); - void mk_sub(unsigned num_args, expr * const * args, expr_ref & result); - void mk_sub(expr * arg1, expr * arg2, expr_ref & result); - void mk_uminus(expr * arg, expr_ref & result); - void mk_mul(unsigned num_args, expr * const * args, expr_ref & result); - void mk_mul(expr * arg1, expr * arg2, expr_ref & result); - - virtual bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result); - - virtual bool reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result); - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - return simplifier_plugin::reduce(f, num_args, args, result); - } - - - expr * get_monomial_body(expr * m); - int get_monomial_body_order(expr * m); - void get_monomial_coeff(expr * m, numeral & result); - void inv_monomial(expr * n, expr_ref & result); - - bool is_var_plus_ground(expr * n, bool & inv, var * & v, expr_ref & t); - -#ifdef Z3DEBUG - bool wf_monomial(expr * m) const; - bool wf_polynomial(expr * m) const; -#endif -}; - -#endif /* POLY_SIMPLIFIER_PLUGIN_H_ */ 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 c02753440..000000000 --- a/src/ast/simplifier/simplifier.cpp +++ /dev/null @@ -1,962 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - simplifier.cpp - -Abstract: - - Expression simplifier. - -Author: - - Leonardo (leonardo) 2008-01-03 - -Notes: - ---*/ -#include "ast/simplifier/simplifier.h" -#include "ast/rewriter/var_subst.h" -#include "ast/ast_ll_pp.h" -#include "ast/ast_pp.h" -#include "ast/well_sorted.h" -#include "ast/ast_smt_pp.h" - -simplifier::simplifier(ast_manager & m): - base_simplifier(m), - m_proofs(m), - m_subst_proofs(m), - m_need_reset(false), - m_use_oeq(false), - m_visited_quantifier(false), - m_ac_support(true) { -} - -void simplifier::register_plugin(plugin * p) { - m_plugins.register_plugin(p); -} - -simplifier::~simplifier() { - flush_cache(); -} - -void simplifier::enable_ac_support(bool flag) { - m_ac_support = flag; - ptr_vector<plugin>::const_iterator it = m_plugins.begin(); - ptr_vector<plugin>::const_iterator end = m_plugins.end(); - for (; it != end; ++it) { - if (*it != 0) - (*it)->enable_ac_support(flag); - } -} - -/** - \brief External interface for the simplifier. - A client will invoke operator()(s, r, p) to simplify s. - The result is stored in r. - When proof generation is enabled, a proof for the equivalence (or equisatisfiability) - of s and r is stored in p. - When proof generation is disabled, this method stores the "undefined proof" object in p. -*/ -void simplifier::operator()(expr * s, expr_ref & r, proof_ref & p) { - m_need_reset = true; - reinitialize(); - expr * s_orig = s; - (void)s_orig; - expr * old_s; - expr * result; - proof * result_proof; - switch (m.proof_mode()) { - case PGM_DISABLED: // proof generation is disabled. - reduce_core(s); - // after executing reduce_core, the result of the simplification is in the cache - get_cached(s, result, result_proof); - r = result; - p = m.mk_undef_proof(); - break; - case PGM_COARSE: // coarse proofs... in this case, we do not produce a step by step (fine grain) proof to show the equivalence (or equisatisfiability) of s an r. - m_subst_proofs.reset(); // m_subst_proofs is an auxiliary vector that is used to justify substitutions. See comment on method get_subst. - reduce_core(s); - get_cached(s, result, result_proof); - r = result; - if (result == s) - p = m.mk_reflexivity(s); - else { - remove_duplicates(m_subst_proofs); - p = m.mk_rewrite_star(s, result, m_subst_proofs.size(), m_subst_proofs.c_ptr()); - } - break; - case PGM_FINE: // fine grain proofs... in this mode, every proof step (or most of them) is described. - m_proofs.reset(); - old_s = 0; - // keep simplyfing until no further simplifications are possible. - while (s != old_s) { - TRACE("simplifier", tout << "simplification pass... " << s->get_id() << "\n";); - TRACE("simplifier_loop", tout << mk_ll_pp(s, m) << "\n";); - reduce_core(s); - get_cached(s, result, result_proof); - SASSERT(is_rewrite_proof(s, result, result_proof)); - if (result_proof != 0) { - m_proofs.push_back(result_proof); - } - old_s = s; - s = result; - } - SASSERT(s != 0); - r = s; - p = m_proofs.empty() ? m.mk_reflexivity(s) : m.mk_transitivity(m_proofs.size(), m_proofs.c_ptr()); - SASSERT(is_rewrite_proof(s_orig, r, p)); - break; - default: - UNREACHABLE(); - } -} - -void simplifier::flush_cache() { - m_cache.flush(); - ptr_vector<plugin>::const_iterator it = m_plugins.begin(); - ptr_vector<plugin>::const_iterator end = m_plugins.end(); - for (; it != end; ++it) { - if (*it != 0) { - (*it)->flush_caches(); - } - } -} - -bool simplifier::get_subst(expr * n, expr_ref & r, proof_ref & p) { - return false; -} - -void simplifier::reduce_core(expr * n1) { - if (!is_cached(n1)) { - // We do not assume m_todo is empty... So, we store the current size of the todo-stack. - unsigned sz = m_todo.size(); - m_todo.push_back(n1); - while (m_todo.size() != sz) { - expr * n = m_todo.back(); - if (is_cached(n)) - m_todo.pop_back(); - else if (visit_children(n)) { - // if all children were already simplified, then remove n from the todo stack and apply a - // simplification step to it. - m_todo.pop_back(); - reduce1(n); - } - if (m.canceled()) { - cache_result(n1, n1, 0); - break; - } - } - } -} - -/** - \brief Return true if all children of n have been already simplified. -*/ -bool simplifier::visit_children(expr * n) { - switch(n->get_kind()) { - case AST_VAR: - return true; - case AST_APP: - // The simplifier has support for flattening AC (associative-commutative) operators. - // The method ast_manager::mk_app is used to create the flat version of an AC operator. - // In Z3 1.x, we used multi-ary operators. This creates problems for the superposition engine. - // So, starting at Z3 2.x, only boolean operators can be multi-ary. - // Example: - // (and (and a b) (and c d)) --> (and a b c d) - // (+ (+ a b) (+ c d)) --> (+ a (+ b (+ c d))) - // Remark: The flattening is only applied if m_ac_support is true. - if (m_ac_support && to_app(n)->get_decl()->is_associative() && to_app(n)->get_decl()->is_commutative()) - return visit_ac(to_app(n)); - else { - bool visited = true; - unsigned j = to_app(n)->get_num_args(); - while (j > 0) { - --j; - visit(to_app(n)->get_arg(j), visited); - } - return visited; - } - case AST_QUANTIFIER: - return visit_quantifier(to_quantifier(n)); - default: - UNREACHABLE(); - return true; - } -} - -/** - \brief Visit the children of n assuming it is an AC (associative-commutative) operator. - - For example, if n is of the form (+ (+ a b) (+ c d)), this method - will return true if the nodes a, b, c and d have been already simplified. - The nodes (+ a b) and (+ c d) are not really checked. -*/ -bool simplifier::visit_ac(app * n) { - bool visited = true; - func_decl * decl = n->get_decl(); - SASSERT(m_ac_support); - SASSERT(decl->is_associative()); - SASSERT(decl->is_commutative()); - m_ac_marked.reset(); - ptr_buffer<app> todo; - todo.push_back(n); - while (!todo.empty()) { - app * n = todo.back(); - todo.pop_back(); - if (m_ac_mark.is_marked(n)) - continue; - m_ac_mark.mark(n, true); - m_ac_marked.push_back(n); - SASSERT(n->get_decl() == decl); - unsigned i = n->get_num_args(); - while (i > 0) { - --i; - expr * arg = n->get_arg(i); - if (is_app_of(arg, decl)) - todo.push_back(to_app(arg)); - else - visit(arg, visited); - } - } - ptr_vector<expr>::const_iterator it = m_ac_marked.begin(); - ptr_vector<expr>::const_iterator end = m_ac_marked.end(); - for (; it != end; ++it) - m_ac_mark.mark(*it, false); - return visited; -} - -bool simplifier::visit_quantifier(quantifier * n) { - m_visited_quantifier = true; - bool visited = true; - unsigned j = to_quantifier(n)->get_num_patterns(); - while (j > 0) { - --j; - visit(to_quantifier(n)->get_pattern(j), visited); - } - j = to_quantifier(n)->get_num_no_patterns(); - while (j > 0) { - --j; - visit(to_quantifier(n)->get_no_pattern(j), visited); - } - visit(to_quantifier(n)->get_expr(), visited); - return visited; -} - -/** - \brief Simplify n and store the result in the cache. -*/ -void simplifier::reduce1(expr * n) { - switch (n->get_kind()) { - case AST_VAR: - cache_result(n, n, 0); - break; - case AST_APP: - reduce1_app(to_app(n)); - break; - case AST_QUANTIFIER: - reduce1_quantifier(to_quantifier(n)); - break; - default: - UNREACHABLE(); - } -} - -/** - \brief Simplify the given application using the cached values, - associativity flattening, the given substitution, and family/theory - specific simplifications via plugins. -*/ -void simplifier::reduce1_app(app * n) { - expr_ref r(m); - proof_ref p(m); - TRACE("reduce", tout << "reducing...\n" << mk_pp(n, m) << "\n";); - if (get_subst(n, r, p)) { - TRACE("reduce", tout << "applying substitution...\n";); - cache_result(n, r, p); - return; - } - - func_decl * decl = n->get_decl(); - if (m_ac_support && decl->is_associative() && decl->is_commutative()) - reduce1_ac_app_core(n); - else - reduce1_app_core(n); -} - - -void simplifier::reduce1_app_core(app * n) { - m_args.reset(); - func_decl * decl = n->get_decl(); - proof_ref p1(m); - // Stores the new arguments of n in m_args. - // Let n be of the form - // (decl arg_0 ... arg_{n-1}) - // then - // m_args contains [arg_0', ..., arg_{n-1}'], - // where arg_i' is the simplification of arg_i - // and - // p1 is a proof for - // (decl arg_0 ... arg_{n-1}) is equivalente/equisatisfiable to (decl arg_0' ... arg_{n-1}') - // p1 is built using the congruence proof step and the proofs for arg_0' ... arg_{n-1}'. - // Of course, p1 is 0 if proofs are not enabled or coarse grain proofs are used. - bool has_new_args = get_args(n, m_args, p1); - // The following if implements a simple trick. - // If none of the arguments have been simplified, and n is not a theory symbol, - // Then no simplification is possible, and we can cache the result of the simplification of n as n. - if (has_new_args || decl->get_family_id() != null_family_id) { - expr_ref r(m); - TRACE("reduce", tout << "reduce1_app\n"; for(unsigned i = 0; i < m_args.size(); i++) tout << mk_ll_pp(m_args[i], m);); - // the method mk_app invokes get_subst and plugins to simplify - // (decl arg_0' ... arg_{n-1}') - mk_app(decl, m_args.size(), m_args.c_ptr(), r); - if (!m.fine_grain_proofs()) { - cache_result(n, r, 0); - } - else { - expr * s = m.mk_app(decl, m_args.size(), m_args.c_ptr()); - proof * p; - if (n == r) - p = 0; - else if (r != s) - // we use a "theory rewrite generic proof" to justify the step - // s = (decl arg_0' ... arg_{n-1}') --> r - p = m.mk_transitivity(p1, m.mk_rewrite(s, r)); - else - p = p1; - cache_result(n, r, p); - } - } - else { - cache_result(n, n, 0); - } -} - -bool is_ac_list(app * n, ptr_vector<expr> & args) { - args.reset(); - func_decl * f = n->get_decl(); - app * curr = n; - while (true) { - if (curr->get_num_args() != 2) - return false; - expr * arg1 = curr->get_arg(0); - if (is_app_of(arg1, f)) - return false; - args.push_back(arg1); - expr * arg2 = curr->get_arg(1); - if (!is_app_of(arg2, f)) { - args.push_back(arg2); - return true; - } - curr = to_app(arg2); - } -} - -bool is_ac_vector(app * n) { - func_decl * f = n->get_decl(); - unsigned num_args = n->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - if (is_app_of(n->get_arg(i), f)) - return false; - } - return true; -} - -void simplifier::reduce1_ac_app_core(app * n) { - app_ref n_c(m); - proof_ref p1(m); - mk_ac_congruent_term(n, n_c, p1); - TRACE("ac", tout << "expr:\n" << mk_pp(n, m) << "\ncongruent term:\n" << mk_pp(n_c, m) << "\n";); - expr_ref r(m); - func_decl * decl = n->get_decl(); - family_id fid = decl->get_family_id(); - plugin * p = get_plugin(fid); - if (is_ac_vector(n_c)) { - if (p != 0 && p->reduce(decl, n_c->get_num_args(), n_c->get_args(), r)) { - // done... - } - else { - r = n_c; - } - } - else if (is_ac_list(n_c, m_args)) { - // m_args contains the arguments... - if (p != 0 && p->reduce(decl, m_args.size(), m_args.c_ptr(), r)) { - // done... - } - else { - r = m.mk_app(decl, m_args.size(), m_args.c_ptr()); - } - } - else { - m_args.reset(); - m_mults.reset(); - get_ac_args(n_c, m_args, m_mults); - TRACE("ac", tout << "AC args:\n"; - for (unsigned i = 0; i < m_args.size(); i++) { - tout << mk_pp(m_args[i], m) << " * " << m_mults[i] << "\n"; - }); - if (p != 0 && p->reduce(decl, m_args.size(), m_mults.c_ptr(), m_args.c_ptr(), r)) { - // done... - } - else { - ptr_buffer<expr> new_args; - expand_args(m_args.size(), m_mults.c_ptr(), m_args.c_ptr(), new_args); - r = m.mk_app(decl, new_args.size(), new_args.c_ptr()); - } - } - TRACE("ac", tout << "AC result:\n" << mk_pp(r, m) << "\n";); - - if (!m.fine_grain_proofs()) { - cache_result(n, r, 0); - } - else { - proof * p; - if (n == r.get()) - p = 0; - else if (r.get() != n_c.get()) - p = m.mk_transitivity(p1, m.mk_rewrite(n_c, r)); - else - p = p1; - cache_result(n, r, p); - } -} - -static unsigned g_rewrite_lemma_id = 0; - -void simplifier::dump_rewrite_lemma(func_decl * decl, unsigned num_args, expr * const * args, expr* result) { - expr_ref arg(m); - arg = m.mk_app(decl, num_args, args); - if (arg.get() != result) { - char buffer[128]; -#ifdef _WINDOWS - sprintf_s(buffer, ARRAYSIZE(buffer), "lemma_%d.smt", g_rewrite_lemma_id); -#else - sprintf(buffer, "rewrite_lemma_%d.smt", g_rewrite_lemma_id); -#endif - ast_smt_pp pp(m); - pp.set_benchmark_name("rewrite_lemma"); - pp.set_status("unsat"); - expr_ref n(m); - n = m.mk_not(m.mk_eq(arg.get(), result)); - std::ofstream out(buffer); - pp.display(out, n); - out.close(); - ++g_rewrite_lemma_id; - } -} - -/** - \brief Return in \c result an expression \c e equivalent to <tt>(f args[0] ... args[num_args - 1])</tt>, and - store in \c pr a proof for <tt>(= (f args[0] ... args[num_args - 1]) e)</tt> - - If e is identical to (f args[0] ... args[num_args - 1]), then pr is set to 0. -*/ -void simplifier::mk_app(func_decl * decl, unsigned num_args, expr * const * args, expr_ref & result) { - m_need_reset = true; - if (m.is_eq(decl)) { - sort * s = m.get_sort(args[0]); - plugin * p = get_plugin(s->get_family_id()); - if (p != 0 && p->reduce_eq(args[0], args[1], result)) - return; - } - else if (m.is_distinct(decl)) { - sort * s = m.get_sort(args[0]); - plugin * p = get_plugin(s->get_family_id()); - if (p != 0 && p->reduce_distinct(num_args, args, result)) - return; - } - family_id fid = decl->get_family_id(); - plugin * p = get_plugin(fid); - if (p != 0 && p->reduce(decl, num_args, args, result)) { - //uncomment this line if you want to trace rewrites as lemmas: - //dump_rewrite_lemma(decl, num_args, args, result.get()); - return; - } - - result = m.mk_app(decl, num_args, args); -} - -/** - \brief Create a term congruence to n (f a[0] ... a[num_args-1]) using the - cached values for the a[i]'s. Store the result in r, and the proof for (= n r) in p. - If n and r are identical, then set p to 0. -*/ -void simplifier::mk_congruent_term(app * n, app_ref & r, proof_ref & p) { - bool has_new_args = false; - ptr_vector<expr> args; - ptr_vector<proof> proofs; - unsigned num = n->get_num_args(); - for (unsigned j = 0; j < num; j++) { - expr * arg = n->get_arg(j); - expr * new_arg; - proof * arg_proof; - get_cached(arg, new_arg, arg_proof); - - CTRACE("simplifier_bug", (arg != new_arg) != (arg_proof != 0), - tout << mk_ll_pp(arg, m) << "\n---->\n" << mk_ll_pp(new_arg, m) << "\n"; - tout << "#" << arg->get_id() << " #" << new_arg->get_id() << "\n"; - tout << arg << " " << new_arg << "\n";); - - - if (arg != new_arg) { - has_new_args = true; - proofs.push_back(arg_proof); - SASSERT(arg_proof); - } - else { - SASSERT(arg_proof == 0); - } - args.push_back(new_arg); - } - if (has_new_args) { - r = m.mk_app(n->get_decl(), args.size(), args.c_ptr()); - if (m_use_oeq) - p = m.mk_oeq_congruence(n, r, proofs.size(), proofs.c_ptr()); - else - p = m.mk_congruence(n, r, proofs.size(), proofs.c_ptr()); - } - else { - r = n; - p = 0; - } -} - -/** - \brief Store the new arguments of \c n in result. Store in p a proof for - (= n (f result[0] ... result[num_args - 1])), where f is the function symbol of n. - - If there are no new arguments or fine grain proofs are disabled, then p is set to 0. - - Return true there are new arguments. -*/ -bool simplifier::get_args(app * n, ptr_vector<expr> & result, proof_ref & p) { - bool has_new_args = false; - unsigned num = n->get_num_args(); - if (m.fine_grain_proofs()) { - app_ref r(m); - mk_congruent_term(n, r, p); - result.append(r->get_num_args(), r->get_args()); - SASSERT(n->get_num_args() == result.size()); - has_new_args = r != n; - } - else { - p = 0; - for (unsigned j = 0; j < num; j++) { - expr * arg = n->get_arg(j); - expr * new_arg; - proof * arg_proof; - get_cached(arg, new_arg, arg_proof); - if (arg != new_arg) { - has_new_args = true; - } - result.push_back(new_arg); - } - } - return has_new_args; -} - -/** - \brief Create a term congruence to n (where n is an expression such as: (f (f a_1 a_2) (f a_3 (f a_4 a_5))) using the - cached values for the a_i's. Store the result in r, and the proof for (= n r) in p. - If n and r are identical, then set p to 0. -*/ -void simplifier::mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p) { - SASSERT(m_ac_support); - func_decl * f = n->get_decl(); - - m_ac_cache.reset(); - m_ac_pr_cache.reset(); - - ptr_buffer<app> todo; - ptr_buffer<expr> new_args; - ptr_buffer<proof> new_arg_prs; - todo.push_back(n); - while (!todo.empty()) { - app * curr = todo.back(); - if (m_ac_cache.contains(curr)) { - todo.pop_back(); - continue; - } - bool visited = true; - bool has_new_arg = false; - new_args.reset(); - new_arg_prs.reset(); - unsigned num_args = curr->get_num_args(); - for (unsigned j = 0; j < num_args; j ++) { - expr * arg = curr->get_arg(j); - if (is_app_of(arg, f)) { - app * new_arg = 0; - if (m_ac_cache.find(to_app(arg), new_arg)) { - SASSERT(new_arg != 0); - new_args.push_back(new_arg); - if (arg != new_arg) - 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) - 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); - if (m.fine_grain_proofs()) { - proof * p = m.mk_congruence(curr, new_curr, new_arg_prs.size(), new_arg_prs.c_ptr()); - m_ac_pr_cache.insert(curr, p); - } - } - } - } - - SASSERT(m_ac_cache.contains(n)); - app * new_n = 0; - m_ac_cache.find(n, new_n); - r = new_n; - if (m.fine_grain_proofs()) { - proof * new_pr = 0; - m_ac_pr_cache.find(n, new_pr); - p = new_pr; - } -} - -#define White 0 -#define Grey 1 -#define Black 2 - -#ifdef Z3DEBUG -static int get_color(obj_map<expr, int> & colors, expr * n) { - obj_map<expr, int>::obj_map_entry * entry = colors.insert_if_not_there2(n, White); - return entry->get_data().m_value; -} -#endif - -static bool visit_ac_children(func_decl * f, expr * n, obj_map<expr, int> & colors, ptr_buffer<expr> & todo, ptr_buffer<expr> & result) { - if (is_app_of(n, f)) { - unsigned num_args = to_app(n)->get_num_args(); - bool visited = true; - // Put the arguments in 'result' in reverse order. - // Reason: preserve the original order of the arguments in the final result. - // Remark: get_ac_args will traverse 'result' backwards. - for (unsigned i = 0; i < num_args; i++) { - expr * arg = to_app(n)->get_arg(i); - obj_map<expr, int>::obj_map_entry * entry = colors.insert_if_not_there2(arg, White); - if (entry->get_data().m_value == White) { - todo.push_back(arg); - visited = false; - } - } - return visited; - } - else { - return true; - } -} - -void simplifier::ac_top_sort(app * n, ptr_buffer<expr> & result) { - ptr_buffer<expr> todo; - func_decl * f = n->get_decl(); - obj_map<expr, int> & colors = m_colors; - colors.reset(); - todo.push_back(n); - while (!todo.empty()) { - expr * curr = todo.back(); - int color; - obj_map<expr, int>::obj_map_entry * entry = colors.insert_if_not_there2(curr, White); - SASSERT(entry); - color = entry->get_data().m_value; - switch (color) { - case White: - // Remark: entry becomes invalid if an element is inserted into the hashtable. - // So, I must set Grey before executing visit_ac_children. - entry->get_data().m_value = Grey; - SASSERT(get_color(colors, curr) == Grey); - if (visit_ac_children(f, curr, colors, todo, result)) { - // If visit_ac_children succeeded, then the hashtable was not modified, - // and entry is still valid. - SASSERT(todo.back() == curr); - entry->get_data().m_value = Black; - SASSERT(get_color(colors, curr) == Black); - result.push_back(curr); - todo.pop_back(); - } - break; - case Grey: - SASSERT(visit_ac_children(f, curr, colors, todo, result)); - SASSERT(entry); - entry->get_data().m_value = Black; - SASSERT(get_color(colors, curr) == Black); - result.push_back(curr); - SASSERT(todo.back() == curr); - todo.pop_back(); - break; - case Black: - todo.pop_back(); - break; - default: - UNREACHABLE(); - } - } -} - -void simplifier::get_ac_args(app * n, ptr_vector<expr> & args, vector<rational> & mults) { - SASSERT(m_ac_support); - ptr_buffer<expr> sorted_exprs; - ac_top_sort(n, sorted_exprs); - SASSERT(!sorted_exprs.empty()); - SASSERT(sorted_exprs[sorted_exprs.size()-1] == n); - - TRACE("ac", tout << mk_ll_pp(n, m, true, false) << "#" << n->get_id() << "\nsorted expressions...\n"; - for (unsigned i = 0; i < sorted_exprs.size(); i++) { - tout << "#" << sorted_exprs[i]->get_id() << " "; - } - tout << "\n";); - - m_ac_mults.reset(); - m_ac_mults.insert(n, rational(1)); - func_decl * decl = n->get_decl(); - unsigned j = sorted_exprs.size(); - while (j > 0) { - --j; - expr * curr = sorted_exprs[j]; - rational mult; - m_ac_mults.find(curr, mult); - SASSERT(!mult.is_zero()); - if (is_app_of(curr, decl)) { - unsigned num_args = to_app(curr)->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = to_app(curr)->get_arg(i); - rational zero; - obj_map<expr, rational>::obj_map_entry * entry = m_ac_mults.insert_if_not_there2(arg, zero); - entry->get_data().m_value += mult; - } - } - else { - args.push_back(curr); - mults.push_back(mult); - } - } -} - -void simplifier::reduce1_quantifier(quantifier * q) { - expr * new_body; - proof * new_body_pr; - SASSERT(is_well_sorted(m, q)); - get_cached(q->get_expr(), new_body, new_body_pr); - - quantifier_ref q1(m); - proof * p1 = 0; - - if (is_quantifier(new_body) && - to_quantifier(new_body)->is_forall() == q->is_forall() && - !to_quantifier(q)->has_patterns() && - !to_quantifier(new_body)->has_patterns()) { - - quantifier * nested_q = to_quantifier(new_body); - - ptr_buffer<sort> sorts; - buffer<symbol> names; - sorts.append(q->get_num_decls(), q->get_decl_sorts()); - names.append(q->get_num_decls(), q->get_decl_names()); - sorts.append(nested_q->get_num_decls(), nested_q->get_decl_sorts()); - names.append(nested_q->get_num_decls(), nested_q->get_decl_names()); - - q1 = m.mk_quantifier(q->is_forall(), - sorts.size(), - sorts.c_ptr(), - names.c_ptr(), - nested_q->get_expr(), - std::min(q->get_weight(), nested_q->get_weight()), - q->get_qid(), - q->get_skid(), - 0, 0, 0, 0); - SASSERT(is_well_sorted(m, q1)); - - if (m.fine_grain_proofs()) { - quantifier * q0 = m.update_quantifier(q, new_body); - proof * p0 = q == q0 ? 0 : m.mk_quant_intro(q, q0, new_body_pr); - p1 = m.mk_pull_quant(q0, q1); - p1 = m.mk_transitivity(p0, p1); - } - } - else { - ptr_buffer<expr> new_patterns; - ptr_buffer<expr> new_no_patterns; - expr * new_pattern; - proof * new_pattern_pr; - - // Remark: we can ignore the proofs for the patterns. - unsigned num = q->get_num_patterns(); - for (unsigned i = 0; i < num; i++) { - get_cached(q->get_pattern(i), new_pattern, new_pattern_pr); - if (m.is_pattern(new_pattern)) { - new_patterns.push_back(new_pattern); - } - } - num = q->get_num_no_patterns(); - for (unsigned i = 0; i < num; i++) { - get_cached(q->get_no_pattern(i), new_pattern, new_pattern_pr); - new_no_patterns.push_back(new_pattern); - } - - remove_duplicates(new_patterns); - remove_duplicates(new_no_patterns); - - q1 = m.mk_quantifier(q->is_forall(), - q->get_num_decls(), - q->get_decl_sorts(), - q->get_decl_names(), - new_body, - q->get_weight(), - q->get_qid(), - q->get_skid(), - new_patterns.size(), - new_patterns.c_ptr(), - new_no_patterns.size(), - new_no_patterns.c_ptr()); - SASSERT(is_well_sorted(m, q1)); - - TRACE("simplifier", tout << mk_pp(q, m) << "\n" << mk_pp(q1, m) << "\n";); - if (m.fine_grain_proofs()) { - if (q != q1 && !new_body_pr) { - new_body_pr = m.mk_rewrite(q->get_expr(), new_body); - } - p1 = q == q1 ? 0 : m.mk_quant_intro(q, q1, new_body_pr); - } - } - - expr_ref r(m); - elim_unused_vars(m, q1, params_ref(), r); - - proof * pr = 0; - if (m.fine_grain_proofs()) { - proof * p2 = 0; - if (q1.get() != r.get()) - p2 = m.mk_elim_unused_vars(q1, r); - pr = m.mk_transitivity(p1, p2); - } - - cache_result(q, r, pr); -} - -/** - \see release_plugins -*/ -void simplifier::borrow_plugins(simplifier const & s) { - ptr_vector<plugin>::const_iterator it = s.begin_plugins(); - ptr_vector<plugin>::const_iterator end = s.end_plugins(); - for (; it != end; ++it) - register_plugin(*it); -} - -/** - \brief Make the simplifier behave as a pre-simplifier: No AC, and plugins are marked in pre-simplification mode. -*/ -void simplifier::enable_presimp() { - enable_ac_support(false); - ptr_vector<plugin>::const_iterator it = begin_plugins(); - ptr_vector<plugin>::const_iterator end = end_plugins(); - for (; it != end; ++it) - (*it)->enable_presimp(true); -} - -/** - \brief This method should be invoked if the plugins of this simplifier were borrowed from a different simplifier. -*/ -void simplifier::release_plugins() { - m_plugins.release(); -} - -void subst_simplifier::set_subst_map(expr_map * s) { - flush_cache(); - m_subst_map = s; -} - -bool subst_simplifier::get_subst(expr * n, expr_ref & r, proof_ref & p) { - if (m_subst_map && m_subst_map->contains(n)) { - expr * _r; - proof * _p = 0; - m_subst_map->get(n, _r, _p); - r = _r; - p = _p; - if (m.coarse_grain_proofs()) - m_subst_proofs.push_back(p); - return true; - } - return false; -} - -static void push_core(ast_manager & m, expr * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs) { - SASSERT(pr == 0 || m.is_undef_proof(pr) || e == m.get_fact(pr)); - TRACE("preprocessor", - tout << mk_pp(e, m) << "\n"; - if (pr) tout << mk_ll_pp(pr, m) << "\n\n";); - if (m.is_true(e)) - return; - result.push_back(e); - if (m.proofs_enabled()) - result_prs.push_back(pr); -} - -static void push_and(ast_manager & m, app * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs) { - unsigned num = e->get_num_args(); - TRACE("push_and", tout << mk_pp(e, m) << "\n";); - for (unsigned i = 0; i < num; i++) - push_assertion(m, e->get_arg(i), m.mk_and_elim(pr, i), result, result_prs); -} - -static void push_not_or(ast_manager & m, app * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs) { - unsigned num = e->get_num_args(); - TRACE("push_not_or", tout << mk_pp(e, m) << "\n";); - for (unsigned i = 0; i < num; i++) { - expr * child = e->get_arg(i); - if (m.is_not(child)) { - expr * not_child = to_app(child)->get_arg(0); - push_assertion(m, not_child, m.mk_not_or_elim(pr, i), result, result_prs); - } - else { - expr_ref not_child(m); - not_child = m.mk_not(child); - push_assertion(m, not_child, m.mk_not_or_elim(pr, i), result, result_prs); - } - } -} - -void push_assertion(ast_manager & m, expr * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs) { - CTRACE("push_assertion", !(pr == 0 || m.is_undef_proof(pr) || m.get_fact(pr) == e), - tout << mk_pp(e, m) << "\n" << mk_pp(m.get_fact(pr), m) << "\n";); - SASSERT(pr == 0 || m.is_undef_proof(pr) || m.get_fact(pr) == e); - if (m.is_and(e)) - push_and(m, to_app(e), pr, result, result_prs); - else if (m.is_not(e) && m.is_or(to_app(e)->get_arg(0))) - push_not_or(m, to_app(to_app(e)->get_arg(0)), pr, result, result_prs); - else - push_core(m, e, pr, result, result_prs); -} - 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<plugin> m_plugins; - ptr_vector<expr> m_args; - vector<rational> m_mults; - ptr_vector<expr> m_args2; - - proof_ref_vector m_proofs; // auxiliary vector for implementing exhaustive simplification. - proof_ref_vector m_subst_proofs; // in coarse grain proof generation mode, this vector tracks the justification for substitutions (see method get_subst). - - bool m_need_reset; - bool m_use_oeq; - - bool m_visited_quantifier; //!< true, if the simplifier found a quantifier - - bool m_ac_support; - - expr_mark m_ac_mark; - ptr_vector<expr> m_ac_marked; - obj_map<app, app *> m_ac_cache; // temporary cache for ac - obj_map<app, proof *> m_ac_pr_cache; // temporary cache for ac - obj_map<expr, int> m_colors; // temporary cache for topological sort. - obj_map<expr, rational> m_ac_mults; - - /* - Simplifier uses an idiom for rewriting ASTs without using recursive calls. - - - It uses a cache (field m_cache in base_simplifier) and a todo-stack (field m_todo in base_simplifier). - - - The cache is a mapping from AST to (AST + Proof). An entry [n -> (n',pr)] is used to store the fact - that n and n' are equivalent and pr is a proof for that. If proofs are disabled, then pr is 0. - We say n' is the result of the simplification of n. - Note: Some simplifications do not preserve equivalence, but equisatisfiability. - For saving space, we use pr = 0 also to represent the reflexivity proof [n -> (n, 0)]. - - - - The simplifier can be extended using plugin (subclasses of the class simplifier_plugin). - Each theory has a family ID. All operators (func_decls) and sorts from a given theory have - the same family_id. Given an application (object of the class app), we use the method - get_family_id() to obtain the family id of the operator in this application. - The simplifier uses plugin to apply theory specific simplifications. The basic idea is: - whenever an AST with family_id X is found, invoke the plugin for this family_id. - A simplifier_plugin implements the following API: - 1) bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) - This method is invoked when the simplifier is trying to reduce/simplify an application - of the form (f args[0] ... args[num_args - 1]), and f has a family_id associated with - the plugin. The plugin may return false to indicate it could not simplify this application. - If it returns true (success), the result should be stored in the argument result. - - 2) bool reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result); - This method is a similar to the previous one, and it is used to handle associative operators. - A plugin does not need to implement this method, the default implementation will use the previous one. - The arguments mults indicates the multiplicity of every argument in args. - For example, suppose this reduce is invoked with the arguments (f, 2, [3, 2], [a, b], result). - This represents the application (f a a a b b). - Some theory simplifiers may have efficient ways to encode this multiplicity. For example, - the arithmetic solver, if f is "+", the multiplicity can be encoded using "*". - This optimization is used because some benchmarks can create term that are very huge when - flattened. One "real" example (that motivated this optimization) is: - let a1 = x1 + x1 - let a2 = a1 + a1 - ... - let an = a{n-1} + a{n-1} - an - In this example, n was 32, so after AC flattening, we had an application - (+ x1 ... x1) with 2^32 arguments. Using the simple reduce would produce a stack overflow. - - This class uses a topological sort for computing the multiplicities efficiently. - So, the field m_colors is used to implement the topological sort. - - - 3) bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result) - This method is invoked when the sort of lhs and rhs has a family_id associated with the plugin. - This method allows theory specific simplifications such as: - (= (+ a b) b) --> (= a 0) - Assuming n1 is a reference to (+ a b) and n2 to b, the simplifier would invoke - reduce_eq(n1, n2, result) - Like reduce, false can be returned if a simplification could not be applied. - And if true is returned, then the result is stored in the argument result. - - 4) bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result) - It is similar to reduce_eq, but it used for theory specific simplifications for - (distinct args[0] ... args[num_args-1]) - Example: - (distinct 0 1 ... n) --> true - - - The idiom used in this class is implemented in the methdo reduce_core. - See reduce_core for more details. The basic idea is: - - 1) Get the next ast to be simplified from the todo-stack. - 2) If it is already cached, then do nothing. That is, this expression was already simplified. - 3) Otherwise, check whether all arguments already have been simplified (method visit_children). - 3a) The arguments that have not been simplified are added to the todo-stack by visit_children. - In this case visit_children will return false. - 3b) If all arguments have already been simplified, then invoke reduce1 to perform a reduction/simplification - step. The cache is updated with the result. - - - After invoking reduce_core(n), the cache contains an entry [n -> (n', pr)]. - - */ - - void flush_cache(); - - /** - \brief This method can be redefined in subclasses of simplifier to implement substitutions. - It returns true if n should be substituted by r, where the substitution is justified by the - proof p. The field m_subst_proofs is used to store these justifications when coarse proofs are used (PGM_COARSE). - This method is redefined in the class subst_simplifier. It is used in asserted_formulas - for implementing constant elimination. For example, if asserted_formulas contains the atoms - (= a (+ b 1)) (p a c), then the constant "a" can be eliminated. This is achieved by set (+ b 1) as - a substitution for "a". - */ - virtual bool get_subst(expr * n, expr_ref & r, proof_ref & p); - - void reduce_core(expr * n); - bool visit_children(expr * n); - bool visit_ac(app * n); - virtual bool visit_quantifier(quantifier * q); - void reduce1(expr * n); - void reduce1_app(app * n); - void reduce1_app_core(app * n); - void reduce1_ac_app_core(app * n); - void mk_congruent_term(app * n, app_ref & r, proof_ref & p); - void mk_ac_congruent_term(app * n, app_ref & r, proof_ref & p); - bool get_args(app * n, ptr_vector<expr> & result, proof_ref & p); - void get_ac_args(app * n, ptr_vector<expr> & args, vector<rational> & mults); - virtual void reduce1_quantifier(quantifier * q); - void dump_rewrite_lemma(func_decl * decl, unsigned num_args, expr * const * args, expr* result); - void ac_top_sort(app * n, ptr_buffer<expr> & result); - -public: - simplifier(ast_manager & manager); - virtual ~simplifier(); - - void enable_ac_support(bool flag); - - /** - \brief Simplify the expression \c s. Store the result in \c r, and a proof that <tt>(= s r)</tt> in \c p. - */ - void operator()(expr * s, expr_ref & r, proof_ref & p); - void reset() { if (m_need_reset) { flush_cache(); m_need_reset = false; } } - - bool visited_quantifier() const { return m_visited_quantifier; } - - void mk_app(func_decl * decl, unsigned num_args, expr * const * args, expr_ref & r); - void cache_result(expr * n, expr * r, proof * p) { m_need_reset = true; base_simplifier::cache_result(n, r, p); } - - void register_plugin(plugin * p); - ptr_vector<plugin>::const_iterator begin_plugins() const { return m_plugins.begin(); } - ptr_vector<plugin>::const_iterator end_plugins() const { return m_plugins.end(); } - - plugin * get_plugin(family_id fid) const { return m_plugins.get_plugin(fid); } - - ast_manager & get_manager() { return m; } - - void borrow_plugins(simplifier const & s); - void release_plugins(); - - void enable_presimp(); -}; - -class subst_simplifier : public simplifier { -protected: - expr_map * m_subst_map; - virtual bool get_subst(expr * n, expr_ref & r, proof_ref & p); -public: - subst_simplifier(ast_manager & manager):simplifier(manager), m_subst_map(0) {} - void set_subst_map(expr_map * s); -}; - -void push_assertion(ast_manager & m, expr * e, proof * pr, expr_ref_vector & result, proof_ref_vector & result_prs); - -#endif 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: - - <abstract> - -Author: - - Leonardo de Moura (leonardo) 2008-12-29. - -Revision History: - ---*/ -#include "ast/simplifier/simplifier_plugin.h" - -/** - \brief Copy every args[i] mult[i] times to new_args. -*/ -void expand_args(unsigned num_args, rational const * mults, expr * const * args, ptr_buffer<expr> & new_args) { - for (unsigned i = 0; i < num_args; i++) { - rational const & c = mults[i]; - SASSERT(c.is_int()); - rational j(0); - while (j < c) { - new_args.push_back(args[i]); - j++; - } - } -} - -bool simplifier_plugin::reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - if (f->is_idempotent()) { - return reduce(f, num_args, args, result); - } - else { - ptr_buffer<expr> new_args; - expand_args(num_args, mults, args, new_args); - return reduce(f, new_args.size(), new_args.c_ptr(), result); - } -} 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<expr> & new_args); - -/** - \brief Abstract simplifier for the operators in a given family. -*/ -class simplifier_plugin { -protected: - ast_manager & m_manager; - family_id m_fid; - bool m_presimp; // true if simplifier is performing pre-simplification... - bool m_reduce_invoked; // true if one of the reduce methods were invoked. - - void set_reduce_invoked() { m_reduce_invoked = true; } - -public: - simplifier_plugin(symbol const & fname, ast_manager & m):m_manager(m), m_fid(m.mk_family_id(fname)), m_presimp(false), m_reduce_invoked(false) {} - - bool reduce_invoked() const { return m_reduce_invoked; } - - virtual ~simplifier_plugin() {} - - virtual simplifier_plugin * mk_fresh() { - UNREACHABLE(); - return 0; - } - - /** - \brief Return in \c result an expression \c e equivalent to <tt>(f args[0] ... args[num_args - 1])</tt>. - - Return true if succeeded. - */ - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { set_reduce_invoked(); return false; } - - /** - \brief Return in \c result an expression \c e equivalent to <tt>(f args[0] ... args[0] ... args[num_args - 1])</tt>. - Where each args[i] occurs mults[i] times. - - Return true if succeeded. - */ - virtual bool reduce(func_decl * f, unsigned num_args, rational const * mults, expr * const * args, expr_ref & result); - - /** - \brief Return in \c result an expression \c e equivalent to <tt>(= lhs rhs)</tt>. - - Return true if succeeded. - */ - virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { set_reduce_invoked(); return false; } - - /** - \brief Return in \c result an expression \c e equivalent to <tt>(distinct args[0] ... args[num_args-1])</tt>. - - Return true if succeeded. - */ - virtual bool reduce_distinct(unsigned num_args, expr * const * args, expr_ref & result) { set_reduce_invoked(); return false; } - - family_id get_family_id() const { return m_fid; } - - /** - \brief Simplifiers may maintain local caches. These caches must be flushed when this method is invoked. - */ - virtual void flush_caches() { /* do nothing */ } - - ast_manager & get_manager() { return m_manager; } - - void enable_presimp(bool flag) { m_presimp = flag; } - - virtual void enable_ac_support(bool flag) {} -}; - -#endif 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 <sstream> -#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/rel/dl_bound_relation.h b/src/muz/rel/dl_bound_relation.h index 1678e23b8..3dec9d313 100644 --- a/src/muz/rel/dl_bound_relation.h +++ b/src/muz/rel/dl_bound_relation.h @@ -26,7 +26,6 @@ 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 { 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/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/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_int.h b/src/smt/theory_arith_int.h index fbcc9c11a..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 { From 4452ff9884f69e06b8a8343b20bec1dea3ebd2ee Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Tue, 29 Aug 2017 19:16:56 -0700 Subject: [PATCH 41/74] elaborate on dom simplifier Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/tactic/core/CMakeLists.txt | 1 + src/tactic/core/dom_simplify_tactic.cpp | 415 ++++++++++++------------ src/tactic/core/dom_simplify_tactic.h | 132 ++++++++ 3 files changed, 336 insertions(+), 212 deletions(-) create mode 100644 src/tactic/core/dom_simplify_tactic.h diff --git a/src/tactic/core/CMakeLists.txt b/src/tactic/core/CMakeLists.txt index f192b4fa6..006948315 100644 --- a/src/tactic/core/CMakeLists.txt +++ b/src/tactic/core/CMakeLists.txt @@ -7,6 +7,7 @@ z3_add_component(core_tactics ctx_simplify_tactic.cpp der_tactic.cpp distribute_forall_tactic.cpp + dom_simplify_tactic.cpp elim_term_ite_tactic.cpp elim_uncnstr_tactic.cpp injectivity_tactic.cpp diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 3b444ef1a..21686fe64 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -17,210 +17,165 @@ Notes: --*/ -#if 0 -#include "ast/ast.h" +#include "ast/ast_util.h" +#include "ast/ast_pp.h" +#include "tactic/core/dom_simplify_tactic.h" -class expr_dominators { -public: - typedef obj_map<expr, ptr_vector<expr>> tree_t; -private: - ast_manager& m; - expr_ref m_root; - obj_map<unsigned> m_expr2post; // reverse post-order number - ptr_vector<expr> m_post2expr; - tree_t m_parents; - obj_map<expr, expr*> m_doms; - tree_t m_tree; - void add_edge(tree_t& tree, expr * src, expr* dst) { - tree.insert_if_not_there(src, ptr_vector<expr>()).push_back(dst); - } - - /** - \brief compute a post-order traversal for e. - Also populate the set of parents - */ - void compute_post_order() { - unsigned post_num = 0; - SASSERT(m_post2expr.empty()); - SASSERT(m_expr2post.empty()); - ast_mark mark; - ptr_vector<expr> todo; - todo.push_back(m_root); - while (!todo.empty()) { - expr* e = todo.back(); - if (is_marked(e)) { - todo.pop_back(); - continue; +/** + \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<expr> 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 (is_app(e)) { - app* a = to_app(e); - bool done = true; + if (done) { + mark.mark(e, true); + m_expr2post.insert(e, post_num++); + m_post2expr.push_back(e); + todo.pop_back(); for (expr* arg : *a) { - if (!is_marked(arg)) { - todo.push_back(arg); - done = false; - } - } - if (done) { - mark.mark(e); - 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 { - todo.pop_back(); - } - } - } - - expr* 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 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<expr> 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; + add_edge(m_parents, arg, a); } } } - } - - void extract_tree() { - for (auto const& kv : m_doms) { - add_edge(m_tree, kv.m_value, kv.m_key); + else { + mark.mark(e, true); + todo.pop_back(); } - } - - void reset() { - m_expr2post.reset(); - m_post2expr.reset(); - m_parents.reset(); - m_doms.reset(); - m_tree.reset(); - m_root.reset(); } +} - -public: - expr_dominators(ast_manager& m): m(m), m_root(m) {} - - void compile(expr * e) { - reset(); - m_root = e; - compute_post_order(); - compute_dominators(); - extract_tree(); +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 compile(unsigned sz, expr * const* es) { - expr_ref e(m.mk_and(sz, es), m); - compile(e); +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<expr> 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(); +} - tree_t const& get_tree() { return m_tree; } -}; // goes to header file: -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; - }; -private: - simplifier& m_simplifier; - params_ref m_params; - expr_ref_vector m_trail; - obj_map<expr, expr*> m_result; - expr_dominators m_dominators; - - 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); - - expr_ref get_cache(expr* t) { 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); } - - void simplify_goal(goal_ref& g); - -public: - dom_simplify_tactic(ast_manager & m, simplifier& s, params_ref const & p = params_ref()); - - virtual tactic * translate(ast_manager & m); - - virtual ~dom_simplify_tactic(); - - 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(); -}; // implementation: -expr_ref dom_simplifier_tactic::simplify_ite(app * ite) { +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)); @@ -233,7 +188,7 @@ expr_ref dom_simplifier_tactic::simplify_ite(app * ite) { r = simplify(e); } else { - expr_ref t = simplify(t); + expr_ref new_t = simplify(t); pop(scope_level() - old_lvl); if (!assert_expr(new_c, true)) { return new_t; @@ -254,14 +209,18 @@ expr_ref dom_simplifier_tactic::simplify_ite(app * ite) { return r; } -expr_ref dom_simplifier_tactic::simplify(expr * e0) { +expr_ref dom_simplify_tactic::simplify(expr * e0) { expr_ref r(m); expr* e = 0; if (!m_result.find(e0, e)) { e = e0; } - - if (m.is_ite(e)) { + + ++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)) { @@ -271,7 +230,7 @@ expr_ref dom_simplifier_tactic::simplify(expr * e0) { r = simplify_or(to_app(e)); } else { - tree_t const& t = m_dominators.get_tree(); + expr_dominators::tree_t const& t = m_dominators.get_tree(); if (t.contains(e)) { ptr_vector<expr> const& children = t[e]; for (expr * child : children) { @@ -281,7 +240,7 @@ expr_ref dom_simplifier_tactic::simplify(expr * e0) { if (is_app(e)) { m_args.reset(); for (expr* arg : *to_app(e)) { - m_args.push_back(get_cached(arg)); + 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()); } @@ -289,18 +248,20 @@ expr_ref dom_simplifier_tactic::simplify(expr * e0) { r = e; } } - m_simplifier(r); + (*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_simplifier_tactic::simplify_or_and(bool is_and, app * e) { +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)) { + if (!assert_expr(r, !is_and)) { r = is_and ? m.mk_false() : m.mk_true(); } m_args.push_back(r); @@ -310,7 +271,7 @@ expr_ref dom_simplifier_tactic::simplify_or_and(bool is_and, app * e) { m_args2.reset(); for (expr * arg : m_args) { r = simplify(arg); - if (!assert_expr(r, is_and)) { + if (!assert_expr(r, !is_and)) { r = is_and ? m.mk_false() : m.mk_true(); } m_args2.push_back(r); @@ -321,31 +282,61 @@ expr_ref dom_simplifier_tactic::simplify_or_and(bool is_and, app * e) { return r; } -void dom_simplifier_tactic::simplify_goal(goal& g) { + +void dom_simplify_tactic::init(goal& g) { expr_ref_vector args(m); - expr_ref fml(m); + unsigned sz = g.size(); for (unsigned i = 0; i < sz; ++i) args.push_back(g.form(i)); - fml = mk_and(args); - expr_ref tmp(fml); - // TBD: deal with dependencies. - do { - m_result.reset(); - m_trail.reset(); - m_dominators.compile(fml); -#if 0 - for (unsigned i = 0; i < sz; ++i) { - r = simplify(g.form(i)); - // TBD: simplfy goal as a conjuction ? - // + 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)); } -#endif - tmp = fml; - fml = simplify(fml); + 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()); } - while (tmp != fml); - //g.reset(); - //g.add(fml); + SASSERT(scope_level() == 0); } -#endif diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h new file mode 100644 index 000000000..9325f95f5 --- /dev/null +++ b/src/tactic/core/dom_simplify_tactic.h @@ -0,0 +1,132 @@ +/*++ +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 "tactic/tactic.h" + + +class expr_dominators { +public: + typedef obj_map<expr, ptr_vector<expr>> tree_t; +private: + ast_manager& m; + expr_ref m_root; + obj_map<expr, unsigned> m_expr2post; // reverse post-order number + ptr_vector<expr> m_post2expr; + tree_t m_parents; + obj_map<expr, expr*> m_doms; + tree_t m_tree; + + void add_edge(tree_t& tree, expr * src, expr* dst) { + tree.insert_if_not_there2(src, ptr_vector<expr>())->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<expr, expr*> 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(); +}; + +#endif From 009e94d18821ed3723f1db681ca032aae086ca0d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Wed, 30 Aug 2017 14:00:01 -0700 Subject: [PATCH 42/74] update to theory_seq following examples from PJLJ Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/expr_substitution.h | 1 + src/ast/pattern/pattern_inference.cpp | 637 +----------------------- src/ast/rewriter/seq_rewriter.cpp | 18 +- src/math/automata/automaton.h | 10 + src/smt/smt_quantifier.cpp | 26 +- src/smt/theory_seq.cpp | 79 ++- src/smt/theory_seq.h | 2 + src/tactic/core/dom_simplify_tactic.cpp | 116 ++++- src/tactic/core/dom_simplify_tactic.h | 31 ++ 9 files changed, 213 insertions(+), 707 deletions(-) diff --git a/src/ast/expr_substitution.h b/src/ast/expr_substitution.h index 924481dd8..d360356eb 100644 --- a/src/ast/expr_substitution.h +++ b/src/ast/expr_substitution.h @@ -79,6 +79,7 @@ public: } } 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); } diff --git a/src/ast/pattern/pattern_inference.cpp b/src/ast/pattern/pattern_inference.cpp index dfeb29ffe..6a91dd85e 100644 --- a/src/ast/pattern/pattern_inference.cpp +++ b/src/ast/pattern/pattern_inference.cpp @@ -97,641 +97,6 @@ static void dump_app_vector(std::ostream & out, ptr_vector<app> const & v, ast_m } #endif -#if 0 -pattern_inference_old::pattern_inference_old(ast_manager & m, pattern_inference_params & params): - simplifier(m), - m_params(params), - m_bfid(m.get_basic_family_id()), - m_afid(m.mk_family_id("arith")), - m_le(m), - m_nested_arith_only(true), - m_block_loop_patterns(params.m_pi_block_loop_patterns), - m_candidates(m), - m_pattern_weight_lt(m_candidates_info), - m_collect(m, *this), - m_contains_subpattern(*this), - m_database(m) { - if (params.m_pi_arith == AP_NO) - register_forbidden_family(m_afid); - enable_ac_support(false); -} - -void pattern_inference_old::collect::operator()(expr * n, unsigned num_bindings) { - SASSERT(m_info.empty()); - SASSERT(m_todo.empty()); - SASSERT(m_cache.empty()); - m_num_bindings = num_bindings; - m_todo.push_back(entry(n, 0)); - while (!m_todo.empty()) { - entry & e = m_todo.back(); - n = e.m_node; - unsigned delta = e.m_delta; - TRACE("collect", tout << "processing: " << n->get_id() << " " << delta << " kind: " << n->get_kind() << "\n";); - TRACE("collect_info", tout << mk_pp(n, m) << "\n";); - if (visit_children(n, delta)) { - m_todo.pop_back(); - save_candidate(n, delta); - } - } - reset(); -} - -inline void pattern_inference_old::collect::visit(expr * n, unsigned delta, bool & visited) { - entry e(n, delta); - if (!m_cache.contains(e)) { - m_todo.push_back(e); - visited = false; - } -} - -bool pattern_inference_old::collect::visit_children(expr * n, unsigned delta) { - bool visited = true; - unsigned i; - switch (n->get_kind()) { - case AST_APP: - i = to_app(n)->get_num_args(); - while (i > 0) { - --i; - visit(to_app(n)->get_arg(i), delta, visited); - } - break; - case AST_QUANTIFIER: - visit(to_quantifier(n)->get_expr(), delta + to_quantifier(n)->get_num_decls(), visited); - break; - default: - break; - } - return visited; -} - -inline void pattern_inference_old::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_old::collect::save_candidate(expr * n, unsigned delta) { - switch (n->get_kind()) { - case AST_VAR: { - unsigned idx = to_var(n)->get_idx(); - if (idx >= delta) { - idx = idx - delta; - uint_set free_vars; - if (idx < m_num_bindings) - free_vars.insert(idx); - info * i = 0; - if (delta == 0) - i = alloc(info, m, n, free_vars, 1); - else - i = alloc(info, m, m.mk_var(idx, to_var(n)->get_sort()), free_vars, 1); - save(n, delta, i); - } - else { - save(n, delta, 0); - } - return; - } - case AST_APP: { - app * c = to_app(n); - func_decl * decl = c->get_decl(); - if (m_owner.is_forbidden(c)) { - save(n, delta, 0); - return; - } - - if (c->get_num_args() == 0) { - save(n, delta, alloc(info, m, n, uint_set(), 1)); - return; - } - - ptr_buffer<expr> buffer; - bool changed = false; // false if none of the children is mapped to a node different from itself. - uint_set free_vars; - unsigned size = 1; - unsigned num = c->get_num_args(); - for (unsigned i = 0; i < num; i++) { - expr * child = c->get_arg(i); - info * child_info = 0; -#ifdef Z3DEBUG - bool found = -#endif - m_cache.find(entry(child, delta), child_info); - SASSERT(found); - if (child_info == 0) { - save(n, delta, 0); - return; - } - buffer.push_back(child_info->m_node.get()); - free_vars |= child_info->m_free_vars; - size += child_info->m_size; - if (child != child_info->m_node.get()) - changed = true; - } - - app * new_node = 0; - if (changed) - new_node = m.mk_app(decl, buffer.size(), buffer.c_ptr()); - else - new_node = to_app(n); - save(n, delta, alloc(info, m, new_node, free_vars, size)); - // Remark: arithmetic patterns are only used if they are nested inside other terms. - // That is, we never consider x + 1 as pattern. On the other hand, f(x+1) can be a pattern - // if arithmetic is not in the forbidden list. - // - // Remark: The rule above has an exception. The operators (div, idiv, mod) are allowed to be - // used as patterns even when they are not nested in other terms. The motivation is that - // Z3 currently doesn't implement them (i.e., they are uninterpreted). So, some users add axioms - // stating properties about these operators. - family_id fid = c->get_family_id(); - decl_kind k = c->get_decl_kind(); - 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); - } - return; - } - default: - save(n, delta, 0); - return; - } -} - - -void pattern_inference_old::collect::reset() { - m_cache.reset(); - std::for_each(m_info.begin(), m_info.end(), delete_proc<info>()); - m_info.reset(); - SASSERT(m_todo.empty()); -} - -void pattern_inference_old::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; - } - - if (!m_candidates_info.contains(n)) { - m_candidates_info.insert(n, info(free_vars, size)); - m_candidates.push_back(n); - } -} - - -/** - \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_old::filter_looping_patterns(ptr_vector<app> & result) { - unsigned num = m_candidates.size(); - for (unsigned i1 = 0; i1 < num; i1++) { - app * n1 = m_candidates.get(i1); - expr2info::obj_map_entry * e1 = m_candidates_info.find_core(n1); - SASSERT(e1); - uint_set const & s1 = e1->get_data().m_value.m_free_vars; - if (m_block_loop_patterns) { - bool smaller = false; - for (unsigned i2 = 0; i2 < num; i2++) { - if (i1 != i2) { - app * n2 = m_candidates.get(i2); - expr2info::obj_map_entry * e2 = m_candidates_info.find_core(n2); - if (e2) { - uint_set const & s2 = e2->get_data().m_value.m_free_vars; - // Remark: the comparison operator only makes sense if both AST nodes - // contain the same number of variables. - // Example: - // (f X Y) <: (f (g X Z W) Y) - if (s1 == s2 && m_le(m_num_bindings, n1, n2) && !m_le(m_num_bindings, n2, n1)) { - smaller = true; - break; - } - } - } - } - if (!smaller) - result.push_back(n1); - else - m_candidates_info.erase(n1); - } - else { - result.push_back(n1); - } - } -} - - - -inline void pattern_inference_old::contains_subpattern::save(expr * n) { - unsigned id = n->get_id(); - m_already_processed.assure_domain(id); - if (!m_already_processed.contains(id)) { - m_todo.push_back(n); - m_already_processed.insert(id); - } -} - -bool pattern_inference_old::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); - SASSERT(_e); - uint_set const & s1 = _e->get_data().m_value.m_free_vars; - save(n); - unsigned num; - while (!m_todo.empty()) { - expr * curr = m_todo.back(); - m_todo.pop_back(); - switch (curr->get_kind()) { - case AST_APP: - if (curr != n) { - expr2info::obj_map_entry * e = m_owner.m_candidates_info.find_core(curr); - if (e) { - uint_set const & s2 = e->get_data().m_value.m_free_vars; - SASSERT(s2.subset_of(s1)); - if (s1 == s2) { - TRACE("pattern_inference", tout << mk_pp(n, m_owner.m) << "\nis bigger than\n" << mk_pp(to_app(curr), m_owner.m) << "\n";); - return true; - } - } - } - num = to_app(curr)->get_num_args(); - for (unsigned i = 0; i < num; i++) - save(to_app(curr)->get_arg(i)); - break; - case AST_VAR: - break; - default: - UNREACHABLE(); - } - } - return false; -} - -/** - 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_old::contains_subpattern(expr * n) { - return m_contains_subpattern(n); -} - -/** - \brief Copy a pattern p in patterns to result, if there is no - direct/indirect child of p in patterns which contains the same set - of variables. - - Remark: Every pattern p in patterns is also a member of - m_pattern_map. -*/ -void pattern_inference_old::filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result) { - for (app * curr : patterns) { - if (!contains_subpattern(curr)) - result.push_back(curr); - } -} - - -bool pattern_inference_old::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); - SASSERT(e2 != 0); - info const & i1 = e1->get_data().m_value; - info const & i2 = e2->get_data().m_value; - unsigned num_free_vars1 = i1.m_free_vars.num_elems(); - unsigned num_free_vars2 = i2.m_free_vars.num_elems(); - return num_free_vars1 > num_free_vars2 || (num_free_vars1 == num_free_vars2 && i1.m_size < i2.m_size); -} - -/** - \brief Create unary patterns (single expressions that contain all - bound variables). If a candidate does not contain all bound - variables, then it is copied to remaining_candidate_patterns. The - new patterns are stored in result. -*/ -void pattern_inference_old::candidates2unary_patterns(ptr_vector<app> const & candidate_patterns, - ptr_vector<app> & remaining_candidate_patterns, - app_ref_buffer & result) { - 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) { - app * new_pattern = m.mk_pattern(candidate); - result.push_back(new_pattern); - } - else { - remaining_candidate_patterns.push_back(candidate); - } - } -} - -// TODO: this code is too inefficient when the number of candidate -// patterns is too big. -// HACK: limit the number of case-splits: -#define MAX_SPLITS 32 - -void pattern_inference_old::candidates2multi_patterns(unsigned max_num_patterns, - ptr_vector<app> const & candidate_patterns, - app_ref_buffer & result) { - SASSERT(!candidate_patterns.empty()); - m_pre_patterns.push_back(alloc(pre_pattern)); - unsigned sz = candidate_patterns.size(); - unsigned num_splits = 0; - for (unsigned j = 0; j < m_pre_patterns.size(); j++) { - pre_pattern * curr = m_pre_patterns[j]; - if (curr->m_free_vars.num_elems() == m_num_bindings) { - app * new_pattern = m.mk_pattern(curr->m_exprs.size(), curr->m_exprs.c_ptr()); - result.push_back(new_pattern); - if (result.size() >= max_num_patterns) - return; - } - else if (curr->m_idx < sz) { - app * n = candidate_patterns[curr->m_idx]; - expr2info::obj_map_entry * e = m_candidates_info.find_core(n); - uint_set const & s = e->get_data().m_value.m_free_vars; - if (!s.subset_of(curr->m_free_vars)) { - pre_pattern * new_p = alloc(pre_pattern,*curr); - new_p->m_exprs.push_back(n); - new_p->m_free_vars |= s; - new_p->m_idx++; - m_pre_patterns.push_back(new_p); - - if (num_splits < MAX_SPLITS) { - m_pre_patterns[j] = 0; - curr->m_idx++; - m_pre_patterns.push_back(curr); - num_splits++; - } - } - else { - m_pre_patterns[j] = 0; - curr->m_idx++; - m_pre_patterns.push_back(curr); - } - } - TRACE("pattern_inference", tout << "m_pre_patterns.size(): " << m_pre_patterns.size() << - "\nnum_splits: " << num_splits << "\n";); - } -} - -void pattern_inference_old::reset_pre_patterns() { - std::for_each(m_pre_patterns.begin(), m_pre_patterns.end(), delete_proc<pre_pattern>()); - m_pre_patterns.reset(); -} - - -bool pattern_inference_old::is_forbidden(app * n) const { - func_decl const * decl = n->get_decl(); - if (is_ground(n)) - return false; - // Remark: skolem constants should not be used in patterns, since they do not - // occur outside of the quantifier. That is, Z3 will never match this kind of - // pattern. - if (m_params.m_pi_avoid_skolems && decl->is_skolem()) { - CTRACE("pattern_inference_skolem", decl->is_skolem(), tout << "ignoring: " << mk_pp(n, m) << "\n";); - return true; - } - if (is_forbidden(decl)) - return true; - return false; -} - -bool pattern_inference_old::has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result) { - if (m_preferred.empty()) - return false; - bool found = false; - 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; - if (i.m_free_vars.num_elems() == m_num_bindings) { - TRACE("pattern_inference", tout << "found preferred pattern:\n" << mk_pp(candidate, m) << "\n";); - app * p = m.mk_pattern(candidate); - result.push_back(p); - found = true; - } - } - } - return found; -} - -void pattern_inference_old::mk_patterns(unsigned num_bindings, - expr * n, - unsigned num_no_patterns, - expr * const * no_patterns, - app_ref_buffer & result) { - m_num_bindings = num_bindings; - m_num_no_patterns = num_no_patterns; - m_no_patterns = no_patterns; - - m_collect(n, num_bindings); - - TRACE("pattern_inference", - tout << mk_pp(n, m); - tout << "\ncandidates:\n"; - unsigned num = m_candidates.size(); - for (unsigned i = 0; i < num; i++) { - tout << mk_pp(m_candidates.get(i), m) << "\n"; - }); - - if (!m_candidates.empty()) { - m_tmp1.reset(); - filter_looping_patterns(m_tmp1); - TRACE("pattern_inference", - tout << "candidates after removing looping-patterns:\n"; - dump_app_vector(tout, m_tmp1, m);); - SASSERT(!m_tmp1.empty()); - if (!has_preferred_patterns(m_tmp1, result)) { - // continue if there are no preferred patterns - m_tmp2.reset(); - filter_bigger_patterns(m_tmp1, m_tmp2); - SASSERT(!m_tmp2.empty()); - TRACE("pattern_inference", - tout << "candidates after removing bigger patterns:\n"; - dump_app_vector(tout, m_tmp2, m);); - m_tmp1.reset(); - candidates2unary_patterns(m_tmp2, m_tmp1, result); - unsigned num_extra_multi_patterns = m_params.m_pi_max_multi_patterns; - if (result.empty()) - num_extra_multi_patterns++; - if (num_extra_multi_patterns > 0 && !m_tmp1.empty()) { - // m_pattern_weight_lt is not a total order - std::stable_sort(m_tmp1.begin(), m_tmp1.end(), m_pattern_weight_lt); - TRACE("pattern_inference", - tout << "candidates after sorting:\n"; - dump_app_vector(tout, m_tmp1, m);); - candidates2multi_patterns(num_extra_multi_patterns, m_tmp1, result); - } - } - } - - reset_pre_patterns(); - m_candidates_info.reset(); - m_candidates.reset(); -} - - -void pattern_inference_old::reduce1_quantifier(quantifier * q) { - TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m) << "\n";); - if (!q->is_forall()) { - simplifier::reduce1_quantifier(q); - return; - } - - int weight = q->get_weight(); - - if (m_params.m_pi_use_database) { - m_database.initialize(g_pattern_database); - app_ref_vector new_patterns(m); - 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 - 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); - } - 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); - 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; - } - } - - if (q->get_num_patterns() > 0) { - simplifier::reduce1_quantifier(q); - return; - } - - if (m_params.m_pi_nopat_weight >= 0) - weight = m_params.m_pi_nopat_weight; - - SASSERT(q->get_num_patterns() == 0); - expr * new_body; - proof * new_body_pr; - get_cached(q->get_expr(), new_body, new_body_pr); - - ptr_buffer<expr> new_no_patterns; - unsigned num_no_patterns = q->get_num_no_patterns(); - for (unsigned i = 0; i < num_no_patterns; i++) { - expr * new_pattern; - proof * new_pattern_pr; - get_cached(q->get_no_pattern(i), new_pattern, new_pattern_pr); - new_no_patterns.push_back(new_pattern); - } - - app_ref_buffer new_patterns(m); - - if (m_params.m_pi_arith == AP_CONSERVATIVE) - m_forbidden.push_back(m_afid); - - mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns); - - if (new_patterns.empty() && !new_no_patterns.empty()) { - 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()) { - warning_msg("ignoring nopats annotation because Z3 couldn't find any other pattern (quantifier id: %s)", q->get_qid().str().c_str()); - } - } - } - - if (m_params.m_pi_arith == AP_CONSERVATIVE) { - m_forbidden.pop_back(); - if (new_patterns.empty()) { - flet<bool> l1(m_block_loop_patterns, false); // allow looping patterns - mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns); - if (!new_patterns.empty()) { - weight = std::max(weight, static_cast<int>(m_params.m_pi_arith_weight)); - if (m_params.m_pi_warnings) { - warning_msg("using arith. in pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_ARITH_WEIGHT=<val>).", - q->get_qid().str().c_str(), weight); - } - } - } - } - - if (m_params.m_pi_arith != AP_NO && new_patterns.empty()) { - if (new_patterns.empty()) { - flet<bool> l1(m_nested_arith_only, false); // try to find a non-nested arith pattern - flet<bool> l2(m_block_loop_patterns, false); // allow looping patterns - mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns); - if (!new_patterns.empty()) { - weight = std::max(weight, static_cast<int>(m_params.m_pi_non_nested_arith_weight)); - if (m_params.m_pi_warnings) { - warning_msg("using non nested arith. pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_NON_NESTED_ARITH_WEIGHT=<val>).", - q->get_qid().str().c_str(), weight); - } - // verbose_stream() << mk_pp(q, m) << "\n"; - } - } - } - - quantifier_ref new_q(m); - new_q = m.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body); - 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); - } - - if (new_patterns.empty() && m_params.m_pi_pull_quantifiers) { - pull_quant pull(m); - 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); - 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()); - 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()))); - } - TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m) << "\n";); - } - } - } - - if (new_patterns.empty()) { - if (m_params.m_pi_warnings) { - warning_msg("failed to find a pattern for quantifier (quantifier id: %s)", q->get_qid().str().c_str()); - } - TRACE("pi_failed", tout << mk_pp(q, m) << "\n";); - } - - if (new_patterns.empty() && new_body == q->get_expr()) { - cache_result(q, q, 0); - return; - } - - 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); -} - -#endif #include "ast/pattern/database.h" @@ -881,7 +246,7 @@ void pattern_inference_cfg::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); diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp index 70eddcea1..997d5671e 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/math/automata/automaton.h b/src/math/automata/automaton.h index 2f55d5cc2..12aa120b3 100644 --- a/src/math/automata/automaton.h +++ b/src/math/automata/automaton.h @@ -300,6 +300,16 @@ public: } } + bool is_sink_state(unsigned s) const { + if (is_final_state(s)) return false; + moves mvs; + get_moves_from(s, mvs); + for (move const& m : mvs) { + if (s != m.dst()) return false; + } + return true; + } + void add_init_to_final_states() { add_to_final_states(init()); } diff --git a/src/smt/smt_quantifier.cpp b/src/smt/smt_quantifier.cpp index 22004ee78..1d58e2bb3 100644 --- a/src/smt/smt_quantifier.cpp +++ b/src/smt/smt_quantifier.cpp @@ -208,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<quantifier>::const_iterator it = m_quantifiers.begin(); - ptr_vector<quantifier>::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(); @@ -220,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; @@ -493,10 +490,11 @@ namespace smt { virtual void assign_eh(quantifier * q) { m_active = true; + ast_manager& m = m_context->get_manager(); 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,16 +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 (!unary && j >= num_eager_multi_patterns) { - TRACE("quantifier", tout << "delaying (too many multipatterns):\n" << mk_ismt2_pp(mp, m_context->get_manager()) << "\n" + 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) << "\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/theory_seq.cpp b/src/smt/theory_seq.cpp index 461e9e8ee..44ce804e7 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -151,9 +151,8 @@ void theory_seq::solution_map::pop_scope(unsigned num_scopes) { } void theory_seq::solution_map::display(std::ostream& out) const { - eqdep_map_t::iterator it = m_map.begin(), end = m_map.end(); - for (; it != end; ++it) { - out << mk_pp(it->m_key, m) << " |-> " << mk_pp(it->m_value.first, m) << "\n"; + for (auto const& kv : m_map) { + out << mk_pp(kv.m_key, m) << " |-> " << mk_pp(kv.m_value.first, m) << "\n"; } } @@ -187,9 +186,8 @@ void theory_seq::exclusion_table::pop_scope(unsigned num_scopes) { } void theory_seq::exclusion_table::display(std::ostream& out) const { - table_t::iterator it = m_table.begin(), end = m_table.end(); - for (; it != end; ++it) { - out << mk_pp(it->first, m) << " != " << mk_pp(it->second, m) << "\n"; + for (auto const& kv : m_table) { + out << mk_pp(kv.first, m) << " != " << mk_pp(kv.second, m) << "\n"; } } @@ -214,6 +212,7 @@ theory_seq::theory_seq(ast_manager& m): m_trail_stack(*this), m_ls(m), m_rs(m), m_lhs(m), m_rhs(m), + m_res(m), m_atoms_qhead(0), m_new_solution(false), m_new_propagation(false), @@ -937,18 +936,14 @@ bool theory_seq::check_length_coherence0(expr* e) { bool theory_seq::check_length_coherence() { - obj_hashtable<expr>::iterator it = m_length.begin(), end = m_length.end(); #if 1 - for (; it != end; ++it) { - expr* e = *it; + for (expr* e : m_length) { if (check_length_coherence0(e)) { return true; } } - it = m_length.begin(); #endif - for (; it != end; ++it) { - expr* e = *it; + for (expr* e : m_length) { if (check_length_coherence(e)) { return true; } @@ -957,10 +952,9 @@ bool theory_seq::check_length_coherence() { } bool theory_seq::fixed_length() { - obj_hashtable<expr>::iterator it = m_length.begin(), end = m_length.end(); bool found = false; - for (; it != end; ++it) { - if (fixed_length(*it)) { + for (expr* e : m_length) { + if (fixed_length(e)) { found = true; } } @@ -2502,12 +2496,11 @@ void theory_seq::display(std::ostream & out) const { } if (!m_re2aut.empty()) { out << "Regex\n"; - obj_map<expr, eautomaton*>::iterator it = m_re2aut.begin(), end = m_re2aut.end(); - for (; it != end; ++it) { - out << mk_pp(it->m_key, m) << "\n"; + for (auto const& kv : m_re2aut) { + out << mk_pp(kv.m_key, m) << "\n"; display_expr disp(m); - if (it->m_value) { - it->m_value->display(out, disp); + if (kv.m_value) { + kv.m_value->display(out, disp); } } } @@ -2521,9 +2514,7 @@ void theory_seq::display(std::ostream & out) const { } if (!m_length.empty()) { - obj_hashtable<expr>::iterator it = m_length.begin(), end = m_length.end(); - for (; it != end; ++it) { - expr* e = *it; + for (expr* e : m_length) { rational lo(-1), hi(-1); lower_bound(e, lo); upper_bound(e, hi); @@ -2636,6 +2627,12 @@ void theory_seq::collect_statistics(::statistics & st) const { st.update("seq int.to.str", m_stats.m_int_string); } +void theory_seq::init_search_eh() { + m_re2aut.reset(); + m_res.reset(); + m_automata.reset(); +} + void theory_seq::init_model(expr_ref_vector const& es) { expr_ref new_s(m); for (expr* e : es) { @@ -3397,7 +3394,6 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { literal lit = ctx.get_literal(n); if (!is_true) { e3 = m_util.re.mk_complement(e2); - is_true = true; lit.neg(); } eautomaton* a = get_automaton(e3); @@ -3416,26 +3412,17 @@ void theory_seq::propagate_in_re(expr* n, bool is_true) { unsigned_vector states; a->get_epsilon_closure(a->init(), states); literal_vector lits; - if (is_true) { - lits.push_back(~lit); - } + lits.push_back(~lit); + for (unsigned i = 0; i < states.size(); ++i) { - if (is_true) { - lits.push_back(mk_accept(e1, zero, e3, states[i])); - } - else { - literal nlit = ~lit; - propagate_lit(0, 1, &nlit, mk_reject(e1, zero, e3, states[i])); - } + lits.push_back(mk_accept(e1, zero, e3, states[i])); } - if (is_true) { - if (lits.size() == 2) { - propagate_lit(0, 1, &lit, lits[1]); - } - else { - TRACE("seq", ctx.display_literals_verbose(tout, lits); tout << "\n";); - ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); - } + if (lits.size() == 2) { + propagate_lit(0, 1, &lit, lits[1]); + } + else { + TRACE("seq", ctx.display_literals_verbose(tout, lits); tout << "\n";); + ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); } } @@ -4180,10 +4167,8 @@ eautomaton* theory_seq::get_automaton(expr* re) { TRACE("seq", result->display(tout, disp);); } m_automata.push_back(result); - m_trail_stack.push(push_back_vector<theory_seq, scoped_ptr_vector<eautomaton> >(m_automata)); - m_re2aut.insert(re, result); - m_trail_stack.push(insert_obj_map<theory_seq, expr, eautomaton*>(m_re2aut, re)); + m_res.push_back(re); return result; } @@ -4264,6 +4249,10 @@ void theory_seq::propagate_acc_rej_length(literal lit, expr* e) { if (m_util.str.is_length(idx)) return; SASSERT(m_autil.is_numeral(idx)); SASSERT(get_context().get_assignment(lit) == l_true); + if (aut->is_sink_state(src)) { + propagate_lit(0, 1, &lit, false_literal); + return; + } bool is_final = aut->is_final_state(src); if (is_final == is_acc) { propagate_lit(0, 1, &lit, mk_literal(m_autil.mk_ge(m_util.str.mk_length(s), idx))); diff --git a/src/smt/theory_seq.h b/src/smt/theory_seq.h index b5a53e8e4..1f97697c2 100644 --- a/src/smt/theory_seq.h +++ b/src/smt/theory_seq.h @@ -328,6 +328,7 @@ namespace smt { // maintain automata with regular expressions. scoped_ptr_vector<eautomaton> m_automata; obj_map<expr, eautomaton*> m_re2aut; + expr_ref_vector m_res; // queue of asserted atoms ptr_vector<expr> m_atoms; @@ -361,6 +362,7 @@ namespace smt { virtual void collect_statistics(::statistics & st) const; virtual model_value_proc * mk_value(enode * n, model_generator & mg); virtual void init_model(model_generator & mg); + virtual void init_search_eh(); void init_model(expr_ref_vector const& es); // final check diff --git a/src/tactic/core/dom_simplify_tactic.cpp b/src/tactic/core/dom_simplify_tactic.cpp index 21686fe64..595f8f7c6 100644 --- a/src/tactic/core/dom_simplify_tactic.cpp +++ b/src/tactic/core/dom_simplify_tactic.cpp @@ -115,8 +115,6 @@ void expr_dominators::extract_tree() { } } - - void expr_dominators::compile(expr * e) { reset(); m_root = e; @@ -130,7 +128,6 @@ void expr_dominators::compile(unsigned sz, expr * const* es) { compile(e); } - void expr_dominators::reset() { m_expr2post.reset(); m_post2expr.reset(); @@ -142,11 +139,8 @@ void expr_dominators::reset() { -// goes to header file: - - - -// implementation: +// ----------------------- +// dom_simplify_tactic tactic * dom_simplify_tactic::translate(ast_manager & m) { return alloc(dom_simplify_tactic, m, m_simplifier->translate(m), m_params); @@ -340,3 +334,109 @@ void dom_simplify_tactic::simplify_goal(goal& g) { } +// ---------------------- +// 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<expr> 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 index 9325f95f5..2fa79dd1d 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -21,6 +21,7 @@ Notes: #define DOM_SIMPLIFY_TACTIC_H_ #include "ast/ast.h" +#include "ast/expr_substitution.h" #include "tactic/tactic.h" @@ -129,4 +130,34 @@ public: 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<expr, unsigned> 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 From 62f8cc1289f925adc416bef90eab3ef3657dcf55 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Thu, 31 Aug 2017 07:33:38 -0700 Subject: [PATCH 43/74] fix ordering for value propagation to ensure values are preferred Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/smt/asserted_formulas.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 626588ab3..6ecf26bd8 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -514,9 +514,15 @@ bool asserted_formulas::is_gt(expr* lhs, expr* rhs) { if (lhs == rhs) { return false; } - if (m.is_value(rhs)) { + // 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; From fff54d5d08e610c856ba5651ab0a1276079445aa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 3 Sep 2017 03:56:10 -0700 Subject: [PATCH 44/74] fix perf regression with negative polynomial normalization, adding new datatype plugin Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/CMakeLists.txt | 1 + src/ast/ast.cpp | 43 +- src/ast/ast.h | 13 +- src/ast/datatype_decl_plugin.cpp | 2 +- src/ast/datatype_decl_plugin.h | 2 +- src/ast/datatype_decl_plugin2.cpp | 819 +++++++++++++++++++++ src/ast/datatype_decl_plugin2.h | 257 +++++++ src/ast/rewriter/arith_rewriter.cpp | 66 +- src/ast/rewriter/arith_rewriter.h | 3 + src/ast/rewriter/arith_rewriter_params.pyg | 1 + src/smt/asserted_formulas.cpp | 2 + src/smt/params/theory_arith_params.cpp | 3 + src/smt/theory_datatype.cpp | 13 +- src/util/symbol_table.h | 21 +- 14 files changed, 1207 insertions(+), 39 deletions(-) create mode 100644 src/ast/datatype_decl_plugin2.cpp create mode 100644 src/ast/datatype_decl_plugin2.h diff --git a/src/ast/CMakeLists.txt b/src/ast/CMakeLists.txt index 0a14d9473..47ed2def8 100644 --- a/src/ast/CMakeLists.txt +++ b/src/ast/CMakeLists.txt @@ -14,6 +14,7 @@ z3_add_component(ast ast_util.cpp bv_decl_plugin.cpp datatype_decl_plugin.cpp + datatype_decl_plugin2.cpp decl_collector.cpp dl_decl_plugin.cpp expr2polynomial.cpp diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index c1ff04ada..1a35e710a 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<parameter>::iterator it = m_parameters.begin(); - vector<parameter>::iterator end = m_parameters.end(); - for (; it != end; ++it) { - it->init_eh(m); + for (parameter & p : m_parameters) { + p.init_eh(m); } } void decl_info::del_eh(ast_manager & m) { - vector<parameter>::iterator it = m_parameters.begin(); - vector<parameter>::iterator end = m_parameters.end(); - for (; it != end; ++it) { - it->del_eh(m, m_family_id); + for (parameter & p : m_parameters) { + p.del_eh(m, m_family_id); } } @@ -1935,6 +1931,35 @@ sort * ast_manager::mk_sort(symbol const & name, sort_info * info) { return register_node(new_node); } +sort * ast_manager::substitute(sort* s, unsigned n, sort * const * src, sort * const * dst) { + for (unsigned i = 0; i < n; ++i) { + if (s == src[i]) return dst[i]; + } + + vector<parameter> ps; + bool change = false; + sort_ref_vector sorts(*this); + for (unsigned i = 0; i < s->get_num_parameters(); ++i) { + parameter const& p = s->get_parameter(i); + if (p.is_ast()) { + SASSERT(is_sort(p.get_ast())); + change = true; + sorts.push_back(substitute(to_sort(p.get_ast()), n, src, dst)); + ps.push_back(parameter(sorts.back())); + } + else { + ps.push_back(p); + } + } + if (!change) { + return s; + } + decl_info dinfo(s->get_family_id(), s->get_decl_kind(), ps.size(), ps.c_ptr(), s->private_parameters()); + sort_info sinfo(dinfo, s->get_num_elements()); + return mk_sort(s->get_name(), &sinfo); +} + + sort * ast_manager::mk_uninterpreted_sort(symbol const & name, unsigned num_parameters, parameter const * parameters) { user_sort_plugin * plugin = get_user_sort_plugin(); decl_kind kind = plugin->register_name(name); @@ -2580,7 +2605,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 699268bd0..a1e31f46f 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(); } }; @@ -988,7 +993,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 +1660,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 +1674,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); diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index b4f30767f..446992105 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -675,7 +675,7 @@ expr * datatype_decl_plugin::get_some_value(sort * s) { return m_manager->mk_app(c, args.size(), args.c_ptr()); } -bool datatype_decl_plugin::is_fully_interp(sort const * s) const { +bool datatype_decl_plugin::is_fully_interp(sort * 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(); diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 3d008ad9c..dcd352471 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -150,7 +150,7 @@ public: virtual expr * get_some_value(sort * s); - virtual bool is_fully_interp(sort const * s) const; + virtual bool is_fully_interp(sort * s) const; virtual bool is_value(app* e) const; diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp new file mode 100644 index 000000000..4e60abcce --- /dev/null +++ b/src/ast/datatype_decl_plugin2.cpp @@ -0,0 +1,819 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + datatype_decl_plugin.cpp + +Abstract: + + <abstract> + +Author: + + Leonardo de Moura (leonardo) 2008-01-10. + +Revision History: + + // compute sort sizes and insert them. + // have a notion of pre-sort or just attach sort size after declaration. + +--*/ +#include "ast/datatype_decl_plugin2.h" +#include "util/warning.h" +#include "ast/ast_smt2_pp.h" + +namespace datatype { + + func_decl_ref accessor::instantiate(sort_ref_vector const& ps) const { + unsigned n = ps.size(); + 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(); } + + util& constructor::u() const { return m_def->u(); } + + func_decl_ref constructor::instantiate(sort_ref_vector const& ps) const { + 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); + } + + sort_ref def::instantiate(sort_ref_vector const& sorts) const { + sort_ref s(m); + if (!m_sort) { + vector<parameter> ps; + 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(), sorts.c_ptr(), m_params.c_ptr()), m); + } + + enum status { + GRAY, + BLACK + }; + + 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); + if (m_util.get() == 0) { + m_util = alloc(util, *m_manager); + } + return *(m_util.get()); + } + + struct invalid_datatype {}; + + sort * plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { + try { + if (k != DATATYPE_SORT) { + throw invalid_datatype(); + } + if (num_parameters < 1) { + 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)); + // compute datatype size + sort_size ts = u().get_datatype_size(s); + s->set_num_elements(ts); + 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); + } + + + func_decl * decl::plugin::mk_constructor(unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) { + ast_manager& m = *m_manager; + SASSERT(num_parameters == 1 && parameters[0].is_symbol() && range && u().is_datatype(range)); + if (num_parameters != 1 || !parameters[0].is_symbol() || !range || !u().is_datatype(range)) { + m_manager->raise_exception("invalid parameters for datatype constructor"); + } + // 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; + SASSERT(arity == 1 && num_parameters == 1 && parameters[0].is_ast() && is_func_decl(parameters[0].get_ast())); + SASSERT(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; + symbol name = to_func_decl(parameters[0].get_ast())->get_name(); + return m.mk_func_decl(name, arity, domain, range); + } + + func_decl * decl::plugin::mk_accessor(unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range) + { + ast_manager& m = *m_manager; + SASSERT(arity == 1 && num_parameters == 2 && parameters[0].is_symbol() && parameters[0].is_symbol()); + SASSERT(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); + } + + 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_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::add(symbol const& name, unsigned n, sort * const * params) { + ast_manager& m = *m_manager; + def* d = alloc(def, m, u(), name, m_class_id, n, params); + m_defs.insert(name, d); + m_def_block.push_back(name); + return *d; + } + + 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)); + } + if (!u().is_well_founded(sorts.size(), sorts.c_ptr())) { + m_manager->raise_exception("datatype is not well-founded"); + } + } + + void plugin::del(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<app> & 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 { + 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<app> 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<builtin_name> & op_names, symbol const & logic) { + if (logic == symbol::null) { + op_names.push_back(builtin_name("update-field", OP_DT_UPDATE_FIELD)); + } + } + + expr * plugin::get_some_value(sort * s) { + SASSERT(u().is_datatype(s)); + func_decl * c = u().get_non_rec_constructor(s); + ptr_buffer<expr> 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<sort, status> already_found; + ptr_vector<sort> 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; + } + + /** + \brief Return the size of the inductive datatype. + Pre-condition: The given argument constains the parameters of an inductive datatype. + */ + sort_size util::get_datatype_size(sort* s0) { + obj_map<sort, status> already_found; + obj_map<sort, sort_size> szs; + ptr_vector<sort> todo; + todo.push_back(s0); + status st; + while (!todo.empty()) { + sort* s = todo.back(); + if (already_found.find(s, st) && st == BLACK) { + todo.pop_back(); + continue; + } + already_found.insert(s, GRAY); + bool is_very_big = false; + bool can_process = true; + def const& d = get_def(s); + for (constructor const& c : d) { + for (accessor const& a : c) { + func_decl_ref ac = a.instantiate(s); + sort* r = ac->get_range(); + if (is_datatype(r)) { + if (already_found.find(r, st)) { + // type is infinite + if (st == GRAY) return sort_size(); + } + else { + todo.push_back(r); + can_process = false; + } + } + else if (r->is_infinite()) { + // type is infinite + return sort_size(); + } + else if (r->is_very_big()) { + is_very_big = true; + } + } + } + + if (can_process) { + todo.pop_back(); + already_found.insert(s, BLACK); + if (is_very_big) { + szs.insert(s, sort_size::mk_very_big()); + } + else { + // the type is not infinite nor the number of elements is infinite... + // computing the number of elements + rational num; + def const& d = get_def(s); + for (constructor const& c : d) { + rational c_num(1); + for (accessor const& a : c) { + func_decl_ref ac = a.instantiate(s); + sort* r = ac->get_range(); + if (szs.contains(r)) { + c_num *= rational(szs[r].size(), rational::ui64()); + } + else { + SASSERT(!r->is_infinite() && !r->is_very_big()); + c_num *= rational(r->get_num_elements().size(), rational::ui64()); + } + } + num += c_num; + } + szs.insert(s, sort_size(num)); + } + } + } + return szs[s0]; + } + + + /** + \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<bool> well_founded(num_types, false); + obj_map<sort, unsigned> 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 (!found_nonwf) { + changed = true; + well_founded[tid] = true; + num_well_founded++; + break; + } + } + } + } + while(changed && num_well_founded < num_types); + return num_well_founded == num_types; + } + + def const& util::get_def(sort* s) const { + return m_plugin->get_def(s); + } + + void util::get_subsorts(sort* s, ptr_vector<sort>& 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); + } + } + } + + + 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<decl::plugin*>(m.get_plugin(m_family_id)); + } + + util::~util() { + std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc<ptr_vector<func_decl> >()); + } + + ptr_vector<func_decl> const & util::get_datatype_constructors(sort * ty) { + SASSERT(is_datatype(ty)); + ptr_vector<func_decl> * r = 0; + if (m_datatype2constructors.find(ty, r)) + return *r; + r = alloc(ptr_vector<func_decl>); + 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<func_decl> const & util::get_constructor_accessors(func_decl * con) { + SASSERT(is_constructor(con)); + ptr_vector<func_decl> * res = 0; + if (m_constructor2accessors.find(con, res)) + return *res; + res = alloc(ptr_vector<func_decl>); + 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) { + res->push_back(a.instantiate(datatype)); + } + break; + } + } + return *res; + } + + func_decl * 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(); + parameter ps[1] = { parameter(constructor) }; + d = m.mk_func_decl(m_family_id, OP_DT_RECOGNISER, 1, ps, 1, &datatype); + SASSERT(d); + m_asts.push_back(constructor); + m_asts.push_back(d); + m_constructor2recognizer.insert(constructor, d); + return d; + } + + func_decl * util::get_recognizer_constructor(func_decl * recognizer) { + SASSERT(is_recognizer(recognizer)); + return to_func_decl(recognizer->get_parameter(0).get_ast()); + } + + 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<func_decl> 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<ptr_vector<func_decl> >()); + 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<sort> 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 * util::get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & 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<func_decl> const& constructors = get_datatype_constructors(ty); + // step 1) + unsigned sz = constructors.size(); + ++m_start; + for (unsigned j = 0; j < sz; ++j) { + func_decl * c = constructors[(j + m_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 + m_start) % sz]; + TRACE("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("util_bug", tout << "c: " << c->get_name() << " i: " << i << " T_i: " << T_i->get_name() << "\n";); + if (!is_datatype(T_i)) { + TRACE("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("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("util_bug", tout << "nested_c: " << nested_c->get_name() << "\n";); + if (nested_c == 0) + break; + } + if (i == num_args) + return c; + } + return 0; + } + + + /** + \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(); + } + } + + void util::display_datatype(sort *s0, std::ostream& strm) { + ast_mark mark; + ptr_buffer<sort> 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<func_decl> 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<func_decl> 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)) { + mark.mark(s1, true); + todo.push_back(s1); + } + } + strm << "\n"; + } + } + } +} diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h new file mode 100644 index 000000000..fad7ff174 --- /dev/null +++ b/src/ast/datatype_decl_plugin2.h @@ -0,0 +1,257 @@ +/*++ +Copyright (c) 2006 Microsoft Corporation + +Module Name: + + datatype_decl_plugin.h + +Abstract: + + <abstract> + +Author: + + Leonardo de Moura (leonardo) 2008-01-09. + +Revision History: + +--*/ +#ifndef DATATYPE_DECL_PLUGIN2_H_ +#define DATATYPE_DECL_PLUGIN2_H_ + +#include "ast/ast.h" +#include "util/buffer.h" +#include "util/symbol_table.h" +#include "util/obj_hashtable.h" + +namespace datatype { + + class util; + class def; + class accessor; + class constructor; + + enum sort_kind { + DATATYPE_SORT + }; + + enum op_kind { + OP_DT_CONSTRUCTOR, + OP_DT_RECOGNISER, + OP_DT_ACCESSOR, + OP_DT_UPDATE_FIELD, + LAST_DT_OP + }; + + class accessor { + ast_manager& m; + symbol m_name; + sort_ref m_domain; + sort_ref m_range; + constructor* m_constructor; + public: + accessor(ast_manager& m, symbol const& n): + m(m), + m_name(n), + m_domain(m), + m_range(m) + {} + sort* range() const { return m_range; } + 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; + }; + + class constructor { + ast_manager& m; + symbol m_name; + vector<accessor> m_accessors; + def* m_def; + public: + constructor(ast_manager& m, symbol n): m(m), m_name(n) {} + void add(accessor& a) { m_accessors.push_back(a); a.attach(this); } + symbol const& name() const { return m_name; } + vector<accessor> const& accessors() const { return m_accessors; } + vector<accessor>::const_iterator begin() const { return m_accessors.begin(); } + vector<accessor>::const_iterator end() const { 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; + }; + + class def { + ast_manager& m; + util& m_util; + symbol m_name; + unsigned m_class_id; + sort_ref_vector m_params; + mutable sort_ref m_sort; + vector<constructor> m_constructors; + public: + def(ast_manager& m, util& u, symbol const& n, unsigned class_id, unsigned num_params, sort * const* params): + m(m), + m_util(u), + m_name(n), + m_class_id(class_id), + m_params(m, num_params, params), + m_sort(m) + {} + 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; + vector<constructor> const& constructors() const { return m_constructors; } + vector<constructor>::const_iterator begin() const { return m_constructors.begin(); } + vector<constructor>::const_iterator end() const { return m_constructors.end(); } + sort_ref_vector const& params() const { return m_params; } + util& u() const { return m_util; } + }; + + namespace decl { + + class plugin : public decl_plugin { + mutable scoped_ptr<util> m_util; + map<symbol, def*, symbol_hash_proc, symbol_eq_proc> m_defs; + svector<symbol> m_def_block; + unsigned m_class_id; + util & u() const; + public: + plugin(): m_class_id(0) {} + virtual ~plugin(); + + virtual void finalize(); + + virtual decl_plugin * mk_fresh() { return alloc(plugin); } + + virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); + + virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + virtual expr * get_some_value(sort * s); + + virtual bool is_fully_interp(sort * s) const; + + virtual bool is_value(app* e) const; + + virtual bool is_unique_value(app * e) const { return is_value(e); } + + virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic); + + void begin_def_block() { m_class_id++; m_def_block.reset(); } + + void end_def_block(); + + def& add(symbol const& name, unsigned n, sort * const * params); + + void del(symbol const& d); + + def const& get_def(sort* s) const { def* d = 0; VERIFY(m_defs.find(datatype_name(s), d)); return *d; } + + private: + bool is_value_visit(expr * arg, ptr_buffer<app> & todo) const; + + func_decl * mk_update_field( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + func_decl * mk_constructor( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + func_decl * mk_accessor( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + func_decl * mk_recognizer( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + 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; + + + func_decl * get_constructor(sort * ty, unsigned c_id) const; + + obj_map<sort, ptr_vector<func_decl> *> m_datatype2constructors; + obj_map<sort, func_decl *> m_datatype2nonrec_constructor; + obj_map<func_decl, ptr_vector<func_decl> *> m_constructor2accessors; + obj_map<func_decl, func_decl *> m_constructor2recognizer; + obj_map<func_decl, func_decl *> m_recognizer2constructor; + obj_map<func_decl, func_decl *> m_accessor2constructor; + obj_map<sort, bool> m_is_recursive; + obj_map<sort, bool> m_is_enum; + mutable obj_map<sort, bool> m_is_fully_interp; + mutable ast_ref_vector m_asts; + ptr_vector<ptr_vector<func_decl> > m_vectors; + unsigned m_start; + mutable ptr_vector<sort> m_fully_interp_trail; + + func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set); + func_decl * get_constructor(sort * ty, unsigned c_id); + + friend class decl::plugin; + + bool is_recursive_core(sort * s) const; + sort_size get_datatype_size(sort* s0); + bool is_well_founded(unsigned num_types, sort* const* sorts); + def const& get_def(sort* s) const; + void get_subsorts(sort* s, ptr_vector<sort>& sorts) const; + + public: + util(ast_manager & m); + ~util(); + ast_manager & get_manager() const { return m; } + 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_decl_of(f, m_family_id, OP_DT_RECOGNISER); } + bool is_accessor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_ACCESSOR); } + bool is_update_field(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_UPDATE_FIELD); } + bool is_constructor(app * f) const { return is_app_of(f, m_family_id, OP_DT_CONSTRUCTOR); } + bool is_recognizer(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER); } + bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); } + bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); } + ptr_vector<func_decl> const & get_datatype_constructors(sort * ty); + unsigned get_datatype_num_constructors(sort * ty); + unsigned get_datatype_num_parameter_sorts(sort * ty); + sort* get_datatype_parameter_sort(sort * ty, unsigned idx); + func_decl * get_non_rec_constructor(sort * ty); + func_decl * get_constructor_recognizer(func_decl * constructor); + ptr_vector<func_decl> const & get_constructor_accessors(func_decl * constructor); + func_decl * get_accessor_constructor(func_decl * accessor); + func_decl * get_recognizer_constructor(func_decl * recognizer); + 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(); + void display_datatype(sort *s, std::ostream& strm); + bool is_fully_interp(sort * s) const; + sort_ref_vector datatype_params(sort * s) const; + }; + +}; + +#endif /* DATATYPE_DECL_PLUGIN_H_ */ + diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 4dfd69ddd..c1ef61938 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -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_expand_eqs = p.expand_eqs(); set_sort_sums(p.sort_sums()); } @@ -454,7 +455,20 @@ 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 (kind == EQ && m_expand_eqs) { + result = m().mk_and(m_util.mk_le(arg1, arg2), m_util.mk_ge(arg1, arg2)); + return BR_REWRITE2; + } + else if (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; } @@ -494,6 +508,56 @@ br_status arith_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result return mk_le_ge_eq_core(arg1, arg2, EQ, result); } +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.append(to_app(e)->get_num_args(), to_app(e)->get_args()); + } + } + 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) { if (!m_anum_simp) return false; diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index 5d9fb1d66..352cb5a6c 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -55,6 +55,7 @@ class arith_rewriter : public poly_rewriter<arith_rewriter_core> { bool m_push_to_real; bool m_anum_simp; bool m_elim_rem; + bool m_expand_eqs; unsigned m_max_degree; void get_coeffs_gcd(expr * t, numeral & g, bool & first, unsigned & num_consts); @@ -88,6 +89,8 @@ class arith_rewriter : public poly_rewriter<arith_rewriter_core> { 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..94ada1b6d 100644 --- a/src/ast/rewriter/arith_rewriter_params.pyg +++ b/src/ast/rewriter/arith_rewriter_params.pyg @@ -12,4 +12,5 @@ def_module_params(module_name='rewriter', ("arith_lhs", BOOL, False, "all monomials are moved to the left-hand-side, and the right-hand-side is just 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 +."), + ("expand_eqs", 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/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 6ecf26bd8..fb2004c77 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -123,6 +123,8 @@ void asserted_formulas::set_eliminate_and(bool flag) { p.set_bool("arith_lhs", true); p.set_bool("sort_sums", true); p.set_bool("rewrite_patterns", true); + p.set_bool("expand_eqs", m_params.m_arith_expand_eqs); + p.set_bool("gcd_rounding", true); m_rewriter.updt_params(p); flush_cache(); } diff --git a/src/smt/params/theory_arith_params.cpp b/src/smt/params/theory_arith_params.cpp index ab80f0c67..9b8aa9b81 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,6 +37,8 @@ void theory_arith_params::updt_params(params_ref const & _p) { m_arith_bound_prop = static_cast<bound_prop_mode>(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_expand_eqs = ap.expand_eqs(); } diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 806d6706b..beb1acf63 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -437,10 +437,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 +610,9 @@ namespace smt { d1->m_constructor = d2->m_constructor; } } - ptr_vector<enode>::iterator it = d2->m_recognizers.begin(); - ptr_vector<enode>::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) { 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<T> 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<T,false>& 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<symbol>& 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); } } }; From 7fbb93847414c166db8b4c694d98c4727382adcc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 3 Sep 2017 12:00:02 -0700 Subject: [PATCH 45/74] working on parametric datatype redo Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/datatype_decl_plugin2.cpp | 184 ++++++++++++++++++++---------- src/ast/datatype_decl_plugin2.h | 101 +++++++++++++++- src/cmd_context/pdecl.cpp | 119 +++++++------------ src/cmd_context/pdecl.h | 14 --- 4 files changed, 266 insertions(+), 152 deletions(-) diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp index 4e60abcce..0030af609 100644 --- a/src/ast/datatype_decl_plugin2.cpp +++ b/src/ast/datatype_decl_plugin2.cpp @@ -15,14 +15,13 @@ Author: Revision History: - // compute sort sizes and insert them. - // have a notion of pre-sort or just attach sort size after declaration. - --*/ -#include "ast/datatype_decl_plugin2.h" #include "util/warning.h" +#include "ast/datatype_decl_plugin2.h" +#include "ast/array_decl_plugin.h" #include "ast/ast_smt2_pp.h" + namespace datatype { func_decl_ref accessor::instantiate(sort_ref_vector const& ps) const { @@ -78,6 +77,32 @@ namespace datatype { 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<size>& 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<size>& 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() { @@ -125,9 +150,16 @@ namespace datatype { sort* s = m_manager->mk_sort(name.get_symbol(), sort_info(m_family_id, k, num_parameters, parameters, true)); - // compute datatype size - sort_size ts = u().get_datatype_size(s); - s->set_num_elements(ts); + def* d = 0; + if (m_defs.find(s->get_name(), d) && d->sort_size()) { + obj_map<sort, sort_size> S; + for (unsigned i = 1; i < num_parameters; ++i) { + sort* r = to_sort(parameters[i].get_ast()); + S.insert(d->params()[i], r->get_num_elements()); + } + sort_size ts = d->sort_size()->fold(S); + s->set_num_elements(ts); + } return s; } catch (invalid_datatype) { @@ -256,6 +288,7 @@ namespace datatype { if (!u().is_well_founded(sorts.size(), sorts.c_ptr())) { m_manager->raise_exception("datatype is not well-founded"); } + u().compute_datatype_size_functions(m_def_block); } void plugin::del(symbol const& s) { @@ -418,84 +451,111 @@ namespace datatype { } 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<sort, param_size::size*> 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<param_size::size> 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) return param_size::size::mk_param(sort_ref(s, m)); + } + return param_size::size::mk_offset(s->get_num_elements()); + } - /** - \brief Return the size of the inductive datatype. - Pre-condition: The given argument constains the parameters of an inductive datatype. - */ - sort_size util::get_datatype_size(sort* s0) { - obj_map<sort, status> already_found; - obj_map<sort, sort_size> szs; - ptr_vector<sort> todo; - todo.push_back(s0); + void util::compute_datatype_size_functions(svector<symbol> const& names) { + map<symbol, status, symbol_hash_proc, symbol_eq_proc> already_found; + map<symbol, param_size::size*, symbol_hash_proc, symbol_eq_proc> szs; + + svector<symbol> todo(names); status st; while (!todo.empty()) { - sort* s = todo.back(); + symbol s = todo.back(); if (already_found.find(s, st) && st == BLACK) { todo.pop_back(); continue; } already_found.insert(s, GRAY); - bool is_very_big = false; - bool can_process = true; - def const& d = get_def(s); + bool is_infinite = false; + bool can_process = true; + def& d = get_def(s); for (constructor const& c : d) { for (accessor const& a : c) { - func_decl_ref ac = a.instantiate(s); - sort* r = ac->get_range(); + sort* r = a.range(); if (is_datatype(r)) { - if (already_found.find(r, st)) { + symbol s2 = r->get_name(); + if (already_found.find(s2, st)) { // type is infinite - if (st == GRAY) return sort_size(); + if (st == GRAY) { + is_infinite = true; + } } - else { - todo.push_back(r); + else if (names.contains(s2)) { + todo.push_back(s2); can_process = false; } } - else if (r->is_infinite()) { - // type is infinite - return sort_size(); - } - else if (r->is_very_big()) { - is_very_big = true; - } } } + 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; + } - if (can_process) { - todo.pop_back(); - already_found.insert(s, BLACK); - if (is_very_big) { - szs.insert(s, sort_size::mk_very_big()); - } - else { - // the type is not infinite nor the number of elements is infinite... - // computing the number of elements - rational num; - def const& d = get_def(s); - for (constructor const& c : d) { - rational c_num(1); - for (accessor const& a : c) { - func_decl_ref ac = a.instantiate(s); - sort* r = ac->get_range(); - if (szs.contains(r)) { - c_num *= rational(szs[r].size(), rational::ui64()); - } - else { - SASSERT(!r->is_infinite() && !r->is_very_big()); - c_num *= rational(r->get_num_elements().size(), rational::ui64()); - } - } - num += c_num; - } - szs.insert(s, sort_size(num)); + ptr_vector<param_size::size> s_add; + for (constructor const& c : d) { + ptr_vector<param_size::size> 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)); } - return szs[s0]; } - + /** \brief Return true if the inductive datatype is well-founded. diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h index fad7ff174..a4a76f346 100644 --- a/src/ast/datatype_decl_plugin2.h +++ b/src/ast/datatype_decl_plugin2.h @@ -85,11 +85,100 @@ namespace datatype { util& u() const; }; + namespace param_size { + class size { + unsigned m_ref; + public: + size(): m_ref(0) {} + virtual ~size() {} + void inc_ref() { ++m_ref; } + void dec_ref() { --m_ref; if (m_ref == 0) dealloc(this); } + static size* mk_offset(sort_size const& s); + static size* mk_param(sort_ref& p); + static size* mk_plus(size* a1, size* a2); + static size* mk_times(size* a1, size* a2); + static size* mk_plus(ptr_vector<size>& szs); + static size* mk_times(ptr_vector<size>& szs); + static size* mk_power(size* a1, size* a2); + + virtual size* subst(obj_map<sort, size*>& S) = 0; + virtual sort_size fold(obj_map<sort, sort_size> const& S) = 0; + + }; + struct offset : public size { + sort_size m_offset; + offset(sort_size const& s): m_offset(s) {} + virtual ~offset() {} + virtual size* subst(obj_map<sort,size*>& S) { return this; } + virtual sort_size fold(obj_map<sort, sort_size> const& S) { return m_offset; } + }; + struct plus : public size { + size* m_arg1, *m_arg2; + plus(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref();} + virtual ~plus() { m_arg1->dec_ref(); m_arg2->dec_ref(); } + virtual size* subst(obj_map<sort,size*>& S) { return mk_plus(m_arg1->subst(S), m_arg2->subst(S)); } + virtual sort_size fold(obj_map<sort, sort_size> const& S) { + sort_size s1 = m_arg1->fold(S); + sort_size s2 = m_arg2->fold(S); + if (s1.is_infinite()) return s1; + if (s2.is_infinite()) return s2; + if (s1.is_very_big()) return s1; + if (s2.is_very_big()) return s2; + rational r = rational(s1.size(), rational::ui64()) + rational(s2.size(), rational::ui64()); + return sort_size(r); + } + }; + struct times : public size { + size* m_arg1, *m_arg2; + times(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); } + virtual ~times() { m_arg1->dec_ref(); m_arg2->dec_ref(); } + virtual size* subst(obj_map<sort,size*>& S) { return mk_times(m_arg1->subst(S), m_arg2->subst(S)); } + virtual sort_size fold(obj_map<sort, sort_size> const& S) { + sort_size s1 = m_arg1->fold(S); + sort_size s2 = m_arg2->fold(S); + if (s1.is_infinite()) return s1; + if (s2.is_infinite()) return s2; + if (s1.is_very_big()) return s1; + if (s2.is_very_big()) return s2; + rational r = rational(s1.size(), rational::ui64()) * rational(s2.size(), rational::ui64()); + return sort_size(r); + } + }; + struct power : public size { + size* m_arg1, *m_arg2; + power(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); } + virtual ~power() { m_arg1->dec_ref(); m_arg2->dec_ref(); } + virtual size* subst(obj_map<sort,size*>& S) { return mk_power(m_arg1->subst(S), m_arg2->subst(S)); } + virtual sort_size fold(obj_map<sort, sort_size> const& S) { + sort_size s1 = m_arg1->fold(S); + sort_size s2 = m_arg2->fold(S); + // s1^s2 + if (s1.is_infinite()) return s1; + if (s2.is_infinite()) return s2; + if (s1.is_very_big()) return s1; + if (s2.is_very_big()) return s2; + if (s1.size() == 1) return s1; + if (s2.size() == 1) return s1; + if (s1.size() > (2 << 20) || s2.size() > 10) return sort_size::mk_very_big(); + rational r = ::power(rational(s1.size(), rational::ui64()), static_cast<unsigned>(s2.size())); + return sort_size(r); + } + }; + struct sparam : public size { + sort_ref m_param; + sparam(sort_ref& p): m_param(p) {} + virtual ~sparam() {} + virtual size* subst(obj_map<sort,size*>& S) { return S[m_param]; } + virtual sort_size fold(obj_map<sort, sort_size> const& S) { return S[m_param]; } + }; + }; + class def { ast_manager& m; util& m_util; symbol m_name; unsigned m_class_id; + param_size::size* m_sort_size; sort_ref_vector m_params; mutable sort_ref m_sort; vector<constructor> m_constructors; @@ -99,9 +188,13 @@ namespace datatype { 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(); + } void add(constructor& c) { m_constructors.push_back(c); c.attach(this); @@ -114,6 +207,8 @@ namespace datatype { vector<constructor>::const_iterator end() const { 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(); } }; namespace decl { @@ -155,7 +250,8 @@ namespace datatype { void del(symbol const& d); - def const& get_def(sort* s) const { def* d = 0; VERIFY(m_defs.find(datatype_name(s), d)); return *d; } + def const& get_def(sort* s) const { return *(m_defs[datatype_name(s)]); } + def& get_def(symbol const& s) { return *(m_defs[s]); } private: bool is_value_visit(expr * arg, ptr_buffer<app> & todo) const; @@ -213,8 +309,11 @@ namespace datatype { bool is_recursive_core(sort * s) const; sort_size get_datatype_size(sort* s0); + void compute_datatype_size_functions(svector<symbol> const& names); + param_size::size* get_sort_size(sort_ref_vector const& params, sort* s); bool is_well_founded(unsigned num_types, sort* const* sorts); def const& get_def(sort* s) const; + def& get_def(symbol const& s) { return m_plugin->get_def(s); } void get_subsorts(sort* s, ptr_vector<sort>& sorts) const; public: diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 983dbbc78..88ab9f8b8 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<sort, void *>::iterator it = m_map.begin(); - obj_map<sort, void *>::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<sort*>((*it).m_value)); + m.m().dec_ref(static_cast<sort*>(kv.m_value)); } else { - psort_inst_cache * child = static_cast<psort_inst_cache*>((*it).m_value); + psort_inst_cache * child = static_cast<psort_inst_cache*>(kv.m_value); child->finalize(m); child->~psort_inst_cache(); m.a().deallocate(sizeof(psort_inst_cache), child); @@ -485,20 +483,16 @@ void pconstructor_decl::finalize(pdecl_manager & m) { } bool pconstructor_decl::has_missing_refs(symbol & missing) const { - ptr_vector<paccessor_decl>::const_iterator it = m_accessors.begin(); - ptr_vector<paccessor_decl>::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<int> const & symbol2idx, symbol & missing) { - ptr_vector<paccessor_decl>::iterator it = m_accessors.begin(); - ptr_vector<paccessor_decl>::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; @@ -506,20 +500,16 @@ bool pconstructor_decl::fix_missing_refs(dictionary<int> const & symbol2idx, sym constructor_decl * pconstructor_decl::instantiate_decl(pdecl_manager & m, sort * const * s) { ptr_buffer<accessor_decl> as; - ptr_vector<paccessor_decl>::iterator it = m_accessors.begin(); - ptr_vector<paccessor_decl>::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<paccessor_decl>::const_iterator it = m_accessors.begin(); - ptr_vector<paccessor_decl>::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 << ")"; } @@ -538,23 +528,17 @@ void pdatatype_decl::finalize(pdecl_manager & m) { } bool pdatatype_decl::has_missing_refs(symbol & missing) const { - ptr_vector<pconstructor_decl>::const_iterator it = m_constructors.begin(); - ptr_vector<pconstructor_decl>::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<symbol, symbol_hash_proc, symbol_eq_proc> names; - ptr_vector<pconstructor_decl>::const_iterator it = m_constructors.begin(); - ptr_vector<pconstructor_decl>::const_iterator end = m_constructors.end(); - for (; it != end; ++it) { - ptr_vector<paccessor_decl> 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; @@ -567,10 +551,8 @@ bool pdatatype_decl::has_duplicate_accessors(symbol & duplicated) const { bool pdatatype_decl::fix_missing_refs(dictionary<int> const & symbol2idx, symbol & missing) { - ptr_vector<pconstructor_decl>::iterator it = m_constructors.begin(); - ptr_vector<pconstructor_decl>::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; @@ -578,10 +560,8 @@ bool pdatatype_decl::fix_missing_refs(dictionary<int> const & symbol2idx, symbol datatype_decl * pdatatype_decl::instantiate_decl(pdecl_manager & m, sort * const * s) { ptr_buffer<constructor_decl> cs; - ptr_vector<pconstructor_decl>::iterator it = m_constructors.begin(); - ptr_vector<pconstructor_decl>::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()); } @@ -624,17 +604,16 @@ sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * void pdatatype_decl::display(std::ostream & out) const { out << "(declare-datatype " << m_name; display_sort_args(out, m_num_params); - ptr_vector<pconstructor_decl>::const_iterator it = m_constructors.begin(); - ptr_vector<pconstructor_decl>::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; } @@ -647,11 +626,9 @@ pdatatypes_decl::pdatatypes_decl(unsigned id, unsigned num_params, pdecl_manager m_datatypes(num_datatypes, dts) { m.inc_ref(num_datatypes, dts); - ptr_vector<pdatatype_decl>::iterator it = m_datatypes.begin(); - ptr_vector<pdatatype_decl>::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; } } @@ -662,36 +639,30 @@ 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<int> symbol2idx; - ptr_vector<pdatatype_decl>::iterator it = m_datatypes.begin(); - ptr_vector<pdatatype_decl>::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; } bool pdatatypes_decl::instantiate(pdecl_manager & m, sort * const * s) { datatype_decl_buffer dts; - ptr_vector<pdatatype_decl>::iterator it = m_datatypes.begin(); - ptr_vector<pdatatype_decl>::iterator end = m_datatypes.end(); - for (; it != end; ++it) { - dts.m_buffer.push_back((*it)->instantiate_decl(m, s)); + for (auto d : m_datatypes) { + dts.m_buffer.push_back(d->instantiate_decl(m, s)); } 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); + unsigned i = 0; + for (auto d : m_datatypes) { + sort * new_dt = sorts.get(i++); + d->cache(m, s, new_dt); + m.save_info(new_dt, d, m_num_params, s); + m.notify_new_dt(new_dt, d); } return true; } @@ -965,11 +936,9 @@ void pdecl_manager::save_info(sort * s, psort_decl * d, unsigned num_indices, un } void pdecl_manager::reset_sort_info() { - obj_map<sort, sort_info *>::iterator it = m_sort2info.begin(); - obj_map<sort, sort_info *>::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 2dfbb93ae..1d7203197 100644 --- a/src/cmd_context/pdecl.h +++ b/src/cmd_context/pdecl.h @@ -134,20 +134,6 @@ 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; From c6722859c271723760b20188bf75a6201ad33af7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 3 Sep 2017 14:36:03 -0700 Subject: [PATCH 46/74] update rewriting of equalities and monomials for regressions Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/justified_expr.h | 4 +- src/ast/rewriter/arith_rewriter.cpp | 20 +++--- src/ast/rewriter/arith_rewriter.h | 4 +- src/ast/rewriter/arith_rewriter_params.pyg | 1 - src/ast/rewriter/bv_rewriter.cpp | 1 + src/ast/rewriter/poly_rewriter.h | 9 ++- src/ast/rewriter/poly_rewriter_def.h | 71 ++++++++++++------- src/cmd_context/cmd_context.cpp | 79 +++++++--------------- src/smt/asserted_formulas.cpp | 8 ++- 9 files changed, 102 insertions(+), 95 deletions(-) diff --git a/src/ast/justified_expr.h b/src/ast/justified_expr.h index 49362940d..8aa961686 100644 --- a/src/ast/justified_expr.h +++ b/src/ast/justified_expr.h @@ -21,12 +21,12 @@ public: 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(); - m.inc_ref(m_fml); - m.inc_ref(m_proof); } return *this; } diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index c1ef61938..b630cdff6 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -26,7 +26,6 @@ void arith_rewriter::updt_local_params(params_ref const & _p) { arith_rewriter_params p(_p); m_arith_lhs = p.arith_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(); @@ -371,7 +370,7 @@ 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); + br_status st = cancel_monomials(arg1, arg2, true, new_arg1, new_arg2); TRACE("mk_le_bug", tout << "st: " << st << " " << new_arg1 << " " << new_arg2 << "\n";); if (st != BR_FAILED) { arg1 = new_arg1; @@ -455,11 +454,7 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin st = BR_DONE; } } - if (kind == EQ && m_expand_eqs) { - result = m().mk_and(m_util.mk_le(arg1, arg2), m_util.mk_ge(arg1, arg2)); - return BR_REWRITE2; - } - else if (is_numeral(arg2, a2) && is_neg_poly(arg1, new_arg1)) { + if (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) { @@ -500,12 +495,19 @@ 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) { + if (m_expand_eqs) { 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 { diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index 352cb5a6c..f1e4c4396 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -50,12 +50,12 @@ public: class arith_rewriter : public poly_rewriter<arith_rewriter_core> { bool m_arith_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_expand_eqs; + bool m_process_all_eqs; unsigned m_max_degree; void get_coeffs_gcd(expr * t, numeral & g, bool & first, unsigned & num_consts); @@ -83,6 +83,8 @@ class arith_rewriter : public poly_rewriter<arith_rewriter_core> { expr * reduce_power(expr * arg, bool is_eq); br_status reduce_power(expr * arg1, expr * arg2, op_kind kind, expr_ref & result); + bool is_arith_term(expr * n) const; + bool is_pi_multiple(expr * t, rational & k); bool is_pi_offset(expr * t, rational & k, expr * & m); bool is_2_pi_integer(expr * t); diff --git a/src/ast/rewriter/arith_rewriter_params.pyg b/src/ast/rewriter/arith_rewriter_params.pyg index 94ada1b6d..9a6c6c1c0 100644 --- a/src/ast/rewriter/arith_rewriter_params.pyg +++ b/src/ast/rewriter/arith_rewriter_params.pyg @@ -6,7 +6,6 @@ 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."), diff --git a/src/ast/rewriter/bv_rewriter.cpp b/src/ast/rewriter/bv_rewriter.cpp index 75f931c1d..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) { diff --git a/src/ast/rewriter/poly_rewriter.h b/src/ast/rewriter/poly_rewriter.h index 8cbc7f864..c00464383 100644 --- a/src/ast/rewriter/poly_rewriter.h +++ b/src/ast/rewriter/poly_rewriter.h @@ -48,7 +48,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); @@ -85,6 +84,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), diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index 85044af08..8fda040b6 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -18,7 +18,7 @@ Notes: --*/ #include "ast/rewriter/poly_rewriter.h" #include "ast/rewriter/poly_rewriter_params.hpp" -#include "ast/ast_lt.h" +// include "ast/ast_lt.h" #include "ast/ast_ll_pp.h" #include "ast/ast_smt2_pp.h" @@ -191,21 +191,9 @@ br_status poly_rewriter<Config>::mk_flat_mul_core(unsigned num_args, expr * cons } -template<typename Config> -struct poly_rewriter<Config>::mon_pw_lt { - poly_rewriter<Config> & m_owner; - mon_pw_lt(poly_rewriter<Config> & o):m_owner(o) {} - - bool operator()(expr * n1, expr * n2) const { - rational k; - return lt(m_owner.get_power_body(n1, k), - m_owner.get_power_body(n2, k)); - } -}; - - template<typename Config> br_status poly_rewriter<Config>::mk_nflat_mul_core(unsigned num_args, expr * const * args, expr_ref & result) { + mon_lt lt(*this); SASSERT(num_args >= 2); // cheap case numeral a; @@ -320,11 +308,8 @@ br_status poly_rewriter<Config>::mk_nflat_mul_core(unsigned num_args, expr * con if (ordered && num_coeffs == 0 && !use_power()) return BR_FAILED; if (!ordered) { - if (use_power()) - std::sort(new_args.begin(), new_args.end(), mon_pw_lt(*this)); - else - std::sort(new_args.begin(), new_args.end(), ast_to_lt()); - TRACE("poly_rewriter", + std::sort(new_args.begin(), new_args.end(), lt); + TRACE("poly_rewriter", tout << "after sorting:\n"; for (unsigned i = 0; i < new_args.size(); i++) { if (i > 0) @@ -498,8 +483,43 @@ void poly_rewriter<Config>::hoist_cmul(expr_ref_buffer & args) { args.resize(j); } +template<typename Config> +bool poly_rewriter<Config>::mon_lt::operator()(expr* e1, expr * e2) const { + return ordinal(e1) < ordinal(e2); +} + +inline bool is_essentially_var(expr * n, family_id fid) { + SASSERT(is_var(n) || is_app(n)); + return is_var(n) || to_app(n)->get_family_id() != fid; +} + +template<typename Config> +int poly_rewriter<Config>::mon_lt::ordinal(expr* e) const { + rational k; + if (is_essentially_var(e, rw.get_fid())) { + return e->get_id(); + } + else if (rw.is_mul(e)) { + if (rw.is_numeral(to_app(e)->get_arg(0))) + return to_app(e)->get_arg(1)->get_id(); + else + return e->get_id(); + } + else if (rw.is_numeral(e)) { + return -1; + } + else if (rw.use_power() && rw.is_power(e) && rw.is_numeral(to_app(e)->get_arg(1), k) && k > rational(1)) { + return to_app(e)->get_arg(0)->get_id(); + } + else { + return e->get_id(); + } +} + + template<typename Config> br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * const * args, expr_ref & result) { + mon_lt lt(*this); SASSERT(num_args >= 2); numeral c; unsigned num_coeffs = 0; @@ -591,9 +611,9 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con else if (m_sort_sums) { 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";); @@ -624,10 +644,10 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con } else if (!ordered) { if (c.is_zero()) - std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), ast_to_lt()); + std::sort(new_args.c_ptr(), new_args.c_ptr() + new_args.size(), lt); else - std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), ast_to_lt()); - } + std::sort(new_args.c_ptr() + 1, new_args.c_ptr() + new_args.size(), lt); + } result = mk_add_app(new_args.size(), new_args.c_ptr()); if (hoist_multiplication(result)) { return BR_REWRITE_FULL; @@ -681,6 +701,7 @@ br_status poly_rewriter<Config>::mk_sub(unsigned num_args, expr * const * args, template<typename Config> br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool move, expr_ref & lhs_result, expr_ref & rhs_result) { set_curr_sort(m().get_sort(lhs)); + mon_lt lt(*this); unsigned lhs_sz; expr * const * lhs_monomials = get_monomials(lhs, lhs_sz); unsigned rhs_sz; @@ -831,7 +852,7 @@ br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool m if (move) { if (m_sort_sums) { // + 1 to skip coefficient - std::sort(new_lhs_monomials.begin() + 1, new_lhs_monomials.end(), ast_to_lt()); + std::sort(new_lhs_monomials.begin() + 1, new_lhs_monomials.end(), lt); } c_at_rhs = true; } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index f172e5e93..d1b8f7f78 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -585,10 +585,8 @@ void cmd_context::register_builtin_sorts(decl_plugin * p) { svector<builtin_name> names; p->get_sort_names(names, m_logic); family_id fid = p->get_family_id(); - svector<builtin_name>::const_iterator it = names.begin(); - svector<builtin_name>::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); } } @@ -597,17 +595,15 @@ void cmd_context::register_builtin_ops(decl_plugin * p) { svector<builtin_name> names; p->get_op_names(names, m_logic); family_id fid = p->get_family_id(); - svector<builtin_name>::const_iterator it = names.begin(); - svector<builtin_name>::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)); } } } @@ -693,10 +689,8 @@ 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<family_id>::iterator it = fids.begin(); - svector<family_id>::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); @@ -1148,11 +1142,8 @@ void cmd_context::erase_object_ref(symbol const & s) { } void cmd_context::reset_func_decls() { - dictionary<func_decls>::iterator it = m_func_decls.begin(); - dictionary<func_decls>::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(); @@ -1160,10 +1151,8 @@ void cmd_context::reset_func_decls() { } void cmd_context::reset_psort_decls() { - dictionary<psort_decl*>::iterator it = m_psort_decls.begin(); - dictionary<psort_decl*>::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(); @@ -1179,19 +1168,14 @@ void cmd_context::reset_macros() { } void cmd_context::reset_cmds() { - dictionary<cmd*>::iterator it = m_cmds.begin(); - dictionary<cmd*>::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<cmd*>::iterator it = m_cmds.begin(); - dictionary<cmd*>::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); } @@ -1204,10 +1188,8 @@ void cmd_context::reset_user_tactics() { } void cmd_context::reset_object_refs() { - dictionary<object_ref*>::iterator it = m_object_refs.begin(); - dictionary<object_ref*>::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(); @@ -1541,10 +1523,8 @@ void cmd_context::reset_assertions() { mk_solver(); } restore_assertions(0); - svector<scope>::iterator it = m_scopes.begin(); - svector<scope>::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(); } } @@ -1717,10 +1697,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<scope>::iterator it = m_scopes.begin(); - svector<scope>::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]); } @@ -1757,11 +1734,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<std::string>::const_iterator it = m_assertion_strings.begin(); - std::vector<std::string>::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 @@ -1837,10 +1812,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<expr>::const_iterator it = m_assertions.begin(); - ptr_vector<expr>::const_iterator end = m_assertions.end(); - for (; it != end; ++it) { - display(out, *it); + for (expr * e : m_assertions) { + display(out, e); out << std::endl; } } diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index fb2004c77..7dca13c07 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -120,7 +120,7 @@ void asserted_formulas::push_assertion(expr * e, proof * pr, vector<justified_ex void asserted_formulas::set_eliminate_and(bool flag) { params_ref p; p.set_bool("elim_and", flag); - p.set_bool("arith_lhs", true); +// p.set_bool("arith_lhs", true); p.set_bool("sort_sums", true); p.set_bool("rewrite_patterns", true); p.set_bool("expand_eqs", m_params.m_arith_expand_eqs); @@ -429,7 +429,6 @@ void asserted_formulas::commit(unsigned new_qhead) { } void asserted_formulas::propagate_values() { - TRACE("propagate_values", tout << "before:\n"; display(tout);); flush_cache(); unsigned num_prop = 0; @@ -466,7 +465,7 @@ void asserted_formulas::propagate_values() { } unsigned asserted_formulas::propagate_values(unsigned i) { - expr * n = m_formulas[i].get_fml(); + 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); @@ -476,6 +475,9 @@ unsigned asserted_formulas::propagate_values(unsigned i) { } 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; } From a887475e9fa1b576fd857b997c5542536bc17c69 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 3 Sep 2017 15:01:54 -0700 Subject: [PATCH 47/74] remove dom-simplifier from build Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/tactic/core/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tactic/core/CMakeLists.txt b/src/tactic/core/CMakeLists.txt index 006948315..f192b4fa6 100644 --- a/src/tactic/core/CMakeLists.txt +++ b/src/tactic/core/CMakeLists.txt @@ -7,7 +7,6 @@ z3_add_component(core_tactics ctx_simplify_tactic.cpp der_tactic.cpp distribute_forall_tactic.cpp - dom_simplify_tactic.cpp elim_term_ite_tactic.cpp elim_uncnstr_tactic.cpp injectivity_tactic.cpp From ee4ae33ac444fdc7407545e06453029aeca45f56 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 3 Sep 2017 15:19:55 -0700 Subject: [PATCH 48/74] build fixes Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/datatype_decl_plugin2.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp index 0030af609..44102156d 100644 --- a/src/ast/datatype_decl_plugin2.cpp +++ b/src/ast/datatype_decl_plugin2.cpp @@ -495,7 +495,10 @@ namespace datatype { return param_size::size::mk_power(sz2, sz1); } for (sort* p : params) { - if (s == p) return param_size::size::mk_param(sort_ref(s, m)); + 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()); } From 10f734357ee2e50e88d29462c857e3757a69e238 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 3 Sep 2017 15:32:57 -0700 Subject: [PATCH 49/74] build fixes Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/array_decl_plugin.cpp | 2 +- src/ast/array_decl_plugin.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 { From eb6b2813ff68501d308cc2696a57568aa9e6e835 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 3 Sep 2017 16:14:22 -0700 Subject: [PATCH 50/74] build fixes Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/datatype_decl_plugin2.cpp | 14 ++++++++++++++ src/ast/datatype_decl_plugin2.h | 19 +++++++++++++++---- src/ast/rewriter/arith_rewriter.cpp | 3 ++- src/ast/rewriter/arith_rewriter.h | 1 + src/ast/rewriter/arith_rewriter_params.pyg | 1 + src/smt/asserted_formulas.cpp | 2 +- 6 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp index 44102156d..8969e02a9 100644 --- a/src/ast/datatype_decl_plugin2.cpp +++ b/src/ast/datatype_decl_plugin2.cpp @@ -24,6 +24,12 @@ Revision History: namespace datatype { + void accessor::fix_range(sort_ref_vector const& dts) { + if (!m_range) { + m_range = dts[m_index]; + } + } + func_decl_ref accessor::instantiate(sort_ref_vector const& ps) const { unsigned n = ps.size(); SASSERT(n == get_def().params().size()); @@ -285,6 +291,14 @@ namespace datatype { 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 (!u().is_well_founded(sorts.size(), sorts.c_ptr())) { m_manager->raise_exception("datatype is not well-founded"); } diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h index a4a76f346..13e85b47f 100644 --- a/src/ast/datatype_decl_plugin2.h +++ b/src/ast/datatype_decl_plugin2.h @@ -46,17 +46,24 @@ namespace datatype { class accessor { ast_manager& m; symbol m_name; - sort_ref m_domain; 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): + accessor(ast_manager& m, symbol const& n, sort* range): m(m), m_name(n), - m_domain(m), - m_range(m) + m_range(range, m), + m_index(UINT_MAX) + {} + accessor(ast_manager& m, symbol const& n, unsigned index): + m(m), + 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; @@ -78,6 +85,8 @@ namespace datatype { vector<accessor> const& accessors() const { return m_accessors; } vector<accessor>::const_iterator begin() const { return m_accessors.begin(); } vector<accessor>::const_iterator end() const { return m_accessors.end(); } + vector<accessor>::iterator begin() { return m_accessors.begin(); } + vector<accessor>::iterator end() { return m_accessors.end(); } func_decl_ref instantiate(sort_ref_vector const& ps) const; func_decl_ref instantiate(sort* dt) const; void attach(def* d) { m_def = d; } @@ -205,6 +214,8 @@ namespace datatype { vector<constructor> const& constructors() const { return m_constructors; } vector<constructor>::const_iterator begin() const { return m_constructors.begin(); } vector<constructor>::const_iterator end() const { return m_constructors.end(); } + vector<constructor>::iterator begin() { return m_constructors.begin(); } + vector<constructor>::iterator end() { return m_constructors.end(); } sort_ref_vector const& params() const { return m_params; } util& u() const { return m_util; } param_size::size* sort_size() { return m_sort_size; } diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index b630cdff6..8b29004ab 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -25,6 +25,7 @@ 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_elim_to_real = p.elim_to_real(); m_push_to_real = p.push_to_real(); @@ -370,7 +371,7 @@ 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, true, new_arg1, new_arg2); + 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; diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index f1e4c4396..af9d0e09d 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -49,6 +49,7 @@ public: class arith_rewriter : public poly_rewriter<arith_rewriter_core> { bool m_arith_lhs; + bool m_arith_ineq_lhs; bool m_gcd_rounding; bool m_elim_to_real; bool m_push_to_real; diff --git a/src/ast/rewriter/arith_rewriter_params.pyg b/src/ast/rewriter/arith_rewriter_params.pyg index 9a6c6c1c0..d40f46917 100644 --- a/src/ast/rewriter/arith_rewriter_params.pyg +++ b/src/ast/rewriter/arith_rewriter_params.pyg @@ -9,6 +9,7 @@ def_module_params(module_name='rewriter', ("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 +."), ("expand_eqs", BOOL, False, "expand equalities into two inequalities"), diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 7dca13c07..f37cabde8 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -120,7 +120,7 @@ void asserted_formulas::push_assertion(expr * e, proof * pr, vector<justified_ex void asserted_formulas::set_eliminate_and(bool flag) { params_ref p; p.set_bool("elim_and", flag); -// p.set_bool("arith_lhs", true); + p.set_bool("arith_ineq_lhs", true); p.set_bool("sort_sums", true); p.set_bool("rewrite_patterns", true); p.set_bool("expand_eqs", m_params.m_arith_expand_eqs); From 7b9b7149798f1f2cfce059727845ac3f58a2c58e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 3 Sep 2017 16:14:58 -0700 Subject: [PATCH 51/74] build fixes Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/rewriter/arith_rewriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 8b29004ab..ff1894a18 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -25,7 +25,7 @@ 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_arith_ineq_lhs = p.arith_ineq_lhs(); m_gcd_rounding = p.gcd_rounding(); m_elim_to_real = p.elim_to_real(); m_push_to_real = p.push_to_real(); From 09386e43e307a95cc9f49bfe3bbdd6f57477cce1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 3 Sep 2017 19:07:02 -0700 Subject: [PATCH 52/74] doctest fix Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/api/python/z3/z3.py | 4 +-- src/ast/datatype_decl_plugin2.cpp | 59 ++++++++++++++++--------------- src/ast/datatype_decl_plugin2.h | 44 +++++++++++------------ 3 files changed, 53 insertions(+), 54 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 1452a037e..0b5f151be 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -3640,7 +3640,7 @@ def BitVecs(names, bv, ctx=None): >>> Product(x, y, z) 1*x*y*z >>> simplify(Product(x, y, z)) - x*y*z + z*x*y """ ctx = _get_ctx(ctx) if isinstance(names, str): @@ -7647,7 +7647,7 @@ def simplify(a, *arguments, **keywords): >>> simplify(x + 1 + y + x + 1) 2 + 2*x + y >>> simplify((x + 1)*(y + 1), som=True) - 1 + x + y + x*y + 1 + x + y + y*x >>> simplify(Distinct(x, y, 1), blast_distinct=True) And(Not(x == y), Not(x == 1), Not(y == 1)) >>> simplify(And(x == 0, y == 1), elim_and=True) diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp index 8969e02a9..8233da7d9 100644 --- a/src/ast/datatype_decl_plugin2.cpp +++ b/src/ast/datatype_decl_plugin2.cpp @@ -31,6 +31,7 @@ namespace datatype { } func_decl_ref accessor::instantiate(sort_ref_vector const& ps) const { + ast_manager& m = ps.get_manager(); unsigned n = ps.size(); SASSERT(n == get_def().params().size()); sort_ref range(m.substitute(m_range, n, get_def().params().c_ptr(), ps.c_ptr()), m); @@ -52,8 +53,8 @@ namespace datatype { func_decl_ref constructor::instantiate(sort_ref_vector const& ps) const { sort_ref_vector domain(m); - for (accessor const& a : accessors()) { - domain.push_back(a.instantiate(ps)->get_range()); + 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()) }; @@ -293,9 +294,9 @@ namespace datatype { } for (symbol const& s : m_def_block) { def& d = *m_defs[s]; - for (constructor& c : d) { - for (accessor& a : c) { - // a.fix_range(sorts); + for (constructor* c : d) { + for (accessor* a : *c) { + a->fix_range(sorts); } } } @@ -401,9 +402,9 @@ namespace datatype { 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); + 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; @@ -438,9 +439,9 @@ namespace datatype { 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(); + 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); @@ -533,9 +534,9 @@ namespace datatype { 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(); + 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)) { @@ -562,10 +563,10 @@ namespace datatype { } ptr_vector<param_size::size> s_add; - for (constructor const& c : d) { + for (constructor const* c : d) { ptr_vector<param_size::size> s_mul; - for (accessor const& a : c) { - s_mul.push_back(get_sort_size(d.params(), a.range())); + 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)); } @@ -594,10 +595,10 @@ namespace datatype { } sort* s = sorts[tid]; def const& d = get_def(s); - for (constructor const& c : d) { + for (constructor const* c : d) { bool found_nonwf = false; - for (accessor const& a : c) { - if (sort2id.find(a.range(), id) && !well_founded[id]) { + for (accessor const* a : *c) { + if (sort2id.find(a->range(), id) && !well_founded[id]) { found_nonwf = true; break; } @@ -652,8 +653,8 @@ namespace datatype { 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); + for (constructor const* c : d) { + func_decl_ref f = c->instantiate(ty); m_asts.push_back(f); r->push_back(f); } @@ -671,10 +672,10 @@ namespace datatype { 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) { - res->push_back(a.instantiate(datatype)); + for (constructor const* c : d) { + if (c->name() == con->get_name()) { + for (accessor const* a : *c) { + res->push_back(a->instantiate(datatype)); } break; } @@ -739,9 +740,9 @@ namespace datatype { 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); + for (constructor const* c : d) { + if (c->name() == c_id) { + fn = c->instantiate(datatype); break; } } diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h index 13e85b47f..c540b7c1c 100644 --- a/src/ast/datatype_decl_plugin2.h +++ b/src/ast/datatype_decl_plugin2.h @@ -44,22 +44,19 @@ namespace datatype { }; class accessor { - ast_manager& m; symbol m_name; - sort_ref m_range; + sort* 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(m), + accessor(symbol const& n, sort* range): m_name(n), - m_range(range, m), + m_range(range), m_index(UINT_MAX) {} - accessor(ast_manager& m, symbol const& n, unsigned index): - m(m), + accessor(symbol const& n, unsigned index): m_name(n), - m_range(m), + m_range(0), m_index(index) {} sort* range() const { return m_range; } @@ -76,17 +73,18 @@ namespace datatype { class constructor { ast_manager& m; symbol m_name; - vector<accessor> m_accessors; + ptr_vector<accessor> m_accessors; def* m_def; public: constructor(ast_manager& m, symbol n): m(m), m_name(n) {} - void add(accessor& a) { m_accessors.push_back(a); a.attach(this); } + ~constructor(); + void add(accessor* a) { m_accessors.push_back(a); a->attach(this); } symbol const& name() const { return m_name; } - vector<accessor> const& accessors() const { return m_accessors; } - vector<accessor>::const_iterator begin() const { return m_accessors.begin(); } - vector<accessor>::const_iterator end() const { return m_accessors.end(); } - vector<accessor>::iterator begin() { return m_accessors.begin(); } - vector<accessor>::iterator end() { return m_accessors.end(); } + ptr_vector<accessor> const& accessors() const { return m_accessors; } + ptr_vector<accessor>::const_iterator begin() const { return m_accessors.begin(); } + ptr_vector<accessor>::const_iterator end() const { return m_accessors.end(); } + ptr_vector<accessor>::iterator begin() { return m_accessors.begin(); } + ptr_vector<accessor>::iterator end() { return m_accessors.end(); } func_decl_ref instantiate(sort_ref_vector const& ps) const; func_decl_ref instantiate(sort* dt) const; void attach(def* d) { m_def = d; } @@ -190,7 +188,7 @@ namespace datatype { param_size::size* m_sort_size; sort_ref_vector m_params; mutable sort_ref m_sort; - vector<constructor> m_constructors; + ptr_vector<constructor> m_constructors; public: def(ast_manager& m, util& u, symbol const& n, unsigned class_id, unsigned num_params, sort * const* params): m(m), @@ -204,18 +202,18 @@ namespace datatype { ~def() { if (m_sort_size) m_sort_size->dec_ref(); } - void add(constructor& c) { + void add(constructor* c) { m_constructors.push_back(c); - c.attach(this); + 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; - vector<constructor> const& constructors() const { return m_constructors; } - vector<constructor>::const_iterator begin() const { return m_constructors.begin(); } - vector<constructor>::const_iterator end() const { return m_constructors.end(); } - vector<constructor>::iterator begin() { return m_constructors.begin(); } - vector<constructor>::iterator end() { return m_constructors.end(); } + ptr_vector<constructor> const& constructors() const { return m_constructors; } + ptr_vector<constructor>::const_iterator begin() const { return m_constructors.begin(); } + ptr_vector<constructor>::const_iterator end() const { return m_constructors.end(); } + ptr_vector<constructor>::iterator begin() { return m_constructors.begin(); } + ptr_vector<constructor>::iterator end() { return m_constructors.end(); } sort_ref_vector const& params() const { return m_params; } util& u() const { return m_util; } param_size::size* sort_size() { return m_sort_size; } From a3dba5b2f97341269e205dbfb18d4c127e084f56 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 3 Sep 2017 20:01:59 -0700 Subject: [PATCH 53/74] hide new datatype plugin Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/api/api_datatype.cpp | 107 +++++++++-------------- src/ast/ast_smt_pp.cpp | 17 ++-- src/ast/datatype_decl_plugin.cpp | 37 ++++---- src/ast/datatype_decl_plugin.h | 11 ++- src/ast/datatype_decl_plugin2.cpp | 12 ++- src/ast/datatype_decl_plugin2.h | 74 ++++++++++++---- src/ast/decl_collector.cpp | 4 +- src/ast/rewriter/datatype_rewriter.cpp | 16 ++-- src/ast/rewriter/enum2bv_rewriter.cpp | 2 +- src/cmd_context/cmd_context.cpp | 12 +-- src/muz/base/dl_rule.h | 2 +- src/muz/base/rule_properties.cpp | 2 +- src/muz/bmc/dl_bmc_engine.cpp | 10 +-- src/muz/pdr/pdr_prop_solver.cpp | 2 +- src/muz/spacer/spacer_util.cpp | 2 +- src/qe/qe_datatype_plugin.cpp | 12 +-- src/qe/qe_datatypes.cpp | 6 +- src/qe/qe_lite.cpp | 2 +- src/smt/proto_model/datatype_factory.cpp | 12 +-- src/smt/smt_value_sort.cpp | 2 +- src/smt/theory_datatype.cpp | 37 ++++---- src/tactic/core/elim_uncnstr_tactic.cpp | 17 ++-- src/tactic/portfolio/enum2bv_solver.cpp | 2 +- src/test/get_consequences.cpp | 2 +- 24 files changed, 211 insertions(+), 191 deletions(-) diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index 851d96a4e..39d147ed1 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -69,18 +69,13 @@ extern "C" { // create constructor SASSERT(dt_util.is_datatype(tuple)); SASSERT(!dt_util.is_recursive(tuple)); - ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(tuple); - func_decl* decl = (*decls)[0]; + ptr_vector<func_decl> const & decls = dt_util.get_datatype_constructors(tuple); + func_decl* decl = (decls)[0]; mk_c(c)->save_multiple_ast_trail(decl); *mk_tuple_decl = of_func_decl(decl); // Create projections - ptr_vector<func_decl> const * accs = dt_util.get_constructor_accessors(decl); - if (!accs) { - SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); - } - ptr_vector<func_decl> const & _accs = *accs; + ptr_vector<func_decl> const & _accs = dt_util.get_constructor_accessors(decl); SASSERT(_accs.size() == num_fields); for (unsigned i = 0; i < _accs.size(); i++) { mk_c(c)->save_multiple_ast_trail(_accs[i]); @@ -136,10 +131,10 @@ extern "C" { // create constructor SASSERT(dt_util.is_datatype(e)); SASSERT(!dt_util.is_recursive(e)); - ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(e); - SASSERT(decls && decls->size() == n); + ptr_vector<func_decl> const & decls = dt_util.get_datatype_constructors(e); + SASSERT(decls.size() == n); for (unsigned i = 0; i < n; ++i) { - func_decl* decl = (*decls)[i]; + func_decl* decl = (decls)[i]; mk_c(c)->save_multiple_ast_trail(decl); enum_consts[i] = of_func_decl(decl); decl = dt_util.get_constructor_recognizer(decl); @@ -191,7 +186,7 @@ extern "C" { sort * s = sorts.get(0); mk_c(c)->save_multiple_ast_trail(s); - ptr_vector<func_decl> const& cnstrs = *data_util.get_datatype_constructors(s); + ptr_vector<func_decl> const& cnstrs = data_util.get_datatype_constructors(s); SASSERT(cnstrs.size() == 2); func_decl* f; if (nil_decl) { @@ -215,18 +210,16 @@ extern "C" { *is_cons_decl = of_func_decl(f); } if (head_decl) { - ptr_vector<func_decl> const* acc = data_util.get_constructor_accessors(cnstrs[1]); - SASSERT(acc); - SASSERT(acc->size() == 2); - f = (*acc)[0]; + ptr_vector<func_decl> const& acc = data_util.get_constructor_accessors(cnstrs[1]); + SASSERT(acc.size() == 2); + f = (acc)[0]; mk_c(c)->save_multiple_ast_trail(f); *head_decl = of_func_decl(f); } if (tail_decl) { - ptr_vector<func_decl> const* acc = data_util.get_constructor_accessors(cnstrs[1]); - SASSERT(acc); - SASSERT(acc->size() == 2); - f = (*acc)[1]; + ptr_vector<func_decl> const& acc = data_util.get_constructor_accessors(cnstrs[1]); + SASSERT(acc.size() == 2); + f = (acc)[1]; mk_c(c)->save_multiple_ast_trail(f); *tail_decl = of_func_decl(f); } @@ -301,13 +294,9 @@ extern "C" { *tester = of_func_decl(f2); } - ptr_vector<func_decl> const* accs = data_util.get_constructor_accessors(f); - if (!accs && num_fields > 0) { - SET_ERROR_CODE(Z3_INVALID_ARG); - return; - } + ptr_vector<func_decl> const& accs = data_util.get_constructor_accessors(f); for (unsigned i = 0; i < num_fields; ++i) { - func_decl* f2 = (*accs)[i]; + func_decl* f2 = (accs)[i]; mk_c(c)->save_multiple_ast_trail(f2); accessors[i] = of_func_decl(f2); } @@ -368,11 +357,11 @@ extern "C" { sort * s = sorts.get(0); mk_c(c)->save_ast_trail(s); - ptr_vector<func_decl> const* cnstrs = data_util.get_datatype_constructors(s); + ptr_vector<func_decl> const& cnstrs = data_util.get_datatype_constructors(s); for (unsigned i = 0; i < num_constructors; ++i) { constructor* cn = reinterpret_cast<constructor*>(constructors[i]); - cn->m_constructor = (*cnstrs)[i]; + cn->m_constructor = cnstrs[i]; } RETURN_Z3_mk_datatype(of_sort(s)); Z3_CATCH_RETURN(0); @@ -434,10 +423,10 @@ extern "C" { mk_c(c)->save_multiple_ast_trail(s); sorts[i] = of_sort(s); constructor_list* cl = reinterpret_cast<constructor_list*>(constructor_lists[i]); - ptr_vector<func_decl> const* cnstrs = data_util.get_datatype_constructors(s); + ptr_vector<func_decl> const& cnstrs = data_util.get_datatype_constructors(s); for (unsigned j = 0; j < cl->size(); ++j) { constructor* cn = (*cl)[j]; - cn->m_constructor = (*cnstrs)[j]; + cn->m_constructor = cnstrs[j]; } } RETURN_Z3_mk_datatypes; @@ -456,12 +445,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(_t); - if (!decls) { - SET_ERROR_CODE(Z3_INVALID_ARG); - return 0; - } - return decls->size(); + return dt_util.get_datatype_constructors(_t).size(); Z3_CATCH_RETURN(0); } @@ -474,12 +458,12 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(_t); - if (!decls || idx >= decls->size()) { + ptr_vector<func_decl> const & decls = dt_util.get_datatype_constructors(_t); + if (idx >= decls.size()) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - func_decl* decl = (*decls)[idx]; + func_decl* decl = (decls)[idx]; mk_c(c)->save_ast_trail(decl); return of_func_decl(decl); } @@ -504,12 +488,12 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(_t); - if (!decls || idx >= decls->size()) { + ptr_vector<func_decl> const & decls = dt_util.get_datatype_constructors(_t); + if (idx >= decls.size()) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - func_decl* decl = (*decls)[idx]; + func_decl* decl = (decls)[idx]; decl = dt_util.get_constructor_recognizer(decl); mk_c(c)->save_ast_trail(decl); RETURN_Z3(of_func_decl(decl)); @@ -527,23 +511,23 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(_t); - if (!decls || idx_c >= decls->size()) { + ptr_vector<func_decl> const & decls = dt_util.get_datatype_constructors(_t); + if (idx_c >= decls.size()) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - func_decl* decl = (*decls)[idx_c]; + func_decl* decl = (decls)[idx_c]; if (decl->get_arity() <= idx_a) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector<func_decl> const * accs = dt_util.get_constructor_accessors(decl); - SASSERT(accs && accs->size() == decl->get_arity()); - if (!accs || accs->size() <= idx_a) { + ptr_vector<func_decl> const & accs = dt_util.get_constructor_accessors(decl); + SASSERT(accs.size() == decl->get_arity()); + if (accs.size() <= idx_a) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - decl = (*accs)[idx_a]; + decl = (accs)[idx_a]; mk_c(c)->save_ast_trail(decl); RETURN_Z3(of_func_decl(decl)); Z3_CATCH_RETURN(0); @@ -574,16 +558,13 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(tuple); - if (!decls || decls->size() != 1) { + ptr_vector<func_decl> const & decls = dt_util.get_datatype_constructors(tuple); + if (decls.size() != 1) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - ptr_vector<func_decl> const * accs = dt_util.get_constructor_accessors((*decls)[0]); - if (!accs) { - return 0; - } - return accs->size(); + ptr_vector<func_decl> const & accs = dt_util.get_constructor_accessors(decls[0]); + return accs.size(); Z3_CATCH_RETURN(0); } @@ -597,21 +578,17 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector<func_decl> const * decls = dt_util.get_datatype_constructors(tuple); - if (!decls || decls->size() != 1) { + ptr_vector<func_decl> const & decls = dt_util.get_datatype_constructors(tuple); + if (decls.size() != 1) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector<func_decl> const * accs = dt_util.get_constructor_accessors((*decls)[0]); - if (!accs) { - SET_ERROR_CODE(Z3_INVALID_ARG); - RETURN_Z3(0); - } - if (accs->size() <= i) { + ptr_vector<func_decl> const & accs = dt_util.get_constructor_accessors((decls)[0]); + if (accs.size() <= i) { SET_ERROR_CODE(Z3_IOB); RETURN_Z3(0); } - func_decl* acc = (*accs)[i]; + func_decl* acc = (accs)[i]; mk_c(c)->save_ast_trail(acc); RETURN_Z3(of_func_decl(acc)); Z3_CATCH_RETURN(0); diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 9ebfdfbef..9211c5899 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -907,7 +907,6 @@ public: void pp_dt(ast_mark& mark, sort* s) { SASSERT(s->is_sort_of(m_dt_fid, DATATYPE_SORT)); datatype_util util(m_manager); - ptr_vector<func_decl> const* decls; ptr_vector<sort> rec_sorts; rec_sorts.push_back(s); @@ -916,10 +915,10 @@ public: // 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); + ptr_vector<func_decl> const& decls = util.get_datatype_constructors(s); - for (unsigned i = 0; i < decls->size(); ++i) { - func_decl* f = (*decls)[i]; + 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)) { @@ -955,11 +954,11 @@ public: m_out << "("; m_out << m_renaming.get_symbol(s->get_name()); m_out << " "; - decls = util.get_datatype_constructors(s); + ptr_vector<func_decl> const& decls = util.get_datatype_constructors(s); - for (unsigned i = 0; i < decls->size(); ++i) { - func_decl* f = (*decls)[i]; - ptr_vector<func_decl> const& accs = *util.get_constructor_accessors(f); + for (unsigned i = 0; i < decls.size(); ++i) { + func_decl* f = decls[i]; + ptr_vector<func_decl> const& accs = util.get_constructor_accessors(f); if (m_is_smt2 || accs.size() > 0) { m_out << "("; } @@ -976,7 +975,7 @@ public: } if (m_is_smt2 || accs.size() > 0) { m_out << ")"; - if (i + 1 < decls->size()) { + if (i + 1 < decls.size()) { m_out << " "; } } diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 446992105..e2aa54236 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -20,6 +20,7 @@ Revision History: #include "util/warning.h" #include "ast/ast_smt2_pp.h" +#ifndef DATATYPE_V2 /** \brief Auxiliary class used to declare inductive datatypes. @@ -802,11 +803,11 @@ func_decl * datatype_util::get_constructor(sort * ty, unsigned c_id) { return d; } -ptr_vector<func_decl> const * datatype_util::get_datatype_constructors(sort * ty) { +ptr_vector<func_decl> const & datatype_util::get_datatype_constructors(sort * ty) { SASSERT(is_datatype(ty)); ptr_vector<func_decl> * r = 0; if (m_datatype2constructors.find(ty, r)) - return r; + return *r; r = alloc(ptr_vector<func_decl>); m_asts.push_back(ty); m_vectors.push_back(r); @@ -819,7 +820,7 @@ ptr_vector<func_decl> const * datatype_util::get_datatype_constructors(sort * ty m_asts.push_back(c); r->push_back(c); } - return r; + return *r; } /** @@ -854,12 +855,12 @@ func_decl * datatype_util::get_non_rec_constructor_core(sort * ty, ptr_vector<so // 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<func_decl> const * constructors = get_datatype_constructors(ty); + ptr_vector<func_decl> const & constructors = get_datatype_constructors(ty); // step 1) - unsigned sz = constructors->size(); + unsigned sz = constructors.size(); ++m_start; for (unsigned j = 0; j < sz; ++j) { - func_decl * c = (*constructors)[(j + m_start) % sz]; + func_decl * c = constructors[(j + m_start) % sz]; unsigned num_args = c->get_arity(); unsigned i = 0; for (; i < num_args; i++) { @@ -872,7 +873,7 @@ func_decl * datatype_util::get_non_rec_constructor_core(sort * ty, ptr_vector<so } // step 2) for (unsigned j = 0; j < sz; ++j) { - func_decl * c = (*constructors)[(j + m_start) % sz]; + func_decl * c = constructors[(j + m_start) % sz]; TRACE("datatype_util_bug", tout << "non_rec_constructor c: " << c->get_name() << "\n";); unsigned num_args = c->get_arity(); unsigned i = 0; @@ -915,11 +916,11 @@ func_decl * datatype_util::get_constructor_recognizer(func_decl * constructor) { return d; } -ptr_vector<func_decl> const * datatype_util::get_constructor_accessors(func_decl * constructor) { +ptr_vector<func_decl> const & datatype_util::get_constructor_accessors(func_decl * constructor) { SASSERT(is_constructor(constructor)); ptr_vector<func_decl> * res = 0; if (m_constructor2accessors.find(constructor, res)) - return res; + return *res; res = alloc(ptr_vector<func_decl>); m_asts.push_back(constructor); m_vectors.push_back(res); @@ -938,7 +939,7 @@ ptr_vector<func_decl> const * datatype_util::get_constructor_accessors(func_decl m_asts.push_back(d); res->push_back(d); } - return res; + return *res; } func_decl * datatype_util::get_accessor_constructor(func_decl * accessor) { @@ -988,7 +989,7 @@ bool datatype_util::is_enum_sort(sort* s) { bool r = false; if (m_is_enum.find(s, r)) return r; - ptr_vector<func_decl> const& cnstrs = *get_datatype_constructors(s); + ptr_vector<func_decl> const& cnstrs = get_datatype_constructors(s); r = true; for (unsigned i = 0; r && i < cnstrs.size(); ++i) { r = cnstrs[i]->get_arity() == 0; @@ -1048,14 +1049,14 @@ void datatype_util::display_datatype(sort *s0, std::ostream& strm) { todo.pop_back(); strm << s->get_name() << " =\n"; - ptr_vector<func_decl> const * cnstrs = get_datatype_constructors(s); - for (unsigned i = 0; i < cnstrs->size(); ++i) { - func_decl* cns = (*cnstrs)[i]; + ptr_vector<func_decl> 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<func_decl> const * accs = get_constructor_accessors(cns); - for (unsigned j = 0; j < accs->size(); ++j) { - func_decl* acc = (*accs)[j]; + ptr_vector<func_decl> 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)) { @@ -1090,3 +1091,5 @@ bool datatype_util::is_constructor_of(unsigned num_params, parameter const* para params[1] == f->get_parameter(1); } + +#endif diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index dcd352471..b9c2602ef 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -16,9 +16,15 @@ Author: Revision History: --*/ +// define DATATYPE_V2 +#ifdef DATATYPE_V2 +#include "ast/datatype_decl_plugin2.h" +#else + #ifndef DATATYPE_DECL_PLUGIN_H_ #define DATATYPE_DECL_PLUGIN_H_ + #include "ast/ast.h" #include "util/tptr.h" #include "util/buffer.h" @@ -210,7 +216,7 @@ public: bool is_recognizer(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER); } bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); } bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); } - ptr_vector<func_decl> const * get_datatype_constructors(sort * ty); + ptr_vector<func_decl> const & get_datatype_constructors(sort * ty); unsigned get_datatype_num_constructors(sort * ty) { SASSERT(is_datatype(ty)); unsigned tid = ty->get_parameter(1).get_int(); @@ -230,7 +236,7 @@ public: unsigned get_recognizer_constructor_idx(func_decl * f) const { SASSERT(is_recognizer(f)); return f->get_parameter(1).get_int(); } func_decl * get_non_rec_constructor(sort * ty); func_decl * get_constructor_recognizer(func_decl * constructor); - ptr_vector<func_decl> const * get_constructor_accessors(func_decl * constructor); + ptr_vector<func_decl> const & get_constructor_accessors(func_decl * constructor); func_decl * get_accessor_constructor(func_decl * accessor); func_decl * get_recognizer_constructor(func_decl * recognizer); family_id get_family_id() const { return m_family_id; } @@ -245,3 +251,4 @@ public: #endif /* DATATYPE_DECL_PLUGIN_H_ */ +#endif /* DATATYPE_V2 */ diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp index 8233da7d9..2fc62af31 100644 --- a/src/ast/datatype_decl_plugin2.cpp +++ b/src/ast/datatype_decl_plugin2.cpp @@ -22,6 +22,7 @@ Revision History: #include "ast/ast_smt2_pp.h" +#ifdef DATATYPE_V2 namespace datatype { void accessor::fix_range(sort_ref_vector const& dts) { @@ -49,6 +50,10 @@ namespace datatype { def const& accessor::get_def() const { return m_constructor->get_def(); } util& accessor::u() const { return m_constructor->u(); } + 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 { @@ -164,7 +169,7 @@ namespace datatype { sort* r = to_sort(parameters[i].get_ast()); S.insert(d->params()[i], r->get_num_elements()); } - sort_size ts = d->sort_size()->fold(S); + sort_size ts = d->sort_size()->eval(S); s->set_num_elements(ts); } return s; @@ -278,7 +283,9 @@ namespace datatype { def& plugin::add(symbol const& name, unsigned n, sort * const * params) { ast_manager& m = *m_manager; - def* d = alloc(def, m, u(), name, m_class_id, n, params); + def* d = 0; + if (m_defs.find(name, d)) dealloc(d); + d = alloc(def, m, u(), name, m_class_id, n, params); m_defs.insert(name, d); m_def_block.push_back(name); return *d; @@ -895,3 +902,4 @@ namespace datatype { } } } +#endif diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h index c540b7c1c..c8aa042f1 100644 --- a/src/ast/datatype_decl_plugin2.h +++ b/src/ast/datatype_decl_plugin2.h @@ -24,17 +24,12 @@ Revision History: #include "util/symbol_table.h" #include "util/obj_hashtable.h" -namespace datatype { - - class util; - class def; - class accessor; - class constructor; +#ifdef DATATYPE_V2 enum sort_kind { DATATYPE_SORT }; - + enum op_kind { OP_DT_CONSTRUCTOR, OP_DT_RECOGNISER, @@ -43,6 +38,14 @@ namespace datatype { LAST_DT_OP }; +namespace datatype { + + class util; + class def; + class accessor; + class constructor; + + class accessor { symbol m_name; sort* m_range; @@ -109,7 +112,7 @@ namespace datatype { static size* mk_power(size* a1, size* a2); virtual size* subst(obj_map<sort, size*>& S) = 0; - virtual sort_size fold(obj_map<sort, sort_size> const& S) = 0; + virtual sort_size eval(obj_map<sort, sort_size> const& S) = 0; }; struct offset : public size { @@ -117,16 +120,16 @@ namespace datatype { offset(sort_size const& s): m_offset(s) {} virtual ~offset() {} virtual size* subst(obj_map<sort,size*>& S) { return this; } - virtual sort_size fold(obj_map<sort, sort_size> const& S) { return m_offset; } + virtual sort_size eval(obj_map<sort, sort_size> const& S) { return m_offset; } }; struct plus : public size { size* m_arg1, *m_arg2; plus(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref();} virtual ~plus() { m_arg1->dec_ref(); m_arg2->dec_ref(); } virtual size* subst(obj_map<sort,size*>& S) { return mk_plus(m_arg1->subst(S), m_arg2->subst(S)); } - virtual sort_size fold(obj_map<sort, sort_size> const& S) { - sort_size s1 = m_arg1->fold(S); - sort_size s2 = m_arg2->fold(S); + virtual sort_size eval(obj_map<sort, sort_size> const& S) { + sort_size s1 = m_arg1->eval(S); + sort_size s2 = m_arg2->eval(S); if (s1.is_infinite()) return s1; if (s2.is_infinite()) return s2; if (s1.is_very_big()) return s1; @@ -140,9 +143,9 @@ namespace datatype { times(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); } virtual ~times() { m_arg1->dec_ref(); m_arg2->dec_ref(); } virtual size* subst(obj_map<sort,size*>& S) { return mk_times(m_arg1->subst(S), m_arg2->subst(S)); } - virtual sort_size fold(obj_map<sort, sort_size> const& S) { - sort_size s1 = m_arg1->fold(S); - sort_size s2 = m_arg2->fold(S); + virtual sort_size eval(obj_map<sort, sort_size> const& S) { + sort_size s1 = m_arg1->eval(S); + sort_size s2 = m_arg2->eval(S); if (s1.is_infinite()) return s1; if (s2.is_infinite()) return s2; if (s1.is_very_big()) return s1; @@ -156,9 +159,9 @@ namespace datatype { power(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); } virtual ~power() { m_arg1->dec_ref(); m_arg2->dec_ref(); } virtual size* subst(obj_map<sort,size*>& S) { return mk_power(m_arg1->subst(S), m_arg2->subst(S)); } - virtual sort_size fold(obj_map<sort, sort_size> const& S) { - sort_size s1 = m_arg1->fold(S); - sort_size s2 = m_arg2->fold(S); + virtual sort_size eval(obj_map<sort, sort_size> const& S) { + sort_size s1 = m_arg1->eval(S); + sort_size s2 = m_arg2->eval(S); // s1^s2 if (s1.is_infinite()) return s1; if (s2.is_infinite()) return s2; @@ -176,7 +179,7 @@ namespace datatype { sparam(sort_ref& p): m_param(p) {} virtual ~sparam() {} virtual size* subst(obj_map<sort,size*>& S) { return S[m_param]; } - virtual sort_size fold(obj_map<sort, sort_size> const& S) { return S[m_param]; } + virtual sort_size eval(obj_map<sort, sort_size> const& S) { return S[m_param]; } }; }; @@ -201,6 +204,8 @@ namespace datatype { {} ~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); @@ -361,5 +366,36 @@ namespace datatype { }; +#ifdef DATATYPE_V2 +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; + +class type_ref { + void * m_data; +public: + type_ref():m_data(TAG(void *, static_cast<void*>(0), 1)) {} + type_ref(int idx):m_data(BOXINT(void *, idx)) {} + type_ref(sort * s):m_data(TAG(void *, s, 1)) {} + + bool is_idx() const { return GET_TAG(m_data) == 0; } + bool is_sort() const { return GET_TAG(m_data) == 1; } + sort * get_sort() const { return UNTAG(sort *, m_data); } + int get_idx() const { return UNBOXINT(m_data); } +}; + +inline accessor_decl * mk_accessor_decl(symbol const & n, type_ref const & t) { + if (t.is_idx()) { + return alloc(accessor_decl, n, t.get_idx()); + } + else { + return alloc(accessor_decl, n, t.get_sort()); + } +} +#endif + #endif /* DATATYPE_DECL_PLUGIN_H_ */ +#endif DATATYPE_V2 diff --git a/src/ast/decl_collector.cpp b/src/ast/decl_collector.cpp index e000f43df..bf509aba5 100644 --- a/src/ast/decl_collector.cpp +++ b/src/ast/decl_collector.cpp @@ -28,9 +28,9 @@ void decl_collector::visit_sort(sort * n) { unsigned num_cnstr = m_dt_util.get_datatype_num_constructors(n); for (unsigned i = 0; i < num_cnstr; i++) { - func_decl * cnstr = m_dt_util.get_datatype_constructors(n)->get(i); + func_decl * cnstr = m_dt_util.get_datatype_constructors(n).get(i); m_decls.push_back(cnstr); - ptr_vector<func_decl> const & cnstr_acc = *m_dt_util.get_constructor_accessors(cnstr); + ptr_vector<func_decl> const & cnstr_acc = m_dt_util.get_constructor_accessors(cnstr); unsigned num_cas = cnstr_acc.size(); for (unsigned j = 0; j < num_cas; j++) { func_decl * accsr = cnstr_acc.get(j); diff --git a/src/ast/rewriter/datatype_rewriter.cpp b/src/ast/rewriter/datatype_rewriter.cpp index d38c9e476..8746fab86 100644 --- a/src/ast/rewriter/datatype_rewriter.cpp +++ b/src/ast/rewriter/datatype_rewriter.cpp @@ -47,11 +47,11 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr func_decl * c_decl = a->get_decl(); if (c_decl != m_util.get_accessor_constructor(f)) return BR_FAILED; - ptr_vector<func_decl> const * acc = m_util.get_constructor_accessors(c_decl); - SASSERT(acc && acc->size() == a->get_num_args()); - unsigned num = acc->size(); + ptr_vector<func_decl> const & acc = m_util.get_constructor_accessors(c_decl); + SASSERT(acc.size() == a->get_num_args()); + unsigned num = acc.size(); for (unsigned i = 0; i < num; ++i) { - if (f == (*acc)[i]) { + if (f == acc[i]) { // found it. result = a->get_arg(i); return BR_DONE; @@ -70,13 +70,13 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr result = a; return BR_DONE; } - ptr_vector<func_decl> const * acc = m_util.get_constructor_accessors(c_decl); - SASSERT(acc && acc->size() == a->get_num_args()); - unsigned num = acc->size(); + ptr_vector<func_decl> const & acc = m_util.get_constructor_accessors(c_decl); + SASSERT(acc.size() == a->get_num_args()); + unsigned num = acc.size(); ptr_buffer<expr> new_args; for (unsigned i = 0; i < num; ++i) { - if (f == (*acc)[i]) { + if (f == acc[i]) { new_args.push_back(args[1]); } else { diff --git a/src/ast/rewriter/enum2bv_rewriter.cpp b/src/ast/rewriter/enum2bv_rewriter.cpp index eb6b195f0..b2ecbcc24 100644 --- a/src/ast/rewriter/enum2bv_rewriter.cpp +++ b/src/ast/rewriter/enum2bv_rewriter.cpp @@ -130,7 +130,7 @@ struct enum2bv_rewriter::imp { m_imp.m_bounds.push_back(m_bv.mk_ule(result, m_bv.mk_numeral(nc-1, bv_size))); } expr_ref f_def(m); - ptr_vector<func_decl> const& cs = *m_dt.get_datatype_constructors(s); + ptr_vector<func_decl> const& cs = m_dt.get_datatype_constructors(s); f_def = m.mk_const(cs[nc-1]); for (unsigned i = nc - 1; i > 0; ) { --i; diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 8b1a89f3f..109fe1718 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1954,19 +1954,19 @@ 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<func_decl> const * constructors = m_dt_util.get_datatype_constructors(dt); - unsigned num_constructors = constructors->size(); + ptr_vector<func_decl> 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); + func_decl * c = constructors[j]; m_owner.insert(c); TRACE("new_dt_eh", tout << "new constructor: " << c->get_name() << "\n";); 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<func_decl> const * accessors = m_dt_util.get_constructor_accessors(c); - unsigned num_accessors = accessors->size(); + ptr_vector<func_decl> 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); + func_decl * a = accessors[k]; m_owner.insert(a); TRACE("new_dt_eh", tout << "new accessor: " << a->get_name() << "\n";); } diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index ea0e64e4f..51d673ba5 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -65,7 +65,7 @@ namespace datalog { else if (m_dt.is_accessor(n)) { sort* s = m.get_sort(n->get_arg(0)); SASSERT(m_dt.is_datatype(s)); - if (m_dt.get_datatype_constructors(s)->size() > 1) { + if (m_dt.get_datatype_constructors(s).size() > 1) { m_found = true; m_func = n->get_decl(); } diff --git a/src/muz/base/rule_properties.cpp b/src/muz/base/rule_properties.cpp index 21317a07c..75487bbfb 100644 --- a/src/muz/base/rule_properties.cpp +++ b/src/muz/base/rule_properties.cpp @@ -191,7 +191,7 @@ void rule_properties::operator()(app* n) { else if (m_dt.is_accessor(n)) { sort* s = m.get_sort(n->get_arg(0)); SASSERT(m_dt.is_datatype(s)); - if (m_dt.get_datatype_constructors(s)->size() > 1) { + if (m_dt.get_datatype_constructors(s).size() > 1) { m_uninterp_funs.insert(n->get_decl(), m_rule); } } diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 6d2f88019..b9dbe83ca 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -808,7 +808,7 @@ namespace datalog { datatype_util dtu(m); ptr_vector<sort> sorts; func_decl* p = r.get_decl(); - ptr_vector<func_decl> const& succs = *dtu.get_datatype_constructors(m.get_sort(path)); + ptr_vector<func_decl> const& succs = dtu.get_datatype_constructors(m.get_sort(path)); // populate substitution of bound variables. r.get_vars(m, sorts); sub.reset(); @@ -871,8 +871,8 @@ namespace datalog { path_var = m.mk_var(0, m_path_sort); trace_var = m.mk_var(1, pred_sort); // sort* sorts[2] = { pred_sort, m_path_sort }; - ptr_vector<func_decl> const& cnstrs = *dtu.get_datatype_constructors(pred_sort); - ptr_vector<func_decl> const& succs = *dtu.get_datatype_constructors(m_path_sort); + ptr_vector<func_decl> const& cnstrs = dtu.get_datatype_constructors(pred_sort); + ptr_vector<func_decl> const& succs = dtu.get_datatype_constructors(m_path_sort); SASSERT(cnstrs.size() == rls.size()); pred = m.mk_app(mk_predicate(p), trace_var.get(), path_var.get()); for (unsigned i = 0; i < rls.size(); ++i) { @@ -1039,8 +1039,8 @@ namespace datalog { sort* trace_sort = m.get_sort(trace); func_decl* p = m_sort2pred.find(trace_sort); datalog::rule_vector const& rules = b.m_rules.get_predicate_rules(p); - ptr_vector<func_decl> const& cnstrs = *dtu.get_datatype_constructors(trace_sort); - ptr_vector<func_decl> const& succs = *dtu.get_datatype_constructors(m_path_sort); + ptr_vector<func_decl> const& cnstrs = dtu.get_datatype_constructors(trace_sort); + ptr_vector<func_decl> const& succs = dtu.get_datatype_constructors(m_path_sort); for (unsigned i = 0; i < cnstrs.size(); ++i) { if (trace->get_decl() == cnstrs[i]) { svector<std::pair<unsigned, unsigned> > positions; diff --git a/src/muz/pdr/pdr_prop_solver.cpp b/src/muz/pdr/pdr_prop_solver.cpp index 3055985f4..1bca8e925 100644 --- a/src/muz/pdr/pdr_prop_solver.cpp +++ b/src/muz/pdr/pdr_prop_solver.cpp @@ -135,7 +135,7 @@ namespace pdr { func_decl* f = to_app(val)->get_decl(); func_decl* r = dt.get_constructor_recognizer(f); conjs[i] = m.mk_app(r, c); - ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(f); + ptr_vector<func_decl> const& acc = dt.get_constructor_accessors(f); for (unsigned j = 0; j < acc.size(); ++j) { conjs.push_back(m.mk_eq(apply_accessor(acc, j, f, c), to_app(val)->get_arg(j))); } diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index a277c9ed6..14d8899c5 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -711,7 +711,7 @@ void expand_literals(ast_manager &m, expr_ref_vector& conjs) func_decl* f = to_app(val)->get_decl(); func_decl* r = dt.get_constructor_recognizer(f); conjs[i] = m.mk_app(r, c); - ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(f); + ptr_vector<func_decl> const& acc = dt.get_constructor_accessors(f); for (unsigned j = 0; j < acc.size(); ++j) { conjs.push_back(m.mk_eq(apply_accessor(m, acc, j, f, c), to_app(val)->get_arg(j))); } diff --git a/src/qe/qe_datatype_plugin.cpp b/src/qe/qe_datatype_plugin.cpp index 4178c3af3..eff230ffe 100644 --- a/src/qe/qe_datatype_plugin.cpp +++ b/src/qe/qe_datatype_plugin.cpp @@ -262,7 +262,7 @@ namespace qe { } func_decl* c = a->get_decl(); func_decl* r = m_util.get_constructor_recognizer(c); - ptr_vector<func_decl> const & acc = *m_util.get_constructor_accessors(c); + ptr_vector<func_decl> const & acc = m_util.get_constructor_accessors(c); SASSERT(acc.size() == a->get_num_args()); // // It suffices to solve just the first available equality. @@ -379,7 +379,7 @@ namespace qe { return false; } func_decl* c = l->get_decl(); - ptr_vector<func_decl> const& acc = *m_util.get_constructor_accessors(c); + ptr_vector<func_decl> const& acc = m_util.get_constructor_accessors(c); func_decl* rec = m_util.get_constructor_recognizer(c); expr_ref_vector conj(m); conj.push_back(m.mk_app(rec, r)); @@ -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)[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)[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)[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)[vl.get_unsigned()]; } subst_constructor(x, c, fml, def); } diff --git a/src/qe/qe_datatypes.cpp b/src/qe/qe_datatypes.cpp index db1e6ec85..f16bdda59 100644 --- a/src/qe/qe_datatypes.cpp +++ b/src/qe/qe_datatypes.cpp @@ -75,7 +75,7 @@ namespace qe { app_ref arg(m); SASSERT(dt.is_constructor(m_val)); func_decl* f = m_val->get_decl(); - ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(f); + ptr_vector<func_decl> const& acc = dt.get_constructor_accessors(f); for (unsigned i = 0; i < acc.size(); ++i) { arg = m.mk_fresh_const(acc[i]->get_name().str().c_str(), acc[i]->get_range()); model.register_decl(arg->get_decl(), m_val->get_arg(i)); @@ -152,7 +152,7 @@ namespace qe { } func_decl* c = a->get_decl(); func_decl* rec = dt.get_constructor_recognizer(c); - ptr_vector<func_decl> const & acc = *dt.get_constructor_accessors(c); + ptr_vector<func_decl> const & acc = dt.get_constructor_accessors(c); SASSERT(acc.size() == a->get_num_args()); // // It suffices to solve just the first available equality. @@ -230,7 +230,7 @@ namespace qe { return false; } func_decl* c = to_app(l)->get_decl(); - ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(c); + ptr_vector<func_decl> const& acc = dt.get_constructor_accessors(c); if (!is_app_of(r, c)) { lits.push_back(m.mk_app(dt.get_constructor_recognizer(c), r)); } diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 257331161..10af3be25 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -671,7 +671,7 @@ namespace eq { else { func_decl* rec = dt.get_constructor_recognizer(d); conjs.push_back(m.mk_app(rec, r)); - ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(d); + ptr_vector<func_decl> const& acc = dt.get_constructor_accessors(d); for (unsigned i = 0; i < acc.size(); ++i) { conjs.push_back(m.mk_eq(c->get_arg(i), m.mk_app(acc[i], r))); } diff --git a/src/smt/proto_model/datatype_factory.cpp b/src/smt/proto_model/datatype_factory.cpp index d738f2cbd..653ef034a 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<func_decl> const * constructors = m_util.get_datatype_constructors(s); - for (func_decl * constructor : *constructors) { + ptr_vector<func_decl> 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<func_decl> const * constructors = m_util.get_datatype_constructors(s); - for (func_decl * constructor : *constructors) { + ptr_vector<func_decl> 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<func_decl> const * constructors = m_util.get_datatype_constructors(s); - for (func_decl * constructor : *constructors) { + ptr_vector<func_decl> 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/smt_value_sort.cpp b/src/smt/smt_value_sort.cpp index 56768b91a..3eeb3461d 100644 --- a/src/smt/smt_value_sort.cpp +++ b/src/smt/smt_value_sort.cpp @@ -52,7 +52,7 @@ namespace smt { // simple } else if (data.is_datatype(s)) { - ptr_vector<func_decl> const& cs = *data.get_datatype_constructors(s); + ptr_vector<func_decl> const& cs = data.get_datatype_constructors(s); for (unsigned i = 0; i < cs.size(); ++i) { func_decl* f = cs[i]; for (unsigned j = 0; j < f->get_arity(); ++j) { diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index beb1acf63..33b4b194d 100644 --- a/src/smt/theory_datatype.cpp +++ b/src/smt/theory_datatype.cpp @@ -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<expr> args; - ptr_vector<func_decl> const * accessors = m_util.get_constructor_accessors(c); - SASSERT(c->get_arity() == accessors->size()); - ptr_vector<func_decl>::const_iterator it = accessors->begin(); - ptr_vector<func_decl>::const_iterator end = accessors->end(); - for (; it != end; ++it) { - func_decl * d = *it; + ptr_vector<func_decl> 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<func_decl> const * accessors = m_util.get_constructor_accessors(d); - SASSERT(n->get_num_args() == accessors->size()); - ptr_vector<func_decl>::const_iterator it = accessors->begin(); - ptr_vector<func_decl>::const_iterator end = accessors->end(); - for (unsigned i = 0; it != end; ++it, ++i) { - func_decl * acc = *it; + ptr_vector<func_decl> 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<func_decl> const * accessors = m_util.get_constructor_accessors(con); - ptr_vector<func_decl>::const_iterator it = accessors->begin(); - ptr_vector<func_decl>::const_iterator end = accessors->end(); + ptr_vector<func_decl> 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); } @@ -215,7 +208,7 @@ namespace smt { ast_manager & m = get_manager(); sort * s = m.get_sort(n->get_owner()); if (m_util.get_datatype_num_constructors(s) == 1) { - func_decl * c = m_util.get_datatype_constructors(s)->get(0); + func_decl * c = m_util.get_datatype_constructors(s)[0]; assert_is_constructor_axiom(n, c, null_literal); } else { @@ -716,8 +709,8 @@ namespace smt { enode * r = d->m_recognizers[unassigned_idx]; literal consequent; if (!r) { - ptr_vector<func_decl> const * constructors = m_util.get_datatype_constructors(dt); - func_decl * rec = m_util.get_constructor_recognizer(constructors->get(unassigned_idx)); + ptr_vector<func_decl> 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)); @@ -781,9 +774,9 @@ namespace smt { for (unsigned idx = 0; it != end; ++it, ++idx) { enode * curr = *it; if (curr == 0) { - ptr_vector<func_decl> const * constructors = m_util.get_datatype_constructors(s); + ptr_vector<func_decl> 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)) { diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 73adabb6f..a13cd54d8 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<func_decl> const * constructors = m_dt_util.get_datatype_constructors(s); - ptr_vector<func_decl>::const_iterator it = constructors->begin(); - ptr_vector<func_decl>::const_iterator end = constructors->end(); - for (; it != end; ++it) { - func_decl * constructor = *it; + ptr_vector<func_decl> 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<func_decl> const * accs = m_dt_util.get_constructor_accessors(c); + ptr_vector<func_decl> const & accs = m_dt_util.get_constructor_accessors(c); ptr_buffer<expr> 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<func_decl> const * accs = m_dt_util.get_constructor_accessors(f); + ptr_vector<func_decl> 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/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index 36a178c41..db7cebd6e 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -136,7 +136,7 @@ public: if (m.is_eq(b, u, v) && is_uninterp_const(u) && m_rewriter.bv2enum().find(to_app(u)->get_decl(), f) && bv.is_numeral(v, num, bvsize)) { SASSERT(num.is_unsigned()); expr_ref head(m); - ptr_vector<func_decl> const& enums = *dt.get_datatype_constructors(f->get_range()); + ptr_vector<func_decl> const& enums = dt.get_datatype_constructors(f->get_range()); if (enums.size() > num.get_unsigned()) { head = m.mk_eq(m.mk_const(f), m.mk_const(enums[num.get_unsigned()])); consequences[i] = m.mk_implies(a, head); diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index 9337dcee3..e8868c661 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -71,7 +71,7 @@ void test2() { 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); - ptr_vector<func_decl> const& enums = *dtutil.get_datatype_constructors(rgb); + ptr_vector<func_decl> const& enums = dtutil.get_datatype_constructors(rgb); expr_ref r = expr_ref(m.mk_const(enums[0]), m); expr_ref g = expr_ref(m.mk_const(enums[1]), m); expr_ref b = expr_ref(m.mk_const(enums[2]), m); From f12a4f04fdf5bcd16a120ffe1c1d64a5b4f02359 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Mon, 4 Sep 2017 09:28:40 -0700 Subject: [PATCH 54/74] aligning simplifier and rewriter for regression tests Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/api/api_datatype.cpp | 10 +++-- src/ast/datatype_decl_plugin.cpp | 2 +- src/ast/datatype_decl_plugin.h | 12 +++--- src/ast/datatype_decl_plugin2.cpp | 64 ++++++++++++++++++++++++++-- src/ast/datatype_decl_plugin2.h | 45 +++++++++++++------ src/ast/rewriter/arith_rewriter.cpp | 4 +- src/ast/rewriter/poly_rewriter.h | 1 + src/ast/rewriter/poly_rewriter_def.h | 7 ++- src/cmd_context/pdecl.cpp | 7 ++- src/cmd_context/pdecl.h | 9 ++-- src/muz/bmc/dl_bmc_engine.cpp | 4 +- src/test/get_consequences.cpp | 3 +- 12 files changed, 125 insertions(+), 43 deletions(-) diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index 39d147ed1..d670888ed 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -51,7 +51,7 @@ extern "C" { 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), 1, constrs); bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &dt, 0, 0, tuples); del_datatype_decl(dt); @@ -113,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), n, constrs.c_ptr()); bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &dt, 0, 0, sorts); del_datatype_decl(dt); @@ -160,6 +160,7 @@ 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] = { @@ -174,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), 2, constrs); bool is_ok = mk_c(c)->get_dt_plugin()->mk_datatypes(1, &decl, 0, 0, sorts); del_datatype_decl(decl); @@ -316,6 +317,7 @@ extern "C" { Z3_symbol name, unsigned num_constructors, Z3_constructor constructors[]) { + datatype_util& dt_util = mk_c(c)->dtutil(); ptr_vector<constructor_decl> constrs; for (unsigned i = 0; i < num_constructors; ++i) { constructor* cn = reinterpret_cast<constructor*>(constructors[i]); @@ -330,7 +332,7 @@ extern "C" { } 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), num_constructors, constrs.c_ptr()); } Z3_sort Z3_API Z3_mk_datatype(Z3_context c, diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index e2aa54236..1c090bc33 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -95,7 +95,7 @@ public: ptr_vector<constructor_decl> const & get_constructors() const { return m_constructors; } }; -datatype_decl * mk_datatype_decl(symbol const & n, unsigned num_constructors, constructor_decl * const * cs) { +datatype_decl * mk_datatype_decl(datatype_util&, symbol const & n, unsigned num_constructors, constructor_decl * const * cs) { return alloc(datatype_decl, n, num_constructors, cs); } diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index b9c2602ef..e3e1b7b10 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -16,7 +16,7 @@ Author: Revision History: --*/ -// define DATATYPE_V2 +//define DATATYPE_V2 #ifdef DATATYPE_V2 #include "ast/datatype_decl_plugin2.h" #else @@ -79,14 +79,14 @@ class datatype_decl; class datatype_util; 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); +//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); +//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); +datatype_decl * mk_datatype_decl(datatype_util& u, 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); diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp index 2fc62af31..c059907d5 100644 --- a/src/ast/datatype_decl_plugin2.cpp +++ b/src/ast/datatype_decl_plugin2.cpp @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2006 Microsoft Corporation +Copyright (c) 2017 Microsoft Corporation Module Name: @@ -11,18 +11,21 @@ Abstract: Author: - Leonardo de Moura (leonardo) 2008-01-10. + Nikolaj Bjorner (nbjorner) 2017-9-1 Revision History: --*/ + +#include "ast/datatype_decl_plugin.h" + +#ifdef DATATYPE_V2 #include "util/warning.h" #include "ast/datatype_decl_plugin2.h" #include "ast/array_decl_plugin.h" #include "ast/ast_smt2_pp.h" -#ifdef DATATYPE_V2 namespace datatype { void accessor::fix_range(sort_ref_vector const& dts) { @@ -57,6 +60,7 @@ namespace datatype { 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()); @@ -281,6 +285,11 @@ namespace datatype { } } + 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); + } + def& plugin::add(symbol const& name, unsigned n, sort * const * params) { ast_manager& m = *m_manager; def* d = 0; @@ -313,6 +322,21 @@ namespace datatype { u().compute_datatype_size_functions(m_def_block); } + 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) { + if (m_defs.find(datatypes[i]->name(), d)) 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::del(symbol const& s) { def* d = 0; if (m_defs.find(s, d)) dealloc(d); @@ -705,7 +729,7 @@ namespace datatype { return d; } - func_decl * util::get_recognizer_constructor(func_decl * recognizer) { + func_decl * util::get_recognizer_constructor(func_decl * recognizer) const { SASSERT(is_recognizer(recognizer)); return to_func_decl(recognizer->get_parameter(0).get_ast()); } @@ -856,6 +880,22 @@ namespace datatype { 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; + } + ++idx; + } + UNREACHABLE(); + return 0; + } + unsigned util::get_recognizer_constructor_idx(func_decl * f) const { + return get_constructor_idx(get_recognizer_constructor(f)); + } + /** \brief Two datatype sorts s1 and s2 are siblings if they were @@ -870,6 +910,12 @@ namespace datatype { } } + unsigned util::get_datatype_num_constructors(sort * ty) { + def const& d = get_def(ty->get_name()); + return d.constructors().size(); + } + + void util::display_datatype(sort *s0, std::ostream& strm) { ast_mark mark; ptr_buffer<sort> todo; @@ -902,4 +948,14 @@ namespace datatype { } } } + +datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_constructors, constructor_decl * const * cs) { + datatype::decl::plugin* p = u.get_plugin(); + datatype::def( d = p->mk(n, 0, 0); + for (unsigned i = 0; i < num_constructors; ++i) { + d->add(cs[i]); + } + return d; +} + #endif diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h index c8aa042f1..c79939a5b 100644 --- a/src/ast/datatype_decl_plugin2.h +++ b/src/ast/datatype_decl_plugin2.h @@ -1,5 +1,5 @@ /*++ -Copyright (c) 2006 Microsoft Corporation +Copyright (c) 2017 Microsoft Corporation Module Name: @@ -11,10 +11,13 @@ 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_PLUGIN2_H_ #define DATATYPE_DECL_PLUGIN2_H_ @@ -74,12 +77,11 @@ namespace datatype { }; class constructor { - ast_manager& m; symbol m_name; ptr_vector<accessor> m_accessors; def* m_def; public: - constructor(ast_manager& m, symbol n): m(m), m_name(n) {} + constructor(symbol n): m_name(n) {} ~constructor(); void add(accessor* a) { m_accessors.push_back(a); a->attach(this); } symbol const& name() const { return m_name; } @@ -262,8 +264,12 @@ namespace datatype { def& add(symbol const& name, unsigned n, sort * const * params); + def* mk(symbol const& name, unsigned n, sort * const * params); + void del(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]); } @@ -299,9 +305,7 @@ namespace datatype { family_id m_family_id; mutable decl::plugin* m_plugin; - - func_decl * get_constructor(sort * ty, unsigned c_id) const; - + obj_map<sort, ptr_vector<func_decl> *> m_datatype2constructors; obj_map<sort, func_decl *> m_datatype2nonrec_constructor; obj_map<func_decl, ptr_vector<func_decl> *> m_constructor2accessors; @@ -310,14 +314,13 @@ namespace datatype { obj_map<func_decl, func_decl *> m_accessor2constructor; obj_map<sort, bool> m_is_recursive; obj_map<sort, bool> m_is_enum; - mutable obj_map<sort, bool> m_is_fully_interp; + mutable obj_map<sort, bool> m_is_fully_interp; mutable ast_ref_vector m_asts; ptr_vector<ptr_vector<func_decl> > m_vectors; unsigned m_start; - mutable ptr_vector<sort> m_fully_interp_trail; + mutable ptr_vector<sort> m_fully_interp_trail; func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set); - func_decl * get_constructor(sort * ty, unsigned c_id); friend class decl::plugin; @@ -353,7 +356,7 @@ namespace datatype { func_decl * get_constructor_recognizer(func_decl * constructor); ptr_vector<func_decl> const & get_constructor_accessors(func_decl * constructor); func_decl * get_accessor_constructor(func_decl * accessor); - func_decl * get_recognizer_constructor(func_decl * recognizer); + 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); @@ -362,11 +365,12 @@ namespace datatype { 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; }; }; -#ifdef DATATYPE_V2 typedef datatype::accessor accessor_decl; typedef datatype::constructor constructor_decl; typedef datatype::def datatype_decl; @@ -394,7 +398,22 @@ inline accessor_decl * mk_accessor_decl(symbol const & n, type_ref const & t) { return alloc(accessor_decl, n, t.get_sort()); } } -#endif + +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); + for (unsigned i = 0; i < num_accessors; ++i) { + c->add(acs[i]); + } + return c; +} + + + +// Remark: the datatype becomes the owner of the constructor_decls +datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, 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) {} + #endif /* DATATYPE_DECL_PLUGIN_H_ */ diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index ff1894a18..fbfcabd78 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -455,7 +455,7 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin st = BR_DONE; } } - if (is_numeral(arg2, a2) && is_neg_poly(arg1, new_arg1)) { + if (m_arith_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) { @@ -523,7 +523,7 @@ expr_ref arith_rewriter::neg_monomial(expr* e) const { } else { args.push_back(m_util.mk_numeral(rational(-1), m_util.is_int(e))); - args.append(to_app(e)->get_num_args(), to_app(e)->get_args()); + args.push_back(e); } } else { diff --git a/src/ast/rewriter/poly_rewriter.h b/src/ast/rewriter/poly_rewriter.h index c00464383..23743399e 100644 --- a/src/ast/rewriter/poly_rewriter.h +++ b/src/ast/rewriter/poly_rewriter.h @@ -36,6 +36,7 @@ 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); } diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index 8fda040b6..b52440393 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -18,7 +18,8 @@ Notes: --*/ #include "ast/rewriter/poly_rewriter.h" #include "ast/rewriter/poly_rewriter_params.hpp" -// include "ast/ast_lt.h" +#include "ast/rewriter/arith_rewriter_params.hpp" +#include "ast/ast_lt.h" #include "ast/ast_ll_pp.h" #include "ast/ast_smt2_pp.h" @@ -33,6 +34,8 @@ void poly_rewriter<Config>::updt_params(params_ref const & _p) { m_som_blowup = p.som_blowup(); if (!m_flat) m_som = false; if (m_som) m_hoist_mul = false; + arith_rewriter_params ap(_p); + m_ast_order = !ap.arith_ineq_lhs(); } template<typename Config> @@ -485,6 +488,8 @@ void poly_rewriter<Config>::hoist_cmul(expr_ref_buffer & args) { template<typename Config> bool poly_rewriter<Config>::mon_lt::operator()(expr* e1, expr * e2) const { + if (rw.m_ast_order) + return lt(e1,e2); return ordinal(e1) < ordinal(e2); } diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 034b067c7..a9ce0b69c 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -566,7 +566,8 @@ datatype_decl * pdatatype_decl::instantiate_decl(pdecl_manager & m, sort * const 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, cs.size(), cs.c_ptr()); } struct datatype_decl_buffer { @@ -679,9 +680,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; }; diff --git a/src/cmd_context/pdecl.h b/src/cmd_context/pdecl.h index 66e9cff53..e7fae8dd5 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; @@ -139,10 +140,10 @@ public: virtual void display(std::ostream & out) const; }; -class datatype_decl_plugin; -class datatype_decl; -class constructor_decl; -class accessor_decl; +//class datatype_decl_plugin; +//class datatype_decl; +//class constructor_decl; +//class accessor_decl; class pdatatypes_decl; class pdatatype_decl; diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index b9dbe83ca..9109f6b3c 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -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(), cnstrs.size(), cnstrs.c_ptr())); } @@ -1027,7 +1027,7 @@ namespace datalog { accs.push_back(mk_accessor_decl(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"), 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(); } diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index e8868c661..229cbe834 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); + datatype_decl * enum_sort = mk_datatype_decl(dtutil, symbol("RGB"), 3, constrs); VERIFY(dt.mk_datatypes(1, &enum_sort, 0, 0, new_sorts)); - del_constructor_decls(3, constrs); 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); From 93474c0263502e9c7575d9c53ade310fccb78bba Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Mon, 4 Sep 2017 09:43:25 -0700 Subject: [PATCH 55/74] aligning simplifier and rewriter for regression tests Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/api/python/z3/z3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 0b5f151be..1452a037e 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -3640,7 +3640,7 @@ def BitVecs(names, bv, ctx=None): >>> Product(x, y, z) 1*x*y*z >>> simplify(Product(x, y, z)) - z*x*y + x*y*z """ ctx = _get_ctx(ctx) if isinstance(names, str): @@ -7647,7 +7647,7 @@ def simplify(a, *arguments, **keywords): >>> simplify(x + 1 + y + x + 1) 2 + 2*x + y >>> simplify((x + 1)*(y + 1), som=True) - 1 + x + y + y*x + 1 + x + y + x*y >>> simplify(Distinct(x, y, 1), blast_distinct=True) And(Not(x == y), Not(x == 1), Not(y == 1)) >>> simplify(And(x == 0, y == 1), elim_and=True) From 5492d0e1355e0979eda801a3110224c6a040fdfc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Mon, 4 Sep 2017 11:03:57 -0700 Subject: [PATCH 56/74] re-introduce eq2ineq name for rewriting parameter Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/rewriter/arith_rewriter.cpp | 4 +-- src/ast/rewriter/arith_rewriter.h | 2 +- src/ast/rewriter/arith_rewriter_params.pyg | 2 +- src/cmd_context/pdecl.cpp | 25 ----------------- src/muz/pdr/pdr_context.cpp | 6 ++-- src/smt/asserted_formulas.cpp | 2 +- src/smt/params/theory_arith_params.cpp | 4 +-- src/smt/params/theory_arith_params.h | 4 +-- src/smt/smt_setup.cpp | 32 +++++++++++----------- 9 files changed, 28 insertions(+), 53 deletions(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index fbfcabd78..275290665 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -35,7 +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_expand_eqs = p.expand_eqs(); + m_eq2ineq = p.eq2ineq(); set_sort_sums(p.sort_sums()); } @@ -501,7 +501,7 @@ bool arith_rewriter::is_arith_term(expr * n) const { } br_status arith_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) { - if (m_expand_eqs) { + if (m_eq2ineq) { result = m().mk_and(m_util.mk_le(arg1, arg2), m_util.mk_ge(arg1, arg2)); return BR_REWRITE2; } diff --git a/src/ast/rewriter/arith_rewriter.h b/src/ast/rewriter/arith_rewriter.h index af9d0e09d..1bef9a964 100644 --- a/src/ast/rewriter/arith_rewriter.h +++ b/src/ast/rewriter/arith_rewriter.h @@ -55,7 +55,7 @@ class arith_rewriter : public poly_rewriter<arith_rewriter_core> { bool m_push_to_real; bool m_anum_simp; bool m_elim_rem; - bool m_expand_eqs; + bool m_eq2ineq; bool m_process_all_eqs; unsigned m_max_degree; diff --git a/src/ast/rewriter/arith_rewriter_params.pyg b/src/ast/rewriter/arith_rewriter_params.pyg index d40f46917..c7374105a 100644 --- a/src/ast/rewriter/arith_rewriter_params.pyg +++ b/src/ast/rewriter/arith_rewriter_params.pyg @@ -12,5 +12,5 @@ def_module_params(module_name='rewriter', ("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 +."), - ("expand_eqs", BOOL, False, "expand equalities into two inequalities"), + ("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/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index a9ce0b69c..04456c076 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -292,27 +292,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) { @@ -859,10 +838,6 @@ psort_decl * pdecl_manager::mk_psort_user_decl(unsigned num_params, symbol const } -//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); } 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/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index f37cabde8..1581e70bd 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -123,7 +123,7 @@ void asserted_formulas::set_eliminate_and(bool flag) { p.set_bool("arith_ineq_lhs", true); p.set_bool("sort_sums", true); p.set_bool("rewrite_patterns", true); - p.set_bool("expand_eqs", m_params.m_arith_expand_eqs); + p.set_bool("eq2ineq", m_params.m_arith_eq2ineq); p.set_bool("gcd_rounding", true); m_rewriter.updt_params(p); flush_cache(); diff --git a/src/smt/params/theory_arith_params.cpp b/src/smt/params/theory_arith_params.cpp index 9b8aa9b81..250848db4 100644 --- a/src/smt/params/theory_arith_params.cpp +++ b/src/smt/params/theory_arith_params.cpp @@ -38,14 +38,14 @@ void theory_arith_params::updt_params(params_ref const & _p) { m_arith_dump_lemmas = p.arith_dump_lemmas(); m_arith_reflect = p.arith_reflect(); arith_rewriter_params ap(_p); - m_arith_expand_eqs = ap.expand_eqs(); + 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_expand_eqs); + 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 diff --git a/src/smt/params/theory_arith_params.h b/src/smt/params/theory_arith_params.h index 89c4fe46c..1fe7e1163 100644 --- a/src/smt/params/theory_arith_params.h +++ b/src/smt/params/theory_arith_params.h @@ -49,7 +49,7 @@ enum arith_pivot_strategy { }; struct theory_arith_params { - bool m_arith_expand_eqs; + 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 @@ -110,7 +110,7 @@ struct theory_arith_params { theory_arith_params(params_ref const & p = params_ref()): - m_arith_expand_eqs(false), + m_arith_eq2ineq(false), m_arith_process_all_eqs(false), m_arith_mode(AS_ARITH), m_arith_auto_config_simplex(false), diff --git a/src/smt/smt_setup.cpp b/src/smt/smt_setup.cpp index f0c44a574..50b49f3b8 100644 --- a/src/smt/smt_setup.cpp +++ b/src/smt/smt_setup.cpp @@ -226,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; @@ -266,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; @@ -318,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; @@ -336,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; @@ -390,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; @@ -406,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; @@ -440,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; @@ -451,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; @@ -480,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; @@ -492,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; @@ -507,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. @@ -755,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)); @@ -770,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)); @@ -785,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 From 5d17e286672ee808702972cb6da60389bb80a720 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Mon, 4 Sep 2017 21:12:43 -0700 Subject: [PATCH 57/74] support for smtlib2.6 datatype parsing Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/api/api_datatype.cpp | 57 +++++----- src/ast/ast.cpp | 35 ++----- src/ast/ast_ll_pp.cpp | 2 +- src/ast/ast_smt2_pp.cpp | 2 +- src/ast/ast_smt_pp.cpp | 32 ++++-- src/ast/datatype_decl_plugin.cpp | 24 ++--- src/ast/datatype_decl_plugin.h | 14 +-- src/ast/datatype_decl_plugin2.cpp | 85 +++++++++------ src/ast/datatype_decl_plugin2.h | 31 +++--- src/ast/decl_collector.cpp | 4 +- src/ast/rewriter/datatype_rewriter.cpp | 4 +- src/ast/rewriter/enum2bv_rewriter.cpp | 2 +- src/cmd_context/cmd_context.cpp | 21 ++-- src/cmd_context/pdecl.cpp | 127 +++++++++++++++++++++-- src/cmd_context/pdecl.h | 29 ++++-- src/muz/base/dl_rule.h | 2 +- src/muz/base/rule_properties.cpp | 2 +- src/muz/bmc/dl_bmc_engine.cpp | 18 ++-- src/muz/pdr/pdr_prop_solver.cpp | 2 +- src/muz/spacer/spacer_util.cpp | 2 +- src/parsers/smt2/smt2parser.cpp | 27 ++++- src/qe/qe_datatype_plugin.cpp | 12 +-- src/qe/qe_datatypes.cpp | 6 +- src/qe/qe_lite.cpp | 2 +- src/smt/proto_model/datatype_factory.cpp | 6 +- src/smt/smt_value_sort.cpp | 2 +- src/smt/theory_datatype.cpp | 22 ++-- src/tactic/core/elim_uncnstr_tactic.cpp | 6 +- src/tactic/portfolio/enum2bv_solver.cpp | 2 +- 29 files changed, 374 insertions(+), 206 deletions(-) diff --git a/src/api/api_datatype.cpp b/src/api/api_datatype.cpp index d670888ed..d667a7428 100644 --- a/src/api/api_datatype.cpp +++ b/src/api/api_datatype.cpp @@ -45,13 +45,13 @@ extern "C" { ptr_vector<accessor_decl> acc; for (unsigned i = 0; i < num_fields; ++i) { - acc.push_back(mk_accessor_decl(to_symbol(field_names[i]), type_ref(to_sort(field_sorts[i])))); + acc.push_back(mk_accessor_decl(m, to_symbol(field_names[i]), type_ref(to_sort(field_sorts[i])))); } constructor_decl* constrs[1] = { mk_constructor_decl(to_symbol(name), recognizer, acc.size(), acc.c_ptr()) }; { - datatype_decl * dt = mk_datatype_decl(dt_util, 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,13 +69,13 @@ extern "C" { // create constructor SASSERT(dt_util.is_datatype(tuple)); SASSERT(!dt_util.is_recursive(tuple)); - ptr_vector<func_decl> const & decls = dt_util.get_datatype_constructors(tuple); + ptr_vector<func_decl> const & decls = *dt_util.get_datatype_constructors(tuple); func_decl* decl = (decls)[0]; mk_c(c)->save_multiple_ast_trail(decl); *mk_tuple_decl = of_func_decl(decl); // Create projections - ptr_vector<func_decl> const & _accs = dt_util.get_constructor_accessors(decl); + ptr_vector<func_decl> const & _accs = *dt_util.get_constructor_accessors(decl); SASSERT(_accs.size() == num_fields); for (unsigned i = 0; i < _accs.size(); i++) { mk_c(c)->save_multiple_ast_trail(_accs[i]); @@ -113,7 +113,7 @@ extern "C" { { - datatype_decl * dt = mk_datatype_decl(dt_util, 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); @@ -131,7 +131,7 @@ extern "C" { // create constructor SASSERT(dt_util.is_datatype(e)); SASSERT(!dt_util.is_recursive(e)); - ptr_vector<func_decl> const & decls = dt_util.get_datatype_constructors(e); + ptr_vector<func_decl> const & decls = *dt_util.get_datatype_constructors(e); SASSERT(decls.size() == n); for (unsigned i = 0; i < n; ++i) { func_decl* decl = (decls)[i]; @@ -164,8 +164,8 @@ extern "C" { 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), @@ -175,7 +175,7 @@ extern "C" { sort_ref_vector sorts(m); { - datatype_decl * decl = mk_datatype_decl(dt_util, 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); @@ -187,7 +187,7 @@ extern "C" { sort * s = sorts.get(0); mk_c(c)->save_multiple_ast_trail(s); - ptr_vector<func_decl> const& cnstrs = data_util.get_datatype_constructors(s); + ptr_vector<func_decl> const& cnstrs = *data_util.get_datatype_constructors(s); SASSERT(cnstrs.size() == 2); func_decl* f; if (nil_decl) { @@ -211,14 +211,14 @@ extern "C" { *is_cons_decl = of_func_decl(f); } if (head_decl) { - ptr_vector<func_decl> const& acc = data_util.get_constructor_accessors(cnstrs[1]); + ptr_vector<func_decl> const& acc = *data_util.get_constructor_accessors(cnstrs[1]); SASSERT(acc.size() == 2); f = (acc)[0]; mk_c(c)->save_multiple_ast_trail(f); *head_decl = of_func_decl(f); } if (tail_decl) { - ptr_vector<func_decl> const& acc = data_util.get_constructor_accessors(cnstrs[1]); + ptr_vector<func_decl> const& acc = *data_util.get_constructor_accessors(cnstrs[1]); SASSERT(acc.size() == 2); f = (acc)[1]; mk_c(c)->save_multiple_ast_trail(f); @@ -295,7 +295,7 @@ extern "C" { *tester = of_func_decl(f2); } - ptr_vector<func_decl> const& accs = data_util.get_constructor_accessors(f); + ptr_vector<func_decl> const& accs = *data_util.get_constructor_accessors(f); for (unsigned i = 0; i < num_fields; ++i) { func_decl* f2 = (accs)[i]; mk_c(c)->save_multiple_ast_trail(f2); @@ -318,21 +318,22 @@ extern "C" { unsigned num_constructors, Z3_constructor constructors[]) { datatype_util& dt_util = mk_c(c)->dtutil(); + ast_manager& m = mk_c(c)->m(); ptr_vector<constructor_decl> constrs; for (unsigned i = 0; i < num_constructors; ++i) { constructor* cn = reinterpret_cast<constructor*>(constructors[i]); ptr_vector<accessor_decl> acc; for (unsigned j = 0; j < cn->m_sorts.size(); ++j) { if (cn->m_sorts[j].get()) { - acc.push_back(mk_accessor_decl(cn->m_field_names[j], type_ref(cn->m_sorts[j].get()))); + acc.push_back(mk_accessor_decl(m, cn->m_field_names[j], type_ref(cn->m_sorts[j].get()))); } else { - acc.push_back(mk_accessor_decl(cn->m_field_names[j], type_ref(cn->m_sort_refs[j]))); + acc.push_back(mk_accessor_decl(m, cn->m_field_names[j], type_ref(cn->m_sort_refs[j]))); } } constrs.push_back(mk_constructor_decl(cn->m_name, cn->m_tester, acc.size(), acc.c_ptr())); } - return mk_datatype_decl(dt_util, 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, @@ -359,7 +360,7 @@ extern "C" { sort * s = sorts.get(0); mk_c(c)->save_ast_trail(s); - ptr_vector<func_decl> const& cnstrs = data_util.get_datatype_constructors(s); + ptr_vector<func_decl> const& cnstrs = *data_util.get_datatype_constructors(s); for (unsigned i = 0; i < num_constructors; ++i) { constructor* cn = reinterpret_cast<constructor*>(constructors[i]); @@ -408,7 +409,7 @@ extern "C" { ptr_vector<datatype_decl> datas; for (unsigned i = 0; i < num_sorts; ++i) { constructor_list* cl = reinterpret_cast<constructor_list*>(constructor_lists[i]); - datas.push_back(mk_datatype_decl(c,sort_names[i], cl->size(), reinterpret_cast<Z3_constructor*>(cl->c_ptr()))); + datas.push_back(mk_datatype_decl(c, sort_names[i], cl->size(), reinterpret_cast<Z3_constructor*>(cl->c_ptr()))); } sort_ref_vector _sorts(m); bool ok = mk_c(c)->get_dt_plugin()->mk_datatypes(datas.size(), datas.c_ptr(), 0, 0, _sorts); @@ -425,7 +426,7 @@ extern "C" { mk_c(c)->save_multiple_ast_trail(s); sorts[i] = of_sort(s); constructor_list* cl = reinterpret_cast<constructor_list*>(constructor_lists[i]); - ptr_vector<func_decl> const& cnstrs = data_util.get_datatype_constructors(s); + ptr_vector<func_decl> const& cnstrs = *data_util.get_datatype_constructors(s); for (unsigned j = 0; j < cl->size(); ++j) { constructor* cn = (*cl)[j]; cn->m_constructor = cnstrs[j]; @@ -447,7 +448,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - return dt_util.get_datatype_constructors(_t).size(); + return dt_util.get_datatype_constructors(_t)->size(); Z3_CATCH_RETURN(0); } @@ -460,7 +461,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - ptr_vector<func_decl> const & decls = dt_util.get_datatype_constructors(_t); + ptr_vector<func_decl> const & decls = *dt_util.get_datatype_constructors(_t); if (idx >= decls.size()) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; @@ -490,7 +491,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector<func_decl> const & decls = dt_util.get_datatype_constructors(_t); + ptr_vector<func_decl> const & decls = *dt_util.get_datatype_constructors(_t); if (idx >= decls.size()) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); @@ -513,7 +514,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector<func_decl> const & decls = dt_util.get_datatype_constructors(_t); + ptr_vector<func_decl> const & decls = *dt_util.get_datatype_constructors(_t); if (idx_c >= decls.size()) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; @@ -523,7 +524,7 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector<func_decl> const & accs = dt_util.get_constructor_accessors(decl); + ptr_vector<func_decl> const & accs = *dt_util.get_constructor_accessors(decl); SASSERT(accs.size() == decl->get_arity()); if (accs.size() <= idx_a) { SET_ERROR_CODE(Z3_INVALID_ARG); @@ -560,12 +561,12 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - ptr_vector<func_decl> const & decls = dt_util.get_datatype_constructors(tuple); + ptr_vector<func_decl> const & decls = *dt_util.get_datatype_constructors(tuple); if (decls.size() != 1) { SET_ERROR_CODE(Z3_INVALID_ARG); return 0; } - ptr_vector<func_decl> const & accs = dt_util.get_constructor_accessors(decls[0]); + ptr_vector<func_decl> const & accs = *dt_util.get_constructor_accessors(decls[0]); return accs.size(); Z3_CATCH_RETURN(0); } @@ -580,12 +581,12 @@ extern "C" { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector<func_decl> const & decls = dt_util.get_datatype_constructors(tuple); + ptr_vector<func_decl> const & decls = *dt_util.get_datatype_constructors(tuple); if (decls.size() != 1) { SET_ERROR_CODE(Z3_INVALID_ARG); RETURN_Z3(0); } - ptr_vector<func_decl> const & accs = dt_util.get_constructor_accessors((decls)[0]); + ptr_vector<func_decl> const & accs = *dt_util.get_constructor_accessors((decls)[0]); if (accs.size() <= i) { SET_ERROR_CODE(Z3_IOB); RETURN_Z3(0); diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 1a35e710a..a905efa28 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1287,10 +1287,8 @@ decl_kind user_sort_plugin::register_name(symbol s) { decl_plugin * user_sort_plugin::mk_fresh() { user_sort_plugin * p = alloc(user_sort_plugin); - svector<symbol>::iterator it = m_sort_names.begin(); - svector<symbol>::iterator end = m_sort_names.end(); - for (; it != end; ++it) - p->register_name(*it); + for (symbol const& s : m_sort_names) + p->register_name(s); return p; } @@ -1410,26 +1408,20 @@ ast_manager::~ast_manager() { dec_ref(m_true); dec_ref(m_false); dec_ref(m_undef_proof); - ptr_vector<decl_plugin>::iterator it = m_plugins.begin(); - ptr_vector<decl_plugin>::iterator end = m_plugins.end(); - for (; it != end; ++it) { - if (*it) - (*it)->finalize(); + for (decl_plugin* p : m_plugins) { + if (p) + p->finalize(); } - it = m_plugins.begin(); - for (; it != end; ++it) { - if (*it) - dealloc(*it); + for (decl_plugin* p : m_plugins) { + if (p) + dealloc(p); } m_plugins.reset(); while (!m_ast_table.empty()) { DEBUG_CODE(std::cout << "ast_manager LEAKED: " << m_ast_table.size() << std::endl;); ptr_vector<ast> roots; ast_mark mark; - ast_table::iterator it_a = m_ast_table.begin(); - ast_table::iterator end_a = m_ast_table.end(); - for (; it_a != end_a; ++it_a) { - ast* n = (*it_a); + for (ast * n : m_ast_table) { switch (n->get_kind()) { case AST_SORT: { sort_info* info = to_sort(n)->get_info(); @@ -1462,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); } @@ -1659,11 +1649,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"; diff --git a/src/ast/ast_ll_pp.cpp b/src/ast/ast_ll_pp.cpp index c00053780..6b14b75a8 100644 --- a/src/ast/ast_ll_pp.cpp +++ b/src/ast/ast_ll_pp.cpp @@ -284,7 +284,7 @@ public: } unsigned num_args = to_app(n)->get_num_args(); if (num_args > 0) - m_out << "("; + m_out << "(_ "; display_name(to_app(n)->get_decl()); display_params(to_app(n)->get_decl()); for (unsigned i = 0; i < num_args; i++) { diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index 51ccc1e7d..642983737 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -431,7 +431,7 @@ 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 +#ifdef DATATYPE_V2 if (get_dtutil().is_datatype(s)) { ptr_buffer<format> fs; unsigned sz = get_dtutil().get_datatype_num_parameter_sorts(s); diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 9211c5899..fdac6c7be 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -21,17 +21,17 @@ Revision History: #include<sstream> #include<iostream> +#include "util/vector.h" +#include "util/smt2_util.h" #include "ast/ast_smt_pp.h" #include "ast/arith_decl_plugin.h" #include "ast/bv_decl_plugin.h" #include "ast/array_decl_plugin.h" #include "ast/datatype_decl_plugin.h" +#include "ast/seq_decl_plugin.h" #include "ast/fpa_decl_plugin.h" -#include "util/vector.h" #include "ast/for_each_ast.h" #include "ast/decl_collector.h" -#include "util/smt2_util.h" -#include "ast/seq_decl_plugin.h" // --------------------------------------- // smt_renaming @@ -210,7 +210,19 @@ class smt_printer { void pp_decl(func_decl* d) { symbol sym = m_renaming.get_symbol(d->get_name()); if (d->get_family_id() == m_dt_fid) { +#ifdef DATATYPE_V2 + std::cout << "printing " << sym << "\n"; + datatype_util util(m_manager); + if (util.is_recognizer(d)) { + std::cout << d->get_num_parameters() << "\n"; + visit_params(false, sym, d->get_num_parameters(), d->get_parameters()); + } + else { + m_out << sym; + } +#else m_out << sym; +#endif } else if (m_manager.is_ite(d)) { if (!m_is_smt2 && is_bool(d->get_range())) { @@ -366,14 +378,15 @@ class smt_printer { return; } else if (s->is_sort_of(m_dt_fid, DATATYPE_SORT)) { +#ifndef DATATYPE_V2 m_out << m_renaming.get_symbol(s->get_name()); -#if 0 +#else 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 << " "; @@ -533,7 +546,8 @@ class smt_printer { pp_arg(curr, n); m_out << ")"; - } else if (m_manager.is_distinct(decl)) { + } + else if (m_manager.is_distinct(decl)) { ptr_vector<expr> args(num_args, n->get_args()); unsigned idx = 0; m_out << "(and"; @@ -915,7 +929,7 @@ public: // collect siblings and sorts that have not already been printed. for (unsigned h = 0; h < rec_sorts.size(); ++h) { s = rec_sorts[h]; - ptr_vector<func_decl> const& decls = util.get_datatype_constructors(s); + ptr_vector<func_decl> const& decls = *util.get_datatype_constructors(s); for (unsigned i = 0; i < decls.size(); ++i) { func_decl* f = decls[i]; @@ -954,11 +968,11 @@ public: m_out << "("; m_out << m_renaming.get_symbol(s->get_name()); m_out << " "; - ptr_vector<func_decl> const& decls = util.get_datatype_constructors(s); + ptr_vector<func_decl> const& decls = *util.get_datatype_constructors(s); for (unsigned i = 0; i < decls.size(); ++i) { func_decl* f = decls[i]; - ptr_vector<func_decl> const& accs = util.get_constructor_accessors(f); + ptr_vector<func_decl> const& accs = *util.get_constructor_accessors(f); if (m_is_smt2 || accs.size() > 0) { m_out << "("; } diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 1c090bc33..7ad80336d 100644 --- a/src/ast/datatype_decl_plugin.cpp +++ b/src/ast/datatype_decl_plugin.cpp @@ -34,7 +34,7 @@ public: type_ref const & get_type() const { return m_type; } }; -accessor_decl * mk_accessor_decl(symbol const & n, type_ref const & t) { +accessor_decl * mk_accessor_decl(ast_manager& m, symbol const & n, type_ref const & t) { return alloc(accessor_decl, n, t); } @@ -95,7 +95,7 @@ public: ptr_vector<constructor_decl> const & get_constructors() const { return m_constructors; } }; -datatype_decl * mk_datatype_decl(datatype_util&, symbol const & n, unsigned num_constructors, constructor_decl * const * cs) { +datatype_decl * mk_datatype_decl(datatype_util&, symbol const & n, unsigned num_params, sort * const* params, unsigned num_constructors, constructor_decl * const * cs) { return alloc(datatype_decl, n, num_constructors, cs); } @@ -803,11 +803,11 @@ func_decl * datatype_util::get_constructor(sort * ty, unsigned c_id) { return d; } -ptr_vector<func_decl> const & datatype_util::get_datatype_constructors(sort * ty) { +ptr_vector<func_decl> const * datatype_util::get_datatype_constructors(sort * ty) { SASSERT(is_datatype(ty)); ptr_vector<func_decl> * r = 0; if (m_datatype2constructors.find(ty, r)) - return *r; + return r; r = alloc(ptr_vector<func_decl>); m_asts.push_back(ty); m_vectors.push_back(r); @@ -820,7 +820,7 @@ ptr_vector<func_decl> const & datatype_util::get_datatype_constructors(sort * ty m_asts.push_back(c); r->push_back(c); } - return *r; + return r; } /** @@ -855,7 +855,7 @@ func_decl * datatype_util::get_non_rec_constructor_core(sort * ty, ptr_vector<so // 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<func_decl> const & constructors = get_datatype_constructors(ty); + ptr_vector<func_decl> const & constructors = *get_datatype_constructors(ty); // step 1) unsigned sz = constructors.size(); ++m_start; @@ -916,11 +916,11 @@ func_decl * datatype_util::get_constructor_recognizer(func_decl * constructor) { return d; } -ptr_vector<func_decl> const & datatype_util::get_constructor_accessors(func_decl * constructor) { +ptr_vector<func_decl> const * datatype_util::get_constructor_accessors(func_decl * constructor) { SASSERT(is_constructor(constructor)); ptr_vector<func_decl> * res = 0; if (m_constructor2accessors.find(constructor, res)) - return *res; + return res; res = alloc(ptr_vector<func_decl>); m_asts.push_back(constructor); m_vectors.push_back(res); @@ -939,7 +939,7 @@ ptr_vector<func_decl> const & datatype_util::get_constructor_accessors(func_decl m_asts.push_back(d); res->push_back(d); } - return *res; + return res; } func_decl * datatype_util::get_accessor_constructor(func_decl * accessor) { @@ -989,7 +989,7 @@ bool datatype_util::is_enum_sort(sort* s) { bool r = false; if (m_is_enum.find(s, r)) return r; - ptr_vector<func_decl> const& cnstrs = get_datatype_constructors(s); + ptr_vector<func_decl> const& cnstrs = *get_datatype_constructors(s); r = true; for (unsigned i = 0; r && i < cnstrs.size(); ++i) { r = cnstrs[i]->get_arity() == 0; @@ -1049,12 +1049,12 @@ void datatype_util::display_datatype(sort *s0, std::ostream& strm) { todo.pop_back(); strm << s->get_name() << " =\n"; - ptr_vector<func_decl> const & cnstrs = get_datatype_constructors(s); + ptr_vector<func_decl> 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<func_decl> const & accs = get_constructor_accessors(cns); + ptr_vector<func_decl> const & accs = *get_constructor_accessors(cns); for (unsigned j = 0; j < accs.size(); ++j) { func_decl* acc = accs[j]; sort* s1 = acc->get_range(); diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index e3e1b7b10..3b4c8dd08 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -16,7 +16,7 @@ Author: Revision History: --*/ -//define DATATYPE_V2 +// define DATATYPE_V2 #ifdef DATATYPE_V2 #include "ast/datatype_decl_plugin2.h" #else @@ -78,15 +78,11 @@ class constructor_decl; class datatype_decl; class datatype_util; -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); +accessor_decl * mk_accessor_decl(ast_manager& m, symbol const & n, type_ref const & t); // 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(datatype_util& u, symbol const & n, unsigned num_constructors, constructor_decl * const * cs); +datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_params, sort * const* params, unsigned num_constructors, constructor_decl * const * cs); void del_datatype_decl(datatype_decl * d); void del_datatype_decls(unsigned num, datatype_decl * const * ds); @@ -216,7 +212,7 @@ public: bool is_recognizer(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER); } bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); } bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); } - ptr_vector<func_decl> const & get_datatype_constructors(sort * ty); + ptr_vector<func_decl> const * get_datatype_constructors(sort * ty); unsigned get_datatype_num_constructors(sort * ty) { SASSERT(is_datatype(ty)); unsigned tid = ty->get_parameter(1).get_int(); @@ -236,7 +232,7 @@ public: unsigned get_recognizer_constructor_idx(func_decl * f) const { SASSERT(is_recognizer(f)); return f->get_parameter(1).get_int(); } func_decl * get_non_rec_constructor(sort * ty); func_decl * get_constructor_recognizer(func_decl * constructor); - ptr_vector<func_decl> const & get_constructor_accessors(func_decl * constructor); + ptr_vector<func_decl> const * get_constructor_accessors(func_decl * constructor); func_decl * get_accessor_constructor(func_decl * accessor); func_decl * get_recognizer_constructor(func_decl * recognizer); family_id get_family_id() const { return m_family_id; } diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp index c059907d5..41ae2e839 100644 --- a/src/ast/datatype_decl_plugin2.cpp +++ b/src/ast/datatype_decl_plugin2.cpp @@ -37,6 +37,7 @@ namespace datatype { 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)); @@ -79,13 +80,14 @@ namespace datatype { sort_ref s(m); if (!m_sort) { vector<parameter> 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(), sorts.c_ptr(), m_params.c_ptr()), m); + return sort_ref(m.substitute(m_sort, sorts.size(), m_params.c_ptr(), sorts.c_ptr()), m); } enum status { @@ -135,6 +137,7 @@ namespace datatype { 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); } @@ -146,9 +149,11 @@ namespace 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]; @@ -169,13 +174,17 @@ namespace datatype { def* d = 0; if (m_defs.find(s->get_name(), d) && d->sort_size()) { obj_map<sort, sort_size> S; - for (unsigned i = 1; i < num_parameters; ++i) { - sort* r = to_sort(parameters[i].get_ast()); + 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) { @@ -227,14 +236,12 @@ namespace datatype { 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"); func_decl * decl::plugin::mk_constructor(unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort * range) { ast_manager& m = *m_manager; - SASSERT(num_parameters == 1 && parameters[0].is_symbol() && range && u().is_datatype(range)); - if (num_parameters != 1 || !parameters[0].is_symbol() || !range || !u().is_datatype(range)) { - m_manager->raise_exception("invalid parameters for datatype constructor"); - } + 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); @@ -245,27 +252,27 @@ namespace datatype { func_decl * decl::plugin::mk_recognizer(unsigned num_parameters, parameter const * parameters, unsigned arity, sort * const * domain, sort *) { ast_manager& m = *m_manager; - SASSERT(arity == 1 && num_parameters == 1 && parameters[0].is_ast() && is_func_decl(parameters[0].get_ast())); - SASSERT(u().is_datatype(domain[0])); + 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* f = to_func_decl(parameters[0].get_ast()); func_decl_info info(m_family_id, OP_DT_RECOGNISER, num_parameters, parameters); info.m_private_parameters = true; - symbol name = to_func_decl(parameters[0].get_ast())->get_name(); - return m.mk_func_decl(name, arity, domain, range); + 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; - SASSERT(arity == 1 && num_parameters == 2 && parameters[0].is_symbol() && parameters[0].is_symbol()); - SASSERT(u().is_datatype(domain[0])); + 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); + 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, @@ -290,15 +297,20 @@ namespace datatype { return alloc(def, m, u(), name, m_class_id, n, params); } +#if 0 def& plugin::add(symbol const& name, unsigned n, sort * const * params) { ast_manager& m = *m_manager; def* d = 0; - if (m_defs.find(name, d)) dealloc(d); + if (m_defs.find(name, d)) { + TRACE("datatype", tout << "delete previous version for " << name << "\n";); + dealloc(d); + } d = alloc(def, m, u(), name, m_class_id, n, params); m_defs.insert(name, d); m_def_block.push_back(name); return *d; } +#endif void plugin::end_def_block() { ast_manager& m = *m_manager; @@ -325,7 +337,11 @@ namespace datatype { 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) { - if (m_defs.find(datatypes[i]->name(), d)) dealloc(d); + def* d = 0; + 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()); } @@ -391,6 +407,7 @@ namespace datatype { } void plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) { + op_names.push_back(builtin_name("is", OP_DT_RECOGNISER)); if (logic == symbol::null) { op_names.push_back(builtin_name("update-field", OP_DT_UPDATE_FIELD)); } @@ -548,6 +565,10 @@ namespace datatype { } 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<symbol> const& names) { map<symbol, status, symbol_hash_proc, symbol_eq_proc> already_found; @@ -668,17 +689,18 @@ namespace datatype { m_asts(m), m_start(0) { m_plugin = dynamic_cast<decl::plugin*>(m.get_plugin(m_family_id)); + SASSERT(m_plugin); } util::~util() { std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc<ptr_vector<func_decl> >()); } - ptr_vector<func_decl> const & util::get_datatype_constructors(sort * ty) { + ptr_vector<func_decl> const * util::get_datatype_constructors(sort * ty) { SASSERT(is_datatype(ty)); ptr_vector<func_decl> * r = 0; if (m_datatype2constructors.find(ty, r)) - return *r; + return r; r = alloc(ptr_vector<func_decl>); m_asts.push_back(ty); m_vectors.push_back(r); @@ -689,14 +711,15 @@ namespace datatype { m_asts.push_back(f); r->push_back(f); } - return *r; + return r; } - ptr_vector<func_decl> const & util::get_constructor_accessors(func_decl * con) { + ptr_vector<func_decl> const * util::get_constructor_accessors(func_decl * con) { SASSERT(is_constructor(con)); ptr_vector<func_decl> * res = 0; - if (m_constructor2accessors.find(con, res)) - return *res; + if (m_constructor2accessors.find(con, res)) { + return res; + } res = alloc(ptr_vector<func_decl>); m_asts.push_back(con); m_vectors.push_back(res); @@ -706,12 +729,14 @@ namespace datatype { for (constructor const* c : d) { if (c->name() == con->get_name()) { for (accessor const* a : *c) { - res->push_back(a->instantiate(datatype)); + func_decl_ref fn = a->instantiate(datatype); + res->push_back(fn); + m_asts.push_back(fn); } break; } } - return *res; + return res; } func_decl * util::get_constructor_recognizer(func_decl * constructor) { @@ -752,7 +777,7 @@ namespace datatype { bool r = false; if (m_is_enum.find(s, r)) return r; - ptr_vector<func_decl> const& cnstrs = get_datatype_constructors(s); + ptr_vector<func_decl> const& cnstrs = *get_datatype_constructors(s); r = true; for (unsigned i = 0; r && i < cnstrs.size(); ++i) { r = cnstrs[i]->get_arity() == 0; @@ -833,7 +858,7 @@ namespace datatype { // 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<func_decl> const& constructors = get_datatype_constructors(ty); + ptr_vector<func_decl> const& constructors = *get_datatype_constructors(ty); // step 1) unsigned sz = constructors.size(); ++m_start; @@ -928,12 +953,12 @@ namespace datatype { todo.pop_back(); strm << s->get_name() << " =\n"; - ptr_vector<func_decl> const& cnstrs = get_datatype_constructors(s); + ptr_vector<func_decl> 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<func_decl> const & accs = get_constructor_accessors(cns); + ptr_vector<func_decl> const & accs = *get_constructor_accessors(cns); for (unsigned j = 0; j < accs.size(); ++j) { func_decl* acc = accs[j]; sort* s1 = acc->get_range(); @@ -949,9 +974,9 @@ namespace datatype { } } -datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_constructors, constructor_decl * const * cs) { +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, 0, 0); + datatype::def* d = p->mk(n, num_params, params); for (unsigned i = 0; i < num_constructors; ++i) { d->add(cs[i]); } diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h index c79939a5b..d7173b24a 100644 --- a/src/ast/datatype_decl_plugin2.h +++ b/src/ast/datatype_decl_plugin2.h @@ -50,19 +50,19 @@ namespace datatype { class accessor { - symbol m_name; - sort* m_range; + 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(symbol const& n, sort* range): + accessor(ast_manager& m, symbol const& n, sort* range): m_name(n), - m_range(range), + m_range(range, m), m_index(UINT_MAX) {} - accessor(symbol const& n, unsigned index): + accessor(ast_manager& m, symbol const& n, unsigned index): m_name(n), - m_range(0), + m_range(m), m_index(index) {} sort* range() const { return m_range; } @@ -262,8 +262,6 @@ namespace datatype { void end_def_block(); - def& add(symbol const& name, unsigned n, sort * const * params); - def* mk(symbol const& name, unsigned n, sort * const * params); void del(symbol const& d); @@ -272,7 +270,7 @@ namespace datatype { def const& get_def(sort* s) const { return *(m_defs[datatype_name(s)]); } def& get_def(symbol const& s) { return *(m_defs[s]); } - + bool is_declared(sort* s) const { return m_defs.contains(datatype_name(s)); } private: bool is_value_visit(expr * arg, ptr_buffer<app> & todo) const; @@ -337,6 +335,7 @@ namespace datatype { 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); @@ -348,13 +347,13 @@ namespace datatype { bool is_recognizer(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER); } bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); } bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); } - ptr_vector<func_decl> const & get_datatype_constructors(sort * ty); + ptr_vector<func_decl> const * get_datatype_constructors(sort * ty); unsigned get_datatype_num_constructors(sort * ty); unsigned get_datatype_num_parameter_sorts(sort * ty); sort* get_datatype_parameter_sort(sort * ty, unsigned idx); func_decl * get_non_rec_constructor(sort * ty); func_decl * get_constructor_recognizer(func_decl * constructor); - ptr_vector<func_decl> const & get_constructor_accessors(func_decl * constructor); + ptr_vector<func_decl> const * get_constructor_accessors(func_decl * constructor); func_decl * get_accessor_constructor(func_decl * accessor); func_decl * get_recognizer_constructor(func_decl * recognizer) const; family_id get_family_id() const { return m_family_id; } @@ -362,11 +361,13 @@ namespace datatype { 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; } }; }; @@ -390,12 +391,12 @@ public: int get_idx() const { return UNBOXINT(m_data); } }; -inline accessor_decl * mk_accessor_decl(symbol const & n, type_ref const & t) { +inline accessor_decl * mk_accessor_decl(ast_manager& m, symbol const & n, type_ref const & t) { if (t.is_idx()) { - return alloc(accessor_decl, n, t.get_idx()); + return alloc(accessor_decl, m, n, t.get_idx()); } else { - return alloc(accessor_decl, n, t.get_sort()); + return alloc(accessor_decl, m, n, t.get_sort()); } } @@ -410,7 +411,7 @@ inline constructor_decl * mk_constructor_decl(symbol const & n, symbol const & r // Remark: the datatype becomes the owner of the constructor_decls -datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_constructors, constructor_decl * const * cs); +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) {} diff --git a/src/ast/decl_collector.cpp b/src/ast/decl_collector.cpp index bf509aba5..e000f43df 100644 --- a/src/ast/decl_collector.cpp +++ b/src/ast/decl_collector.cpp @@ -28,9 +28,9 @@ void decl_collector::visit_sort(sort * n) { unsigned num_cnstr = m_dt_util.get_datatype_num_constructors(n); for (unsigned i = 0; i < num_cnstr; i++) { - func_decl * cnstr = m_dt_util.get_datatype_constructors(n).get(i); + func_decl * cnstr = m_dt_util.get_datatype_constructors(n)->get(i); m_decls.push_back(cnstr); - ptr_vector<func_decl> const & cnstr_acc = m_dt_util.get_constructor_accessors(cnstr); + ptr_vector<func_decl> const & cnstr_acc = *m_dt_util.get_constructor_accessors(cnstr); unsigned num_cas = cnstr_acc.size(); for (unsigned j = 0; j < num_cas; j++) { func_decl * accsr = cnstr_acc.get(j); diff --git a/src/ast/rewriter/datatype_rewriter.cpp b/src/ast/rewriter/datatype_rewriter.cpp index 8746fab86..9efa61f70 100644 --- a/src/ast/rewriter/datatype_rewriter.cpp +++ b/src/ast/rewriter/datatype_rewriter.cpp @@ -47,7 +47,7 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr func_decl * c_decl = a->get_decl(); if (c_decl != m_util.get_accessor_constructor(f)) return BR_FAILED; - ptr_vector<func_decl> const & acc = m_util.get_constructor_accessors(c_decl); + ptr_vector<func_decl> const & acc = *m_util.get_constructor_accessors(c_decl); SASSERT(acc.size() == a->get_num_args()); unsigned num = acc.size(); for (unsigned i = 0; i < num; ++i) { @@ -70,7 +70,7 @@ br_status datatype_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr result = a; return BR_DONE; } - ptr_vector<func_decl> const & acc = m_util.get_constructor_accessors(c_decl); + ptr_vector<func_decl> const & acc = *m_util.get_constructor_accessors(c_decl); SASSERT(acc.size() == a->get_num_args()); unsigned num = acc.size(); ptr_buffer<expr> new_args; diff --git a/src/ast/rewriter/enum2bv_rewriter.cpp b/src/ast/rewriter/enum2bv_rewriter.cpp index b2ecbcc24..eb6b195f0 100644 --- a/src/ast/rewriter/enum2bv_rewriter.cpp +++ b/src/ast/rewriter/enum2bv_rewriter.cpp @@ -130,7 +130,7 @@ struct enum2bv_rewriter::imp { m_imp.m_bounds.push_back(m_bv.mk_ule(result, m_bv.mk_numeral(nc-1, bv_size))); } expr_ref f_def(m); - ptr_vector<func_decl> const& cs = m_dt.get_datatype_constructors(s); + ptr_vector<func_decl> const& cs = *m_dt.get_datatype_constructors(s); f_def = m.mk_const(cs[nc-1]); for (unsigned i = nc - 1; i > 0; ) { --i; diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 109fe1718..21f1cfe27 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -682,8 +682,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); @@ -719,6 +717,8 @@ void cmd_context::init_manager_core(bool new_manager) { } } } + 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. @@ -795,6 +795,7 @@ void cmd_context::insert(symbol const & s, func_decl * f) { dictionary<func_decls>::entry * e = m_func_decls.insert_if_not_there2(s, func_decls()); func_decls & fs = e->get_data().m_value; if (!fs.insert(m(), f)) { + UNREACHABLE(); std::string msg = "invalid declaration, "; msg += f->get_arity() == 0 ? "constant" : "function"; msg += " '"; @@ -1954,21 +1955,17 @@ 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<func_decl> 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[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); +#ifndef DATATYPE_V2 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<func_decl> 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[k]; - m_owner.insert(a); +#endif + 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 04456c076..4417061ec 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -170,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<psort_var const *>(other)->m_idx; + return + other->hcons_kind() == hcons_kind() && + get_num_params() == other->get_num_params() && + m_idx == static_cast<psort_var const *>(other)->m_idx; } virtual void display(std::ostream & out) const { out << "s_" << m_idx; @@ -344,6 +345,53 @@ 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) { +#ifndef DATATYPE_V2 + UNREACHABLE(); + return 0; +#else + SASSERT(n == m_num_params); + sort * r = find(s); + if (r) + return r; + buffer<parameter> ps; + ps.push_back(parameter(m_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()); + cache(m, s, r); + m.save_info(r, this, n, s); + if (m_num_params > 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, this); + } + } + return r; +#endif +} + +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), @@ -435,8 +483,8 @@ bool paccessor_decl::fix_missing_refs(dictionary<int> 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(); @@ -546,7 +594,7 @@ datatype_decl * pdatatype_decl::instantiate_decl(pdecl_manager & m, sort * const cs.push_back(c->instantiate_decl(m, s)); } datatype_util util(m.m()); - return mk_datatype_decl(util, m_name, cs.size(), cs.c_ptr()); + return mk_datatype_decl(util, m_name, m_num_params, s, cs.size(), cs.c_ptr()); } struct datatype_decl_buffer { @@ -554,6 +602,12 @@ struct datatype_decl_buffer { ~datatype_decl_buffer() { del_datatype_decls(m_buffer.size(), m_buffer.c_ptr()); } }; +#ifdef DATATYPE_V2 +sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { + UNREACHABLE(); + return 0; +} +#else sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { SASSERT(m_num_params == n); sort * r = find(s); @@ -583,6 +637,7 @@ sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * } return 0; } +#endif void pdatatype_decl::display(std::ostream & out) const { out << "(declare-datatype " << m_name; @@ -603,6 +658,27 @@ void pdatatype_decl::display(std::ostream & out) const { out << ")"; } +#ifdef DATATYPE_V2 +bool pdatatype_decl::commit(pdecl_manager& m) { + 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) { + if (m_num_params == 0) { + m.notify_new_dt(sorts.get(0), this); + } + } + return is_ok; +} +#endif + + pdatatypes_decl::pdatatypes_decl(unsigned id, unsigned num_params, pdecl_manager & m, unsigned num_datatypes, pdatatype_decl * const * dts): pdecl(id, num_params), @@ -631,6 +707,12 @@ bool pdatatypes_decl::fix_missing_refs(symbol & missing) { return true; } +#ifdef DATATYPE_V2 +bool pdatatypes_decl::instantiate(pdecl_manager & m, sort * const * s) { + UNREACHABLE(); + return false; +} +#else bool pdatatypes_decl::instantiate(pdecl_manager & m, sort * const * s) { datatype_decl_buffer dts; for (auto d : m_datatypes) { @@ -649,6 +731,31 @@ bool pdatatypes_decl::instantiate(pdecl_manager & m, sort * const * s) { } return true; } +#endif + +#ifdef DATATYPE_V2 +bool pdatatypes_decl::commit(pdecl_manager& m) { + datatype_decl_buffer dts; + 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(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 is_ok; +} +#endif struct pdecl_manager::sort_info { psort_decl * m_decl; @@ -790,9 +897,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) { @@ -837,6 +943,11 @@ 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) { + // std::cout << "insert dt-psort: " << n << " " << num_params << "\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); diff --git a/src/cmd_context/pdecl.h b/src/cmd_context/pdecl.h index e7fae8dd5..414415255 100644 --- a/src/cmd_context/pdecl.h +++ b/src/cmd_context/pdecl.h @@ -87,7 +87,7 @@ typedef ptr_hashtable<psort, psort_hash_proc, psort_eq_proc> 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: @@ -111,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 { @@ -125,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; @@ -140,10 +141,17 @@ public: virtual void display(std::ostream & out) const; }; -//class datatype_decl_plugin; -//class datatype_decl; -//class constructor_decl; -//class accessor_decl; +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 ~psort_dt_decl() {} +public: + virtual sort * instantiate(pdecl_manager & m, unsigned n, sort * const * s); + virtual void display(std::ostream & out) const; +}; + class pdatatypes_decl; class pdatatype_decl; @@ -233,6 +241,9 @@ public: virtual void display(std::ostream & out) const; bool has_missing_refs(symbol & missing) const; bool has_duplicate_accessors(symbol & repeated) const; +#ifdef DATATYPE_V2 + bool commit(pdecl_manager& m); +#endif }; /** @@ -250,6 +261,10 @@ class pdatatypes_decl : public pdecl { virtual ~pdatatypes_decl() {} public: pdatatype_decl const * const * children() const { return m_datatypes.c_ptr(); } +#ifdef DATATYPE_V2 + // commit declaration + bool commit(pdecl_manager& m); +#endif }; class new_datatype_eh { @@ -292,7 +307,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); diff --git a/src/muz/base/dl_rule.h b/src/muz/base/dl_rule.h index 51d673ba5..ea0e64e4f 100644 --- a/src/muz/base/dl_rule.h +++ b/src/muz/base/dl_rule.h @@ -65,7 +65,7 @@ namespace datalog { else if (m_dt.is_accessor(n)) { sort* s = m.get_sort(n->get_arg(0)); SASSERT(m_dt.is_datatype(s)); - if (m_dt.get_datatype_constructors(s).size() > 1) { + if (m_dt.get_datatype_constructors(s)->size() > 1) { m_found = true; m_func = n->get_decl(); } diff --git a/src/muz/base/rule_properties.cpp b/src/muz/base/rule_properties.cpp index 75487bbfb..21317a07c 100644 --- a/src/muz/base/rule_properties.cpp +++ b/src/muz/base/rule_properties.cpp @@ -191,7 +191,7 @@ void rule_properties::operator()(app* n) { else if (m_dt.is_accessor(n)) { sort* s = m.get_sort(n->get_arg(0)); SASSERT(m_dt.is_datatype(s)); - if (m_dt.get_datatype_constructors(s).size() > 1) { + if (m_dt.get_datatype_constructors(s)->size() > 1) { m_uninterp_funs.insert(n->get_decl(), m_rule); } } diff --git a/src/muz/bmc/dl_bmc_engine.cpp b/src/muz/bmc/dl_bmc_engine.cpp index 9109f6b3c..3368c7640 100644 --- a/src/muz/bmc/dl_bmc_engine.cpp +++ b/src/muz/bmc/dl_bmc_engine.cpp @@ -808,7 +808,7 @@ namespace datalog { datatype_util dtu(m); ptr_vector<sort> sorts; func_decl* p = r.get_decl(); - ptr_vector<func_decl> const& succs = dtu.get_datatype_constructors(m.get_sort(path)); + ptr_vector<func_decl> const& succs = *dtu.get_datatype_constructors(m.get_sort(path)); // populate substitution of bound variables. r.get_vars(m, sorts); sub.reset(); @@ -871,8 +871,8 @@ namespace datalog { path_var = m.mk_var(0, m_path_sort); trace_var = m.mk_var(1, pred_sort); // sort* sorts[2] = { pred_sort, m_path_sort }; - ptr_vector<func_decl> const& cnstrs = dtu.get_datatype_constructors(pred_sort); - ptr_vector<func_decl> const& succs = dtu.get_datatype_constructors(m_path_sort); + ptr_vector<func_decl> const& cnstrs = *dtu.get_datatype_constructors(pred_sort); + ptr_vector<func_decl> const& succs = *dtu.get_datatype_constructors(m_path_sort); SASSERT(cnstrs.size() == rls.size()); pred = m.mk_app(mk_predicate(p), trace_var.get(), path_var.get()); for (unsigned i = 0; i < rls.size(); ++i) { @@ -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(dtu, 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<accessor_decl> 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(dtu, 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(); } @@ -1039,8 +1039,8 @@ namespace datalog { sort* trace_sort = m.get_sort(trace); func_decl* p = m_sort2pred.find(trace_sort); datalog::rule_vector const& rules = b.m_rules.get_predicate_rules(p); - ptr_vector<func_decl> const& cnstrs = dtu.get_datatype_constructors(trace_sort); - ptr_vector<func_decl> const& succs = dtu.get_datatype_constructors(m_path_sort); + ptr_vector<func_decl> const& cnstrs = *dtu.get_datatype_constructors(trace_sort); + ptr_vector<func_decl> const& succs = *dtu.get_datatype_constructors(m_path_sort); for (unsigned i = 0; i < cnstrs.size(); ++i) { if (trace->get_decl() == cnstrs[i]) { svector<std::pair<unsigned, unsigned> > positions; diff --git a/src/muz/pdr/pdr_prop_solver.cpp b/src/muz/pdr/pdr_prop_solver.cpp index 1bca8e925..3055985f4 100644 --- a/src/muz/pdr/pdr_prop_solver.cpp +++ b/src/muz/pdr/pdr_prop_solver.cpp @@ -135,7 +135,7 @@ namespace pdr { func_decl* f = to_app(val)->get_decl(); func_decl* r = dt.get_constructor_recognizer(f); conjs[i] = m.mk_app(r, c); - ptr_vector<func_decl> const& acc = dt.get_constructor_accessors(f); + ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(f); for (unsigned j = 0; j < acc.size(); ++j) { conjs.push_back(m.mk_eq(apply_accessor(acc, j, f, c), to_app(val)->get_arg(j))); } diff --git a/src/muz/spacer/spacer_util.cpp b/src/muz/spacer/spacer_util.cpp index 14d8899c5..a277c9ed6 100644 --- a/src/muz/spacer/spacer_util.cpp +++ b/src/muz/spacer/spacer_util.cpp @@ -711,7 +711,7 @@ void expand_literals(ast_manager &m, expr_ref_vector& conjs) func_decl* f = to_app(val)->get_decl(); func_decl* r = dt.get_constructor_recognizer(f); conjs[i] = m.mk_app(r, c); - ptr_vector<func_decl> const& acc = dt.get_constructor_accessors(f); + ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(f); for (unsigned j = 0; j < acc.size(); ++j) { conjs.push_back(m.mk_eq(apply_accessor(m, acc, j, f, c), to_app(val)->get_arg(j))); } diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 3d895668b..9526429cb 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<sstream> @@ -885,6 +885,9 @@ namespace smt2 { } else if (sz == 1) { check_missing(new_dt_decls[0], line, pos); +#ifdef DATATYPE_V2 + new_dt_decls[0]->commit(pm()); +#endif } else { SASSERT(sz > 1); @@ -897,8 +900,13 @@ namespace smt2 { err_msg += "'"; throw parser_exception(err_msg, line, pos); } +#ifndef DATATYPE_V2 m_ctx.insert_aux_pdecl(dts.get()); +#else + dts->commit(pm()); +#endif } +#ifndef DATATYPE_V2 for (unsigned i = 0; i < sz; i++) { pdatatype_decl * d = new_dt_decls[i]; SASSERT(d != 0); @@ -911,6 +919,13 @@ namespace smt2 { s = d->instantiate(pm(), 0, 0); } } +#else + for (unsigned i = 0; i < sz; i++) { + pdatatype_decl * d = new_dt_decls[i]; + symbol duplicated; + check_duplicate(d, line, pos); + } +#endif 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";); m_ctx.print_success(); @@ -940,12 +955,16 @@ namespace smt2 { check_missing(d, line, pos); check_duplicate(d, line, pos); +#ifndef DATATYPE_V2 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); } +#else + d->commit(pm()); +#endif check_rparen_next("invalid end of datatype declaration, ')' expected"); m_ctx.print_success(); } @@ -1909,6 +1928,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/qe_datatype_plugin.cpp b/src/qe/qe_datatype_plugin.cpp index eff230ffe..c3525aa33 100644 --- a/src/qe/qe_datatype_plugin.cpp +++ b/src/qe/qe_datatype_plugin.cpp @@ -262,7 +262,7 @@ namespace qe { } func_decl* c = a->get_decl(); func_decl* r = m_util.get_constructor_recognizer(c); - ptr_vector<func_decl> const & acc = m_util.get_constructor_accessors(c); + ptr_vector<func_decl> const & acc = *m_util.get_constructor_accessors(c); SASSERT(acc.size() == a->get_num_args()); // // It suffices to solve just the first available equality. @@ -379,7 +379,7 @@ namespace qe { return false; } func_decl* c = l->get_decl(); - ptr_vector<func_decl> const& acc = m_util.get_constructor_accessors(c); + ptr_vector<func_decl> const& acc = *m_util.get_constructor_accessors(c); func_decl* rec = m_util.get_constructor_recognizer(c); expr_ref_vector conj(m); conj.push_back(m.mk_app(rec, r)); @@ -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/qe_datatypes.cpp b/src/qe/qe_datatypes.cpp index f16bdda59..db1e6ec85 100644 --- a/src/qe/qe_datatypes.cpp +++ b/src/qe/qe_datatypes.cpp @@ -75,7 +75,7 @@ namespace qe { app_ref arg(m); SASSERT(dt.is_constructor(m_val)); func_decl* f = m_val->get_decl(); - ptr_vector<func_decl> const& acc = dt.get_constructor_accessors(f); + ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(f); for (unsigned i = 0; i < acc.size(); ++i) { arg = m.mk_fresh_const(acc[i]->get_name().str().c_str(), acc[i]->get_range()); model.register_decl(arg->get_decl(), m_val->get_arg(i)); @@ -152,7 +152,7 @@ namespace qe { } func_decl* c = a->get_decl(); func_decl* rec = dt.get_constructor_recognizer(c); - ptr_vector<func_decl> const & acc = dt.get_constructor_accessors(c); + ptr_vector<func_decl> const & acc = *dt.get_constructor_accessors(c); SASSERT(acc.size() == a->get_num_args()); // // It suffices to solve just the first available equality. @@ -230,7 +230,7 @@ namespace qe { return false; } func_decl* c = to_app(l)->get_decl(); - ptr_vector<func_decl> const& acc = dt.get_constructor_accessors(c); + ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(c); if (!is_app_of(r, c)) { lits.push_back(m.mk_app(dt.get_constructor_recognizer(c), r)); } diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index 10af3be25..257331161 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -671,7 +671,7 @@ namespace eq { else { func_decl* rec = dt.get_constructor_recognizer(d); conjs.push_back(m.mk_app(rec, r)); - ptr_vector<func_decl> const& acc = dt.get_constructor_accessors(d); + ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(d); for (unsigned i = 0; i < acc.size(); ++i) { conjs.push_back(m.mk_eq(c->get_arg(i), m.mk_app(acc[i], r))); } diff --git a/src/smt/proto_model/datatype_factory.cpp b/src/smt/proto_model/datatype_factory.cpp index 653ef034a..03f008fe6 100644 --- a/src/smt/proto_model/datatype_factory.cpp +++ b/src/smt/proto_model/datatype_factory.cpp @@ -88,7 +88,7 @@ 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<func_decl> const & constructors = m_util.get_datatype_constructors(s); + ptr_vector<func_decl> const & constructors = *m_util.get_datatype_constructors(s); for (func_decl * constructor : constructors) { expr_ref_vector args(m_manager); bool found_fresh_arg = false; @@ -151,7 +151,7 @@ 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<func_decl> const & constructors = m_util.get_datatype_constructors(s); + ptr_vector<func_decl> const & constructors = *m_util.get_datatype_constructors(s); for (func_decl * constructor : constructors) { expr_ref_vector args(m_manager); bool found_fresh_arg = false; @@ -189,7 +189,7 @@ 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<func_decl> const & constructors = m_util.get_datatype_constructors(s); + ptr_vector<func_decl> const & constructors = *m_util.get_datatype_constructors(s); for (func_decl * constructor : constructors) { expr_ref_vector args(m_manager); bool found_sibling = false; diff --git a/src/smt/smt_value_sort.cpp b/src/smt/smt_value_sort.cpp index 3eeb3461d..56768b91a 100644 --- a/src/smt/smt_value_sort.cpp +++ b/src/smt/smt_value_sort.cpp @@ -52,7 +52,7 @@ namespace smt { // simple } else if (data.is_datatype(s)) { - ptr_vector<func_decl> const& cs = data.get_datatype_constructors(s); + ptr_vector<func_decl> const& cs = *data.get_datatype_constructors(s); for (unsigned i = 0; i < cs.size(); ++i) { func_decl* f = cs[i]; for (unsigned j = 0; j < f->get_arity(); ++j) { diff --git a/src/smt/theory_datatype.cpp b/src/smt/theory_datatype.cpp index 33b4b194d..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,7 +97,7 @@ namespace smt { SASSERT(m_util.is_datatype(get_manager().get_sort(n->get_owner()))); ast_manager & m = get_manager(); ptr_vector<expr> args; - ptr_vector<func_decl> const & accessors = m_util.get_constructor_accessors(c); + ptr_vector<func_decl> const & accessors = *m_util.get_constructor_accessors(c); SASSERT(c->get_arity() == accessors.size()); for (func_decl * d : accessors) { SASSERT(d->get_arity() == 1); @@ -120,7 +120,7 @@ namespace smt { SASSERT(is_constructor(n)); ast_manager & m = get_manager(); func_decl * d = n->get_decl(); - ptr_vector<func_decl> const & accessors = m_util.get_constructor_accessors(d); + ptr_vector<func_decl> const & accessors = *m_util.get_constructor_accessors(d); SASSERT(n->get_num_args() == accessors.size()); unsigned i = 0; for (func_decl * acc : accessors) { @@ -168,7 +168,7 @@ 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<func_decl> const & accessors = m_util.get_constructor_accessors(con); + ptr_vector<func_decl> 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)); @@ -208,7 +208,7 @@ namespace smt { ast_manager & m = get_manager(); sort * s = m.get_sort(n->get_owner()); if (m_util.get_datatype_num_constructors(s) == 1) { - func_decl * c = m_util.get_datatype_constructors(s)[0]; + func_decl * c = m_util.get_datatype_constructors(s)->get(0); assert_is_constructor_axiom(n, c, null_literal); } else { @@ -709,7 +709,7 @@ namespace smt { enode * r = d->m_recognizers[unassigned_idx]; literal consequent; if (!r) { - ptr_vector<func_decl> const & constructors = m_util.get_datatype_constructors(dt); + ptr_vector<func_decl> 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); @@ -774,7 +774,7 @@ namespace smt { for (unsigned idx = 0; it != end; ++it, ++idx) { enode * curr = *it; if (curr == 0) { - ptr_vector<func_decl> const & constructors = m_util.get_datatype_constructors(s); + ptr_vector<func_decl> const & constructors = *m_util.get_datatype_constructors(s); // found empty slot... r = m_util.get_constructor_recognizer(constructors[idx]); break; @@ -793,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/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index a13cd54d8..6a38f787e 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -174,7 +174,7 @@ 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<func_decl> const & constructors = m_dt_util.get_datatype_constructors(s); + ptr_vector<func_decl> const & constructors = *m_dt_util.get_datatype_constructors(s); for (func_decl * constructor : constructors) { unsigned num = constructor->get_arity(); unsigned target = UINT_MAX; @@ -704,7 +704,7 @@ class elim_uncnstr_tactic : public tactic { app * u; if (!mk_fresh_uncnstr_var_for(f, num, args, u)) return u; - ptr_vector<func_decl> const & accs = m_dt_util.get_constructor_accessors(c); + ptr_vector<func_decl> const & accs = *m_dt_util.get_constructor_accessors(c); ptr_buffer<expr> new_args; for (unsigned i = 0; i < accs.size(); i++) { if (accs[i] == f) @@ -723,7 +723,7 @@ class elim_uncnstr_tactic : public tactic { return u; if (!m_mc) return u; - ptr_vector<func_decl> const & accs = m_dt_util.get_constructor_accessors(f); + ptr_vector<func_decl> const & accs = *m_dt_util.get_constructor_accessors(f); for (unsigned i = 0; i < num; i++) { add_def(args[i], m().mk_app(accs[i], u)); } diff --git a/src/tactic/portfolio/enum2bv_solver.cpp b/src/tactic/portfolio/enum2bv_solver.cpp index db7cebd6e..36a178c41 100644 --- a/src/tactic/portfolio/enum2bv_solver.cpp +++ b/src/tactic/portfolio/enum2bv_solver.cpp @@ -136,7 +136,7 @@ public: if (m.is_eq(b, u, v) && is_uninterp_const(u) && m_rewriter.bv2enum().find(to_app(u)->get_decl(), f) && bv.is_numeral(v, num, bvsize)) { SASSERT(num.is_unsigned()); expr_ref head(m); - ptr_vector<func_decl> const& enums = dt.get_datatype_constructors(f->get_range()); + ptr_vector<func_decl> const& enums = *dt.get_datatype_constructors(f->get_range()); if (enums.size() > num.get_unsigned()) { head = m.mk_eq(m.mk_const(f), m.mk_const(enums[num.get_unsigned()])); consequences[i] = m.mk_implies(a, head); From aac7773a525b71fa6aab771163718ae9266d4835 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Mon, 4 Sep 2017 21:15:44 -0700 Subject: [PATCH 58/74] support for smtlib2.6 datatype parsing Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/cmd_context/cmd_context.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 21f1cfe27..e93e51186 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -795,7 +795,6 @@ void cmd_context::insert(symbol const & s, func_decl * f) { dictionary<func_decls>::entry * e = m_func_decls.insert_if_not_there2(s, func_decls()); func_decls & fs = e->get_data().m_value; if (!fs.insert(m(), f)) { - UNREACHABLE(); std::string msg = "invalid declaration, "; msg += f->get_arity() == 0 ? "constant" : "function"; msg += " '"; From 06087c17be591ce889927d07397e334e07ce8d79 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Tue, 5 Sep 2017 10:28:11 -0700 Subject: [PATCH 59/74] support for legacy datatype test Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/datatype_decl_plugin.h | 2 +- src/ast/datatype_decl_plugin2.cpp | 60 +++++++++++++++----------- src/ast/datatype_decl_plugin2.h | 21 ++++++--- src/ast/rewriter/datatype_rewriter.cpp | 1 + src/ast/rewriter/poly_rewriter_def.h | 4 -- src/ast/static_features.cpp | 13 +++--- src/cmd_context/basic_cmds.cpp | 42 ++++++++---------- src/cmd_context/cmd_context.cpp | 38 ++++++---------- src/cmd_context/pdecl.cpp | 2 +- src/cmd_context/tactic_cmds.cpp | 6 +-- src/smt/theory_dense_diff_logic_def.h | 5 ++- src/test/get_consequences.cpp | 4 +- 12 files changed, 100 insertions(+), 98 deletions(-) diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 3b4c8dd08..840329dda 100644 --- a/src/ast/datatype_decl_plugin.h +++ b/src/ast/datatype_decl_plugin.h @@ -16,7 +16,7 @@ Author: Revision History: --*/ -// define DATATYPE_V2 +#define DATATYPE_V2 #ifdef DATATYPE_V2 #include "ast/datatype_decl_plugin2.h" #else diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp index 41ae2e839..fa3c73bca 100644 --- a/src/ast/datatype_decl_plugin2.cpp +++ b/src/ast/datatype_decl_plugin2.cpp @@ -236,7 +236,7 @@ namespace datatype { 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"); +#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) { @@ -252,13 +252,26 @@ namespace datatype { 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 == 1 && parameters[0].is_ast() && is_func_decl(parameters[0].get_ast())); + 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* f = to_func_decl(parameters[0].get_ast()); 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* f = to_func_decl(parameters[0].get_ast()); + 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); } @@ -282,6 +295,8 @@ namespace datatype { 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: @@ -297,20 +312,6 @@ namespace datatype { return alloc(def, m, u(), name, m_class_id, n, params); } -#if 0 - def& plugin::add(symbol const& name, unsigned n, sort * const * params) { - ast_manager& m = *m_manager; - def* d = 0; - if (m_defs.find(name, d)) { - TRACE("datatype", tout << "delete previous version for " << name << "\n";); - dealloc(d); - } - d = alloc(def, m, u(), name, m_class_id, n, params); - m_defs.insert(name, d); - m_def_block.push_back(name); - return *d; - } -#endif void plugin::end_def_block() { ast_manager& m = *m_manager; @@ -407,7 +408,7 @@ namespace datatype { } void plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) { - op_names.push_back(builtin_name("is", OP_DT_RECOGNISER)); + 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)); } @@ -739,18 +740,25 @@ namespace datatype { return res; } - func_decl * util::get_constructor_recognizer(func_decl * constructor) { - SASSERT(is_constructor(constructor)); + func_decl * util::get_constructor_recognizer(func_decl * con) { + SASSERT(is_constructor(con)); func_decl * d = 0; - if (m_constructor2recognizer.find(constructor, d)) + if (m_constructor2recognizer.find(con, d)) return d; - sort * datatype = constructor->get_range(); - parameter ps[1] = { parameter(constructor) }; - d = m.mk_func_decl(m_family_id, OP_DT_RECOGNISER, 1, ps, 1, &datatype); + 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(constructor); + m_asts.push_back(con); m_asts.push_back(d); - m_constructor2recognizer.insert(constructor, d); + m_constructor2recognizer.insert(con, d); return d; } @@ -917,11 +925,11 @@ namespace datatype { UNREACHABLE(); return 0; } + unsigned util::get_recognizer_constructor_idx(func_decl * f) const { return get_constructor_idx(get_recognizer_constructor(f)); } - /** \brief Two datatype sorts s1 and s2 are siblings if they were defined together in the same mutually recursive definition. diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h index d7173b24a..f076bb43f 100644 --- a/src/ast/datatype_decl_plugin2.h +++ b/src/ast/datatype_decl_plugin2.h @@ -36,7 +36,8 @@ Revision History: 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 }; @@ -78,13 +79,15 @@ namespace datatype { class constructor { symbol m_name; + symbol m_recognizer; ptr_vector<accessor> m_accessors; def* m_def; public: - constructor(symbol n): m_name(n) {} + constructor(symbol n, symbol const& r): m_name(n), m_recognizer(r) {} ~constructor(); void add(accessor* a) { m_accessors.push_back(a); a->attach(this); } symbol const& name() const { return m_name; } + symbol const& recognizer() const { return m_recognizer; } ptr_vector<accessor> const& accessors() const { return m_accessors; } ptr_vector<accessor>::const_iterator begin() const { return m_accessors.begin(); } ptr_vector<accessor>::const_iterator end() const { return m_accessors.end(); } @@ -290,6 +293,10 @@ namespace datatype { 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(); @@ -340,11 +347,15 @@ namespace datatype { 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_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_recognizer(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER); } + bool is_recognizer0(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER);} + bool is_is(app * f) const { return is_app_of(f, m_family_id, OP_DT_IS);} + bool is_recognizer(app * f) const { return is_recognizer0(f) || is_is(f); } bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); } bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); } ptr_vector<func_decl> const * get_datatype_constructors(sort * ty); @@ -401,7 +412,7 @@ inline accessor_decl * mk_accessor_decl(ast_manager& m, symbol const & n, type_r } 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); + constructor_decl* c = alloc(constructor_decl, n, r); for (unsigned i = 0; i < num_accessors; ++i) { c->add(acs[i]); } diff --git a/src/ast/rewriter/datatype_rewriter.cpp b/src/ast/rewriter/datatype_rewriter.cpp index 9efa61f70..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 diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index b52440393..39c4a1078 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -753,18 +753,14 @@ br_status poly_rewriter<Config>::cancel_monomials(expr * lhs, expr * rhs, bool m normalize(c); - TRACE("mk_le_bug", tout << c << "\n";); - if (!has_multiple && num_coeffs <= 1) { if (move) { if (is_numeral(rhs)) { - TRACE("mk_le_bug", tout << "rhs is numeral\n";); return BR_FAILED; } } else { if (num_coeffs == 0 || is_numeral(rhs)) { - TRACE("mk_le_bug", tout << "rhs is numeral or no coeffs\n";); return BR_FAILED; } } 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<symbol> 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<named_cmd>::const_iterator it2 = cmds.begin(); - vector<named_cmd>::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<symbol>::const_iterator it = m_cmds.begin(); - svector<symbol>::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<macro_decls> const & macros = ctx.get_macros(); - dictionary<macro_decls>::iterator it = macros.begin(); - dictionary<macro_decls>::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<expr> core; ctx.get_check_sat_result()->get_unsat_core(core); ctx.regular_stream() << "("; - ptr_vector<expr>::const_iterator it = core.begin(); - ptr_vector<expr>::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 e93e51186..c0e1c9f9c 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -18,7 +18,10 @@ Notes: #include<signal.h> #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) @@ -1957,11 +1949,9 @@ void cmd_context::dt_eh::operator()(sort * dt, pdecl* pd) { 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); -#ifndef DATATYPE_V2 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";); -#endif 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); diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 4417061ec..9d6c5065e 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -267,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) { } diff --git a/src/cmd_context/tactic_cmds.cpp b/src/cmd_context/tactic_cmds.cpp index b5ad0707d..3eafc6bbd 100644 --- a/src/cmd_context/tactic_cmds.cpp +++ b/src/cmd_context/tactic_cmds.cpp @@ -255,11 +255,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<expr>::const_iterator it = core_elems.begin(); - ptr_vector<expr>::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/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<context, bool>(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/test/get_consequences.cpp b/src/test/get_consequences.cpp index 229cbe834..b9a54245e 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -65,12 +65,12 @@ 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(dtutil, symbol("RGB"), 3, constrs); + datatype_decl * enum_sort = mk_datatype_decl(dtutil, symbol("RGB"), 0, nullptr, 3, constrs); VERIFY(dt.mk_datatypes(1, &enum_sort, 0, 0, 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); - ptr_vector<func_decl> const& enums = dtutil.get_datatype_constructors(rgb); + ptr_vector<func_decl> const& enums = *dtutil.get_datatype_constructors(rgb); expr_ref r = expr_ref(m.mk_const(enums[0]), m); expr_ref g = expr_ref(m.mk_const(enums[1]), m); expr_ref b = expr_ref(m.mk_const(enums[2]), m); From 1f551f19f5ca16761d664b58d507d7776a7efaa1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Tue, 5 Sep 2017 16:37:07 -0700 Subject: [PATCH 60/74] remove extra token Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/datatype_decl_plugin2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h index f076bb43f..d9bfea4a5 100644 --- a/src/ast/datatype_decl_plugin2.h +++ b/src/ast/datatype_decl_plugin2.h @@ -429,4 +429,4 @@ inline void del_datatype_decls(unsigned num, datatype_decl * const * ds) {} #endif /* DATATYPE_DECL_PLUGIN_H_ */ -#endif DATATYPE_V2 +#endif /* DATATYPE_V2 */ From c708691a506bef18db13e1963b69fccbc420387d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Tue, 5 Sep 2017 17:24:29 -0700 Subject: [PATCH 61/74] merge Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/datatype_decl_plugin2.cpp | 9 +++++++++ src/ast/datatype_decl_plugin2.h | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp index bd7b41a88..a7d41dcbd 100644 --- a/src/ast/datatype_decl_plugin2.cpp +++ b/src/ast/datatype_decl_plugin2.cpp @@ -78,6 +78,7 @@ namespace datatype { 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<parameter> ps; ps.push_back(parameter(m_name)); @@ -315,6 +316,7 @@ namespace datatype { 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]; @@ -332,7 +334,12 @@ namespace datatype { if (!u().is_well_founded(sorts.size(), sorts.c_ptr())) { m_manager->raise_exception("datatype is not well-founded"); } + 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); + } } bool plugin::mk_datatypes(unsigned num_datatypes, def * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_sorts) { @@ -579,6 +586,8 @@ namespace datatype { 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; diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h index d9bfea4a5..a5db0dbc6 100644 --- a/src/ast/datatype_decl_plugin2.h +++ b/src/ast/datatype_decl_plugin2.h @@ -227,7 +227,7 @@ namespace datatype { 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(); } + void set_sort_size(param_size::size* p) { m_sort_size = p; p->inc_ref(); m_sort = 0; } }; namespace decl { From dabf88b95d9178ffcb7d88b9e04eec700fca7d02 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Tue, 5 Sep 2017 17:40:22 -0700 Subject: [PATCH 62/74] rename del to remove to avoid compiler error Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/datatype_decl_plugin2.cpp | 2 +- src/ast/datatype_decl_plugin2.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp index a7d41dcbd..74750d2ca 100644 --- a/src/ast/datatype_decl_plugin2.cpp +++ b/src/ast/datatype_decl_plugin2.cpp @@ -361,7 +361,7 @@ namespace datatype { return true; } - void plugin::del(symbol const& s) { + void plugin::remove(symbol const& s) { def* d = 0; if (m_defs.find(s, d)) dealloc(d); m_defs.remove(s); diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h index a5db0dbc6..3ea2ad1da 100644 --- a/src/ast/datatype_decl_plugin2.h +++ b/src/ast/datatype_decl_plugin2.h @@ -267,7 +267,7 @@ namespace datatype { def* mk(symbol const& name, unsigned n, sort * const * params); - void del(symbol const& d); + 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); From 9f5bd2feda960dbdd10977026478f3fcae792eb9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Tue, 5 Sep 2017 19:58:05 -0700 Subject: [PATCH 63/74] fix front-end for datatype Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/rewriter/arith_rewriter.cpp | 2 +- src/cmd_context/pdecl.cpp | 8 ++++---- src/parsers/smt2/smt2parser.cpp | 12 +++--------- src/test/get_consequences.cpp | 2 +- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp index 275290665..631e1d8f3 100644 --- a/src/ast/rewriter/arith_rewriter.cpp +++ b/src/ast/rewriter/arith_rewriter.cpp @@ -455,7 +455,7 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin st = BR_DONE; } } - if (m_arith_lhs && is_numeral(arg2, a2) && is_neg_poly(arg1, new_arg1)) { + 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) { diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 9d6c5065e..1887d677d 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -660,6 +660,7 @@ void pdatatype_decl::display(std::ostream & out) const { #ifdef DATATYPE_V2 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)); @@ -669,10 +670,8 @@ bool pdatatype_decl::commit(pdecl_manager& m) { 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) { - if (m_num_params == 0) { - m.notify_new_dt(sorts.get(0), this); - } + if (is_ok && m_num_params == 0) { + m.notify_new_dt(sorts.get(0), this); } return is_ok; } @@ -917,6 +916,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); } diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 9526429cb..8144ebc08 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -619,14 +619,7 @@ namespace smt2 { 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)); @@ -924,10 +917,11 @@ namespace smt2 { pdatatype_decl * d = new_dt_decls[i]; symbol duplicated; check_duplicate(d, line, pos); + m_ctx.insert(d); } #endif 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(); } diff --git a/src/test/get_consequences.cpp b/src/test/get_consequences.cpp index b9a54245e..6d600f594 100644 --- a/src/test/get_consequences.cpp +++ b/src/test/get_consequences.cpp @@ -66,7 +66,7 @@ void test2() { 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(dtutil, symbol("RGB"), 0, nullptr, 3, constrs); - VERIFY(dt.mk_datatypes(1, &enum_sort, 0, 0, new_sorts)); + 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); From d05d3bac4f8e57fc9168af1a80d93221cfad9bfa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Tue, 5 Sep 2017 20:12:48 -0700 Subject: [PATCH 64/74] fix instantiations Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/cmd_context/pdecl.cpp | 26 ++++++++++++++++++++++++-- src/parsers/smt2/smt2parser.cpp | 5 ++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 1887d677d..2293072a2 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -604,8 +604,30 @@ struct datatype_decl_buffer { #ifdef DATATYPE_V2 sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { - UNREACHABLE(); - return 0; + // TBD: copied + SASSERT(n == m_num_params); + sort * r = find(s); + if (r) + return r; + buffer<parameter> ps; + ps.push_back(parameter(m_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()); + cache(m, s, r); + m.save_info(r, this, n, s); + if (m_num_params > 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, this); + } + } + return r; } #else sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 8144ebc08..7bfc8bd99 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -917,7 +917,10 @@ namespace smt2 { pdatatype_decl * d = new_dt_decls[i]; symbol duplicated; check_duplicate(d, line, pos); - m_ctx.insert(d); + if (!is_smt2_6) { + // datatypes are inserted up front in SMT2.6 mode, so no need to re-insert them. + m_ctx.insert(d); + } } #endif TRACE("declare_datatypes", tout << "i: " << i << " new_dt_decls.size(): " << sz << "\n"; From fe02a5f87be30c3dda5c1c1dcf879081ff68602f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Wed, 6 Sep 2017 02:16:00 -0700 Subject: [PATCH 65/74] fix parse/print of ADTs Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/ast_smt_pp.cpp | 369 ++++++++++-------------------- src/ast/datatype_decl_plugin2.cpp | 33 ++- src/ast/datatype_decl_plugin2.h | 1 + src/smt/asserted_formulas.cpp | 3 +- 4 files changed, 153 insertions(+), 253 deletions(-) diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index fdac6c7be..1c3b4aeb2 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -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,12 +198,7 @@ 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) { @@ -225,23 +219,15 @@ class smt_printer { #endif } else if (m_manager.is_ite(d)) { - if (!m_is_smt2 && is_bool(d->get_range())) { - m_out << "if_then_else"; - } - else { - m_out << "ite"; - } + m_out << "ite"; } - else if (!m_is_smt2 && m_manager.is_implies(d)) { - m_out << "implies"; - } - 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 { @@ -263,28 +249,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()) { @@ -305,20 +286,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 { @@ -327,9 +298,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)) { @@ -341,42 +310,9 @@ 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)) { #ifndef DATATYPE_V2 m_out << m_renaming.get_symbol(s->get_name()); @@ -416,20 +352,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) { @@ -444,12 +367,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 << ")"; } @@ -471,12 +389,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 " << @@ -486,37 +399,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()) { @@ -595,14 +488,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; } @@ -616,9 +506,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 << "("; @@ -627,15 +515,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()); } @@ -654,28 +540,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 << ")"; @@ -739,21 +615,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(); } @@ -865,7 +731,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(); @@ -919,8 +784,63 @@ public: } void pp_dt(ast_mark& mark, sort* s) { - SASSERT(s->is_sort_of(m_dt_fid, DATATYPE_SORT)); datatype_util util(m_manager); + SASSERT(util.is_datatype(s)); + +#ifdef DATATYPE_V2 + + sort_ref_vector ps(m_manager); + ptr_vector<datatype::def> defs; + util.get_defs(s, defs); + + 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 << ")"; + } + m_out << "("; + m_out << m_renaming.get_symbol(d->name()); + m_out << " "; + 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 << ")"; + } + m_out << ")"; + } + if (!d->params().empty()) { + m_out << ")"; + } + m_out << ")"; + } + m_out << "))"; +#else + ptr_vector<sort> rec_sorts; rec_sorts.push_back(s); @@ -954,55 +874,30 @@ public: } } - 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 << "(declare-datatypes () ("; + bool first_sort = true; + for (sort * s : rec_sorts) { + if (!first_sort) m_out << " "; else first_sort = false; + m_out << "("; m_out << m_renaming.get_symbol(s->get_name()); m_out << " "; - ptr_vector<func_decl> const& decls = *util.get_datatype_constructors(s); - - for (unsigned i = 0; i < decls.size(); ++i) { - func_decl* f = decls[i]; - ptr_vector<func_decl> const& accs = *util.get_constructor_accessors(f); - if (m_is_smt2 || accs.size() > 0) { - m_out << "("; - } + bool first_constr = true; + for (func_decl* f : *util.get_datatype_constructors(s)) { + if (!first_constr) m_out << " "; else first_constr = false; + 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()) << " "; + for (func_decl* a : *util.get_constructor_accessors(f)) { + m_out << " (" << m_renaming.get_symbol(a->get_name()) << " "; visit_sort(a->get_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 << ")"; } m_out << ")"; - if (si + 1 < rec_sorts.size()) { - m_out << " "; - } } - if (m_is_smt2) { - m_out << ")"; - } - m_out << ")"; + m_out << "))"; +#endif newline(); } @@ -1015,12 +910,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(); @@ -1034,29 +924,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/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp index 74750d2ca..b53a2743f 100644 --- a/src/ast/datatype_decl_plugin2.cpp +++ b/src/ast/datatype_decl_plugin2.cpp @@ -965,35 +965,56 @@ namespace datatype { return d.constructors().size(); } + void util::get_defs(sort* s0, ptr_vector<def>& defs) { + svector<symbol> mark; + ptr_buffer<sort> 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); + } + } + } + } + } - void util::display_datatype(sort *s0, std::ostream& strm) { + void util::display_datatype(sort *s0, std::ostream& out) { ast_mark mark; ptr_buffer<sort> todo; SASSERT(is_datatype(s0)); - strm << s0->get_name() << " where\n"; + out << 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"; + out << s->get_name() << " =\n"; ptr_vector<func_decl> 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() << " :: "; + out << " " << cns->get_name() << " :: " << rec->get_name() << " :: "; ptr_vector<func_decl> 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() << ") "; + 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); } } - strm << "\n"; + out << "\n"; } } } diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h index 3ea2ad1da..d9a069de3 100644 --- a/src/ast/datatype_decl_plugin2.h +++ b/src/ast/datatype_decl_plugin2.h @@ -379,6 +379,7 @@ namespace datatype { unsigned get_constructor_idx(func_decl * f) const; unsigned get_recognizer_constructor_idx(func_decl * f) const; decl::plugin* get_plugin() { return m_plugin; } + void get_defs(sort* s, ptr_vector<def>& defs); }; }; diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 1581e70bd..ebdda73a1 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -432,7 +432,8 @@ void asserted_formulas::propagate_values() { flush_cache(); unsigned num_prop = 0; - while (!inconsistent()) { + unsigned num_iterations = 0; + while (!inconsistent() && ++num_iterations < 2) { m_expr2depth.reset(); m_scoped_substitution.push(); unsigned prop = num_prop; From f40a66c095b97c7b4ec607e3e1b1f8e81b277821 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Wed, 6 Sep 2017 02:26:19 -0700 Subject: [PATCH 66/74] fixes Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/ast_smt2_pp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index cdc771f12..63c7de1a9 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -43,6 +43,9 @@ format * smt2_pp_environment::pp_fdecl_name(symbol const & s, unsigned & len) co len = static_cast<unsigned>(str.length()); return mk_string(m, str.c_str()); } + else if (!s.bare_str()) { + return mk_string(m,"null"); + } else { len = static_cast<unsigned>(strlen(s.bare_str())); return mk_string(m, s.bare_str()); From 7f127cdd5dfc2a21433e64e19a5e91ab344648c4 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Wed, 6 Sep 2017 09:48:10 -0700 Subject: [PATCH 67/74] adding declarations for regression tests Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/datatype_decl_plugin2.cpp | 1 + src/ast/datatype_decl_plugin2.h | 2 +- src/cmd_context/pdecl.cpp | 99 +++++++++++++++++-------------- src/cmd_context/pdecl.h | 3 + src/parsers/smt2/smt2parser.cpp | 1 + 5 files changed, 62 insertions(+), 44 deletions(-) diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp index b53a2743f..43164a436 100644 --- a/src/ast/datatype_decl_plugin2.cpp +++ b/src/ast/datatype_decl_plugin2.cpp @@ -346,6 +346,7 @@ namespace datatype { 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); diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h index d9a069de3..a88c7100e 100644 --- a/src/ast/datatype_decl_plugin2.h +++ b/src/ast/datatype_decl_plugin2.h @@ -334,7 +334,6 @@ namespace datatype { void compute_datatype_size_functions(svector<symbol> const& names); param_size::size* get_sort_size(sort_ref_vector const& params, sort* s); bool is_well_founded(unsigned num_types, sort* const* sorts); - def const& get_def(sort* s) const; def& get_def(symbol const& s) { return m_plugin->get_def(s); } void get_subsorts(sort* s, ptr_vector<sort>& sorts) const; @@ -380,6 +379,7 @@ namespace datatype { unsigned get_recognizer_constructor_idx(func_decl * f) const; decl::plugin* get_plugin() { return m_plugin; } void get_defs(sort* s, ptr_vector<def>& defs); + def const& get_def(sort* s) const; }; }; diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 2293072a2..95a6030f3 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -360,28 +360,7 @@ sort * psort_dt_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * return 0; #else SASSERT(n == m_num_params); - sort * r = find(s); - if (r) - return r; - buffer<parameter> ps; - ps.push_back(parameter(m_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()); - cache(m, s, r); - m.save_info(r, this, n, s); - if (m_num_params > 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, this); - } - } - return r; + return m.instantiate_datatype(this, m_name, n, s); #endif } @@ -603,32 +582,39 @@ struct datatype_decl_buffer { }; #ifdef DATATYPE_V2 + sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { - // TBD: copied - SASSERT(n == m_num_params); - sort * r = find(s); - if (r) - return r; - buffer<parameter> ps; - ps.push_back(parameter(m_name)); - for (unsigned i = 0; i < n; i++) - ps.push_back(parameter(s[i])); + sort * r = m.instantiate_datatype(this, m_name, n, s); datatype_util util(m.m()); - r = m.m().mk_sort(util.get_family_id(), DATATYPE_SORT, ps.size(), ps.c_ptr()); - cache(m, s, r); - m.save_info(r, this, n, s); - if (m_num_params > 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, this); + 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<sort> 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; + } + } + } + } } } return r; } + #else sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { SASSERT(m_num_params == n); @@ -729,6 +715,33 @@ bool pdatatypes_decl::fix_missing_refs(symbol & missing) { } #ifdef DATATYPE_V2 +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<parameter> 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; @@ -887,6 +900,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): @@ -966,7 +980,6 @@ psort_decl * pdecl_manager::mk_psort_user_decl(unsigned num_params, symbol const } psort_decl * pdecl_manager::mk_psort_dt_decl(unsigned num_params, symbol const & n) { - // std::cout << "insert dt-psort: " << n << " " << num_params << "\n"; return new (a().allocate(sizeof(psort_dt_decl))) psort_dt_decl(m_id_gen.mk(), num_params, *this, n); } diff --git a/src/cmd_context/pdecl.h b/src/cmd_context/pdecl.h index 414415255..bef723380 100644 --- a/src/cmd_context/pdecl.h +++ b/src/cmd_context/pdecl.h @@ -261,6 +261,8 @@ 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(); } #ifdef DATATYPE_V2 // commit declaration bool commit(pdecl_manager& m); @@ -316,6 +318,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/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index 7bfc8bd99..ab2eecb36 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -897,6 +897,7 @@ namespace smt2 { m_ctx.insert_aux_pdecl(dts.get()); #else dts->commit(pm()); + m_ctx.insert_aux_pdecl(dts.get()); #endif } #ifndef DATATYPE_V2 From 2ea9bfaa41652303b50ece8afc5a7af6908ddb08 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Wed, 6 Sep 2017 13:34:41 -0700 Subject: [PATCH 68/74] remove unstable sequence interpolant from doc test Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/api/python/z3/z3.py | 6 +-- src/ast/ast_ll_pp.cpp | 2 +- src/ast/rewriter/bool_rewriter.cpp | 76 +++++++----------------------- src/ast/rewriter/rewriter_def.h | 7 +-- src/ast/rewriter/th_rewriter.cpp | 1 + src/smt/asserted_formulas.cpp | 4 ++ src/smt/asserted_formulas.h | 1 + src/smt/tactic/smt_tactic.cpp | 1 + 8 files changed, 31 insertions(+), 67 deletions(-) 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/ast_ll_pp.cpp b/src/ast/ast_ll_pp.cpp index 6b14b75a8..c00053780 100644 --- a/src/ast/ast_ll_pp.cpp +++ b/src/ast/ast_ll_pp.cpp @@ -284,7 +284,7 @@ public: } unsigned num_args = to_app(n)->get_num_args(); if (num_args > 0) - m_out << "(_ "; + m_out << "("; display_name(to_app(n)->get_decl()); display_params(to_app(n)->get_decl()); for (unsigned i = 0; i < num_args; i++) { 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<app> todo; - todo.push_back(ite); - -#define VISIT(ARG) { \ - if (m.is_value(ARG)) { \ - if (ARG == val) \ - return false; \ - } \ - else if (m.is_ite(ARG)) { \ - if (!visited.is_marked(ARG)) { \ - visited.mark(ARG); \ - todo.push_back(to_app(ARG)); \ - } \ - } \ - else { \ - return false; \ - } \ - } - - while (!todo.empty()) { - app * ite = todo.back(); - todo.pop_back(); - SASSERT(m.is_ite(ite)); - expr * t = ite->get_arg(1); - expr * e = ite->get_arg(2); - VISIT(t); - VISIT(e); - } - - return true; -} -#endif br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { if (m().are_equal(lhs, rhs)) { @@ -697,26 +659,20 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) { } br_status r = BR_FAILED; + if (m().is_ite(lhs) && m().is_value(rhs)) { - // if (is_ite_value_tree_neq_value(m(), to_app(lhs), to_app(rhs))) { - // result = m().mk_false(); - // return BR_DONE; - // } r = try_ite_value(to_app(lhs), to_app(rhs), result); CTRACE("try_ite_value", r != BR_FAILED, - tout << mk_ismt2_pp(lhs, m()) << "\n" << mk_ismt2_pp(rhs, m()) << "\n--->\n" << mk_ismt2_pp(result, m()) << "\n";); + tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";); } else if (m().is_ite(rhs) && m().is_value(lhs)) { - // if (is_ite_value_tree_neq_value(m(), to_app(rhs), to_app(lhs))) { - // result = m().mk_false(); - // return BR_DONE; - // } r = try_ite_value(to_app(rhs), to_app(lhs), result); CTRACE("try_ite_value", r != BR_FAILED, - tout << mk_ismt2_pp(lhs, m()) << "\n" << mk_ismt2_pp(rhs, m()) << "\n--->\n" << mk_ismt2_pp(result, m()) << "\n";); + tout << mk_bounded_pp(lhs, m()) << "\n" << mk_bounded_pp(rhs, m()) << "\n--->\n" << mk_bounded_pp(result, m()) << "\n";); } if (r != BR_FAILED) return r; + if (m().is_bool(lhs)) { bool unfolded = false; diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index c511f00d0..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<typename Config> template<bool ProofGen> @@ -259,10 +260,10 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) { } br_status st = m_cfg.reduce_app(f, new_num_args, new_args, m_r, m_pr2); SASSERT(st != BR_DONE || m().get_sort(m_r) == m().get_sort(t)); - TRACE("reduce_app", - tout << mk_ismt2_pp(t, m()) << "\n"; + CTRACE("reduce_app", st != BR_FAILED, + tout << mk_bounded_pp(t, m()) << "\n"; tout << "st: " << st; - if (m_r) tout << " --->\n" << mk_ismt2_pp(m_r, m()); + if (m_r) tout << " --->\n" << mk_bounded_pp(m_r, m()); tout << "\n";); if (st != BR_FAILED) { result_stack().shrink(fr.m_spos); diff --git a/src/ast/rewriter/th_rewriter.cpp b/src/ast/rewriter/th_rewriter.cpp index a2ca12b24..dd431bf85 100644 --- a/src/ast/rewriter/th_rewriter.cpp +++ b/src/ast/rewriter/th_rewriter.cpp @@ -736,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/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index ebdda73a1..c8670bd36 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -60,6 +60,7 @@ asserted_formulas::asserted_formulas(ast_manager & m, smt_params & p): m_macro_finder = alloc(macro_finder, m, m_macro_manager); + m_elim_and = true; set_eliminate_and(false); } @@ -118,7 +119,10 @@ void asserted_formulas::push_assertion(expr * e, proof * pr, vector<justified_ex } void asserted_formulas::set_eliminate_and(bool flag) { + 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); diff --git a/src/smt/asserted_formulas.h b/src/smt/asserted_formulas.h index d0db105d3..88c9e13a7 100644 --- a/src/smt/asserted_formulas.h +++ b/src/smt/asserted_formulas.h @@ -52,6 +52,7 @@ class asserted_formulas { static_features m_static_features; vector<justified_expr> m_formulas; unsigned m_qhead; + bool m_elim_and; macro_manager m_macro_manager; scoped_ptr<macro_finder> m_macro_finder; maximize_bv_sharing_rw m_bv_sharing; 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(); From 19fa5f8cb360a1aa6a80e04402eeffd00dbeb1ac Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Thu, 7 Sep 2017 06:23:01 -0700 Subject: [PATCH 69/74] expand select/store in pre-processor Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/smt/asserted_formulas.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index c8670bd36..c52ad851c 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -129,6 +129,7 @@ void asserted_formulas::set_eliminate_and(bool flag) { 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(); } From 0c9711aad7550f246d9596abf628e58089efa6eb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Fri, 8 Sep 2017 21:20:54 +0300 Subject: [PATCH 70/74] copy declarations Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/ast.cpp | 6 ++++ src/ast/ast.h | 4 +++ src/ast/ast_translation.cpp | 8 ++---- src/ast/datatype_decl_plugin2.cpp | 47 +++++++++++++++++++++++++++++++ src/ast/datatype_decl_plugin2.h | 6 ++++ src/smt/smt_solver.cpp | 18 +++++------- 6 files changed, 73 insertions(+), 16 deletions(-) diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index a905efa28..bb81c1eba 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -1529,12 +1529,15 @@ void ast_manager::raise_exception(char const * msg) { throw ast_exception(msg); } +#include "ast/ast_translation.h" + void ast_manager::copy_families_plugins(ast_manager const & from) { TRACE("copy_families_plugins", tout << "target:\n"; for (family_id fid = 0; m_family_manager.has_family(fid); fid++) { tout << "fid: " << fid << " fidname: " << get_family_name(fid) << "\n"; }); + ast_translation trans(const_cast<ast_manager&>(from), *this, false); for (family_id fid = 0; from.m_family_manager.has_family(fid); fid++) { SASSERT(from.is_builtin_family_id(fid) == is_builtin_family_id(fid)); SASSERT(!from.is_builtin_family_id(fid) || m_family_manager.has_family(fid)); @@ -1555,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)); diff --git a/src/ast/ast.h b/src/ast/ast.h index a1e31f46f..4eb43d30b 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -895,6 +895,8 @@ struct ast_eq_proc { } }; +class ast_translation; + class ast_table : public chashtable<ast*, obj_ptr_hash<ast>, ast_eq_proc> { public: void erase(ast * n); @@ -930,6 +932,8 @@ protected: m_family_id = id; } + virtual void inherit(decl_plugin* other_p, ast_translation& ) { } + friend class ast_manager; public: 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<ast, ast*>::iterator it = m_cache.begin(); - obj_map<ast, ast*>::iterator end = m_cache.end(); - for (; it != end; ++it) { - m_from_manager.dec_ref(it->m_key); - m_to_manager.dec_ref(it->m_value); + for (auto & kv : m_cache) { + m_from_manager.dec_ref(kv.m_key); + m_to_manager.dec_ref(kv.m_value); } m_cache.reset(); } diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp index 43164a436..0a002ed08 100644 --- a/src/ast/datatype_decl_plugin2.cpp +++ b/src/ast/datatype_decl_plugin2.cpp @@ -24,6 +24,7 @@ Revision History: #include "ast/datatype_decl_plugin2.h" #include "ast/array_decl_plugin.h" #include "ast/ast_smt2_pp.h" +#include "ast/ast_translation.h" namespace datatype { @@ -53,6 +54,9 @@ namespace datatype { 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); @@ -76,6 +80,15 @@ namespace datatype { 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";); @@ -91,6 +104,19 @@ namespace datatype { 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) { + 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) { + add(c->translate(tr)); + } + if (m_sort) result->m_sort = to_sort(tr(m_sort.get())); + return result; + } + enum status { GRAY, BLACK @@ -145,6 +171,27 @@ namespace datatype { return *(m_util.get()); } + static unsigned stack_depth = 0; + + void plugin::inherit(decl_plugin* other_p, ast_translation& tr) { + ++stack_depth; + SASSERT(stack_depth < 10); + plugin* p = dynamic_cast<plugin*>(other_p); + svector<symbol> names; + 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); + m_defs.insert(kv.m_key, d->translate(tr, u())); + } + } + m_class_id = m_defs.size(); + u().compute_datatype_size_functions(names); + --stack_depth; + } + + struct invalid_datatype {}; sort * plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h index a88c7100e..364ba9350 100644 --- a/src/ast/datatype_decl_plugin2.h +++ b/src/ast/datatype_decl_plugin2.h @@ -75,6 +75,7 @@ namespace datatype { constructor const& get_constructor() const { return *m_constructor; } def const& get_def() const; util& u() const; + accessor* translate(ast_translation& tr); }; class constructor { @@ -98,6 +99,7 @@ namespace datatype { 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 { @@ -228,6 +230,7 @@ namespace datatype { 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 { @@ -238,6 +241,9 @@ namespace datatype { svector<symbol> m_def_block; unsigned m_class_id; util & u() const; + + virtual void inherit(decl_plugin* other_p, ast_translation& tr); + public: plugin(): m_class_id(0) {} virtual ~plugin(); diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 9d86436d9..36272a139 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<expr, expr*>::iterator it = m_name2assertion.begin(); - obj_map<expr, expr*>::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; } @@ -264,7 +263,7 @@ namespace smt { } void compute_assrtn_fds(ptr_vector<expr> & core, vector<func_decl_set> & assrtn_fds) { - assrtn_fds.resize(m_name2assertion.size()); + assrtn_fds.resize(m_name2assertion.size()); obj_map<expr, expr*>::iterator ait = m_name2assertion.begin(); obj_map<expr, expr*>::iterator aend = m_name2assertion.end(); for (unsigned i = 0; ait != aend; ait++, i++) { @@ -277,10 +276,7 @@ namespace smt { } 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; } From ed6e23f153ec3b63efc75c0ef12a89d789b100c5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 9 Sep 2017 05:40:12 +0300 Subject: [PATCH 71/74] iterator -> for Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/smt/smt_solver.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 36272a139..65ba1ee24 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -264,14 +264,14 @@ namespace smt { void compute_assrtn_fds(ptr_vector<expr> & core, vector<func_decl_set> & assrtn_fds) { assrtn_fds.resize(m_name2assertion.size()); - obj_map<expr, expr*>::iterator ait = m_name2assertion.begin(); - obj_map<expr, expr*>::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); + 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; } } @@ -293,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); @@ -305,12 +304,12 @@ namespace smt { if (assrtn_fds.empty()) compute_assrtn_fds(core, assrtn_fds); - obj_map<expr, expr*>::iterator ait = m_name2assertion.begin(); - obj_map<expr, expr*>::iterator aend = m_name2assertion.end(); - for (unsigned i = 0; ait != aend; ait++, i++) { + unsigned i = 0; + for (auto & kv : m_name2assertion) { if (!core.contains(ait->m_key) && fds_intersect(pattern_fds, assrtn_fds[i])) new_core_literals.push_back(ait->m_key); + ++i; } } From 04e57e08ba93be87633f2dbf9bfe3a500ac51081 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sat, 9 Sep 2017 08:37:17 +0300 Subject: [PATCH 72/74] na Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/smt/smt_solver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index 65ba1ee24..e78c6388e 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -306,9 +306,9 @@ namespace smt { unsigned i = 0; for (auto & kv : m_name2assertion) { - if (!core.contains(ait->m_key) && + 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; } } From 4fe55cf8e5509f5ea409d2ef0dc3643e1db0d26c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 10 Sep 2017 14:48:57 +0300 Subject: [PATCH 73/74] fix plugin translation Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/datatype_decl_plugin2.cpp | 15 ++++++--------- src/parsers/smt2/smt2parser.cpp | 1 - 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp index 0a002ed08..743a08e98 100644 --- a/src/ast/datatype_decl_plugin2.cpp +++ b/src/ast/datatype_decl_plugin2.cpp @@ -105,13 +105,14 @@ namespace datatype { } 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) { - add(c->translate(tr)); + result->add(c->translate(tr)); } if (m_sort) result->m_sort = to_sort(tr(m_sort.get())); return result; @@ -171,24 +172,22 @@ namespace datatype { return *(m_util.get()); } - static unsigned stack_depth = 0; - void plugin::inherit(decl_plugin* other_p, ast_translation& tr) { - ++stack_depth; - SASSERT(stack_depth < 10); plugin* p = dynamic_cast<plugin*>(other_p); svector<symbol> names; + ptr_vector<def> 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); - m_defs.insert(kv.m_key, d->translate(tr, u())); + 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); - --stack_depth; } @@ -304,7 +303,6 @@ namespace datatype { VALIDATE_PARAM(u().is_datatype(domain[0])); // blindly trust that parameter is a constructor sort* range = m_manager->mk_bool_sort(); - func_decl* f = to_func_decl(parameters[0].get_ast()); 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); @@ -317,7 +315,6 @@ namespace datatype { VALIDATE_PARAM(u().is_datatype(domain[0])); // blindly trust that parameter is a constructor sort* range = m_manager->mk_bool_sort(); - func_decl* f = to_func_decl(parameters[0].get_ast()); 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); diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index ab2eecb36..a1304a848 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -617,7 +617,6 @@ 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) { unknown_sort(id); } From 070c699ffcfd2c1ffe10ac40825de13cdb195cd9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner <nbjorner@microsoft.com> Date: Sun, 10 Sep 2017 15:32:53 +0300 Subject: [PATCH 74/74] remove V2 reference Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> --- src/ast/CMakeLists.txt | 1 - src/ast/ast_smt2_pp.cpp | 2 - src/ast/ast_smt_pp.cpp | 71 - src/ast/datatype_decl_plugin.cpp | 2003 ++++++++++++++--------------- src/ast/datatype_decl_plugin.h | 582 ++++++--- src/ast/datatype_decl_plugin2.cpp | 1077 ---------------- src/ast/datatype_decl_plugin2.h | 439 ------- src/cmd_context/pdecl.cpp | 62 - src/cmd_context/pdecl.h | 4 - src/parsers/smt2/smt2parser.cpp | 32 +- 10 files changed, 1377 insertions(+), 2896 deletions(-) delete mode 100644 src/ast/datatype_decl_plugin2.cpp delete mode 100644 src/ast/datatype_decl_plugin2.h diff --git a/src/ast/CMakeLists.txt b/src/ast/CMakeLists.txt index 47ed2def8..0a14d9473 100644 --- a/src/ast/CMakeLists.txt +++ b/src/ast/CMakeLists.txt @@ -14,7 +14,6 @@ z3_add_component(ast ast_util.cpp bv_decl_plugin.cpp datatype_decl_plugin.cpp - datatype_decl_plugin2.cpp decl_collector.cpp dl_decl_plugin.cpp expr2polynomial.cpp diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index c69cafc71..abb4ae959 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -434,7 +434,6 @@ 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"); } -#ifdef DATATYPE_V2 if (get_dtutil().is_datatype(s)) { unsigned sz = get_dtutil().get_datatype_num_parameter_sorts(s); if (sz > 0) { @@ -445,7 +444,6 @@ format_ns::format * smt2_pp_environment::pp_sort(sort * s) { 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()); } diff --git a/src/ast/ast_smt_pp.cpp b/src/ast/ast_smt_pp.cpp index 1c3b4aeb2..906fd054b 100644 --- a/src/ast/ast_smt_pp.cpp +++ b/src/ast/ast_smt_pp.cpp @@ -204,19 +204,13 @@ class smt_printer { void pp_decl(func_decl* d) { symbol sym = m_renaming.get_symbol(d->get_name()); if (d->get_family_id() == m_dt_fid) { -#ifdef DATATYPE_V2 - std::cout << "printing " << sym << "\n"; datatype_util util(m_manager); if (util.is_recognizer(d)) { - std::cout << d->get_num_parameters() << "\n"; visit_params(false, sym, d->get_num_parameters(), d->get_parameters()); } else { m_out << sym; } -#else - m_out << sym; -#endif } else if (m_manager.is_ite(d)) { m_out << "ite"; @@ -314,9 +308,6 @@ class smt_printer { sym = "Array"; } else if (s->is_sort_of(m_dt_fid, DATATYPE_SORT)) { -#ifndef DATATYPE_V2 - m_out << m_renaming.get_symbol(s->get_name()); -#else datatype_util util(m_manager); unsigned num_sorts = util.get_datatype_num_parameter_sorts(s); if (num_sorts > 0) { @@ -330,7 +321,6 @@ class smt_printer { } m_out << ")"; } -#endif return; } else { @@ -787,8 +777,6 @@ public: datatype_util util(m_manager); SASSERT(util.is_datatype(s)); -#ifdef DATATYPE_V2 - sort_ref_vector ps(m_manager); ptr_vector<datatype::def> defs; util.get_defs(s, defs); @@ -839,65 +827,6 @@ public: m_out << ")"; } m_out << "))"; -#else - - ptr_vector<sort> rec_sorts; - - rec_sorts.push_back(s); - mark.mark(s, true); - - // collect siblings and sorts that have not already been printed. - for (unsigned h = 0; h < rec_sorts.size(); ++h) { - s = rec_sorts[h]; - ptr_vector<func_decl> const& 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); - } - } - } - } - } - - m_out << "(declare-datatypes () ("; - bool first_sort = true; - for (sort * s : rec_sorts) { - if (!first_sort) m_out << " "; else first_sort = false; - - m_out << "("; - m_out << m_renaming.get_symbol(s->get_name()); - m_out << " "; - bool first_constr = true; - for (func_decl* f : *util.get_datatype_constructors(s)) { - if (!first_constr) m_out << " "; else first_constr = false; - m_out << "("; - m_out << m_renaming.get_symbol(f->get_name()); - for (func_decl* a : *util.get_constructor_accessors(f)) { - m_out << " (" << m_renaming.get_symbol(a->get_name()) << " "; - visit_sort(a->get_range()); - m_out << ")"; - } - m_out << ")"; - } - m_out << ")"; - } - m_out << "))"; -#endif newline(); } diff --git a/src/ast/datatype_decl_plugin.cpp b/src/ast/datatype_decl_plugin.cpp index 1090b3ff1..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,321 +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" -#ifndef DATATYPE_V2 -/** - \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(ast_manager& m, 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<accessor_decl> 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<accessor_decl>()); - } - symbol const & get_name() const { return m_name; } - symbol const & get_recognizer_name() const { return m_recogniser_name; } - ptr_vector<accessor_decl> 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<constructor_decl> 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<constructor_decl>()); - } - symbol const & get_name() const { return m_name; } - ptr_vector<constructor_decl> const & get_constructors() const { return m_constructors; } -}; - -datatype_decl * mk_datatype_decl(datatype_util&, symbol const & n, unsigned num_params, sort * const* params, 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, false, 256> 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<status> already_found(num_types, WHITE); - buffer<unsigned> 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<parameter> 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<size>& 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<size>& 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<plugin*>(other_p); + svector<symbol> names; + ptr_vector<def> 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<sort, sort_size> 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<sort_size> szs(num_types, sort_size()); - buffer<status> already_found(num_types, WHITE); - buffer<unsigned> 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<app> & 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<app> 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<builtin_name> & 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<bool> 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<expr> 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<sort, status> already_found; + ptr_vector<sort> 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<sort, param_size::size*> 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<param_size::size> 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<symbol> const& names) { + map<symbol, status, symbol_hash_proc, symbol_eq_proc> already_found; + map<symbol, param_size::size*, symbol_hash_proc, symbol_eq_proc> szs; + + svector<symbol> 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<param_size::size> s_add; + for (constructor const* c : d) { + ptr_vector<param_size::size> 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<bool> well_founded(num_types, false); + obj_map<sort, unsigned> 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++; @@ -333,759 +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<bool, false, 256> 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<sort>& 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<decl::plugin*>(m.get_plugin(m_family_id)); + SASSERT(m_plugin); + } + + util::~util() { + std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc<ptr_vector<func_decl> >()); + } + + ptr_vector<func_decl> const * util::get_datatype_constructors(sort * ty) { + SASSERT(is_datatype(ty)); + ptr_vector<func_decl> * r = 0; + if (m_datatype2constructors.find(ty, r)) + return r; + r = alloc(ptr_vector<func_decl>); + 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<func_decl> const * util::get_constructor_accessors(func_decl * con) { + SASSERT(is_constructor(con)); + ptr_vector<func_decl> * res = 0; + if (m_constructor2accessors.find(con, res)) { + return res; + } + res = alloc(ptr_vector<func_decl>); + 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<unsigned>(source_datatype->get_parameter(1).get_int())) { - return source_datatype; - } - buffer<parameter> 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<func_decl> 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<ptr_vector<func_decl> >()); + 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<sort> 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<sort> & 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<func_decl> 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<parameter> 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<constructor_decl> 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<constructor_decl> 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<accessor_decl> 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<unsigned>(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<def>& defs) { + svector<symbol> mark; + ptr_buffer<sort> 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<expr> 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<sort> 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 * 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<app> & 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<app> 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<builtin_name> & 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<ptr_vector<func_decl> >()); -} - -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<sort> 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<func_decl> const * datatype_util::get_datatype_constructors(sort * ty) { - SASSERT(is_datatype(ty)); - ptr_vector<func_decl> * r = 0; - if (m_datatype2constructors.find(ty, r)) - return r; - r = alloc(ptr_vector<func_decl>); - 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<sort> 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<sort> & 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<func_decl> 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 && !is_datatype(c->get_domain(i)); i++) {}; - 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<func_decl> const * datatype_util::get_constructor_accessors(func_decl * constructor) { - SASSERT(is_constructor(constructor)); - ptr_vector<func_decl> * res = 0; - if (m_constructor2accessors.find(constructor, res)) - return res; - res = alloc(ptr_vector<func_decl>); - 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<func_decl> 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<ptr_vector<func_decl> >()); - 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<sort> 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<func_decl> 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<func_decl> 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<func_decl> 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<func_decl> 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); -} - - -#endif diff --git a/src/ast/datatype_decl_plugin.h b/src/ast/datatype_decl_plugin.h index 840329dda..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,55 +11,390 @@ Abstract: Author: - Leonardo de Moura (leonardo) 2008-01-09. + Nikolaj Bjorner (nbjorner) 2017-9-1 Revision History: ---*/ -#define DATATYPE_V2 -#ifdef DATATYPE_V2 -#include "ast/datatype_decl_plugin2.h" -#else + rewritten to support SMTLIB-2.6 parameters from + Leonardo de Moura (leonardo) 2008-01-09. +--*/ #ifndef DATATYPE_DECL_PLUGIN_H_ #define DATATYPE_DECL_PLUGIN_H_ - #include "ast/ast.h" -#include "util/tptr.h" #include "util/buffer.h" +#include "util/symbol_table.h" #include "util/obj_hashtable.h" -enum datatype_sort_kind { + +enum sort_kind { DATATYPE_SORT }; -enum datatype_op_kind { +enum op_kind { OP_DT_CONSTRUCTOR, OP_DT_RECOGNISER, - OP_DT_ACCESSOR, + OP_DT_IS, + OP_DT_ACCESSOR, OP_DT_UPDATE_FIELD, LAST_DT_OP }; -/** - \brief Auxiliary class used to declare inductive datatypes. - It may be a sort or an integer. If it is an integer, - then it represents a reference to a recursive type. +namespace datatype { - For example, consider the datatypes - Datatype - Tree = tree(value:Real, children:TreeList) - TreeList = cons_t(first_t:Tree, rest_t:Tree) - | nil_t - End - - The recursive occurrences of Tree and TreeList will have idx 0 and - 1 respectively. + class util; + class def; + class accessor; + class constructor; + + + class accessor { + symbol m_name; + sort_ref m_range; + unsigned m_index; // reference to recursive data-type may only get resolved after all mutually recursive data-types are procssed. + constructor* m_constructor; + public: + accessor(ast_manager& m, symbol const& n, sort* range): + m_name(n), + m_range(range, m), + m_index(UINT_MAX) + {} + accessor(ast_manager& m, symbol const& n, unsigned index): + m_name(n), + m_range(m), + m_index(index) + {} + sort* range() const { return m_range; } + void fix_range(sort_ref_vector const& dts); + symbol const& name() const { return m_name; } + func_decl_ref instantiate(sort_ref_vector const& ps) const; + func_decl_ref instantiate(sort* dt) const; + void attach(constructor* d) { m_constructor = d; } + constructor const& get_constructor() const { return *m_constructor; } + def const& get_def() const; + util& u() const; + accessor* translate(ast_translation& tr); + }; + + class constructor { + symbol m_name; + symbol m_recognizer; + ptr_vector<accessor> m_accessors; + def* m_def; + public: + constructor(symbol n, symbol const& r): m_name(n), m_recognizer(r) {} + ~constructor(); + void add(accessor* a) { m_accessors.push_back(a); a->attach(this); } + symbol const& name() const { return m_name; } + symbol const& recognizer() const { return m_recognizer; } + ptr_vector<accessor> const& accessors() const { return m_accessors; } + ptr_vector<accessor>::const_iterator begin() const { return m_accessors.begin(); } + ptr_vector<accessor>::const_iterator end() const { return m_accessors.end(); } + ptr_vector<accessor>::iterator begin() { return m_accessors.begin(); } + ptr_vector<accessor>::iterator end() { return m_accessors.end(); } + func_decl_ref instantiate(sort_ref_vector const& ps) const; + func_decl_ref instantiate(sort* dt) const; + void attach(def* d) { m_def = d; } + def const& get_def() const { return *m_def; } + util& u() const; + constructor* translate(ast_translation& tr); + }; + + namespace param_size { + class size { + unsigned m_ref; + public: + size(): m_ref(0) {} + virtual ~size() {} + void inc_ref() { ++m_ref; } + void dec_ref() { --m_ref; if (m_ref == 0) dealloc(this); } + static size* mk_offset(sort_size const& s); + static size* mk_param(sort_ref& p); + static size* mk_plus(size* a1, size* a2); + static size* mk_times(size* a1, size* a2); + static size* mk_plus(ptr_vector<size>& szs); + static size* mk_times(ptr_vector<size>& szs); + static size* mk_power(size* a1, size* a2); + + virtual size* subst(obj_map<sort, size*>& S) = 0; + virtual sort_size eval(obj_map<sort, sort_size> const& S) = 0; + + }; + struct offset : public size { + sort_size m_offset; + offset(sort_size const& s): m_offset(s) {} + virtual ~offset() {} + virtual size* subst(obj_map<sort,size*>& S) { return this; } + virtual sort_size eval(obj_map<sort, sort_size> const& S) { return m_offset; } + }; + struct plus : public size { + size* m_arg1, *m_arg2; + plus(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref();} + virtual ~plus() { m_arg1->dec_ref(); m_arg2->dec_ref(); } + virtual size* subst(obj_map<sort,size*>& S) { return mk_plus(m_arg1->subst(S), m_arg2->subst(S)); } + virtual sort_size eval(obj_map<sort, sort_size> const& S) { + sort_size s1 = m_arg1->eval(S); + sort_size s2 = m_arg2->eval(S); + if (s1.is_infinite()) return s1; + if (s2.is_infinite()) return s2; + if (s1.is_very_big()) return s1; + if (s2.is_very_big()) return s2; + rational r = rational(s1.size(), rational::ui64()) + rational(s2.size(), rational::ui64()); + return sort_size(r); + } + }; + struct times : public size { + size* m_arg1, *m_arg2; + times(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); } + virtual ~times() { m_arg1->dec_ref(); m_arg2->dec_ref(); } + virtual size* subst(obj_map<sort,size*>& S) { return mk_times(m_arg1->subst(S), m_arg2->subst(S)); } + virtual sort_size eval(obj_map<sort, sort_size> const& S) { + sort_size s1 = m_arg1->eval(S); + sort_size s2 = m_arg2->eval(S); + if (s1.is_infinite()) return s1; + if (s2.is_infinite()) return s2; + if (s1.is_very_big()) return s1; + if (s2.is_very_big()) return s2; + rational r = rational(s1.size(), rational::ui64()) * rational(s2.size(), rational::ui64()); + return sort_size(r); + } + }; + struct power : public size { + size* m_arg1, *m_arg2; + power(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); } + virtual ~power() { m_arg1->dec_ref(); m_arg2->dec_ref(); } + virtual size* subst(obj_map<sort,size*>& S) { return mk_power(m_arg1->subst(S), m_arg2->subst(S)); } + virtual sort_size eval(obj_map<sort, sort_size> const& S) { + sort_size s1 = m_arg1->eval(S); + sort_size s2 = m_arg2->eval(S); + // s1^s2 + if (s1.is_infinite()) return s1; + if (s2.is_infinite()) return s2; + if (s1.is_very_big()) return s1; + if (s2.is_very_big()) return s2; + if (s1.size() == 1) return s1; + if (s2.size() == 1) return s1; + if (s1.size() > (2 << 20) || s2.size() > 10) return sort_size::mk_very_big(); + rational r = ::power(rational(s1.size(), rational::ui64()), static_cast<unsigned>(s2.size())); + return sort_size(r); + } + }; + struct sparam : public size { + sort_ref m_param; + sparam(sort_ref& p): m_param(p) {} + virtual ~sparam() {} + virtual size* subst(obj_map<sort,size*>& S) { return S[m_param]; } + virtual sort_size eval(obj_map<sort, sort_size> const& S) { return S[m_param]; } + }; + }; + + class def { + ast_manager& m; + util& m_util; + symbol m_name; + unsigned m_class_id; + param_size::size* m_sort_size; + sort_ref_vector m_params; + mutable sort_ref m_sort; + ptr_vector<constructor> m_constructors; + public: + def(ast_manager& m, util& u, symbol const& n, unsigned class_id, unsigned num_params, sort * const* params): + m(m), + m_util(u), + m_name(n), + m_class_id(class_id), + m_sort_size(0), + m_params(m, num_params, params), + m_sort(m) + {} + ~def() { + if (m_sort_size) m_sort_size->dec_ref(); + for (constructor* c : m_constructors) dealloc(c); + m_constructors.reset(); + } + void add(constructor* c) { + m_constructors.push_back(c); + c->attach(this); + } + symbol const& name() const { return m_name; } + unsigned id() const { return m_class_id; } + sort_ref instantiate(sort_ref_vector const& ps) const; + ptr_vector<constructor> const& constructors() const { return m_constructors; } + ptr_vector<constructor>::const_iterator begin() const { return m_constructors.begin(); } + ptr_vector<constructor>::const_iterator end() const { return m_constructors.end(); } + ptr_vector<constructor>::iterator begin() { return m_constructors.begin(); } + ptr_vector<constructor>::iterator end() { return m_constructors.end(); } + sort_ref_vector const& params() const { return m_params; } + util& u() const { return m_util; } + param_size::size* sort_size() { return m_sort_size; } + void set_sort_size(param_size::size* p) { m_sort_size = p; p->inc_ref(); m_sort = 0; } + def* translate(ast_translation& tr, util& u); + }; + + namespace decl { + + class plugin : public decl_plugin { + mutable scoped_ptr<util> m_util; + map<symbol, def*, symbol_hash_proc, symbol_eq_proc> m_defs; + svector<symbol> m_def_block; + unsigned m_class_id; + util & u() const; + + virtual void inherit(decl_plugin* other_p, ast_translation& tr); + + public: + plugin(): m_class_id(0) {} + virtual ~plugin(); + + virtual void finalize(); + + virtual decl_plugin * mk_fresh() { return alloc(plugin); } + + virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); + + virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + virtual expr * get_some_value(sort * s); + + virtual bool is_fully_interp(sort * s) const; + + virtual bool is_value(app* e) const; + + virtual bool is_unique_value(app * e) const { return is_value(e); } + + virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic); + + void begin_def_block() { m_class_id++; m_def_block.reset(); } + + void end_def_block(); + + def* mk(symbol const& name, unsigned n, sort * const * params); + + void remove(symbol const& d); + + bool mk_datatypes(unsigned num_datatypes, def * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_sorts); + + def const& get_def(sort* s) const { return *(m_defs[datatype_name(s)]); } + def& get_def(symbol const& s) { return *(m_defs[s]); } + bool is_declared(sort* s) const { return m_defs.contains(datatype_name(s)); } + private: + bool is_value_visit(expr * arg, ptr_buffer<app> & todo) const; + + func_decl * mk_update_field( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + func_decl * mk_constructor( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + func_decl * mk_accessor( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + func_decl * mk_recognizer( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + func_decl * mk_is( + unsigned num_parameters, parameter const * parameters, + unsigned arity, sort * const * domain, sort * range); + + symbol datatype_name(sort * s) const { + //SASSERT(u().is_datatype(s)); + return s->get_parameter(0).get_symbol(); + } + + }; + } + + class util { + ast_manager & m; + family_id m_family_id; + mutable decl::plugin* m_plugin; + + + obj_map<sort, ptr_vector<func_decl> *> m_datatype2constructors; + obj_map<sort, func_decl *> m_datatype2nonrec_constructor; + obj_map<func_decl, ptr_vector<func_decl> *> m_constructor2accessors; + obj_map<func_decl, func_decl *> m_constructor2recognizer; + obj_map<func_decl, func_decl *> m_recognizer2constructor; + obj_map<func_decl, func_decl *> m_accessor2constructor; + obj_map<sort, bool> m_is_recursive; + obj_map<sort, bool> m_is_enum; + mutable obj_map<sort, bool> m_is_fully_interp; + mutable ast_ref_vector m_asts; + ptr_vector<ptr_vector<func_decl> > m_vectors; + unsigned m_start; + mutable ptr_vector<sort> m_fully_interp_trail; + + func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set); + + friend class decl::plugin; + + bool is_recursive_core(sort * s) const; + sort_size get_datatype_size(sort* s0); + void compute_datatype_size_functions(svector<symbol> const& names); + param_size::size* get_sort_size(sort_ref_vector const& params, sort* s); + bool is_well_founded(unsigned num_types, sort* const* sorts); + def& get_def(symbol const& s) { return m_plugin->get_def(s); } + void get_subsorts(sort* s, ptr_vector<sort>& sorts) const; + + public: + util(ast_manager & m); + ~util(); + ast_manager & get_manager() const { return m; } + // sort * mk_datatype_sort(symbol const& name, unsigned n, sort* const* params); + bool is_datatype(sort const* s) const { return is_sort_of(s, m_family_id, DATATYPE_SORT); } + bool is_enum_sort(sort* s); + bool is_recursive(sort * ty); + bool is_constructor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_CONSTRUCTOR); } + bool is_recognizer(func_decl * f) const { return is_recognizer0(f) || is_is(f); } + bool is_recognizer0(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_RECOGNISER); } + bool is_is(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_IS); } + bool is_accessor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_ACCESSOR); } + bool is_update_field(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_UPDATE_FIELD); } + bool is_constructor(app * f) const { return is_app_of(f, m_family_id, OP_DT_CONSTRUCTOR); } + bool is_recognizer0(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER);} + bool is_is(app * f) const { return is_app_of(f, m_family_id, OP_DT_IS);} + bool is_recognizer(app * f) const { return is_recognizer0(f) || is_is(f); } + bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); } + bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); } + ptr_vector<func_decl> const * get_datatype_constructors(sort * ty); + unsigned get_datatype_num_constructors(sort * ty); + unsigned get_datatype_num_parameter_sorts(sort * ty); + sort* get_datatype_parameter_sort(sort * ty, unsigned idx); + func_decl * get_non_rec_constructor(sort * ty); + func_decl * get_constructor_recognizer(func_decl * constructor); + ptr_vector<func_decl> const * get_constructor_accessors(func_decl * constructor); + func_decl * get_accessor_constructor(func_decl * accessor); + func_decl * get_recognizer_constructor(func_decl * recognizer) const; + family_id get_family_id() const { return m_family_id; } + bool are_siblings(sort * s1, sort * s2); + bool is_func_decl(op_kind k, unsigned num_params, parameter const* params, func_decl* f); + bool is_constructor_of(unsigned num_params, parameter const* params, func_decl* f); + void reset(); + bool is_declared(sort* s) const; + void display_datatype(sort *s, std::ostream& strm); + bool is_fully_interp(sort * s) const; + sort_ref_vector datatype_params(sort * s) const; + unsigned get_constructor_idx(func_decl * f) const; + unsigned get_recognizer_constructor_idx(func_decl * f) const; + decl::plugin* get_plugin() { return m_plugin; } + void get_defs(sort* s, ptr_vector<def>& defs); + def const& get_def(sort* s) const; + }; + +}; + +typedef datatype::accessor accessor_decl; +typedef datatype::constructor constructor_decl; +typedef datatype::def datatype_decl; +typedef datatype::decl::plugin datatype_decl_plugin; +typedef datatype::util datatype_util; - This is a transient value, it is only used to declare a set of - recursive datatypes. -*/ class type_ref { void * m_data; public: @@ -73,178 +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(ast_manager& m, symbol const & n, type_ref const & t); -// 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); // Remark: the datatype becomes the owner of the constructor_decls -datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_params, sort * const* params, unsigned num_constructors, constructor_decl * const * cs); -void del_datatype_decl(datatype_decl * d); -void del_datatype_decls(unsigned num, datatype_decl * const * ds); +datatype_decl * mk_datatype_decl(datatype_util& u, symbol const & n, unsigned num_params, sort*const* params, unsigned num_constructors, constructor_decl * const * cs); +inline void del_datatype_decl(datatype_decl * d) {} +inline void del_datatype_decls(unsigned num, datatype_decl * const * ds) {} -class datatype_decl_plugin : public decl_plugin { - mutable scoped_ptr<datatype_util> m_util; - datatype_util & get_util() const; -public: - datatype_decl_plugin() {} - - virtual ~datatype_decl_plugin(); - virtual void finalize(); - - virtual decl_plugin * mk_fresh() { return alloc(datatype_decl_plugin); } - - - /** - Contract for sort: - parameters[0] - (int) n - number of recursive types. - parameters[1] - (int) i - index 0..n-1 of which type is defined. - - parameters[2] - (int) p - number of type parameters. - - for j = 0..p-1 - parameters[3 + j] - (sort) s - type parameter - - c_offset := 3 + p - for j in 0..n-1 - parameters[c_offset + 2*j] - (symbol) name of the type - parameters[c_offset + 2*j + 1] - (int) o - offset where the constructors are defined. - - for each offset o at parameters[2 + 2*j + 1] for some j in 0..n-1 - parameters[o] - (int) m - number of constructors - parameters[o+1] - (int) k_1 - offset for constructor definition - ... - parameters[o+m] - (int) k_m - offset for constructor definition - - for each offset k_i at parameters[o+s] for some s in 0..m-1 - parameters[k_i] - (symbol) name of the constructor - parameters[k_i+1] - (symbol) name of the recognizer - parameters[k_i+2] - (int) m' - number of accessors - parameters[k_i+3+2*r] - (symbol) name of the r accessor - parameters[k_i+3+2*r+1] - (int or type_ast) type of the accessor. If integer, then the value must be in [0..n-1], and it - represents an reference to the recursive type. - - The idea with the additional offsets is that - access to relevant constructors and types can be performed using - a few address calculations. - */ - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); - - /** - Contract for constructors - parameters[0] - (ast) datatype ast. - parmaeters[1] - (int) constructor idx. - Contract for accessors - parameters[0] - (ast) datatype ast. - parameters[1] - (int) constructor idx. - parameters[2] - (int) accessor idx. - Contract for tester - parameters[0] - (ast) datatype ast. - parameters[1] - (int) constructor idx. - */ - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - - bool mk_datatypes(unsigned num_datatypes, datatype_decl * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_sorts); - - virtual expr * get_some_value(sort * s); - - virtual bool is_fully_interp(sort * s) const; - - virtual bool is_value(app* e) const; - - virtual bool is_unique_value(app * e) const { return is_value(e); } - - virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic); - - static unsigned constructor_offset(sort const* s); - static unsigned constructor_offset(parameter const& p); - static unsigned constructor_offset(parameter const* ps); - - static unsigned constructor_offset(sort const* s, unsigned tid); - static unsigned constructor_offset(parameter const* ps, unsigned tid); - -private: - bool is_value_visit(expr * arg, ptr_buffer<app> & todo) const; - - func_decl * mk_update_field( - unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); -}; - -class datatype_util { - ast_manager & m_manager; - family_id m_family_id; - - func_decl * get_constructor(sort * ty, unsigned c_id) const; - - obj_map<sort, ptr_vector<func_decl> *> m_datatype2constructors; - obj_map<sort, func_decl *> m_datatype2nonrec_constructor; - obj_map<func_decl, ptr_vector<func_decl> *> m_constructor2accessors; - obj_map<func_decl, func_decl *> m_constructor2recognizer; - obj_map<func_decl, func_decl *> m_recognizer2constructor; - obj_map<func_decl, func_decl *> m_accessor2constructor; - obj_map<sort, bool> m_is_recursive; - obj_map<sort, bool> m_is_enum; - ast_ref_vector m_asts; - ptr_vector<ptr_vector<func_decl> > m_vectors; - unsigned m_start; - - func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set); - func_decl * get_constructor(sort * ty, unsigned c_id); - -public: - datatype_util(ast_manager & m); - ~datatype_util(); - ast_manager & get_manager() const { return m_manager; } - bool is_datatype(sort * s) const { return is_sort_of(s, m_family_id, DATATYPE_SORT); } - bool is_enum_sort(sort* s); - - bool is_recursive(sort * ty); - bool is_constructor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_CONSTRUCTOR); } - bool is_recognizer(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_RECOGNISER); } - bool is_accessor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_ACCESSOR); } - bool is_update_field(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_UPDATE_FIELD); } - bool is_constructor(app * f) const { return is_app_of(f, m_family_id, OP_DT_CONSTRUCTOR); } - bool is_recognizer(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER); } - bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); } - bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); } - ptr_vector<func_decl> const * get_datatype_constructors(sort * ty); - unsigned get_datatype_num_constructors(sort * ty) { - SASSERT(is_datatype(ty)); - unsigned tid = ty->get_parameter(1).get_int(); - unsigned o = datatype_decl_plugin::constructor_offset(ty, tid); - return ty->get_parameter(o).get_int(); - } - unsigned get_datatype_num_parameter_sorts(sort * ty) { - SASSERT(is_datatype(ty)); - return ty->get_parameter(2).get_int(); - } - sort* get_datatype_parameter_sort(sort * ty, unsigned idx) { - SASSERT(is_datatype(ty)); - SASSERT(idx < get_datatype_num_parameter_sorts(ty)); - return to_sort(ty->get_parameter(3 + idx).get_ast()); - } - unsigned get_constructor_idx(func_decl * f) const { SASSERT(is_constructor(f)); return f->get_parameter(1).get_int(); } - unsigned get_recognizer_constructor_idx(func_decl * f) const { SASSERT(is_recognizer(f)); return f->get_parameter(1).get_int(); } - func_decl * get_non_rec_constructor(sort * ty); - func_decl * get_constructor_recognizer(func_decl * constructor); - ptr_vector<func_decl> const * get_constructor_accessors(func_decl * constructor); - func_decl * get_accessor_constructor(func_decl * accessor); - func_decl * get_recognizer_constructor(func_decl * recognizer); - family_id get_family_id() const { return m_family_id; } - bool are_siblings(sort * s1, sort * s2); - bool is_func_decl(datatype_op_kind k, unsigned num_params, parameter const* params, func_decl* f); - bool is_constructor_of(unsigned num_params, parameter const* params, func_decl* f); - void reset(); - void display_datatype(sort *s, std::ostream& strm); - - -}; #endif /* DATATYPE_DECL_PLUGIN_H_ */ - -#endif /* DATATYPE_V2 */ diff --git a/src/ast/datatype_decl_plugin2.cpp b/src/ast/datatype_decl_plugin2.cpp deleted file mode 100644 index 743a08e98..000000000 --- a/src/ast/datatype_decl_plugin2.cpp +++ /dev/null @@ -1,1077 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - datatype_decl_plugin.cpp - -Abstract: - - <abstract> - -Author: - - Nikolaj Bjorner (nbjorner) 2017-9-1 - -Revision History: - ---*/ - -#include "ast/datatype_decl_plugin.h" - -#ifdef DATATYPE_V2 -#include "util/warning.h" -#include "ast/datatype_decl_plugin2.h" -#include "ast/array_decl_plugin.h" -#include "ast/ast_smt2_pp.h" -#include "ast/ast_translation.h" - - -namespace datatype { - - void accessor::fix_range(sort_ref_vector const& dts) { - if (!m_range) { - m_range = dts[m_index]; - } - } - - 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<parameter> 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<size>& 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<size>& 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<plugin*>(other_p); - svector<symbol> names; - ptr_vector<def> 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<sort, sort_size> 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 (!u().is_well_founded(sorts.size(), sorts.c_ptr())) { - m_manager->raise_exception("datatype is not well-founded"); - } - - 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); - } - } - - 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<app> & 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 { - 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<app> 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<builtin_name> & 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)); - } - } - - expr * plugin::get_some_value(sort * s) { - SASSERT(u().is_datatype(s)); - func_decl * c = u().get_non_rec_constructor(s); - ptr_buffer<expr> 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<sort, status> already_found; - ptr_vector<sort> 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<sort, param_size::size*> 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<param_size::size> 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<symbol> const& names) { - map<symbol, status, symbol_hash_proc, symbol_eq_proc> already_found; - map<symbol, param_size::size*, symbol_hash_proc, symbol_eq_proc> szs; - - svector<symbol> 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<param_size::size> s_add; - for (constructor const* c : d) { - ptr_vector<param_size::size> 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<bool> well_founded(num_types, false); - obj_map<sort, unsigned> 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 (!found_nonwf) { - changed = true; - well_founded[tid] = true; - num_well_founded++; - break; - } - } - } - } - while(changed && num_well_founded < num_types); - return num_well_founded == num_types; - } - - def const& util::get_def(sort* s) const { - return m_plugin->get_def(s); - } - - void util::get_subsorts(sort* s, ptr_vector<sort>& 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); - } - } - } - - - 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<decl::plugin*>(m.get_plugin(m_family_id)); - SASSERT(m_plugin); - } - - util::~util() { - std::for_each(m_vectors.begin(), m_vectors.end(), delete_proc<ptr_vector<func_decl> >()); - } - - ptr_vector<func_decl> const * util::get_datatype_constructors(sort * ty) { - SASSERT(is_datatype(ty)); - ptr_vector<func_decl> * r = 0; - if (m_datatype2constructors.find(ty, r)) - return r; - r = alloc(ptr_vector<func_decl>); - 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<func_decl> const * util::get_constructor_accessors(func_decl * con) { - SASSERT(is_constructor(con)); - ptr_vector<func_decl> * res = 0; - if (m_constructor2accessors.find(con, res)) { - return res; - } - res = alloc(ptr_vector<func_decl>); - 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; - } - } - return res; - } - - 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; - } - - func_decl * util::get_recognizer_constructor(func_decl * recognizer) const { - SASSERT(is_recognizer(recognizer)); - return to_func_decl(recognizer->get_parameter(0).get_ast()); - } - - 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<func_decl> 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<ptr_vector<func_decl> >()); - 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<sort> 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<sort> & 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<func_decl> 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; - } - ++idx; - } - UNREACHABLE(); - return 0; - } - - unsigned util::get_recognizer_constructor_idx(func_decl * f) const { - return get_constructor_idx(get_recognizer_constructor(f)); - } - - /** - \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(); - } - } - - 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<def>& defs) { - svector<symbol> mark; - ptr_buffer<sort> 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); - } - } - } - } - } - - void util::display_datatype(sort *s0, std::ostream& out) { - ast_mark mark; - ptr_buffer<sort> 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"; - - ptr_vector<func_decl> 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<func_decl> 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"; - } - } - } -} - -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 d; -} - -#endif diff --git a/src/ast/datatype_decl_plugin2.h b/src/ast/datatype_decl_plugin2.h deleted file mode 100644 index 364ba9350..000000000 --- a/src/ast/datatype_decl_plugin2.h +++ /dev/null @@ -1,439 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - datatype_decl_plugin.h - -Abstract: - - <abstract> - -Author: - - 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_PLUGIN2_H_ -#define DATATYPE_DECL_PLUGIN2_H_ - -#include "ast/ast.h" -#include "util/buffer.h" -#include "util/symbol_table.h" -#include "util/obj_hashtable.h" - -#ifdef DATATYPE_V2 - - enum sort_kind { - DATATYPE_SORT - }; - - enum op_kind { - OP_DT_CONSTRUCTOR, - OP_DT_RECOGNISER, - OP_DT_IS, - OP_DT_ACCESSOR, - OP_DT_UPDATE_FIELD, - LAST_DT_OP - }; - -namespace datatype { - - class util; - class def; - class accessor; - class constructor; - - - class accessor { - symbol m_name; - sort_ref m_range; - unsigned m_index; // reference to recursive data-type may only get resolved after all mutually recursive data-types are procssed. - constructor* m_constructor; - public: - accessor(ast_manager& m, symbol const& n, sort* range): - m_name(n), - m_range(range, m), - m_index(UINT_MAX) - {} - accessor(ast_manager& m, symbol const& n, unsigned index): - m_name(n), - m_range(m), - m_index(index) - {} - sort* range() const { return m_range; } - void fix_range(sort_ref_vector const& dts); - symbol const& name() const { return m_name; } - func_decl_ref instantiate(sort_ref_vector const& ps) const; - func_decl_ref instantiate(sort* dt) const; - void attach(constructor* d) { m_constructor = d; } - constructor const& get_constructor() const { return *m_constructor; } - def const& get_def() const; - util& u() const; - accessor* translate(ast_translation& tr); - }; - - class constructor { - symbol m_name; - symbol m_recognizer; - ptr_vector<accessor> m_accessors; - def* m_def; - public: - constructor(symbol n, symbol const& r): m_name(n), m_recognizer(r) {} - ~constructor(); - void add(accessor* a) { m_accessors.push_back(a); a->attach(this); } - symbol const& name() const { return m_name; } - symbol const& recognizer() const { return m_recognizer; } - ptr_vector<accessor> const& accessors() const { return m_accessors; } - ptr_vector<accessor>::const_iterator begin() const { return m_accessors.begin(); } - ptr_vector<accessor>::const_iterator end() const { return m_accessors.end(); } - ptr_vector<accessor>::iterator begin() { return m_accessors.begin(); } - ptr_vector<accessor>::iterator end() { return m_accessors.end(); } - func_decl_ref instantiate(sort_ref_vector const& ps) const; - func_decl_ref instantiate(sort* dt) const; - void attach(def* d) { m_def = d; } - def const& get_def() const { return *m_def; } - util& u() const; - constructor* translate(ast_translation& tr); - }; - - namespace param_size { - class size { - unsigned m_ref; - public: - size(): m_ref(0) {} - virtual ~size() {} - void inc_ref() { ++m_ref; } - void dec_ref() { --m_ref; if (m_ref == 0) dealloc(this); } - static size* mk_offset(sort_size const& s); - static size* mk_param(sort_ref& p); - static size* mk_plus(size* a1, size* a2); - static size* mk_times(size* a1, size* a2); - static size* mk_plus(ptr_vector<size>& szs); - static size* mk_times(ptr_vector<size>& szs); - static size* mk_power(size* a1, size* a2); - - virtual size* subst(obj_map<sort, size*>& S) = 0; - virtual sort_size eval(obj_map<sort, sort_size> const& S) = 0; - - }; - struct offset : public size { - sort_size m_offset; - offset(sort_size const& s): m_offset(s) {} - virtual ~offset() {} - virtual size* subst(obj_map<sort,size*>& S) { return this; } - virtual sort_size eval(obj_map<sort, sort_size> const& S) { return m_offset; } - }; - struct plus : public size { - size* m_arg1, *m_arg2; - plus(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref();} - virtual ~plus() { m_arg1->dec_ref(); m_arg2->dec_ref(); } - virtual size* subst(obj_map<sort,size*>& S) { return mk_plus(m_arg1->subst(S), m_arg2->subst(S)); } - virtual sort_size eval(obj_map<sort, sort_size> const& S) { - sort_size s1 = m_arg1->eval(S); - sort_size s2 = m_arg2->eval(S); - if (s1.is_infinite()) return s1; - if (s2.is_infinite()) return s2; - if (s1.is_very_big()) return s1; - if (s2.is_very_big()) return s2; - rational r = rational(s1.size(), rational::ui64()) + rational(s2.size(), rational::ui64()); - return sort_size(r); - } - }; - struct times : public size { - size* m_arg1, *m_arg2; - times(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); } - virtual ~times() { m_arg1->dec_ref(); m_arg2->dec_ref(); } - virtual size* subst(obj_map<sort,size*>& S) { return mk_times(m_arg1->subst(S), m_arg2->subst(S)); } - virtual sort_size eval(obj_map<sort, sort_size> const& S) { - sort_size s1 = m_arg1->eval(S); - sort_size s2 = m_arg2->eval(S); - if (s1.is_infinite()) return s1; - if (s2.is_infinite()) return s2; - if (s1.is_very_big()) return s1; - if (s2.is_very_big()) return s2; - rational r = rational(s1.size(), rational::ui64()) * rational(s2.size(), rational::ui64()); - return sort_size(r); - } - }; - struct power : public size { - size* m_arg1, *m_arg2; - power(size* a1, size* a2): m_arg1(a1), m_arg2(a2) { a1->inc_ref(); a2->inc_ref(); } - virtual ~power() { m_arg1->dec_ref(); m_arg2->dec_ref(); } - virtual size* subst(obj_map<sort,size*>& S) { return mk_power(m_arg1->subst(S), m_arg2->subst(S)); } - virtual sort_size eval(obj_map<sort, sort_size> const& S) { - sort_size s1 = m_arg1->eval(S); - sort_size s2 = m_arg2->eval(S); - // s1^s2 - if (s1.is_infinite()) return s1; - if (s2.is_infinite()) return s2; - if (s1.is_very_big()) return s1; - if (s2.is_very_big()) return s2; - if (s1.size() == 1) return s1; - if (s2.size() == 1) return s1; - if (s1.size() > (2 << 20) || s2.size() > 10) return sort_size::mk_very_big(); - rational r = ::power(rational(s1.size(), rational::ui64()), static_cast<unsigned>(s2.size())); - return sort_size(r); - } - }; - struct sparam : public size { - sort_ref m_param; - sparam(sort_ref& p): m_param(p) {} - virtual ~sparam() {} - virtual size* subst(obj_map<sort,size*>& S) { return S[m_param]; } - virtual sort_size eval(obj_map<sort, sort_size> const& S) { return S[m_param]; } - }; - }; - - class def { - ast_manager& m; - util& m_util; - symbol m_name; - unsigned m_class_id; - param_size::size* m_sort_size; - sort_ref_vector m_params; - mutable sort_ref m_sort; - ptr_vector<constructor> m_constructors; - public: - def(ast_manager& m, util& u, symbol const& n, unsigned class_id, unsigned num_params, sort * const* params): - m(m), - m_util(u), - m_name(n), - m_class_id(class_id), - m_sort_size(0), - m_params(m, num_params, params), - m_sort(m) - {} - ~def() { - if (m_sort_size) m_sort_size->dec_ref(); - for (constructor* c : m_constructors) dealloc(c); - m_constructors.reset(); - } - void add(constructor* c) { - m_constructors.push_back(c); - c->attach(this); - } - symbol const& name() const { return m_name; } - unsigned id() const { return m_class_id; } - sort_ref instantiate(sort_ref_vector const& ps) const; - ptr_vector<constructor> const& constructors() const { return m_constructors; } - ptr_vector<constructor>::const_iterator begin() const { return m_constructors.begin(); } - ptr_vector<constructor>::const_iterator end() const { return m_constructors.end(); } - ptr_vector<constructor>::iterator begin() { return m_constructors.begin(); } - ptr_vector<constructor>::iterator end() { return m_constructors.end(); } - sort_ref_vector const& params() const { return m_params; } - util& u() const { return m_util; } - param_size::size* sort_size() { return m_sort_size; } - void set_sort_size(param_size::size* p) { m_sort_size = p; p->inc_ref(); m_sort = 0; } - def* translate(ast_translation& tr, util& u); - }; - - namespace decl { - - class plugin : public decl_plugin { - mutable scoped_ptr<util> m_util; - map<symbol, def*, symbol_hash_proc, symbol_eq_proc> m_defs; - svector<symbol> m_def_block; - unsigned m_class_id; - util & u() const; - - virtual void inherit(decl_plugin* other_p, ast_translation& tr); - - public: - plugin(): m_class_id(0) {} - virtual ~plugin(); - - virtual void finalize(); - - virtual decl_plugin * mk_fresh() { return alloc(plugin); } - - virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters); - - virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - - virtual expr * get_some_value(sort * s); - - virtual bool is_fully_interp(sort * s) const; - - virtual bool is_value(app* e) const; - - virtual bool is_unique_value(app * e) const { return is_value(e); } - - virtual void get_op_names(svector<builtin_name> & op_names, symbol const & logic); - - void begin_def_block() { m_class_id++; m_def_block.reset(); } - - void end_def_block(); - - def* mk(symbol const& name, unsigned n, sort * const * params); - - void remove(symbol const& d); - - bool mk_datatypes(unsigned num_datatypes, def * const * datatypes, unsigned num_params, sort* const* sort_params, sort_ref_vector & new_sorts); - - def const& get_def(sort* s) const { return *(m_defs[datatype_name(s)]); } - def& get_def(symbol const& s) { return *(m_defs[s]); } - bool is_declared(sort* s) const { return m_defs.contains(datatype_name(s)); } - private: - bool is_value_visit(expr * arg, ptr_buffer<app> & todo) const; - - func_decl * mk_update_field( - unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - - func_decl * mk_constructor( - unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - - func_decl * mk_accessor( - unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - - func_decl * mk_recognizer( - unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - - func_decl * mk_is( - unsigned num_parameters, parameter const * parameters, - unsigned arity, sort * const * domain, sort * range); - - symbol datatype_name(sort * s) const { - //SASSERT(u().is_datatype(s)); - return s->get_parameter(0).get_symbol(); - } - - }; - } - - class util { - ast_manager & m; - family_id m_family_id; - mutable decl::plugin* m_plugin; - - - obj_map<sort, ptr_vector<func_decl> *> m_datatype2constructors; - obj_map<sort, func_decl *> m_datatype2nonrec_constructor; - obj_map<func_decl, ptr_vector<func_decl> *> m_constructor2accessors; - obj_map<func_decl, func_decl *> m_constructor2recognizer; - obj_map<func_decl, func_decl *> m_recognizer2constructor; - obj_map<func_decl, func_decl *> m_accessor2constructor; - obj_map<sort, bool> m_is_recursive; - obj_map<sort, bool> m_is_enum; - mutable obj_map<sort, bool> m_is_fully_interp; - mutable ast_ref_vector m_asts; - ptr_vector<ptr_vector<func_decl> > m_vectors; - unsigned m_start; - mutable ptr_vector<sort> m_fully_interp_trail; - - func_decl * get_non_rec_constructor_core(sort * ty, ptr_vector<sort> & forbidden_set); - - friend class decl::plugin; - - bool is_recursive_core(sort * s) const; - sort_size get_datatype_size(sort* s0); - void compute_datatype_size_functions(svector<symbol> const& names); - param_size::size* get_sort_size(sort_ref_vector const& params, sort* s); - bool is_well_founded(unsigned num_types, sort* const* sorts); - def& get_def(symbol const& s) { return m_plugin->get_def(s); } - void get_subsorts(sort* s, ptr_vector<sort>& sorts) const; - - public: - util(ast_manager & m); - ~util(); - ast_manager & get_manager() const { return m; } - // sort * mk_datatype_sort(symbol const& name, unsigned n, sort* const* params); - bool is_datatype(sort const* s) const { return is_sort_of(s, m_family_id, DATATYPE_SORT); } - bool is_enum_sort(sort* s); - bool is_recursive(sort * ty); - bool is_constructor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_CONSTRUCTOR); } - bool is_recognizer(func_decl * f) const { return is_recognizer0(f) || is_is(f); } - bool is_recognizer0(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_RECOGNISER); } - bool is_is(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_IS); } - bool is_accessor(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_ACCESSOR); } - bool is_update_field(func_decl * f) const { return is_decl_of(f, m_family_id, OP_DT_UPDATE_FIELD); } - bool is_constructor(app * f) const { return is_app_of(f, m_family_id, OP_DT_CONSTRUCTOR); } - bool is_recognizer0(app * f) const { return is_app_of(f, m_family_id, OP_DT_RECOGNISER);} - bool is_is(app * f) const { return is_app_of(f, m_family_id, OP_DT_IS);} - bool is_recognizer(app * f) const { return is_recognizer0(f) || is_is(f); } - bool is_accessor(app * f) const { return is_app_of(f, m_family_id, OP_DT_ACCESSOR); } - bool is_update_field(app * f) const { return is_app_of(f, m_family_id, OP_DT_UPDATE_FIELD); } - ptr_vector<func_decl> const * get_datatype_constructors(sort * ty); - unsigned get_datatype_num_constructors(sort * ty); - unsigned get_datatype_num_parameter_sorts(sort * ty); - sort* get_datatype_parameter_sort(sort * ty, unsigned idx); - func_decl * get_non_rec_constructor(sort * ty); - func_decl * get_constructor_recognizer(func_decl * constructor); - ptr_vector<func_decl> const * get_constructor_accessors(func_decl * constructor); - func_decl * get_accessor_constructor(func_decl * accessor); - func_decl * get_recognizer_constructor(func_decl * recognizer) const; - family_id get_family_id() const { return m_family_id; } - bool are_siblings(sort * s1, sort * s2); - bool is_func_decl(op_kind k, unsigned num_params, parameter const* params, func_decl* f); - bool is_constructor_of(unsigned num_params, parameter const* params, func_decl* f); - void reset(); - bool is_declared(sort* s) const; - void display_datatype(sort *s, std::ostream& strm); - bool is_fully_interp(sort * s) const; - sort_ref_vector datatype_params(sort * s) const; - unsigned get_constructor_idx(func_decl * f) const; - unsigned get_recognizer_constructor_idx(func_decl * f) const; - decl::plugin* get_plugin() { return m_plugin; } - void get_defs(sort* s, ptr_vector<def>& defs); - def const& get_def(sort* s) const; - }; - -}; - -typedef datatype::accessor accessor_decl; -typedef datatype::constructor constructor_decl; -typedef datatype::def datatype_decl; -typedef datatype::decl::plugin datatype_decl_plugin; -typedef datatype::util datatype_util; - -class type_ref { - void * m_data; -public: - type_ref():m_data(TAG(void *, static_cast<void*>(0), 1)) {} - type_ref(int idx):m_data(BOXINT(void *, idx)) {} - type_ref(sort * s):m_data(TAG(void *, s, 1)) {} - - bool is_idx() const { return GET_TAG(m_data) == 0; } - bool is_sort() const { return GET_TAG(m_data) == 1; } - sort * get_sort() const { return UNTAG(sort *, m_data); } - int get_idx() const { return UNBOXINT(m_data); } -}; - -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; -} - - - -// Remark: the datatype becomes the owner of the constructor_decls -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) {} - - -#endif /* DATATYPE_DECL_PLUGIN_H_ */ - -#endif /* DATATYPE_V2 */ diff --git a/src/cmd_context/pdecl.cpp b/src/cmd_context/pdecl.cpp index 95a6030f3..7eac1f347 100644 --- a/src/cmd_context/pdecl.cpp +++ b/src/cmd_context/pdecl.cpp @@ -355,13 +355,8 @@ psort_dt_decl::psort_dt_decl(unsigned id, unsigned num_params, pdecl_manager & m sort * psort_dt_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { -#ifndef DATATYPE_V2 - UNREACHABLE(); - return 0; -#else SASSERT(n == m_num_params); return m.instantiate_datatype(this, m_name, n, s); -#endif } void psort_dt_decl::display(std::ostream & out) const { @@ -581,7 +576,6 @@ struct datatype_decl_buffer { ~datatype_decl_buffer() { del_datatype_decls(m_buffer.size(), m_buffer.c_ptr()); } }; -#ifdef DATATYPE_V2 sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * s) { sort * r = m.instantiate_datatype(this, m_name, n, s); @@ -615,37 +609,6 @@ sort * pdatatype_decl::instantiate(pdecl_manager & m, unsigned n, sort * const * return r; } -#else -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; - } - } - 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; -} -#endif void pdatatype_decl::display(std::ostream & out) const { out << "(declare-datatype " << m_name; @@ -666,7 +629,6 @@ void pdatatype_decl::display(std::ostream & out) const { out << ")"; } -#ifdef DATATYPE_V2 bool pdatatype_decl::commit(pdecl_manager& m) { TRACE("datatype", tout << m_name << "\n";); sort_ref_vector ps(m.m()); @@ -683,7 +645,6 @@ bool pdatatype_decl::commit(pdecl_manager& m) { } return is_ok; } -#endif pdatatypes_decl::pdatatypes_decl(unsigned id, unsigned num_params, pdecl_manager & m, @@ -714,7 +675,6 @@ bool pdatatypes_decl::fix_missing_refs(symbol & missing) { return true; } -#ifdef DATATYPE_V2 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; @@ -746,28 +706,7 @@ bool pdatatypes_decl::instantiate(pdecl_manager & m, sort * const * s) { UNREACHABLE(); return false; } -#else -bool pdatatypes_decl::instantiate(pdecl_manager & m, sort * const * s) { - datatype_decl_buffer dts; - for (auto d : m_datatypes) { - dts.m_buffer.push_back(d->instantiate_decl(m, s)); - } - 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; - unsigned i = 0; - for (auto d : m_datatypes) { - sort * new_dt = sorts.get(i++); - d->cache(m, s, new_dt); - m.save_info(new_dt, d, m_num_params, s); - m.notify_new_dt(new_dt, d); - } - return true; -} -#endif -#ifdef DATATYPE_V2 bool pdatatypes_decl::commit(pdecl_manager& m) { datatype_decl_buffer dts; for (pdatatype_decl* d : m_datatypes) { @@ -789,7 +728,6 @@ bool pdatatypes_decl::commit(pdecl_manager& m) { } return is_ok; } -#endif struct pdecl_manager::sort_info { psort_decl * m_decl; diff --git a/src/cmd_context/pdecl.h b/src/cmd_context/pdecl.h index bef723380..c72020827 100644 --- a/src/cmd_context/pdecl.h +++ b/src/cmd_context/pdecl.h @@ -241,9 +241,7 @@ public: virtual void display(std::ostream & out) const; bool has_missing_refs(symbol & missing) const; bool has_duplicate_accessors(symbol & repeated) const; -#ifdef DATATYPE_V2 bool commit(pdecl_manager& m); -#endif }; /** @@ -263,10 +261,8 @@ 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(); } -#ifdef DATATYPE_V2 // commit declaration bool commit(pdecl_manager& m); -#endif }; class new_datatype_eh { diff --git a/src/parsers/smt2/smt2parser.cpp b/src/parsers/smt2/smt2parser.cpp index a1304a848..681c3d597 100644 --- a/src/parsers/smt2/smt2parser.cpp +++ b/src/parsers/smt2/smt2parser.cpp @@ -877,9 +877,7 @@ namespace smt2 { } else if (sz == 1) { check_missing(new_dt_decls[0], line, pos); -#ifdef DATATYPE_V2 new_dt_decls[0]->commit(pm()); -#endif } else { SASSERT(sz > 1); @@ -892,27 +890,9 @@ namespace smt2 { err_msg += "'"; throw parser_exception(err_msg, line, pos); } -#ifndef DATATYPE_V2 - m_ctx.insert_aux_pdecl(dts.get()); -#else dts->commit(pm()); - m_ctx.insert_aux_pdecl(dts.get()); -#endif + m_ctx.insert_aux_pdecl(dts.get()); } -#ifndef DATATYPE_V2 - 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); - } - } -#else for (unsigned i = 0; i < sz; i++) { pdatatype_decl * d = new_dt_decls[i]; symbol duplicated; @@ -922,7 +902,6 @@ namespace smt2 { m_ctx.insert(d); } } -#endif TRACE("declare_datatypes", tout << "i: " << i << " new_dt_decls.size(): " << sz << "\n"; for (unsigned j = 0; j < new_dt_decls.size(); ++j) tout << new_dt_decls[j]->get_name() << "\n";); m_ctx.print_success(); @@ -952,16 +931,7 @@ namespace smt2 { check_missing(d, line, pos); check_duplicate(d, line, pos); -#ifndef DATATYPE_V2 - 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); - } -#else d->commit(pm()); -#endif check_rparen_next("invalid end of datatype declaration, ')' expected"); m_ctx.print_success(); }