3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-07 11:41:22 +00:00
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2021-08-12 17:08:59 -07:00
parent 39e98b3835
commit cdbd121b5e
3 changed files with 68 additions and 35 deletions

View file

@ -237,7 +237,7 @@ namespace polysat {
svector<std::pair<unsigned, ineq>> stack; svector<std::pair<unsigned, ineq>> stack;
uint_set on_stack; uint_set on_stack;
lbool propagate_ineqs(ineq const& i0); lbool propagate_ineqs(ineq& i0);
void propagate_eqs(); void propagate_eqs();
vector<var_eq> const& var_eqs() const { return m_var_eqs; } vector<var_eq> const& var_eqs() const { return m_var_eqs; }
void reset_eqs() { m_var_eqs.reset(); } void reset_eqs() { m_var_eqs.reset(); }
@ -248,7 +248,7 @@ namespace polysat {
private: private:
std::ostream& display_row(std::ostream& out, row const& r, bool values = true); std::ostream& display_row(std::ostream& out, row const& r, bool values = true) const;
var_t get_base_var(row const& r) const { return m_rows[r.id()].m_base; } var_t get_base_var(row const& r) const { return m_rows[r.id()].m_base; }
void update_value_core(var_t v, numeral const& delta); void update_value_core(var_t v, numeral const& delta);

View file

@ -57,6 +57,16 @@ Inequality handling.
- cuts: - cuts:
would be good to understand how to adapt a notion of cuts for modular case. would be good to understand how to adapt a notion of cuts for modular case.
TODOs:
- complete inequality propagation using incremental topological sort + patching using assignment to minimal values
- equality extraction
- bounds + row propagaiton
- freedom interval patching
- cuts
- branch
- update synthesis of bounds tightnening
--*/ --*/
#pragma once #pragma once
@ -162,9 +172,10 @@ namespace polysat {
} }
} }
SASSERT(well_formed()); SASSERT(well_formed());
std::cout << "non-integral: " << m_num_non_integral << "\n";
if (ineqs_are_violated()) if (ineqs_are_violated())
return l_false; return l_false;
if (ineqs_are_satisfied()) if (ineqs_are_satisfied() && m_num_non_integral == 0)
return l_true; return l_true;
return l_undef; return l_undef;
} }
@ -316,7 +327,6 @@ namespace polysat {
m_vars[v].m_value += delta; m_vars[v].m_value += delta;
touch_var(v); touch_var(v);
SASSERT(!is_base(v)); SASSERT(!is_base(v));
// //
// v <- v + delta // v <- v + delta
// s*s_coeff + R = 0, where R contains v*v_coeff // s*s_coeff + R = 0, where R contains v*v_coeff
@ -499,12 +509,11 @@ namespace polysat {
*/ */
template<typename Ext> template<typename Ext>
typename fixplex<Ext>::numeral typename fixplex<Ext>::numeral
fixplex<Ext>::value2delta(var_t v, numeral const& value) const { fixplex<Ext>::value2delta(var_t v, numeral const& val) const {
if (lo(v) - val < val - hi(v))
if (lo(v) - value < value - hi(v)) return lo(v) - val;
return lo(v) - value;
else else
return hi(v) - value - 1; return hi(v) - val - 1;
} }
template<typename Ext> template<typename Ext>
@ -556,9 +565,9 @@ namespace polysat {
SASSERT(lo(v) != hi(v)); SASSERT(lo(v) != hi(v));
if (is_base(v)) if (is_base(v))
add_patch(v); add_patch(v);
else else
update_value(v, value2delta(v, value(v))); update_value(v, value2delta(v, value(v)));
SASSERT(in_bounds(v)); SASSERT(is_base(v) || in_bounds(v));
} }
template<typename Ext> template<typename Ext>
@ -604,7 +613,7 @@ namespace polysat {
template<typename Ext> template<typename Ext>
void fixplex<Ext>::restore_ineq() { void fixplex<Ext>::restore_ineq() {
auto ineq = m_ineqs.back(); auto const& ineq = m_ineqs.back();
m_var2ineqs[ineq.v].pop_back(); m_var2ineqs[ineq.v].pop_back();
m_var2ineqs[ineq.w].pop_back(); m_var2ineqs[ineq.w].pop_back();
m_ineqs.pop_back(); m_ineqs.pop_back();
@ -791,6 +800,8 @@ namespace polysat {
template<typename Ext> template<typename Ext>
void fixplex<Ext>::pivot(var_t x, var_t y, numeral const& b, numeral const& new_value) { void fixplex<Ext>::pivot(var_t x, var_t y, numeral const& b, numeral const& new_value) {
++m_stats.m_num_pivots; ++m_stats.m_num_pivots;
TRACE("fixplex", tout << "pivot " << x << " " << y << "\n";);
SASSERT(is_base(x)); SASSERT(is_base(x));
SASSERT(!is_base(y)); SASSERT(!is_base(y));
var_info& xI = m_vars[x]; var_info& xI = m_vars[x];
@ -819,8 +830,10 @@ namespace polysat {
unsigned rz = r_z.id(); unsigned rz = r_z.id();
if (rz == rx) if (rz == rx)
continue; continue;
TRACE("fixplex,", display_row(tout << "eliminate ", r_z, false) << "\n";);
numeral c = col.get_row_entry().coeff(); numeral c = col.get_row_entry().coeff();
VERIFY(eliminate_var(r_x, r_z, c, tz_b, old_value_y)); VERIFY(eliminate_var(r_x, r_z, c, tz_b, old_value_y));
TRACE("fixplex,", display_row(tout << "eliminated ", r_z, false) << "\n";);
add_patch(row2base(r_z)); add_patch(row2base(r_z));
} }
SASSERT(well_formed()); SASSERT(well_formed());
@ -850,12 +863,13 @@ namespace polysat {
numeral b1, c1; numeral b1, c1;
if (tz_b <= tz_c) { if (tz_b <= tz_c) {
b1 = b >> tz_b; b1 = b >> tz_b;
c1 = 0 - (c >> (tz_c - tz_b)); c1 = 0 - (c >> tz_b);
} }
else { else {
b1 = b >> (tz_b - tz_c); b1 = b >> tz_c;
c1 = 0 - (c >> tz_c); c1 = 0 - (c >> tz_c);
} }
M.mul(r_z, b1); M.mul(r_z, b1);
M.add(r_z, c1, r_y); M.add(r_z, c1, r_y);
row_z.m_value = (b1 * (row2value(r_z) - c * old_value_y)) + c1 * row2value(r_y); row_z.m_value = (b1 * (row2value(r_z) - c * old_value_y)) + c1 * row2value(r_y);
@ -1149,9 +1163,9 @@ namespace polysat {
// //
// DFS search propagating inequalities // DFS search propagating inequalities
// TBDs: // TBDs:
// - manage on_stack: which variables? (not source of root inequality) // - replace by incremental topological sort (util/topsort.h uses stack and is non-incremental).
// - propagate other direction? // Then patch solutions following a pre-order processing
// - re-propagate if lower bound for w gets increased in stack? // value(v) := max({ value(w) | w <= v } u { value(w) + 1 | w < v } u { lo(v) }) unsat if out of bounds.
// - combine with row propagation? // - combine with row propagation?
// - search for shorter cycles? conflicts with literals asserted at lower (glue) levels? // - search for shorter cycles? conflicts with literals asserted at lower (glue) levels?
// - statistics // - statistics
@ -1161,7 +1175,7 @@ namespace polysat {
// //
template<typename Ext> template<typename Ext>
lbool fixplex<Ext>::propagate_ineqs(ineq const& i0) { lbool fixplex<Ext>::propagate_ineqs(ineq& i0) {
numeral old_lo = m_vars[i0.w].lo; numeral old_lo = m_vars[i0.w].lo;
SASSERT(!m_inconsistent); SASSERT(!m_inconsistent);
// std::cout << "propagate " << i0 << "\n"; // std::cout << "propagate " << i0 << "\n";
@ -1172,6 +1186,7 @@ namespace polysat {
on_stack.reset(); on_stack.reset();
stack.reset(); stack.reset();
stack.push_back(std::make_pair(0, i0)); stack.push_back(std::make_pair(0, i0));
i0.is_touched = true;
on_stack.insert(i0.v); on_stack.insert(i0.v);
while (!stack.empty()) { while (!stack.empty()) {
if (!m_limit.inc()) if (!m_limit.inc())
@ -1521,14 +1536,14 @@ namespace polysat {
d = m_deps.mk_join(m_vars[v].m_lo_dep, d); d = m_deps.mk_join(m_vars[v].m_lo_dep, d);
d = m_deps.mk_join(m_vars[v].m_hi_dep, d); d = m_deps.mk_join(m_vars[v].m_hi_dep, d);
} }
return d; return d;
} }
template<typename Ext> template<typename Ext>
bool fixplex<Ext>::new_bound(ineq const& i, var_t x, numeral const& l, numeral const& h, u_dependency* a, u_dependency* b, u_dependency* c, u_dependency* d) { bool fixplex<Ext>::new_bound(ineq const& i, var_t x, numeral const& l, numeral const& h, u_dependency* a, u_dependency* b, u_dependency* c, u_dependency* d) {
bool was_fixed = lo(x) + 1 == hi(x); bool was_fixed = lo(x) + 1 == hi(x);
SASSERT(!inconsistent()); SASSERT(!inconsistent());
u_dependency* dep = m_deps.mk_join(i.dep, m_deps.mk_join(a, m_deps.mk_join(b, m_deps.mk_join(c, d)))); u_dependency* dep = m_deps.mk_join(i.dep, m_deps.mk_join(a, m_deps.mk_join(b, m_deps.mk_join(c, d))));
update_bounds(x, l, h, dep); update_bounds(x, l, h, dep);
if (inconsistent()) if (inconsistent())
return false; return false;
@ -1549,12 +1564,12 @@ namespace polysat {
IF_VERBOSE(0, verbose_stream() << "new-bound v" << x << " " << m_vars[x] << "\n"); IF_VERBOSE(0, verbose_stream() << "new-bound v" << x << " " << m_vars[x] << "\n");
if (inconsistent()) if (inconsistent())
return false; return false;
else if (!was_fixed && lo(x) + 1 == hi(x)) else if (!was_fixed && lo(x) + 1 == hi(x))
fixed_var_eh(r, x); fixed_var_eh(r, x);
return true; return true;
} }
template<typename Ext> template<typename Ext>
std::ostream& fixplex<Ext>::display(std::ostream& out) const { std::ostream& fixplex<Ext>::display(std::ostream& out) const {
M.display(out); M.display(out);
for (unsigned i = 0; i < m_vars.size(); ++i) { for (unsigned i = 0; i < m_vars.size(); ++i) {
@ -1564,12 +1579,12 @@ namespace polysat {
out << "\n"; out << "\n";
} }
for (ineq const& i : m_ineqs) for (ineq const& i : m_ineqs)
out << i << "\n"; out << i << "\n";
return out; return out;
} }
template<typename Ext> template<typename Ext>
std::ostream& fixplex<Ext>::display_row(std::ostream& out, row const& r, bool values) { std::ostream& fixplex<Ext>::display_row(std::ostream& out, row const& r, bool values) const {
out << r.id() << " := " << pp(row2value(r)) << " : "; out << r.id() << " := " << pp(row2value(r)) << " : ";
for (auto const& e : M.row_entries(r)) { for (auto const& e : M.row_entries(r)) {
var_t v = e.var(); var_t v = e.var();
@ -1579,19 +1594,19 @@ namespace polysat {
if (is_base(v)) if (is_base(v))
out << "b"; out << "b";
out << " "; out << " ";
if (values) if (values)
out << pp(value(v)) << " " << m_vars[v] << " "; out << pp(value(v)) << " " << m_vars[v] << " ";
} }
return out << "\n"; return out << "\n";
} }
template<typename Ext> template<typename Ext>
bool fixplex<Ext>::well_formed() const { bool fixplex<Ext>::well_formed() const {
SASSERT(M.well_formed()); SASSERT(M.well_formed());
for (unsigned i = 0; i < m_rows.size(); ++i) { for (unsigned i = 0; i < m_rows.size(); ++i) {
row r(i); row r(i);
var_t s = row2base(r); var_t s = row2base(r);
if (s == null_var) if (s == null_var)
continue; continue;
SASSERT(i == base2row(s).id()); SASSERT(i == base2row(s).id());
VERIFY(well_formed_row(r)); VERIFY(well_formed_row(r));
@ -1604,8 +1619,8 @@ namespace polysat {
return true; return true;
} }
template<typename Ext> template<typename Ext>
bool fixplex<Ext>::well_formed_row(row const& r) const { bool fixplex<Ext>::well_formed_row(row const& r) const {
var_t s = row2base(r); var_t s = row2base(r);
VERIFY(base2row(s).id() == r.id()); VERIFY(base2row(s).id() == r.id());
VERIFY(m_vars[s].m_is_base); VERIFY(m_vars[s].m_is_base);
@ -1620,6 +1635,14 @@ namespace polysat {
TRACE("polysat", display(tout << "non-well formed row\n"); M.display_row(tout << "row: ", r);); TRACE("polysat", display(tout << "non-well formed row\n"); M.display_row(tout << "row: ", r););
throw default_exception("non-well formed row"); throw default_exception("non-well formed row");
} }
if (sum != row2value(r) + base_coeff * value(s)) {
std::cout << sum << "\n";
std::cout << (row2value(r) + base_coeff * value(s)) << "\n";
display_row(std::cout, r, false);
display(std::cout);
}
SASSERT(sum == row2value(r) + base_coeff * value(s)); SASSERT(sum == row2value(r) + base_coeff * value(s));
return true; return true;
} }

View file

@ -449,6 +449,12 @@ namespace polysat {
uint64_t sum = 0; uint64_t sum = 0;
for (auto col : row) for (auto col : row)
sum += col.second * fp.value(col.first); sum += col.second * fp.value(col.first);
if (sum != 0) {
std::cout << sum << " = ";
for (auto col : row)
std::cout << pp(col.second) << "*v" << col.first << "(" << pp(fp.value(col.first)) << ") ";
std::cout << "\n";
}
VALIDATE(sum == 0); VALIDATE(sum == 0);
} }
for (unsigned i = 0; i < bounds.size(); ++i) { for (unsigned i = 0; i < bounds.size(); ++i) {
@ -509,7 +515,8 @@ namespace polysat {
} }
for (unsigned i = 0; i < num_rows; ++i) { for (unsigned i = 0; i < num_rows; ++i) {
svector<std::pair<unsigned, uint64_t>> row; svector<std::pair<unsigned, uint64_t>> row;
uint64_t coeff = (r() % 2 == 0) ? r() % 100 : (0 - r() % 10); uint64_t coeff = (r() % 2 == 0) ? (1 + r() % 100) : (0 - 1 - r() % 10);
SASSERT(coeff != 0);
row.push_back(std::make_pair(i, coeff)); row.push_back(std::make_pair(i, coeff));
uint_set seen; uint_set seen;
for (unsigned j = 0; j + 1 < num_vars_per_row; ++j) { for (unsigned j = 0; j + 1 < num_vars_per_row; ++j) {
@ -519,7 +526,8 @@ namespace polysat {
} }
while (seen.contains(v)); while (seen.contains(v));
seen.insert(v); seen.insert(v);
coeff = (r() % 2 == 0) ? r() % 100 : (0 - r() % 10); coeff = (r() % 2 == 0) ? (1 + r() % 100) : (0 - 1 - r() % 10);
SASSERT(coeff != 0);
row.push_back(std::make_pair(v, coeff)); row.push_back(std::make_pair(v, coeff));
} }
rows.push_back(row); rows.push_back(row);
@ -530,10 +538,12 @@ namespace polysat {
static void test_lps() { static void test_lps() {
random_gen r; random_gen r;
for (unsigned i = 0; i < 10000; ++i)
test_lps(r, 6, 0, 0, 5);
for (unsigned i = 0; i < 10000; ++i) for (unsigned i = 0; i < 10000; ++i)
test_lps(r, 6, 3, 3, 0); test_lps(r, 6, 3, 3, 0);
return;
for (unsigned i = 0; i < 10000; ++i)
test_lps(r, 6, 0, 0, 5);
for (unsigned i = 0; i < 10000; ++i) for (unsigned i = 0; i < 10000; ++i)
test_lps(r, 6, 3, 3, 3); test_lps(r, 6, 3, 3, 3);