diff --git a/scripts/mk_genfile_common.py b/scripts/mk_genfile_common.py index 3b19b8c25..e242fa443 100644 --- a/scripts/mk_genfile_common.py +++ b/scripts/mk_genfile_common.py @@ -672,6 +672,7 @@ def mk_install_tactic_cpp_internal(h_files_full_path, path): components. """ ADD_TACTIC_DATA = [] + ADD_SIMPLIFIER_DATA = [] ADD_PROBE_DATA = [] def ADD_TACTIC(name, descr, cmd): ADD_TACTIC_DATA.append((name, descr, cmd)) @@ -679,9 +680,13 @@ def mk_install_tactic_cpp_internal(h_files_full_path, path): def ADD_PROBE(name, descr, cmd): ADD_PROBE_DATA.append((name, descr, cmd)) + def ADD_SIMPLIFIER(name, descr, cmd): + ADD_SIMPLIFIER_DATA.append((name, descr, cmd)) + eval_globals = { 'ADD_TACTIC': ADD_TACTIC, 'ADD_PROBE': ADD_PROBE, + 'ADD_SIMPLIFIER': ADD_SIMPLIFIER } assert isinstance(h_files_full_path, list) @@ -691,9 +696,11 @@ def mk_install_tactic_cpp_internal(h_files_full_path, path): fout.write('// Automatically generated file.\n') fout.write('#include "tactic/tactic.h"\n') fout.write('#include "cmd_context/tactic_cmds.h"\n') + fout.write('#include "cmd_context/simplifier_cmds.h"\n') fout.write('#include "cmd_context/cmd_context.h"\n') tactic_pat = re.compile('[ \t]*ADD_TACTIC\(.*\)') - probe_pat = re.compile('[ \t]*ADD_PROBE\(.*\)') + probe_pat = re.compile('[ \t]*ADD_PROBE\(.*\)') + simplifier_pat = re.compile('[ \t]*ADD_SIMPLIFIER\(.*\)') for h_file in sorted_headers_by_component(h_files_full_path): added_include = False try: @@ -719,17 +726,31 @@ def mk_install_tactic_cpp_internal(h_files_full_path, path): _logger.error("Failed processing ADD_PROBE command at '{}'\n{}".format( fullname, line)) raise e + if simplifier_pat.match(line): + if not added_include: + added_include = True + fout.write('#include "%s"\n' % path_after_src(h_file)) + try: + eval(line.strip('\n '), eval_globals, None) + except Exception as e: + _logger.error("Failed processing ADD_SIMPLIFIER command at '{}'\n{}".format( + fullname, line)) + raise e + except Exception as e: _logger.error("Failed to read file {}\n".format(h_file)) raise e # First pass will just generate the tactic factories fout.write('#define ADD_TACTIC_CMD(NAME, DESCR, CODE) ctx.insert(alloc(tactic_cmd, symbol(NAME), DESCR, [](ast_manager &m, const params_ref &p) { return CODE; }))\n') fout.write('#define ADD_PROBE(NAME, DESCR, PROBE) ctx.insert(alloc(probe_info, symbol(NAME), DESCR, PROBE))\n') + fout.write('#define ADD_SIMPLIFIER_CMD(NAME, DESCR, FUNCTION) ctx.insert(alloc(simplifier_cmd, symbol(NAME), DESCR, FUNCTION))\n') fout.write('void install_tactics(tactic_manager & ctx) {\n') for data in ADD_TACTIC_DATA: fout.write(' ADD_TACTIC_CMD("%s", "%s", %s);\n' % data) for data in ADD_PROBE_DATA: fout.write(' ADD_PROBE("%s", "%s", %s);\n' % data) + for data in ADD_SIMPLIFIER_DATA: + fout.write(' ADD_SIMPLIFIER_CMD("%s", "%s", %s);\n' % data) fout.write('}\n') fout.close() return fullname diff --git a/src/ast/simplifiers/CMakeLists.txt b/src/ast/simplifiers/CMakeLists.txt index 127db786a..e30224402 100644 --- a/src/ast/simplifiers/CMakeLists.txt +++ b/src/ast/simplifiers/CMakeLists.txt @@ -29,4 +29,8 @@ z3_add_component(simplifiers normal_forms rewriter substitution + TACTIC_HEADERS + bit_blaster.h + rewriter_simplifier.h + ) diff --git a/src/ast/simplifiers/bit_blaster.h b/src/ast/simplifiers/bit_blaster.h index 5724cc075..820431706 100644 --- a/src/ast/simplifiers/bit_blaster.h +++ b/src/ast/simplifiers/bit_blaster.h @@ -49,3 +49,6 @@ public: }; +/* + ADD_SIMPLIFIER("bit-blaster", "reduce bit-vector expressions into SAT.", "[](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(bit_blaster_simplifier, m, p, s); }") +*/ diff --git a/src/ast/simplifiers/dependent_expr_state.h b/src/ast/simplifiers/dependent_expr_state.h index 0fedf484c..d4d449cf8 100644 --- a/src/ast/simplifiers/dependent_expr_state.h +++ b/src/ast/simplifiers/dependent_expr_state.h @@ -32,6 +32,7 @@ Author: #include "util/trail.h" #include "util/statistics.h" #include "util/params.h" +#include "util/z3_exception.h" #include "ast/converters/model_converter.h" #include "ast/simplifiers/dependent_expr.h" #include "ast/simplifiers/model_reconstruction_trail.h" @@ -98,6 +99,17 @@ public: bool has_quantifiers(); }; +class default_dependent_expr_state : public dependent_expr_state { +public: + default_dependent_expr_state(ast_manager& m): dependent_expr_state(m) {} + virtual unsigned qtail() const { return 0; } + virtual dependent_expr const& operator[](unsigned i) { throw default_exception("unexpected access"); } + virtual void update(unsigned i, dependent_expr const& j) { throw default_exception("unexpected update"); } + virtual void add(dependent_expr const& j) { throw default_exception("unexpected addition"); } + virtual bool inconsistent() { return false; } + virtual model_reconstruction_trail& model_trail() { throw default_exception("unexpected access to model reconstruction"); } +}; + inline std::ostream& operator<<(std::ostream& out, dependent_expr_state& st) { return st.display(out); } @@ -150,3 +162,5 @@ public: ast_manager& get_manager() { return m; } dependent_expr_state& get_fmls() { return m_fmls; } }; + +typedef std::function simplifier_factory; diff --git a/src/ast/simplifiers/model_reconstruction_trail.cpp b/src/ast/simplifiers/model_reconstruction_trail.cpp index 82d56f491..22b600ded 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.cpp +++ b/src/ast/simplifiers/model_reconstruction_trail.cpp @@ -139,18 +139,15 @@ void model_reconstruction_trail::replay(unsigned qhead, expr_ref_vector& assumpt */ model_converter_ref model_reconstruction_trail::get_model_converter() { generic_model_converter_ref mc = alloc(generic_model_converter, m, "dependent-expr-model"); - unsigned i = 0; - append(*mc, i); + append(*mc); return model_converter_ref(mc.get()); } /** * Append model conversions starting at index i */ -void model_reconstruction_trail::append(generic_model_converter& mc, unsigned& i) { - TRACE("simplifier", display(tout)); - for (; i < m_trail.size(); ++i) { - auto* t = m_trail[i]; +void model_reconstruction_trail::append(generic_model_converter& mc) { + for (auto* t : m_trail) { if (!t->m_active) continue; else if (t->is_hide()) @@ -163,13 +160,10 @@ void model_reconstruction_trail::append(generic_model_converter& mc, unsigned& i mc.add(v, def); } } + TRACE("simplifier", display(tout); mc.display(tout)); } -void model_reconstruction_trail::append(generic_model_converter& mc) { - m_trail_stack.push(value_trail(m_trail_index)); - append(mc, m_trail_index); -} std::ostream& model_reconstruction_trail::display(std::ostream& out) const { for (auto* t : m_trail) { diff --git a/src/ast/simplifiers/model_reconstruction_trail.h b/src/ast/simplifiers/model_reconstruction_trail.h index 36ddde9ff..89a112c24 100644 --- a/src/ast/simplifiers/model_reconstruction_trail.h +++ b/src/ast/simplifiers/model_reconstruction_trail.h @@ -84,7 +84,6 @@ class model_reconstruction_trail { ast_manager& m; trail_stack& m_trail_stack; scoped_ptr_vector m_trail; - unsigned m_trail_index = 0; void add_vars(expr* e, ast_mark& free_vars) { for (expr* t : subterms::all(expr_ref(e, m))) @@ -108,10 +107,6 @@ class model_reconstruction_trail { return any_of(added, [&](dependent_expr const& d) { return intersects(free_vars, d); }); } - /** - * Append new updates to model converter, update the current index into the trail in the process. - */ - void append(generic_model_converter& mc, unsigned& index); public: model_reconstruction_trail(ast_manager& m, trail_stack& tr): diff --git a/src/ast/simplifiers/rewriter_simplifier.h b/src/ast/simplifiers/rewriter_simplifier.h index f3dc91a51..f74c213d4 100644 --- a/src/ast/simplifiers/rewriter_simplifier.h +++ b/src/ast/simplifiers/rewriter_simplifier.h @@ -53,3 +53,7 @@ public: void updt_params(params_ref const& p) override { m_params.append(p); m_rewriter.updt_params(m_params); } void collect_param_descrs(param_descrs& r) override { th_rewriter::get_param_descrs(r); } }; + +/* + ADD_SIMPLIFIER("simplify", "apply simplification rules.", "[](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(rewriter_simplifier, m, p, s); }") + */ diff --git a/src/cmd_context/CMakeLists.txt b/src/cmd_context/CMakeLists.txt index f8c1aa38f..f3cdb3c03 100644 --- a/src/cmd_context/CMakeLists.txt +++ b/src/cmd_context/CMakeLists.txt @@ -9,6 +9,7 @@ z3_add_component(cmd_context parametric_cmd.cpp pdecl.cpp simplify_cmd.cpp + simplifier_cmds.cpp tactic_cmds.cpp tactic_manager.cpp COMPONENT_DEPENDENCIES diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 5602f53a3..89733a7ea 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -546,6 +546,7 @@ cmd_context::cmd_context(bool main_ctx, ast_manager * m, symbol const & l): install_basic_cmds(*this); install_ext_basic_cmds(*this); install_core_tactic_cmds(*this); + install_core_simplifier_cmds(*this); m_mcs.push_back(nullptr); SASSERT(m != 0 || !has_manager()); if (m_main_ctx) { @@ -559,8 +560,7 @@ cmd_context::~cmd_context() { } pop(m_scopes.size()); finalize_cmds(); - finalize_tactic_cmds(); - finalize_probes(); + finalize_tactic_manager(); m_proof_cmds = nullptr; reset(true); m_mcs.reset(); diff --git a/src/cmd_context/cmd_context.h b/src/cmd_context/cmd_context.h index 93d2c0d3e..f5a247794 100644 --- a/src/cmd_context/cmd_context.h +++ b/src/cmd_context/cmd_context.h @@ -318,7 +318,7 @@ protected: void register_builtin_ops(decl_plugin * p); void load_plugin(symbol const & name, bool install_names, svector& fids); void init_manager_core(bool new_manager); - void init_manager(); + void init_external_manager(); void reset_cmds(); void finalize_cmds(); @@ -414,7 +414,9 @@ public: sexpr_manager & sm() const { if (!m_sexpr_manager) const_cast(this)->m_sexpr_manager = alloc(sexpr_manager); return *m_sexpr_manager; } proof_cmds* get_proof_cmds() { return m_proof_cmds.get(); } + void init_manager(); solver* get_solver() { return m_solver.get(); } + void set_solver(solver* s) { m_solver = s; } void set_proof_cmds(proof_cmds* pc) { m_proof_cmds = pc; } void set_solver_factory(solver_factory * s); diff --git a/src/cmd_context/simplifier_cmds.cpp b/src/cmd_context/simplifier_cmds.cpp new file mode 100644 index 000000000..b8ce15081 --- /dev/null +++ b/src/cmd_context/simplifier_cmds.cpp @@ -0,0 +1,158 @@ +/*++ +Copyright (c) 2023 Microsoft Corporation + +Module Name: + + simplifier_cmds.h + +Abstract: + Support for simplifier commands in SMT 2.0 front-end + +Author: + + Nikolaj Bjorner (nbjorner) 2023-01-30 + +--*/ +#include +#include "cmd_context/simplifier_cmds.h" +#include "cmd_context/cmd_context.h" +#include "cmd_context/cmd_util.h" +#include "cmd_context/parametric_cmd.h" +#include "model/model_smt2_pp.h" +#include "ast/ast_smt2_pp.h" +#include "ast/simplifiers/seq_simplifier.h" +#include "solver/simplifier_solver.h" + +typedef dependent_expr_simplifier simplifier; + +static simplifier_factory mk_and_then(cmd_context & ctx, sexpr * n) { + SASSERT(n->is_composite()); + unsigned num_children = n->get_num_children(); + if (num_children < 2) + throw cmd_exception("invalid and-then combinator, at least one argument expected", n->get_line(), n->get_pos()); + if (num_children == 2) + return sexpr2simplifier(ctx, n->get_child(1)); + vector args; + for (unsigned i = 1; i < num_children; i++) + args.push_back(sexpr2simplifier(ctx, n->get_child(i))); + simplifier_factory result = [args](ast_manager& m, const params_ref& p, dependent_expr_state& st) { + scoped_ptr s = alloc(seq_simplifier, m, p, st); + for (auto & simp : args) + s->add_simplifier(simp(m, p, st)); + return s.detach(); + }; + return result; +} + +static simplifier_factory mk_using_params(cmd_context & ctx, sexpr * n) { + SASSERT(n->is_composite()); + unsigned num_children = n->get_num_children(); + if (num_children < 2) + throw cmd_exception("invalid using-params combinator, at least one argument expected", n->get_line(), n->get_pos()); + if (num_children == 2) + return sexpr2simplifier(ctx, n->get_child(1)); + simplifier_factory t = sexpr2simplifier(ctx, n->get_child(1)); +#if 0 + // hoist parameter parsing code from tactic_cmds to share. + param_descrs descrs; + t->collect_param_descrs(descrs); + +#endif + return t; +// return using_params(t.detach(), p); +} + + +simplifier_factory sexpr2simplifier(cmd_context & ctx, sexpr * n) { + if (n->is_symbol()) { + simplifier_cmd * cmd = ctx.find_simplifier_cmd(n->get_symbol()); + if (cmd != nullptr) + return cmd->factory(); + throw cmd_exception("invalid tactic, unknown tactic ", n->get_symbol(), n->get_line(), n->get_pos()); + } + else if (n->is_composite()) { + unsigned num_children = n->get_num_children(); + if (num_children == 0) + throw cmd_exception("invalid tactic, arguments expected", n->get_line(), n->get_pos()); + sexpr * head = n->get_child(0); + if (!head->is_symbol()) + throw cmd_exception("invalid tactic, symbol expected", n->get_line(), n->get_pos()); + symbol const & cmd_name = head->get_symbol(); + if (cmd_name == "and-then" || cmd_name == "then") + return mk_and_then(ctx, n); + else + throw cmd_exception("invalid tactic, unknown tactic combinator ", cmd_name, n->get_line(), n->get_pos()); + } + else { + throw cmd_exception("invalid tactic, unexpected input", n->get_line(), n->get_pos()); + } +} + + +void help_simplifier(cmd_context & ctx) { + std::ostringstream buf; + buf << "combinators:\n"; + buf << "- (and-then +) executes the given simplifiers sequentially.\n"; + // buf << "- (using-params *) executes the given tactic using the given attributes, where ::= . ! is a syntax sugar for using-params.\n"; + buf << "builtin simplifiers:\n"; + for (simplifier_cmd* cmd : ctx.simplifiers()) { + buf << "- " << cmd->get_name() << " " << cmd->get_descr() << "\n"; + auto fac = cmd->factory(); + param_descrs descrs; + ast_manager& m = ctx.get_ast_manager(); + default_dependent_expr_state st(m); + params_ref p; + scoped_ptr s = fac(m, p, st); + s->collect_param_descrs(descrs); + descrs.display(buf, 4); + } + ctx.regular_stream() << '"' << escaped(buf.str()) << "\"\n"; +} + +ATOMIC_CMD(help_simplifier_cmd, "help-simplifier", "display the simplifier combinators and primitives.", help_simplifier(ctx);); + +class set_simplifier_cmd : public parametric_cmd { +protected: + sexpr * m_simplifier; +public: + set_simplifier_cmd(): + parametric_cmd("set-simplifier") {} + + char const * get_usage() const override { return " ( )*"; } + + void prepare(cmd_context & ctx) override { + parametric_cmd::prepare(ctx); + m_simplifier = nullptr; + } + + cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { + if (m_simplifier == nullptr) return CPK_SEXPR; + return parametric_cmd::next_arg_kind(ctx); + } + + void set_next_arg(cmd_context & ctx, sexpr * arg) override { + m_simplifier = arg; + } + + char const * get_main_descr() const override { return "update main solver with simplification pre-processing."; } + + void init_pdescrs(cmd_context & ctx, param_descrs & p) override { + } + + void execute(cmd_context & ctx) override { + if (!m_simplifier) + throw cmd_exception("set-simplifier needs a simplifier argument"); + + auto simplifier_factory = sexpr2simplifier(ctx, m_simplifier); + ctx.init_manager(); + auto* s = ctx.get_solver(); + if (s) + ctx.set_solver(mk_simplifier_solver(s, &simplifier_factory)); + } +}; + + +void install_core_simplifier_cmds(cmd_context & ctx) { + ctx.insert(alloc(set_simplifier_cmd)); + ctx.insert(alloc(help_simplifier_cmd)); +} diff --git a/src/cmd_context/simplifier_cmds.h b/src/cmd_context/simplifier_cmds.h new file mode 100644 index 000000000..e75376dfb --- /dev/null +++ b/src/cmd_context/simplifier_cmds.h @@ -0,0 +1,42 @@ +/*++ +Copyright (c) 2023 Microsoft Corporation + +Module Name: + + simplifier_cmds.h + +Abstract: + Support for simplifier commands in SMT 2.0 front-end + +Author: + + Nikolaj Bjorner (nbjorner) 2023-01-30 + +--*/ +#pragma once + +#include "ast/ast.h" +#include "ast/simplifiers/dependent_expr_state.h" +#include "util/params.h" +#include "util/cmd_context_types.h" +#include "util/ref.h" + + +class simplifier_cmd { + symbol m_name; + char const * m_descr; + simplifier_factory m_factory; +public: + simplifier_cmd(symbol const & n, char const * d, simplifier_factory f): + m_name(n), m_descr(d), m_factory(f) {} + + symbol get_name() const { return m_name; } + + char const * get_descr() const { return m_descr; } + + simplifier_factory factory() { return m_factory; } +}; + +simplifier_factory sexpr2simplifier(cmd_context & ctx, sexpr * n); + +void install_core_simplifier_cmds(cmd_context & ctx); diff --git a/src/cmd_context/tactic_manager.cpp b/src/cmd_context/tactic_manager.cpp index d4b3374b4..1691f5b45 100644 --- a/src/cmd_context/tactic_manager.cpp +++ b/src/cmd_context/tactic_manager.cpp @@ -7,7 +7,7 @@ Module Name: Abstract: - Collection of tactics & probes + Collection of tactics, simplifiers & probes Author: @@ -19,8 +19,21 @@ Notes: #include "cmd_context/tactic_manager.h" tactic_manager::~tactic_manager() { - finalize_tactic_cmds(); - finalize_probes(); + finalize_tactic_manager(); +} + +void tactic_manager::finalize_tactic_manager() { + std::for_each(m_tactics.begin(), m_tactics.end(), delete_proc()); + m_tactics.reset(); + m_name2tactic.reset(); + + std::for_each(m_simplifiers.begin(), m_simplifiers.end(), delete_proc()); + m_simplifiers.reset(); + m_name2simplifier.reset(); + + std::for_each(m_probes.begin(), m_probes.end(), delete_proc()); + m_probes.reset(); + m_name2probe.reset(); } void tactic_manager::insert(tactic_cmd * c) { @@ -30,6 +43,13 @@ void tactic_manager::insert(tactic_cmd * c) { m_tactics.push_back(c); } +void tactic_manager::insert(simplifier_cmd * c) { + symbol const & s = c->get_name(); + SASSERT(!m_name2simplifier.contains(s)); + m_name2simplifier.insert(s, c); + m_simplifiers.push_back(c); +} + void tactic_manager::insert(probe_info * p) { symbol const & s = p->get_name(); SASSERT(!m_name2probe.contains(s)); @@ -43,20 +63,15 @@ tactic_cmd * tactic_manager::find_tactic_cmd(symbol const & s) const { return c; } +simplifier_cmd * tactic_manager::find_simplifier_cmd(symbol const & s) const { + simplifier_cmd * c = nullptr; + m_name2simplifier.find(s, c); + return c; +} + probe_info * tactic_manager::find_probe(symbol const & s) const { probe_info * p = nullptr; m_name2probe.find(s, p); return p; } -void tactic_manager::finalize_tactic_cmds() { - std::for_each(m_tactics.begin(), m_tactics.end(), delete_proc()); - m_tactics.reset(); - m_name2tactic.reset(); -} - -void tactic_manager::finalize_probes() { - std::for_each(m_probes.begin(), m_probes.end(), delete_proc()); - m_probes.reset(); - m_name2probe.reset(); -} diff --git a/src/cmd_context/tactic_manager.h b/src/cmd_context/tactic_manager.h index 3a57d6297..ec60b0873 100644 --- a/src/cmd_context/tactic_manager.h +++ b/src/cmd_context/tactic_manager.h @@ -18,54 +18,37 @@ Notes: #pragma once #include "cmd_context/tactic_cmds.h" +#include "cmd_context/simplifier_cmds.h" #include "util/dictionary.h" class tactic_manager { protected: dictionary m_name2tactic; dictionary m_name2probe; + dictionary m_name2simplifier; ptr_vector m_tactics; + ptr_vector m_simplifiers; ptr_vector m_probes; - void finalize_tactic_cmds(); - void finalize_probes(); + void finalize_tactic_manager(); public: ~tactic_manager(); void insert(tactic_cmd * c); + void insert(simplifier_cmd* c); void insert(probe_info * p); tactic_cmd * find_tactic_cmd(symbol const & s) const; probe_info * find_probe(symbol const & s) const; + simplifier_cmd* find_simplifier_cmd(symbol const& s) const; unsigned num_tactics() const { return m_tactics.size(); } unsigned num_probes() const { return m_probes.size(); } tactic_cmd * get_tactic(unsigned i) const { return m_tactics[i]; } probe_info * get_probe(unsigned i) const { return m_probes[i]; } + + ptr_vector const& simplifiers() const { return m_simplifiers; } + ptr_vector const& tactics() const { return m_tactics; } + ptr_vector const& probes() const { return m_probes; } - typedef ptr_vector::const_iterator tactic_cmd_iterator; - tactic_cmd_iterator begin_tactic_cmds() const { return m_tactics.begin(); } - tactic_cmd_iterator end_tactic_cmds() const { return m_tactics.end(); } - class tactics_iterator { - tactic_manager const& m; - public: - tactics_iterator(tactic_manager const& m):m(m) {} - tactic_cmd_iterator begin() const { return m.begin_tactic_cmds(); } - tactic_cmd_iterator end() const { return m.end_tactic_cmds(); } - }; - tactics_iterator tactics() const { return tactics_iterator(*this); } - - typedef ptr_vector::const_iterator probe_iterator; - probe_iterator begin_probes() const { return m_probes.begin(); } - probe_iterator end_probes() const { return m_probes.end(); } - - class probes_iterator { - tactic_manager const& m; - public: - probes_iterator(tactic_manager const& m):m(m) {} - probe_iterator begin() const { return m.begin_probes(); } - probe_iterator end() const { return m.end_probes(); } - }; - - probes_iterator probes() const { return probes_iterator(*this); } }; diff --git a/src/sat/sat_solver/sat_smt_solver.cpp b/src/sat/sat_solver/sat_smt_solver.cpp index dbc2d9505..82aeded6f 100644 --- a/src/sat/sat_solver/sat_smt_solver.cpp +++ b/src/sat/sat_solver/sat_smt_solver.cpp @@ -700,6 +700,6 @@ private: solver* mk_sat_smt_solver(ast_manager& m, params_ref const& p) { - return mk_simplifier_solver(alloc(sat_smt_solver, m, p)); + return mk_simplifier_solver(alloc(sat_smt_solver, m, p), nullptr); } diff --git a/src/shell/main.cpp b/src/shell/main.cpp index 2fdd95d79..4c26d91d9 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -98,6 +98,7 @@ void display_usage() { std::cout << " -pmmd:name display Z3 module ('name') parameters in Markdown format.\n"; std::cout << " -pp:name display Z3 parameter description, if 'name' is not provided, then all module names are listed.\n"; std::cout << " -tactics[:name] display built-in tactics or if argument is given, display detailed information on tactic.\n"; + std::cout << " -simplifiers[:name] display built-in simplifiers or if argument is given, display detailed information on simplifier.\n"; std::cout << " -probes display avilable probes.\n"; std::cout << " --" << " all remaining arguments are assumed to be part of the input file name. This option allows Z3 to read files with strange names such as: -foo.smt2.\n"; std::cout << "\nResources:\n"; @@ -295,6 +296,12 @@ static void parse_cmd_line_args(std::string& input_file, int argc, char ** argv) else help_tactic(opt_arg, false); } + else if (strcmp(opt_name, "simplifiers") == 0) { + if (!opt_arg) + help_simplifiers(); + else + help_simplifier(opt_arg, false); + } else if (strcmp(opt_name, "tacticsmd") == 0 && opt_arg) help_tactic(opt_arg, true); else if (strcmp(opt_name, "probes") == 0) diff --git a/src/shell/smtlib_frontend.cpp b/src/shell/smtlib_frontend.cpp index 698f0f239..008142c1a 100644 --- a/src/shell/smtlib_frontend.cpp +++ b/src/shell/smtlib_frontend.cpp @@ -88,6 +88,22 @@ void help_tactics() { std::cout << "- " << cmd->get_name() << " " << cmd->get_descr() << "\n"; } +void help_simplifiers() { + struct cmp { + bool operator()(simplifier_cmd* a, simplifier_cmd* b) const { + return a->get_name().str() < b->get_name().str(); + } + }; + cmd_context ctx; + ptr_vector cmds; + for (auto cmd : ctx.simplifiers()) + cmds.push_back(cmd); + cmp lt; + std::sort(cmds.begin(), cmds.end(), lt); + for (auto cmd : cmds) + std::cout << "- " << cmd->get_name() << " " << cmd->get_descr() << "\n"; +} + void help_tactic(char const* name, bool markdown) { cmd_context ctx; for (auto cmd : ctx.tactics()) { @@ -103,6 +119,25 @@ void help_tactic(char const* name, bool markdown) { } } +void help_simplifier(char const* name, bool markdown) { + cmd_context ctx; + for (auto cmd : ctx.simplifiers()) { + if (cmd->get_name() == name) { + auto fac = cmd->factory(); + param_descrs descrs; + ast_manager& m = ctx.m(); + default_dependent_expr_state st(m); + params_ref p; + scoped_ptr s = fac(m, p, st); + s->collect_param_descrs(descrs); + if (markdown) + descrs.display_markdown(std::cout); + else + descrs.display(std::cout, 4); + } + } +} + void help_probes() { struct cmp { bool operator()(probe_info* a, probe_info* b) const { diff --git a/src/shell/smtlib_frontend.h b/src/shell/smtlib_frontend.h index 9769472f2..36818f3f6 100644 --- a/src/shell/smtlib_frontend.h +++ b/src/shell/smtlib_frontend.h @@ -21,7 +21,9 @@ Revision History: unsigned read_smtlib_file(char const * benchmark_file); unsigned read_smtlib2_commands(char const * command_file); void help_tactics(); +void help_simplifiers(); void help_probes(); void help_tactic(char const* name, bool markdown); +void help_simplifier(char const* name, bool markdown); diff --git a/src/solver/simplifier_solver.cpp b/src/solver/simplifier_solver.cpp index 17a39509e..faaf5b28f 100644 --- a/src/solver/simplifier_solver.cpp +++ b/src/solver/simplifier_solver.cpp @@ -89,7 +89,7 @@ class simplifier_solver : public solver { }; ast_manager& m; - scoped_ptr s; + solver_ref s; vector m_fmls; dep_expr_state m_preprocess_state; seq_simplifier m_preprocess; @@ -143,7 +143,7 @@ class simplifier_solver : public solver { public: - simplifier_solver(solver* s) : + simplifier_solver(solver* s, simplifier_factory* fac) : solver(s->get_manager()), m(s->get_manager()), s(s), @@ -152,7 +152,10 @@ public: m_assumptions(m), m_proof(m) { - init_preprocess(m, s->get_params(), m_preprocess, m_preprocess_state); + if (fac) + m_preprocess.add_simplifier((*fac)(m, s->get_params(), m_preprocess_state)); + else + init_preprocess(m, s->get_params(), m_preprocess, m_preprocess_state); } void assert_expr_core2(expr* t, expr* a) override { @@ -197,7 +200,8 @@ public: } model_ref m_cached_model; - void get_model_core(model_ref& m) override { + void get_model_core(model_ref& m) override { + CTRACE("simplifier", m_mc.get(), m_mc->display(tout)); if (m_cached_model) { m = m_cached_model; return; @@ -229,7 +233,7 @@ public: solver* translate(ast_manager& m, params_ref const& p) override { solver* new_s = s->translate(m, p); ast_translation tr(get_manager(), m); - simplifier_solver* result = alloc(simplifier_solver, new_s); + simplifier_solver* result = alloc(simplifier_solver, new_s, nullptr); // factory? for (dependent_expr const& f : m_fmls) result->m_fmls.push_back(dependent_expr(tr, f)); if (m_mc) @@ -311,7 +315,7 @@ public: }; -solver* mk_simplifier_solver(solver* s) { - return alloc(simplifier_solver, s); +solver* mk_simplifier_solver(solver* s, simplifier_factory* fac) { + return alloc(simplifier_solver, s, fac); } diff --git a/src/solver/simplifier_solver.h b/src/solver/simplifier_solver.h index 3d97a3869..afc701ca0 100644 --- a/src/solver/simplifier_solver.h +++ b/src/solver/simplifier_solver.h @@ -20,6 +20,9 @@ Author: class solver; class solver_factory; +class dependent_expr_simplifier; +class dependent_expr_state; +typedef std::function simplifier_factory; -solver * mk_simplifier_solver(solver * s); +solver * mk_simplifier_solver(solver * s, simplifier_factory* fac); diff --git a/src/tactic/arith/bound_simplifier_tactic.h b/src/tactic/arith/bound_simplifier_tactic.h index c8bc1318c..5451caa20 100644 --- a/src/tactic/arith/bound_simplifier_tactic.h +++ b/src/tactic/arith/bound_simplifier_tactic.h @@ -38,4 +38,5 @@ inline tactic* mk_bound_simplifier_tactic(ast_manager& m, params_ref const& p = /* ADD_TACTIC("bound-simplifier", "Simplify arithmetical expressions modulo bounds.", "mk_bound_simplifier_tactic(m, p)") + ADD_SIMPLIFIER("bound-simplifier", "Simplify arithmetical expressions modulo bounds.", "[](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(bound_simplifier, m, p, s); }") */ diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index 416997d45..032e964f9 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -69,4 +69,5 @@ inline tactic* mk_card2bv_tactic(ast_manager& m, params_ref const& p = params_re /* ADD_TACTIC("card2bv", "convert pseudo-boolean constraints to bit-vectors.", "mk_card2bv_tactic(m, p)") + ADD_SIMPLIFIER("card2bv", "convert pseudo-boolean constraints to bit-vectors.", "[](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(card2bv, m, p, s); }") */ diff --git a/src/tactic/arith/propagate_ineqs_tactic.h b/src/tactic/arith/propagate_ineqs_tactic.h index 1dbb0844b..68156c410 100644 --- a/src/tactic/arith/propagate_ineqs_tactic.h +++ b/src/tactic/arith/propagate_ineqs_tactic.h @@ -64,5 +64,6 @@ inline tactic* mk_propagate_ineqs_tactic(ast_manager& m, params_ref const& p = p /* ADD_TACTIC("propagate-ineqs", "propagate ineqs/bounds, remove subsumed inequalities.", "mk_propagate_ineqs_tactic(m, p)") + ADD_SIMPLIFIER("propagate-ineqs", "propagate ineqs/bounds, remove subsumed inequalities.", "[](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(bound_simplifier, m, p, s); }") */ diff --git a/src/tactic/bv/bv_bounds_tactic.h b/src/tactic/bv/bv_bounds_tactic.h index 8153ad52f..eb75ceca7 100644 --- a/src/tactic/bv/bv_bounds_tactic.h +++ b/src/tactic/bv/bv_bounds_tactic.h @@ -37,6 +37,7 @@ Contextual bounds simplification tactic. --*/ #pragma once #include "tactic/tactic.h" +#include "ast/simplifiers/bv_bounds_simplifier.h" tactic * mk_bv_bounds_tactic(ast_manager & m, params_ref const & p = params_ref()); @@ -45,6 +46,7 @@ tactic * mk_dom_bv_bounds_tactic(ast_manager & m, params_ref const & p = params_ /* ADD_TACTIC("propagate-bv-bounds", "propagate bit-vector bounds by simplifying implied or contradictory bounds.", "mk_bv_bounds_tactic(m, p)") + ADD_SIMPLIFIER("propagate-bv-bounds", "propagate bit-vector bounds by simplifying implied or contradictory bounds.", "mk_bv_bounds_simplifier") ADD_TACTIC("propagate-bv-bounds2", "propagate bit-vector bounds by simplifying implied or contradictory bounds.", "mk_dom_bv_bounds_tactic(m, p)") diff --git a/src/tactic/core/demodulator_tactic.h b/src/tactic/core/demodulator_tactic.h index 9ffaa6ca9..507b4e5c5 100644 --- a/src/tactic/core/demodulator_tactic.h +++ b/src/tactic/core/demodulator_tactic.h @@ -100,4 +100,5 @@ inline tactic * mk_demodulator_tactic(ast_manager& m, params_ref const& p = para /* ADD_TACTIC("demodulator", "extracts equalities from quantifiers and applies them to simplify.", "mk_demodulator_tactic(m, p)") + ADD_SIMPLIFIER("demodulator", "extracts equalities from quantifiers and applies them to simplify.", "[](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(demodulator_simplifier, m, p, s); }") */ diff --git a/src/tactic/core/distribute_forall_tactic.h b/src/tactic/core/distribute_forall_tactic.h index 328a62b2f..419eba71e 100644 --- a/src/tactic/core/distribute_forall_tactic.h +++ b/src/tactic/core/distribute_forall_tactic.h @@ -50,5 +50,6 @@ inline tactic * mk_distribute_forall_tactic(ast_manager& m, params_ref const& p /* ADD_TACTIC("distribute-forall", "distribute forall over conjunctions.", "mk_distribute_forall_tactic(m, p)") + ADD_SIMPLIFIER("distribute-forall", "distribute forall over conjunctions.", "[](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(distribute_forall_simplifier, m, p, s); }") */ diff --git a/src/tactic/core/dom_simplify_tactic.h b/src/tactic/core/dom_simplify_tactic.h index 2dba378b7..795db0f26 100644 --- a/src/tactic/core/dom_simplify_tactic.h +++ b/src/tactic/core/dom_simplify_tactic.h @@ -56,5 +56,6 @@ inline tactic* mk_dom_simplify_tactic(ast_manager& m, params_ref const& p) { /* ADD_TACTIC("dom-simplify", "apply dominator simplification rules.", "mk_dom_simplify_tactic(m, p)") +ADD_SIMPLIFIER("dom-simplify", "apply dominator simplification rules.", "[](auto& m, auto& p, auto& s) -> dependent_expr_simplifier* { return alloc(dominator_simplifier, m, s, mk_expr_substitution_simplifier(m), p); }") */ diff --git a/src/tactic/core/elim_uncnstr2_tactic.h b/src/tactic/core/elim_uncnstr2_tactic.h index f1c9b9bd7..fc249da64 100644 --- a/src/tactic/core/elim_uncnstr2_tactic.h +++ b/src/tactic/core/elim_uncnstr2_tactic.h @@ -118,4 +118,5 @@ inline tactic * mk_elim_uncnstr2_tactic(ast_manager & m, params_ref const & p = /* ADD_TACTIC("elim-uncnstr2", "eliminate unconstrained variables.", "mk_elim_uncnstr2_tactic(m, p)") + ADD_SIMPLIFIER("elim-unconstrained", "eliminate unconstrained variables.", "[](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(elim_unconstrained, m, s); }") */ diff --git a/src/tactic/core/eliminate_predicates_tactic.h b/src/tactic/core/eliminate_predicates_tactic.h index 4d90b1acf..b53892e8b 100644 --- a/src/tactic/core/eliminate_predicates_tactic.h +++ b/src/tactic/core/eliminate_predicates_tactic.h @@ -64,4 +64,5 @@ inline tactic * mk_eliminate_predicates_tactic(ast_manager& m, params_ref const& /* ADD_TACTIC("elim-predicates", "eliminate predicates.", "mk_eliminate_predicates_tactic(m, p)") + ADD_SIMPLIFIER("elim-predicates", "eliminate predicates.", "[](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(eliminate_predicates, m, s); }") */ diff --git a/src/tactic/core/propagate_values2_tactic.h b/src/tactic/core/propagate_values2_tactic.h index e380ce7d3..466ef87a1 100644 --- a/src/tactic/core/propagate_values2_tactic.h +++ b/src/tactic/core/propagate_values2_tactic.h @@ -55,4 +55,5 @@ inline tactic * mk_propagate_values2_tactic(ast_manager & m, params_ref const & /* ADD_TACTIC("propagate-values2", "propagate constants.", "mk_propagate_values2_tactic(m, p)") + ADD_SIMPLIFIER("propagate-values", "propagate constants.", "[](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(propagate_values, m, p, s); }") */ diff --git a/src/tactic/core/reduce_args_tactic.h b/src/tactic/core/reduce_args_tactic.h index fa90837bf..4bfb7ed2f 100644 --- a/src/tactic/core/reduce_args_tactic.h +++ b/src/tactic/core/reduce_args_tactic.h @@ -79,5 +79,7 @@ inline tactic* mk_reduce_args_tactic2(ast_manager& m, params_ref const& p = para } /* ADD_TACTIC("reduce-args2", "reduce the number of arguments of function applications, when for all occurrences of a function f the i-th is a value.", "mk_reduce_args_tactic2(m, p)") + ADD_SIMPLIFIER("reduce-args", "reduce the number of arguments of function applications, when for all occurrences of a function f the i-th is a value.", "[](auto& m, auto& p, auto& s) -> dependent_expr_simplifier* { return mk_reduce_args_simplifier(m, s, p); }") + */ diff --git a/src/tactic/core/solve_eqs_tactic.h b/src/tactic/core/solve_eqs_tactic.h index fec46bf04..af27d4576 100644 --- a/src/tactic/core/solve_eqs_tactic.h +++ b/src/tactic/core/solve_eqs_tactic.h @@ -79,4 +79,5 @@ inline tactic * mk_solve_eqs_tactic(ast_manager& m, params_ref const& p = params /* ADD_TACTIC("solve-eqs", "solve for variables.", "mk_solve_eqs_tactic(m, p)") + ADD_SIMPLIFIER("solve-eqs", "solve for variables.", "[](auto& m, auto& p, auto &s) -> dependent_expr_simplifier* { return alloc(euf::solve_eqs, m, s); }") */