3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-04-15 08:44:10 +00:00

Fixed the model generation fix

This commit is contained in:
CEisenhofer 2026-04-12 19:34:11 +02:00
parent 2a142cd150
commit 95d28ad02c
2 changed files with 58 additions and 6 deletions

View file

@ -324,7 +324,7 @@ namespace smt {
}
if (n->is_var())
return expr_ref(get_var_value(n), m);
return expr_ref(get_var_value(n, dep_values), m);
if (n->is_concat()) {
SASSERT(n->get_sort() && m_seq.is_seq(n->get_sort()));
@ -436,6 +436,15 @@ namespace smt {
if (!n)
return;
if (n->is_var()) {
expr* e = n->get_expr();
if (e && m_seq.is_seq(e)) {
expr_ref len_expr(m_seq.str.mk_length(e), m);
collect_expr_dependencies(m_ctx, len_expr, seen, deps);
}
return;
}
if (n->is_char() || n->is_unit()) {
expr* e = n->get_expr();
if (e && m_seq.str.is_unit(e)) {
@ -476,7 +485,7 @@ namespace smt {
}
}
expr* seq_model::get_var_value(euf::snode* var) {
expr* seq_model::get_var_value(euf::snode* var, obj_map<enode, expr*> const* dep_values) {
SASSERT(var);
unsigned key = var->first()->id();
expr* val = nullptr;
@ -484,7 +493,7 @@ namespace smt {
return val;
// unconstrained or regex-constrained: delegate to mk_fresh_value
val = mk_fresh_value(var);
val = mk_fresh_value(var, dep_values);
if (val) {
m_trail.push_back(val);
m_var_values.insert(key, val);
@ -492,7 +501,7 @@ namespace smt {
return val;
}
expr* seq_model::mk_fresh_value(euf::snode* var) {
expr* seq_model::mk_fresh_value(euf::snode* var, obj_map<enode, expr*> const* dep_values) {
SASSERT(var->get_expr());
if (!m_seq.is_seq(var->get_expr()))
return nullptr;
@ -516,6 +525,49 @@ namespace smt {
UNREACHABLE();
}
// No regex constraint: try to respect the assigned length for the variable.
// This prevents invalid models such as len(x)=1 with x="".
arith_util arith(m);
expr_ref len_expr(m_seq.str.mk_length(var->get_expr()), m);
rational len_val;
bool has_len = false;
if (dep_values) {
expr* dval = nullptr;
enode* dep = find_root_enode(m_ctx, len_expr);
if (dep && dep_values->find(dep, dval) && dval && arith.is_numeral(dval, len_val))
has_len = true;
}
if (!has_len && m_mg) {
expr_ref eval_len(m);
if (m_mg->get_model().eval(len_expr, eval_len, true) && arith.is_numeral(eval_len, len_val))
has_len = true;
}
if (has_len) {
if (!len_val.is_int() || len_val.is_neg())
len_val = rational(0);
if (len_val.is_zero())
return m_seq.str.mk_empty(srt);
constexpr unsigned MAX_CONCRETE_WITNESS = 1024;
if (len_val.is_unsigned() && len_val.get_unsigned() <= MAX_CONCRETE_WITNESS) {
unsigned n = len_val.get_unsigned();
zstring w;
for (unsigned i = 0; i < n; ++i)
w += zstring('0');
expr* witness = m_seq.str.mk_string(w);
m_factory->register_value(witness);
return witness;
}
expr* base = m_seq.str.mk_string("0");
expr* witness = m_seq.str.mk_power(base, arith.mk_int(len_val));
m_factory->register_value(witness);
return witness;
}
// no regex constraint or witness generation failed: use empty string
return m_seq.str.mk_empty(srt);
}

View file

@ -117,14 +117,14 @@ namespace smt {
// look up or compute the value for an snode variable.
// If no assignment exists, delegates to mk_fresh_value.
expr* get_var_value(euf::snode* var);
expr* get_var_value(euf::snode* var, obj_map<enode, expr*> const* dep_values = nullptr);
// generate a fresh value for a variable, respecting regex
// membership constraints. If the variable has associated
// regex constraints (collected during init), generates a
// witness satisfying the intersection; otherwise falls back
// to a plain fresh value from the factory.
expr* mk_fresh_value(euf::snode* var);
expr* mk_fresh_value(euf::snode* var, obj_map<enode, expr*> const* dep_values = nullptr);
// collect per-variable regex constraints from the state.
// For each positive str_mem, records the regex (or intersects