mirror of
https://github.com/Z3Prover/z3
synced 2025-05-07 15:55:46 +00:00
Add simplification customization for SMTLIB2
Add the ability to customize incremental pre-processing simplification for the SMTLIB2 front-end. The main new capability is to use pre-processing tactics in incremental mode that were previously not available. The main new capabilities are - solve-eqs - reduce-args - elim-unconstrained There are several more. Documentation and exposed simplifiers are populated incrementally. The current set of supported simplifiers can be inspected by using z3 with the --simplifiers flag or referring to https://microsoft.github.io/z3guide/docs/strategies/simplifiers Some pending features are: - add the ability to update parameters to simplifiers similar to how tactics can be controlled using parameters. - expose simplification solvers over the binary API.
This commit is contained in:
parent
dd0decfe5d
commit
6022c17131
32 changed files with 370 additions and 69 deletions
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -318,7 +318,7 @@ protected:
|
|||
void register_builtin_ops(decl_plugin * p);
|
||||
void load_plugin(symbol const & name, bool install_names, svector<family_id>& 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<cmd_context*>(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);
|
||||
|
|
158
src/cmd_context/simplifier_cmds.cpp
Normal file
158
src/cmd_context/simplifier_cmds.cpp
Normal file
|
@ -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<sstream>
|
||||
#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<simplifier_factory> 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<seq_simplifier> 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 <simplifier>+) executes the given simplifiers sequentially.\n";
|
||||
// buf << "- (using-params <tactic> <attribute>*) executes the given tactic using the given attributes, where <attribute> ::= <keyword> <value>. ! 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<dependent_expr_simplifier> 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 "<tactic> (<keyword> <value>)*"; }
|
||||
|
||||
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));
|
||||
}
|
42
src/cmd_context/simplifier_cmds.h
Normal file
42
src/cmd_context/simplifier_cmds.h
Normal file
|
@ -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);
|
|
@ -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<tactic_cmd>());
|
||||
m_tactics.reset();
|
||||
m_name2tactic.reset();
|
||||
|
||||
std::for_each(m_simplifiers.begin(), m_simplifiers.end(), delete_proc<simplifier_cmd>());
|
||||
m_simplifiers.reset();
|
||||
m_name2simplifier.reset();
|
||||
|
||||
std::for_each(m_probes.begin(), m_probes.end(), delete_proc<probe_info>());
|
||||
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<tactic_cmd>());
|
||||
m_tactics.reset();
|
||||
m_name2tactic.reset();
|
||||
}
|
||||
|
||||
void tactic_manager::finalize_probes() {
|
||||
std::for_each(m_probes.begin(), m_probes.end(), delete_proc<probe_info>());
|
||||
m_probes.reset();
|
||||
m_name2probe.reset();
|
||||
}
|
||||
|
|
|
@ -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<tactic_cmd*> m_name2tactic;
|
||||
dictionary<probe_info*> m_name2probe;
|
||||
dictionary<simplifier_cmd*> m_name2simplifier;
|
||||
ptr_vector<tactic_cmd> m_tactics;
|
||||
ptr_vector<simplifier_cmd> m_simplifiers;
|
||||
ptr_vector<probe_info> 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<simplifier_cmd> const& simplifiers() const { return m_simplifiers; }
|
||||
ptr_vector<tactic_cmd> const& tactics() const { return m_tactics; }
|
||||
ptr_vector<probe_info> const& probes() const { return m_probes; }
|
||||
|
||||
typedef ptr_vector<tactic_cmd>::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<probe_info>::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); }
|
||||
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue