mirror of
https://github.com/Z3Prover/z3
synced 2025-08-23 19:47:52 +00:00
handle non-linear division axioms, consolidate backtracking state in nla_core
this update enables new incremental linear axioms based on division terms. It also consolidates some of the backtracking state in nla_core / emons to use stack traces instead of custom backtracking state.
This commit is contained in:
parent
4ffe3fab05
commit
8e37e2f913
9 changed files with 196 additions and 81 deletions
|
@ -23,43 +23,128 @@ namespace nla {
|
|||
m_core.trail().push(push_back_vector(m_idivisions));
|
||||
}
|
||||
|
||||
void divisions::add_rdivision(lpvar r, lpvar x, lpvar y) {
|
||||
m_rdivisions.push_back({ r, x, y });
|
||||
m_core.trail().push(push_back_vector(m_rdivisions));
|
||||
}
|
||||
|
||||
typedef lp::lar_term term;
|
||||
|
||||
// y1 >= y2 > 0 & x1 <= x2 => x1/y1 <= x2/y2
|
||||
// y2 <= y1 < 0 & x1 >= x2 => x1/y1 <= x2/y2
|
||||
// y2 <= y1 < 0 & x1 >= x2 >= 0 => x1/y1 <= x2/y2
|
||||
// y2 <= y1 < 0 & x1 <= x2 <= 0 => x1/y1 >= x2/y2
|
||||
|
||||
void divisions::check(vector<lemma>& lemmas) {
|
||||
core& c = m_core;
|
||||
if (c.use_nra_model())
|
||||
return;
|
||||
|
||||
auto monotonicity1 = [&](auto x1, auto& x1val, auto y1, auto& y1val, auto& r1, auto& r1val,
|
||||
auto x2, auto& x2val, auto y2, auto& y2val, auto& r2, auto& r2val) {
|
||||
if (y1val >= y2val && y2val > 0 && x1val <= x2val && r1val > r2val) {
|
||||
new_lemma lemma(c, "y1 >= y2 > 0 & x1 <= x2 => x1/y1 <= x2/y2");
|
||||
lemma |= ineq(term(y1, rational(-1), y2), llc::LT, 0);
|
||||
lemma |= ineq(y2, llc::LE, 0);
|
||||
lemma |= ineq(term(x1, rational(-1), x2), llc::GT, 0);
|
||||
lemma |= ineq(term(r1, rational(-1), r2), llc::LE, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
auto monotonicity2 = [&](auto x1, auto& x1val, auto y1, auto& y1val, auto& r1, auto& r1val,
|
||||
auto x2, auto& x2val, auto y2, auto& y2val, auto& r2, auto& r2val) {
|
||||
if (y2val <= y1val && y1val < 0 && x1val >= x2val && x2val >= 0 && r1val > r2val) {
|
||||
new_lemma lemma(c, "y2 <= y1 < 0 & x1 >= x2 >= 0 => x1/y1 <= x2/y2");
|
||||
lemma |= ineq(term(y1, rational(-1), y2), llc::LT, 0);
|
||||
lemma |= ineq(y1, llc::GE, 0);
|
||||
lemma |= ineq(term(x1, rational(-1), x2), llc::LT, 0);
|
||||
lemma |= ineq(x2, llc::LT, 0);
|
||||
lemma |= ineq(term(r1, rational(-1), r2), llc::LE, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
auto monotonicity3 = [&](auto x1, auto& x1val, auto y1, auto& y1val, auto& r1, auto& r1val,
|
||||
auto x2, auto& x2val, auto y2, auto& y2val, auto& r2, auto& r2val) {
|
||||
if (y2val <= y1val && y1val < 0 && x1val <= x2val && x2val <= 0 && r1val < r2val) {
|
||||
new_lemma lemma(c, "y2 <= y1 < 0 & x1 <= x2 <= 0 => x1/y1 >= x2/y2");
|
||||
lemma |= ineq(term(y1, rational(-1), y2), llc::LT, 0);
|
||||
lemma |= ineq(y1, llc::GE, 0);
|
||||
lemma |= ineq(term(x1, rational(-1), x2), llc::GT, 0);
|
||||
lemma |= ineq(x2, llc::GT, 0);
|
||||
lemma |= ineq(term(r1, rational(-1), r2), llc::GE, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
auto monotonicity = [&](auto x1, auto& x1val, auto y1, auto& y1val, auto& r1, auto& r1val,
|
||||
auto x2, auto& x2val, auto y2, auto& y2val, auto& r2, auto& r2val) {
|
||||
if (monotonicity1(x1, x1val, y1, y1val, r1, r1val, x2, x2val, y2, y2val, r2, r2val))
|
||||
return true;
|
||||
if (monotonicity1(x2, x2val, y2, y2val, r2, r2val, x1, x1val, y1, y1val, r1, r1val))
|
||||
return true;
|
||||
if (monotonicity2(x1, x1val, y1, y1val, r1, r1val, x2, x2val, y2, y2val, r2, r2val))
|
||||
return true;
|
||||
if (monotonicity2(x2, x2val, y2, y2val, r2, r2val, x1, x1val, y1, y1val, r1, r1val))
|
||||
return true;
|
||||
if (monotonicity3(x1, x1val, y1, y1val, r1, r1val, x2, x2val, y2, y2val, r2, r2val))
|
||||
return true;
|
||||
if (monotonicity3(x2, x2val, y2, y2val, r2, r2val, x1, x1val, y1, y1val, r1, r1val))
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
for (auto const & [r, x, y] : m_idivisions) {
|
||||
if (!c.is_relevant(r))
|
||||
continue;
|
||||
auto xval = c.val(x);
|
||||
auto yval = c.val(y);
|
||||
auto rval = c.val(r);
|
||||
if (!c.var_is_int(x))
|
||||
continue;
|
||||
if (yval == 0)
|
||||
continue;
|
||||
// idiv semantics
|
||||
if (rval == div(xval, yval))
|
||||
if (!xval.is_int() || !yval.is_int() || yval == 0 || rval == div(xval, yval))
|
||||
continue;
|
||||
for (auto const& [r2, x2, y2] : m_idivisions) {
|
||||
if (r2 == r)
|
||||
continue;
|
||||
if (!c.is_relevant(r2))
|
||||
continue;
|
||||
auto x2val = c.val(x2);
|
||||
auto y2val = c.val(y2);
|
||||
auto r2val = c.val(r2);
|
||||
if (yval >= y2val && y2val > 0 && xval <= x2val && rval > r2val) {
|
||||
new_lemma lemma(c, "y1 >= y2 > 0 & x1 <= x2 => x1/y1 <= x2/y2");
|
||||
lemma |= ineq(term(y, rational(-1), y2), llc::LT, rational::zero());
|
||||
lemma |= ineq(y2, llc::LE, rational::zero());
|
||||
lemma |= ineq(term(x, rational(-1), x2), llc::GT, rational::zero());
|
||||
lemma |= ineq(term(r, rational(-1), r2), llc::LE, rational::zero());
|
||||
if (monotonicity(x, xval, y, yval, r, rval, x2, x2val, y2, y2val, r2, r2val))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& [r, x, y] : m_rdivisions) {
|
||||
if (!c.is_relevant(r))
|
||||
continue;
|
||||
auto xval = c.val(x);
|
||||
auto yval = c.val(y);
|
||||
auto rval = c.val(r);
|
||||
// / semantics
|
||||
if (yval == 0 || rval == xval / yval)
|
||||
continue;
|
||||
for (auto const& [r2, x2, y2] : m_rdivisions) {
|
||||
if (r2 == r)
|
||||
continue;
|
||||
if (!c.is_relevant(r2))
|
||||
continue;
|
||||
auto x2val = c.val(x2);
|
||||
auto y2val = c.val(y2);
|
||||
auto r2val = c.val(r2);
|
||||
if (monotonicity(x, xval, y, yval, r, rval, x2, x2val, y2, y2val, r2, r2val))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if p is bounded, q a value, r = eval(p):
|
||||
// p <= q * div(r, q) + q - 1 => div(p, q) <= div(r, q)
|
||||
// p >= q * div(r, q) => div(r, q) <= div(p, q)
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue