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

handle lambda equalities

This commit is contained in:
Nikolaj Bjorner 2026-07-05 12:51:33 -07:00
parent eccdffa781
commit 165f79a051
3 changed files with 36 additions and 1 deletions

View file

@ -23,6 +23,7 @@ Revision History:
#include "smt/smt_model_generator.h"
#include "model/func_interp.h"
#include "ast/ast_smt2_pp.h"
#include "ast/pattern/pattern_inference.h"
namespace smt {
@ -413,6 +414,16 @@ namespace smt {
expr * eq = m.mk_eq(sel1, sel2);
expr_ref q(m.mk_forall(dimension, sorts.data(), names.data(), eq), m);
ctx.get_rewriter()(q);
// The select terms are beta-reduced away by the rewriter, so the
// resulting quantifier carries no patterns. Infer patterns so that the
// e-matching engine can instantiate it (dynamically generated
// quantifiers bypass the pre-processing pattern inference pass).
if (is_forall(q) && to_quantifier(q)->get_num_patterns() == 0) {
pattern_inference_rw infer(m, ctx.get_fparams());
expr_ref q2(m);
infer(q, q2);
q = q2;
}
if (!ctx.b_internalized(q)) {
ctx.internalize(q, true);
}

View file

@ -354,6 +354,14 @@ namespace smt {
add_as_array(v1, n);
for (enode* n : d2->m_lambdas)
add_lambda(v1, n);
// When a lambda is equated to another array term, assert the congruence
// axiom n1 = n2 => forall k . select(n1, k) = select(n2, k).
// This lets positive equalities between lambdas (which have no select
// parents of their own) produce usable consequences.
enode* n1 = get_enode(v1);
enode* n2 = get_enode(v2);
if (is_lambda(n1->get_expr()) || is_lambda(n2->get_expr()))
assert_congruent(n1, n2);
TRACE(array,
tout << pp(get_enode(v1), m) << "\n";
tout << pp(get_enode(v2), m) << "\n";
@ -854,13 +862,28 @@ namespace smt {
}
for (enode* n : m_lambdas)
for (enode* p : n->get_parents())
if (ctx.is_relevant(p) && !is_default(p) && !ctx.is_beta_redex(p, n)) {
if (ctx.is_relevant(p) && !is_default(p) && !ctx.is_beta_redex(p, n) && !is_congruent_eq(p)) {
TRACE(array, tout << "lambda is not a beta redex " << enode_pp(p, ctx) << "\n");
return true;
}
return false;
}
/**
\brief A relevant equality between two array terms whose roots coincide is
handled by the congruence axiom asserted on merge (see merge_eh /
assert_congruent). Such an equality parent does not make a lambda an
unsupported (non beta-redex) occurrence, so it should not trigger a
final-check give-up.
*/
bool theory_array_full::is_congruent_eq(enode* p) {
expr* a = nullptr, * b = nullptr;
if (!m.is_eq(p->get_expr(), a, b))
return false;
return is_array_sort(p->get_arg(0)) &&
p->get_arg(0)->get_root() == p->get_arg(1)->get_root();
}
bool theory_array_full::instantiate_parent_stores_default(theory_var v) {
SASSERT(v != null_theory_var);

View file

@ -92,6 +92,7 @@ namespace smt {
enode_vector m_as_array;
enode_vector m_lambdas;
bool has_non_beta_as_array();
bool is_congruent_eq(enode* p);
bool instantiate_select_const_axiom(enode* select, enode* cnst);
bool instantiate_select_as_array_axiom(enode* select, enode* arr);