3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-22 00:26:38 +00:00

Add lemma: y = x[h:l] & y != 0 ==> x >= 2^l

This commit is contained in:
Jakob Rath 2023-08-16 09:57:45 +02:00
parent afc292e5db
commit bc6f0729a0
4 changed files with 57 additions and 3 deletions

View file

@ -47,6 +47,7 @@ namespace polysat {
}
void saturation::perform(pvar v, conflict& core) {
LOG_H1("Saturation for v" << v << ", core: " << core);
IF_VERBOSE(2, verbose_stream() << "v" << v << " " << core << "\n");
for (signed_constraint c : core)
perform(v, c, core);
@ -73,6 +74,8 @@ namespace polysat {
bool prop = false;
if (s.size(v) != i.lhs().power_of_2())
return false;
if (try_nonzero_upper_extract(v, core, i))
prop = true;
if (try_mul_bounds(v, core, i))
prop = true;
if (try_parity(v, core, i))
@ -106,6 +109,44 @@ namespace polysat {
return prop;
}
bool saturation::try_nonzero_upper_extract(pvar y, conflict& core, inequality const& i) {
set_rule("y = x[h:l] & y != 0 ==> x >= 2^l");
if (!s.m_justification[y].is_propagation_by_slicing())
return false;
if (!s.get_value(y).is_zero())
return false;
if (!is_nonzero_by(y, i))
return false;
for (pvar x : core.vars()) {
if (!s.get_value(x).is_zero())
continue;
unsigned hi, lo;
if (!s.m_slicing.is_extract(y, x, hi, lo)) // TODO: generalize; use is_equal to check this and if yes, extract the explanation. otherwise it will only work in very limited cases.
continue;
if (propagate(y, core, i, s.ule(rational::power_of_two(lo), s.var(x))))
return true;
}
return false;
}
// TODO: can be generalized
bool saturation::is_nonzero_by(pvar x, inequality const& i) {
if (i.is_strict() && i.lhs().is_zero()) {
// 0 < p
pdd const& p = i.rhs();
if (p.is_val())
return false;
if (!p.lo().is_zero())
return false;
if (!p.hi().is_val())
return false;
SASSERT(!p.hi().is_zero());
// 0 < a*x for a != 0
return true;
}
return false;
}
bool saturation::try_umul_ovfl(pvar v, signed_constraint c, conflict& core) {
SASSERT(c->is_umul_ovfl());
bool prop = false;
@ -526,8 +567,8 @@ namespace polysat {
return false;
}
bool saturation::is_forced_diseq(pdd const& p, int i, signed_constraint& c) {
c = s.eq(p, i);
bool saturation::is_forced_diseq(pdd const& p, rational const& val, signed_constraint& c) {
c = s.eq(p, val);
return is_forced_false(c);
}

View file

@ -121,6 +121,8 @@ namespace polysat {
bool try_infer_parity_equality(pvar x, conflict& core, inequality const& a_l_b);
bool try_div_monotonicity(conflict& core);
bool try_nonzero_upper_extract(pvar v, conflict& core, inequality const& i);
rational round(rational const& M, rational const& x);
bool eval_round(rational const& M, pdd const& p, rational& r);
bool extract_linear_form(pdd const& q, pvar& y, rational& a, rational& b);
@ -199,6 +201,9 @@ namespace polysat {
bool has_lower_bound(pvar x, conflict& core, rational& bound, vector<signed_constraint>& x_le_bound);
// inequality i implies x != 0
bool is_nonzero_by(pvar x, inequality const& i);
// determine min/max parity of polynomial
unsigned min_parity(pdd const& p, vector<signed_constraint>& explain);
unsigned max_parity(pdd const& p, vector<signed_constraint>& explain);
@ -210,7 +215,8 @@ namespace polysat {
bool is_forced_eq(pdd const& p, rational const& val);
bool is_forced_eq(pdd const& p, int i) { return is_forced_eq(p, rational(i)); }
bool is_forced_diseq(pdd const& p, int i, signed_constraint& c);
bool is_forced_diseq(pdd const& p, rational const& val, signed_constraint& c);
bool is_forced_diseq(pdd const& p, int i, signed_constraint& c) { return is_forced_diseq(p, rational(i), c); }
bool is_forced_odd(pdd const& p, signed_constraint& c);

View file

@ -834,6 +834,10 @@ namespace polysat {
}
}
bool slicing::is_extract(pvar x, pvar src, unsigned& out_hi, unsigned& out_lo) {
return find_range_in_ancestor(var2slice(x), var2slice(src), out_hi, out_lo);
}
void slicing::egraph_on_merge(enode* root, enode* other) {
SASSERT(!is_value(other)); // by convention, interpreted nodes are always chosen as root
if (is_value(root)) {

View file

@ -320,6 +320,9 @@ namespace polysat {
pvar mk_concat(unsigned num_args, pvar const* args) { return mk_concat(num_args, args, null_var); }
pvar mk_concat(std::initializer_list<pvar> args);
// Find hi, lo such that x = src[hi:lo].
bool is_extract(pvar x, pvar src, unsigned& out_hi, unsigned& out_lo);
// Track value assignments to variables (and propagate to subslices)
// (could generalize to fixed bits, then we need a way to merge interpreted enodes)
void add_value(pvar v, rational const& value);