mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 08:35:31 +00:00
update names and nature of multiplication blast rules
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
60add85c47
commit
88b315cdb0
5 changed files with 54 additions and 22 deletions
|
@ -88,6 +88,10 @@ namespace polysat {
|
|||
return eq(p * rational::power_of_two(N - k));
|
||||
}
|
||||
|
||||
signed_constraint constraints::parity_at_most(pdd const& p, unsigned k) {
|
||||
return ~parity_at_least(p, k + 1);
|
||||
}
|
||||
|
||||
// 2^{N-i-1}* p >= 2^{N-1}
|
||||
signed_constraint constraints::bit(pdd const& p, unsigned i) {
|
||||
unsigned N = p.manager().power_of_2();
|
||||
|
|
|
@ -169,6 +169,7 @@ namespace polysat {
|
|||
signed_constraint umul_ovfl(unsigned p, pdd const& q) { return umul_ovfl(rational(p), q); }
|
||||
|
||||
signed_constraint parity_at_least(pdd const& p, unsigned k);
|
||||
signed_constraint parity_at_most(pdd const& p, unsigned k);
|
||||
|
||||
signed_constraint lshr(pdd const& a, pdd const& b, pdd const& r);
|
||||
signed_constraint ashr(pdd const& a, pdd const& b, pdd const& r);
|
||||
|
|
|
@ -66,12 +66,12 @@ namespace polysat {
|
|||
return l_false;
|
||||
if (any_of(m_to_refine, [&](auto i) { return mul1(m_monomials[i]); }))
|
||||
return l_false;
|
||||
if (any_of(m_to_refine, [&](auto i) { return mul1_inverse(m_monomials[i]); }))
|
||||
if (any_of(m_to_refine, [&](auto i) { return mul_parametric_inverse(m_monomials[i]); }))
|
||||
return l_false;
|
||||
|
||||
if (any_of(m_to_refine, [&](auto i) { return non_overflow_unit(m_monomials[i]); }))
|
||||
if (any_of(m_to_refine, [&](auto i) { return mul1_inverse(m_monomials[i]); }))
|
||||
return l_false;
|
||||
if (any_of(m_to_refine, [&](auto i) { return non_overflow_zero(m_monomials[i]); }))
|
||||
if (any_of(m_to_refine, [&](auto i) { return mul0_inverse(m_monomials[i]); }))
|
||||
return l_false;
|
||||
if (false && any_of(m_to_refine, [&](auto i) { return parity0(m_monomials[i]); }))
|
||||
return l_false;
|
||||
|
@ -171,19 +171,32 @@ namespace polysat {
|
|||
return c.add_axiom("p = k => p * q = k * q", cs, true);
|
||||
}
|
||||
|
||||
// p * q = p => q = 1 or p = 0
|
||||
//
|
||||
// In general not true, because there exist a, b >= 2 with a * b = 0; then (a+1) * b = b.
|
||||
// For now, add no-overflow condition on p*q.
|
||||
bool monomials::mul1_inverse(monomial const& mon) {
|
||||
// p * q = p => parity(q - 1) + parity(p) >= N
|
||||
// p * q = p & ~Ovfl(p,q) => q = 1 or p = 0
|
||||
bool monomials::mul_parametric_inverse(monomial const& mon) {
|
||||
for (unsigned j = mon.size(); j-- > 0; ) {
|
||||
auto const& arg_val = mon.arg_vals[j];
|
||||
if (arg_val == mon.val) {
|
||||
auto const& p = mon.args[j];
|
||||
pdd qs = c.value(rational(1), mon.num_bits());
|
||||
rational qv(1);
|
||||
for (unsigned k = mon.size(); k-- > 0; )
|
||||
if (k != j)
|
||||
qs *= mon.args[k];
|
||||
if (k != j)
|
||||
qs *= mon.args[k], qv *= mon.arg_vals[k];
|
||||
|
||||
if (qv == 0) {
|
||||
if (c.add_axiom("q = 0 & p * q = p => p = 0", { ~C.eq(qs), ~C.eq(mon.var, p), C.eq(p)}, true))
|
||||
return true;
|
||||
continue;
|
||||
}
|
||||
qv = qv - 1;
|
||||
unsigned qb = qv.get_num_bits();
|
||||
unsigned pb = arg_val.get_num_bits();
|
||||
unsigned N = p.manager().power_of_2();
|
||||
if (qb + pb < N) {
|
||||
if (c.add_axiom("p * q = p => parity(q - 1) + parity(p) >= N", { ~C.eq(mon.var, p), ~C.parity_at_most(p, pb), C.parity_at_least(qs - 1, N - pb) }, true))
|
||||
return true;
|
||||
}
|
||||
if (c.add_axiom("p * q = p => q = 1 or p = 0", { ~C.eq(mon.var, p), ~C.umul_ovfl(p, qs), C.eq(qs, 1), C.eq(p) }, true))
|
||||
return true;
|
||||
}
|
||||
|
@ -234,8 +247,21 @@ namespace polysat {
|
|||
return c.add_axiom("~ovfl*(p,q) & q != 0 => p <= p*q", clause, true);
|
||||
}
|
||||
|
||||
// p * q = 1 => parity(p) = 0 (instance of parity(p*q) >= min(N, parity(p) + parity(q))
|
||||
// ~ovfl*(p,q) & p*q = 1 => p = 1, q = 1
|
||||
bool monomials::non_overflow_unit(monomial const& mon) {
|
||||
bool monomials::mul1_inverse(monomial const& mon) {
|
||||
if (!mon.val.is_odd())
|
||||
return false;
|
||||
|
||||
unsigned j = 0;
|
||||
for (auto const& val : mon.arg_vals) {
|
||||
if (val.is_even()) {
|
||||
if (c.add_axiom("odd(p*q) => odd(p)",
|
||||
{~C.parity_at_most(mon.var, 0), C.parity_at_most(mon.args[j], 0) }, true))
|
||||
return true;
|
||||
}
|
||||
++j;
|
||||
}
|
||||
if (mon.val != 1)
|
||||
return false;
|
||||
rational product(1);
|
||||
|
@ -260,8 +286,11 @@ namespace polysat {
|
|||
return new_axiom;
|
||||
}
|
||||
|
||||
|
||||
// p*q = 0 => parity(p) + parity(q) >= N
|
||||
// TODO: update to use parity instead of overflow
|
||||
// ~ovfl*(p,q) & p*q = 0 => p = 0 or q = 0
|
||||
bool monomials::non_overflow_zero(monomial const& mon) {
|
||||
bool monomials::mul0_inverse(monomial const& mon) {
|
||||
if (mon.val != 0)
|
||||
return false;
|
||||
for (auto const& val : mon.arg_vals)
|
||||
|
|
|
@ -49,12 +49,12 @@ namespace polysat {
|
|||
bool mul0(monomial const& mon);
|
||||
bool mul1(monomial const& mon);
|
||||
bool mulp2(monomial const& mon);
|
||||
bool mul1_inverse(monomial const& mon);
|
||||
bool mul_parametric_inverse(monomial const& mon);
|
||||
bool mul(monomial const& mon, std::function<bool(rational const&)> const& p);
|
||||
bool parity(monomial const& mon);
|
||||
bool non_overflow_monotone(monomial const& mon);
|
||||
bool non_overflow_unit(monomial const& mon);
|
||||
bool non_overflow_zero(monomial const& mon);
|
||||
bool mul1_inverse(monomial const& mon);
|
||||
bool mul0_inverse(monomial const& mon);
|
||||
bool parity0(monomial const& mon);
|
||||
bool prefix_overflow(monomial const& mon);
|
||||
|
||||
|
|
|
@ -268,7 +268,7 @@ namespace polysat {
|
|||
add_clause("~Ovfl(x, y) & x <= y => x < 2^{(N + 1) div 2}",
|
||||
{ d, ~C.ule(x, y), C.ult(x, rational::power_of_two((N + 1) / 2)) },
|
||||
true);
|
||||
}
|
||||
}
|
||||
else if (bx + by > N + 1)
|
||||
add_clause("~Ovfl(x, y) & msb(x) >= k => msb(y) <= N - k - 1",
|
||||
{d, ~msb_ge(x, k), msb_le(y, N - k - 1)},
|
||||
|
@ -276,11 +276,9 @@ namespace polysat {
|
|||
else {
|
||||
auto x1 = c.mk_zero_extend(1, x);
|
||||
auto y1 = c.mk_zero_extend(1, y);
|
||||
add_clause("~Ovfl(x, y) & msb(x) >= k & msb(y) >= N - k - 1 => 0x * 0y < 2^{N-1}",
|
||||
{ d, ~msb_ge(x, k),
|
||||
~msb_ge(y, N - k - 1),
|
||||
C.ult(x1 * y1, rational::power_of_two(N - 1))
|
||||
}, true);
|
||||
add_clause("~Ovfl(x, y) => 0x * 0y < 2^{N}",
|
||||
{ d, C.ult(x1 * y1, rational::power_of_two(N)) },
|
||||
true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -303,7 +301,7 @@ namespace polysat {
|
|||
auto k = bx - 1;
|
||||
auto x1 = c.mk_zero_extend(1, x);
|
||||
auto y1 = c.mk_zero_extend(1, y);
|
||||
add_clause("Ovfl(x, y) & msb(x) <= k & msb(y) <= N - k - 1 = > 0x * 0y >= 2 ^ {N - 1}",
|
||||
add_clause("Ovfl(x, y) & msb(x) <= k & msb(y) <= N - k - 1 => 0x * 0y >= 2 ^ {N - 1}",
|
||||
{ d, ~msb_le(x, k), ~msb_le(y, N - k - 1), C.uge(x1 * y1, rational::power_of_two(N - 1)) },
|
||||
true);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue