mirror of
https://github.com/Z3Prover/z3
synced 2025-04-14 21:08:46 +00:00
bug fixes to min-max, and experiments with hsmax
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
2071029bb3
commit
57fc0f3f55
|
@ -37,6 +37,7 @@ Notes:
|
|||
#include "opt_sls_solver.h"
|
||||
#include "cancel_eh.h"
|
||||
#include "scoped_timer.h"
|
||||
#include "optsmt.h"
|
||||
|
||||
namespace opt {
|
||||
|
||||
|
@ -611,7 +612,11 @@ namespace opt {
|
|||
};
|
||||
|
||||
scoped_ptr<maxsmt_solver_base> maxs;
|
||||
optsmt m_optsmt; // hitting set optimizer based on simplex.
|
||||
opt_solver m_solver;
|
||||
unsigned m_objective; // index of objective
|
||||
expr_ref_vector m_aux; // auxiliary (indicator) variables.
|
||||
expr_ref_vector m_iaux; // auxiliary integer (indicator) variables.
|
||||
expr_ref_vector m_naux; // negation of auxiliary variables.
|
||||
obj_map<expr, unsigned> m_aux2index; // expr |-> index
|
||||
unsigned_vector m_core_activity; // number of times soft constraint is used in a core.
|
||||
|
@ -619,6 +624,7 @@ namespace opt {
|
|||
svector<bool> m_aux_active; // active soft clauses.
|
||||
ptr_vector<expr> m_asms; // assumptions (over aux)
|
||||
pb_util pb;
|
||||
arith_util a;
|
||||
stats m_stats;
|
||||
|
||||
|
||||
|
@ -626,20 +632,30 @@ namespace opt {
|
|||
hsmax(solver* s, ast_manager& m, maxsmt_solver_base* maxs):
|
||||
maxsmt_solver_base(s, m),
|
||||
maxs(maxs),
|
||||
m_optsmt(m),
|
||||
m_solver(m, m_params, symbol()),
|
||||
m_aux(m),
|
||||
m_iaux(m),
|
||||
m_naux(m),
|
||||
pb(m) {
|
||||
pb(m),
|
||||
a(m) {
|
||||
}
|
||||
virtual ~hsmax() {}
|
||||
|
||||
virtual void set_cancel(bool f) {
|
||||
maxsmt_solver_base::set_cancel(f);
|
||||
maxs->set_cancel(f);
|
||||
// maxs->set_cancel(f);
|
||||
m_optsmt.set_cancel(f);
|
||||
}
|
||||
|
||||
virtual void updt_params(params_ref& p) {
|
||||
maxsmt_solver_base::updt_params(p);
|
||||
m_solver.updt_params(p);
|
||||
}
|
||||
|
||||
virtual void collect_statistics(statistics& st) const {
|
||||
maxsmt_solver_base::collect_statistics(st);
|
||||
maxs->collect_statistics(st);
|
||||
// maxs->s().collect_statistics(st);
|
||||
st.update("hsmax-num-iterations", m_stats.m_num_iterations);
|
||||
st.update("hsmax-num-core-reductions-n", m_stats.m_num_core_reductions_failure);
|
||||
st.update("hsmax-num-core-reductions-y", m_stats.m_num_core_reductions_success);
|
||||
|
@ -702,9 +718,12 @@ namespace opt {
|
|||
|
||||
void init_local() {
|
||||
unsigned sz = num_soft();
|
||||
app_ref fml(m), obj(m);
|
||||
expr_ref_vector sum(m);
|
||||
m_asms.reset();
|
||||
m_seed.reset();
|
||||
m_aux.reset();
|
||||
m_iaux.reset();
|
||||
m_naux.reset();
|
||||
m_aux_active.reset();
|
||||
m_aux2index.reset();
|
||||
|
@ -712,17 +731,28 @@ namespace opt {
|
|||
for (unsigned i = 0; i < sz; ++i) {
|
||||
bool tt = is_true(m_model, m_soft[i].get());
|
||||
m_seed.push_back(tt);
|
||||
m_aux. push_back(mk_fresh());
|
||||
m_aux. push_back(mk_fresh(m.mk_bool_sort()));
|
||||
m_iaux.push_back(mk_fresh(a.mk_int()));
|
||||
expr* iaux = m_iaux.back();
|
||||
m_naux.push_back(m.mk_not(m_aux.back()));
|
||||
m_aux_active.push_back(false);
|
||||
m_core_activity.push_back(0);
|
||||
m_aux2index.insert(m_aux[i].get(), i);
|
||||
m_aux2index.insert(m_aux.back(), i);
|
||||
m_aux2index.insert(m_iaux.back(), i);
|
||||
fml = m.mk_and(a.mk_le(a.mk_numeral(rational::zero(), true), iaux),
|
||||
a.mk_le(iaux, a.mk_numeral(rational::one(), true)));
|
||||
rational const& w = m_weights[i];
|
||||
sum.push_back(a.mk_mul(a.mk_numeral(w, w.is_int()), iaux));
|
||||
m_solver.assert_expr(fml);
|
||||
if (tt) {
|
||||
m_asms.push_back(m_aux.back());
|
||||
ensure_active(i);
|
||||
}
|
||||
}
|
||||
maxs->init_soft(m_weights, m_aux);
|
||||
obj = a.mk_add(sum.size(), sum.c_ptr());
|
||||
m_objective = m_optsmt.add(obj);
|
||||
m_optsmt.setup(m_solver);
|
||||
// maxs->init_soft(m_weights, m_aux);
|
||||
TRACE("opt", print_seed(tout););
|
||||
}
|
||||
|
||||
|
@ -858,18 +888,6 @@ namespace opt {
|
|||
}
|
||||
}
|
||||
|
||||
struct cancel_maxs {
|
||||
hsmax& hs;
|
||||
cancel_maxs(hsmax& hs):hs(hs) {}
|
||||
void reset_cancel() {
|
||||
hs.maxs->set_cancel(false);
|
||||
}
|
||||
void cancel() {
|
||||
hs.maxs->set_cancel(true);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// retrieve the next seed that satisfies state of maxs.
|
||||
// state of maxs must be satisfiable before optimization is called.
|
||||
|
@ -881,6 +899,26 @@ namespace opt {
|
|||
lbool next_seed() {
|
||||
scoped_stopwatch _sw(m_stats.m_aux_sat_time);
|
||||
TRACE("opt", tout << "\n";);
|
||||
#if 1
|
||||
m_solver.display(std::cout);
|
||||
lbool is_sat = m_optsmt.lex(m_objective);
|
||||
if (is_sat == l_true) {
|
||||
model_ref mdl;
|
||||
m_optsmt.get_model(mdl);
|
||||
|
||||
for (unsigned i = 0; i < num_soft(); ++i) {
|
||||
if (is_active(i)) {
|
||||
m_seed[i] = is_one(mdl, m_iaux[i].get());
|
||||
}
|
||||
else {
|
||||
m_seed[i] = false;
|
||||
}
|
||||
}
|
||||
print_seed(std::cout);
|
||||
TRACE("opt", print_seed(tout););
|
||||
}
|
||||
|
||||
#else
|
||||
lbool is_sat = maxs->s().check_sat(0,0);
|
||||
if (is_sat == l_true) {
|
||||
maxs->set_model();
|
||||
|
@ -903,6 +941,7 @@ namespace opt {
|
|||
}
|
||||
TRACE("opt", print_seed(tout););
|
||||
}
|
||||
#endif
|
||||
return is_sat;
|
||||
}
|
||||
|
||||
|
@ -1070,6 +1109,16 @@ namespace opt {
|
|||
}
|
||||
expr_ref_vector fmls(m);
|
||||
expr_ref fml(m);
|
||||
#if 1
|
||||
for (unsigned i = 0; i < num_soft(); ++i) {
|
||||
if (!indices.contains(i)) {
|
||||
fmls.push_back(m_iaux[i].get());
|
||||
}
|
||||
}
|
||||
fml = a.mk_ge(a.mk_add(fmls.size(), fmls.c_ptr()), a.mk_numeral(rational::one(), true));
|
||||
m_solver.assert_expr(fml);
|
||||
|
||||
#else
|
||||
for (unsigned i = 0; i < num_soft(); ++i) {
|
||||
if (!indices.contains(i)) {
|
||||
fmls.push_back(m_aux[i].get());
|
||||
|
@ -1077,8 +1126,9 @@ namespace opt {
|
|||
}
|
||||
fml = m.mk_or(fmls.size(), fmls.c_ptr());
|
||||
maxs->add_hard(fml);
|
||||
#endif
|
||||
TRACE("opt", tout << fml << "\n";);
|
||||
set_upper();
|
||||
// set_upper();
|
||||
}
|
||||
|
||||
// constrain the upper bound.
|
||||
|
@ -1093,13 +1143,25 @@ namespace opt {
|
|||
void block_up() {
|
||||
expr_ref_vector fmls(m);
|
||||
expr_ref fml(m);
|
||||
#if 1
|
||||
for (unsigned i = 0; i < m_asms.size(); ++i) {
|
||||
unsigned index = m_aux2index.find(m_asms[i]);
|
||||
m_core_activity[index]++;
|
||||
fmls.push_back(m_iaux[index].get());
|
||||
}
|
||||
fml = a.mk_lt(a.mk_add(fmls.size(), fmls.c_ptr()), a.mk_numeral(rational(fmls.size()), true));
|
||||
TRACE("opt", tout << fml << "\n";);
|
||||
m_solver.assert_expr(fml);
|
||||
#else
|
||||
for (unsigned i = 0; i < m_asms.size(); ++i) {
|
||||
unsigned index = m_aux2index.find(m_asms[i]);
|
||||
fmls.push_back(m.mk_not(m_asms[i]));
|
||||
m_core_activity[m_aux2index.find(m_asms[i])]++;
|
||||
m_core_activity[index]++;
|
||||
}
|
||||
fml = m.mk_or(fmls.size(), fmls.c_ptr());
|
||||
TRACE("opt", tout << fml << "\n";);
|
||||
maxs->add_hard(fml);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -1113,19 +1175,28 @@ namespace opt {
|
|||
}
|
||||
}
|
||||
|
||||
app_ref mk_fresh() {
|
||||
app_ref mk_fresh(sort* s) {
|
||||
app_ref r(m);
|
||||
r = m.mk_fresh_const("r", m.mk_bool_sort());
|
||||
r = m.mk_fresh_const("r", s);
|
||||
m_mc->insert(r->get_decl());
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
bool is_true(model_ref& mdl, expr* e) {
|
||||
expr_ref val(m);
|
||||
VERIFY(mdl->eval(e, val));
|
||||
return m.is_true(val);
|
||||
}
|
||||
|
||||
bool is_one(model_ref& mdl, expr* e) {
|
||||
rational r;
|
||||
expr_ref val(m);
|
||||
VERIFY(mdl->eval(e, val));
|
||||
std::cout << mk_pp(e, m) << " |-> " << val << "\n";
|
||||
return a.is_numeral(val, r) && r.is_one();
|
||||
}
|
||||
|
||||
bool is_active(unsigned i) const {
|
||||
return m_aux_active[i];
|
||||
}
|
||||
|
|
|
@ -857,7 +857,7 @@ namespace smt {
|
|||
void add_tmp_row(row & r1, numeral const & coeff, row const & r2);
|
||||
theory_var pick_var_to_leave(bool has_int, theory_var x_j, bool inc, numeral & a_ij, inf_numeral & gain, bool& skiped_row);
|
||||
bool is_safe_to_leave(theory_var x, bool& has_int);
|
||||
void move_to_bound(theory_var x_i, bool inc);
|
||||
bool move_to_bound(theory_var x_i, bool inc);
|
||||
template<bool invert>
|
||||
void add_tmp_row_entry(row & r, numeral const & coeff, theory_var v);
|
||||
enum max_min_t { UNBOUNDED, AT_BOUND, OPTIMIZED, BEST_EFFORT};
|
||||
|
@ -1061,6 +1061,7 @@ namespace smt {
|
|||
bool valid_row_assignment() const;
|
||||
bool valid_row_assignment(row const & r) const;
|
||||
bool satisfy_bounds() const;
|
||||
bool satisfy_integrality() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -1069,7 +1069,7 @@ namespace smt {
|
|||
|
||||
template<typename Ext>
|
||||
inf_eps_rational<inf_rational> theory_arith<Ext>::maximize(theory_var v, expr_ref& blocker) {
|
||||
TRACE("opt", tout << "data-size: " << m_data.size() << "\n";);
|
||||
TRACE("bound_bug", display_var(tout, v); display(tout););
|
||||
max_min_t r = max_min(v, true);
|
||||
if (r == UNBOUNDED) {
|
||||
blocker = get_manager().mk_false();
|
||||
|
@ -1361,7 +1361,8 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
TRACE("opt", tout << "after traversing row:\nx_i: v" << x_i << ", x_j: v" << x_j << ", gain: " << gain << "\n";
|
||||
tout << "skipped row: " << (skipped_row?"yes":"no") << "\n";);
|
||||
tout << "skipped row: " << (skipped_row?"yes":"no") << "\n";
|
||||
display(tout););
|
||||
|
||||
if (x_j == null_theory_var) {
|
||||
TRACE("opt", tout << "row is " << (max ? "maximized" : "minimized") << "\n";);
|
||||
|
@ -1378,6 +1379,7 @@ namespace smt {
|
|||
TRACE("opt", tout << "moved v" << x_j << " to upper bound\n";);
|
||||
SASSERT(valid_row_assignment());
|
||||
SASSERT(satisfy_bounds());
|
||||
SASSERT(satisfy_integrality());
|
||||
continue;
|
||||
}
|
||||
if (!inc && lower(x_j)) {
|
||||
|
@ -1385,13 +1387,14 @@ namespace smt {
|
|||
TRACE("opt", tout << "moved v" << x_j << " to lower bound\n";);
|
||||
SASSERT(valid_row_assignment());
|
||||
SASSERT(satisfy_bounds());
|
||||
SASSERT(satisfy_integrality());
|
||||
continue;
|
||||
}
|
||||
result = skipped_row?BEST_EFFORT:UNBOUNDED;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_fixed(x_j) && is_bounded(x_j) && (upper_bound(x_j) - lower_bound(x_j) <= gain)) {
|
||||
if (!is_fixed(x_j) && is_bounded(x_j) && !skipped_row && (upper_bound(x_j) - lower_bound(x_j) <= gain)) {
|
||||
// can increase/decrease x_j up to upper/lower bound.
|
||||
if (inc) {
|
||||
update_value(x_j, upper_bound(x_j) - get_value(x_j));
|
||||
|
@ -1403,6 +1406,7 @@ namespace smt {
|
|||
}
|
||||
SASSERT(valid_row_assignment());
|
||||
SASSERT(satisfy_bounds());
|
||||
SASSERT(satisfy_integrality());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1425,7 +1429,10 @@ namespace smt {
|
|||
move_xi_to_lower = a_ij.is_pos();
|
||||
else
|
||||
move_xi_to_lower = a_ij.is_neg();
|
||||
move_to_bound(x_i, move_xi_to_lower);
|
||||
if (!move_to_bound(x_i, move_xi_to_lower)) {
|
||||
result = BEST_EFFORT;
|
||||
break;
|
||||
}
|
||||
|
||||
row & r2 = m_rows[get_var_row(x_j)];
|
||||
coeff.neg();
|
||||
|
@ -1433,6 +1440,7 @@ namespace smt {
|
|||
SASSERT(r.get_idx_of(x_j) == -1);
|
||||
SASSERT(valid_row_assignment());
|
||||
SASSERT(satisfy_bounds());
|
||||
SASSERT(satisfy_integrality());
|
||||
}
|
||||
TRACE("opt", display(tout););
|
||||
return result;
|
||||
|
@ -1444,7 +1452,7 @@ namespace smt {
|
|||
*/
|
||||
|
||||
template<typename Ext>
|
||||
void theory_arith<Ext>::move_to_bound(theory_var x_i, bool move_to_lower) {
|
||||
bool theory_arith<Ext>::move_to_bound(theory_var x_i, bool move_to_lower) {
|
||||
inf_numeral delta, delta_abs;
|
||||
|
||||
if (move_to_lower) {
|
||||
|
@ -1484,6 +1492,9 @@ namespace smt {
|
|||
}
|
||||
}
|
||||
|
||||
if (is_int(x_i)) {
|
||||
delta_abs = floor(delta_abs);
|
||||
}
|
||||
|
||||
if (move_to_lower) {
|
||||
delta = -delta_abs;
|
||||
|
@ -1493,8 +1504,8 @@ namespace smt {
|
|||
}
|
||||
|
||||
TRACE("opt", tout << "Safe delta: " << delta << "\n";);
|
||||
|
||||
update_value(x_i, delta);
|
||||
return !delta.is_zero();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -199,6 +199,18 @@ namespace smt {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
bool theory_arith<Ext>::satisfy_integrality() const {
|
||||
int num = get_num_vars();
|
||||
for (theory_var v = 0; v < num; v++) {
|
||||
if (!(is_int(v) && get_value(v).is_int())) {
|
||||
TRACE("bound_bug", display_var(tout, v); display(tout););
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue