3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-01-25 03:24:01 +00:00
z3/src/smt/theory_sls.cpp
Nikolaj Bjorner 62b3668beb remove set cardinality operators from array theory. Make final-check use priority levels
Issue #7502 shows that running nlsat eagerly during final check can block quantifier instantiation.
To give space for quantifier instances we introduce two levels for final check such that nlsat is only applied in the second and final level.
2025-11-26 15:35:19 -08:00

274 lines
7.9 KiB
C++

/*++
Copyright (c) 2020 Microsoft Corporation
Module Name:
theory_sls
Abstract:
Interface to Concurrent SLS solver
Author:
Nikolaj Bjorner (nbjorner) 2024-10-24
--*/
#include "smt/smt_context.h"
#include "ast/sls/sls_context.h"
#include "ast/for_each_expr.h"
#include "smt/theory_sls.h"
namespace smt {
theory_sls::theory_sls(smt::context& ctx) :
theory(ctx, ctx.get_manager().mk_family_id("sls"))
{}
#ifndef SINGLE_THREAD
theory_sls::~theory_sls() {
finalize();
}
params_ref theory_sls::get_params() {
return ctx.get_params();
}
void theory_sls::set_value(expr* t, expr* v) {
ctx.user_propagate_initialize_value(t, v);
}
void theory_sls::force_phase(sat::literal lit) {
ctx.force_phase(lit);
}
void theory_sls::set_has_new_best_phase(bool b) {
}
bool theory_sls::get_best_phase(sat::bool_var v) {
return ctx.get_assignment(v) == l_true;
}
expr* theory_sls::bool_var2expr(sat::bool_var v) {
return ctx.bool_var2expr(v);
}
void theory_sls::set_finished() {
ctx.set_internal_completed();
}
bool theory_sls::get_smt_value(expr* v, expr_ref& value) {
if (!ctx.e_internalized(v))
return false;
auto* n = ctx.get_enode(v);
return n && ctx.get_value(n, value);
}
void theory_sls::inc_activity(sat::bool_var v, double inc) {
ctx.inc_bvar_activity(v, inc);
}
unsigned theory_sls::get_num_bool_vars() const {
return ctx.get_num_bool_vars();
}
void theory_sls::init_search_eh() {
m_init_search = true;
}
void theory_sls::finalize() const {
if (!m_smt_plugin)
return;
m_smt_plugin->finalize(m_model, m_st);
m_model = nullptr;
m_smt_plugin = nullptr;
m_init_search = false;
}
void theory_sls::propagate() {
if (!m_init_search)
return;
if (!m_smt_plugin)
m_smt_plugin = alloc(sls::smt_plugin, * this);
if (!m_checking) {
expr_ref_vector fmls(m);
for (unsigned i = 0; i < ctx.get_num_asserted_formulas(); ++i)
fmls.push_back(ctx.get_asserted_formula(i));
m_checking = true;
vector<sat::literal_vector> clauses;
m_smt_plugin->check(fmls, clauses);
m_smt_plugin->get_shared_clauses(m_shared_clauses);
}
else if (m_parallel_mode && m_smt_plugin->completed()) {
m_smt_plugin->finalize(m_model, m_st);
m_smt_plugin = nullptr;
m_init_search = false;
}
else
propagate_local_search();
}
void theory_sls::pop_scope_eh(unsigned n) {
if (!m_smt_plugin)
return;
if (ctx.get_search_level() == ctx.get_scope_level() - n) {
auto& lits = ctx.assigned_literals();
for (; m_trail_lim < lits.size() && ctx.get_assign_level(lits[m_trail_lim]) == ctx.get_search_level(); ++m_trail_lim)
m_smt_plugin->add_unit(lits[m_trail_lim]);
}
check_for_unassigned_clause_after_resolve();
#if 0
if (ctx.has_new_best_phase())
m_smt_plugin->import_phase_from_smt();
#endif
}
//
// hybrid-smt uses a heuristic to determine when to restart local search.
// it is based on when the assignment to shared clauses has a change in literal assignment.
//
void theory_sls::check_for_unassigned_clause_after_resolve() {
if (m_has_unassigned_clause_after_resolve) {
m_after_resolve_decide_count = 0;
if (m_after_resolve_decide_gap >= 16)
m_after_resolve_decide_gap /= 4;
}
else if (!shared_clauses_are_true()) {
m_resolve_count++;
if (m_resolve_count > m_resolve_gap) {
m_resolve_gap++;
m_has_unassigned_clause_after_resolve = true;
m_resolve_count = 0;
m_after_resolve_decide_count = 0;
m_after_resolve_decide_gap = 4;
}
}
}
void theory_sls::update_propagation_scope() {
if (m_propagation_scope > ctx.get_scope_level() && m_propagation_scope == m_max_propagation_scope) {
m_smt_plugin->smt_values_to_sls();
}
m_propagation_scope = ctx.get_scope_level();
m_max_propagation_scope = std::max(m_max_propagation_scope, m_propagation_scope);
}
void theory_sls::propagate_local_search() {
if (!m_has_unassigned_clause_after_resolve)
return;
if (!m_smt_plugin)
return;
++m_after_resolve_decide_count;
if (100 + m_after_resolve_decide_gap > m_after_resolve_decide_count) {
//update_propagation_scope();
return;
}
m_after_resolve_decide_gap *= 2;
if (!shared_clauses_are_true()) {
update_propagation_scope();
return;
}
m_resolve_count = 0;
m_has_unassigned_clause_after_resolve = false;
run_guided_sls();
}
void theory_sls::run_guided_sls() {
m_smt_plugin->smt_values_to_sls();
if (m_parallel_mode)
return;
++m_stats.m_num_guided_sls;
m_smt_plugin->smt_phase_to_sls();
m_smt_plugin->smt_units_to_sls();
bounded_run(m_final_check_ls_steps);
dec_final_check_ls_steps();
if (m_smt_plugin) {
m_smt_plugin->sls_phase_to_smt();
m_smt_plugin->sls_values_to_smt();
if (m_stats.m_num_guided_sls % 20 == 0)
m_smt_plugin->sls_activity_to_smt();
}
}
void theory_sls::init() {
if (m_smt_plugin)
finalize();
smt_params p(ctx.get_fparams());
m_parallel_mode = p.m_sls_parallel;
m_smt_plugin = nullptr;
m_checking = false;
m_init_search = false;
}
void theory_sls::collect_statistics(::statistics& st) const {
finalize();
st.copy(m_st);
st.update("sls-num-guided-search", m_stats.m_num_guided_sls);
st.update("sls-num-restart-search", m_stats.m_num_restart_sls);
}
void theory_sls::restart_eh() {
if (m_parallel_mode || !m_smt_plugin)
return;
if (ctx.m_stats.m_num_restarts >= m_restart_gap + 5) {
m_restart_gap *= 2;
m_smt_plugin->smt_units_to_sls();
++m_stats.m_num_restart_sls;
bounded_run(m_restart_ls_steps);
inc_restart_ls_steps();
if (m_smt_plugin)
m_smt_plugin->sls_activity_to_smt();
}
}
void theory_sls::bounded_run(unsigned num_steps) {
m_smt_plugin->bounded_run(num_steps);
if (m_smt_plugin->result() == l_true) {
m_smt_plugin->finalize(m_model, m_st);
m_smt_plugin = nullptr;
m_init_search = false;
}
}
final_check_status theory_sls::final_check_eh(unsigned) {
if (!m_smt_plugin)
return FC_DONE;
++m_after_resolve_decide_count;
if (m_after_resolve_decide_gap > m_after_resolve_decide_count)
return FC_DONE;
m_after_resolve_decide_gap *= 2;
run_guided_sls();
return FC_DONE;
}
bool theory_sls::shared_clauses_are_true() const {
#if 0
for (auto const& cl : m_shared_clauses) {
for (auto lit : cl)
verbose_stream() << lit << " : " << ctx.get_assignment(lit);
verbose_stream() << "\n";
}
#endif
for (auto const& cl : m_shared_clauses)
if (all_of(cl, [this](sat::literal lit) { return ctx.get_assignment(lit) != l_true; }))
return false;
return true;
}
void theory_sls::display(std::ostream& out) const {
out << "theory-sls\n";
}
#endif
}