mirror of
https://github.com/Z3Prover/z3
synced 2026-06-26 02:20:58 +00:00
Merge branch 'master' into c3
This commit is contained in:
commit
043c6c0ad1
259 changed files with 18907 additions and 3725 deletions
|
|
@ -133,7 +133,7 @@ namespace euf {
|
|||
// Instructions
|
||||
//
|
||||
// ------------------------------------
|
||||
typedef enum {
|
||||
typedef enum : uint8_t {
|
||||
INIT1=0, INIT2, INIT3, INIT4, INIT5, INIT6, INITN, INITAC,
|
||||
BIND1, BIND2, BIND3, BIND4, BIND5, BIND6, BINDN,
|
||||
YIELD1, YIELD2, YIELD3, YIELD4, YIELD5, YIELD6, YIELDN,
|
||||
|
|
@ -239,6 +239,7 @@ namespace euf {
|
|||
unsigned short m_num_args;
|
||||
unsigned m_ireg;
|
||||
unsigned m_oreg;
|
||||
unsigned m_curr_generation;
|
||||
};
|
||||
|
||||
struct get_cgr : public instruction {
|
||||
|
|
@ -1926,28 +1927,38 @@ namespace euf {
|
|||
m_max_generation = std::max(m_max_generation, n->generation());
|
||||
}
|
||||
|
||||
void get_f_app(func_decl* lbl, unsigned num_expected_args, enode* curr, enode*& matching_cgr, enode*& min_gen_match) {
|
||||
if (curr->get_decl() == lbl && curr->num_args() == num_expected_args) {
|
||||
if (curr->is_cgr() && !matching_cgr)
|
||||
matching_cgr = curr;
|
||||
if (!min_gen_match || min_gen_match->generation() > curr->generation())
|
||||
min_gen_match = curr;
|
||||
}
|
||||
}
|
||||
|
||||
// We have to provide the number of expected arguments because we have flat-assoc applications such as +.
|
||||
// Flat-assoc applications may have arbitrary number of arguments.
|
||||
enode * get_first_f_app(func_decl * lbl, unsigned num_expected_args, enode * first) {
|
||||
enode *matching_cgr = nullptr, *min_gen_match = nullptr;
|
||||
for (enode* curr : euf::enode_class(first)) {
|
||||
if (curr->get_decl() == lbl && curr->is_cgr() && curr->num_args() == num_expected_args) {
|
||||
update_max_generation(curr, first);
|
||||
return curr;
|
||||
}
|
||||
get_f_app(lbl, num_expected_args, curr, matching_cgr, min_gen_match);
|
||||
curr = curr->get_next();
|
||||
}
|
||||
return nullptr;
|
||||
if (matching_cgr)
|
||||
update_max_generation(min_gen_match, first);
|
||||
return matching_cgr;
|
||||
}
|
||||
|
||||
enode * get_next_f_app(func_decl * lbl, unsigned num_expected_args, enode * first, enode * curr) {
|
||||
curr = curr->get_next();
|
||||
enode *matching_cgr = nullptr, *min_gen_match = nullptr;
|
||||
while (curr != first) {
|
||||
if (curr->get_decl() == lbl && curr->is_cgr() && curr->num_args() == num_expected_args) {
|
||||
update_max_generation(curr, first);
|
||||
return curr;
|
||||
}
|
||||
get_f_app(lbl, num_expected_args, curr, matching_cgr, min_gen_match);
|
||||
curr = curr->get_next();
|
||||
}
|
||||
return nullptr;
|
||||
if (matching_cgr)
|
||||
update_max_generation(min_gen_match, first);
|
||||
return matching_cgr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2563,6 +2574,7 @@ namespace euf {
|
|||
m_backtrack_stack[m_top].m_instr = m_pc; \
|
||||
m_backtrack_stack[m_top].m_old_max_generation = m_curr_max_generation; \
|
||||
m_backtrack_stack[m_top].m_curr = m_app; \
|
||||
const_cast<bind*>(static_cast<bind const*>(m_pc))->m_curr_generation = m_max_generation; \
|
||||
m_top++;
|
||||
|
||||
BIND_COMMON();
|
||||
|
|
@ -2829,7 +2841,8 @@ namespace euf {
|
|||
goto backtrack; \
|
||||
} \
|
||||
bp.m_curr = m_app; \
|
||||
TRACE(mam_int, tout << "bind next candidate:\n" << mk_ll_pp(m_app->get_expr(), m);); \
|
||||
m_max_generation = m_b->m_curr_generation; \
|
||||
TRACE(mam_int, tout << "bind next candidate:\n" << mk_ll_pp(m_app->get_expr(), m);); \
|
||||
m_oreg = m_b->m_oreg
|
||||
|
||||
BBIND_COMMON();
|
||||
|
|
@ -4059,4 +4072,4 @@ void euf::mam::ground_subterms(expr* e, ptr_vector<app>& ground) {
|
|||
|
||||
euf::mam* euf::mam::mk(euf::mam_solver& ctx, euf::on_binding_callback& em) {
|
||||
return alloc(mam_impl, ctx, em, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ namespace euf {
|
|||
}
|
||||
|
||||
void ho_matcher::search() {
|
||||
IF_VERBOSE(1, display(verbose_stream()));
|
||||
IF_VERBOSE(10, display(verbose_stream()));
|
||||
|
||||
while (m.inc()) {
|
||||
// Q, B -> Q', B'. Push work on the backtrack stack and new work items
|
||||
|
|
@ -77,7 +77,7 @@ namespace euf {
|
|||
break;
|
||||
}
|
||||
|
||||
IF_VERBOSE(1, display(verbose_stream() << "ho_matcher: done\n"));
|
||||
IF_VERBOSE(10, display(verbose_stream() << "ho_matcher: done\n"));
|
||||
}
|
||||
|
||||
void ho_matcher::backtrack() {
|
||||
|
|
@ -92,7 +92,7 @@ namespace euf {
|
|||
while (!m_backtrack.empty()) {
|
||||
auto& wi = *m_backtrack.back();
|
||||
bool st = consume_work(wi);
|
||||
IF_VERBOSE(3, display(verbose_stream() << "ho_matcher::consume_work: " << wi.pat << " =?= " << wi.t << " -> " << (st?"true":"false") << "\n"););
|
||||
TRACE(ho_matching, display(tout << "ho_matcher::consume_work: " << mk_bounded_pp(wi.pat, m) << " =?= " << mk_bounded_pp(wi.t, m) << " -> " << (st?"true":"false") << "\n"););
|
||||
if (st) {
|
||||
if (m_goals.empty())
|
||||
m_on_match(m_subst);
|
||||
|
|
@ -110,7 +110,11 @@ namespace euf {
|
|||
}
|
||||
|
||||
lbool ho_matcher::are_equal(unsigned o1, expr* p, unsigned o2, expr* t) const {
|
||||
SASSERT(p->get_sort() == t->get_sort());
|
||||
if (p->get_sort() != t->get_sort()) {
|
||||
TRACE(ho_matching, tout << "sort mismatch: " << mk_pp(p, m) << " : " << mk_pp(p->get_sort(), m)
|
||||
<< " vs " << mk_pp(t, m) << " : " << mk_pp(t->get_sort(), m) << "\n";);
|
||||
return l_false;
|
||||
}
|
||||
if (o1 == o2 && p == t)
|
||||
return l_true;
|
||||
|
||||
|
|
@ -239,25 +243,19 @@ namespace euf {
|
|||
return r;
|
||||
}
|
||||
|
||||
// We assume that m_rewriter should produce
|
||||
// something amounting to weak-head normal form WHNF
|
||||
expr_ref ho_matcher::whnf_star(expr *e, unsigned offset) const {
|
||||
expr_ref r(e, m);
|
||||
while (true) {
|
||||
auto q = whnf(r, offset);
|
||||
if (q == r)
|
||||
return r;
|
||||
r = q;
|
||||
}
|
||||
}
|
||||
|
||||
void ho_matcher::reduce(match_goal& wi) {
|
||||
while (true) {
|
||||
expr_ref r = whnf(wi.pat, wi.pat_offset());
|
||||
if (r == wi.pat)
|
||||
break;
|
||||
IF_VERBOSE(3, verbose_stream() << "ho_matcher::reduce: " << wi.pat << " -> " << r << "\n";);
|
||||
wi.pat = r;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
expr_ref r = whnf(wi.t, wi.term_offset());
|
||||
if (r == wi.t)
|
||||
break;
|
||||
IF_VERBOSE(3, verbose_stream() << "ho_matcher::reduce: " << wi.t << " -> " << r << "\n";);
|
||||
wi.t = r;
|
||||
}
|
||||
wi.pat = whnf_star(wi.pat, wi.pat_offset());
|
||||
wi.t = whnf_star(wi.t, wi.term_offset());
|
||||
}
|
||||
|
||||
bool ho_matcher::consume_work(match_goal &wi) {
|
||||
|
|
@ -288,7 +286,6 @@ namespace euf {
|
|||
break;
|
||||
}
|
||||
|
||||
|
||||
// v >= offset
|
||||
// v - offset |-> t
|
||||
if (is_meta_var(p, wi.pat_offset()) && is_closed(t, 0, wi.term_offset())) {
|
||||
|
|
@ -299,7 +296,6 @@ namespace euf {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
// N = \ x. T => ((shift1 N) x) = T
|
||||
if (is_lambda(t) && !is_lambda(p)) {
|
||||
auto q = to_quantifier(t);
|
||||
|
|
@ -318,6 +314,43 @@ namespace euf {
|
|||
return true;
|
||||
}
|
||||
|
||||
// \x . N = T => N = ((shift1 T) x)
|
||||
if (is_lambda(p) && !is_lambda(t)) {
|
||||
auto q = to_quantifier(p);
|
||||
auto p_body = q->get_expr();
|
||||
auto nd = q->get_num_decls();
|
||||
var_shifter vs(m);
|
||||
expr_ref r(m);
|
||||
vs(t, nd, r);
|
||||
expr_ref_vector args(m);
|
||||
args.push_back(r);
|
||||
for (unsigned i = 0; i < nd; ++i)
|
||||
args.push_back(m.mk_var(nd - 1 - i, q->get_decl_sort(i)));
|
||||
r = m_array.mk_select(args);
|
||||
m_goals.push(wi.level, wi.term_offset() + nd, p_body, r);
|
||||
wi.set_done();
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// lambda x . p == lambda x . t
|
||||
//
|
||||
if (is_quantifier(p) && is_quantifier(t)) {
|
||||
auto qp = to_quantifier(p);
|
||||
auto qt = to_quantifier(t);
|
||||
unsigned pd = qp->get_num_decls();
|
||||
unsigned td = qt->get_num_decls();
|
||||
if (qp->get_kind() != qt->get_kind())
|
||||
return false;
|
||||
if (pd != td)
|
||||
return false;
|
||||
for (unsigned i = 0; i < pd; ++i)
|
||||
if (qp->get_decl_sort(i) != qt->get_decl_sort(i))
|
||||
return false;
|
||||
m_goals.push(wi.level, wi.term_offset() + td, qp->get_expr(), qt->get_expr());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Flex head unitary
|
||||
// H(pat) = t
|
||||
|
||||
|
|
@ -457,25 +490,7 @@ namespace euf {
|
|||
m_goals.push(wi.level, wi.term_offset(), tp->get_arg(i), ta->get_arg(i));
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// lambda x . p == lambda x . t
|
||||
//
|
||||
if (is_quantifier(p) && is_quantifier(t)) {
|
||||
auto qp = to_quantifier(p);
|
||||
auto qt = to_quantifier(t);
|
||||
unsigned pd = qp->get_num_decls();
|
||||
unsigned td = qt->get_num_decls();
|
||||
if (qp->get_kind() != qt->get_kind())
|
||||
return false;
|
||||
if (pd != td)
|
||||
return false;
|
||||
for (unsigned i = 0; i < pd; ++i)
|
||||
if (qp->get_decl_sort(i) != qt->get_decl_sort(i))
|
||||
return false;
|
||||
m_goals.push(wi.level, wi.term_offset() + td, qp->get_expr(), qt->get_expr());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -488,8 +503,7 @@ namespace euf {
|
|||
uint_set vars;
|
||||
while (m_array.is_select(p)) {
|
||||
auto a = to_app(p);
|
||||
for (unsigned i = 1; i < a->get_num_args(); ++i) {
|
||||
auto arg = a->get_arg(i);
|
||||
for (auto arg : *a) {
|
||||
if (!is_bound_var(arg, offset))
|
||||
return false;
|
||||
auto idx = to_var(arg)->get_idx();
|
||||
|
|
@ -549,15 +563,12 @@ namespace euf {
|
|||
}
|
||||
expr_ref_vector pat2bound(m);
|
||||
for (auto a : pats) {
|
||||
unsigned sz = a->get_num_args();
|
||||
for (unsigned i = 1; i < sz; ++i) {
|
||||
auto arg = a->get_arg(i);
|
||||
for (auto arg : *a) {
|
||||
SASSERT(is_bound_var(arg, offset));
|
||||
auto idx = to_var(arg)->get_idx();
|
||||
pat2bound.reserve(idx + 1);
|
||||
pat2bound[idx] = m.mk_var(--num_bound, arg->get_sort());
|
||||
}
|
||||
p1 = a->get_arg(0);
|
||||
}
|
||||
}
|
||||
var_subst sub(m, false);
|
||||
expr_ref lam = sub(t, pat2bound);
|
||||
|
|
@ -575,7 +586,7 @@ namespace euf {
|
|||
|
||||
//
|
||||
// keep track of number of internal scopes and offset to non-capture variables.
|
||||
// a variable is captured if it's index is in the interval [scopes, offset[.
|
||||
// a variable is captured if its index is in the interval [scopes, offset[.
|
||||
//
|
||||
bool ho_matcher::is_closed(expr* v, unsigned scopes, unsigned offset) const {
|
||||
if (is_ground(v))
|
||||
|
|
@ -630,49 +641,59 @@ namespace euf {
|
|||
void ho_matcher::add_binding(var* v, unsigned offset, expr* t) {
|
||||
SASSERT(v->get_idx() >= offset);
|
||||
m_subst.set(v->get_idx() - offset, t);
|
||||
IF_VERBOSE(1, verbose_stream() << "ho_matcher::add_binding: v" << v->get_idx() - offset << " -> " << mk_pp(t, m) << "\n";);
|
||||
SASSERT(v->get_sort() == t->get_sort());
|
||||
TRACE(ho_matching, tout << "ho_matcher::add_binding: v" << v->get_idx() - offset << " -> " << mk_pp(t, m) << "\n";);
|
||||
m_trail.push(undo_set(m_subst, v->get_idx() - offset));
|
||||
}
|
||||
|
||||
|
||||
std::pair<quantifier*, app*> ho_matcher::compile_ho_pattern(quantifier* q, app* p) {
|
||||
app* p1 = nullptr;
|
||||
if (m_pat2hopat.find(p, p)) {
|
||||
q = m_q2hoq[q];
|
||||
return { q, p };
|
||||
quantifier *q1 = nullptr;
|
||||
if (m_pat2hopat.find(p, p1) && m_q2hoq.find(q, q1)) {
|
||||
return { q1, p1 };
|
||||
}
|
||||
auto is_ho = any_of(subterms::all(expr_ref(p, m)), [&](expr* t) { return m_unitary.is_flex(0, t); });
|
||||
auto is_ho = any_of(subterms::all(expr_ref(p, m)), [&](expr* t) {
|
||||
return m_unitary.is_flex(0, t) ||
|
||||
// m.is_lambda_def(t) ||
|
||||
is_lambda(t);
|
||||
});
|
||||
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();
|
||||
todo.push_back(p);
|
||||
bool contains_pat2abs = m_pat2abs.contains(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_pat2abs.insert_if_not_there(p, svector<std::pair<unsigned, expr*>>()).push_back({ nb, 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());
|
||||
bound.push_back(v);
|
||||
cache.setx(t->get_id(), v);
|
||||
todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (is_app(t)) {
|
||||
auto a = to_app(t);
|
||||
|
||||
unsigned sz = a->get_num_args();
|
||||
ptr_buffer<expr> args;
|
||||
for (auto arg : *a) {
|
||||
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);
|
||||
}
|
||||
|
|
@ -682,11 +703,15 @@ namespace euf {
|
|||
cache.setx(t->get_id(), m.mk_app(a->get_decl(), args.size(), args.data()));
|
||||
}
|
||||
if (is_quantifier(t)) {
|
||||
m_pat2abs.remove(p);
|
||||
if (!contains_pat2abs)
|
||||
m_pat2abs.remove(p);
|
||||
return { q, p };
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
|
@ -713,6 +738,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);
|
||||
|
|
@ -721,23 +748,40 @@ namespace euf {
|
|||
p1 = m.mk_pattern(pats.size(), pats.data());
|
||||
}
|
||||
|
||||
quantifier* q1 = m.mk_forall(sorts.size(), sorts.data(), names.data(), body);
|
||||
q1 = m.mk_forall(sorts.size(), sorts.data(), names.data(), body);
|
||||
|
||||
m_pat2hopat.insert(p, p1);
|
||||
m_hopat2pat.insert(p1, p);
|
||||
m_q2hoq.insert(q, q1);
|
||||
m_hoq2q.insert(q1, q);
|
||||
m_hopat2free_vars.insert(p1, std::move(free_vars));
|
||||
m_ho_patterns.push_back(p1);
|
||||
m_ho_qs.push_back(q1);
|
||||
trail().push(push_back_vector(m_ho_patterns));
|
||||
trail().push(push_back_vector(m_ho_qs));
|
||||
trail().push(insert_map(m_pat2hopat, p));
|
||||
trail().push(insert_map(m_hopat2pat, p1));
|
||||
trail().push(insert_map(m_pat2abs, p));
|
||||
trail().push(insert_map(m_q2hoq, q));
|
||||
trail().push(insert_map(m_hoq2q, q1));
|
||||
trail().push(insert_map(m_hopat2free_vars, p1));
|
||||
|
||||
if (!m_pat2hopat.contains(p)) {
|
||||
m_pat2hopat.insert(p, p1);
|
||||
trail().push(insert_map(m_pat2hopat, p));
|
||||
}
|
||||
if (!m_hopat2pat.contains(p1)) {
|
||||
m_hopat2pat.insert(p1, p);
|
||||
trail().push(insert_map(m_hopat2pat, p1));
|
||||
}
|
||||
if (!m_q2hoq.contains(q)) {
|
||||
m_q2hoq.insert(q, q1);
|
||||
trail().push(insert_map(m_q2hoq, q));
|
||||
}
|
||||
if (!m_hoq2q.contains(q1)) {
|
||||
m_hoq2q.insert(q1, q);
|
||||
trail().push(insert_map(m_hoq2q, q1));
|
||||
}
|
||||
if (!m_hopat2free_vars.contains(p1)) {
|
||||
m_hopat2free_vars.insert(p1, std::move(free_vars));
|
||||
trail().push(insert_map(m_hopat2free_vars, p1));
|
||||
}
|
||||
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 };
|
||||
}
|
||||
|
||||
|
|
@ -745,28 +789,46 @@ namespace euf {
|
|||
return m_hopat2pat.contains(p);
|
||||
}
|
||||
|
||||
void ho_matcher::register_ho_pattern(app* alias_p, app* full_p) {
|
||||
if (alias_p == full_p) return;
|
||||
auto orig_p = m_hopat2pat[full_p];
|
||||
m_hopat2pat.insert(alias_p, orig_p);
|
||||
m_hopat2free_vars.insert(alias_p, m_hopat2free_vars[full_p]);
|
||||
m_ho_patterns.push_back(alias_p);
|
||||
trail().push(push_back_vector(m_ho_patterns));
|
||||
trail().push(insert_map(m_hopat2pat, alias_p));
|
||||
trail().push(insert_map(m_hopat2free_vars, alias_p));
|
||||
}
|
||||
|
||||
void ho_matcher::refine_ho_match(app* p, expr_ref_vector& s) {
|
||||
auto fo_pat = m_hopat2pat[p];
|
||||
IF_VERBOSE(10, verbose_stream() << "refine_ho_match: p=" << mk_pp(p, m) << "\n fo_pat=" << mk_pp(fo_pat, m) << "\n";
|
||||
verbose_stream() << " m_pat2abs has fo_pat: " << m_pat2abs.contains(fo_pat) << "\n";
|
||||
auto& abs = m_pat2abs[fo_pat];
|
||||
verbose_stream() << " m_pat2abs size: " << abs.size() << "\n";
|
||||
for (auto [v, pat] : abs) verbose_stream() << " v=" << v << " pat=" << mk_pp(pat, m) << "\n";);
|
||||
m_trail.push_scope();
|
||||
m_subst.resize(0);
|
||||
m_subst.resize(s.size());
|
||||
m_goals.reset();
|
||||
// MAM bindings are reversed: s[i] = binding for var idx = s.size()-1-i
|
||||
// m_subst is indexed by var index directly
|
||||
for (unsigned i = 0; i < s.size(); ++i) {
|
||||
auto idx = s.size() - i - 1;
|
||||
if (!m_hopat2free_vars[p].contains(idx))
|
||||
s[i] = m.mk_var(idx, s[i]->get_sort());
|
||||
else if (s.get(i))
|
||||
m_subst.set(i, s.get(i));
|
||||
m_subst.set(idx, s.get(i));
|
||||
}
|
||||
|
||||
IF_VERBOSE(1, verbose_stream() << "refine " << mk_pp(p, m) << "\n" << s << "\n");
|
||||
TRACE(ho_matching, tout << "refine " << mk_pp(p, m) << "\n" << s << "\n");
|
||||
|
||||
unsigned num_bound = 0, level = 0;
|
||||
for (auto [v, pat] : m_pat2abs[fo_pat]) {
|
||||
var_subst sub(m, true);
|
||||
auto pat_refined = sub(pat, s);
|
||||
IF_VERBOSE(1, verbose_stream() << mk_pp(pat, m) << " -> " << pat_refined << "\n");
|
||||
m_goals.push(level, num_bound, pat_refined, s.get(s.size() - v - 1));
|
||||
TRACE(ho_matching, tout << mk_pp(pat, m) << " -> " << pat_refined << "\n");
|
||||
m_goals.push(level, num_bound, pat_refined, m_subst.get(v));
|
||||
}
|
||||
|
||||
search();
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ Author:
|
|||
#include "ast/for_each_expr.h"
|
||||
#include "ast/reg_decl_plugins.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/rewriter/array_rewriter.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
|
||||
|
|
@ -88,13 +89,15 @@ namespace euf {
|
|||
}
|
||||
|
||||
match_goal(unsigned level, unsigned offset, expr_ref const& pat, expr_ref const& t) noexcept :
|
||||
base_offset(offset), pat(pat), t(t), level(level) {}
|
||||
base_offset(offset), pat(pat), t(t), level(level) {
|
||||
SASSERT(pat->get_sort() == t->get_sort());
|
||||
}
|
||||
|
||||
unsigned term_offset() const { return base_offset + delta_offset; }
|
||||
unsigned pat_offset() const { return base_offset + delta_offset; }
|
||||
|
||||
std::ostream& display(std::ostream& out) const {
|
||||
return out << "[" << level << ":" << base_offset + delta_offset << "] " << pat << " ~ " << t << "\n";
|
||||
return out << "[" << level << ":" << base_offset + delta_offset << "] " << mk_bounded_pp(pat, pat.m()) << " ~ " << mk_bounded_pp(t, t.m()) << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -329,6 +332,8 @@ namespace euf {
|
|||
bool consume_work(match_goal& wi);
|
||||
|
||||
expr_ref whnf(expr* e, unsigned offset) const;
|
||||
|
||||
expr_ref whnf_star(expr *e, unsigned offset) const;
|
||||
|
||||
bool is_bound_var(expr* v, unsigned offset) const { return is_var(v) && to_var(v)->get_idx() < offset; }
|
||||
|
||||
|
|
@ -389,11 +394,23 @@ namespace euf {
|
|||
|
||||
bool is_ho_pattern(app* p);
|
||||
|
||||
// Register an alias pattern (e.g., after stripping ground elements)
|
||||
// that maps to the same original pattern as full_p
|
||||
void register_ho_pattern(app* alias_p, app* full_p);
|
||||
|
||||
void refine_ho_match(app* p, expr_ref_vector& s);
|
||||
|
||||
bool is_free(app* p, unsigned i) const { return m_hopat2free_vars[p].contains(i); }
|
||||
|
||||
quantifier* hoq2q(quantifier* q) const { return m_hoq2q[q]; }
|
||||
|
||||
|
||||
svector<std::pair<unsigned, expr*>> const* get_flex_subterms(app* p) const {
|
||||
auto orig_p = m_hopat2pat.find_core(p);
|
||||
if (!orig_p) return nullptr;
|
||||
auto abs = m_pat2abs.find_core(orig_p->get_data().get_value());
|
||||
return abs ? &abs->get_data().get_value() : nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue