3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 17:15:31 +00:00

Add initial value setting for variables in Z3 API, solver, and optimize modules

This commit is contained in:
Nikolaj Bjorner 2024-09-18 16:13:15 +03:00
parent 0ba306e7b3
commit 48712b4f60
31 changed files with 297 additions and 9 deletions

View file

@ -2914,6 +2914,44 @@ namespace smt {
register_plugin(m_user_propagator);
}
void context::user_propagate_initialize_value(expr* var, expr* value) {
m_values.push_back({expr_ref(var, m), expr_ref(value, m)});
push_trail(push_back_vector(m_values));
}
void context::initialize_value(expr* var, expr* value) {
IF_VERBOSE(10, verbose_stream() << "context initialize " << mk_pp(var, m) << " := " << mk_pp(value, m) << "\n");
sort* s = var->get_sort();
ensure_internalized(var);
if (m.is_bool(s)) {
auto v = get_bool_var_of_id_option(var->get_id());
if (v == null_bool_var) {
IF_VERBOSE(5, verbose_stream() << "Boolean variable has no literal " << mk_pp(var, m) << " := " << mk_pp(value, m) << "\n");
return;
}
m_bdata[v].m_phase_available = true;
if (m.is_true(value))
m_bdata[v].m_phase = true;
else if (m.is_false(value))
m_bdata[v].m_phase = false;
else
IF_VERBOSE(5, verbose_stream() << "Boolean value is not constant " << mk_pp(var, m) << " := " << mk_pp(value, m) << "\n");
return;
}
if (!e_internalized(var))
return;
enode* n = get_enode(var);
theory* th = m_theories.get_plugin(s->get_family_id());
if (!th) {
IF_VERBOSE(5, verbose_stream() << "No theory is attached to variable " << mk_pp(var, m) << " := " << mk_pp(value, m) << "\n");
return;
}
th->initialize_value(var, value);
}
bool context::watches_fixed(enode* n) const {
return m_user_propagator && m_user_propagator->has_fixed() && n->get_th_var(m_user_propagator->get_family_id()) != null_theory_var;
}
@ -3756,6 +3794,9 @@ namespace smt {
TRACE("search", display(tout); display_enodes_lbls(tout););
TRACE("search_detail", m_asserted_formulas.display(tout););
init_search();
for (auto const& [var, value] : m_values)
initialize_value(var, value);
flet<bool> l(m_searching, true);
TRACE("after_init_search", display(tout););
IF_VERBOSE(2, verbose_stream() << "(smt.searching)\n";);

View file

@ -123,6 +123,7 @@ namespace smt {
unsigned m_par_index = 0;
bool m_internalizing_assertions = false;
// -----------------------------------
//
// Equality & Uninterpreted functions
@ -246,6 +247,16 @@ namespace smt {
vector<literal_vector> m_th_case_split_sets;
u_map< vector<literal_vector> > m_literal2casesplitsets; // returns the case split literal sets that a literal participates in
// ----------------------------------
//
// Value initialization
//
// ----------------------------------
vector<std::pair<expr_ref, expr_ref>> m_values;
void initialize_value(expr* var, expr* value);
// -----------------------------------
//
// Accessors
@ -1777,6 +1788,8 @@ namespace smt {
m_user_propagator->register_decide(r);
}
void user_propagate_initialize_value(expr* var, expr* value);
bool watches_fixed(enode* n) const;
bool has_split_candidate(bool_var& var, bool& is_pos);

View file

@ -305,5 +305,9 @@ namespace smt {
void kernel::user_propagate_register_decide(user_propagator::decide_eh_t& r) {
m_imp->m_kernel.user_propagate_register_decide(r);
}
void kernel::user_propagate_initialize_value(expr* var, expr* value) {
m_imp->m_kernel.user_propagate_initialize_value(var, value);
}
};

View file

@ -322,6 +322,8 @@ namespace smt {
void user_propagate_register_decide(user_propagator::decide_eh_t& r);
void user_propagate_initialize_value(expr* var, expr* value);
/**
\brief Return a reference to smt::context.
This breaks abstractions.

View file

@ -252,6 +252,10 @@ namespace {
m_context.user_propagate_register_decide(c);
}
void user_propagate_initialize_value(expr* var, expr* value) override {
m_context.user_propagate_initialize_value(var, value);
}
struct scoped_minimize_core {
smt_solver& s;
expr_ref_vector m_assumptions;

View file

@ -549,6 +549,10 @@ namespace smt {
return get_manager().mk_eq(lhs, rhs);
}
virtual void initialize_value(expr* var, expr* value) {
IF_VERBOSE(5, verbose_stream() << "no default initialization associated with " << mk_pp(var, m) << " := " << mk_pp(value, m) << "\n");
}
literal mk_eq(expr * a, expr * b, bool gate_ctx);
literal mk_preferred_eq(expr* a, expr* b);

View file

@ -41,6 +41,7 @@ class smt_tactic : public tactic {
smt_params m_params;
params_ref m_params_ref;
expr_ref_vector m_vars;
vector<std::pair<expr_ref, expr_ref>> m_values;
statistics m_stats;
smt::kernel* m_ctx = nullptr;
symbol m_logic;
@ -344,6 +345,8 @@ public:
for (expr* v : m_vars)
m_ctx->user_propagate_register_expr(v);
for (auto& [var, value] : m_values)
m_ctx->user_propagate_initialize_value(var, value);
}
void user_propagate_clear() override {
@ -403,6 +406,10 @@ public:
void user_propagate_register_decide(user_propagator::decide_eh_t& decide_eh) override {
m_decide_eh = decide_eh;
}
void user_propagate_initialize_value(expr* var, expr* value) override {
m_values.push_back({expr_ref(var, m), expr_ref(value, m)});
}
};
static tactic * mk_seq_smt_tactic(ast_manager& m, params_ref const & p) {

View file

@ -662,6 +662,7 @@ namespace smt {
void restart_eh() override;
void init_search_eh() override;
void initialize_value(expr* var, expr* value) override;
/**
\brief True if the assignment may be changed during final
check. assume_eqs, check_int_feasibility,

View file

@ -2249,6 +2249,21 @@ namespace smt {
return false;
}
template<typename Ext>
void theory_arith<Ext>::initialize_value(expr* var, expr* value) {
theory_var v = expr2var(var);
rational r;
if (!m_util.is_numeral(value, r)) {
IF_VERBOSE(5, verbose_stream() << "numeric constant expected in initialization " << mk_pp(var, m) << " := " << mk_pp(value, m) << "\n");
return;
}
if (v == null_theory_var)
return;
if (is_base(v))
return;
update_value(v, inf_numeral(r));
}
#if 0
/**

View file

@ -154,6 +154,7 @@ class theory_lra::imp {
svector<delayed_atom> m_asserted_atoms;
ptr_vector<expr> m_not_handled;
ptr_vector<app> m_underspecified;
vector<std::pair<lpvar, rational>> m_values;
vector<ptr_vector<api_bound> > m_use_list; // bounds where variables are used.
// attributes for incremental version:
@ -991,6 +992,16 @@ public:
return lp().compare_values(vi, k, b->get_value()) ? l_true : l_false;
}
void initialize_value(expr* var, expr* value) {
rational r;
if (!a.is_numeral(value, r)) {
IF_VERBOSE(5, verbose_stream() << "numeric constant expected in initialization " << mk_pp(var, m) << " := " << mk_pp(value, m) << "\n");
return;
}
ctx().push_trail(push_back_vector(m_values));
m_values.push_back({get_lpvar(var), r});
}
void new_eq_eh(theory_var v1, theory_var v2) {
TRACE("arith", tout << "eq " << v1 << " == " << v2 << "\n";);
if (!is_int(v1) && !is_real(v1))
@ -1409,6 +1420,9 @@ public:
void init_search_eh() {
m_arith_eq_adapter.init_search_eh();
m_num_conflicts = 0;
for (auto const& [v, r] : m_values)
lp().move_lpvar_to_value(v, r);
display(verbose_stream() << "init search\n");
}
bool can_get_value(theory_var v) const {
@ -3878,6 +3892,9 @@ void theory_lra::assign_eh(bool_var v, bool is_true) {
lbool theory_lra::get_phase(bool_var v) {
return m_imp->get_phase(v);
}
void theory_lra::initialize_value(expr* var, expr* value) {
m_imp->initialize_value(var, value);
}
void theory_lra::new_eq_eh(theory_var v1, theory_var v2) {
m_imp->new_eq_eh(v1, v2);
}
@ -3912,7 +3929,7 @@ final_check_status theory_lra::final_check_eh() {
}
bool theory_lra::is_shared(theory_var v) const {
return m_imp->is_shared(v);
}
}
bool theory_lra::can_propagate() {
return m_imp->can_propagate();
}

View file

@ -80,6 +80,8 @@ namespace smt {
void apply_sort_cnstr(enode * n, sort * s) override;
void init_model(model_generator & m) override;
void initialize_value(expr* var, expr* value) override;
model_value_proc * mk_value(enode * n, model_generator & mg) override;
void validate_model(proto_model& mdl) override;