3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-02-20 07:24:40 +00:00

revise axiom instantiation scheme for finite-sets

Instead of asserting theory axioms lazily we create them on the fly and allow propagation eagerly.
The approach uses a waterfall model as follows:
- terms are created: they are inserted into an index for (set.in x S) axiom creation.
- two terms are merged by an equality.
  Loop over all new opportunities for axiom instantiation
  New axioms are added to a queue of recently created axioms.
- an atomic formula was asserted by the SAT solver.
  Update the watch list to find new propagations.

During propagation recently created axioms are either inserted into a propagation queue, or inserted into a watch list.
They are inserted into a propagation queue all or all but one literal is assigned to false.
They are inserted into a watch list if at least two literals are unassigned
They are dropped if the axiom contains a literal that is assigned to true

The propagation queue is processed by by asserting the theory axiom to the core.

Also add some elementary statistics.

A breaking change is to change the datatype for undo-trail in smt_context to not use a custom data-structure.
This can likely cause regressions. For example, the region allocator now comes from the stack_trail instead of being
owned within smt_context with a different declaration order. smt_context could crash during destruction or maybe even pop.
We take the risk as the change is overdue.

Add swap method to ref_vector.
This commit is contained in:
Nikolaj Bjorner 2025-10-18 12:08:39 +02:00
parent aa1f1f56b6
commit 43d40ac142
7 changed files with 522 additions and 209 deletions

View file

@ -66,7 +66,7 @@ namespace smt {
m_progress_callback(nullptr),
m_next_progress_sample(0),
m_clause_proof(*this),
m_fingerprints(m, m_region),
m_fingerprints(m, get_region()),
m_b_internalized_stack(m),
m_e_internalized_stack(m),
m_l_internalized_stack(m),
@ -799,7 +799,7 @@ namespace smt {
}
else {
// uncommon case: r2 will have two theory_vars attached to it.
r2->add_th_var(v1, t1, m_region);
r2->add_th_var(v1, t1, get_region());
push_new_th_diseqs(r2, v1, get_theory(t1));
push_new_th_diseqs(r1, v2, get_theory(t2));
}
@ -850,7 +850,7 @@ namespace smt {
theory_var v2 = r2->get_th_var(t1);
TRACE(merge_theory_vars, tout << get_theory(t1)->get_name() << ": " << v2 << " == " << v1 << "\n");
if (v2 == null_theory_var) {
r2->add_th_var(v1, t1, m_region);
r2->add_th_var(v1, t1, get_region());
push_new_th_diseqs(r2, v1, get_theory(t1));
}
l1 = l1->get_next();
@ -1939,14 +1939,13 @@ namespace smt {
m.trace_stream() << "[push] " << m_scope_lvl << "\n";
m_scope_lvl++;
m_region.push_scope();
get_region().push_scope();
m_scopes.push_back(scope());
scope & s = m_scopes.back();
// TRACE(context, tout << "push " << m_scope_lvl << "\n";);
m_relevancy_propagator->push();
s.m_assigned_literals_lim = m_assigned_literals.size();
s.m_trail_stack_lim = m_trail_stack.size();
s.m_aux_clauses_lim = m_aux_clauses.size();
s.m_justifications_lim = m_justifications.size();
s.m_units_to_reassert_lim = m_units_to_reassert.size();
@ -1962,12 +1961,6 @@ namespace smt {
CASSERT("context", check_invariant());
}
/**
\brief Execute generic undo-objects.
*/
void context::undo_trail_stack(unsigned old_size) {
::undo_trail_stack(m_trail_stack, old_size);
}
/**
\brief Remove watch literal idx from the given clause.
@ -2455,7 +2448,7 @@ namespace smt {
m_fingerprints.pop_scope(num_scopes);
unassign_vars(s.m_assigned_literals_lim);
undo_trail_stack(s.m_trail_stack_lim);
m_trail_stack.pop_scope(num_scopes);
for (theory* th : m_theory_set)
th->pop_scope_eh(num_scopes);
@ -2470,7 +2463,6 @@ namespace smt {
m_th_eq_propagation_queue.reset();
m_th_diseq_propagation_queue.reset();
m_atom_propagation_queue.reset();
m_region.pop_scope(num_scopes);
m_scopes.shrink(new_lvl);
m_conflict_resolution->reset();
@ -3058,7 +3050,7 @@ namespace smt {
del_clauses(m_lemmas, 0);
del_justifications(m_justifications, 0);
reset_tmp_clauses();
undo_trail_stack(0);
m_trail_stack.reset();
m_qmanager = nullptr;
if (m_is_diseq_tmp) {
m_is_diseq_tmp->del_eh(m, false);