diff --git a/src/opt/inc_sat_solver.cpp b/src/opt/inc_sat_solver.cpp index 1a3fc7ff5..6dd562f82 100644 --- a/src/opt/inc_sat_solver.cpp +++ b/src/opt/inc_sat_solver.cpp @@ -30,6 +30,7 @@ Notes: #include "simplify_tactic.h" #include "goal2sat.h" #include "ast_pp.h" +#include "model_smt2_pp.h" // incremental SAT solver. class inc_sat_solver : public solver { @@ -396,14 +397,15 @@ private: (*m_mc)(m_model); } SASSERT(m_model); - // IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *(m_model.get()), 0);); DEBUG_CODE( for (unsigned i = 0; i < m_fmls.size(); ++i) { expr_ref tmp(m); VERIFY(m_model->eval(m_fmls[i].get(), tmp)); CTRACE("opt", !m.is_true(tmp), - tout << "Evaluation failed: " << mk_pp(m_fmls[i].get(), m) << "\n";); + tout << "Evaluation failed: " << mk_pp(m_fmls[i].get(), m) + << " to " << tmp << "\n"; + model_smt2_pp(tout, m, *(m_model.get()), 0);); SASSERT(m.is_true(tmp)); }); } diff --git a/src/opt/maxsmt.cpp b/src/opt/maxsmt.cpp index 16e577021..b1bf015f9 100644 --- a/src/opt/maxsmt.cpp +++ b/src/opt/maxsmt.cpp @@ -251,11 +251,11 @@ namespace opt { } void maxsmt::update_lower(rational const& r) { - if (m_lower > r) m_lower = r; + m_lower = r; } void maxsmt::update_upper(rational const& r) { - if (m_upper < r) m_upper = r; + m_upper = r; } void maxsmt::get_model(model_ref& mdl) { diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 141a2d425..5cd2e1c1e 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -247,8 +247,7 @@ namespace opt { mdl = m_model; } - void context::get_model(model_ref& mdl) { - mdl = m_model; + void context::fix_model(model_ref& mdl) { if (mdl) { if (m_model_converter) { (*m_model_converter)(mdl, 0); @@ -257,6 +256,16 @@ namespace opt { } } + void context::set_model(model_ref& mdl) { + m_model = mdl; + fix_model(mdl); + } + + void context::get_model(model_ref& mdl) { + mdl = m_model; + fix_model(mdl); + } + lbool context::execute_min_max(unsigned index, bool committed, bool scoped, bool is_max) { if (scoped) get_solver().push(); lbool result = m_optsmt.lex(index, is_max); @@ -384,6 +393,9 @@ namespace opt { break; } } + TRACE("opt", + model_smt2_pp(tout << "Model:\n", m, *mdl, 0); + mdl->eval(term, val); tout << term << " " << val << "\n";); VERIFY(mdl->eval(term, val) && is_numeral(val, r)); } @@ -914,9 +926,12 @@ namespace opt { objective const& obj = m_objectives[i]; rational r; switch(obj.m_type) { - case O_MINIMIZE: - if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { + case O_MINIMIZE: { + bool evaluated = m_model->eval(obj.m_term, val); + TRACE("opt", tout << obj.m_term << " " << val << " " << evaluated << " " << is_numeral(val, r) << "\n";); + if (evaluated && is_numeral(val, r)) { inf_eps val = inf_eps(obj.m_adjust_value(r)); + TRACE("opt", tout << "adjusted value: " << val << "\n";); if (is_lower) { m_optsmt.update_lower(obj.m_index, val); } @@ -925,9 +940,13 @@ namespace opt { } } break; - case O_MAXIMIZE: - if (m_model->eval(obj.m_term, val) && is_numeral(val, r)) { + } + case O_MAXIMIZE: { + bool evaluated = m_model->eval(obj.m_term, val); + TRACE("opt", tout << obj.m_term << " " << val << "\n";); + if (evaluated && is_numeral(val, r)) { inf_eps val = inf_eps(obj.m_adjust_value(r)); + TRACE("opt", tout << "adjusted value: " << val << "\n";); if (is_lower) { m_optsmt.update_lower(obj.m_index, val); } @@ -936,10 +955,13 @@ namespace opt { } } break; + } case O_MAXSMT: { bool ok = true; for (unsigned j = 0; ok && j < obj.m_terms.size(); ++j) { - if (m_model->eval(obj.m_terms[j], val)) { + bool evaluated = m_model->eval(obj.m_terms[j], val); + TRACE("opt", tout << mk_pp(obj.m_terms[j], m) << " " << val << "\n";); + if (evaluated) { if (!m.is_true(val)) { r += obj.m_weights[j]; } @@ -949,11 +971,14 @@ namespace opt { } } if (ok) { + maxsmt& ms = *m_maxsmts.find(obj.m_id); if (is_lower) { - m_maxsmts.find(obj.m_id)->update_upper(r); + ms.update_upper(r); + TRACE("opt", tout << r << " " << ms.get_upper() << "\n";); } else { - m_maxsmts.find(obj.m_id)->update_lower(r); + ms.update_lower(r); + TRACE("opt", tout << r << " " << ms.get_lower() << "\n";); } } break; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 5ebb4db3f..3d29c8fee 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -147,6 +147,8 @@ namespace opt { virtual void set_hard_constraints(ptr_vector & hard); virtual lbool optimize(); virtual void get_model(model_ref& m); + virtual void set_model(model_ref& m); + virtual void fix_model(model_ref& m); virtual void collect_statistics(statistics& stats) const; virtual proof* get_proof() { return 0; } virtual void get_labels(svector & r) {} diff --git a/src/opt/opt_pareto.cpp b/src/opt/opt_pareto.cpp index 2e0286945..e8b295d9f 100644 --- a/src/opt/opt_pareto.cpp +++ b/src/opt/opt_pareto.cpp @@ -38,7 +38,10 @@ namespace opt { return l_undef; } m_solver->get_model(m_model); - IF_VERBOSE(1, model_smt2_pp(verbose_stream() << "new model:\n", m, *m_model, 0);); + IF_VERBOSE(1, + model_ref mdl(m_model); + cb.fix_model(mdl); + model_smt2_pp(verbose_stream() << "new model:\n", m, *mdl, 0);); // TBD: we can also use local search to tune solution coordinate-wise. mk_dominates(); is_sat = m_solver->check_sat(0, 0); @@ -65,6 +68,7 @@ namespace opt { fmls.push_back(m.mk_or(gt.size(), gt.c_ptr())); fml = m.mk_and(fmls.size(), fmls.c_ptr()); IF_VERBOSE(10, verbose_stream() << "dominates: " << fml << "\n";); + TRACE("opt", tout << fml << "\n";); m_solver->assert_expr(fml); } @@ -77,6 +81,7 @@ namespace opt { } fml = m.mk_not(m.mk_and(le.size(), le.c_ptr())); IF_VERBOSE(10, verbose_stream() << "not dominated by: " << fml << "\n";); + TRACE("opt", tout << fml << "\n";); m_solver->assert_expr(fml); } diff --git a/src/opt/opt_pareto.h b/src/opt/opt_pareto.h index 84e0702aa..ce78e68f3 100644 --- a/src/opt/opt_pareto.h +++ b/src/opt/opt_pareto.h @@ -31,6 +31,8 @@ namespace opt { virtual expr_ref mk_gt(unsigned i, model_ref& model) = 0; virtual expr_ref mk_ge(unsigned i, model_ref& model) = 0; virtual expr_ref mk_le(unsigned i, model_ref& model) = 0; + virtual void set_model(model_ref& m) = 0; + virtual void fix_model(model_ref& m) = 0; }; class pareto_base { protected: diff --git a/src/opt/opt_solver.cpp b/src/opt/opt_solver.cpp index 2f0fc4661..2a12818c5 100644 --- a/src/opt/opt_solver.cpp +++ b/src/opt/opt_solver.cpp @@ -194,6 +194,7 @@ namespace opt { inf_eps val = get_optimizer().maximize(v, blocker, has_shared); inf_eps val2; m_valid_objectives[i] = true; + TRACE("opt", tout << (has_shared?"has shared":"non-shared") << "\n";); if (m_context.get_context().update_model(has_shared)) { if (has_shared) { val2 = current_objective_value(i); @@ -302,20 +303,31 @@ namespace opt { if (typeid(smt::theory_inf_arith) == typeid(opt)) { smt::theory_inf_arith& th = dynamic_cast(opt); - return expr_ref(th.mk_ge(m_fm, v, val), m); + return th.mk_ge(m_fm, v, val); } if (typeid(smt::theory_mi_arith) == typeid(opt)) { smt::theory_mi_arith& th = dynamic_cast(opt); SASSERT(val.is_finite()); - return expr_ref(th.mk_ge(m_fm, v, val.get_numeral()), m); + return th.mk_ge(m_fm, v, val.get_numeral()); } if (typeid(smt::theory_i_arith) == typeid(opt)) { SASSERT(val.is_finite()); SASSERT(val.get_infinitesimal().is_zero()); smt::theory_i_arith& th = dynamic_cast(opt); - return expr_ref(th.mk_ge(m_fm, v, val.get_rational()), m); + return th.mk_ge(m_fm, v, val.get_rational()); + } + + if (typeid(smt::theory_idl) == typeid(opt)) { + smt::theory_idl& th = dynamic_cast(opt); + return th.mk_ge(m_fm, v, val.get_rational()); + } + + if (typeid(smt::theory_rdl) == typeid(opt) && + val.get_infinitesimal().is_zero()) { + smt::theory_rdl& th = dynamic_cast(opt); + return th.mk_ge(m_fm, v, val.get_rational()); } // difference logic? diff --git a/src/opt/optsmt.cpp b/src/opt/optsmt.cpp index f0ef78c77..1148e3411 100644 --- a/src/opt/optsmt.cpp +++ b/src/opt/optsmt.cpp @@ -170,11 +170,13 @@ namespace opt { } void optsmt::update_lower(unsigned idx, inf_eps const& v) { + TRACE("opt", tout << "v" << idx << " >= " << v << "\n";); m_lower_fmls[idx] = m_s->mk_ge(idx, v); m_lower[idx] = v; } void optsmt::update_upper(unsigned idx, inf_eps const& v) { + TRACE("opt", tout << "v" << idx << " <= " << v << "\n";); m_upper[idx] = v; } @@ -302,6 +304,9 @@ namespace opt { lbool is_sat = l_true; expr_ref block(m), tmp(m); + for (unsigned i = 0; i < obj_index; ++i) { + commit_assignment(i); + } while (is_sat == l_true && !m_cancel) { is_sat = m_s->check_sat(0, 0); if (is_sat != l_true) break; diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 32f8111f0..0685bb90c 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -1193,6 +1193,10 @@ public: return m_assignment[v]; } + void set_assignment(dl_var v, numeral const & n) { + m_assignment[v] = n; + } + unsigned get_timestamp() const { return m_timestamp; } diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 8a355009a..adb17f6e2 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -3944,10 +3944,12 @@ namespace smt { if (refinalize) { fcs = final_check(); } + TRACE("opt", tout << (refinalize?"refinalize":"no-op") << " " << fcs << "\n";); if (fcs == FC_DONE) { mk_proto_model(l_true); m_model = m_proto_model->mk_model(); } + return fcs == FC_DONE; } diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 1dadeeca0..a81be26f6 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -894,7 +894,7 @@ namespace smt { void init_gains(theory_var x, bool inc, inf_numeral& min_gain, inf_numeral& max_gain); bool update_gains(bool inc, theory_var x_i, numeral const& a_ij, inf_numeral& min_gain, inf_numeral& max_gain); - bool move_to_bound_new(theory_var x_i, bool inc, bool& best_effort, bool& has_shared); + bool move_to_bound_new(theory_var x_i, bool inc, unsigned& best_efforts, bool& has_shared); bool pick_var_to_leave( theory_var x_j, bool inc, numeral & a_ij, inf_numeral& min_gain, inf_numeral& max_gain, @@ -1036,7 +1036,7 @@ namespace smt { virtual inf_eps_rational maximize(theory_var v, expr_ref& blocker, bool& has_shared); virtual inf_eps_rational value(theory_var v); virtual theory_var add_objective(app* term); - virtual expr* mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val); + virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val); void enable_record_conflict(expr* bound); void record_conflict(unsigned num_lits, literal const * lits, unsigned num_eqs, enode_pair const * eqs, diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index ffc8314e0..d8c615547 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1189,7 +1189,7 @@ namespace smt { This allows to handle inequalities with non-standard numbers. */ template - expr* theory_arith::mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val) { + expr_ref theory_arith::mk_ge(filter_model_converter& fm, theory_var v, inf_numeral const& val) { ast_manager& m = get_manager(); context& ctx = get_context(); std::ostringstream strm; @@ -1208,7 +1208,7 @@ namespace smt { TRACE("arith", tout << mk_pp(b, m) << "\n"; display_atom(tout, a, false);); } - return b; + return expr_ref(b, m); } @@ -1658,9 +1658,17 @@ namespace smt { bool is_tighter = false; if (is_int(x_i)) den_aij = denominator(a_ij); SASSERT(den_aij.is_pos() && den_aij.is_int()); + + if (is_int(x_i) && !den_aij.is_one()) { + SASSERT(min_gain.is_pos()); + min_gain = inf_numeral(lcm(min_gain.get_rational(), den_aij)); + normalize_gain(min_gain.get_rational(), max_gain); + } + if (!max_inc.is_minus_one()) { if (is_int(x_i)) { - normalize_gain(den_aij, max_inc); + max_inc = floor(max_inc); + normalize_gain(min_gain.get_rational(), max_inc); } if (unbounded_gain(max_gain)) { max_gain = max_inc; @@ -1671,13 +1679,6 @@ namespace smt { is_tighter = true; } } - if (is_int(x_i)) { - SASSERT(min_gain.is_pos()); - if (!den_aij.is_one()) { - min_gain = inf_numeral(lcm(min_gain.get_rational(), den_aij)); - normalize_gain(den_aij, max_gain); - } - } TRACE("opt", tout << "v" << x_i << " a_ij " << a_ij << " " << "min gain: " << min_gain << " " @@ -1701,7 +1702,8 @@ namespace smt { bool max, bool& has_shared) { m_stats.m_max_min++; - bool best_effort = false, inc = false; + unsigned best_efforts = 0; + bool inc = false; SASSERT(valid_assignment()); @@ -1712,7 +1714,8 @@ namespace smt { #endif max_min_t result = OPTIMIZED; has_shared = false; - while (true) { + unsigned max_efforts = 10 + (get_context().get_random_value() % 20); + while (best_efforts < max_efforts) { theory_var x_j = null_theory_var; theory_var x_i = null_theory_var; max_gain.reset(); @@ -1734,10 +1737,11 @@ namespace smt { if (!pick_var_to_leave(curr_x_j, curr_inc, curr_a_ij, curr_min_gain, curr_max_gain, has_shared, curr_x_i)) { - best_effort = true; - continue; + best_efforts++; + } + else { + SASSERT(safe_gain(curr_min_gain, curr_max_gain)); } - SASSERT(safe_gain(curr_min_gain, curr_max_gain)); if (curr_x_i == null_theory_var) { TRACE("opt", tout << "unbounded\n";); // we can increase/decrease curr_x_j as much as we want. @@ -1770,7 +1774,7 @@ namespace smt { } TRACE("opt", tout << "after traversing row:\nx_i: v" << x_i << ", x_j: v" << x_j << ", gain: " << max_gain << "\n"; - tout << "skipped row: " << (best_effort?"yes":"no") << "\n"; + tout << "best efforts: " << best_efforts << "\n"; display(tout);); if (x_j == null_theory_var) { @@ -1781,7 +1785,7 @@ namespace smt { } if (min_gain.is_pos() && !min_gain.is_one()) { - best_effort = true; + ++best_efforts; } if (x_i == null_theory_var) { // can increase/decrease x_j as much as we want. @@ -1802,7 +1806,7 @@ namespace smt { continue; } SASSERT(unbounded_gain(max_gain)); - best_effort = false; + best_efforts = 0; result = UNBOUNDED; break; } @@ -1836,9 +1840,8 @@ namespace smt { SASSERT(is_base(x_j)); bool inc_xi = inc?a_ij.is_neg():a_ij.is_pos(); - if (!move_to_bound_new(x_i, inc_xi, best_effort, has_shared)) { - best_effort = true; - break; + if (!move_to_bound_new(x_i, inc_xi, best_efforts, has_shared)) { + // break; } row & r2 = m_rows[get_var_row(x_j)]; @@ -1848,7 +1851,7 @@ namespace smt { SASSERT(valid_assignment()); } TRACE("opt", display(tout);); - return best_effort?BEST_EFFORT:result; + return (best_efforts>0)?BEST_EFFORT:result; } /** @@ -1862,7 +1865,7 @@ namespace smt { bool theory_arith::move_to_bound_new( theory_var x_i, // variable to move bool inc, // increment variable or decrement - bool& best_effort, // is bound move a best effort? + unsigned& best_efforts, // is bound move a best effort? bool& has_shared) { // does move include shared variables? inf_numeral min_gain, max_gain; init_gains(x_i, inc, min_gain, max_gain); @@ -1877,6 +1880,7 @@ namespace smt { update_gains(inc, s, coeff, min_gain, max_gain); has_shared |= get_context().is_shared(get_enode(s)); } + bool result = false; if (safe_gain(min_gain, max_gain)) { TRACE("opt", tout << "Safe delta: " << max_gain << "\n";); SASSERT(!unbounded_gain(max_gain)); @@ -1884,12 +1888,15 @@ namespace smt { max_gain.neg(); } update_value(x_i, max_gain); - best_effort = min_gain.is_pos() && !min_gain.is_one(); - return !max_gain.is_zero(); + if (!min_gain.is_pos() || min_gain.is_one()) { + ++best_efforts; + } + result = !max_gain.is_zero(); } - else { - return false; + if (!result) { + ++best_efforts; } + return result; } /** @@ -2004,7 +2011,7 @@ namespace smt { add_tmp_row_entry(m_tmp_row, it->m_coeff, it->m_var); } } - max_min_t r = max_min_orig(m_tmp_row, max, has_shared); + max_min_t r = max_min_new(m_tmp_row, max, has_shared); if (r == OPTIMIZED) { TRACE("opt", tout << mk_pp(e, get_manager()) << " " << (max ? "max" : "min") << " value is: " << get_value(v) << "\n"; display_row(tout, m_tmp_row, true); display_row_info(tout, m_tmp_row);); diff --git a/src/smt/theory_dense_diff_logic.h b/src/smt/theory_dense_diff_logic.h index 4144d9c03..04e257889 100644 --- a/src/smt/theory_dense_diff_logic.h +++ b/src/smt/theory_dense_diff_logic.h @@ -198,6 +198,7 @@ namespace smt { void del_vars(unsigned old_num_vars); void init_model(); bool internalize_objective(expr * n, rational const& m, rational& r, objective_term & objective); + expr_ref mk_ineq(theory_var v, inf_rational const& val, bool is_strict); #ifdef Z3DEBUG bool check_vector_sizes() const; bool check_matrix() const; @@ -270,8 +271,8 @@ namespace smt { virtual inf_eps_rational value(theory_var v); virtual theory_var add_objective(app* term); virtual expr_ref mk_gt(theory_var v, inf_rational const& val); - virtual expr* mk_ge(theory_var v, inf_rational const& val) { return 0; } - + virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val); + // ----------------------------------- // // Main diff --git a/src/smt/theory_dense_diff_logic_def.h b/src/smt/theory_dense_diff_logic_def.h index 29684d987..89e23cd3f 100644 --- a/src/smt/theory_dense_diff_logic_def.h +++ b/src/smt/theory_dense_diff_logic_def.h @@ -1030,6 +1030,17 @@ namespace smt { template expr_ref theory_dense_diff_logic::mk_gt(theory_var v, inf_rational const& val) { + return mk_ineq(v, val, true); + } + + template + expr_ref theory_dense_diff_logic::mk_ge( + filter_model_converter& fm, theory_var v, inf_rational const& val) { + return mk_ineq(v, val, false); + } + + template + expr_ref theory_dense_diff_logic::mk_ineq(theory_var v, inf_rational const& val, bool is_strict) { ast_manager& m = get_manager(); objective_term const& t = m_objectives[v]; expr_ref e(m), f(m), f2(m); @@ -1052,19 +1063,32 @@ namespace smt { else { // expr_ref_vector const& core = m_objective_assignments[v]; - f = m.mk_not(m.mk_and(core.size(), core.c_ptr())); + f = m.mk_and(core.size(), core.c_ptr()); + if (is_strict) { + f = m.mk_not(f); + } TRACE("arith", tout << "block: " << f << "\n";); return f; } - inf_rational new_val = val - inf_rational(m_objective_consts[v]); - e = m_autil.mk_numeral(new_val.get_rational(), m.get_sort(f)); + e = m_autil.mk_numeral(val.get_rational(), m.get_sort(f)); - if (new_val.get_infinitesimal().is_neg()) { - f = m_autil.mk_ge(f, e); + if (val.get_infinitesimal().is_neg()) { + if (is_strict) { + f = m_autil.mk_ge(f, e); + } + else { + expr_ref_vector const& core = m_objective_assignments[v]; + f = m.mk_and(core.size(), core.c_ptr()); + } } else { - f = m_autil.mk_gt(f, e); + if (is_strict) { + f = m_autil.mk_gt(f, e); + } + else { + f = m_autil.mk_ge(f, e); + } } return f; } diff --git a/src/smt/theory_diff_logic.h b/src/smt/theory_diff_logic.h index 0327298b3..8b5bb2b86 100644 --- a/src/smt/theory_diff_logic.h +++ b/src/smt/theory_diff_logic.h @@ -324,13 +324,13 @@ namespace smt { virtual inf_eps value(theory_var v); virtual theory_var add_objective(app* term); virtual expr_ref mk_gt(theory_var v, inf_rational const& val); - virtual expr* mk_ge(theory_var v, inf_rational const& val) { return 0; } + virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val); bool internalize_objective(expr * n, rational const& m, rational& r, objective_term & objective); private: - expr_ref block_objective(theory_var v, inf_rational const& val); + expr_ref mk_ineq(theory_var v, inf_rational const& val, bool is_strict); virtual void new_eq_eh(theory_var v1, theory_var v2, justification& j); diff --git a/src/smt/theory_diff_logic_def.h b/src/smt/theory_diff_logic_def.h index ee9823912..6c43c8d11 100644 --- a/src/smt/theory_diff_logic_def.h +++ b/src/smt/theory_diff_logic_def.h @@ -546,7 +546,7 @@ void theory_diff_logic::propagate_core() { template bool theory_diff_logic::propagate_atom(atom* a) { context& ctx = get_context(); - TRACE("arith", a->display(*this, tout); ); + TRACE("arith", a->display(*this, tout); tout << "\n";); if (ctx.inconsistent()) { return false; } @@ -1236,6 +1236,13 @@ theory_diff_logic::maximize(theory_var v, expr_ref& blocker, bool& has_shar core.push_back(tmp); } } + compute_delta(); + for (unsigned i = 0; i < m_graph.get_num_nodes(); ++i) { + unsigned w = node2simplex(i); + simplex::mpq_ext::eps_numeral const& val = S.get_value(w); + rational r = rational(val.first) + m_delta*rational(val.second); + m_graph.set_assignment(i, numeral(r)); + } blocker = mk_gt(v, r); return inf_eps(rational(0), r + m_objective_consts[v]); } @@ -1267,7 +1274,7 @@ theory_var theory_diff_logic::add_objective(app* term) { } template -expr_ref theory_diff_logic::block_objective(theory_var v, inf_rational const& val) { +expr_ref theory_diff_logic::mk_ineq(theory_var v, inf_rational const& val, bool is_strict) { ast_manager& m = get_manager(); objective_term const& t = m_objectives[v]; expr_ref e(m), f(m), f2(m); @@ -1290,7 +1297,10 @@ expr_ref theory_diff_logic::block_objective(theory_var v, inf_rational cons else { // expr_ref_vector const& core = m_objective_assignments[v]; - f = m.mk_not(m.mk_and(core.size(), core.c_ptr())); + f = m.mk_and(core.size(), core.c_ptr()); + if (is_strict) { + f = m.mk_not(f); + } TRACE("arith", tout << "block: " << f << "\n";); return f; } @@ -1299,18 +1309,35 @@ expr_ref theory_diff_logic::block_objective(theory_var v, inf_rational cons e = m_util.mk_numeral(new_val.get_rational(), m.get_sort(f)); if (new_val.get_infinitesimal().is_neg()) { - f = m_util.mk_ge(f, e); + if (is_strict) { + f = m_util.mk_ge(f, e); + } + else { + expr_ref_vector const& core = m_objective_assignments[v]; + f = m.mk_and(core.size(), core.c_ptr()); + } } else { - f = m_util.mk_gt(f, e); + if (is_strict) { + f = m_util.mk_gt(f, e); + } + else { + f = m_util.mk_ge(f, e); + } } return f; } template expr_ref theory_diff_logic::mk_gt(theory_var v, inf_rational const& val) { - expr_ref o = block_objective(v, val); - return o; + return mk_ineq(v, val, true); +} + +template +expr_ref theory_diff_logic::mk_ge(filter_model_converter& fm, theory_var v, inf_rational const& val) { + return mk_ineq(v, val, false); +} + #if 0 context & ctx = get_context(); model_ref mdl; @@ -1321,7 +1348,6 @@ expr_ref theory_diff_logic::mk_gt(theory_var v, inf_rational const& val) { expr_ref_vector implicants = impl_extractor.minimize_literals(formulas, mdl); return m.mk_and(o, m.mk_not(m.mk_and(implicants.size(), implicants.c_ptr()))); #endif -} template bool theory_diff_logic::internalize_objective(expr * n, rational const& m, rational& q, objective_term & objective) { diff --git a/src/smt/theory_opt.h b/src/smt/theory_opt.h index 9db05a438..61acfc381 100644 --- a/src/smt/theory_opt.h +++ b/src/smt/theory_opt.h @@ -33,7 +33,7 @@ namespace smt { virtual inf_eps value(theory_var) = 0; virtual inf_eps maximize(theory_var v, expr_ref& blocker, bool& has_shared) = 0; virtual theory_var add_objective(app* term) = 0; - virtual expr* mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val) { UNREACHABLE(); return 0; } + virtual expr_ref mk_ge(filter_model_converter& fm, theory_var v, inf_eps const& val) { UNREACHABLE(); return expr_ref(*((ast_manager*)0)); } bool is_linear(ast_manager& m, expr* term); bool is_numeral(arith_util& a, expr* term); };