mirror of
https://github.com/Z3Prover/z3
synced 2025-06-01 11:51:20 +00:00
fixing lex optimization
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
df5c2adc4e
commit
8c85ee6b7c
13 changed files with 219 additions and 125 deletions
|
@ -314,7 +314,7 @@ public:
|
||||||
break;
|
break;
|
||||||
case l_undef:
|
case l_undef:
|
||||||
ctx.regular_stream() << "unknown\n";
|
ctx.regular_stream() << "unknown\n";
|
||||||
opt.display_range_assignment(ctx.regular_stream());
|
opt.display_assignment(ctx.regular_stream());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (p.get_bool("print_statistics", false)) {
|
if (p.get_bool("print_statistics", false)) {
|
||||||
|
|
|
@ -28,6 +28,7 @@ Notes:
|
||||||
#include "lia2card_tactic.h"
|
#include "lia2card_tactic.h"
|
||||||
#include "elim01_tactic.h"
|
#include "elim01_tactic.h"
|
||||||
#include "tactical.h"
|
#include "tactical.h"
|
||||||
|
#include "model_smt2_pp.h"
|
||||||
|
|
||||||
namespace opt {
|
namespace opt {
|
||||||
|
|
||||||
|
@ -85,12 +86,13 @@ namespace opt {
|
||||||
return is_sat;
|
return is_sat;
|
||||||
}
|
}
|
||||||
s.get_model(m_model);
|
s.get_model(m_model);
|
||||||
|
m_optsmt.setup(s);
|
||||||
update_lower();
|
update_lower();
|
||||||
switch (m_objectives.size()) {
|
switch (m_objectives.size()) {
|
||||||
case 0:
|
case 0:
|
||||||
return is_sat;
|
return is_sat;
|
||||||
case 1:
|
case 1:
|
||||||
return execute(m_objectives[0], false);
|
return execute(m_objectives[0], true);
|
||||||
default: {
|
default: {
|
||||||
opt_params optp(m_params);
|
opt_params optp(m_params);
|
||||||
symbol pri = optp.priority();
|
symbol pri = optp.priority();
|
||||||
|
@ -111,19 +113,17 @@ namespace opt {
|
||||||
mdl = m_model;
|
mdl = m_model;
|
||||||
if (m_model_converter) {
|
if (m_model_converter) {
|
||||||
(*m_model_converter)(mdl, 0);
|
(*m_model_converter)(mdl, 0);
|
||||||
|
get_solver().mc()(mdl, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lbool context::execute_min_max(unsigned index, bool committed, bool is_max) {
|
lbool context::execute_min_max(unsigned index, bool committed) {
|
||||||
// HACK: reuse m_optsmt without regard for box reuse and not considering
|
lbool result = m_optsmt.lex(index);
|
||||||
// use-case of lex.
|
|
||||||
lbool result = m_optsmt(get_solver());
|
|
||||||
if (result == l_true) m_optsmt.get_model(m_model);
|
if (result == l_true) m_optsmt.get_model(m_model);
|
||||||
if (committed) m_optsmt.commit_assignment(index);
|
if (committed) m_optsmt.commit_assignment(index);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
lbool context::execute_maxsat(symbol const& id, bool committed) {
|
lbool context::execute_maxsat(symbol const& id, bool committed) {
|
||||||
maxsmt& ms = *m_maxsmts.find(id);
|
maxsmt& ms = *m_maxsmts.find(id);
|
||||||
lbool result = ms(get_solver());
|
lbool result = ms(get_solver());
|
||||||
|
@ -134,8 +134,8 @@ namespace opt {
|
||||||
|
|
||||||
lbool context::execute(objective const& obj, bool committed) {
|
lbool context::execute(objective const& obj, bool committed) {
|
||||||
switch(obj.m_type) {
|
switch(obj.m_type) {
|
||||||
case O_MAXIMIZE: return execute_min_max(obj.m_index, committed, true);
|
case O_MAXIMIZE: return execute_min_max(obj.m_index, committed);
|
||||||
case O_MINIMIZE: return execute_min_max(obj.m_index, committed, false);
|
case O_MINIMIZE: return execute_min_max(obj.m_index, committed);
|
||||||
case O_MAXSMT: return execute_maxsat(obj.m_id, committed);
|
case O_MAXSMT: return execute_maxsat(obj.m_id, committed);
|
||||||
default: UNREACHABLE(); return l_undef;
|
default: UNREACHABLE(); return l_undef;
|
||||||
}
|
}
|
||||||
|
@ -145,16 +145,23 @@ namespace opt {
|
||||||
lbool r = l_true;
|
lbool r = l_true;
|
||||||
for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) {
|
for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) {
|
||||||
r = execute(m_objectives[i], i + 1 < m_objectives.size());
|
r = execute(m_objectives[i], i + 1 < m_objectives.size());
|
||||||
|
if (r == l_true && !get_lower_as_num(i).is_finite()) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
DEBUG_CODE(if (r == l_true) validate_lex(););
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
lbool context::execute_box() {
|
lbool context::execute_box() {
|
||||||
lbool r = l_true;
|
lbool r = m_optsmt.box();
|
||||||
for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) {
|
for (unsigned i = 0; r == l_true && i < m_objectives.size(); ++i) {
|
||||||
get_solver().push();
|
objective const& obj = m_objectives[i];
|
||||||
r = execute(m_objectives[i], false);
|
if (obj.m_type == O_MAXSMT) {
|
||||||
get_solver().pop(1);
|
get_solver().push();
|
||||||
|
r = execute(obj, false);
|
||||||
|
get_solver().pop(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -244,7 +251,9 @@ namespace opt {
|
||||||
terms[i] = m.mk_not(terms[i].get());
|
terms[i] = m.mk_not(terms[i].get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
id = symbol(index);
|
std::ostringstream out;
|
||||||
|
out << term;
|
||||||
|
id = symbol(out.str().c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (is_maximize(fml, term, index) &&
|
if (is_maximize(fml, term, index) &&
|
||||||
|
@ -266,7 +275,9 @@ namespace opt {
|
||||||
offset += weights[i];
|
offset += weights[i];
|
||||||
}
|
}
|
||||||
neg = true;
|
neg = true;
|
||||||
id = symbol(index);
|
std::ostringstream out;
|
||||||
|
out << term;
|
||||||
|
id = symbol(out.str().c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -426,17 +437,15 @@ namespace opt {
|
||||||
for (unsigned i = 0; i < m_objectives.size(); ++i) {
|
for (unsigned i = 0; i < m_objectives.size(); ++i) {
|
||||||
objective const& obj = m_objectives[i];
|
objective const& obj = m_objectives[i];
|
||||||
display_objective(out, obj);
|
display_objective(out, obj);
|
||||||
out << "|-> " << get_upper(i) << "\n";
|
if (get_lower_as_num(i) != get_upper_as_num(i)) {
|
||||||
|
out << " |-> [" << get_lower(i) << ":" << get_upper(i) << "]\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out << "|-> " << get_lower(i) << "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void context::display_range_assignment(std::ostream& out) {
|
|
||||||
for (unsigned i = 0; i < m_objectives.size(); ++i) {
|
|
||||||
objective const& obj = m_objectives[i];
|
|
||||||
display_objective(out, obj);
|
|
||||||
out << " |-> [" << get_lower(i) << ":" << get_upper(i) << "]\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void context::display_objective(std::ostream& out, objective const& obj) const {
|
void context::display_objective(std::ostream& out, objective const& obj) const {
|
||||||
switch(obj.m_type) {
|
switch(obj.m_type) {
|
||||||
|
@ -453,8 +462,7 @@ namespace opt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inf_eps context::get_lower_as_num(unsigned idx) {
|
||||||
expr_ref context::get_lower(unsigned idx) {
|
|
||||||
if (idx > m_objectives.size()) {
|
if (idx > m_objectives.size()) {
|
||||||
throw default_exception("index out of bounds");
|
throw default_exception("index out of bounds");
|
||||||
}
|
}
|
||||||
|
@ -464,18 +472,19 @@ namespace opt {
|
||||||
rational r = m_maxsmts.find(obj.m_id)->get_lower();
|
rational r = m_maxsmts.find(obj.m_id)->get_lower();
|
||||||
if (obj.m_neg) r.neg();
|
if (obj.m_neg) r.neg();
|
||||||
r += obj.m_offset;
|
r += obj.m_offset;
|
||||||
return to_expr(inf_eps(r));
|
return inf_eps(r);
|
||||||
}
|
}
|
||||||
case O_MINIMIZE:
|
case O_MINIMIZE:
|
||||||
case O_MAXIMIZE:
|
case O_MAXIMIZE:
|
||||||
return to_expr(m_optsmt.get_lower(obj.m_index));
|
return m_optsmt.get_lower(obj.m_index);
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return expr_ref(m);
|
return inf_eps();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_ref context::get_upper(unsigned idx) {
|
|
||||||
|
inf_eps context::get_upper_as_num(unsigned idx) {
|
||||||
if (idx > m_objectives.size()) {
|
if (idx > m_objectives.size()) {
|
||||||
throw default_exception("index out of bounds");
|
throw default_exception("index out of bounds");
|
||||||
}
|
}
|
||||||
|
@ -485,17 +494,25 @@ namespace opt {
|
||||||
rational r = m_maxsmts.find(obj.m_id)->get_upper();
|
rational r = m_maxsmts.find(obj.m_id)->get_upper();
|
||||||
if (obj.m_neg) r.neg();
|
if (obj.m_neg) r.neg();
|
||||||
r += obj.m_offset;
|
r += obj.m_offset;
|
||||||
return to_expr(inf_eps(r));
|
return inf_eps(r);
|
||||||
}
|
}
|
||||||
case O_MINIMIZE:
|
case O_MINIMIZE:
|
||||||
case O_MAXIMIZE:
|
case O_MAXIMIZE:
|
||||||
return to_expr(m_optsmt.get_upper(obj.m_index));
|
return m_optsmt.get_upper(obj.m_index);
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return expr_ref(m);
|
return inf_eps();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expr_ref context::get_lower(unsigned idx) {
|
||||||
|
return to_expr(get_lower_as_num(idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
expr_ref context::get_upper(unsigned idx) {
|
||||||
|
return to_expr(get_upper_as_num(idx));
|
||||||
|
}
|
||||||
|
|
||||||
expr_ref context::to_expr(inf_eps const& n) {
|
expr_ref context::to_expr(inf_eps const& n) {
|
||||||
rational inf = n.get_infinity();
|
rational inf = n.get_infinity();
|
||||||
rational r = n.get_rational();
|
rational r = n.get_rational();
|
||||||
|
@ -676,4 +693,30 @@ namespace opt {
|
||||||
return out.str();
|
return out.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void context::validate_lex() {
|
||||||
|
arith_util a(m);
|
||||||
|
rational r1;
|
||||||
|
expr_ref val(m);
|
||||||
|
for (unsigned i = 0; i < m_objectives.size(); ++i) {
|
||||||
|
objective const& obj = m_objectives[i];
|
||||||
|
switch(obj.m_type) {
|
||||||
|
case O_MINIMIZE:
|
||||||
|
case O_MAXIMIZE: {
|
||||||
|
inf_eps n = m_optsmt.get_lower(obj.m_index);
|
||||||
|
if (n.get_infinity().is_zero() &&
|
||||||
|
n.get_infinitesimal().is_zero() &&
|
||||||
|
m_model->eval(obj.m_term, val) &&
|
||||||
|
a.is_numeral(val, r1)) {
|
||||||
|
rational r2 = n.get_rational();
|
||||||
|
CTRACE("opt", r1 != r2, tout << obj.m_term << " evaluates to " << r1 << " but has objective " << r2 << "\n";);
|
||||||
|
CTRACE("opt", r1 != r2, model_smt2_pp(tout, m, *m_model, 0););
|
||||||
|
SASSERT(r1 == r2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case O_MAXSMT:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,7 @@ namespace opt {
|
||||||
void validate_feasibility(maxsmt& ms);
|
void validate_feasibility(maxsmt& ms);
|
||||||
|
|
||||||
lbool execute(objective const& obj, bool committed);
|
lbool execute(objective const& obj, bool committed);
|
||||||
lbool execute_min_max(unsigned index, bool committed, bool is_max);
|
lbool execute_min_max(unsigned index, bool committed);
|
||||||
lbool execute_maxsat(symbol const& s, bool committed);
|
lbool execute_maxsat(symbol const& s, bool committed);
|
||||||
lbool execute_lex();
|
lbool execute_lex();
|
||||||
lbool execute_box();
|
lbool execute_box();
|
||||||
|
@ -139,10 +139,16 @@ namespace opt {
|
||||||
|
|
||||||
void update_lower();
|
void update_lower();
|
||||||
|
|
||||||
|
inf_eps get_lower_as_num(unsigned idx);
|
||||||
|
inf_eps get_upper_as_num(unsigned idx);
|
||||||
|
|
||||||
|
|
||||||
opt_solver& get_solver();
|
opt_solver& get_solver();
|
||||||
|
|
||||||
void display_objective(std::ostream& out, objective const& obj) const;
|
void display_objective(std::ostream& out, objective const& obj) const;
|
||||||
|
|
||||||
|
void validate_lex();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,9 @@ namespace opt {
|
||||||
m_params(p),
|
m_params(p),
|
||||||
m_context(mgr, m_params),
|
m_context(mgr, m_params),
|
||||||
m(mgr),
|
m(mgr),
|
||||||
m_objective_enabled(false),
|
|
||||||
m_dump_benchmarks(false),
|
m_dump_benchmarks(false),
|
||||||
m_dump_count(0) {
|
m_dump_count(0),
|
||||||
|
m_fm(m) {
|
||||||
m_logic = l;
|
m_logic = l;
|
||||||
if (m_logic != symbol::null)
|
if (m_logic != symbol::null)
|
||||||
m_context.set_logic(m_logic);
|
m_context.set_logic(m_logic);
|
||||||
|
@ -71,7 +71,6 @@ namespace opt {
|
||||||
m_context.pop(n);
|
m_context.pop(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
smt::theory_opt& opt_solver::get_optimizer() {
|
smt::theory_opt& opt_solver::get_optimizer() {
|
||||||
smt::context& ctx = m_context.get_context();
|
smt::context& ctx = m_context.get_context();
|
||||||
smt::theory_id arith_id = m_context.m().get_family_id("arith");
|
smt::theory_id arith_id = m_context.m().get_family_id("arith");
|
||||||
|
@ -118,21 +117,26 @@ namespace opt {
|
||||||
to_smt2_benchmark(buffer, "opt_solver", "QF_BV");
|
to_smt2_benchmark(buffer, "opt_solver", "QF_BV");
|
||||||
buffer.close();
|
buffer.close();
|
||||||
}
|
}
|
||||||
if (r == l_true && m_objective_enabled) {
|
|
||||||
m_objective_values.reset();
|
|
||||||
smt::theory_opt& opt = get_optimizer();
|
|
||||||
for (unsigned i = 0; i < m_objective_vars.size(); ++i) {
|
|
||||||
smt::theory_var v = m_objective_vars[i];
|
|
||||||
m_objective_values.push_back(opt.maximize(v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void opt_solver::maximize_objectives() {
|
||||||
|
for (unsigned i = 0; i < m_objective_vars.size(); ++i) {
|
||||||
|
maximize_objective(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void opt_solver::maximize_objective(unsigned i) {
|
||||||
|
smt::theory_var v = m_objective_vars[i];
|
||||||
|
m_objective_values[i] = get_optimizer().maximize(v);
|
||||||
|
m_context.get_context().update_model();
|
||||||
|
}
|
||||||
|
|
||||||
void opt_solver::get_unsat_core(ptr_vector<expr> & r) {
|
void opt_solver::get_unsat_core(ptr_vector<expr> & r) {
|
||||||
unsigned sz = m_context.get_unsat_core_size();
|
unsigned sz = m_context.get_unsat_core_size();
|
||||||
for (unsigned i = 0; i < sz; i++)
|
for (unsigned i = 0; i < sz; i++) {
|
||||||
r.push_back(m_context.get_unsat_core_expr(i));
|
r.push_back(m_context.get_unsat_core_expr(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void opt_solver::get_model(model_ref & m) {
|
void opt_solver::get_model(model_ref & m) {
|
||||||
|
@ -177,6 +181,7 @@ namespace opt {
|
||||||
|
|
||||||
smt::theory_var opt_solver::add_objective(app* term) {
|
smt::theory_var opt_solver::add_objective(app* term) {
|
||||||
m_objective_vars.push_back(get_optimizer().add_objective(term));
|
m_objective_vars.push_back(get_optimizer().add_objective(term));
|
||||||
|
m_objective_values.push_back(inf_eps(rational(-1), inf_rational()));
|
||||||
return m_objective_vars.back();
|
return m_objective_vars.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,26 +189,30 @@ namespace opt {
|
||||||
return m_objective_values;
|
return m_objective_values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inf_eps const& opt_solver::get_objective_value(unsigned i) {
|
||||||
|
return m_objective_values[i];
|
||||||
|
}
|
||||||
|
|
||||||
expr_ref opt_solver::mk_ge(unsigned var, inf_eps const& val) {
|
expr_ref opt_solver::mk_ge(unsigned var, inf_eps const& val) {
|
||||||
smt::theory_opt& opt = get_optimizer();
|
smt::theory_opt& opt = get_optimizer();
|
||||||
smt::theory_var v = m_objective_vars[var];
|
smt::theory_var v = m_objective_vars[var];
|
||||||
|
|
||||||
if (typeid(smt::theory_inf_arith) == typeid(opt)) {
|
if (typeid(smt::theory_inf_arith) == typeid(opt)) {
|
||||||
smt::theory_inf_arith& th = dynamic_cast<smt::theory_inf_arith&>(opt);
|
smt::theory_inf_arith& th = dynamic_cast<smt::theory_inf_arith&>(opt);
|
||||||
return expr_ref(th.mk_ge(v, val), m);
|
return expr_ref(th.mk_ge(m_fm, v, val), m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeid(smt::theory_mi_arith) == typeid(opt)) {
|
if (typeid(smt::theory_mi_arith) == typeid(opt)) {
|
||||||
smt::theory_mi_arith& th = dynamic_cast<smt::theory_mi_arith&>(opt);
|
smt::theory_mi_arith& th = dynamic_cast<smt::theory_mi_arith&>(opt);
|
||||||
SASSERT(val.get_infinity().is_zero());
|
SASSERT(val.is_finite());
|
||||||
return expr_ref(th.mk_ge(v, val.get_numeral()), m);
|
return expr_ref(th.mk_ge(m_fm, v, val.get_numeral()), m);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeid(smt::theory_i_arith) == typeid(opt)) {
|
if (typeid(smt::theory_i_arith) == typeid(opt)) {
|
||||||
SASSERT(val.get_infinity().is_zero());
|
SASSERT(val.is_finite());
|
||||||
SASSERT(val.get_infinitesimal().is_zero());
|
SASSERT(val.get_infinitesimal().is_zero());
|
||||||
smt::theory_i_arith& th = dynamic_cast<smt::theory_i_arith&>(opt);
|
smt::theory_i_arith& th = dynamic_cast<smt::theory_i_arith&>(opt);
|
||||||
return expr_ref(th.mk_ge(v, val.get_rational()), m);
|
return expr_ref(th.mk_ge(m_fm, v, val.get_rational()), m);
|
||||||
}
|
}
|
||||||
|
|
||||||
// difference logic?
|
// difference logic?
|
||||||
|
@ -251,12 +260,5 @@ namespace opt {
|
||||||
pp.display_smt2(buffer, to_expr(m.mk_true()));
|
pp.display_smt2(buffer, to_expr(m.mk_true()));
|
||||||
}
|
}
|
||||||
|
|
||||||
opt_solver::toggle_objective::toggle_objective(opt_solver& s, bool new_value): s(s), m_old_value(s.m_objective_enabled) {
|
|
||||||
s.m_objective_enabled = new_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
opt_solver::toggle_objective::~toggle_objective() {
|
|
||||||
s.m_objective_enabled = m_old_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ Notes:
|
||||||
#include"smt_params.h"
|
#include"smt_params.h"
|
||||||
#include"smt_types.h"
|
#include"smt_types.h"
|
||||||
#include"theory_opt.h"
|
#include"theory_opt.h"
|
||||||
|
#include"filter_model_converter.h"
|
||||||
|
|
||||||
namespace opt {
|
namespace opt {
|
||||||
|
|
||||||
|
@ -49,6 +50,7 @@ namespace opt {
|
||||||
bool m_dump_benchmarks;
|
bool m_dump_benchmarks;
|
||||||
unsigned m_dump_count;
|
unsigned m_dump_count;
|
||||||
statistics m_stats;
|
statistics m_stats;
|
||||||
|
filter_model_converter m_fm;
|
||||||
public:
|
public:
|
||||||
opt_solver(ast_manager & m, params_ref const & p, symbol const & l);
|
opt_solver(ast_manager & m, params_ref const & p, symbol const & l);
|
||||||
virtual ~opt_solver();
|
virtual ~opt_solver();
|
||||||
|
@ -73,22 +75,19 @@ namespace opt {
|
||||||
|
|
||||||
smt::theory_var add_objective(app* term);
|
smt::theory_var add_objective(app* term);
|
||||||
void reset_objectives();
|
void reset_objectives();
|
||||||
|
void maximize_objective(unsigned i);
|
||||||
|
void maximize_objectives();
|
||||||
|
|
||||||
vector<inf_eps> const& get_objective_values();
|
vector<inf_eps> const& get_objective_values();
|
||||||
|
inf_eps const & get_objective_value(unsigned obj_index);
|
||||||
expr_ref mk_gt(unsigned obj_index, inf_eps const& val);
|
expr_ref mk_gt(unsigned obj_index, inf_eps const& val);
|
||||||
expr_ref mk_ge(unsigned obj_index, inf_eps const& val);
|
expr_ref mk_ge(unsigned obj_index, inf_eps const& val);
|
||||||
|
|
||||||
|
model_converter& mc() { return m_fm; }
|
||||||
|
|
||||||
static opt_solver& to_opt(solver& s);
|
static opt_solver& to_opt(solver& s);
|
||||||
bool dump_benchmarks();
|
bool dump_benchmarks();
|
||||||
|
|
||||||
class toggle_objective {
|
|
||||||
opt_solver& s;
|
|
||||||
bool m_old_value;
|
|
||||||
public:
|
|
||||||
toggle_objective(opt_solver& s, bool new_value);
|
|
||||||
~toggle_objective();
|
|
||||||
};
|
|
||||||
|
|
||||||
smt::context& get_context() { return m_context.get_context(); } // used by weighted maxsat.
|
smt::context& get_context() { return m_context.get_context(); } // used by weighted maxsat.
|
||||||
|
|
||||||
smt::theory_opt& get_optimizer();
|
smt::theory_opt& get_optimizer();
|
||||||
|
|
|
@ -66,7 +66,6 @@ namespace opt {
|
||||||
Enumerate locally optimal assignments until fixedpoint.
|
Enumerate locally optimal assignments until fixedpoint.
|
||||||
*/
|
*/
|
||||||
lbool optsmt::basic_opt() {
|
lbool optsmt::basic_opt() {
|
||||||
opt_solver::toggle_objective _t(*m_s, true);
|
|
||||||
lbool is_sat = l_true;
|
lbool is_sat = l_true;
|
||||||
|
|
||||||
while (is_sat == l_true && !m_cancel) {
|
while (is_sat == l_true && !m_cancel) {
|
||||||
|
@ -98,8 +97,7 @@ namespace opt {
|
||||||
return l_undef;
|
return l_undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
opt_solver::toggle_objective _t(*m_s, true);
|
lbool is_sat = l_true;
|
||||||
lbool is_sat= l_true;
|
|
||||||
|
|
||||||
while (is_sat == l_true && !m_cancel) {
|
while (is_sat == l_true && !m_cancel) {
|
||||||
is_sat = update_upper();
|
is_sat = update_upper();
|
||||||
|
@ -126,6 +124,7 @@ namespace opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
void optsmt::update_lower() {
|
void optsmt::update_lower() {
|
||||||
|
m_s->maximize_objectives();
|
||||||
m_s->get_model(m_model);
|
m_s->get_model(m_model);
|
||||||
set_max(m_lower, m_s->get_objective_values());
|
set_max(m_lower, m_s->get_objective_values());
|
||||||
IF_VERBOSE(1,
|
IF_VERBOSE(1,
|
||||||
|
@ -150,7 +149,6 @@ namespace opt {
|
||||||
smt::theory_opt& opt = m_s->get_optimizer();
|
smt::theory_opt& opt = m_s->get_optimizer();
|
||||||
SASSERT(typeid(smt::theory_inf_arith) == typeid(opt));
|
SASSERT(typeid(smt::theory_inf_arith) == typeid(opt));
|
||||||
smt::theory_inf_arith& th = dynamic_cast<smt::theory_inf_arith&>(opt);
|
smt::theory_inf_arith& th = dynamic_cast<smt::theory_inf_arith&>(opt);
|
||||||
|
|
||||||
expr_ref bound(m);
|
expr_ref bound(m);
|
||||||
expr_ref_vector bounds(m);
|
expr_ref_vector bounds(m);
|
||||||
|
|
||||||
|
@ -165,10 +163,9 @@ namespace opt {
|
||||||
|
|
||||||
for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) {
|
for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) {
|
||||||
if (m_lower[i] < m_upper[i]) {
|
if (m_lower[i] < m_upper[i]) {
|
||||||
smt::theory_var v = m_vars[i];
|
|
||||||
mid.push_back((m_upper[i]+m_lower[i])/rational(2));
|
mid.push_back((m_upper[i]+m_lower[i])/rational(2));
|
||||||
//mid.push_back(m_upper[i]);
|
//mid.push_back(m_upper[i]);
|
||||||
bound = th.mk_ge(v, mid[i]);
|
bound = m_s->mk_ge(i, mid[i]);
|
||||||
bounds.push_back(bound);
|
bounds.push_back(bound);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -190,7 +187,7 @@ namespace opt {
|
||||||
break;
|
break;
|
||||||
case l_false:
|
case l_false:
|
||||||
IF_VERBOSE(2, verbose_stream() << "conflict: " << th.conflict_minimize() << "\n";);
|
IF_VERBOSE(2, verbose_stream() << "conflict: " << th.conflict_minimize() << "\n";);
|
||||||
if (!th.conflict_minimize().get_infinity().is_zero()) {
|
if (!th.conflict_minimize().is_finite()) {
|
||||||
// bounds is not in the core. The context is unsat.
|
// bounds is not in the core. The context is unsat.
|
||||||
m_upper[i] = m_lower[i];
|
m_upper[i] = m_lower[i];
|
||||||
return l_false;
|
return l_false;
|
||||||
|
@ -216,28 +213,76 @@ namespace opt {
|
||||||
return l_true;
|
return l_true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void optsmt::setup(opt_solver& solver) {
|
||||||
Takes solver with hard constraints added.
|
|
||||||
Returns an optimal assignment to objective functions.
|
|
||||||
*/
|
|
||||||
lbool optsmt::operator()(opt_solver& solver) {
|
|
||||||
if (m_objs.empty()) {
|
|
||||||
return l_true;
|
|
||||||
}
|
|
||||||
lbool is_sat = l_true;
|
|
||||||
m_s = &solver;
|
m_s = &solver;
|
||||||
solver.reset_objectives();
|
solver.reset_objectives();
|
||||||
m_vars.reset();
|
m_vars.reset();
|
||||||
|
|
||||||
|
// force base level
|
||||||
{
|
{
|
||||||
// force base level
|
|
||||||
solver::scoped_push _push(solver);
|
solver::scoped_push _push(solver);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < m_objs.size(); ++i) {
|
for (unsigned i = 0; i < m_objs.size(); ++i) {
|
||||||
m_vars.push_back(solver.add_objective(m_objs[i].get()));
|
m_vars.push_back(solver.add_objective(m_objs[i].get()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lbool optsmt::lex(unsigned obj_index) {
|
||||||
|
solver::scoped_push _push(*m_s);
|
||||||
|
SASSERT(obj_index < m_vars.size());
|
||||||
|
return basic_lex(obj_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
lbool optsmt::basic_lex(unsigned obj_index) {
|
||||||
|
lbool is_sat = l_true;
|
||||||
|
expr_ref block(m);
|
||||||
|
|
||||||
|
while (is_sat == l_true && !m_cancel) {
|
||||||
|
is_sat = m_s->check_sat(0, 0);
|
||||||
|
if (is_sat != l_true) break;
|
||||||
|
|
||||||
|
m_s->maximize_objective(obj_index);
|
||||||
|
m_s->get_model(m_model);
|
||||||
|
inf_eps obj = m_s->get_objective_value(obj_index);
|
||||||
|
if (obj > m_lower[obj_index]) {
|
||||||
|
m_lower[obj_index] = obj;
|
||||||
|
for (unsigned i = obj_index+1; i < m_vars.size(); ++i) {
|
||||||
|
m_s->maximize_objective(i);
|
||||||
|
m_lower[i] = m_s->get_objective_value(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
block = m_s->mk_gt(obj_index, obj);
|
||||||
|
m_s->assert_expr(block);
|
||||||
|
|
||||||
|
// TBD: only works for simplex
|
||||||
|
// blocking formula should be extracted based
|
||||||
|
// on current state.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_cancel || is_sat == l_undef) {
|
||||||
|
return l_undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the solution tight.
|
||||||
|
m_upper[obj_index] = m_lower[obj_index];
|
||||||
|
for (unsigned i = obj_index+1; i < m_lower.size(); ++i) {
|
||||||
|
m_lower[i] = inf_eps(rational(-1), inf_rational(0));
|
||||||
|
}
|
||||||
|
return l_true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Takes solver with hard constraints added.
|
||||||
|
Returns an optimal assignment to objective functions.
|
||||||
|
*/
|
||||||
|
lbool optsmt::box() {
|
||||||
|
lbool is_sat = l_true;
|
||||||
|
if (m_vars.empty()) {
|
||||||
|
return is_sat;
|
||||||
|
}
|
||||||
|
// assertions added during search are temporary.
|
||||||
|
solver::scoped_push _push(*m_s);
|
||||||
if (m_engine == symbol("farkas")) {
|
if (m_engine == symbol("farkas")) {
|
||||||
is_sat = farkas_opt();
|
is_sat = farkas_opt();
|
||||||
}
|
}
|
||||||
|
@ -252,15 +297,15 @@ namespace opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
inf_eps optsmt::get_value(unsigned i) const {
|
inf_eps optsmt::get_value(unsigned i) const {
|
||||||
return m_is_max[i]?m_lower[i]:-m_lower[i];
|
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_upper[i];
|
return m_is_max[i]?m_lower[i]:-m_lower[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
inf_eps optsmt::get_upper(unsigned i) const {
|
inf_eps optsmt::get_upper(unsigned i) const {
|
||||||
return m_is_max[i]?m_upper[i]:-m_lower[i];
|
return m_is_max[i]?m_upper[i]:-m_upper[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void optsmt::get_model(model_ref& mdl) {
|
void optsmt::get_model(model_ref& mdl) {
|
||||||
|
@ -269,33 +314,13 @@ namespace opt {
|
||||||
|
|
||||||
// force lower_bound(i) <= objective_value(i)
|
// force lower_bound(i) <= objective_value(i)
|
||||||
void optsmt::commit_assignment(unsigned i) {
|
void optsmt::commit_assignment(unsigned i) {
|
||||||
inf_eps mid(0);
|
inf_eps lo = m_lower[i];
|
||||||
|
TRACE("opt", tout << "set lower bound of "; display_objective(tout, i) << " to: " << lo << "\n";
|
||||||
// TBD: case analysis should be revisited
|
|
||||||
rational hi = get_upper(i).get_infinity();
|
|
||||||
rational lo = get_lower(i).get_infinity();
|
|
||||||
if (hi.is_pos() && !lo.is_neg()) {
|
|
||||||
mid = get_lower(i);
|
|
||||||
}
|
|
||||||
else if (hi.is_pos() && lo.is_neg()) {
|
|
||||||
mid = inf_eps(0);
|
|
||||||
}
|
|
||||||
else if (hi.is_pos() && lo.is_pos()) {
|
|
||||||
mid = inf_eps(0); // TBD: get a value from a model?
|
|
||||||
}
|
|
||||||
else if (hi.is_neg() && lo.is_neg()) {
|
|
||||||
mid = inf_eps(0); // TBD: get a value from a model?
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
mid = hi;
|
|
||||||
}
|
|
||||||
m_lower[i] = mid;
|
|
||||||
m_upper[i] = mid;
|
|
||||||
TRACE("opt", tout << "set lower bound of "; display_objective(tout, i) << " to: " << mid << "\n";
|
|
||||||
tout << get_lower(i) << ":" << get_upper(i) << "\n";);
|
tout << get_lower(i) << ":" << get_upper(i) << "\n";);
|
||||||
// Only assert bounds for bounded objectives
|
// Only assert bounds for bounded objectives
|
||||||
if (mid.get_infinity().is_zero())
|
if (lo.is_finite()) {
|
||||||
m_s->assert_expr(m_s->mk_ge(i, mid));
|
m_s->assert_expr(m_s->mk_ge(i, lo));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& optsmt::display_objective(std::ostream& out, unsigned i) const {
|
std::ostream& optsmt::display_objective(std::ostream& out, unsigned i) const {
|
||||||
|
@ -314,14 +339,13 @@ namespace opt {
|
||||||
void optsmt::display_assignment(std::ostream& out) const {
|
void optsmt::display_assignment(std::ostream& out) const {
|
||||||
unsigned sz = m_objs.size();
|
unsigned sz = m_objs.size();
|
||||||
for (unsigned i = 0; i < sz; ++i) {
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
display_objective(out, i) << " |-> " << get_value(i) << std::endl;
|
if (get_lower(i) != get_upper(i)) {
|
||||||
}
|
display_objective(out, i) << " |-> [" << get_lower(i)
|
||||||
}
|
<< ":" << get_upper(i) << "]" << std::endl;
|
||||||
|
}
|
||||||
void optsmt::display_range_assignment(std::ostream& out) const {
|
else {
|
||||||
unsigned sz = m_objs.size();
|
display_objective(out, i) << " |-> " << get_value(i) << std::endl;
|
||||||
for (unsigned i = 0; i < sz; ++i) {
|
}
|
||||||
display_objective(out, i) << " |-> [" << get_lower(i) << ":" << get_upper(i) << "]" << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,11 @@ namespace opt {
|
||||||
public:
|
public:
|
||||||
optsmt(ast_manager& m): m(m), m_s(0), m_cancel(false), m_objs(m) {}
|
optsmt(ast_manager& m): m(m), m_s(0), m_cancel(false), m_objs(m) {}
|
||||||
|
|
||||||
lbool operator()(opt_solver& solver);
|
void setup(opt_solver& solver);
|
||||||
|
|
||||||
|
lbool box();
|
||||||
|
|
||||||
|
lbool lex(unsigned obj_index);
|
||||||
|
|
||||||
void add(app* t, bool is_max);
|
void add(app* t, bool is_max);
|
||||||
|
|
||||||
|
@ -67,6 +71,8 @@ namespace opt {
|
||||||
|
|
||||||
lbool basic_opt();
|
lbool basic_opt();
|
||||||
|
|
||||||
|
lbool basic_lex(unsigned idx);
|
||||||
|
|
||||||
lbool farkas_opt();
|
lbool farkas_opt();
|
||||||
|
|
||||||
void set_max(vector<inf_eps>& dst, vector<inf_eps> const& src);
|
void set_max(vector<inf_eps>& dst, vector<inf_eps> const& src);
|
||||||
|
|
|
@ -3937,6 +3937,11 @@ namespace smt {
|
||||||
return th->get_value(n, value);
|
return th->get_value(n, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void context::update_model() {
|
||||||
|
mk_proto_model(l_true);
|
||||||
|
m_model = m_proto_model->mk_model();
|
||||||
|
}
|
||||||
|
|
||||||
void context::mk_proto_model(lbool r) {
|
void context::mk_proto_model(lbool r) {
|
||||||
TRACE("get_model",
|
TRACE("get_model",
|
||||||
display(tout);
|
display(tout);
|
||||||
|
|
|
@ -1390,6 +1390,8 @@ namespace smt {
|
||||||
|
|
||||||
void get_model(model_ref & m) const;
|
void get_model(model_ref & m) const;
|
||||||
|
|
||||||
|
void update_model();
|
||||||
|
|
||||||
void get_proto_model(proto_model_ref & m) const;
|
void get_proto_model(proto_model_ref & m) const;
|
||||||
|
|
||||||
unsigned get_num_asserted_formulas() const { return m_asserted_formulas.get_num_formulas(); }
|
unsigned get_num_asserted_formulas() const { return m_asserted_formulas.get_num_formulas(); }
|
||||||
|
|
|
@ -1000,7 +1000,7 @@ namespace smt {
|
||||||
virtual inf_eps_rational<inf_rational> maximize(theory_var v);
|
virtual inf_eps_rational<inf_rational> maximize(theory_var v);
|
||||||
virtual theory_var add_objective(app* term);
|
virtual theory_var add_objective(app* term);
|
||||||
virtual expr* mk_gt(theory_var v, inf_rational const& val);
|
virtual expr* mk_gt(theory_var v, inf_rational const& val);
|
||||||
virtual expr* mk_ge(theory_var v, inf_numeral const& val);
|
virtual expr* mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val);
|
||||||
void enable_record_conflict(expr* bound);
|
void enable_record_conflict(expr* bound);
|
||||||
void record_conflict(unsigned num_lits, literal const * lits,
|
void record_conflict(unsigned num_lits, literal const * lits,
|
||||||
unsigned num_eqs, enode_pair const * eqs,
|
unsigned num_eqs, enode_pair const * eqs,
|
||||||
|
|
|
@ -23,6 +23,7 @@ Revision History:
|
||||||
#include"theory_arith.h"
|
#include"theory_arith.h"
|
||||||
#include"smt_farkas_util.h"
|
#include"smt_farkas_util.h"
|
||||||
#include"th_rewriter.h"
|
#include"th_rewriter.h"
|
||||||
|
#include"filter_model_converter.h"
|
||||||
|
|
||||||
namespace smt {
|
namespace smt {
|
||||||
|
|
||||||
|
@ -1085,14 +1086,15 @@ namespace smt {
|
||||||
This allows to handle inequalities with non-standard numbers.
|
This allows to handle inequalities with non-standard numbers.
|
||||||
*/
|
*/
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
expr* theory_arith<Ext>::mk_ge(theory_var v, inf_numeral const& val) {
|
expr* theory_arith<Ext>::mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val) {
|
||||||
SASSERT(m_objective_theory_vars.contains(v));
|
SASSERT(m_objective_theory_vars.contains(v));
|
||||||
ast_manager& m = get_manager();
|
ast_manager& m = get_manager();
|
||||||
context& ctx = get_context();
|
context& ctx = get_context();
|
||||||
std::ostringstream strm;
|
std::ostringstream strm;
|
||||||
strm << val << " <= v" << v;
|
strm << val << " <= " << mk_pp(get_enode(v)->get_owner(), get_manager());
|
||||||
expr* b = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort());
|
app* b = m.mk_const(symbol(strm.str().c_str()), m.mk_bool_sort());
|
||||||
if (!ctx.b_internalized(b)) {
|
if (!ctx.b_internalized(b)) {
|
||||||
|
fm.insert(b->get_decl());
|
||||||
bool_var bv = ctx.mk_bool_var(b);
|
bool_var bv = ctx.mk_bool_var(b);
|
||||||
ctx.set_var_theory(bv, get_id());
|
ctx.set_var_theory(bv, get_id());
|
||||||
// ctx.set_enode_flag(bv, true);
|
// ctx.set_enode_flag(bv, true);
|
||||||
|
|
|
@ -24,6 +24,7 @@ Notes:
|
||||||
#ifndef _THEORY_OPT_H_
|
#ifndef _THEORY_OPT_H_
|
||||||
#define _THEORY_OPT_H_
|
#define _THEORY_OPT_H_
|
||||||
|
|
||||||
|
class filter_model_converter;
|
||||||
namespace smt {
|
namespace smt {
|
||||||
class theory_opt {
|
class theory_opt {
|
||||||
public:
|
public:
|
||||||
|
@ -31,7 +32,7 @@ namespace smt {
|
||||||
virtual inf_eps maximize(theory_var v) { UNREACHABLE(); return inf_eps::infinity(); }
|
virtual inf_eps maximize(theory_var v) { UNREACHABLE(); return inf_eps::infinity(); }
|
||||||
virtual theory_var add_objective(app* term) { UNREACHABLE(); return null_theory_var; }
|
virtual theory_var add_objective(app* term) { UNREACHABLE(); return null_theory_var; }
|
||||||
virtual expr* mk_gt(theory_var v, inf_rational const& val) { UNREACHABLE(); return 0; }
|
virtual expr* mk_gt(theory_var v, inf_rational const& val) { UNREACHABLE(); return 0; }
|
||||||
virtual expr* mk_ge(theory_var v, inf_eps const& val) { UNREACHABLE(); return 0; }
|
virtual expr* mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val) { UNREACHABLE(); return 0; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,6 +143,10 @@ class inf_eps_rational {
|
||||||
return m_infty;
|
return m_infty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_finite() const {
|
||||||
|
return m_infty.is_zero();
|
||||||
|
}
|
||||||
|
|
||||||
static inf_eps_rational zero() {
|
static inf_eps_rational zero() {
|
||||||
return inf_eps_rational(Numeral::zero());
|
return inf_eps_rational(Numeral::zero());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue