mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
add built-in support for bvor: the rewriter converts bitwise and to bit-wise or so using bvor as a basis makes better sense
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
e2c5d7d358
commit
e7c9c5f7a2
10 changed files with 279 additions and 137 deletions
|
@ -63,6 +63,12 @@ namespace polysat {
|
|||
return signed_constraint(ckind_t::op_t, cnstr);
|
||||
}
|
||||
|
||||
signed_constraint constraints::bor(pdd const& a, pdd const& b, pdd const& r) {
|
||||
auto* cnstr = alloc(op_constraint, op_constraint::code::or_op, a, b, r);
|
||||
c.trail().push(new_obj_trail(cnstr));
|
||||
return signed_constraint(ckind_t::op_t, cnstr);
|
||||
}
|
||||
|
||||
// parity p >= k if low order k bits of p are 0
|
||||
signed_constraint constraints::parity_at_least(pdd const& p, unsigned k) {
|
||||
if (k == 0)
|
||||
|
@ -82,6 +88,12 @@ namespace polysat {
|
|||
return eq(p * rational::power_of_two(N - k));
|
||||
}
|
||||
|
||||
// 2^{N-i-1}* p >= 2^{N-1}
|
||||
signed_constraint constraints::bit(pdd const& p, unsigned i) {
|
||||
unsigned N = p.manager().power_of_2();
|
||||
return uge(p * rational::power_of_two(N - i - 1), rational::power_of_two(N - 1));
|
||||
}
|
||||
|
||||
bool signed_constraint::is_eq(pvar& v, rational& val) {
|
||||
if (m_sign)
|
||||
return false;
|
||||
|
|
|
@ -22,6 +22,8 @@ namespace polysat {
|
|||
class core;
|
||||
class ule_constraint;
|
||||
class umul_ovfl_constraint;
|
||||
class op_constraint;
|
||||
|
||||
class assignment;
|
||||
|
||||
using pdd = dd::pdd;
|
||||
|
@ -84,8 +86,10 @@ namespace polysat {
|
|||
bool is_ule() const { return m_op == ule_t; }
|
||||
bool is_umul_ovfl() const { return m_op == umul_ovfl_t; }
|
||||
bool is_smul_fl() const { return m_op == smul_fl_t; }
|
||||
bool is_op() const { return m_op == op_t; }
|
||||
ule_constraint const& to_ule() const { SASSERT(is_ule()); return *reinterpret_cast<ule_constraint*>(m_constraint); }
|
||||
umul_ovfl_constraint const& to_umul_ovfl() const { SASSERT(is_umul_ovfl()); return *reinterpret_cast<umul_ovfl_constraint*>(m_constraint); }
|
||||
op_constraint const& to_op() const { SASSERT(is_op()); return *reinterpret_cast<op_constraint*>(m_constraint); }
|
||||
bool is_eq(pvar& v, rational& val);
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
};
|
||||
|
@ -108,7 +112,7 @@ namespace polysat {
|
|||
signed_constraint umul_ovfl(pdd const& p, pdd const& q);
|
||||
signed_constraint smul_ovfl(pdd const& p, pdd const& q) { throw default_exception("smul ovfl nyi"); }
|
||||
signed_constraint smul_udfl(pdd const& p, pdd const& q) { throw default_exception("smult-udfl nyi"); }
|
||||
signed_constraint bit(pdd const& p, unsigned i) { throw default_exception("bit nyi"); }
|
||||
signed_constraint bit(pdd const& p, unsigned i);
|
||||
|
||||
signed_constraint diseq(pdd const& p) { return ~eq(p); }
|
||||
signed_constraint diseq(pdd const& p, pdd const& q) { return diseq(p - q); }
|
||||
|
@ -172,6 +176,7 @@ namespace polysat {
|
|||
signed_constraint ashr(pdd const& a, pdd const& b, pdd const& r);
|
||||
signed_constraint shl(pdd const& a, pdd const& b, pdd const& r);
|
||||
signed_constraint band(pdd const& a, pdd const& b, pdd const& r);
|
||||
signed_constraint bor(pdd const& a, pdd const& b, pdd const& r);
|
||||
|
||||
//signed_constraint even(pdd const& p) { return parity_at_least(p, 1); }
|
||||
//signed_constraint odd(pdd const& p) { return ~even(p); }
|
||||
|
|
|
@ -206,6 +206,7 @@ namespace polysat {
|
|||
case l_false:
|
||||
return sat::check_result::CR_CONTINUE;
|
||||
case l_undef:
|
||||
verbose_stream() << "giveup assign\n";
|
||||
return sat::check_result::CR_GIVEUP;
|
||||
// or:
|
||||
// r = l_undef;
|
||||
|
@ -220,6 +221,7 @@ namespace polysat {
|
|||
TRACE("bv", tout << "saturate\n");
|
||||
return sat::check_result::CR_CONTINUE;
|
||||
case l_undef:
|
||||
verbose_stream() << "giveup saturate\n";
|
||||
r = l_undef;
|
||||
break;
|
||||
}
|
||||
|
@ -231,6 +233,7 @@ namespace polysat {
|
|||
TRACE("bv", tout << "refine\n");
|
||||
return sat::check_result::CR_CONTINUE;
|
||||
case l_undef:
|
||||
verbose_stream() << "giveup refine\n";
|
||||
r = l_undef;
|
||||
break;
|
||||
}
|
||||
|
@ -242,6 +245,7 @@ namespace polysat {
|
|||
TRACE("bv", tout << "blast\n");
|
||||
return sat::check_result::CR_CONTINUE;
|
||||
case l_undef:
|
||||
verbose_stream() << "giveup blast\n";
|
||||
r = l_undef;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -129,6 +129,7 @@ namespace polysat {
|
|||
void ashr(pdd const& a, pdd const& b, pdd const& r) { add_opdef(m_constraints.ashr(a, b, r)); }
|
||||
void shl(pdd const& a, pdd const& b, pdd const& r) { add_opdef(m_constraints.shl(a, b, r)); }
|
||||
void band(pdd const& a, pdd const& b, pdd const& r) { add_opdef(m_constraints.band(a, b, r)); }
|
||||
void bor(pdd const& a, pdd const& b, pdd const& r) { add_opdef(m_constraints.bor(a, b, r)); }
|
||||
|
||||
pdd bnot(pdd p) { return -p - 1; }
|
||||
pvar mul(unsigned n, pdd const* args) { return m_monomials.mk(n, args); }
|
||||
|
|
|
@ -86,10 +86,10 @@ namespace polysat {
|
|||
// bit blast a monomial definition
|
||||
lbool monomials::bit_blast() {
|
||||
// disable for now
|
||||
return l_undef;
|
||||
init_to_refine();
|
||||
if (m_to_refine.empty())
|
||||
return l_true;
|
||||
return l_undef;
|
||||
shuffle(m_to_refine.size(), m_to_refine.data(), c.rand());
|
||||
if (any_of(m_to_refine, [&](auto i) { return bit_blast(m_monomials[i]); }))
|
||||
return l_false;
|
||||
|
|
|
@ -61,6 +61,8 @@ namespace polysat {
|
|||
return eval_shl(p, q, r);
|
||||
case code::and_op:
|
||||
return eval_and(p, q, r);
|
||||
case code::or_op:
|
||||
return eval_or(p, q, r);
|
||||
case code::inv_op:
|
||||
return eval_inv(p, r);
|
||||
case code::ashr_op:
|
||||
|
@ -96,7 +98,7 @@ namespace polysat {
|
|||
if (r.is_val() && p.is_val() && q.is_val()) {
|
||||
auto M = m.max_value();
|
||||
auto N = M + 1;
|
||||
if (p.val() >= N/2) {
|
||||
if (p.val() >= N / 2) {
|
||||
if (q.val() >= m.power_of_2())
|
||||
return to_lbool(r.val() == M);
|
||||
unsigned k = q.val().get_unsigned();
|
||||
|
@ -144,6 +146,19 @@ namespace polysat {
|
|||
return l_undef;
|
||||
}
|
||||
|
||||
/** Evaluate constraint: r == p | q */
|
||||
lbool op_constraint::eval_or(pdd const& p, pdd const& q, pdd const& r) {
|
||||
if (p.is_zero() && q == r)
|
||||
return l_true;
|
||||
if (q.is_zero() && p == r)
|
||||
return l_true;
|
||||
|
||||
if (p.is_val() && q.is_val() && r.is_val())
|
||||
return r.val() == bitwise_or(p.val(), q.val()) ? l_true : l_false;
|
||||
|
||||
return l_undef;
|
||||
}
|
||||
|
||||
/** Evaluate constraint: r == inv p */
|
||||
lbool op_constraint::eval_inv(pdd const& p, pdd const& r) {
|
||||
if (!p.is_val() || !r.is_val())
|
||||
|
@ -173,6 +188,8 @@ namespace polysat {
|
|||
return out << "<<";
|
||||
case op_constraint::code::and_op:
|
||||
return out << "&";
|
||||
case op_constraint::code::or_op:
|
||||
return out << "|";
|
||||
case op_constraint::code::inv_op:
|
||||
return out << "inv";
|
||||
default:
|
||||
|
@ -202,15 +219,22 @@ namespace polysat {
|
|||
case code::and_op:
|
||||
activate_and(c, dep);
|
||||
break;
|
||||
case code::or_op:
|
||||
c.add_axiom("p | q >= p", { C.ule(p, r) }, false);
|
||||
c.add_axiom("p | q >= q", { C.ule(q, r) }, false);
|
||||
c.add_axiom("p = q -> p | q = p", { ~C.eq(p, q), C.eq(r, p) }, false);
|
||||
c.add_axiom("p | 0 = p", { ~C.eq(q), C.eq(r, p) }, false);
|
||||
c.add_axiom("0 | q = q", { ~C.eq(p), C.eq(r, q) }, false);
|
||||
break;
|
||||
case code::ashr_op:
|
||||
c.add_axiom("q >= N & p < 0 -> p <<a q = -1", { ~C.uge(q, N), ~C.slt(p, 0), C.eq(r, m.max_value()) }, false);
|
||||
c.add_axiom("q >= N & p >= 0 -> p <<a q = 0", { ~C.uge(q, N), ~C.sge(p, 0), C.eq(r) }, false);
|
||||
c.add_axiom("q = 0 -> p <<a q = p", { ~C.eq(q), C.eq(r, p) }, false);
|
||||
break;
|
||||
case code::lshr_op:
|
||||
case code::lshr_op:
|
||||
c.add_axiom("q >= N -> p <<l q = 0", { ~C.uge(q, N), C.eq(r) }, false);
|
||||
c.add_axiom("q = 0 -> p <<l q = p", { ~C.eq(q), C.eq(r, p) }, false);
|
||||
break;
|
||||
break;
|
||||
case code::shl_op:
|
||||
c.add_axiom("q >= N -> p >> q = 0", { ~C.uge(q, N), C.eq(r) }, false);
|
||||
c.add_axiom("q = 0 -> p >> q = p", { ~C.eq(q), C.eq(r, p) }, false);
|
||||
|
@ -226,19 +250,22 @@ namespace polysat {
|
|||
SASSERT(value == l_true);
|
||||
switch (m_op) {
|
||||
case code::lshr_op:
|
||||
propagate_lshr(c, dep);
|
||||
propagate_lshr(c);
|
||||
break;
|
||||
case code::ashr_op:
|
||||
propagate_ashr(c, dep);
|
||||
propagate_ashr(c);
|
||||
break;
|
||||
case code::shl_op:
|
||||
propagate_shl(c, dep);
|
||||
propagate_shl(c);
|
||||
break;
|
||||
case code::and_op:
|
||||
propagate_and(c, dep);
|
||||
propagate_and(c);
|
||||
break;
|
||||
case code::or_op:
|
||||
propagate_or(c);
|
||||
break;
|
||||
case code::inv_op:
|
||||
propagate_inv(c, dep);
|
||||
propagate_inv(c);
|
||||
break;
|
||||
default:
|
||||
verbose_stream() << "not implemented yet: " << *this << "\n";
|
||||
|
@ -247,10 +274,20 @@ namespace polysat {
|
|||
}
|
||||
}
|
||||
|
||||
void op_constraint::propagate_inv(core& s, dependency const& dep) {
|
||||
void op_constraint::propagate_inv(core& s) {
|
||||
|
||||
}
|
||||
|
||||
void op_constraint::propagate(core& c, signed_constraint const& sc) {
|
||||
c.propagate(sc, c.explain_weak_eval(sc));
|
||||
}
|
||||
|
||||
void op_constraint::add_conflict(core& c, char const* ax, constraint_or_dependency_list const& cs) {
|
||||
for (auto sc : cs)
|
||||
if (std::holds_alternative<signed_constraint>(sc))
|
||||
propagate(c, ~*std::get_if<signed_constraint>(&sc));
|
||||
c.add_axiom(ax, cs, true);
|
||||
}
|
||||
/**
|
||||
* Enforce basic axioms for r == p >> q:
|
||||
*
|
||||
|
@ -270,10 +307,10 @@ namespace polysat {
|
|||
*
|
||||
* TODO: use also
|
||||
* s.m_viable.min_viable();
|
||||
* s.m_viable.max_viable()
|
||||
* s.m_viable.max_viable(
|
||||
* when r, q are variables.
|
||||
*/
|
||||
void op_constraint::propagate_lshr(core& c, dependency const& d) {
|
||||
void op_constraint::propagate_lshr(core& c) {
|
||||
auto& m = p.manager();
|
||||
auto const pv = c.subst(p);
|
||||
auto const qv = c.subst(q);
|
||||
|
@ -283,25 +320,25 @@ namespace polysat {
|
|||
auto& C = c.cs();
|
||||
|
||||
if (pv.is_val() && rv.is_val() && rv.val() > pv.val())
|
||||
c.add_axiom("lshr 1", { C.ule(r, p) }, false);
|
||||
return add_conflict(c, "lshr 1", { C.ule(r, p) });
|
||||
|
||||
else if (qv.is_val() && qv.val() >= N && rv.is_val() && !rv.is_zero())
|
||||
// TODO: instead of rv.is_val() && !rv.is_zero(), we should use !is_forced_zero(r) which checks whether eval(r) = 0 or bvalue(r=0) = true; see saturation.cpp
|
||||
c.add_axiom("q >= N -> r = 0", { ~C.ule(N, q), C.eq(r) }, true);
|
||||
else if (qv.is_zero() && pv.is_val() && rv.is_val() && pv != rv)
|
||||
c.add_axiom("q = 0 -> p = r", { ~C.eq(q), C.eq(p, r) } , true);
|
||||
c.add_axiom("q = 0 -> p = r", { ~C.eq(q), C.eq(p, r) }, true);
|
||||
else if (qv.is_val() && !qv.is_zero() && pv.is_val() && rv.is_val() && !pv.is_zero() && rv.val() >= pv.val())
|
||||
c.add_axiom("q != 0 & p > 0 -> r < p", { C.eq(q), C.ule(p, 0), C.ult(r, p) }, true);
|
||||
else if (qv.is_val() && !qv.is_zero() && qv.val() < N && rv.is_val() && rv.val() > rational::power_of_two(N - qv.val().get_unsigned()) - 1)
|
||||
c.add_axiom("q >= k -> r <= 2^{N-k} - 1", { ~C.ule(qv.val(), q), C.ule(r, rational::power_of_two(N - qv.val().get_unsigned()) - 1)}, true);
|
||||
c.add_axiom("q >= k -> r <= 2^{N-k} - 1", { ~C.ule(qv.val(), q), C.ule(r, rational::power_of_two(N - qv.val().get_unsigned()) - 1) }, true);
|
||||
else if (pv.is_val() && rv.is_val() && qv.is_val() && !qv.is_zero()) {
|
||||
unsigned k = qv.val().get_unsigned();
|
||||
for (unsigned i = 0; i < N - k; ++i) {
|
||||
if (rv.val().get_bit(i) && !pv.val().get_bit(i + k))
|
||||
if (rv.val().get_bit(i) && !pv.val().get_bit(i + k))
|
||||
c.add_axiom("q = k -> r[i] = p[i+k] for 0 <= i < N - k", { ~C.eq(q, k), ~C.bit(r, i), C.bit(p, i + k) }, true);
|
||||
|
||||
if (!rv.val().get_bit(i) && pv.val().get_bit(i + k))
|
||||
c.add_axiom("q = k -> r[i] = p[i+k] for 0 <= i < N - k", { ~C.eq(q, k), C.bit(r, i), ~C.bit(p, i + k) }, true);
|
||||
|
||||
if (!rv.val().get_bit(i) && pv.val().get_bit(i + k))
|
||||
c.add_axiom("q = k -> r[i] = p[i+k] for 0 <= i < N - k", { ~C.eq(q, k), C.bit(r, i), ~C.bit(p, i + k) }, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -350,9 +387,9 @@ namespace polysat {
|
|||
rational exp = rational::power_of_two(N - k);
|
||||
c.add_axiom("(p & 0011)*2^k = p*2^k", { C.eq(x * exp, r * exp) }, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void op_constraint::propagate_ashr(core& c, dependency const& dep) {
|
||||
void op_constraint::propagate_ashr(core& c) {
|
||||
//
|
||||
// Suppose q = k, p >= 0:
|
||||
// p = ab, where b has length k, a has length N - k
|
||||
|
@ -387,7 +424,7 @@ namespace polysat {
|
|||
rational twoNk = rational::power_of_two(N - k);
|
||||
auto eqK = C.eq(q, k);
|
||||
c.add_axiom("q = k -> r*2^k + p < 2^k", { ~eqK, C.ult(p - r * twoK, twoK) }, true);
|
||||
c.add_axiom("q = k & p >= 0 -> r < 2^{N-k}", { ~eqK, ~C.ule(0, p), C.ult(r, twoNk) }, true);
|
||||
c.add_axiom("q = k & p >= 0 -> r < 2^{N-k}", { ~eqK, ~C.ule(0, p), C.ult(r, twoNk) }, true);
|
||||
c.add_axiom("q = k & p < 0 -> r >= 2^N - 2^{N-k}", { ~eqK, ~C.slt(p, 0), C.uge(r, twoN - twoNk) }, true);
|
||||
}
|
||||
}
|
||||
|
@ -402,7 +439,7 @@ namespace polysat {
|
|||
* q = k -> r[i+k] = p[i] for 0 <= i < N - k
|
||||
* q = 0 -> r = p
|
||||
*/
|
||||
void op_constraint::propagate_shl(core& c, dependency const& d) {
|
||||
void op_constraint::propagate_shl(core& c) {
|
||||
auto& m = p.manager();
|
||||
auto const pv = c.subst(p);
|
||||
auto const qv = c.subst(q);
|
||||
|
@ -410,7 +447,7 @@ namespace polysat {
|
|||
unsigned const N = m.power_of_2();
|
||||
auto& C = c.cs();
|
||||
|
||||
if (qv.is_val() && qv.val() >= N && rv.is_val() && !rv.is_zero())
|
||||
if (qv.is_val() && qv.val() >= N && rv.is_val() && !rv.is_zero())
|
||||
c.add_axiom("q >= N -> p >> q = 0", { ~C.ule(N, q), C.eq(r) }, true);
|
||||
else if (qv.is_zero() && pv.is_val() && rv.is_val() && rv != pv)
|
||||
//
|
||||
|
@ -424,10 +461,10 @@ namespace polysat {
|
|||
unsigned k = qv.val().get_unsigned();
|
||||
// q = k -> r[i+k] = p[i] for 0 <= i < N - k
|
||||
for (unsigned i = 0; i < N - k; ++i) {
|
||||
if (rv.val().get_bit(i + k) && !pv.val().get_bit(i))
|
||||
c.add_axiom("q = k -> p>>q[i+k] = p[i] for 0 <= i < N - k", { ~C.eq(q, k), ~C.bit(r, i + k), C.bit(p, i) }, true);
|
||||
else if (!rv.val().get_bit(i + k) && pv.val().get_bit(i))
|
||||
c.add_axiom("q = k -> p>>q[i+k] = p[i] for 0 <= i < N - k", { ~C.eq(q, k), C.bit(r, i + k), ~C.bit(p, i) }, true);
|
||||
if (rv.val().get_bit(i + k) && !pv.val().get_bit(i))
|
||||
c.add_axiom("q = k -> p>>q[i+k] = p[i] for 0 <= i < N - k", { ~C.eq(q, k), ~C.bit(r, i + k), C.bit(p, i) }, true);
|
||||
else if (!rv.val().get_bit(i + k) && pv.val().get_bit(i))
|
||||
c.add_axiom("q = k -> p>>q[i+k] = p[i] for 0 <= i < N - k", { ~C.eq(q, k), C.bit(r, i + k), ~C.bit(p, i) }, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -435,13 +472,13 @@ namespace polysat {
|
|||
SASSERT(!(pv.is_val() && qv.is_val() && rv.is_val()));
|
||||
if (qv.is_val() && !rv.is_val()) {
|
||||
rational const& q_val = qv.val();
|
||||
if (q_val >= N)
|
||||
c.add_axiom("q >= N ==> p << q = 0", {~C.ule(N, q), C.eq(r)}, true);
|
||||
if (q_val >= N)
|
||||
c.add_axiom("q >= N ==> p << q = 0", { ~C.ule(N, q), C.eq(r) }, true);
|
||||
if (pv.is_val()) {
|
||||
SASSERT(q_val.is_unsigned());
|
||||
// p = p_val & q = q_val ==> r = p_val * 2^q_val
|
||||
rational const r_val = pv.val() * rational::power_of_two(q_val.get_unsigned());
|
||||
c.add_axiom("p = v1, q = v2, p << q -> v1 << v2", {~C.eq(p, pv), ~C.eq(q, qv), C.eq(r, r_val)}, true);
|
||||
c.add_axiom("p = v1, q = v2, p << q -> v1 << v2", { ~C.eq(p, pv), ~C.eq(q, qv), C.eq(r, r_val) }, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -460,62 +497,109 @@ namespace polysat {
|
|||
* p = 2^k - 1 && r = 0 && q != 0 => q >= 2^k
|
||||
* q = 2^k - 1 && r = 0 && p != 0 => p >= 2^k
|
||||
*/
|
||||
void op_constraint::propagate_and(core& c, dependency const& d) {
|
||||
void op_constraint::propagate_and(core& c) {
|
||||
auto& m = p.manager();
|
||||
auto pv = c.subst(p);
|
||||
auto qv = c.subst(q);
|
||||
auto rv = c.subst(r);
|
||||
auto& C = c.cs();
|
||||
|
||||
if (pv.is_val() && rv.is_val() && rv.val() > pv.val())
|
||||
c.add_axiom("p & q <= p", { C.ule(r, p) }, true);
|
||||
else if (qv.is_val() && rv.is_val() && rv.val() > qv.val())
|
||||
c.add_axiom("p & q <= q", { C.ule(r, q) }, true);
|
||||
else if (pv.is_val() && qv.is_val() && rv.is_val() && pv == qv && rv != pv)
|
||||
c.add_axiom("p = q => p & q = p", { ~C.eq(p, q), C.eq(r, p) }, true);
|
||||
// p = a && q = b ==> r = a & b
|
||||
else if (pv.is_val() && qv.is_val() && !rv.is_val())
|
||||
// Just assign by this very weak justification. It will be strengthened in saturation in case of a conflict
|
||||
c.add_axiom("p = a & q = b => r = a&b", { ~C.eq(p, pv), ~C.eq(q, qv), C.eq(r, bitwise_and(pv.val(), qv.val())) }, true);
|
||||
else if (pv.is_val() && qv.is_val() && rv.is_val()) {
|
||||
if (pv.is_max() && qv != rv)
|
||||
c.add_axiom("p = -1 => p & q = q", { ~C.eq(p, m.max_value()), C.eq(q, r) }, true);
|
||||
else if (qv.is_max() && pv != rv)
|
||||
c.add_axiom("q = -1 => p & q = p", { ~C.eq(q, m.max_value()), C.eq(p, r) }, true);
|
||||
else {
|
||||
unsigned const N = m.power_of_2();
|
||||
unsigned pow;
|
||||
if ((pv.val() + 1).is_power_of_two(pow)) {
|
||||
if (rv.is_zero() && !qv.is_zero() && qv.val() <= pv.val())
|
||||
c.add_axiom("p = 2^k - 1 && p & q = 0 && q != 0 => q >= 2^k", { ~C.eq(p, pv), ~C.eq(r), C.eq(q), C.ule(pv + 1, q) }, true);
|
||||
else if (rv != qv)
|
||||
c.add_axiom("p = 2^k - 1 ==> (p&q)*2^{N - k} = q*2^{N - k}", { ~C.eq(p, pv), C.eq(r * rational::power_of_two(N - pow), q * rational::power_of_two(N - pow)) }, true);
|
||||
}
|
||||
if ((qv.val() + 1).is_power_of_two(pow)) {
|
||||
if (rv.is_zero() && !pv.is_zero() && pv.val() <= qv.val())
|
||||
c.add_axiom("q = 2^k - 1 && p & q = 0 && p != 0 ==> p >= 2^k", { ~C.eq(q, qv), ~C.eq(r), C.eq(p), C.ule(qv + 1, p) }, true);
|
||||
else if (rv != pv)
|
||||
c.add_axiom("q = 2^k - 1 ==> (p&q)*2^{N - k} = p*2^{N - k}", { ~C.eq(q, qv), C.eq(r * rational::power_of_two(N - pow), p * rational::power_of_two(N - pow)) }, true);
|
||||
}
|
||||
if (!pv.is_val() || !qv.is_val() || !rv.is_val())
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < N; ++i) {
|
||||
bool pb = pv.val().get_bit(i);
|
||||
bool qb = qv.val().get_bit(i);
|
||||
bool rb = rv.val().get_bit(i);
|
||||
if (rb == (pb && qb))
|
||||
continue;
|
||||
if (pb && qb && !rb)
|
||||
c.add_axiom("p&q[i] = p[i]&q[i]", { ~C.bit(p, i), ~C.bit(q, i), C.bit(r, i) }, true);
|
||||
else if (!pb && rb)
|
||||
c.add_axiom("p&q[i] = p[i]&q[i]", { C.bit(p, i), ~C.bit(r, i) }, true);
|
||||
else if (!qb && rb)
|
||||
c.add_axiom("p&q[i] = p[i]&q[i]", { C.bit(q, i), ~C.bit(r, i) }, true);
|
||||
else
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (pv.is_max() && qv != rv)
|
||||
return add_conflict(c, "p = -1 => p & q = q", { ~C.eq(p, m.max_value()), C.eq(q, r) });
|
||||
|
||||
if (qv.is_max() && pv != rv)
|
||||
return add_conflict(c, "q = -1 => p & q = p", { ~C.eq(q, m.max_value()), C.eq(p, r) });
|
||||
|
||||
if (pv.is_zero() && !rv.is_zero())
|
||||
return add_conflict(c, "p = 0 => p & q = 0", { ~C.eq(p), C.eq(r) });
|
||||
|
||||
if (qv.is_zero() && !rv.is_zero())
|
||||
return add_conflict(c, "q = 0 => p & q = 0", { ~C.eq(q), C.eq(r) });
|
||||
|
||||
if (propagate_mask(c, p, q, r, pv.val(), qv.val(), rv.val()))
|
||||
return;
|
||||
|
||||
if (propagate_mask(c, q, p, r, qv.val(), pv.val(), rv.val()))
|
||||
return;
|
||||
|
||||
unsigned const N = m.power_of_2();
|
||||
for (unsigned i = 0; i < N; ++i) {
|
||||
bool pb = pv.val().get_bit(i);
|
||||
bool qb = qv.val().get_bit(i);
|
||||
bool rb = rv.val().get_bit(i);
|
||||
if (rb == (pb && qb))
|
||||
continue;
|
||||
if (pb && qb && !rb)
|
||||
add_conflict(c, "p&q[i] = p[i]&q[i]", { ~C.bit(p, i), ~C.bit(q, i), C.bit(r, i) });
|
||||
else if (!pb && rb)
|
||||
add_conflict(c, "p&q[i] = p[i]&q[i]", { C.bit(p, i), ~C.bit(r, i) });
|
||||
else if (!qb && rb)
|
||||
add_conflict(c, "p&q[i] = p[i]&q[i]", { C.bit(q, i), ~C.bit(r, i) });
|
||||
else
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void op_constraint::propagate_or(core& c) {
|
||||
auto& m = p.manager();
|
||||
auto pv = c.subst(p);
|
||||
auto qv = c.subst(q);
|
||||
auto rv = c.subst(r);
|
||||
auto& C = c.cs();
|
||||
|
||||
verbose_stream() << "propagate or " << p << " | " << q << " = " << r << "\n";
|
||||
|
||||
if (!pv.is_val() || !qv.is_val() || !rv.is_val())
|
||||
return;
|
||||
|
||||
if (pv.is_max() && pv != rv)
|
||||
return add_conflict(c, "p = -1 => p & q = p", { ~C.eq(p, m.max_value()), C.eq(p, r)});
|
||||
|
||||
if (qv.is_max() && qv != rv)
|
||||
return add_conflict(c, "q = -1 => p & q = q", { ~C.eq(q, m.max_value()), C.eq(q, r) });
|
||||
|
||||
unsigned const N = m.power_of_2();
|
||||
for (unsigned i = 0; i < N; ++i) {
|
||||
bool pb = pv.val().get_bit(i);
|
||||
bool qb = qv.val().get_bit(i);
|
||||
bool rb = rv.val().get_bit(i);
|
||||
if (rb == (pb || qb))
|
||||
continue;
|
||||
if (pb && !qb && rb)
|
||||
add_conflict(c, "p[i] => (p|q)[i]", { ~C.bit(p, i), C.bit(r, i) });
|
||||
else if (!pb && qb && rb)
|
||||
add_conflict(c, "q[i] => (p|q)[i]", { ~C.bit(q, i), C.bit(r, i) });
|
||||
else if (!pb && !qb && rb)
|
||||
add_conflict(c, "(p|q)[i] => p[i] or q[i]", { C.bit(p, i), C.bit(q, i), ~C.bit(r, i) });
|
||||
else
|
||||
UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool op_constraint::propagate_mask(core& c, pdd const& p, pdd const& q, pdd const& r, rational const& pv, rational const& qv, rational const& rv) {
|
||||
auto& m = p.manager();
|
||||
auto& C = c.cs();
|
||||
unsigned const N = m.power_of_2();
|
||||
unsigned pow;
|
||||
if (!(pv + 1).is_power_of_two(pow))
|
||||
return false;
|
||||
|
||||
if (rv.is_zero() && !qv.is_zero() && qv <= pv) {
|
||||
add_conflict(c, "p = 2^k - 1 && p & q = 0 && q != 0 => q >= 2^k", { ~C.eq(p, pv), ~C.eq(r), C.eq(q), C.ule(pv + 1, q) });
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rv != qv) {
|
||||
add_conflict(c, "p = 2^k - 1 ==> (p&q)*2^{N - k} = q*2^{N - k}", { ~C.eq(p, pv), C.eq(r * rational::power_of_two(N - pow), q * rational::power_of_two(N - pow)) });
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ namespace polysat {
|
|||
shl_op,
|
||||
/// r is the bit-wise 'and' of p and q.
|
||||
and_op,
|
||||
/// r is the bit-wise 'or' of p and q.
|
||||
or_op,
|
||||
/// r is the smallest multiplicative pseudo-inverse of p;
|
||||
/// by definition we set r == 0 when p == 0.
|
||||
/// Note that in general, there are 2^parity(p) many pseudo-inverses of p.
|
||||
|
@ -56,12 +58,18 @@ namespace polysat {
|
|||
static lbool eval_shl(pdd const& p, pdd const& q, pdd const& r);
|
||||
static lbool eval_and(pdd const& p, pdd const& q, pdd const& r);
|
||||
static lbool eval_inv(pdd const& p, pdd const& r);
|
||||
static lbool eval_or(pdd const& p, pdd const& q, pdd const& r);
|
||||
|
||||
void propagate_lshr(core& s, dependency const& dep);
|
||||
void propagate_ashr(core& s, dependency const& dep);
|
||||
void propagate_shl(core& s, dependency const& dep);
|
||||
void propagate_and(core& s, dependency const& dep);
|
||||
void propagate_inv(core& s, dependency const& dep);
|
||||
void propagate_lshr(core& c);
|
||||
void propagate_ashr(core& c);
|
||||
void propagate_shl(core& c);
|
||||
void propagate_and(core& c);
|
||||
void propagate_or(core& c);
|
||||
void propagate_inv(core& c);
|
||||
bool propagate_mask(core& c, pdd const& p, pdd const& q, pdd const& r, rational const& pv, rational const& qv, rational const& rv);
|
||||
|
||||
void propagate(core& c, signed_constraint const& sc);
|
||||
void add_conflict(core& c, char const* ax, constraint_or_dependency_list const& cs);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -51,6 +51,8 @@ namespace polysat {
|
|||
resolve(v, inequality::from_ule(c, id));
|
||||
else if (sc.is_umul_ovfl())
|
||||
try_umul_ovfl(v, umul_ovfl(id, sc));
|
||||
else if (sc.is_op())
|
||||
try_op(v, sc, c.get_dependency(id));
|
||||
|
||||
return c.inconsistent();
|
||||
}
|
||||
|
@ -238,4 +240,16 @@ namespace polysat {
|
|||
add_clause("ax + b = 0 & cx + d = 0 ==> cb - da = 0", { i.dep(), j.dep(), C.eq(r) }, true);
|
||||
}
|
||||
|
||||
|
||||
void saturation::try_op(pvar v, signed_constraint& sc, dependency const& d) {
|
||||
verbose_stream() << "try op " << sc << "\n";
|
||||
SASSERT(sc.is_op());
|
||||
sc.propagate(c, l_true, d);
|
||||
}
|
||||
|
||||
// possible algebraic rule:
|
||||
// From "Hacker's Delight", section 2-2. Addition Combined with Logical Operations;
|
||||
// found via Int-Blasting paper; see https://doi.org/10.1007/978-3-030-94583-1_24
|
||||
// bor(p,q) = (p + q) - band(p, q);
|
||||
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ namespace polysat {
|
|||
void try_ugt_y(pvar v, inequality const& i);
|
||||
void try_ugt_z(pvar z, inequality const& i);
|
||||
void try_umul_ovfl(pvar v, umul_ovfl const& sc);
|
||||
void try_op(pvar v, signed_constraint& sc, dependency const& d);
|
||||
|
||||
signed_constraint ineq(bool is_strict, pdd const& x, pdd const& y);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ Module Name:
|
|||
Abstract:
|
||||
|
||||
PolySAT internalize
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2022-01-26
|
||||
|
@ -43,7 +43,7 @@ namespace polysat {
|
|||
visit_rec(m, e, false, false);
|
||||
}
|
||||
|
||||
bool solver::visit(expr* e) {
|
||||
bool solver::visit(expr* e) {
|
||||
force_push();
|
||||
if (!is_app(e) || to_app(e)->get_family_id() != get_id()) {
|
||||
ctx.internalize(e);
|
||||
|
@ -55,7 +55,7 @@ namespace polysat {
|
|||
|
||||
bool solver::visited(expr* e) {
|
||||
euf::enode* n = expr2enode(e);
|
||||
return n && n->is_attached_to(get_id());
|
||||
return n && n->is_attached_to(get_id());
|
||||
}
|
||||
|
||||
bool solver::post_visit(expr* e, bool sign, bool root) {
|
||||
|
@ -75,7 +75,7 @@ namespace polysat {
|
|||
internalize_polysat(a);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void solver::internalize_polysat(app* a) {
|
||||
|
||||
#define if_unary(F) if (a->get_num_args() == 1) { internalize_unary(a, [&](pdd const& p) { return F(p); }); break; }
|
||||
|
@ -98,13 +98,13 @@ namespace polysat {
|
|||
case OP_MKBV: internalize_mkbv(a); break;
|
||||
case OP_BV_NUM: internalize_num(a); break;
|
||||
case OP_ULEQ: internalize_le<false, false, false>(a); break;
|
||||
case OP_SLEQ: internalize_le<true, false, false>(a); break;
|
||||
case OP_UGEQ: internalize_le<false, true, false>(a); break;
|
||||
case OP_SGEQ: internalize_le<true, true, false>(a); break;
|
||||
case OP_ULT: internalize_le<false, true, true>(a); break;
|
||||
case OP_SLT: internalize_le<true, true, true>(a); break;
|
||||
case OP_SLEQ: internalize_le<true, false, false>(a); break;
|
||||
case OP_UGEQ: internalize_le<false, true, false>(a); break;
|
||||
case OP_SGEQ: internalize_le<true, true, false>(a); break;
|
||||
case OP_ULT: internalize_le<false, true, true>(a); break;
|
||||
case OP_SLT: internalize_le<true, true, true>(a); break;
|
||||
case OP_UGT: internalize_le<false, false, true>(a); break;
|
||||
case OP_SGT: internalize_le<true, false, true>(a); break;
|
||||
case OP_SGT: internalize_le<true, false, true>(a); break;
|
||||
|
||||
case OP_BUMUL_NO_OVFL: internalize_binary_predicate(a, [&](pdd const& p, pdd const& q) { return ~m_core.umul_ovfl(p, q); }); break;
|
||||
case OP_BSMUL_NO_OVFL: internalize_binary_predicate(a, [&](pdd const& p, pdd const& q) { return ~m_core.smul_ovfl(p, q); }); break;
|
||||
|
@ -137,13 +137,13 @@ namespace polysat {
|
|||
case OP_EXTRACT: internalize_extract(a); break;
|
||||
case OP_CONCAT: internalize_concat(a); break;
|
||||
case OP_ZERO_EXT: internalize_zero_extend(a); break;
|
||||
case OP_SIGN_EXT: internalize_sign_extend(a); break;
|
||||
case OP_SIGN_EXT: internalize_sign_extend(a); break;
|
||||
|
||||
case OP_BSREM:
|
||||
case OP_BSREM_I:
|
||||
case OP_BSMOD:
|
||||
case OP_BSMOD_I:
|
||||
case OP_BSDIV:
|
||||
case OP_BSREM:
|
||||
case OP_BSREM_I:
|
||||
case OP_BSMOD:
|
||||
case OP_BSMOD_I:
|
||||
case OP_BSDIV:
|
||||
case OP_BSDIV_I:
|
||||
case OP_BREDOR: // x > 0 unary, return single bit, 1 if at least one input bit is set.
|
||||
case OP_BREDAND: // x == 2^K - 1 unary, return single bit, 1 if all input bits are set.
|
||||
|
@ -153,10 +153,10 @@ namespace polysat {
|
|||
case OP_EXT_ROTATE_LEFT:
|
||||
case OP_EXT_ROTATE_RIGHT:
|
||||
case OP_INT2BV:
|
||||
case OP_BV2INT:
|
||||
case OP_BV2INT:
|
||||
if (bv.is_bv(a))
|
||||
expr2pdd(a);
|
||||
m_delayed_axioms.push_back(a);
|
||||
m_delayed_axioms.push_back(a);
|
||||
ctx.push(push_back_vector(m_delayed_axioms));
|
||||
break;
|
||||
|
||||
|
@ -181,7 +181,7 @@ namespace polysat {
|
|||
solver::atom* solver::mk_atom(sat::bool_var bv, signed_constraint& sc) {
|
||||
auto a = get_bv2a(bv);
|
||||
if (a)
|
||||
return a;
|
||||
return a;
|
||||
auto index = m_core.register_constraint(sc, dependency(bv));
|
||||
a = new (get_region()) atom(bv, index);
|
||||
insert_bv2a(bv, a);
|
||||
|
@ -200,7 +200,7 @@ namespace polysat {
|
|||
}
|
||||
|
||||
void solver::internalize_udiv_i(app* e) {
|
||||
expr* x, *y;
|
||||
expr* x, * y;
|
||||
expr_ref rm(m);
|
||||
if (bv.is_bv_udivi(e, x, y))
|
||||
rm = bv.mk_bv_urem_i(x, y);
|
||||
|
@ -214,16 +214,29 @@ namespace polysat {
|
|||
// From "Hacker's Delight", section 2-2. Addition Combined with Logical Operations;
|
||||
// found via Int-Blasting paper; see https://doi.org/10.1007/978-3-030-94583-1_24
|
||||
// (p + q) - band(p, q);
|
||||
void solver::internalize_bor(app* n) {
|
||||
internalize_binary(n, [&](expr* const& x, expr* const& y) { return bv.mk_bv_sub(bv.mk_bv_add(x, y), bv.mk_bv_and(x, y)); });
|
||||
void solver::internalize_bor(app* n) {
|
||||
if (n->get_num_args() == 2) {
|
||||
expr* x, * y;
|
||||
VERIFY(bv.is_bv_or(n, x, y));
|
||||
m_core.bor(expr2pdd(x), expr2pdd(y), expr2pdd(n));
|
||||
}
|
||||
else {
|
||||
expr_ref z(n->get_arg(0), m);
|
||||
for (unsigned i = 1; i < n->get_num_args(); ++i) {
|
||||
z = bv.mk_bv_or(z, n->get_arg(i));
|
||||
ctx.internalize(z);
|
||||
}
|
||||
internalize_set(n, expr2pdd(z));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// From "Hacker's Delight", section 2-2. Addition Combined with Logical Operations;
|
||||
// found via Int-Blasting paper; see https://doi.org/10.1007/978-3-030-94583-1_24
|
||||
// (p + q) - 2*band(p, q);
|
||||
void solver::internalize_bxor(app* n) {
|
||||
internalize_binary(n, [&](expr* const& x, expr* const& y) {
|
||||
return bv.mk_bv_sub(bv.mk_bv_add(x, y), bv.mk_bv_add(bv.mk_bv_and(x, y), bv.mk_bv_and(x, y)));
|
||||
internalize_binary(n, [&](expr* const& x, expr* const& y) {
|
||||
return bv.mk_bv_sub(bv.mk_bv_add(x, y), bv.mk_bv_add(bv.mk_bv_and(x, y), bv.mk_bv_and(x, y)));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -279,7 +292,7 @@ namespace polysat {
|
|||
ctx.push(value_trail(m_delayed_axioms_qhead));
|
||||
for (; m_delayed_axioms_qhead < m_delayed_axioms.size() && !inconsistent(); ++m_delayed_axioms_qhead) {
|
||||
app* e = m_delayed_axioms[m_delayed_axioms_qhead];
|
||||
expr* x, *y;
|
||||
expr* x, * y;
|
||||
unsigned n = 0;
|
||||
if (bv.is_bv_sdiv(e, x, y))
|
||||
axiomatize_sdiv(e, x, y);
|
||||
|
@ -327,7 +340,7 @@ namespace polysat {
|
|||
rational N = rational::power_of_two(sz);
|
||||
add_axiom("int2bv", { eq_internalize(bv.mk_bv2int(e), m_autil.mk_mod(x, m_autil.mk_int(N))) });
|
||||
}
|
||||
|
||||
|
||||
void solver::axiomatize_bv2int(app* e, expr* x) {
|
||||
// e := bv2int(x)
|
||||
// e = sum_bits(x)
|
||||
|
@ -349,7 +362,7 @@ namespace polysat {
|
|||
return x;
|
||||
else
|
||||
return bv.mk_concat(bv.mk_extract(n, 0, x), bv.mk_extract(sz - 1, sz - n - 1, x));
|
||||
}
|
||||
}
|
||||
|
||||
void solver::axiomatize_rotate_left(app* e, unsigned n, expr* x) {
|
||||
// e = x[n : 0] ++ x[sz - 1, sz - n - 1]
|
||||
|
@ -398,9 +411,9 @@ namespace polysat {
|
|||
// else x - sdiv(x, y) * y
|
||||
void solver::axiomatize_srem(app* e, expr* x, expr* y) {
|
||||
unsigned sz = bv.get_bv_size(x);
|
||||
sat::literal y_eq0 = eq_internalize(y, bv.mk_zero(sz));
|
||||
sat::literal y_eq0 = eq_internalize(y, bv.mk_zero(sz));
|
||||
add_axiom("srem", { ~y_eq0, eq_internalize(e, x) });
|
||||
add_axiom("srem", { y_eq0, eq_internalize(e, bv.mk_bv_mul(bv.mk_bv_sdiv(x, y), y)) });
|
||||
add_axiom("srem", { y_eq0, eq_internalize(e, bv.mk_bv_mul(bv.mk_bv_sdiv(x, y), y)) });
|
||||
}
|
||||
|
||||
// u := umod(x, y)
|
||||
|
@ -442,10 +455,10 @@ namespace polysat {
|
|||
void solver::axiomatize_sdiv(app* e, expr* x, expr* y) {
|
||||
unsigned sz = bv.get_bv_size(x);
|
||||
rational N = rational::power_of_two(bv.get_bv_size(x));
|
||||
expr* signx = bv.mk_ule(bv.mk_numeral(N/2, sz), x);
|
||||
expr* signy = bv.mk_ule(bv.mk_numeral(N/2, sz), y);
|
||||
expr* absx = m.mk_ite(signx, bv.mk_bv_sub(bv.mk_numeral(N-1, sz), x), x);
|
||||
expr* absy = m.mk_ite(signy, bv.mk_bv_sub(bv.mk_numeral(N-1, sz), y), y);
|
||||
expr* signx = bv.mk_ule(bv.mk_numeral(N / 2, sz), x);
|
||||
expr* signy = bv.mk_ule(bv.mk_numeral(N / 2, sz), y);
|
||||
expr* absx = m.mk_ite(signx, bv.mk_bv_sub(bv.mk_numeral(N - 1, sz), x), x);
|
||||
expr* absy = m.mk_ite(signy, bv.mk_bv_sub(bv.mk_numeral(N - 1, sz), y), y);
|
||||
expr* d = bv.mk_bv_udiv(absx, absy);
|
||||
sat::literal lsignx = mk_literal(signx);
|
||||
sat::literal lsigny = mk_literal(signy);
|
||||
|
@ -457,10 +470,10 @@ namespace polysat {
|
|||
add_axiom(name, { y_eq0, ~lsignx, lsigny, eq_internalize(e, bv.mk_bv_neg(d)) });
|
||||
add_axiom(name, { y_eq0, lsignx, lsigny, eq_internalize(e, d) });
|
||||
add_axiom(name, { y_eq0, ~lsignx, ~lsigny, eq_internalize(e, d) });
|
||||
}
|
||||
}
|
||||
|
||||
void solver::internalize_urem_i(app* rem) {
|
||||
expr* x, *y;
|
||||
expr* x, * y;
|
||||
euf::enode* n = expr2enode(rem);
|
||||
SASSERT(n && n->is_attached_to(get_id()));
|
||||
theory_var v = n->get_th_var(get_id());
|
||||
|
@ -478,7 +491,7 @@ namespace polysat {
|
|||
m_var2pdd_valid.setx(v, false, false);
|
||||
quot_rem(quot, rem, x, y);
|
||||
}
|
||||
|
||||
|
||||
void solver::quot_rem(expr* quot, expr* rem, expr* x, expr* y) {
|
||||
pdd a = expr2pdd(x);
|
||||
pdd b = expr2pdd(y);
|
||||
|
@ -513,8 +526,8 @@ namespace polysat {
|
|||
internalize_set(quot, q);
|
||||
internalize_set(rem, r);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pdd r = var2pdd(rn->get_th_var(get_id()));
|
||||
pdd q = var2pdd(qn->get_th_var(get_id()));
|
||||
|
||||
|
@ -542,13 +555,13 @@ namespace polysat {
|
|||
}
|
||||
|
||||
void solver::internalize_sign_extend(app* e) {
|
||||
expr* arg = e->get_arg(0);
|
||||
expr* arg = e->get_arg(0);
|
||||
unsigned sz = bv.get_bv_size(e);
|
||||
unsigned arg_sz = bv.get_bv_size(arg);
|
||||
unsigned sz2 = sz - arg_sz;
|
||||
var2pdd(expr2enode(e)->get_th_var(get_id()));
|
||||
auto name = "sign extend";
|
||||
if (arg_sz == sz)
|
||||
if (arg_sz == sz)
|
||||
add_axiom(name, { eq_internalize(e, arg) });
|
||||
else {
|
||||
sat::literal lt0 = ctx.mk_literal(bv.mk_slt(arg, bv.mk_numeral(0, arg_sz)));
|
||||
|
@ -568,7 +581,7 @@ namespace polysat {
|
|||
auto name = "zero extend";
|
||||
if (arg_sz == sz)
|
||||
add_axiom(name, { eq_internalize(e, arg) });
|
||||
else
|
||||
else
|
||||
// e = concat(0...0, arg)
|
||||
add_axiom(name, { eq_internalize(e, bv.mk_concat(bv.mk_numeral(0, sz2), arg)) });
|
||||
}
|
||||
|
@ -593,13 +606,13 @@ namespace polysat {
|
|||
add_axiom(name, { ~eqZ, eqU });
|
||||
add_axiom(name, { eqZ, eqI });
|
||||
ctx.add_aux(~eqZ, eqU);
|
||||
ctx.add_aux(eqZ, eqI);
|
||||
ctx.add_aux(eqZ, eqI);
|
||||
}
|
||||
|
||||
void solver::internalize_num(app* a) {
|
||||
rational val;
|
||||
unsigned sz = 0;
|
||||
VERIFY(bv.is_numeral(a, val, sz));
|
||||
VERIFY(bv.is_numeral(a, val, sz));
|
||||
auto p = m_core.value(val, sz);
|
||||
internalize_set(a, p);
|
||||
}
|
||||
|
@ -630,7 +643,7 @@ namespace polysat {
|
|||
unsigned i = 0;
|
||||
for (expr* arg : *a) {
|
||||
expr_ref b2b(m);
|
||||
b2b = bv.mk_bit2bool(a, i);
|
||||
b2b = bv.mk_bit2bool(a, i);
|
||||
sat::literal bit_i = ctx.internalize(b2b, false, false);
|
||||
sat::literal lit = expr2literal(arg);
|
||||
equiv_axiom("mkbv", lit, bit_i);
|
||||
|
@ -656,10 +669,10 @@ namespace polysat {
|
|||
auto sz_e = hi - lo + 1;
|
||||
auto sz_x = bv.get_bv_size(x);
|
||||
auto eq0 = eq_internalize(e, bv.mk_numeral(0, sz_e));
|
||||
auto gelo = mk_literal(bv.mk_ule(bv.mk_numeral(rational::power_of_two(lo), sz_x), x));
|
||||
auto gelo = mk_literal(bv.mk_ule(bv.mk_numeral(rational::power_of_two(lo), sz_x), x));
|
||||
auto name = "extract";
|
||||
add_axiom(name, { eq0, gelo });
|
||||
if (hi + 1 == sz_e)
|
||||
if (hi + 1 == sz_e)
|
||||
add_axiom(name, { ~eq0, ~gelo });
|
||||
}
|
||||
|
||||
|
@ -681,7 +694,7 @@ namespace polysat {
|
|||
add_axiom("hi = 0 => concat(hi, lo) < 2^|lo|", neqs, false);
|
||||
neqs.pop_back();
|
||||
for (auto neq : neqs)
|
||||
add_axiom("concat(hi,lo) < 2^|lo| => hi = 0", {~neq, ~gtlo}); // hi = 0 or e >= 2^|lo|
|
||||
add_axiom("concat(hi,lo) < 2^|lo| => hi = 0", { ~neq, ~gtlo }); // hi = 0 or e >= 2^|lo|
|
||||
expr* lo = e->get_arg(i);
|
||||
auto sz_l = bv.get_bv_size(lo);
|
||||
neqs.push_back(~eq_internalize(lo, bv.mk_numeral(0, sz_l)));
|
||||
|
@ -696,7 +709,7 @@ namespace polysat {
|
|||
var2pdd(expr2enode(e)->get_th_var(get_id()));
|
||||
}
|
||||
|
||||
void solver::internalize_par_unary(app* e, std::function<pdd(pdd,unsigned)> const& fn) {
|
||||
void solver::internalize_par_unary(app* e, std::function<pdd(pdd, unsigned)> const& fn) {
|
||||
pdd const p = expr2pdd(e->get_arg(0));
|
||||
unsigned const par = e->get_parameter(0).get_int();
|
||||
internalize_set(e, fn(p, par));
|
||||
|
@ -705,7 +718,7 @@ namespace polysat {
|
|||
void solver::internalize_binary(app* e, std::function<pdd(pdd, pdd)> const& fn) {
|
||||
SASSERT(e->get_num_args() >= 1);
|
||||
auto p = expr2pdd(e->get_arg(0));
|
||||
for (unsigned i = 1; i < e->get_num_args(); ++i)
|
||||
for (unsigned i = 1; i < e->get_num_args(); ++i)
|
||||
p = fn(p, expr2pdd(e->get_arg(i)));
|
||||
internalize_set(e, p);
|
||||
}
|
||||
|
@ -735,7 +748,7 @@ namespace polysat {
|
|||
auto sc = Signed ? m_core.sle(p, q) : m_core.ule(p, q);
|
||||
if (Negated)
|
||||
sc = ~sc;
|
||||
|
||||
|
||||
sat::literal lit = expr2literal(e);
|
||||
if (lit.sign())
|
||||
sc = ~sc;
|
||||
|
@ -777,7 +790,7 @@ namespace polysat {
|
|||
if (!bv.is_bv(n->get_expr()))
|
||||
return;
|
||||
theory_var v = n->get_th_var(get_id());
|
||||
if (v == euf::null_theory_var)
|
||||
if (v == euf::null_theory_var)
|
||||
v = mk_var(n);
|
||||
var2pdd(v);
|
||||
}
|
||||
|
@ -824,7 +837,7 @@ namespace polysat {
|
|||
return elem.first;
|
||||
is_new = false;
|
||||
}
|
||||
auto sc = m_core.eq(p, q);
|
||||
auto sc = m_core.eq(p, q);
|
||||
idx = m_core.register_constraint(sc, d);
|
||||
if (is_new) {
|
||||
m_eq2constraint[sz].insert(r.index(), { idx, sign });
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue