3
0
Fork 0
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:
Nikolaj Bjorner 2013-12-13 23:36:42 +01:00
parent df5c2adc4e
commit 8c85ee6b7c
13 changed files with 219 additions and 125 deletions

View file

@ -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)) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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,

View file

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

View file

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

View file

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