mirror of
https://github.com/Z3Prover/z3
synced 2025-08-07 19:51:22 +00:00
add hooks for multiplication overflow
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
d18a2427a4
commit
4e0604bc22
3 changed files with 72 additions and 5 deletions
|
@ -54,11 +54,8 @@ namespace polysat {
|
||||||
auto i = inequality::from_ule(c);
|
auto i = inequality::from_ule(c);
|
||||||
return try_inequality(v, i, core);
|
return try_inequality(v, i, core);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (c->is_umul_ovfl())
|
if (c->is_umul_ovfl())
|
||||||
return try_umul_ovfl(v, c, core);
|
return try_umul_ovfl(v, c, core);
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,6 +93,24 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool saturation::try_umul_ovfl(pvar v, signed_constraint const& c, conflict& core) {
|
bool saturation::try_umul_ovfl(pvar v, signed_constraint const& c, conflict& core) {
|
||||||
|
#if 1
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
SASSERT(c->is_umul_ovfl());
|
||||||
|
bool prop = false;
|
||||||
|
if (c.is_positive()) {
|
||||||
|
prop = try_umul_ovfl_bounds(v, c, core);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
prop = try_umul_noovfl_bounds(v, c, core);
|
||||||
|
if (false && try_umul_noovfl_lo(v, c, core))
|
||||||
|
prop = true;
|
||||||
|
}
|
||||||
|
return prop;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool saturation::try_umul_noovfl_lo(pvar v, signed_constraint const& c, conflict& core) {
|
||||||
set_rule("[x] ~ovfl(x, y) => y = 0 or x <= x * y");
|
set_rule("[x] ~ovfl(x, y) => y = 0 or x <= x * y");
|
||||||
SASSERT(c->is_umul_ovfl());
|
SASSERT(c->is_umul_ovfl());
|
||||||
if (!c.is_negative())
|
if (!c.is_negative())
|
||||||
|
@ -117,6 +132,54 @@ namespace polysat {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ~ovfl(p, q) & p >= k => q < 2^N/k
|
||||||
|
*/
|
||||||
|
bool saturation::try_umul_noovfl_bounds(pvar x, signed_constraint const& c, conflict& core) {
|
||||||
|
set_rule("[x] ~ovfl(x, q) & x >= k => q <= (2^N-1)/k");
|
||||||
|
SASSERT(c->is_umul_ovfl());
|
||||||
|
SASSERT(c.is_negative());
|
||||||
|
auto const& ovfl = c->to_umul_ovfl();
|
||||||
|
auto p = ovfl.p(), q = ovfl.q();
|
||||||
|
auto X = s.var(x);
|
||||||
|
auto& m = p.manager();
|
||||||
|
rational p_val, q_val;
|
||||||
|
if (q == X)
|
||||||
|
std::swap(p, q);
|
||||||
|
if (p == X) {
|
||||||
|
vector<signed_constraint> x_ge_bound;
|
||||||
|
if (!s.try_eval(q, q_val))
|
||||||
|
return false;
|
||||||
|
if (!has_lower_bound(x, core, p_val, x_ge_bound))
|
||||||
|
return false;
|
||||||
|
if (p_val * q_val <= m.max_value())
|
||||||
|
return false;
|
||||||
|
m_lemma.reset();
|
||||||
|
m_lemma.insert_eval(~s.uge(X, p_val));
|
||||||
|
signed_constraint conseq = s.ule(q, floor(m.max_value()/p_val));
|
||||||
|
return propagate(x, core, c, conseq);
|
||||||
|
}
|
||||||
|
if (!s.try_eval(p, p_val) || !s.try_eval(q, q_val))
|
||||||
|
return false;
|
||||||
|
if (p_val * q_val <= m.max_value())
|
||||||
|
return false;
|
||||||
|
m_lemma.reset();
|
||||||
|
m_lemma.insert_eval(~s.uge(q, q_val));
|
||||||
|
signed_constraint conseq = s.ule(p, floor(m.max_value()/q_val));
|
||||||
|
return propagate(x, core, c, conseq);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ovfl(p, q) & p <= k => q > 2^N/k
|
||||||
|
*/
|
||||||
|
bool saturation::try_umul_ovfl_bounds(pvar v, signed_constraint const& c, conflict& core) {
|
||||||
|
SASSERT(c->is_umul_ovfl());
|
||||||
|
SASSERT(c.is_positive());
|
||||||
|
auto const& ovfl = c->to_umul_ovfl();
|
||||||
|
auto p = ovfl.p(), q = ovfl.q();
|
||||||
|
rational p_val, q_val;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
signed_constraint saturation::ineq(bool is_strict, pdd const& lhs, pdd const& rhs) {
|
signed_constraint saturation::ineq(bool is_strict, pdd const& lhs, pdd const& rhs) {
|
||||||
if (is_strict)
|
if (is_strict)
|
||||||
|
@ -1313,10 +1376,12 @@ namespace polysat {
|
||||||
}
|
}
|
||||||
// verbose_stream() << "TODO bound 1 " << a_l_b << " " << x_ge_bound << " " << b << " " << b_val << " " << y << "\n";
|
// verbose_stream() << "TODO bound 1 " << a_l_b << " " << x_ge_bound << " " << b << " " << b_val << " " << y << "\n";
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
if (has_lower_bound(x, core, x_bound, x_le_bound) && !x_le_bound.contains(a_l_b.as_signed_constraint())) {
|
if (has_lower_bound(x, core, x_bound, x_le_bound) && !x_le_bound.contains(a_l_b.as_signed_constraint())) {
|
||||||
|
|
||||||
// verbose_stream() << "TODO bound 2 " << a_l_b << " " << x_le_bound << "\n";
|
// verbose_stream() << "TODO bound 2 " << a_l_b << " " << x_le_bound << "\n";
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (is_Y_l_AxB(x, a_l_b, y, a, b) && y.is_val() && s.try_eval(b, b_val)) {
|
if (is_Y_l_AxB(x, a_l_b, y, a, b) && y.is_val() && s.try_eval(b, b_val)) {
|
||||||
// verbose_stream() << "TODO bound 3 " << a_l_b << "\n";
|
// verbose_stream() << "TODO bound 3 " << a_l_b << "\n";
|
||||||
|
|
|
@ -142,6 +142,9 @@ namespace polysat {
|
||||||
bool try_inequality(pvar v, inequality const& i, conflict& core);
|
bool try_inequality(pvar v, inequality const& i, conflict& core);
|
||||||
|
|
||||||
bool try_umul_ovfl(pvar v, signed_constraint const& c, conflict& core);
|
bool try_umul_ovfl(pvar v, signed_constraint const& c, conflict& core);
|
||||||
|
bool try_umul_noovfl_lo(pvar v, signed_constraint const& c, conflict& core);
|
||||||
|
bool try_umul_noovfl_bounds(pvar v, signed_constraint const& c, conflict& core);
|
||||||
|
bool try_umul_ovfl_bounds(pvar v, signed_constraint const& c, conflict& core);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
saturation(solver& s);
|
saturation(solver& s);
|
||||||
|
|
|
@ -675,7 +675,6 @@ namespace polysat {
|
||||||
return !out_c.empty();
|
return !out_c.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TBD: generalize to multiple intervals similar to upper bound
|
|
||||||
bool viable::has_lower_bound(pvar v, rational& out_lo, vector<signed_constraint>& out_c) {
|
bool viable::has_lower_bound(pvar v, rational& out_lo, vector<signed_constraint>& out_c) {
|
||||||
entry const* first = m_units[v];
|
entry const* first = m_units[v];
|
||||||
entry const* e = first;
|
entry const* e = first;
|
||||||
|
@ -688,7 +687,7 @@ namespace polysat {
|
||||||
auto const& lo = e->interval.lo();
|
auto const& lo = e->interval.lo();
|
||||||
auto const& hi = e->interval.hi();
|
auto const& hi = e->interval.hi();
|
||||||
if (lo.is_val() && hi.is_val()) {
|
if (lo.is_val() && hi.is_val()) {
|
||||||
if (out_c.empty() && (lo.val() == 0 || lo.val() > hi.val())) {
|
if (out_c.empty() && hi.val() != 0 && (lo.val() == 0 || lo.val() > hi.val())) {
|
||||||
out_c.push_back(e->src);
|
out_c.push_back(e->src);
|
||||||
out_lo = hi.val();
|
out_lo = hi.val();
|
||||||
found = true;
|
found = true;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue