3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-23 03:27:52 +00:00

fixes to mostly solver arith/euf and backtracking scopes

This commit is contained in:
Nikolaj Bjorner 2020-10-26 11:06:34 -07:00
parent 1ee2ba2a9b
commit 8d76470a8a
25 changed files with 189 additions and 93 deletions

View file

@ -96,6 +96,8 @@ namespace sat {
virtual void push() = 0;
void push_scopes(unsigned n) { for (unsigned i = 0; i < n; ++i) push(); }
virtual void pop(unsigned n) = 0;
virtual void user_push() { push(); }
virtual void user_pop(unsigned n) { pop(n); }
virtual void pre_simplify() {}
virtual void simplify() {}
// have a way to replace l by r in all constraints

View file

@ -109,7 +109,13 @@ namespace sat {
void solver::set_extension(extension* ext) {
m_ext = ext;
if (ext) ext->set_solver(this);
if (ext) {
ext->set_solver(this);
for (unsigned i = num_user_scopes(); i-- > 0;)
ext->user_push();
for (unsigned i = num_scopes(); i-- > 0;)
ext->push();
}
}
void solver::copy(solver const & src, bool copy_learned) {
@ -3622,6 +3628,8 @@ namespace sat {
lit = literal(new_v, false);
m_user_scope_literals.push_back(lit);
m_cut_simplifier = nullptr; // for simplicity, wipe it out
if (m_ext)
m_ext->user_push();
TRACE("sat", tout << "user_push: " << lit << "\n";);
}
@ -3704,6 +3712,8 @@ namespace sat {
void solver::user_pop(unsigned num_scopes) {
pop_to_base_level();
TRACE("sat", display(tout););
if (m_ext)
m_ext->user_pop(num_scopes);
while (num_scopes > 0) {
literal lit = m_user_scope_literals.back();
m_user_scope_literals.pop_back();

View file

@ -257,9 +257,8 @@ public:
}
void push_internal() {
m_goal2sat.user_push();
m_solver.user_push();
if (get_euf())
get_euf()->user_push();
++m_num_scopes;
m_mcs.push_back(m_mcs.back());
m_fmls_lim.push_back(m_fmls.size());
@ -279,6 +278,7 @@ public:
m_map.pop(n);
SASSERT(n <= m_num_scopes);
m_solver.user_pop(n);
m_goal2sat.user_pop(n);
m_num_scopes -= n;
// ? m_internalized_converted = false;
m_has_uninterpreted.pop(n);
@ -339,12 +339,8 @@ public:
m_params.set_sym("pb.solver", p1.pb_solver());
m_solver.updt_params(m_params);
m_solver.set_incremental(is_incremental() && !override_incremental());
if (p1.euf() && !get_euf()) {
ensure_euf();
for (unsigned i = 0; i < m_num_scopes; ++i)
get_euf()->user_push();
}
if (p1.euf() && !get_euf())
ensure_euf();
}
void collect_statistics(statistics & st) const override {
if (m_preprocess) m_preprocess->collect_statistics(st);

View file

@ -332,8 +332,6 @@ namespace arith {
le = mk_literal(a.mk_le(diff, zero));
ge = mk_literal(a.mk_ge(diff, zero));
}
// std::cout << "eq " << mk_pp(e1, m) << " " << mk_pp(e2, m) << " ";
// std::cout << le << " " << ge << "\n";
add_clause(~eq, le);
add_clause(~eq, ge);
add_clause(~le, ~ge, eq);

View file

@ -39,14 +39,27 @@ namespace arith {
auto t = get_tv(v);
auto vi = lp().external_to_column_index(v);
out << "v" << v << " ";
if (t.is_null()) out << "null"; else out << (t.is_term() ? "t" : "j") << vi;
if (m_nla && m_nla->use_nra_model() && can_get_ivalue(v)) {
scoped_anum an(m_nla->am());
m_nla->am().display(out << " = ", nl_value(v, an));
if (is_bool(v)) {
euf::enode* n = var2enode(v);
api_bound* b = nullptr;
if (m_bool_var2bound.find(n->bool_var(), b)) {
sat::literal lit = b->get_lit();
out << lit << " " << s().value(lit);
}
}
else {
if (t.is_null())
out << "null";
else
out << (t.is_term() ? "t" : "j") << vi;
if (m_nla && m_nla->use_nra_model() && can_get_ivalue(v)) {
scoped_anum an(m_nla->am());
m_nla->am().display(out << " = ", nl_value(v, an));
}
else if (can_get_value(v)) out << " = " << get_value(v);
if (is_int(v)) out << ", int";
if (ctx.is_shared(var2enode(v))) out << ", shared";
}
else if (can_get_value(v)) out << " = " << get_value(v);
if (is_int(v)) out << ", int";
if (ctx.is_shared(var2enode(v))) out << ", shared";
out << " := " << mk_bounded_pp(var2expr(v), m) << "\n";
}
return out;

View file

@ -21,7 +21,7 @@ Author:
namespace arith {
sat::literal solver::internalize(expr* e, bool sign, bool root, bool learned) {
force_push();
init_internalize();
flet<bool> _is_learned(m_is_redundant, learned);
internalize_atom(e);
literal lit = ctx.expr2literal(e);
@ -31,7 +31,7 @@ namespace arith {
}
void solver::internalize(expr* e, bool redundant) {
force_push();
init_internalize();
flet<bool> _is_learned(m_is_redundant, redundant);
if (m.is_bool(e))
internalize_atom(e);
@ -39,6 +39,19 @@ namespace arith {
internalize_term(e);
}
void solver::init_internalize() {
force_push();
// initialize 0, 1 variables:
if (!m_internalize_initialized) {
get_one(true);
get_one(false);
get_zero(true);
get_zero(false);
ctx.push(value_trail<euf::solver, bool>(m_internalize_initialized));
m_internalize_initialized = true;
}
}
lpvar solver::get_one(bool is_int) {
return add_const(1, is_int ? m_one_var : m_rone_var, is_int);
}
@ -113,11 +126,11 @@ namespace arith {
if (var != UINT_MAX) {
return var;
}
ctx.push(value_trail<euf::solver, lpvar>(var));
app_ref cnst(a.mk_numeral(rational(c), is_int), m);
mk_enode(cnst);
theory_var v = mk_evar(cnst);
var = lp().add_var(v, is_int);
lp().push();
add_def_constraint_and_equality(var, lp::GE, rational(c));
add_def_constraint_and_equality(var, lp::LE, rational(c));
TRACE("arith", tout << "add " << cnst << ", var = " << var << "\n";);
@ -540,11 +553,15 @@ namespace arith {
enode* n = ctx.get_enode(e);
if (n)
return n;
ptr_buffer<enode> args;
if (reflect(e))
for (expr* arg : *to_app(e))
args.push_back(e_internalize(arg));
n = ctx.mk_enode(e, args.size(), args.c_ptr());
if (!a.is_arith_expr(e))
n = e_internalize(e);
else {
ptr_buffer<enode> args;
if (reflect(e))
for (expr* arg : *to_app(e))
args.push_back(e_internalize(arg));
n = ctx.mk_enode(e, args.size(), args.c_ptr());
}
return n;
}
@ -597,7 +614,7 @@ namespace arith {
}
bool solver::reflect(expr* n) const {
return get_config().m_arith_reflect || a.is_underspecified(n);
return get_config().m_arith_reflect || a.is_underspecified(n) || !a.is_arith_expr(n);
}
lpvar solver::get_lpvar(theory_var v) const {

View file

@ -32,11 +32,6 @@ namespace arith {
{
reset_variable_values();
m_solver = alloc(lp::lar_solver);
// initialize 0, 1 variables:
get_one(true);
get_one(false);
get_zero(true);
get_zero(false);
smt_params_helper lpar(ctx.s().params());
lp().settings().set_resource_limit(m_resource_limit);
@ -556,8 +551,35 @@ namespace arith {
return end;
}
void solver::init_model() {
init_variable_values();
void solver::dbg_finalize_model(model& mdl) {
bool found_bad = false;
for (unsigned v = 0; v < get_num_vars(); ++v) {
if (!is_bool(v))
continue;
euf::enode* n = var2enode(v);
api_bound* b = nullptr;
if (!m_bool_var2bound.find(n->bool_var(), b)) {
IF_VERBOSE(0, verbose_stream() << "no boolean variable\n";);
continue;
}
lbool value = n->value();
expr_ref eval = mdl(var2expr(v));
if (m.is_true(eval) && l_false == value)
found_bad = true;
if (m.is_false(eval) && l_true == value)
found_bad = true;
if (b->get_lit().sign())
value = ~value;
if (!found_bad && value == get_phase(n->bool_var()))
continue;
IF_VERBOSE(0,
verbose_stream() << eval << " " << value << " " << ctx.bpp(n) << "\n";
verbose_stream() << n->bool_var() << " " << n->value() << " " << get_phase(n->bool_var()) << " " << ctx.bpp(n) << "\n";
verbose_stream() << *b << "\n";);
IF_VERBOSE(0, ctx.display(verbose_stream()));
UNREACHABLE();
}
}
void solver::add_value(euf::enode* n, model& mdl, expr_ref_vector& values) {

View file

@ -208,9 +208,7 @@ namespace arith {
svector<enode_pair> m_eqs;
vector<parameter> m_params;
nla::lemma m_lemma;
arith_util a;
arith_util a;
bool is_int(theory_var v) const { return is_int(var2enode(v)); }
bool is_int(euf::enode* n) const { return a.is_int(n->get_expr()); }
@ -221,6 +219,8 @@ namespace arith {
// internalize
bool m_internalize_initialized { false };
void init_internalize();
lpvar add_const(int c, lpvar& var, bool is_int);
lpvar get_one(bool is_int);
lpvar get_zero(bool is_int);
@ -408,6 +408,7 @@ namespace arith {
void assign(literal lit, literal_vector const& core, svector<enode_pair> const& eqs, vector<parameter> const& params);
void false_case_of_check_nla(const nla::lemma& l);
void dbg_finalize_model(model& mdl);
public:
solver(euf::solver& ctx, theory_id id);
@ -426,7 +427,8 @@ namespace arith {
void new_eq_eh(euf::th_eq const& eq) override { mk_eq_axiom(true, eq.v1(), eq.v2()); }
void new_diseq_eh(euf::th_eq const& de) override { mk_eq_axiom(false, de.v1(), de.v2()); }
bool unit_propagate() override;
void init_model() override;
void init_model() override { init_variable_values(); }
void finalize_model(model& mdl) override { DEBUG_CODE(dbg_finalize_model(mdl);); }
void add_value(euf::enode* n, model& mdl, expr_ref_vector& values) override;
sat::literal internalize(expr* e, bool sign, bool root, bool learned) override;
void internalize(expr* e, bool redundant) override;

View file

@ -60,7 +60,6 @@ namespace euf {
SASSERT(get_enode(e));
if (m.is_bool(e))
return literal(si.to_bool_var(e), sign);
std::cout << "internalize-non-bool\n";
return sat::null_literal;
}

View file

@ -31,8 +31,11 @@ namespace euf {
}
void solver::ensure_dual_solver() {
if (!m_dual_solver)
if (!m_dual_solver) {
m_dual_solver = alloc(sat::dual_solver, s().rlimit());
for (unsigned i = s().num_user_scopes(); i-- > 0; )
m_dual_solver->push();
}
}
void solver::add_root(unsigned n, sat::literal const* lits) {
@ -79,7 +82,6 @@ namespace euf {
continue;
expr* c = nullptr, *th = nullptr, *el = nullptr;
if (m.is_ite(e, c, th, el)) {
std::cout << mk_pp(c, m) << "\n";
sat::literal lit = expr2literal(c);
todo.push_back(c);
switch (s().value(lit)) {

View file

@ -126,7 +126,7 @@ namespace euf {
if (use_drat())
s().get_drat().add_theory(fid, th->name());
th->set_solver(m_solver);
th->push_scopes(s().num_scopes());
th->push_scopes(s().num_scopes() + s().num_user_scopes());
m_solvers.push_back(th);
m_id2solver.setx(fid, th, nullptr);
if (th->use_diseqs())
@ -430,18 +430,6 @@ namespace euf {
m_egraph.push();
}
void solver::user_push() {
push();
if (m_dual_solver)
m_dual_solver->push();
}
void solver::user_pop(unsigned n) {
pop(n);
if (m_dual_solver)
m_dual_solver->pop(n);
}
void solver::pop(unsigned n) {
start_reinit(n);
m_trail.pop_scope(n);
@ -455,7 +443,19 @@ namespace euf {
m_var_trail.shrink(s.m_var_lim);
m_scopes.shrink(m_scopes.size() - n);
SASSERT(m_egraph.num_scopes() == m_scopes.size());
TRACE("euf", display(tout << "pop to: " << m_scopes.size() << "\n"););
TRACE("euf_verbose", display(tout << "pop to: " << m_scopes.size() << "\n"););
}
void solver::user_push() {
push();
if (m_dual_solver)
m_dual_solver->push();
}
void solver::user_pop(unsigned n) {
pop(n);
if (m_dual_solver)
m_dual_solver->pop(n);
}
void solver::start_reinit(unsigned n) {
@ -487,6 +487,8 @@ namespace euf {
}
};
scoped_set_replay replay(*this);
scoped_suspend_rlimit suspend_rlimit(m.limit());
unsigned i = 0;
for (sat::bool_var v : s().get_vars_to_reinit()) {
expr* e = m_reinit_exprs.get(i++);
@ -696,7 +698,7 @@ namespace euf {
unsigned solver::max_var(unsigned w) const {
for (auto* e : m_solvers)
w = e->max_var(w);
for (unsigned sz = m_bool_var2expr.size(); sz-- > 0; ) {
for (unsigned sz = m_bool_var2expr.size(); sz > w && sz-- > 0; ) {
expr* n = m_bool_var2expr[sz];
if (n && m.is_bool(n)) {
w = std::max(w, sz);

View file

@ -261,8 +261,8 @@ namespace euf {
sat::check_result check() override;
void push() override;
void pop(unsigned n) override;
void user_push();
void user_pop(unsigned n);
void user_push() override;
void user_pop(unsigned n) override;
void pre_simplify() override;
void simplify() override;
// have a way to replace l by r in all constraints

View file

@ -158,6 +158,7 @@ namespace q {
mbody = subst(mbody, result->vars);
if (is_forall(q))
mbody = mk_not(m, mbody);
TRACE("q", tout << "specialize " << mbody << "\n";);
return result;
}
@ -187,9 +188,11 @@ namespace q {
expr_ref mbqi::solver_project(model& mdl, q_body& qb) {
for (app* v : qb.vars)
m_model->register_decl(v->get_decl(), mdl(v));
std::cout << "Project\n";
std::cout << *m_model << "\n";
std::cout << qb.vbody << "\n";
TRACE("q",
tout << "Project\n";
tout << *m_model << "\n";
tout << qb.vbody << "\n";
tout << "model of projection\n" << mdl << "\n";);
expr_ref_vector fmls(qb.vbody);
app_ref_vector vars(qb.vars);
mbp::project_plugin proj(m);

View file

@ -71,6 +71,7 @@ namespace q {
if (univ.empty())
return;
TRACE("q", tout << "start: " << mdl << "\n";);
m_dependencies.reset();
m_projection_data.reset();
m_projection_pinned.reset();
@ -88,6 +89,7 @@ namespace q {
univ.append(residue);
add_projection_functions(mdl, univ);
TRACE("q", tout << "end: " << mdl << "\n";);
}
quantifier_macro_info* model_fixer::operator()(quantifier* q) {
@ -103,11 +105,9 @@ namespace q {
void model_fixer::add_projection_functions(model& mdl, ptr_vector<quantifier> const& qs) {
func_decl_set fns;
TRACE("q", tout << mdl << "\n";);
collect_partial_functions(qs, fns);
for (func_decl* f : fns)
add_projection_functions(mdl, f);
TRACE("q", tout << mdl << "\n";);
}
void model_fixer::add_projection_functions(model& mdl, func_decl* f) {

View file

@ -606,8 +606,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
if (!ext) {
euf = alloc(euf::solver, m, *this);
m_solver.set_extension(euf);
for (unsigned i = m_solver.num_scopes(); i-- > 0; )
euf->push();
#if 0
std::function<solver*(void)> mk_solver = [&]() {
return mk_inc_sat_solver(m, m_params, true);
@ -911,6 +909,14 @@ struct goal2sat::imp : public sat::sat_internalizer {
ext->update_model(mdl);
}
void user_push() {
}
void user_pop(unsigned n) {
m_true = sat::null_literal;
}
};
struct unsupported_bool_proc {
@ -984,6 +990,16 @@ void goal2sat::update_model(model_ref& mdl) {
m_imp->update_model(mdl);
}
void goal2sat::user_push() {
if (m_imp)
m_imp->user_push();
}
void goal2sat::user_pop(unsigned n) {
if (m_imp)
m_imp->user_pop(n);
}
sat::sat_internalizer& goal2sat::si(ast_manager& m, params_ref const& p, sat::solver_core& t, atom2bool_var& a2b, dep2asm_map& dep2asm, bool default_external) {
if (!m_imp)

View file

@ -69,6 +69,10 @@ public:
void update_model(model_ref& mdl);
void user_push();
void user_pop(unsigned n);
};