3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-27 19:05:51 +00:00
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2021-08-13 23:18:52 -07:00
parent 60dbfed69e
commit 6ac7c2b942
3 changed files with 105 additions and 122 deletions

View file

@ -64,8 +64,6 @@ namespace polysat {
var_t v = UINT_MAX;
var_t w = UINT_MAX;
bool strict = false;
bool is_active = true;
bool is_touched = false;
u_dependency* dep = nullptr;
ineq(var_t v, var_t w, u_dependency* dep, bool s) :
v(v), w(w), strict(s), dep(dep) {}
@ -174,13 +172,14 @@ namespace polysat {
mutable matrix M;
unsigned m_max_iterations = UINT_MAX;
unsigned m_num_non_integral = 0;
uint_set m_non_integral;
var_heap m_to_patch;
vector<var_info> m_vars;
vector<row_info> m_rows;
vector<var_eq> m_var_eqs;
bool m_bland = false ;
unsigned m_blands_rule_threshold = 1000;
var_t m_last_pivot_var = null_var;
unsigned m_num_repeated = 0;
random_gen m_random;
uint_set m_left_basis;
unsigned_vector m_unsat_core;
@ -195,10 +194,9 @@ namespace polysat {
// inequalities
svector<ineq> m_ineqs;
unsigned_vector m_ineqs_to_check;
bool_vector m_var_is_touched;
uint_set m_ineqs_to_propagate;
uint_set m_touched_vars;
vector<unsigned_vector> m_var2ineqs;
svector<var_t> m_vars_to_untouch;
public:
fixplex(params_ref const& p, reslimit& lim):
@ -239,7 +237,6 @@ namespace polysat {
void set_max_iterations(unsigned n) { m_max_iterations = n; }
unsigned get_num_vars() const { return m_vars.size(); }
void reset();
lbool propagate_bounds();
svector<std::pair<unsigned, ineq>> stack;
uint_set on_stack;
@ -260,6 +257,10 @@ namespace polysat {
void update_value_core(var_t v, numeral const& delta);
void ensure_var(var_t v);
bool patch();
bool propagate();
bool is_satisfied();
var_t select_smallest_var() { return m_to_patch.empty()?null_var:m_to_patch.erase_min(); }
lbool make_var_feasible(var_t x_i);
bool is_infeasible_row(var_t x);
@ -306,7 +307,7 @@ namespace polysat {
int get_num_non_free_dep_vars(var_t x_j, int best_so_far);
void add_patch(var_t v);
var_t select_var_to_fix();
void check_blands_rule(var_t v, unsigned& num_repeated);
void check_blands_rule(var_t v);
pivot_strategy_t pivot_strategy() { return m_bland ? S_BLAND : S_DEFAULT; }
var_t select_error_var(bool least);
void set_infeasible_base(var_t v);
@ -317,9 +318,7 @@ namespace polysat {
// facilities for handling inequalities
void add_ineq(var_t v, var_t w, unsigned dep, bool strict);
void touch_var(var_t x);
bool ineqs_are_violated();
bool ineqs_are_satisfied();
void reset_ineqs_to_check();
bool is_solved(row const& r) const;
bool is_solved(var_t v) const { SASSERT(is_base(v)); return is_solved(base2row(v)); }

View file

@ -99,19 +99,19 @@ namespace polysat {
m_deps.pop_scope(n);
while (n > 0) {
switch (m_trail.back()) {
case trail_i::inc_level_i:
case trail_i::inc_level_i:
--n;
break;
case trail_i::set_bound_i:
case trail_i::set_bound_i:
restore_bound();
break;
case trail_i::add_row_i:
break;
case trail_i::add_row_i:
del_row(m_row_trail.back());
m_row_trail.pop_back();
break;
case trail_i::add_ineq_i:
break;
case trail_i::add_ineq_i:
restore_ineq();
break;
break;
case trail_i::set_inconsistent_i:
SASSERT(m_inconsistent);
m_inconsistent = false;
@ -147,45 +147,48 @@ namespace polysat {
template<typename Ext>
lbool fixplex<Ext>::make_feasible() {
if (m_inconsistent)
return l_false;
++m_stats.m_num_checks;
m_left_basis.reset();
m_last_pivot_var = null_var;
unsigned num_iterations = 0;
unsigned num_repeated = 0;
var_t v = null_var;
m_num_repeated = 0;
m_bland = false;
unsigned num_iterations = 0;
SASSERT(well_formed());
while ((v = select_var_to_fix()) != null_var) {
TRACE("polysat", display(tout << "v" << v << "\n"););
if (!m_limit.inc() || num_iterations > m_max_iterations)
return l_undef;
check_blands_rule(v, num_repeated);
switch (make_var_feasible(v)) {
case l_true:
++num_iterations;
break;
case l_false:
m_to_patch.insert(v);
set_infeasible_base(v);
++m_stats.m_num_infeasible;
while (m_limit.inc() && num_iterations < m_max_iterations) {
if (inconsistent())
return l_false;
case l_undef:
m_to_patch.insert(v);
if (ineqs_are_violated())
return l_false;
if (!propagate())
return l_false;
if (is_satisfied())
return l_true;
if (!patch())
return l_undef;
}
++num_iterations;
SASSERT(well_formed());
}
SASSERT(well_formed());
if (ineqs_are_violated())
return l_false;
if (ineqs_are_satisfied() && m_num_non_integral == 0)
return l_true;
return l_undef;
}
template<typename Ext>
bool fixplex<Ext>::patch() {
var_t v = select_var_to_fix();
if (v == null_var)
return false;
check_blands_rule(v);
switch (make_var_feasible(v)) {
case l_true:
return true;
case l_false:
m_to_patch.insert(v);
set_infeasible_base(v);
return true;
case l_undef:
m_to_patch.insert(v);
return false;
}
UNREACHABLE();
return true;
}
template<typename Ext>
void fixplex<Ext>::add_row(var_t base_var, unsigned num_vars, var_t const* vars, rational const* coeffs) {
vector<numeral> _coeffs;
@ -277,6 +280,7 @@ namespace polysat {
m_vars[var].m_is_base = false;
m_vars[var].set_free();
m_rows[r.id()].m_base = null_var;
m_non_integral.remove(r.id());
M.del(r);
SASSERT(M.col_begin(var) == M.col_end(var));
SASSERT(well_formed());
@ -414,8 +418,6 @@ namespace polysat {
numeral const& b = r.coeff();
if (x == y)
continue;
if (y == m_last_pivot_var)
continue;
if (!has_minimal_trailing_zeros(y, b))
continue;
numeral new_y_value = solve_for(row_value - b * value(y), b);
@ -478,7 +480,7 @@ namespace polysat {
row r = base2row(x);
for (auto const& c : M.col_entries(r)) {
var_t y = c.var();
if (x == y || y >= result || y == m_last_pivot_var)
if (x == y || y >= result)
continue;
numeral const& b = c.coeff();
if (can_improve(y, b)) {
@ -615,7 +617,8 @@ namespace polysat {
m_var2ineqs.reserve(std::max(v, w) + 1);
m_var2ineqs[v].push_back(idx);
m_var2ineqs[w].push_back(idx);
m_ineqs_to_check.push_back(idx);
touch_var(v);
m_ineqs_to_propagate.insert(idx);
m_trail.push_back(trail_i::add_ineq_i);
m_ineqs.push_back(ineq(v, w, mk_leaf(dep), strict));
}
@ -630,49 +633,32 @@ namespace polysat {
template<typename Ext>
void fixplex<Ext>::touch_var(var_t v) {
if (v >= m_var2ineqs.size())
return;
if (m_var_is_touched.get(v, false))
return;
m_var_is_touched.setx(v, true, false);
for (auto idx : m_var2ineqs[v]) {
if (!m_ineqs[idx].is_active) {
m_ineqs[idx].is_active = true;
m_ineqs_to_check.push_back(idx);
}
}
}
template<typename Ext>
void fixplex<Ext>::reset_ineqs_to_check() {
for (auto idx : m_ineqs_to_check) {
if (idx >= m_ineqs.size())
continue;
auto& ineq = m_ineqs[idx];
m_var_is_touched.setx(ineq.v, false, false);
m_var_is_touched.setx(ineq.w, false, false);
ineq.is_active = false;
}
m_ineqs_to_check.reset();
m_touched_vars.insert(v);
}
/**
* Check if the current assignment satisfies the inequalities
*/
template<typename Ext>
bool fixplex<Ext>::ineqs_are_satisfied() {
for (auto idx : m_ineqs_to_check) {
if (idx >= m_ineqs.size())
continue;
auto& ineq = m_ineqs[idx];
var_t v = ineq.v;
var_t w = ineq.w;
if (ineq.strict && value(v) >= value(w))
return false;
if (!ineq.strict && value(v) > value(w))
return false;
bool fixplex<Ext>::is_satisfied() {
if (!m_to_patch.empty())
return false;
if (!m_non_integral.empty())
return false;
for (auto var : m_touched_vars) {
for (auto idx : m_var2ineqs[var]) {
if (idx >= m_ineqs.size())
continue;
auto& ineq = m_ineqs[idx];
var_t v = ineq.v;
var_t w = ineq.w;
if (ineq.strict && value(v) >= value(w))
return false;
if (!ineq.strict && value(v) > value(w))
return false;
}
}
reset_ineqs_to_check();
m_touched_vars.reset();
return true;
}
@ -680,16 +666,16 @@ namespace polysat {
* Propagate bounds and check if the current inequalities are satisfied
*/
template<typename Ext>
bool fixplex<Ext>::ineqs_are_violated() {
bool fixplex<Ext>::propagate() {
lbool r;
for (unsigned i = 0; i < m_ineqs_to_check.size(); ++i) {
unsigned idx = m_ineqs_to_check[i];
for (unsigned idx : m_ineqs_to_propagate) {
if (idx >= m_ineqs.size())
continue;
if (r = propagate_ineqs(m_ineqs[idx]), r == l_false)
return true;
return false;
}
return false;
m_ineqs_to_propagate.reset();
return true;
}
/**
@ -799,7 +785,7 @@ namespace polysat {
z = base(r)
d = base_coeff(r)
b1 = (b >> tz(b))
c1 = (c >> (tz(c) - tz(b)))
c1 = (c >> tz(b))
r <- b1 * r - c1 * r_x
value(r) := b1 * value(r) - b1 * old_value(y) - c1 * value(r_x)
value(z) := - value(r) / d
@ -808,7 +794,6 @@ namespace polysat {
template<typename Ext>
void fixplex<Ext>::pivot(var_t x, var_t y, numeral const& b, numeral const& new_value) {
++m_stats.m_num_pivots;
m_last_pivot_var = x;
SASSERT(is_base(x));
SASSERT(!is_base(y));
var_info& xI = m_vars[x];
@ -909,7 +894,7 @@ namespace polysat {
m_inconsistent = true;
m_trail.push_back(trail_i::set_inconsistent_i);
m_deps.linearize(todo, m_unsat_core);
++m_stats.m_num_infeasible;
}
/**
@ -975,15 +960,15 @@ namespace polysat {
}
template<typename Ext>
void fixplex<Ext>::check_blands_rule(var_t v, unsigned& num_repeated) {
void fixplex<Ext>::check_blands_rule(var_t v) {
if (m_bland)
return;
if (!m_left_basis.contains(v))
m_left_basis.insert(v);
else {
++num_repeated;
m_bland = num_repeated > m_blands_rule_threshold;
CTRACE("polysat", m_bland, tout << "using blands rule, " << num_repeated << "\n";);
++m_num_repeated;
m_bland = m_num_repeated > m_blands_rule_threshold;
CTRACE("polysat", m_bland, tout << "using blands rule, " << m_num_repeated << "\n";);
}
}
@ -1038,12 +1023,11 @@ namespace polysat {
row r = base2row(x);
m_vars[x].m_value = solve_for(row2value(r), row2base_coeff(r));
touch_var(x);
bool was_integral = row_is_integral(r);
m_rows[r.id()].m_integral = is_solved(r);
if (was_integral && !row_is_integral(r))
++m_num_non_integral;
else if (!was_integral && row_is_integral(r))
--m_num_non_integral;
if (row_is_integral(r))
m_non_integral.remove(r.id());
else
m_non_integral.insert(r.id());
}
/**
@ -1152,6 +1136,7 @@ namespace polysat {
m_var_eqs.push_back(var_eq(x, y, r1, r2));
}
#if 0
template<typename Ext>
lbool fixplex<Ext>::propagate_bounds() {
lbool r = l_true;
@ -1163,6 +1148,7 @@ namespace polysat {
return r;
return l_true;
}
#endif
//
// DFS search propagating inequalities
@ -1185,12 +1171,9 @@ namespace polysat {
// std::cout << "propagate " << i0 << "\n";
if (!propagate_ineq(i0))
return l_false;
if (old_lo == m_vars[i0.w].lo && i0.is_touched)
return l_true;
on_stack.reset();
stack.reset();
stack.push_back(std::make_pair(0, i0));
i0.is_touched = true;
on_stack.insert(i0.v);
while (!stack.empty()) {
if (!m_limit.inc())
@ -1209,8 +1192,7 @@ namespace polysat {
return l_false;
bool is_onstack = on_stack.contains(i_out.w);
if ((old_lo != m_vars[i_out.w].lo || !i_out.is_touched) && !is_onstack) {
i_out.is_touched = true;
if ((old_lo != m_vars[i_out.w].lo) && !is_onstack) {
on_stack.insert(i_out.w);
stack.back().first = ineq_out + 1;
stack.push_back(std::make_pair(0, i_out));
@ -1528,6 +1510,7 @@ namespace polysat {
m_deps.linearize(a, m_unsat_core);
SASSERT(!m_inconsistent);
m_inconsistent = true;
++m_stats.m_num_infeasible;
m_trail.push_back(trail_i::set_inconsistent_i);
TRACE("polysat", tout << "core: " << m_unsat_core << "\n";);
}
@ -1657,7 +1640,7 @@ return d;
st.update("fixplex num pivots", m_stats.m_num_pivots);
st.update("fixplex num infeasible", m_stats.m_num_infeasible);
st.update("fixplex num checks", m_stats.m_num_checks);
st.update("fixplex num non-integral", m_num_non_integral);
st.update("fixplex num non-integral", m_non_integral.num_elems());
st.update("fixplex num approximated row additions", m_stats.m_num_approx);
}
}

View file

@ -71,21 +71,18 @@ namespace polysat {
fp.set_bounds(x, 3, 4, 1);
fp.set_bounds(y, 3, 6, 2);
fp.run();
fp.propagate_bounds();
fp.reset();
coeffs[2] = 0ull - 1;
fp.add_row(x, 3, ys, coeffs);
fp.set_bounds(x, 3, 4, 1);
fp.set_bounds(y, 3, 6, 2);
fp.run();
fp.propagate_bounds();
fp.reset();
fp.add_row(x, 3, ys, coeffs);
fp.set_bounds(x, 3, 4, 1);
fp.set_bounds(y, 3, 6, 2);
fp.set_bounds(z, 1, 8, 3);
fp.run();
fp.propagate_bounds();
fp.reset();
}
@ -372,31 +369,35 @@ namespace polysat {
}
static void save_scenario(
unsigned id,
vector<svector<std::pair<unsigned, uint64_t>>> const& rows,
svector<ineq> const& ineqs,
vector<mod_interval<uint64_t>> const& bounds) {
std::cout << "static void scenario() {";
std::cout << " vector<svector<std::pair<unsigned, uint64_t>>> rows\n;";
std::cout << " svector<ineq> ineqs\n;";
std::cout << " vector<mod_interval<uint64_t>> bounds\n";
for (auto row : rows) {
std::cout << "static void scenario" << id << "() {\n";
std::cout << " vector<svector<std::pair<unsigned, uint64_t>>> rows;\n";
std::cout << " svector<ineq> ineqs;\n";
std::cout << " vector<mod_interval<uint64_t>> bounds;\n";
for (auto const& row : rows) {
std::cout << " rows.push_back(svector<std::pair<unsigned, uint64_t>>());\n";
for (auto col : row)
std::cout << " rows.back().push_back(std::make_pair(" << col.first << ", " << col.second << ");\n";
}
for (auto ineq : ineqs)
std::cout << " ineqs.push_back(ineq(" << ineq.v << ", " << ineq.w << " " << ineq.strict << ");\n";
for (auto bound : bounds)
for (auto const& ineq : ineqs)
std::cout << " ineqs.push_back(ineq(" << ineq.v << ", " << ineq.w << ", 0, " << (ineq.strict?"true":"false") << ");\n";
for (auto const& bound : bounds)
std::cout << " bounds.push_back(mod_interval<uint64_t>(" << bound.lo << ", " << bound.hi << ");\n";
std::cout << " test_lp(rows, ineqs, bounds);\n}\n";
std::cout << " test_lp(rows, ineqs, bounds); \n }\n";
}
static unsigned num_test = 0;
static void test_lp(
vector<svector<std::pair<unsigned, uint64_t>>> const& rows,
svector<ineq> const& ineqs,
vector<mod_interval<uint64_t>> const& bounds) {
// save_scenario(++num_test, rows, ineqs, bounds);
unsigned num_vars = 0;
for (auto const& row : rows)
for (auto [v, c] : row)