mirror of
https://github.com/Z3Prover/z3
synced 2025-04-26 10:35:33 +00:00
handle root expressions, and checking exponentiation with nlsat
this one is for you @matthai
This commit is contained in:
parent
2fe2735b5e
commit
ff920ba51b
2 changed files with 131 additions and 61 deletions
|
@ -80,113 +80,175 @@ namespace nla {
|
||||||
|
|
||||||
lbool powers::check(lpvar r, lpvar x, lpvar y, vector<lemma>& lemmas) {
|
lbool powers::check(lpvar r, lpvar x, lpvar y, vector<lemma>& lemmas) {
|
||||||
TRACE("nla", tout << r << " == " << x << "^" << y << "\n");
|
TRACE("nla", tout << r << " == " << x << "^" << y << "\n");
|
||||||
core& c = m_core;
|
core& c = m_core;
|
||||||
if (x == null_lpvar || y == null_lpvar || r == null_lpvar)
|
if (x == null_lpvar || y == null_lpvar || r == null_lpvar)
|
||||||
return l_undef;
|
return l_undef;
|
||||||
if (c.lra.column_has_term(x) || c.lra.column_has_term(y) || c.lra.column_has_term(r))
|
// if (c.lra.column_has_term(x) || c.lra.column_has_term(y) || c.lra.column_has_term(r))
|
||||||
return l_undef;
|
// return l_undef;
|
||||||
|
|
||||||
if (c.use_nra_model())
|
|
||||||
return l_undef;
|
|
||||||
|
|
||||||
auto xval = c.val(x);
|
|
||||||
auto yval = c.val(y);
|
|
||||||
auto rval = c.val(r);
|
|
||||||
|
|
||||||
lemmas.reset();
|
lemmas.reset();
|
||||||
|
|
||||||
if (xval != 0 && yval == 0 && rval != 1) {
|
auto x_exp_0 = [&]() {
|
||||||
new_lemma lemma(c, "x != 0 => x^0 = 1");
|
new_lemma lemma(c, "x != 0 => x^0 = 1");
|
||||||
lemma |= ineq(x, llc::EQ, rational::zero());
|
lemma |= ineq(x, llc::EQ, rational::zero());
|
||||||
lemma |= ineq(y, llc::NE, rational::zero());
|
lemma |= ineq(y, llc::NE, rational::zero());
|
||||||
lemma |= ineq(r, llc::EQ, rational::one());
|
lemma |= ineq(r, llc::EQ, rational::one());
|
||||||
return l_false;
|
return l_false;
|
||||||
}
|
};
|
||||||
|
|
||||||
if (xval == 0 && yval != 0 && rval != 0) {
|
auto zero_exp_y = [&]() {
|
||||||
new_lemma lemma(c, "y != 0 => 0^y = 0");
|
new_lemma lemma(c, "y != 0 => 0^y = 0");
|
||||||
lemma |= ineq(x, llc::NE, rational::zero());
|
lemma |= ineq(x, llc::NE, rational::zero());
|
||||||
lemma |= ineq(y, llc::EQ, rational::zero());
|
lemma |= ineq(y, llc::EQ, rational::zero());
|
||||||
lemma |= ineq(r, llc::EQ, rational::zero());
|
lemma |= ineq(r, llc::EQ, rational::zero());
|
||||||
return l_false;
|
return l_false;
|
||||||
}
|
};
|
||||||
|
|
||||||
if (xval > 0 && rval <= 0) {
|
auto x_gt_0 = [&]() {
|
||||||
new_lemma lemma(c, "x > 0 => x^y > 0");
|
new_lemma lemma(c, "x > 0 => x^y > 0");
|
||||||
lemma |= ineq(x, llc::LE, rational::zero());
|
lemma |= ineq(x, llc::LE, rational::zero());
|
||||||
lemma |= ineq(r, llc::GT, rational::zero());
|
lemma |= ineq(r, llc::GT, rational::zero());
|
||||||
return l_false;
|
return l_false;
|
||||||
}
|
};
|
||||||
|
|
||||||
if (xval > 1 && yval < 0 && rval >= 1) {
|
auto y_lt_1 = [&]() {
|
||||||
new_lemma lemma(c, "x > 1, y < 0 => x^y < 1");
|
new_lemma lemma(c, "x > 1, y < 0 => x^y < 1");
|
||||||
lemma |= ineq(x, llc::LE, rational::one());
|
lemma |= ineq(x, llc::LE, rational::one());
|
||||||
lemma |= ineq(y, llc::GE, rational::zero());
|
lemma |= ineq(y, llc::GE, rational::zero());
|
||||||
lemma |= ineq(r, llc::LT, rational::one());
|
lemma |= ineq(r, llc::LT, rational::one());
|
||||||
return l_false;
|
return l_false;
|
||||||
}
|
};
|
||||||
|
|
||||||
if (xval > 1 && yval > 0 && rval <= 1) {
|
auto y_gt_1 = [&]() {
|
||||||
new_lemma lemma(c, "x > 1, y > 0 => x^y > 1");
|
new_lemma lemma(c, "x > 1, y > 0 => x^y > 1");
|
||||||
lemma |= ineq(x, llc::LE, rational::one());
|
lemma |= ineq(x, llc::LE, rational::one());
|
||||||
lemma |= ineq(y, llc::LE, rational::zero());
|
lemma |= ineq(y, llc::LE, rational::zero());
|
||||||
lemma |= ineq(r, llc::GT, rational::one());
|
lemma |= ineq(r, llc::GT, rational::one());
|
||||||
return l_false;
|
return l_false;
|
||||||
}
|
};
|
||||||
|
|
||||||
if (xval >= 3 && yval != 0 && rval <= yval + 1) {
|
auto x_ge_3 = [&]() {
|
||||||
new_lemma lemma(c, "x >= 3, y != 0 => x^y > ln(x)y + 1");
|
new_lemma lemma(c, "x >= 3, y != 0 => x^y > ln(x)y + 1");
|
||||||
lemma |= ineq(x, llc::LT, rational(3));
|
lemma |= ineq(x, llc::LT, rational(3));
|
||||||
lemma |= ineq(y, llc::EQ, rational::zero());
|
lemma |= ineq(y, llc::EQ, rational::zero());
|
||||||
lemma |= ineq(lp::lar_term(r, rational::minus_one(), y), llc::GT, rational::one());
|
lemma |= ineq(lp::lar_term(r, rational::minus_one(), y), llc::GT, rational::one());
|
||||||
return l_false;
|
return l_false;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool use_rational = !c.use_nra_model();
|
||||||
|
rational xval, yval, rval;
|
||||||
|
if (use_rational) {
|
||||||
|
xval = c.val(x);
|
||||||
|
yval = c.val(y);
|
||||||
|
rval = c.val(r);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto& am = c.m_nra.am();
|
||||||
|
if (am.is_rational(c.m_nra.value(x)) &&
|
||||||
|
am.is_rational(c.m_nra.value(y)) &&
|
||||||
|
am.is_rational(c.m_nra.value(r))) {
|
||||||
|
am.to_rational(c.m_nra.value(x), xval);
|
||||||
|
am.to_rational(c.m_nra.value(y), yval);
|
||||||
|
am.to_rational(c.m_nra.value(r), rval);
|
||||||
|
use_rational = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xval > 0 && yval.is_unsigned()) {
|
if (use_rational) {
|
||||||
auto r2val = power(xval, yval.get_unsigned());
|
auto xval = c.val(x);
|
||||||
if (rval == r2val)
|
auto yval = c.val(y);
|
||||||
return l_true;
|
auto rval = c.val(r);
|
||||||
if (c.random() % 2 == 0) {
|
if (xval != 0 && yval == 0 && rval != 1)
|
||||||
new_lemma lemma(c, "x == x0, y == y0 => r = x0^y0");
|
return x_exp_0();
|
||||||
lemma |= ineq(x, llc::NE, xval);
|
else if (xval == 0 && yval != 0 && rval != 0)
|
||||||
lemma |= ineq(y, llc::NE, yval);
|
return zero_exp_y();
|
||||||
lemma |= ineq(r, llc::EQ, r2val);
|
else if (xval > 0 && rval <= 0)
|
||||||
return l_false;
|
return x_gt_0();
|
||||||
|
else if (xval > 1 && yval < 0 && rval >= 1)
|
||||||
|
return y_lt_1();
|
||||||
|
else if (xval > 1 && yval > 0 && rval <= 1)
|
||||||
|
return y_gt_1();
|
||||||
|
else if (xval >= 3 && yval != 0 && rval <= yval + 1)
|
||||||
|
return x_ge_3();
|
||||||
|
else if (xval > 0 && yval.is_unsigned()) {
|
||||||
|
auto r2val = power(xval, yval.get_unsigned());
|
||||||
|
if (rval == r2val)
|
||||||
|
return l_true;
|
||||||
|
if (c.random() % 2 == 0) {
|
||||||
|
new_lemma lemma(c, "x == x0, y == y0 => r = x0^y0");
|
||||||
|
lemma |= ineq(x, llc::NE, xval);
|
||||||
|
lemma |= ineq(y, llc::NE, yval);
|
||||||
|
lemma |= ineq(r, llc::EQ, r2val);
|
||||||
|
return l_false;
|
||||||
|
}
|
||||||
|
if (yval > 0 && r2val > rval) {
|
||||||
|
new_lemma lemma(c, "x >= x0 > 0, y >= y0 > 0 => r >= x0^y0");
|
||||||
|
lemma |= ineq(x, llc::LT, xval);
|
||||||
|
lemma |= ineq(y, llc::LT, yval);
|
||||||
|
lemma |= ineq(r, llc::GE, r2val);
|
||||||
|
return l_false;
|
||||||
|
}
|
||||||
|
if (r2val < rval) {
|
||||||
|
new_lemma lemma(c, "0 < x <= x0, y <= y0 => r <= x0^y0");
|
||||||
|
lemma |= ineq(x, llc::LE, rational::zero());
|
||||||
|
lemma |= ineq(x, llc::GT, xval);
|
||||||
|
lemma |= ineq(y, llc::GT, yval);
|
||||||
|
lemma |= ineq(r, llc::LE, r2val);
|
||||||
|
return l_false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (yval > 0 && r2val > rval) {
|
if (xval > 0 && yval > 0 && !yval.is_int()) {
|
||||||
new_lemma lemma(c, "x >= x0 > 0, y >= y0 > 0 => r >= x0^y0");
|
auto ynum = numerator(yval);
|
||||||
lemma |= ineq(x, llc::LT, xval);
|
auto yden = denominator(yval);
|
||||||
lemma |= ineq(y, llc::LT, yval);
|
// r = x^{yn/yd}
|
||||||
lemma |= ineq(r, llc::GE, r2val);
|
// <=>
|
||||||
return l_false;
|
// r^yd = x^yn
|
||||||
}
|
if (ynum.is_unsigned() && yden.is_unsigned()) {
|
||||||
if (r2val < rval) {
|
auto ryd = power(rval, yden.get_unsigned());
|
||||||
new_lemma lemma(c, "0 < x <= x0, y <= y0 => r <= x0^y0");
|
auto xyn = power(xval, ynum.get_unsigned());
|
||||||
lemma |= ineq(x, llc::LE, rational::zero());
|
if (ryd == xyn)
|
||||||
lemma |= ineq(x, llc::GT, xval);
|
return l_true;
|
||||||
lemma |= ineq(y, llc::GT, yval);
|
}
|
||||||
lemma |= ineq(r, llc::LE, r2val);
|
|
||||||
return l_false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (xval > 0 && yval > 0 && !yval.is_int()) {
|
|
||||||
auto ynum = numerator(yval);
|
if (!use_rational) {
|
||||||
auto yden = denominator(yval);
|
auto& am = c.m_nra.am();
|
||||||
if (!ynum.is_unsigned())
|
scoped_anum xval(am), yval(am), rval(am);
|
||||||
return l_undef;
|
am.set(xval, c.m_nra.value(x));
|
||||||
if (!yden.is_unsigned())
|
am.set(yval, c.m_nra.value(y));
|
||||||
return l_undef;
|
am.set(rval, c.m_nra.value(r));
|
||||||
// r = x^{yn/yd}
|
if (xval != 0 && yval == 0 && rval != 1)
|
||||||
// <=>
|
return x_exp_0();
|
||||||
// r^yd = x^yn
|
else if (xval == 0 && yval != 0 && rval != 0)
|
||||||
auto ryd = power(rval, yden.get_unsigned());
|
return zero_exp_y();
|
||||||
auto xyn = power(xval, ynum.get_unsigned());
|
else if (xval > 0 && rval <= 0)
|
||||||
if (ryd == xyn)
|
return x_gt_0();
|
||||||
return l_true;
|
else if (xval > 1 && yval < 0 && rval >= 1)
|
||||||
}
|
return y_lt_1();
|
||||||
|
else if (xval > 1 && yval > 0 && rval <= 1)
|
||||||
|
return y_gt_1();
|
||||||
|
else if (xval >= 3 && yval != 0 && rval <= yval + 1)
|
||||||
|
return x_ge_3();
|
||||||
|
else if (xval > 0 && yval > 0 && am.is_rational(yval)) {
|
||||||
|
rational yr;
|
||||||
|
am.to_rational(yval, yr);
|
||||||
|
auto ynum = numerator(yr);
|
||||||
|
auto yden = denominator(yr);
|
||||||
|
// r = x^{yn/yd}
|
||||||
|
// <=>
|
||||||
|
// r^yd = x^yn
|
||||||
|
if (ynum.is_unsigned() && yden.is_unsigned()) {
|
||||||
|
am.set(rval, power(rval, yden.get_unsigned()));
|
||||||
|
am.set(xval, power(xval, ynum.get_unsigned()));
|
||||||
|
if (rval == xval)
|
||||||
|
return l_true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return l_undef;
|
return l_undef;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1099,6 +1099,14 @@ public:
|
||||||
expr_ref zero(a.mk_real(0), m);
|
expr_ref zero(a.mk_real(0), m);
|
||||||
mk_axiom(~mk_literal(a.mk_le(p, zero)));
|
mk_axiom(~mk_literal(a.mk_le(p, zero)));
|
||||||
}
|
}
|
||||||
|
if (a.is_extended_numeral(y, r) && r > 0) {
|
||||||
|
// r is 1/n then x >= 0 => x = p^n
|
||||||
|
if (numerator(r) == 1 && denominator(r) > 1) {
|
||||||
|
expr_ref x_ge_0(a.mk_ge(x, a.mk_real(0)), m);
|
||||||
|
expr_ref x_eq_pn(a.mk_eq(x, a.mk_power(p, a.mk_real(denominator(r)))), m);
|
||||||
|
mk_axiom(~mk_literal(x_ge_0), mk_literal(x_eq_pn));
|
||||||
|
}
|
||||||
|
}
|
||||||
bool can_be_underspecified = false;
|
bool can_be_underspecified = false;
|
||||||
if (a.is_numeral(x, r) && r == 0 && (!a.is_numeral(y, r) || r == 0))
|
if (a.is_numeral(x, r) && r == 0 && (!a.is_numeral(y, r) || r == 0))
|
||||||
can_be_underspecified = true;
|
can_be_underspecified = true;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue