mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 12:08:18 +00:00
fix #4116
delta has to be computed based on Simplex tableau not on difference graph.
This commit is contained in:
parent
3a63c3751e
commit
4f462925a0
|
@ -20,7 +20,50 @@ Notes:
|
||||||
#include "math/simplex/simplex.h"
|
#include "math/simplex/simplex.h"
|
||||||
#include "math/simplex/sparse_matrix_def.h"
|
#include "math/simplex/sparse_matrix_def.h"
|
||||||
#include "math/simplex/simplex_def.h"
|
#include "math/simplex/simplex_def.h"
|
||||||
|
#include "util/rational.h"
|
||||||
|
#include "util/inf_rational.h"
|
||||||
|
|
||||||
namespace simplex {
|
namespace simplex {
|
||||||
template class simplex<mpz_ext>;
|
template class simplex<mpz_ext>;
|
||||||
template class simplex<mpq_ext>;
|
template class simplex<mpq_ext>;
|
||||||
|
|
||||||
|
static void refine_delta(rational& delta, inf_rational const& l, inf_rational const& u) {
|
||||||
|
if (l.get_rational() < u.get_rational() && l.get_infinitesimal() > u.get_infinitesimal()) {
|
||||||
|
rational new_delta = (u.get_rational() - l.get_rational()) / (l.get_infinitesimal() - u.get_infinitesimal());
|
||||||
|
if (new_delta < delta) {
|
||||||
|
delta = new_delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ensure_rational_solution(simplex<mpq_ext>& S) {
|
||||||
|
rational delta(1);
|
||||||
|
for (unsigned i = 0; i < S.get_num_vars(); ++i) {
|
||||||
|
auto const& _value = S.get_value(i);
|
||||||
|
inf_rational value(rational(_value.first), rational(_value.second));
|
||||||
|
if (S.lower_valid(i)) {
|
||||||
|
auto const& _bound = S.get_lower(i);
|
||||||
|
inf_rational bound(rational(_bound.first), rational(_bound.second));
|
||||||
|
refine_delta(delta, bound, value);
|
||||||
|
}
|
||||||
|
if (S.upper_valid(i)) {
|
||||||
|
auto const& _bound = S.get_upper(i);
|
||||||
|
inf_rational bound(rational(_bound.first), rational(_bound.second));
|
||||||
|
refine_delta(delta, value, bound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsynch_mpq_inf_manager inf_mgr;
|
||||||
|
scoped_mpq_inf q(inf_mgr);
|
||||||
|
for (unsigned i = 0; i < S.get_num_vars(); ++i) {
|
||||||
|
auto const& _value = S.get_value(i);
|
||||||
|
rational inf(_value.second);
|
||||||
|
if (!inf.is_zero()) {
|
||||||
|
rational fin = rational(_value.first) + inf * delta;
|
||||||
|
inf = 0;
|
||||||
|
inf_mgr.set(q, fin.to_mpq(), inf.to_mpq());
|
||||||
|
S.set_value(i, q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -133,6 +133,8 @@ namespace simplex {
|
||||||
void set_upper(var_t var, eps_numeral const& b);
|
void set_upper(var_t var, eps_numeral const& b);
|
||||||
void get_lower(var_t var, scoped_eps_numeral& b) const { b = m_vars[var].m_lower; }
|
void get_lower(var_t var, scoped_eps_numeral& b) const { b = m_vars[var].m_lower; }
|
||||||
void get_upper(var_t var, scoped_eps_numeral& b) const { b = m_vars[var].m_upper; }
|
void get_upper(var_t var, scoped_eps_numeral& b) const { b = m_vars[var].m_upper; }
|
||||||
|
eps_numeral const& get_lower(var_t var) const { return m_vars[var].m_lower; }
|
||||||
|
eps_numeral const& get_upper(var_t var) const { return m_vars[var].m_upper; }
|
||||||
bool above_lower(var_t var, eps_numeral const& b) const;
|
bool above_lower(var_t var, eps_numeral const& b) const;
|
||||||
bool below_upper(var_t var, eps_numeral const& b) const;
|
bool below_upper(var_t var, eps_numeral const& b) const;
|
||||||
bool below_lower(var_t v) const;
|
bool below_lower(var_t v) const;
|
||||||
|
@ -198,6 +200,7 @@ namespace simplex {
|
||||||
bool is_feasible() const;
|
bool is_feasible() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void ensure_rational_solution(simplex<mpq_ext>& s);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -5,8 +5,6 @@ Module Name:
|
||||||
|
|
||||||
simplex_def.h
|
simplex_def.h
|
||||||
|
|
||||||
Abstract:
|
|
||||||
|
|
||||||
Author:
|
Author:
|
||||||
|
|
||||||
Nikolaj Bjorner (nbjorner) 2014-01-15
|
Nikolaj Bjorner (nbjorner) 2014-01-15
|
||||||
|
|
|
@ -414,6 +414,7 @@ private:
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DL_PROCESSED:
|
case DL_PROCESSED:
|
||||||
|
TRACE("arith", display_edge(tout << "processed twice: ", e););
|
||||||
// if two edges with the same source/target occur in the graph.
|
// if two edges with the same source/target occur in the graph.
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -514,10 +515,8 @@ public:
|
||||||
// The method assumes the graph is feasible before the invocation.
|
// The method assumes the graph is feasible before the invocation.
|
||||||
bool enable_edge(edge_id id) {
|
bool enable_edge(edge_id id) {
|
||||||
edge& e = m_edges[id];
|
edge& e = m_edges[id];
|
||||||
|
SASSERT(is_feasible());
|
||||||
bool r = true;
|
bool r = true;
|
||||||
if (!is_feasible()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!e.is_enabled()) {
|
if (!e.is_enabled()) {
|
||||||
e.enable(m_timestamp);
|
e.enable(m_timestamp);
|
||||||
m_last_enabled_edge = id;
|
m_last_enabled_edge = id;
|
||||||
|
|
|
@ -985,6 +985,8 @@ namespace smt {
|
||||||
TRACE("opt", S.display(tout); );
|
TRACE("opt", S.display(tout); );
|
||||||
SASSERT(is_sat != l_false);
|
SASSERT(is_sat != l_false);
|
||||||
lbool is_fin = S.minimize(w);
|
lbool is_fin = S.minimize(w);
|
||||||
|
|
||||||
|
ensure_rational_solution(S);
|
||||||
|
|
||||||
switch (is_fin) {
|
switch (is_fin) {
|
||||||
case l_true: {
|
case l_true: {
|
||||||
|
@ -1010,10 +1012,10 @@ namespace smt {
|
||||||
}
|
}
|
||||||
for (unsigned i = 0; i < num_nodes; ++i) {
|
for (unsigned i = 0; i < num_nodes; ++i) {
|
||||||
mpq_inf const& val = S.get_value(i);
|
mpq_inf const& val = S.get_value(i);
|
||||||
rational q(val.first), eps(val.second);
|
rational q(val.first);
|
||||||
|
SASSERT(rational(val.second).is_zero());
|
||||||
numeral a(q);
|
numeral a(q);
|
||||||
m_assignment[i] = a;
|
m_assignment[i] = a;
|
||||||
// TBD: if epsilon is != 0, then adjust a by some small fraction.
|
|
||||||
}
|
}
|
||||||
inf_eps result(rational(0), r);
|
inf_eps result(rational(0), r);
|
||||||
blocker = mk_gt(v, result);
|
blocker = mk_gt(v, result);
|
||||||
|
|
|
@ -341,7 +341,9 @@ void theory_diff_logic<Ext>::pop_scope_eh(unsigned num_scopes) {
|
||||||
m_scopes.shrink(new_lvl);
|
m_scopes.shrink(new_lvl);
|
||||||
unsigned num_edges = m_graph.get_num_edges();
|
unsigned num_edges = m_graph.get_num_edges();
|
||||||
m_graph.pop(num_scopes);
|
m_graph.pop(num_scopes);
|
||||||
if (num_edges != m_graph.get_num_edges() && m_num_simplex_edges > 0) {
|
TRACE("arith", m_graph.display(tout););
|
||||||
|
SASSERT(m_graph.is_feasible());
|
||||||
|
if (true || (num_edges != m_graph.get_num_edges() && m_num_simplex_edges > 0)) {
|
||||||
m_S.reset();
|
m_S.reset();
|
||||||
m_num_simplex_edges = 0;
|
m_num_simplex_edges = 0;
|
||||||
m_objective_rows.reset();
|
m_objective_rows.reset();
|
||||||
|
@ -565,6 +567,7 @@ bool theory_diff_logic<Ext>::propagate_atom(atom* a) {
|
||||||
}
|
}
|
||||||
int edge_id = a->get_asserted_edge();
|
int edge_id = a->get_asserted_edge();
|
||||||
if (!m_graph.enable_edge(edge_id)) {
|
if (!m_graph.enable_edge(edge_id)) {
|
||||||
|
TRACE("arith", display(tout););
|
||||||
set_neg_cycle_conflict();
|
set_neg_cycle_conflict();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -685,11 +688,8 @@ void theory_diff_logic<Ext>::set_neg_cycle_conflict() {
|
||||||
context & ctx = get_context();
|
context & ctx = get_context();
|
||||||
TRACE("arith_conflict",
|
TRACE("arith_conflict",
|
||||||
tout << "conflict: ";
|
tout << "conflict: ";
|
||||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
for (literal lit : lits) ctx.display_literal_info(tout, lit);
|
||||||
ctx.display_literal_info(tout, lits[i]);
|
tout << "\n";);
|
||||||
}
|
|
||||||
tout << "\n";
|
|
||||||
);
|
|
||||||
|
|
||||||
if (dump_lemmas()) {
|
if (dump_lemmas()) {
|
||||||
symbol logic(m_lia_or_lra == is_lia ? "QF_LIA" : "QF_LRA");
|
symbol logic(m_lia_or_lra == is_lia ? "QF_LIA" : "QF_LRA");
|
||||||
|
@ -911,6 +911,7 @@ void theory_diff_logic<Ext>::compute_delta() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
void theory_diff_logic<Ext>::init_model(smt::model_generator & m) {
|
void theory_diff_logic<Ext>::init_model(smt::model_generator & m) {
|
||||||
m_factory = alloc(arith_factory, get_manager());
|
m_factory = alloc(arith_factory, get_manager());
|
||||||
|
@ -935,9 +936,11 @@ model_value_proc * theory_diff_logic<Ext>::mk_value(enode * n, model_generator &
|
||||||
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
void theory_diff_logic<Ext>::display(std::ostream & out) const {
|
void theory_diff_logic<Ext>::display(std::ostream & out) const {
|
||||||
for (unsigned i = 0; i < m_atoms.size(); ++i) {
|
out << "atoms\n";
|
||||||
m_atoms[i]->display(*this, out);
|
for (atom* a : m_atoms) {
|
||||||
|
a->display(*this, out) << "\n";
|
||||||
}
|
}
|
||||||
|
out << "graph\n";
|
||||||
m_graph.display(out);
|
m_graph.display(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1150,6 +1153,8 @@ void theory_diff_logic<Ext>::update_simplex(Simplex& S) {
|
||||||
}
|
}
|
||||||
S.set_lower(node2simplex(get_zero(true)), mpq_inf(mpq(0), mpq(0)));
|
S.set_lower(node2simplex(get_zero(true)), mpq_inf(mpq(0), mpq(0)));
|
||||||
S.set_upper(node2simplex(get_zero(true)), mpq_inf(mpq(0), mpq(0)));
|
S.set_upper(node2simplex(get_zero(true)), mpq_inf(mpq(0), mpq(0)));
|
||||||
|
S.set_lower(node2simplex(get_zero(false)), mpq_inf(mpq(0), mpq(0)));
|
||||||
|
S.set_upper(node2simplex(get_zero(false)), mpq_inf(mpq(0), mpq(0)));
|
||||||
svector<unsigned> vars;
|
svector<unsigned> vars;
|
||||||
scoped_mpq_vector coeffs(mgr);
|
scoped_mpq_vector coeffs(mgr);
|
||||||
coeffs.push_back(mpq(1));
|
coeffs.push_back(mpq(1));
|
||||||
|
@ -1215,6 +1220,8 @@ typename theory_diff_logic<Ext>::inf_eps theory_diff_logic<Ext>::value(theory_va
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
typename theory_diff_logic<Ext>::inf_eps
|
typename theory_diff_logic<Ext>::inf_eps
|
||||||
theory_diff_logic<Ext>::maximize(theory_var v, expr_ref& blocker, bool& has_shared) {
|
theory_diff_logic<Ext>::maximize(theory_var v, expr_ref& blocker, bool& has_shared) {
|
||||||
|
@ -1224,6 +1231,9 @@ theory_diff_logic<Ext>::maximize(theory_var v, expr_ref& blocker, bool& has_shar
|
||||||
Simplex& S = m_S;
|
Simplex& S = m_S;
|
||||||
ast_manager& m = get_manager();
|
ast_manager& m = get_manager();
|
||||||
|
|
||||||
|
CTRACE("arith",!m_graph.is_feasible(), m_graph.display(tout););
|
||||||
|
SASSERT(m_graph.is_feasible());
|
||||||
|
|
||||||
update_simplex(S);
|
update_simplex(S);
|
||||||
|
|
||||||
TRACE("arith",
|
TRACE("arith",
|
||||||
|
@ -1235,7 +1245,12 @@ theory_diff_logic<Ext>::maximize(theory_var v, expr_ref& blocker, bool& has_shar
|
||||||
tout << "Free coefficient " << m_objective_consts[v] << "\n";
|
tout << "Free coefficient " << m_objective_consts[v] << "\n";
|
||||||
);
|
);
|
||||||
|
|
||||||
TRACE("opt", S.display(tout); display(tout););
|
TRACE("opt",
|
||||||
|
S.display(tout);
|
||||||
|
for (unsigned i = 0; i < m_graph.get_num_nodes(); ++i)
|
||||||
|
tout << "$" << i << ": " << node2simplex(i) << "\n";
|
||||||
|
display(tout);
|
||||||
|
);
|
||||||
|
|
||||||
// optimize
|
// optimize
|
||||||
lbool is_sat = S.make_feasible();
|
lbool is_sat = S.make_feasible();
|
||||||
|
@ -1252,8 +1267,6 @@ theory_diff_logic<Ext>::maximize(theory_var v, expr_ref& blocker, bool& has_shar
|
||||||
simplex::mpq_ext::eps_numeral const& val = S.get_value(w);
|
simplex::mpq_ext::eps_numeral const& val = S.get_value(w);
|
||||||
inf_rational r(-rational(val.first), -rational(val.second));
|
inf_rational r(-rational(val.first), -rational(val.second));
|
||||||
Simplex::row row = m_objective_rows[v];
|
Simplex::row row = m_objective_rows[v];
|
||||||
TRACE("opt", tout << r << " " << "\n";
|
|
||||||
S.display_row(tout, row, true););
|
|
||||||
Simplex::row_iterator it = S.row_begin(row), end = S.row_end(row);
|
Simplex::row_iterator it = S.row_begin(row), end = S.row_end(row);
|
||||||
expr_ref_vector& core = m_objective_assignments[v];
|
expr_ref_vector& core = m_objective_assignments[v];
|
||||||
expr_ref tmp(m);
|
expr_ref tmp(m);
|
||||||
|
@ -1269,13 +1282,21 @@ theory_diff_logic<Ext>::maximize(theory_var v, expr_ref& blocker, bool& has_shar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compute_delta();
|
ensure_rational_solution(S);
|
||||||
|
TRACE("opt", tout << r << " " << "\n";
|
||||||
|
S.display_row(tout, row, true);
|
||||||
|
S.display(tout);
|
||||||
|
);
|
||||||
|
|
||||||
for (unsigned i = 0; i < m_graph.get_num_nodes(); ++i) {
|
for (unsigned i = 0; i < m_graph.get_num_nodes(); ++i) {
|
||||||
unsigned w = node2simplex(i);
|
unsigned w = node2simplex(i);
|
||||||
simplex::mpq_ext::eps_numeral const& val = S.get_value(w);
|
auto const& val = S.get_value(w);
|
||||||
rational r = rational(val.first) + m_delta*rational(val.second);
|
SASSERT(rational(val.second).is_zero());
|
||||||
|
rational r = rational(val.first);
|
||||||
m_graph.set_assignment(i, numeral(r));
|
m_graph.set_assignment(i, numeral(r));
|
||||||
}
|
}
|
||||||
|
CTRACE("arith",!m_graph.is_feasible(), m_graph.display(tout););
|
||||||
|
SASSERT(m_graph.is_feasible());
|
||||||
inf_eps r1(rational(0), r);
|
inf_eps r1(rational(0), r);
|
||||||
blocker = mk_gt(v, r1);
|
blocker = mk_gt(v, r1);
|
||||||
return inf_eps(rational(0), r + m_objective_consts[v]);
|
return inf_eps(rational(0), r + m_objective_consts[v]);
|
||||||
|
|
|
@ -286,4 +286,8 @@ typedef mpq_inf_manager<false> synch_mpq_inf_manager;
|
||||||
#endif
|
#endif
|
||||||
typedef mpq_inf_manager<false> unsynch_mpq_inf_manager;
|
typedef mpq_inf_manager<false> unsynch_mpq_inf_manager;
|
||||||
|
|
||||||
|
typedef _scoped_numeral<unsynch_mpq_inf_manager> scoped_mpq_inf;
|
||||||
|
typedef _scoped_numeral<synch_mpq_inf_manager> scoped_synch_mpq_inf;
|
||||||
|
typedef _scoped_numeral_vector<unsynch_mpq_inf_manager> scoped_mpq_inf_vector;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue