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:
parent
2cc4422018
commit
dbe986fdf7
10 changed files with 97 additions and 87 deletions
|
|
@ -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 };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -384,6 +384,8 @@ bool pattern_inference_cfg::contains_subpattern::operator()(expr * n) {
|
|||
break;
|
||||
case AST_VAR:
|
||||
break;
|
||||
case AST_QUANTIFIER:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue