3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-07-20 03:12:03 +00:00

fixes to maxsmt

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2013-12-14 16:06:03 +02:00
parent 5f72325e99
commit ac893e907f
11 changed files with 124 additions and 113 deletions

View file

@ -22,10 +22,9 @@ Notes:
namespace opt { namespace opt {
core_maxsat::core_maxsat(ast_manager& m, solver& s, expr_ref_vector& soft_constraints): core_maxsat::core_maxsat(ast_manager& m, solver& s, expr_ref_vector& soft_constraints):
m(m), s(s), m_soft(soft_constraints), m_answer(m) { m(m), s(s), m_lower(0), m_upper(soft_constraints.size()), m_soft(soft_constraints) {
m_upper = m_soft.size(); m_answer.resize(m_soft.size(), false);
} }
core_maxsat::~core_maxsat() {} core_maxsat::~core_maxsat() {}
@ -41,7 +40,7 @@ namespace opt {
s.assert_expr(m.mk_or(a, m_soft[i].get())); s.assert_expr(m.mk_or(a, m_soft[i].get()));
block_vars.insert(aux.back()); block_vars.insert(aux.back());
} }
while (m_answer.size() < m_upper) { while (m_lower < m_upper) {
ptr_vector<expr> vars; ptr_vector<expr> vars;
set2vector(block_vars, vars); set2vector(block_vars, vars);
lbool is_sat = s.check_sat(vars.size(), vars.c_ptr()); lbool is_sat = s.check_sat(vars.size(), vars.c_ptr());
@ -51,31 +50,31 @@ namespace opt {
return l_undef; return l_undef;
case l_true: { case l_true: {
model_ref mdl; model_ref mdl;
expr_ref_vector ans(m); svector<bool> ans;
unsigned new_lower = 0;
s.get_model(mdl); s.get_model(mdl);
for (unsigned i = 0; i < aux.size(); ++i) { for (unsigned i = 0; i < aux.size(); ++i) {
expr_ref val(m); expr_ref val(m);
VERIFY(mdl->eval(m_soft[i].get(), val)); VERIFY(mdl->eval(m_soft[i].get(), val));
if (m.is_true(val)) { ans.push_back(m.is_true(val));
ans.push_back(m_soft[i].get()); if (ans.back()) ++new_lower;
}
} }
TRACE("opt", tout << "sat\n"; TRACE("opt", tout << "sat\n";
for (unsigned i = 0; i < ans.size(); ++i) { for (unsigned i = 0; i < ans.size(); ++i) {
tout << mk_pp(ans[i].get(), m) << "\n"; tout << mk_pp(m_soft[i].get(), m) << " |-> " << ans[i] << "\n";
}); });
IF_VERBOSE(1, verbose_stream() << "(maxsat.core sat with lower bound: " << ans.size() << "\n";); IF_VERBOSE(1, verbose_stream() << "(maxsat.core sat with lower bound: " << new_lower << "\n";);
if (ans.size() > m_answer.size()) { if (new_lower > m_lower) {
m_answer.reset(); m_answer.reset();
m_answer.append(ans); m_answer.append(ans);
m_model = mdl.get(); m_model = mdl.get();
m_lower = new_lower;
} }
if (m_answer.size() == m_upper) { if (m_lower == m_upper) {
return l_true; return l_true;
} }
SASSERT(m_soft.size() >= m_answer.size()+1); SASSERT(m_soft.size() >= new_lower+1);
unsigned k = m_soft.size()-m_answer.size()-1; unsigned k = m_soft.size()-new_lower-1;
expr_ref fml = mk_at_most(core_vars, k); expr_ref fml = mk_at_most(core_vars, k);
TRACE("opt", tout << "add: " << fml << "\n";); TRACE("opt", tout << "add: " << fml << "\n";);
s.assert_expr(fml); s.assert_expr(fml);
@ -95,7 +94,7 @@ namespace opt {
} }
IF_VERBOSE(1, verbose_stream() << "(maxsat.core unsat (core size = " << core.size() << ")\n";); IF_VERBOSE(1, verbose_stream() << "(maxsat.core unsat (core size = " << core.size() << ")\n";);
if (core.empty()) { if (core.empty()) {
m_upper = m_answer.size(); m_upper = m_lower;
return l_true; return l_true;
} }
else { else {
@ -134,16 +133,13 @@ namespace opt {
} }
rational core_maxsat::get_lower() const { rational core_maxsat::get_lower() const {
return rational(m_answer.size()); return rational(m_soft.size()-m_upper);
} }
rational core_maxsat::get_upper() const { rational core_maxsat::get_upper() const {
return rational(m_upper); return rational(m_soft.size()-m_lower);
} }
rational core_maxsat::get_value() const { bool core_maxsat::get_assignment(unsigned idx) const {
return get_lower(); return m_answer[idx];
}
expr_ref_vector core_maxsat::get_assignment() const {
return m_answer;
} }
void core_maxsat::set_cancel(bool f) { void core_maxsat::set_cancel(bool f) {
@ -153,6 +149,14 @@ namespace opt {
} }
void core_maxsat::get_model(model_ref& mdl) { void core_maxsat::get_model(model_ref& mdl) {
mdl = m_model.get(); mdl = m_model.get();
if (!mdl) {
SASSERT(m_upper == 0);
lbool is_sat = s.check_sat(0, 0);
if (is_sat == l_true) {
s.get_model(m_model);
}
mdl = m_model;
}
} }

View file

@ -29,8 +29,9 @@ namespace opt {
ast_manager& m; ast_manager& m;
solver& s; solver& s;
expr_ref_vector m_soft; expr_ref_vector m_soft;
expr_ref_vector m_answer; svector<bool> m_answer;
unsigned m_upper; unsigned m_upper;
unsigned m_lower;
model_ref m_model; model_ref m_model;
public: public:
core_maxsat(ast_manager& m, solver& s, expr_ref_vector& soft_constraints); core_maxsat(ast_manager& m, solver& s, expr_ref_vector& soft_constraints);
@ -38,8 +39,7 @@ namespace opt {
virtual lbool operator()(); virtual lbool operator()();
virtual rational get_lower() const; virtual rational get_lower() const;
virtual rational get_upper() const; virtual rational get_upper() const;
virtual rational get_value() const; virtual bool get_assignment(unsigned idx) const;
virtual expr_ref_vector get_assignment() const;
virtual void set_cancel(bool f); virtual void set_cancel(bool f);
virtual void collect_statistics(statistics& st) const; virtual void collect_statistics(statistics& st) const;
virtual void get_model(model_ref& mdl); virtual void get_model(model_ref& mdl);

View file

@ -49,7 +49,7 @@ namespace opt {
expr_ref_vector m_soft; expr_ref_vector m_soft;
expr_ref_vector m_orig_soft; expr_ref_vector m_orig_soft;
expr_ref_vector m_aux; expr_ref_vector m_aux;
expr_ref_vector m_assignment; svector<bool> m_assignment;
unsigned m_upper; unsigned m_upper;
unsigned m_lower; unsigned m_lower;
model_ref m_model; model_ref m_model;
@ -63,12 +63,12 @@ namespace opt {
m_soft(soft), m_soft(soft),
m_orig_soft(soft), m_orig_soft(soft),
m_aux(m), m_aux(m),
m_assignment(m),
m_upper(0), m_upper(0),
m_lower(0), m_lower(0),
m_use_new_bv_solver(false) m_use_new_bv_solver(false)
{ {
m_upper = m_soft.size() + 1; m_upper = m_soft.size() + 1;
m_assignment.resize(m_soft.size(), false);
} }
solver& s() { return *m_s; } solver& s() { return *m_s; }
@ -286,44 +286,44 @@ namespace opt {
// TBD: bug when cancel flag is set, fu_malik returns is_sat == l_true instead of l_undef // TBD: bug when cancel flag is set, fu_malik returns is_sat == l_true instead of l_undef
lbool operator()() { lbool operator()() {
lbool is_sat = l_true;
if (m_soft.empty()) {
return is_sat;
}
set_solver(); set_solver();
lbool is_sat = s().check_sat(0,0); solver::scoped_push _sp(s());
if (!m_soft.empty() && is_sat == l_true) { expr_ref tmp(m);
solver::scoped_push _sp(s());
expr_ref tmp(m);
TRACE("opt",
tout << "soft constraints:\n";
for (unsigned i = 0; i < m_soft.size(); ++i) {
tout << mk_pp(m_soft[i].get(), m) << "\n";
});
for (unsigned i = 0; i < m_soft.size(); ++i) {
m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort()));
m_opt_solver.mc().insert(to_app(m_aux.back())->get_decl());
tmp = m.mk_or(m_soft[i].get(), m_aux[i].get());
s().assert_expr(tmp);
}
lbool is_sat = l_true; TRACE("opt",
do { tout << "soft constraints:\n";
is_sat = step(); for (unsigned i = 0; i < m_soft.size(); ++i) {
--m_upper; tout << mk_pp(m_soft[i].get(), m) << "\n";
} });
while (is_sat == l_false);
if (is_sat == l_true) { for (unsigned i = 0; i < m_soft.size(); ++i) {
// Get a list satisfying m_soft m_aux.push_back(m.mk_fresh_const("p", m.mk_bool_sort()));
s().get_model(m_model); m_opt_solver.mc().insert(to_app(m_aux.back())->get_decl());
m_lower = m_upper; tmp = m.mk_or(m_soft[i].get(), m_aux[i].get());
m_assignment.reset(); s().assert_expr(tmp);
for (unsigned i = 0; i < m_orig_soft.size(); ++i) { }
expr_ref val(m);
VERIFY(m_model->eval(m_orig_soft[i].get(), val)); do {
if (m.is_true(val)) { is_sat = step();
m_assignment.push_back(m_orig_soft[i].get()); --m_upper;
} }
} while (is_sat == l_false);
TRACE("opt", tout << "maxsat cost: " << m_upper << "\n";);
if (is_sat == l_true) {
// Get a list satisfying m_soft
s().get_model(m_model);
m_lower = m_upper;
m_assignment.reset();
for (unsigned i = 0; i < m_orig_soft.size(); ++i) {
expr_ref val(m);
VERIFY(m_model->eval(m_orig_soft[i].get(), val));
m_assignment.push_back(m.is_true(val));
} }
TRACE("opt", tout << "maxsat cost: " << m_upper << "\n";);
} }
// We are done and soft_constraints has // We are done and soft_constraints has
// been updated with the max-sat assignment. // been updated with the max-sat assignment.
@ -347,16 +347,13 @@ namespace opt {
return (*m_imp)(); return (*m_imp)();
} }
rational fu_malik::get_lower() const { rational fu_malik::get_lower() const {
return rational(m_imp->m_lower); return rational(m_imp->m_soft.size()-m_imp->m_upper);
} }
rational fu_malik::get_upper() const { rational fu_malik::get_upper() const {
return rational(m_imp->m_upper); return rational(m_imp->m_soft.size()-m_imp->m_lower);
} }
rational fu_malik::get_value() const { bool fu_malik::get_assignment(unsigned idx) const {
return rational(m_imp->m_assignment.size()); return m_imp->m_assignment[idx];
}
expr_ref_vector fu_malik::get_assignment() const {
return m_imp->m_assignment;
} }
void fu_malik::set_cancel(bool f) { void fu_malik::set_cancel(bool f) {
// no-op // no-op

View file

@ -38,8 +38,7 @@ namespace opt {
virtual lbool operator()(); virtual lbool operator()();
virtual rational get_lower() const; virtual rational get_lower() const;
virtual rational get_upper() const; virtual rational get_upper() const;
virtual rational get_value() const; virtual bool get_assignment(unsigned idx) const;
virtual expr_ref_vector get_assignment() const;
virtual void set_cancel(bool f); virtual void set_cancel(bool f);
virtual void collect_statistics(statistics& st) const; virtual void collect_statistics(statistics& st) const;
virtual void get_model(model_ref& m); virtual void get_model(model_ref& m);

View file

@ -28,14 +28,12 @@ namespace opt {
lbool maxsmt::operator()(opt_solver& s) { lbool maxsmt::operator()(opt_solver& s) {
lbool is_sat; lbool is_sat;
m_answer.reset();
m_msolver = 0; m_msolver = 0;
m_s = &s; m_s = &s;
if (m_soft_constraints.empty()) { if (m_soft_constraints.empty()) {
TRACE("opt", tout << "no constraints\n";); TRACE("opt", tout << "no constraints\n";);
m_msolver = 0; m_msolver = 0;
is_sat = s.check_sat(0, 0); is_sat = s.check_sat(0, 0);
m_answer.reset();
} }
else if (is_maxsat_problem(m_weights)) { else if (is_maxsat_problem(m_weights)) {
if (m_maxsat_engine == symbol("core_maxsat")) { if (m_maxsat_engine == symbol("core_maxsat")) {
@ -51,7 +49,6 @@ namespace opt {
if (m_msolver) { if (m_msolver) {
is_sat = (*m_msolver)(); is_sat = (*m_msolver)();
m_answer.append(m_msolver->get_assignment());
if (is_sat == l_true) { if (is_sat == l_true) {
m_msolver->get_model(m_model); m_msolver->get_model(m_model);
} }
@ -75,15 +72,13 @@ namespace opt {
return is_sat; return is_sat;
} }
expr_ref_vector maxsmt::get_assignment() const { bool maxsmt::get_assignment(unsigned idx) const {
return m_answer;
}
rational maxsmt::get_value() const {
if (m_msolver) { if (m_msolver) {
return m_msolver->get_value(); return m_msolver->get_assignment(idx);
}
else {
return true;
} }
return m_upper;
} }
rational maxsmt::get_lower() const { rational maxsmt::get_lower() const {
@ -114,14 +109,28 @@ namespace opt {
void maxsmt::commit_assignment() { void maxsmt::commit_assignment() {
SASSERT(m_s); SASSERT(m_s);
for (unsigned i = 0; i < m_answer.size(); ++i) { for (unsigned i = 0; i < m_soft_constraints.size(); ++i) {
m_s->assert_expr(m_answer[i].get()); expr_ref tmp(m);
tmp = m_soft_constraints[i].get();
if (get_assignment(i)) {
m_s->assert_expr(tmp);
}
else {
tmp = m.mk_not(tmp);
m_s->assert_expr(tmp);
}
} }
} }
void maxsmt::display_answer(std::ostream& out) const { void maxsmt::display_answer(std::ostream& out) const {
for (unsigned i = 0; i < m_answer.size(); ++i) { for (unsigned i = 0; i < m_soft_constraints.size(); ++i) {
out << mk_pp(m_answer[i], m) << "\n"; out << mk_pp(m_soft_constraints[i], m);
if (get_assignment(i)) {
out << " |-> true\n";
}
else {
out << " |-> false\n";
}
} }
} }

View file

@ -30,8 +30,7 @@ namespace opt {
virtual lbool operator()() = 0; virtual lbool operator()() = 0;
virtual rational get_lower() const = 0; virtual rational get_lower() const = 0;
virtual rational get_upper() const = 0; virtual rational get_upper() const = 0;
virtual rational get_value() const = 0; virtual bool get_assignment(unsigned index) const = 0;
virtual expr_ref_vector get_assignment() const = 0;
virtual void set_cancel(bool f) = 0; virtual void set_cancel(bool f) = 0;
virtual void collect_statistics(statistics& st) const = 0; virtual void collect_statistics(statistics& st) const = 0;
virtual void get_model(model_ref& mdl) = 0; virtual void get_model(model_ref& mdl) = 0;
@ -80,7 +79,7 @@ namespace opt {
rational get_upper() const; rational get_upper() const;
void update_lower(rational const& r); void update_lower(rational const& r);
void get_model(model_ref& mdl); void get_model(model_ref& mdl);
expr_ref_vector get_assignment() const; bool get_assignment(unsigned index) const;
void display_answer(std::ostream& out) const; void display_answer(std::ostream& out) const;
void collect_statistics(statistics& st) const; void collect_statistics(statistics& st) const;

View file

@ -54,6 +54,7 @@ namespace opt {
maxsmt* ms; maxsmt* ms;
if (!m_maxsmts.find(id, ms)) { if (!m_maxsmts.find(id, ms)) {
ms = alloc(maxsmt, m); ms = alloc(maxsmt, m);
ms->updt_params(m_params);
m_maxsmts.insert(id, ms); m_maxsmts.insert(id, ms);
m_objectives.push_back(objective(m, id)); m_objectives.push_back(objective(m, id));
m_indices.insert(id, m_objectives.size() - 1); m_indices.insert(id, m_objectives.size() - 1);
@ -352,6 +353,7 @@ namespace opt {
obj.m_weights.append(weights); obj.m_weights.append(weights);
SASSERT(!m_maxsmts.contains(id)); SASSERT(!m_maxsmts.contains(id));
maxsmt* ms = alloc(maxsmt, m); maxsmt* ms = alloc(maxsmt, m);
ms->updt_params(m_params);
m_maxsmts.insert(id, ms); m_maxsmts.insert(id, ms);
m_indices.insert(id, index); m_indices.insert(id, index);
} }
@ -730,9 +732,15 @@ namespace opt {
} }
break; break;
} }
case O_MAXSMT: case O_MAXSMT: {
maxsmt& ms = *m_maxsmts.find(obj.m_id);
for (unsigned i = 0; i < obj.m_terms.size(); ++i) {
VERIFY(m_model->eval(obj.m_terms[i], val));
SASSERT(ms.get_assignment(i) == (m.mk_true() == val));
}
break; break;
} }
}
} }
} }
} }

View file

@ -296,9 +296,6 @@ namespace opt {
return is_sat; return is_sat;
} }
inf_eps optsmt::get_value(unsigned i) const {
return get_lower(i);
}
inf_eps optsmt::get_lower(unsigned i) const { inf_eps optsmt::get_lower(unsigned i) const {
return m_is_max[i]?m_lower[i]:-m_lower[i]; return m_is_max[i]?m_lower[i]:-m_lower[i];
@ -325,7 +322,7 @@ namespace opt {
std::ostream& optsmt::display_objective(std::ostream& out, unsigned i) const { std::ostream& optsmt::display_objective(std::ostream& out, unsigned i) const {
bool is_max = m_is_max[i]; bool is_max = m_is_max[i];
inf_eps val = get_value(i); inf_eps val = get_lower(i);
expr_ref obj(m_objs[i], m); expr_ref obj(m_objs[i], m);
if (!is_max) { if (!is_max) {
arith_util a(m); arith_util a(m);
@ -344,7 +341,7 @@ namespace opt {
<< ":" << get_upper(i) << "]" << std::endl; << ":" << get_upper(i) << "]" << std::endl;
} }
else { else {
display_objective(out, i) << " |-> " << get_value(i) << std::endl; display_objective(out, i) << " |-> " << get_lower(i) << std::endl;
} }
} }
} }

View file

@ -58,7 +58,6 @@ namespace opt {
unsigned get_num_objectives() const { return m_objs.size(); } unsigned get_num_objectives() const { return m_objs.size(); }
void commit_assignment(unsigned index); void commit_assignment(unsigned index);
inf_eps get_value(unsigned index) const;
inf_eps get_lower(unsigned index) const; inf_eps get_lower(unsigned index) const;
inf_eps get_upper(unsigned index) const; inf_eps get_upper(unsigned index) const;
void get_model(model_ref& mdl); void get_model(model_ref& mdl);

View file

@ -46,15 +46,16 @@ namespace smt {
/** /**
\brief return the complement of variables that are currently assigned. \brief return the complement of variables that are currently assigned.
*/ */
void get_assignment(expr_ref_vector& result) { void get_assignment(svector<bool>& result) {
result.reset(); result.reset();
std::sort(m_cost_save.begin(), m_cost_save.end()); std::sort(m_cost_save.begin(), m_cost_save.end());
for (unsigned i = 0, j = 0; i < m_vars.size(); ++i) { for (unsigned i = 0, j = 0; i < m_vars.size(); ++i) {
if (j < m_cost_save.size() && m_cost_save[j] == i) { if (j < m_cost_save.size() && m_cost_save[j] == i) {
result.push_back(false);
++j; ++j;
} }
else { else {
result.push_back(m_fmls[i].get()); result.push_back(true);
} }
} }
} }
@ -282,15 +283,17 @@ namespace opt {
ast_manager& m; ast_manager& m;
opt_solver& s; opt_solver& s;
expr_ref_vector m_soft; expr_ref_vector m_soft;
expr_ref_vector m_assignment; svector<bool> m_assignment;
vector<rational> m_weights; vector<rational> m_weights;
rational m_upper; rational m_upper;
rational m_lower; rational m_lower;
model_ref m_model; model_ref m_model;
imp(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector<rational> const& weights): imp(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector<rational> const& weights):
m(m), s(s), m_soft(soft_constraints), m_assignment(m), m_weights(weights) m(m), s(s), m_soft(soft_constraints), m_weights(weights)
{} {
m_assignment.resize(m_soft.size(), false);
}
~imp() {} ~imp() {}
smt::theory_weighted_maxsat* get_theory() const { smt::theory_weighted_maxsat* get_theory() const {
@ -333,9 +336,9 @@ namespace opt {
wth.assert_weighted(m_soft[i].get(), m_weights[i]); wth.assert_weighted(m_soft[i].get(), m_weights[i]);
} }
result = s.check_sat_core(0,0); result = s.check_sat_core(0,0);
SASSERT(result != l_true);
wth.get_assignment(m_assignment); wth.get_assignment(m_assignment);
if (!m_assignment.empty() && result == l_false) { if (result == l_false) {
result = l_true; result = l_true;
} }
} }
@ -382,11 +385,8 @@ namespace opt {
rational wmaxsmt::get_upper() const { rational wmaxsmt::get_upper() const {
return m_imp->get_upper(); return m_imp->get_upper();
} }
rational wmaxsmt::get_value() const { bool wmaxsmt::get_assignment(unsigned idx) const {
return m_imp->get_upper(); return m_imp->m_assignment[idx];
}
expr_ref_vector wmaxsmt::get_assignment() const {
return m_imp->m_assignment;
} }
void wmaxsmt::set_cancel(bool f) { void wmaxsmt::set_cancel(bool f) {
// no-op // no-op

View file

@ -36,8 +36,7 @@ namespace opt {
virtual lbool operator()(); virtual lbool operator()();
virtual rational get_lower() const; virtual rational get_lower() const;
virtual rational get_upper() const; virtual rational get_upper() const;
virtual rational get_value() const; virtual bool get_assignment(unsigned idx) const;
virtual expr_ref_vector get_assignment() const;
virtual void set_cancel(bool f); virtual void set_cancel(bool f);
virtual void collect_statistics(statistics& st) const; virtual void collect_statistics(statistics& st) const;
virtual void get_model(model_ref& mdl); virtual void get_model(model_ref& mdl);