3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-06-10 19:07:18 +00:00

move closure conversion to solver internalization

- only the internalizer performs closure conversion
- theory_array treats propagation of lambdas similar to stores
- ho_matcher treats top-level flex patterns as first-order
- pattern-inference fix to handle quantifiers (lambdas) in patterns that are computed
This commit is contained in:
Nikolaj Bjorner 2026-05-30 18:41:37 -07:00
parent 2cc4422018
commit dbe986fdf7
10 changed files with 97 additions and 87 deletions

View file

@ -689,20 +689,21 @@ namespace euf {
});
if (!is_ho)
return { q, p };
ptr_vector<expr> todo;
vector<std::pair<expr*, unsigned>> todo;
ptr_buffer<var> bound;
expr_ref_vector cache(m);
unsigned nb = q->get_num_decls();
bool contains_pat2abs = m_pat2abs.contains(p);
todo.push_back(p);
SASSERT(m.is_pattern(p));
todo.push_back({p, 0});
while (!todo.empty()) {
auto t = todo.back();
auto [t, lvl] = todo.back();
if (is_var(t)) {
cache.setx(t->get_id(), t);
todo.pop_back();
continue;
}
if (m_unitary.is_flex(0, t) || m.is_lambda_def(t) || is_lambda(t)) {
if ((m_unitary.is_flex(0, t) && lvl > 1) || m.is_lambda_def(t) || is_lambda(t)) {
if (!contains_pat2abs)
m_pat2abs.insert_if_not_there(p, svector<std::pair<unsigned, expr*>>()).push_back({ nb, t });
auto v = m.mk_var(nb++, t->get_sort());
@ -720,7 +721,7 @@ namespace euf {
cache.reserve(arg->get_id() + 1);
expr* arg1 = cache.get(arg->get_id());
if (!arg1)
todo.push_back(arg);
todo.push_back({arg, lvl + 1});
else
args.push_back(arg1);
}
@ -736,6 +737,9 @@ namespace euf {
}
}
p1 = to_app(cache.get(p->get_id()));
if (p1 == p)
return {q, p};
expr_free_vars free_vars;
free_vars(p1);
app_ref_vector new_ground(m);
@ -762,6 +766,8 @@ namespace euf {
auto body = q->get_expr();
if (!new_patterns.empty()) {
ptr_vector<app> pats;
CTRACE(ho_matching, !m.is_pattern(p1),
tout << mk_pp(p, m) << "\n" << mk_pp(p1, m) << "\n";);
VERIFY(m.is_pattern(p1, pats));
for (auto p : new_patterns) // patterns for variables that are not free in new pattern
pats.push_back(p);
@ -800,6 +806,10 @@ namespace euf {
if (!contains_pat2abs)
trail().push(insert_map(m_pat2abs, p));
TRACE(ho_matching, tout << mk_pp(q, m) << "\n"
<< mk_pp(p, m) << "\n->\n"
<< mk_pp(q1, m) << "\n"
<< mk_pp(p1, m) << "\n");
return { q1, p1 };
}

View file

@ -193,43 +193,7 @@ void defined_names::impl::mk_definition(expr * e, app * n, sort_ref_buffer & var
else if (m.is_term_ite(e)) {
bound_vars(var_sorts, var_names, MK_OR(MK_NOT(to_app(e)->get_arg(0)), MK_EQ(n, to_app(e)->get_arg(1))), n, defs);
bound_vars(var_sorts, var_names, MK_OR(to_app(e)->get_arg(0), MK_EQ(n, to_app(e)->get_arg(2))), n, defs);
}
else if (is_lambda(e)) {
// n(y) = \x . M[x,y]
// =>
// n(y)[x] = M, forall x y
//
// NB. The pattern is incomplete.
// consider store(a, i, v) == \lambda j . if i = j then v else a[j]
// the instantiation rules for store(a, i, v) are:
// store(a, i, v)[j] = if i = j then v else a[j] with patterns {a[j], store(a, i, v)} { store(a, i, v)[j] }
// The first pattern is not included.
// TBD use a model-based scheme for extracting instantiations instead of
// using multi-patterns.
//
quantifier* q = to_quantifier(e);
expr_ref_vector args(m);
expr_ref n2(m), n3(m);
var_shifter vs(m);
vs(n, q->get_num_decls(), n2);
args.push_back(n2);
var_sorts.append(q->get_num_decls(), q->get_decl_sorts());
var_names.append(q->get_num_decls(), q->get_decl_names());
for (unsigned i = 0; i < q->get_num_decls(); ++i) {
args.push_back(m.mk_var(q->get_num_decls() - i - 1, q->get_decl_sort(i)));
}
array_util autil(m);
func_decl * f = nullptr;
if (autil.is_as_array(n2, f)) {
n3 = m.mk_app(f, args.size()-1, args.data() + 1);
}
else {
n3 = autil.mk_select(args.size(), args.data());
}
bound_vars(var_sorts, var_names, MK_EQ(q->get_expr(), n3), to_app(n3), defs, m.lambda_def_qid());
}
}
else {
bound_vars(var_sorts, var_names, MK_EQ(e, n), n, defs);
}

View file

@ -100,7 +100,7 @@ class name_quantifier_labels : public name_exprs_core {
public:
pred(ast_manager & m):m(m) {}
bool operator()(expr * t) override {
return is_quantifier(t) || m.is_label(t);
return (is_quantifier(t) && !is_lambda(t)) || m.is_label(t);
}
};
@ -127,7 +127,7 @@ class name_nested_formulas : public name_exprs_core {
TRACE(name_exprs, tout << "name_nested_formulas::pred:\n" << mk_ismt2_pp(t, m) << "\n";);
if (is_app(t))
return to_app(t)->get_family_id() == m.get_basic_family_id() && to_app(t)->get_num_args() > 0 && t != m_root;
return m.is_label(t) || is_quantifier(t);
return m.is_label(t) || (is_quantifier(t) && !is_lambda(t));
}
};

View file

@ -384,6 +384,8 @@ bool pattern_inference_cfg::contains_subpattern::operator()(expr * n) {
break;
case AST_VAR:
break;
case AST_QUANTIFIER:
break;
default:
UNREACHABLE();
}