3
0
Fork 0
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:
Nikolaj Bjorner 2014-05-28 15:44:39 -07:00
parent 2071029bb3
commit 57fc0f3f55
4 changed files with 124 additions and 29 deletions

View file

@ -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];
}

View file

@ -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
};

View file

@ -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();
}
/**

View file

@ -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
};