3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-10-03 22:43:56 +00:00

fix mixed integer/real bugs for maximization exposed by non-termination in slow.smt. partially fixes issue #56

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2015-06-23 12:05:19 +02:00
parent d32e4a9476
commit d9522cfd07
5 changed files with 130 additions and 175 deletions

View file

@ -989,83 +989,6 @@ namespace smt {
}
/**
\brief Select tightest variable x_i to pivot with x_j. The goal
is to select a x_i such that the value of x_j is increased
(decreased) if inc = true (inc = false), and the tableau
remains feasible. Store the gain in x_j of the pivoting
operation in 'gain'. Note the gain can be too much. That is,
it may make x_i infeasible. In this case, instead of pivoting
we move x_j to its upper bound (lower bound) when inc = true (inc = false).
If no x_i imposes a restriction on x_j, then return null_theory_var.
That is, x_j is free to move to its upper bound (lower bound).
Get the equations for x_j:
x_i1 = coeff_1 * x_j + rest_1
...
x_in = coeff_n * x_j + rest_n
gain_k := (upper_bound(x_ik) - value(x_ik))/coeff_k
*/
template<typename Ext>
theory_var theory_arith<Ext>::pick_var_to_leave(
bool has_int, theory_var x_j, bool inc,
numeral & a_ij, inf_numeral & gain, bool& skipped_row) {
TRACE("opt", tout << "selecting variable to replace v" << x_j << ", inc: " << inc << "\n";);
theory_var x_i = null_theory_var;
inf_numeral curr_gain;
column & c = m_columns[x_j];
typename svector<col_entry>::iterator it = c.begin_entries();
typename svector<col_entry>::iterator end = c.end_entries();
for (; it != end; ++it) {
if (!it->is_dead()) {
row & r = m_rows[it->m_row_id];
theory_var s = r.get_base_var();
if (s != null_theory_var && !is_quasi_base(s)) {
numeral const & coeff = r[it->m_row_idx].m_coeff;
bool inc_s = coeff.is_neg() ? inc : !inc;
bound * b = get_bound(s, inc_s);
if (b) {
curr_gain = get_value(s);
curr_gain -= b->get_value();
curr_gain /= coeff;
if (curr_gain.is_neg())
curr_gain.neg();
if (x_i == null_theory_var || (curr_gain < gain) || (gain.is_zero() && curr_gain.is_zero() && s < x_i)) {
if (is_int(s) && !curr_gain.is_int()) {
skipped_row = true;
continue;
}
if (is_int(x_j) && !curr_gain.is_int()) {
skipped_row = true;
continue;
}
if (!curr_gain.is_int() && has_int) {
skipped_row = true;
continue;
}
x_i = s;
a_ij = coeff;
gain = curr_gain;
TRACE("opt",
tout << "x_i: v" << x_i << ", gain: " << gain << "\n";
tout << "value(s): (" << get_value(s) << " - " << b->get_value() << ")/" << coeff << "\n";
display_row(tout, r, true);
);
}
}
}
TRACE("opt", tout << "x_i: v" << x_i << ", gain: " << gain << "\n";);
}
}
TRACE("opt", tout << "x_i v" << x_i << "\n";);
return x_i;
}
template<typename Ext>
bool theory_arith<Ext>::get_theory_vars(expr * n, uint_set & vars) {
rational r;
@ -1388,6 +1311,9 @@ namespace smt {
bool& has_shared, // determine if pivot involves shared variable
theory_var& x_i) { // base variable to pivot with x_j
if (is_int(x_j) && !get_value(x_j).is_int()) {
return false;
}
x_i = null_theory_var;
context& ctx = get_context();
column & c = m_columns[x_j];
@ -1447,8 +1373,7 @@ namespace smt {
template<typename Ext>
void theory_arith<Ext>::normalize_gain(numeral const& divisor, inf_numeral & max_gain) const {
SASSERT(divisor.is_int());
SASSERT(divisor.is_pos());
if (!divisor.is_one() && !max_gain.is_minus_one()) {
if (!divisor.is_minus_one() && !divisor.is_one() && !max_gain.is_minus_one()) {
max_gain = floor(max_gain/divisor)*divisor;
}
}
@ -1473,14 +1398,15 @@ namespace smt {
if (is_int(x)) {
min_gain = inf_numeral::one();
}
TRACE("opt",
tout << "v" << x << " := " << get_value(x) << " "
<< "min gain: " << min_gain << " "
<< "max gain: " << max_gain << "\n";);
SASSERT(max_gain.is_minus_one() || !max_gain.is_neg());
SASSERT(min_gain.is_minus_one() || min_gain.is_one());
SASSERT(!is_int(x) || max_gain.is_int());
SASSERT(is_int(x) == min_gain.is_one());
TRACE("opt",
tout << "v" << x << " "
<< "min gain: " << min_gain << " "
<< "max gain: " << max_gain << "\n";);
}
@ -1512,14 +1438,18 @@ namespace smt {
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());
if (is_int(x_i) && !den_aij.is_one() && 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)) {
TRACE("opt",
tout << "v" << x_i << " a_ij " << a_ij << " "
<< "min gain: " << min_gain << " "
<< "max gain: " << max_gain << "\n";);
max_inc = floor(max_inc);
normalize_gain(min_gain.get_rational(), max_inc);
}
@ -1539,9 +1469,9 @@ namespace smt {
<< (is_tighter?"true":"false") << "\n";);
SASSERT(max_gain.is_minus_one() || !max_gain.is_neg());
SASSERT(min_gain.is_minus_one() || !min_gain.is_neg());
SASSERT(!is_int(x_i) || min_gain.is_pos());
SASSERT(!is_int(x_i) || min_gain.is_int());
SASSERT(!is_int(x_i) || max_gain.is_int());
//SASSERT(!is_int(x_i) || min_gain.is_pos());
//SASSERT(!is_int(x_i) || min_gain.is_int());
//SASSERT(!is_int(x_i) || max_gain.is_int());
return is_tighter;
}
@ -1759,6 +1689,10 @@ namespace smt {
unsigned& best_efforts, // is bound move a best effort?
bool& has_shared) { // does move include shared variables?
inf_numeral min_gain, max_gain;
if (is_int(x_i) && !get_value(x_i).is_int()) {
++best_efforts;
return false;
}
init_gains(x_i, inc, min_gain, max_gain);
column & c = m_columns[x_i];
typename svector<col_entry>::iterator it = c.begin_entries();