3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-20 18:20:22 +00:00

turn on ho-matcher for completion

This commit is contained in:
Nikolaj Bjorner 2025-07-07 14:08:51 +02:00
parent 1b3c3c2716
commit 0c5b0c3724
10 changed files with 166 additions and 63 deletions

View file

@ -70,7 +70,8 @@ namespace euf {
m_canonical_proofs(m),
// m_infer_patterns(m, m_smt_params),
m_deps(m),
m_rewriter(m) {
m_rewriter(m),
m_matcher(m, m_trail) {
m_tt = m_egraph.mk(m.mk_true(), 0, 0, nullptr);
m_ff = m_egraph.mk(m.mk_false(), 0, 0, nullptr);
m_rewriter.set_order_eq(true);
@ -92,6 +93,39 @@ namespace euf {
m_egraph.add_plugin(alloc(arith_plugin, m_egraph));
m_egraph.add_plugin(alloc(bv_plugin, m_egraph));
std::function<void(ho_subst&)> on_match =
[&](ho_subst& s) {
IF_VERBOSE(1, s.display(verbose_stream() << "on-match\n") << "\n");
auto& b = *m_ho_binding;
auto* hopat = b.m_pattern;
auto* hoq = b.m_q;
auto* q = m_matcher.hoq2q(hoq);
// shrink binding
expr_ref_vector binding(m);
for (unsigned i = 0; i < s.size(); ++i)
binding.push_back(s.get(i));
binding.reverse();
if (binding.size() > q->get_num_decls()) {
bool change = true;
while (change) {
change = false;
for (unsigned i = binding.size(); i-- > 0;) {
var_subst sub(m, false);
auto r = sub(binding.get(i), binding);
change |= r != binding.get(i);
binding[i] = r;
}
}
}
binding.shrink(q->get_num_decls());
binding.reverse();
IF_VERBOSE(1, verbose_stream() << binding << "\n");
apply_binding(b, q, binding);
};
m_matcher.set_on_match(on_match);
}
completion::~completion() {
@ -108,6 +142,7 @@ namespace euf {
void completion::updt_params(params_ref const& p) {
smt_params_helper sp(p);
m_max_instantiations = sp.qi_max_instances();
// m_max_generation = sp.qi_max_generation();
}
struct completion::push_watch_rule : public trail {
@ -222,6 +257,7 @@ namespace euf {
void completion::add_constraint(expr* f, proof* pr, expr_dependency* d) {
if (m_egraph.inconsistent())
return;
TRACE(euf_completion, tout << mk_pp(f, m) << "\n");
auto add_children = [&](enode* n) {
for (auto* ch : enode_args(n))
m_nodes_to_canonize.push_back(ch);
@ -234,12 +270,14 @@ namespace euf {
m_egraph.merge(a, b, to_ptr(push_pr_dep(pr, d)));
add_children(a);
add_children(b);
m_should_propagate = true;
}
else if (m.is_not(f, f)) {
enode* n = mk_enode(f);
auto j = to_ptr(push_pr_dep(pr, d));
m_egraph.new_diseq(n, j);
add_children(n);
m_should_propagate = true;
}
else {
enode* n = mk_enode(f);
@ -255,13 +293,15 @@ namespace euf {
q = to_quantifier(tmp);
}
#endif
ptr_vector<app> ground;
for (unsigned i = 0; i < q->get_num_patterns(); ++i) {
auto p = to_app(q->get_pattern(i));
auto q1 = m_matcher.compile_ho_pattern(q, p);
ptr_vector<app> ground;
mam::ground_subterms(p, ground);
for (expr* g : ground)
mk_enode(g);
m_mam->add_pattern(q, p);
m_mam->add_pattern(q1, p);
}
m_q2dep.insert(q, { pr, d});
get_trail().push(insert_obj_map(m_q2dep, q));
@ -295,7 +335,7 @@ namespace euf {
if (m.is_true(n->get_root()->get_expr()))
return l_false;
}
if (m_side_condition_solver) {
if (m_side_condition_solver && m_propagate_with_solver) {
expr_dependency* sd = nullptr;
if (m_side_condition_solver->is_true(f, pr, sd)) {
add_constraint(f, pr, sd);
@ -363,6 +403,7 @@ namespace euf {
}
void completion::propagate_all_rules() {
flet<bool> _propagate_with_solver(m_propagate_with_solver, true);
for (auto* r : m_rules)
if (!r->m_in_queue)
r->m_in_queue = true,
@ -456,6 +497,8 @@ namespace euf {
void completion::on_binding(quantifier* q, app* pat, enode* const* binding, unsigned max_global, unsigned min_top, unsigned max_top) {
if (should_stop())
return;
if (max_top >= m_max_generation)
return;
auto* b = alloc_binding(q, pat, binding, max_global, min_top, max_top);
if (!b)
return;
@ -487,23 +530,21 @@ namespace euf {
void completion::apply_binding(binding& b) {
if (should_stop())
return;
#if 0
if (is_ho_binding(b))
apply_ho_binding(b);
else
#endif
{
expr_ref_vector _binding(m);
quantifier* q = b.m_q;
for (unsigned i = 0; i < q->get_num_decls(); ++i)
_binding.push_back(b.m_nodes[i]->get_expr());
apply_binding(b, _binding);
expr_ref_vector _binding(m);
quantifier* q = b.m_q;
for (unsigned i = 0; i < q->get_num_decls(); ++i)
_binding.push_back(b.m_nodes[i]->get_expr());
if (m_matcher.is_ho_pattern(b.m_pattern)) {
flet<binding*> set_binding(m_ho_binding, &b);
m_matcher.refine_ho_match(b.m_pattern, _binding);
}
else
apply_binding(b, q, _binding);
}
void completion::apply_binding(binding& b, expr_ref_vector const& s) {
void completion::apply_binding(binding& b, quantifier* q, expr_ref_vector const& s) {
var_subst subst(m);
quantifier* q = b.m_q;
expr_ref r = subst(q->get_expr(), s);
scoped_generation sg(*this, b.m_max_top_generation + 1);
auto [pr, d] = get_dependency(q);
@ -512,10 +553,8 @@ namespace euf {
add_constraint(r, pr, d);
propagate_rules();
m_egraph.propagate();
m_should_propagate = true;
}
void completion::read_egraph() {
if (m_egraph.inconsistent()) {
auto* d = explain_conflict();

View file

@ -25,6 +25,7 @@ Author:
#include "ast/simplifiers/dependent_expr_state.h"
#include "ast/euf/euf_egraph.h"
#include "ast/euf/euf_mam.h"
#include "ast/euf/ho_matcher.h"
#include "ast/rewriter/th_rewriter.h"
// include "ast/pattern/pattern_inference.h"
#include "params/smt_params.h"
@ -133,18 +134,22 @@ namespace euf {
bindings m_bindings;
scoped_ptr<binding> m_tmp_binding;
unsigned m_tmp_binding_capacity = 0;
binding* m_ho_binding = nullptr;
expr_dependency_ref_vector m_deps;
obj_map<quantifier, std::pair<proof*, expr_dependency*>> m_q2dep;
vector<std::pair<proof_ref, expr_dependency*>> m_pr_dep;
unsigned m_epoch = 0;
unsigned_vector m_epochs;
th_rewriter m_rewriter;
ho_matcher m_matcher;
stats m_stats;
scoped_ptr<side_condition_solver> m_side_condition_solver;
ptr_vector<conditional_rule> m_rules;
bool m_has_new_eq = false;
bool m_should_propagate = false;
bool m_propagate_with_solver = false;
unsigned m_max_instantiations = std::numeric_limits<unsigned>::max();
unsigned m_max_generation = 10;
unsigned m_generation = 0;
vector<ptr_vector<conditional_rule>> m_rule_watch;
@ -176,7 +181,7 @@ namespace euf {
binding* alloc_binding(quantifier* q, app* pat, euf::enode* const* _binding, unsigned max_generation, unsigned min_top, unsigned max_top);
void insert_binding(binding* b);
void apply_binding(binding& b);
void apply_binding(binding& b, expr_ref_vector const& s);
void apply_binding(binding& b, quantifier* q, expr_ref_vector const& s);
void flush_binding_queue();
vector<ptr_vector<binding>> m_queue;