3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-02-19 23:14: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

@ -608,7 +608,7 @@ namespace smt {
m_lambdas.insert(lam_node, q);
m_app2enode.setx(q->get_id(), lam_node, nullptr);
m_l_internalized_stack.push_back(q);
m_trail_stack.push_back(&m_mk_lambda_trail);
m_trail_stack.push_ptr(&m_mk_lambda_trail);
bool_var bv = get_bool_var(fa);
assign(literal(bv, false), nullptr);
mark_as_relevant(bv);
@ -959,7 +959,7 @@ namespace smt {
m_activity[v] = 0.0;
m_case_split_queue->mk_var_eh(v);
m_b_internalized_stack.push_back(n);
m_trail_stack.push_back(&m_mk_bool_var_trail);
m_trail_stack.push_ptr(&m_mk_bool_var_trail);
m_stats.m_num_mk_bool_var++;
SASSERT(check_bool_var_vector_sizes());
return v;
@ -1010,7 +1010,8 @@ namespace smt {
CTRACE(cached_generation, generation != m_generation,
tout << "cached_generation: #" << n->get_id() << " " << generation << " " << m_generation << "\n";);
}
enode * e = enode::mk(m, m_region, m_app2enode, n, generation, suppress_args, merge_tf, m_scope_lvl, cgc_enabled, true);
enode *e = enode::mk(m, get_region(), m_app2enode, n, generation, suppress_args, merge_tf, m_scope_lvl,
cgc_enabled, true);
TRACE(mk_enode_detail, tout << "e.get_num_args() = " << e->get_num_args() << "\n";);
if (m.is_unique_value(n))
e->mark_as_interpreted();
@ -1018,7 +1019,7 @@ namespace smt {
TRACE(generation, tout << "mk_enode: " << id << " " << generation << "\n";);
m_app2enode.setx(id, e, nullptr);
m_e_internalized_stack.push_back(n);
m_trail_stack.push_back(&m_mk_enode_trail);
m_trail_stack.push_ptr(&m_mk_enode_trail);
m_enodes.push_back(e);
if (e->get_num_args() > 0) {
if (e->is_true_eq()) {
@ -1864,11 +1865,11 @@ namespace smt {
if (old_v == null_theory_var) {
enode * r = n->get_root();
theory_var v2 = r->get_th_var(th_id);
n->add_th_var(v, th_id, m_region);
n->add_th_var(v, th_id, get_region());
push_trail(add_th_var_trail(n, th_id));
if (v2 == null_theory_var) {
if (r != n)
r->add_th_var(v, th_id, m_region);
r->add_th_var(v, th_id, get_region());
push_new_th_diseqs(r, v, th);
}
else if (r != n) {