3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-24 06:43:40 +00:00

review and fix soundness bug in band rule

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2022-12-02 19:04:23 -08:00
parent 2704626a5d
commit 215a4e9bad
4 changed files with 21 additions and 17 deletions

View file

@ -37,17 +37,12 @@ namespace polysat {
switch (c) { switch (c) {
case code::and_op: case code::and_op:
case code::or_op:
case code::xor_op:
if (p.index() > q.index()) if (p.index() > q.index())
std::swap(m_p, m_q); std::swap(m_p, m_q);
break; break;
default: default:
break; break;
} }
// The following can currently not be used as standalone constraints
SASSERT(c != code::or_op);
SASSERT(c != code::xor_op);
} }
lbool op_constraint::eval() const { lbool op_constraint::eval() const {
@ -89,10 +84,6 @@ namespace polysat {
return out << "<<"; return out << "<<";
case op_constraint::code::and_op: case op_constraint::code::and_op:
return out << "&"; return out << "&";
case op_constraint::code::or_op:
return out << "|";
case op_constraint::code::xor_op:
return out << "^";
default: default:
UNREACHABLE(); UNREACHABLE();
return out; return out;
@ -333,8 +324,8 @@ namespace polysat {
* p[i] && q[i] = r[i] * p[i] && q[i] = r[i]
* p = 2^K - 1 => q = r * p = 2^K - 1 => q = r
* q = 2^K - 1 => p = r * q = 2^K - 1 => p = r
* r = 0 && p = 2^k - 1 => q >= 2^k (or: q > p) * r = 0 && q != 0 & p = 2^k - 1 => q >= 2^k
* r = 0 && q = 2^k - 1 => p >= 2^k (or: p > q) * r = 0 && p != 0 & q = 2^k - 1 => p >= 2^k
*/ */
clause_ref op_constraint::lemma_and(solver& s, assignment const& a) { clause_ref op_constraint::lemma_and(solver& s, assignment const& a) {
auto& m = p().manager(); auto& m = p().manager();
@ -344,21 +335,29 @@ namespace polysat {
signed_constraint const andc(this, true); signed_constraint const andc(this, true);
// r <= p
if (pv.is_val() && rv.is_val() && rv.val() > pv.val()) if (pv.is_val() && rv.is_val() && rv.val() > pv.val())
return s.mk_clause(~andc, s.ule(r(), p()), true); return s.mk_clause(~andc, s.ule(r(), p()), true);
// r <= q
if (qv.is_val() && rv.is_val() && rv.val() > qv.val()) if (qv.is_val() && rv.is_val() && rv.val() > qv.val())
return s.mk_clause(~andc, s.ule(r(), q()), true); return s.mk_clause(~andc, s.ule(r(), q()), true);
// p = q => r = p
if (pv.is_val() && qv.is_val() && rv.is_val() && pv == qv && rv != pv) if (pv.is_val() && qv.is_val() && rv.is_val() && pv == qv && rv != pv)
return s.mk_clause(~andc, ~s.eq(p(), q()), s.eq(r(), p()), true); return s.mk_clause(~andc, ~s.eq(p(), q()), s.eq(r(), p()), true);
if (pv.is_val() && qv.is_val() && rv.is_val()) { if (pv.is_val() && qv.is_val() && rv.is_val()) {
// p = -1 => r = q
if (pv.val() == m.max_value() && qv != rv) if (pv.val() == m.max_value() && qv != rv)
return s.mk_clause(~andc, ~s.eq(p(), m.max_value()), s.eq(q(), r()), true); return s.mk_clause(~andc, ~s.eq(p(), m.max_value()), s.eq(q(), r()), true);
// q = -1 => r = p
if (qv.val() == m.max_value() && pv != rv) if (qv.val() == m.max_value() && pv != rv)
return s.mk_clause(~andc, ~s.eq(q(), m.max_value()), s.eq(p(), r()), true); return s.mk_clause(~andc, ~s.eq(q(), m.max_value()), s.eq(p(), r()), true);
if (rv.is_zero() && (pv.val() + 1).is_power_of_two() && qv.val() <= pv.val()) // r = 0 && q != 0 & p = 2^k - 1 => q >= 2^k
return s.mk_clause(~andc, ~s.eq(r()), ~s.eq(p(), pv.val()), s.ult(q(), p()), true); if ((pv.val() + 1).is_power_of_two() && rv.val() > pv.val())
return s.mk_clause(~andc, ~s.eq(r()), ~s.eq(p(), pv.val()), s.eq(q()), s.ult(p(), q()), true);
// r = 0 && p != 0 & q = 2^k - 1 => p >= 2^k
if (rv.is_zero() && (qv.val() + 1).is_power_of_two() && pv.val() <= qv.val()) if (rv.is_zero() && (qv.val() + 1).is_power_of_two() && pv.val() <= qv.val())
return s.mk_clause(~andc, ~s.eq(r()), ~s.eq(q(), qv.val()), s.ult(p(), q()), true); return s.mk_clause(~andc, ~s.eq(r()), ~s.eq(q(), qv.val()), s.eq(p()),s.ult(q(), p()), true);
unsigned K = p().manager().power_of_2(); unsigned K = p().manager().power_of_2();
for (unsigned i = 0; i < K; ++i) { for (unsigned i = 0; i < K; ++i) {
bool pb = pv.val().get_bit(i); bool pb = pv.val().get_bit(i);

View file

@ -28,7 +28,7 @@ namespace polysat {
class op_constraint final : public constraint { class op_constraint final : public constraint {
public: public:
enum class code { lshr_op, ashr_op, shl_op, and_op, or_op, xor_op }; enum class code { lshr_op, ashr_op, shl_op, and_op };
protected: protected:
friend class constraint_manager; friend class constraint_manager;

View file

@ -1080,7 +1080,7 @@ namespace polysat {
} }
void solver::add_clause(std::initializer_list<signed_constraint> cs, bool is_redundant) { void solver::add_clause(std::initializer_list<signed_constraint> cs, bool is_redundant) {
add_clause(cs.size(), std::data(cs), is_redundant); add_clause(static_cast<unsigned>(cs.size()), std::data(cs), is_redundant);
} }
void solver::add_clause(signed_constraint c1, bool is_redundant) { void solver::add_clause(signed_constraint c1, bool is_redundant) {
@ -1100,7 +1100,7 @@ namespace polysat {
} }
clause_ref solver::mk_clause(std::initializer_list<signed_constraint> cs, bool is_redundant) { clause_ref solver::mk_clause(std::initializer_list<signed_constraint> cs, bool is_redundant) {
return mk_clause(cs.size(), std::data(cs), is_redundant); return mk_clause(static_cast<unsigned>(cs.size()), std::data(cs), is_redundant);
} }
clause_ref solver::mk_clause(unsigned n, signed_constraint const* cs, bool is_redundant) { clause_ref solver::mk_clause(unsigned n, signed_constraint const* cs, bool is_redundant) {
@ -1127,6 +1127,10 @@ namespace polysat {
return mk_clause({ c1, c2, c3, c4 }, is_redundant); return mk_clause({ c1, c2, c3, c4 }, is_redundant);
} }
clause_ref solver::mk_clause(signed_constraint c1, signed_constraint c2, signed_constraint c3, signed_constraint c4, signed_constraint c5, bool is_redundant) {
return mk_clause({ c1, c2, c3, c4, c5 }, is_redundant);
}
void solver::push() { void solver::push() {
LOG_H3("Push user scope"); LOG_H3("Push user scope");
push_level(); push_level();

View file

@ -294,6 +294,7 @@ namespace polysat {
clause_ref mk_clause(signed_constraint c1, signed_constraint c2, bool is_redundant); clause_ref mk_clause(signed_constraint c1, signed_constraint c2, bool is_redundant);
clause_ref mk_clause(signed_constraint c1, signed_constraint c2, signed_constraint c3, bool is_redundant); clause_ref mk_clause(signed_constraint c1, signed_constraint c2, signed_constraint c3, bool is_redundant);
clause_ref mk_clause(signed_constraint c1, signed_constraint c2, signed_constraint c3, signed_constraint c4, bool is_redundant); clause_ref mk_clause(signed_constraint c1, signed_constraint c2, signed_constraint c3, signed_constraint c4, bool is_redundant);
clause_ref mk_clause(signed_constraint c1, signed_constraint c2, signed_constraint c3, signed_constraint c4, signed_constraint c5, bool is_redundant);
clause_ref mk_clause(std::initializer_list<signed_constraint> cs, bool is_redundant); clause_ref mk_clause(std::initializer_list<signed_constraint> cs, bool is_redundant);
clause_ref mk_clause(unsigned n, signed_constraint const* cs, bool is_redundant); clause_ref mk_clause(unsigned n, signed_constraint const* cs, bool is_redundant);