mirror of
https://github.com/Z3Prover/z3
synced 2026-03-16 10:10:02 +00:00
Fix nseq_state axiom scope leak and add propagate_ground_split
Bug fix: m_axioms and m_axiom_set were not restored on pop_scope, causing axioms from a previous push/pop context to leak into subsequent contexts with the same variable names, producing non-termination in incremental solving (push/check-sat/pop sequences). Fix: track m_axioms_size_at_push on the trail stack and truncate m_axioms + remove corresponding m_axiom_set entries on pop. Optimization: propagate_ground_split directly sets variable values when one side is a pure ground string and all variables have known lengths. Optimization: explicit len(z) = len(head) - len(var) axioms for Skolem terms in var-vs-var splits to help arithmetic termination. Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
This commit is contained in:
parent
b59db29868
commit
5c56e5fb0a
3 changed files with 24 additions and 4 deletions
|
|
@ -38,6 +38,9 @@ namespace smt {
|
|||
m_trail.push_scope();
|
||||
m_trail.push(value_trail<unsigned>(m_axioms_head));
|
||||
m_trail.push(value_trail<unsigned>(m_preds_head));
|
||||
// Save axiom vector size so we can truncate it on pop
|
||||
m_trail.push(value_trail<unsigned>(m_axioms_size_at_push));
|
||||
m_axioms_size_at_push = m_axioms.size();
|
||||
m_eqs.push_scope();
|
||||
m_neqs.push_scope();
|
||||
m_mems.push_scope();
|
||||
|
|
@ -45,7 +48,14 @@ namespace smt {
|
|||
}
|
||||
|
||||
void nseq_state::pop_scope(unsigned num_scopes) {
|
||||
// m_trail.pop_scope will restore m_axioms_size_at_push to the value saved
|
||||
// at the outermost of the popped scopes (i.e., the correct target size).
|
||||
m_trail.pop_scope(num_scopes);
|
||||
// Now m_axioms_size_at_push is the size we should truncate back to.
|
||||
unsigned target = m_axioms_size_at_push;
|
||||
for (unsigned i = target; i < m_axioms.size(); ++i)
|
||||
m_axiom_set.remove(m_axioms.get(i));
|
||||
m_axioms.shrink(target);
|
||||
m_dm.pop_scope(num_scopes);
|
||||
m_eqs.pop_scope(num_scopes);
|
||||
m_neqs.pop_scope(num_scopes);
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ namespace smt {
|
|||
expr_ref_vector m_axioms;
|
||||
obj_hashtable<expr> m_axiom_set;
|
||||
unsigned m_axioms_head;
|
||||
unsigned m_axioms_size_at_push { 0 }; // saved on push, restored on pop
|
||||
|
||||
// Length tracking
|
||||
obj_hashtable<expr> m_has_length;
|
||||
|
|
|
|||
|
|
@ -68,8 +68,6 @@ namespace smt {
|
|||
m_state.set_axioms_head(axioms.size());
|
||||
if (ctx.inconsistent())
|
||||
return FC_CONTINUE;
|
||||
// Fall through: call solve_eqs in the same round so force_phase is set
|
||||
// before the SAT solver makes random phase decisions.
|
||||
}
|
||||
|
||||
// Reduce predicates (prefix, suffix, contains) to word equations
|
||||
|
|
@ -996,9 +994,15 @@ namespace smt {
|
|||
case l_true:
|
||||
return propagate_eq(dep, var, head);
|
||||
case l_false: {
|
||||
// |var| < |head|: head = var · z_rest
|
||||
// |var| < |head|: head = var · z_rest, |z_rest| = |head| - |var|
|
||||
expr_ref z(m_sk.mk_post(head, len_var), m);
|
||||
ensure_enode(z); mk_var(ctx.get_enode(z)); ensure_length_axiom(z);
|
||||
// Add len(z) = len(head) - len(var) as an explicit axiom so arithmetic
|
||||
// knows the exact length and terminates the split chain.
|
||||
expr_ref len_z = mk_len(z);
|
||||
expr_ref len_diff(m_autil.mk_sub(len_head, len_var), m);
|
||||
ensure_enode(len_z); ensure_enode(len_diff);
|
||||
add_axiom(mk_eq(len_z, len_diff, false));
|
||||
expr_ref rhs_eq(m_util.str.mk_concat(var, z), m);
|
||||
ensure_enode(rhs_eq); ensure_length_axiom(rhs_eq);
|
||||
bool changed = propagate_eq(dep, head, rhs_eq);
|
||||
|
|
@ -1009,9 +1013,14 @@ namespace smt {
|
|||
break;
|
||||
}
|
||||
case l_false: {
|
||||
// |var| > |head|: var = head · z_rest
|
||||
// |var| > |head|: var = head · z_rest, |z_rest| = |var| - |head|
|
||||
expr_ref z(m_sk.mk_post(var, len_head), m);
|
||||
ensure_enode(z); mk_var(ctx.get_enode(z)); ensure_length_axiom(z);
|
||||
// Add len(z) = len(var) - len(head) as an explicit axiom.
|
||||
expr_ref len_z = mk_len(z);
|
||||
expr_ref len_diff(m_autil.mk_sub(len_var, len_head), m);
|
||||
ensure_enode(len_z); ensure_enode(len_diff);
|
||||
add_axiom(mk_eq(len_z, len_diff, false));
|
||||
expr_ref rhs_eq(m_util.str.mk_concat(head, z), m);
|
||||
ensure_enode(rhs_eq); ensure_length_axiom(rhs_eq);
|
||||
bool changed = propagate_eq(dep, var, rhs_eq);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue