mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 00:55:31 +00:00
fix mb maximization logic, so far not accessible
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
c7ff05cc78
commit
9c099d6b1b
12 changed files with 318 additions and 109 deletions
|
@ -105,7 +105,10 @@ namespace qe {
|
|||
expr_ref t(m);
|
||||
opt::ineq_type ty = opt::t_le;
|
||||
expr* e1, *e2;
|
||||
DEBUG_CODE(expr_ref val(m); VERIFY(model.eval(lit, val) && m.is_true(val)););
|
||||
DEBUG_CODE(expr_ref val(m);
|
||||
VERIFY(model.eval(lit, val));
|
||||
CTRACE("qe", !m.is_true(val), tout << mk_pp(lit, m) << " := " << val << "\n";);
|
||||
SASSERT(m.is_true(val)););
|
||||
|
||||
bool is_not = m.is_not(lit, lit);
|
||||
if (is_not) {
|
||||
|
@ -942,7 +945,7 @@ namespace qe {
|
|||
SASSERT(m_u < m_delta && rational(0) <= m_u);
|
||||
for (unsigned i = 0; i < n; ++i) {
|
||||
add_lit(model, lits, mk_divides(div_divisor(i),
|
||||
mk_add(mk_num(div_coeff(i) * m_u), div_term(i))));
|
||||
mk_add(mk_num(div_coeff(i) * m_u), div_term(i))));
|
||||
}
|
||||
reset_divs();
|
||||
//
|
||||
|
@ -1070,7 +1073,7 @@ namespace qe {
|
|||
|
||||
for (unsigned i = 0; i < rows.size(); ++i) {
|
||||
expr_ref_vector ts(m);
|
||||
expr_ref t(m), s(m);
|
||||
expr_ref t(m), s(m), val(m);
|
||||
row const& r = rows[i];
|
||||
if (r.m_vars.size() == 0) {
|
||||
continue;
|
||||
|
@ -1088,6 +1091,8 @@ namespace qe {
|
|||
case opt::t_eq: t = a.mk_eq(t, s); break;
|
||||
}
|
||||
fmls.push_back(t);
|
||||
VERIFY(model.eval(t, val));
|
||||
CTRACE("qe", !m.is_true(val), tout << "Evaluated unit " << t << " to " << val << "\n";);
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < r.m_vars.size(); ++j) {
|
||||
|
@ -1111,10 +1116,16 @@ namespace qe {
|
|||
case opt::t_eq: t = a.mk_eq(t, s); break;
|
||||
}
|
||||
fmls.push_back(t);
|
||||
|
||||
|
||||
VERIFY(model.eval(t, val));
|
||||
CTRACE("qe", !m.is_true(val), tout << "Evaluated " << t << " to " << val << "\n";);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
opt::inf_eps maximize(expr_ref_vector const& fmls0, model& mdl, app* t, expr_ref& bound) {
|
||||
opt::inf_eps maximize(expr_ref_vector const& fmls0, model& mdl, app* t, expr_ref& ge, expr_ref& gt) {
|
||||
validate_model(mdl, fmls0);
|
||||
m_trail.reset();
|
||||
SASSERT(a.is_real(t));
|
||||
expr_ref_vector fmls(fmls0);
|
||||
|
@ -1139,11 +1150,6 @@ namespace qe {
|
|||
// find optimal value
|
||||
value = mbo.maximize();
|
||||
|
||||
expr_ref val(a.mk_numeral(value.get_rational(), false), m);
|
||||
if (!value.is_finite()) {
|
||||
bound = m.mk_false();
|
||||
return value;
|
||||
}
|
||||
|
||||
// update model to use new values that satisfy optimality
|
||||
ptr_vector<expr> vars;
|
||||
|
@ -1160,17 +1166,42 @@ namespace qe {
|
|||
TRACE("qe", tout << "omitting model update for non-uninterpreted constant " << mk_pp(e, m) << "\n";);
|
||||
}
|
||||
}
|
||||
expr_ref val(a.mk_numeral(value.get_rational(), false), m);
|
||||
expr_ref tval(m);
|
||||
VERIFY (mdl.eval(t, tval));
|
||||
|
||||
// update the predicate 'bound' which forces larger values.
|
||||
if (value.get_infinitesimal().is_neg()) {
|
||||
bound = a.mk_le(val, t);
|
||||
// update the predicate 'bound' which forces larger values when 'strict' is true.
|
||||
// strict: bound := valuue < t
|
||||
// !strict: bound := value <= t
|
||||
if (!value.is_finite()) {
|
||||
ge = a.mk_ge(t, tval);
|
||||
gt = m.mk_false();
|
||||
}
|
||||
else if (value.get_infinitesimal().is_neg()) {
|
||||
ge = a.mk_ge(t, tval);
|
||||
gt = a.mk_ge(t, val);
|
||||
}
|
||||
else {
|
||||
bound = a.mk_lt(val, t);
|
||||
}
|
||||
ge = a.mk_ge(t, val);
|
||||
gt = a.mk_gt(t, val);
|
||||
}
|
||||
validate_model(mdl, fmls0);
|
||||
return value;
|
||||
}
|
||||
|
||||
bool validate_model(model& mdl, expr_ref_vector const& fmls) {
|
||||
bool valid = true;
|
||||
for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||
expr_ref val(m);
|
||||
VERIFY(mdl.eval(fmls[i], val));
|
||||
if (!m.is_true(val)) {
|
||||
valid = false;
|
||||
TRACE("qe", tout << mk_pp(fmls[i], m) << " := " << val << "\n";);
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
void extract_coefficients(opt::model_based_opt& mbo, model& model, obj_map<expr, rational> const& ts, obj_map<expr, unsigned>& tids, vars& coeffs) {
|
||||
coeffs.reset();
|
||||
obj_map<expr, rational>::iterator it = ts.begin(), end = ts.end();
|
||||
|
@ -1219,8 +1250,8 @@ namespace qe {
|
|||
return m_imp->a.get_family_id();
|
||||
}
|
||||
|
||||
opt::inf_eps arith_project_plugin::maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& bound) {
|
||||
return m_imp->maximize(fmls, mdl, t, bound);
|
||||
opt::inf_eps arith_project_plugin::maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt) {
|
||||
return m_imp->maximize(fmls, mdl, t, ge, gt);
|
||||
}
|
||||
|
||||
bool arith_project(model& model, app* var, expr_ref_vector& lits) {
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace qe {
|
|||
virtual void operator()(model& model, app_ref_vector& vars, expr_ref_vector& lits);
|
||||
|
||||
|
||||
opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& bound);
|
||||
opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt);
|
||||
};
|
||||
|
||||
bool arith_project(model& model, app* var, expr_ref_vector& lits);
|
||||
|
|
|
@ -285,9 +285,9 @@ class mbp::impl {
|
|||
public:
|
||||
|
||||
|
||||
opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& bound) {
|
||||
opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt) {
|
||||
arith_project_plugin arith(m);
|
||||
return arith.maximize(fmls, mdl, t, bound);
|
||||
return arith.maximize(fmls, mdl, t, ge, gt);
|
||||
}
|
||||
|
||||
void extract_literals(model& model, expr_ref_vector& fmls) {
|
||||
|
@ -428,7 +428,16 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
bool validate_model(model& model, expr_ref_vector const& fmls) {
|
||||
expr_ref val(m);
|
||||
for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||
VERIFY(model.eval(fmls[i], val) && m.is_true(val));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void operator()(bool force_elim, app_ref_vector& vars, model& model, expr_ref_vector& fmls) {
|
||||
SASSERT(validate_model(model, fmls));
|
||||
expr_ref val(m), tmp(m);
|
||||
app_ref var(m);
|
||||
expr_ref_vector unused_fmls(m);
|
||||
|
@ -446,6 +455,7 @@ public:
|
|||
}
|
||||
}
|
||||
while (!vars.empty() && !fmls.empty()) {
|
||||
std::cout << "mbp: " << var << "\n";
|
||||
var = vars.back();
|
||||
vars.pop_back();
|
||||
project_plugin* p = get_plugin(var);
|
||||
|
@ -483,6 +493,7 @@ public:
|
|||
vars.reset();
|
||||
}
|
||||
fmls.append(unused_fmls);
|
||||
SASSERT(validate_model(model, fmls));
|
||||
TRACE("qe", tout << vars << " " << fmls << "\n";);
|
||||
}
|
||||
|
||||
|
@ -508,6 +519,6 @@ void mbp::extract_literals(model& model, expr_ref_vector& lits) {
|
|||
m_impl->extract_literals(model, lits);
|
||||
}
|
||||
|
||||
opt::inf_eps mbp::maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& bound) {
|
||||
return m_impl->maximize(fmls, mdl, t, bound);
|
||||
opt::inf_eps mbp::maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt) {
|
||||
return m_impl->maximize(fmls, mdl, t, ge, gt);
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace qe {
|
|||
\brief
|
||||
Maximize objective t under current model for constraints in fmls.
|
||||
*/
|
||||
opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& bound);
|
||||
opt::inf_eps maximize(expr_ref_vector const& fmls, model& mdl, app* t, expr_ref& ge, expr_ref& gt);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
127
src/qe/qsat.cpp
127
src/qe/qsat.cpp
|
@ -507,6 +507,26 @@ namespace qe {
|
|||
}
|
||||
}
|
||||
|
||||
bool pred_abs::validate_defs(model& model) const {
|
||||
bool valid = true;
|
||||
obj_map<expr, expr*>::iterator it = m_pred2lit.begin(), end = m_pred2lit.end();
|
||||
for (; it != end; ++it) {
|
||||
expr_ref val_a(m), val_b(m);
|
||||
expr* a = it->m_key;
|
||||
expr* b = it->m_value;
|
||||
VERIFY(model.eval(a, val_a));
|
||||
VERIFY(model.eval(b, val_b));
|
||||
if (val_a != val_b) {
|
||||
TRACE("qe",
|
||||
tout << mk_pp(a, m) << " := " << val_a << "\n";
|
||||
tout << mk_pp(b, m) << " := " << val_b << "\n";
|
||||
tout << m_elevel.find(a) << "\n";);
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
class kernel {
|
||||
ast_manager& m;
|
||||
params_ref m_params;
|
||||
|
@ -575,6 +595,9 @@ namespace qe {
|
|||
app* m_objective;
|
||||
opt::inf_eps* m_value;
|
||||
bool m_was_sat;
|
||||
model_ref m_model_save;
|
||||
expr_ref m_gt;
|
||||
opt::inf_eps m_value_save;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -588,15 +611,23 @@ namespace qe {
|
|||
check_cancel();
|
||||
expr_ref_vector asms(m_asms);
|
||||
m_pred_abs.get_assumptions(m_model.get(), asms);
|
||||
if (m_model.get()) {
|
||||
validate_assumptions(*m_model.get(), asms);
|
||||
}
|
||||
TRACE("qe", tout << asms << "\n";);
|
||||
solver& s = get_kernel(m_level).s();
|
||||
lbool res = s.check_sat(asms);
|
||||
switch (res) {
|
||||
case l_true:
|
||||
s.get_model(m_model);
|
||||
SASSERT(validate_defs("check_sat"));
|
||||
SASSERT(validate_assumptions(*m_model.get(), asms));
|
||||
SASSERT(validate_model(asms));
|
||||
TRACE("qe", s.display(tout); display(tout << "\n", *m_model.get()); display(tout, asms); );
|
||||
push();
|
||||
if (m_level == 1 && m_mode == qsat_maximize) {
|
||||
maximize_model();
|
||||
}
|
||||
break;
|
||||
case l_false:
|
||||
switch (m_level) {
|
||||
|
@ -607,6 +638,7 @@ namespace qe {
|
|||
return l_true;
|
||||
}
|
||||
if (m_model.get()) {
|
||||
SASSERT(validate_assumptions(*m_model.get(), asms));
|
||||
if (!project_qe(asms)) return l_undef;
|
||||
}
|
||||
else {
|
||||
|
@ -734,7 +766,28 @@ namespace qe {
|
|||
}
|
||||
}
|
||||
|
||||
bool validate_defs(char const* msg) {
|
||||
if (m_model.get() && !m_pred_abs.validate_defs(*m_model.get())) {
|
||||
TRACE("qe",
|
||||
tout << msg << "\n";
|
||||
display(tout);
|
||||
if (m_level > 0) {
|
||||
get_kernel(m_level-1).s().display(tout);
|
||||
}
|
||||
expr_ref_vector asms(m);
|
||||
m_pred_abs.get_assumptions(m_model.get(), asms);
|
||||
tout << asms << "\n";
|
||||
m_pred_abs.pred2lit(asms);
|
||||
tout << asms << "\n";);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool get_core(expr_ref_vector& core, unsigned level) {
|
||||
SASSERT(validate_defs("get_core"));
|
||||
get_kernel(level).get_core(core);
|
||||
m_pred_abs.pred2lit(core);
|
||||
return true;
|
||||
|
@ -814,33 +867,33 @@ namespace qe {
|
|||
if (!get_core(core, m_level)) {
|
||||
return false;
|
||||
}
|
||||
SASSERT(validate_core(core));
|
||||
SASSERT(validate_core(mdl, core));
|
||||
get_vars(m_level);
|
||||
SASSERT(validate_assumptions(mdl, core));
|
||||
m_mbp(force_elim(), m_avars, mdl, core);
|
||||
SASSERT(validate_defs("project_qe"));
|
||||
if (m_mode == qsat_maximize) {
|
||||
maximize(core, mdl);
|
||||
pop(1);
|
||||
maximize_core(core, mdl);
|
||||
}
|
||||
else {
|
||||
fml = negate_core(core);
|
||||
add_assumption(fml);
|
||||
m_answer.push_back(fml);
|
||||
m_free_vars.append(m_avars);
|
||||
pop(1);
|
||||
}
|
||||
pop(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool project(expr_ref_vector& core) {
|
||||
if (!get_core(core, m_level)) return false;
|
||||
TRACE("qe", display(tout); display(tout << "core\n", core););
|
||||
SASSERT(validate_core(core));
|
||||
SASSERT(m_level >= 2);
|
||||
expr_ref fml(m);
|
||||
expr_ref_vector defs(m), core_save(m);
|
||||
max_level level;
|
||||
model& mdl = *m_model.get();
|
||||
|
||||
SASSERT(validate_core(mdl, core));
|
||||
get_vars(m_level-1);
|
||||
SASSERT(validate_project(mdl, core));
|
||||
m_mbp(force_elim(), m_avars, mdl, core);
|
||||
|
@ -875,6 +928,7 @@ namespace qe {
|
|||
fml = m_pred_abs.mk_abstract(fml);
|
||||
get_kernel(m_level).assert_expr(fml);
|
||||
}
|
||||
SASSERT(!m_model.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1005,7 +1059,19 @@ namespace qe {
|
|||
}
|
||||
}
|
||||
|
||||
bool validate_core(expr_ref_vector const& core) {
|
||||
bool validate_assumptions(model& mdl, expr_ref_vector const& core) {
|
||||
for (unsigned i = 0; i < core.size(); ++i) {
|
||||
expr_ref val(m);
|
||||
VERIFY(mdl.eval(core[i], val));
|
||||
if (!m.is_true(val)) {
|
||||
TRACE("qe", tout << "component of core is not true: " << mk_pp(core[i], m) << "\n";);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool validate_core(model& mdl, expr_ref_vector const& core) {
|
||||
return true;
|
||||
#if 0
|
||||
TRACE("qe", tout << "Validate core\n";);
|
||||
|
@ -1130,7 +1196,8 @@ namespace qe {
|
|||
m_free_vars(m),
|
||||
m_objective(0),
|
||||
m_value(0),
|
||||
m_was_sat(false)
|
||||
m_was_sat(false),
|
||||
m_gt(m)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
@ -1258,6 +1325,7 @@ namespace qe {
|
|||
m_objective = t;
|
||||
m_value = &value;
|
||||
m_was_sat = false;
|
||||
m_model_save.reset();
|
||||
m_pred_abs.abstract_atoms(fml, defs);
|
||||
fml = m_pred_abs.mk_abstract(fml);
|
||||
m_ex.assert_expr(mk_and(defs));
|
||||
|
@ -1271,6 +1339,7 @@ namespace qe {
|
|||
if (!m_was_sat) {
|
||||
return l_false;
|
||||
}
|
||||
mdl = m_model_save;
|
||||
break;
|
||||
case l_true:
|
||||
UNREACHABLE();
|
||||
|
@ -1286,15 +1355,49 @@ namespace qe {
|
|||
return l_true;
|
||||
}
|
||||
|
||||
void maximize(expr_ref_vector const& core, model& mdl) {
|
||||
void maximize_core(expr_ref_vector const& core, model& mdl) {
|
||||
SASSERT(m_value);
|
||||
SASSERT(m_objective);
|
||||
TRACE("qe", tout << "maximize: " << core << "\n";);
|
||||
m_was_sat |= !core.empty();
|
||||
expr_ref bound(m);
|
||||
*m_value = m_mbp.maximize(core, mdl, m_objective, bound);
|
||||
IF_VERBOSE(0, verbose_stream() << "(maximize " << *m_value << " bound: " << bound << ")\n";);
|
||||
m_ex.assert_expr(bound);
|
||||
*m_value = m_value_save;
|
||||
IF_VERBOSE(3, verbose_stream() << "(maximize " << *m_value << ")\n";);
|
||||
m_ex.assert_expr(m_gt);
|
||||
m_fa.assert_expr(m_gt);
|
||||
}
|
||||
|
||||
void maximize_model() {
|
||||
SASSERT(m_level == 1 && m_mode == qsat_maximize);
|
||||
SASSERT(m_objective);
|
||||
expr_ref ge(m);
|
||||
expr_ref_vector asms(m), defs(m);
|
||||
m_pred_abs.get_assumptions(m_model.get(), asms);
|
||||
m_pred_abs.pred2lit(asms);
|
||||
|
||||
SASSERT(validate_defs("maximize_model1"));
|
||||
|
||||
m_value_save = m_mbp.maximize(asms, *m_model.get(), m_objective, ge, m_gt);
|
||||
|
||||
SASSERT(validate_defs("maximize_model2"));
|
||||
|
||||
// bound := val <= m_objective
|
||||
|
||||
IF_VERBOSE(3, verbose_stream() << "(qsat-maximize-bound: " << m_value_save << ")\n";);
|
||||
|
||||
max_level level;
|
||||
m_pred_abs.abstract_atoms(ge, level, defs);
|
||||
m_ex.assert_expr(mk_and(defs));
|
||||
m_fa.assert_expr(mk_and(defs));
|
||||
|
||||
ge = m_pred_abs.mk_abstract(ge);
|
||||
|
||||
SASSERT(is_uninterp_const(ge));
|
||||
// update model with evaluation for bound.
|
||||
if (is_uninterp_const(ge)) {
|
||||
m_model->register_decl(to_app(ge)->get_decl(), m.mk_true());
|
||||
}
|
||||
SASSERT(validate_defs("maximize_model3"));
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -112,6 +112,8 @@ namespace qe {
|
|||
void display(std::ostream& out) const;
|
||||
void display(std::ostream& out, expr_ref_vector const& asms) const;
|
||||
void collect_statistics(statistics& st) const;
|
||||
|
||||
bool validate_defs(model& model) const;
|
||||
};
|
||||
|
||||
class qmax {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue