mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 09:05:31 +00:00
address divergence in the case of shared theory symbols. Codeplex issue 147, thanks to George Karpenkov
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
commit
08cb8b8de8
74 changed files with 1280 additions and 896 deletions
|
@ -1202,7 +1202,8 @@ namespace opt {
|
|||
case O_MINIMIZE:
|
||||
case O_MAXIMIZE: {
|
||||
inf_eps n = m_optsmt.get_lower(obj.m_index);
|
||||
if (n.get_infinity().is_zero() &&
|
||||
if (m_optsmt.objective_is_model_valid(obj.m_index) &&
|
||||
n.get_infinity().is_zero() &&
|
||||
n.get_infinitesimal().is_zero() &&
|
||||
m_model->eval(obj.m_term, val) &&
|
||||
is_numeral(val, r1)) {
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace opt {
|
|||
m(mgr),
|
||||
m_dump_benchmarks(false),
|
||||
m_fm(fm),
|
||||
m_objective_sorts(m),
|
||||
m_first(true) {
|
||||
m_params.updt_params(p);
|
||||
m_params.m_relevancy_lvl = 0;
|
||||
|
@ -173,13 +174,56 @@ namespace opt {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief maximize the value of objective i in the current state.
|
||||
Return a predicate that blocks the current maximal value.
|
||||
|
||||
The result of 'maximize' is post-processed.
|
||||
When maximization involves shared symbols the model produced
|
||||
by local optimization does not necessarily satisfy combination
|
||||
constraints (it may not be a real model).
|
||||
In this case, the model is post-processed (update_model
|
||||
causes an additional call to final_check to propagate theory equalities
|
||||
when 'has_shared' is true).
|
||||
|
||||
*/
|
||||
void opt_solver::maximize_objective(unsigned i, expr_ref& blocker) {
|
||||
smt::theory_var v = m_objective_vars[i];
|
||||
m_objective_values[i] = get_optimizer().maximize(v, blocker);
|
||||
m_context.get_context().update_model();
|
||||
bool has_shared = false;
|
||||
inf_eps val = get_optimizer().maximize(v, blocker, has_shared);
|
||||
inf_eps val2;
|
||||
m_valid_objectives[i] = true;
|
||||
if (m_context.get_context().update_model(has_shared)) {
|
||||
if (has_shared) {
|
||||
val2 = current_objective_value(i);
|
||||
if (val2 != val) {
|
||||
decrement_value(i, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
SASSERT(has_shared);
|
||||
// model is not final. We set the current objective to
|
||||
// close to the optimal (ignoring types).
|
||||
decrement_value(i, val);
|
||||
}
|
||||
m_objective_values[i] = val;
|
||||
|
||||
TRACE("opt", { model_ref mdl; tout << m_objective_values[i] << "\n";
|
||||
get_model(mdl); model_smt2_pp(tout << "update model: ", m, *mdl, 0); });
|
||||
tout << blocker << "\n";
|
||||
get_model(mdl); model_smt2_pp(tout << "update model:\n", m, *mdl, 0); });
|
||||
}
|
||||
|
||||
void opt_solver::decrement_value(unsigned i, inf_eps& val) {
|
||||
if (arith_util(m).is_real(m_objective_sorts[i].get())) {
|
||||
val -= inf_eps(inf_rational(rational(0),true));
|
||||
}
|
||||
else {
|
||||
val -= inf_eps(inf_rational(rational(1)));
|
||||
}
|
||||
m_valid_objectives[i] = false;
|
||||
}
|
||||
|
||||
|
||||
void opt_solver::get_unsat_core(ptr_vector<expr> & r) {
|
||||
unsigned sz = m_context.get_unsat_core_size();
|
||||
|
@ -232,6 +276,8 @@ namespace opt {
|
|||
smt::theory_var v = get_optimizer().add_objective(term);
|
||||
m_objective_vars.push_back(v);
|
||||
m_objective_values.push_back(inf_eps(rational(-1), inf_rational()));
|
||||
m_objective_sorts.push_back(m.get_sort(term));
|
||||
m_valid_objectives.push_back(true);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
@ -278,6 +324,8 @@ namespace opt {
|
|||
void opt_solver::reset_objectives() {
|
||||
m_objective_vars.reset();
|
||||
m_objective_values.reset();
|
||||
m_objective_sorts.reset();
|
||||
m_valid_objectives.reset();
|
||||
}
|
||||
|
||||
opt_solver& opt_solver::to_opt(solver& s) {
|
||||
|
|
|
@ -76,6 +76,8 @@ namespace opt {
|
|||
bool m_objective_enabled;
|
||||
svector<smt::theory_var> m_objective_vars;
|
||||
vector<inf_eps> m_objective_values;
|
||||
sort_ref_vector m_objective_sorts;
|
||||
svector<bool> m_valid_objectives;
|
||||
bool m_dump_benchmarks;
|
||||
static unsigned m_dump_count;
|
||||
statistics m_stats;
|
||||
|
@ -109,6 +111,9 @@ namespace opt {
|
|||
void maximize_objectives(expr_ref_vector& blockers);
|
||||
inf_eps const & saved_objective_value(unsigned obj_index);
|
||||
inf_eps current_objective_value(unsigned obj_index);
|
||||
bool objective_is_model_valid(unsigned obj_index) const {
|
||||
return m_valid_objectives[obj_index];
|
||||
}
|
||||
|
||||
vector<inf_eps> const& get_objective_values();
|
||||
expr_ref mk_ge(unsigned obj_index, inf_eps const& val);
|
||||
|
@ -124,6 +129,9 @@ namespace opt {
|
|||
unsigned num_assumptions, expr * const * assumptions,
|
||||
char const * name = "benchmarks",
|
||||
char const * logic = "", char const * status = "unknown", char const * attributes = "");
|
||||
|
||||
private:
|
||||
void decrement_value(unsigned i, inf_eps& val);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -222,7 +222,6 @@ namespace opt {
|
|||
for (unsigned i = 0; i < m_lower.size() && !m_cancel; ++i) {
|
||||
if (m_lower[i] < m_upper[i]) {
|
||||
mid.push_back((m_upper[i]+m_lower[i])/rational(2));
|
||||
//mid.push_back(m_upper[i]);
|
||||
bound = m_s->mk_ge(i, mid[i]);
|
||||
bounds.push_back(bound);
|
||||
}
|
||||
|
@ -373,6 +372,10 @@ namespace opt {
|
|||
return m_lower[i];
|
||||
}
|
||||
|
||||
bool optsmt::objective_is_model_valid(unsigned index) const {
|
||||
return m_s->objective_is_model_valid(index);
|
||||
}
|
||||
|
||||
inf_eps optsmt::get_upper(unsigned i) const {
|
||||
if (i >= m_upper.size()) return inf_eps();
|
||||
return m_upper[i];
|
||||
|
|
|
@ -58,6 +58,7 @@ namespace opt {
|
|||
void commit_assignment(unsigned index);
|
||||
inf_eps get_lower(unsigned index) const;
|
||||
inf_eps get_upper(unsigned index) const;
|
||||
bool objective_is_model_valid(unsigned index) const;
|
||||
void get_model(model_ref& mdl);
|
||||
|
||||
void update_lower(unsigned idx, inf_eps const& r);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue