3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-24 17:45:32 +00:00

Merge remote-tracking branch 'origin/polysat' into polysat

This commit is contained in:
Jakob Rath 2022-12-19 09:11:18 +01:00
commit 208f166934
7 changed files with 261 additions and 99 deletions

View file

@ -37,6 +37,7 @@ void bv_rewriter::updt_local_params(params_ref const & _p) {
m_ite2id = p.bv_ite2id();
m_le_extra = p.bv_le_extra();
m_le2extract = p.bv_le2extract();
m_le2extract = false; //
set_sort_sums(p.bv_sort_ac());
}
@ -1724,6 +1725,9 @@ br_status bv_rewriter::mk_bv_or(unsigned num, expr * const * args, expr_ref & re
}
}
if (!m_le2extract)
return BR_FAILED;
if (!v1.is_zero() && new_args.size() == 1) {
v1 = m_util.norm(v1, sz);
#ifdef _TRACE

View file

@ -32,44 +32,84 @@ namespace polysat {
saturation::saturation(solver& s) : s(s), m_lemma(s) {}
void saturation::log_lemma(pvar v, conflict& core) {
IF_VERBOSE(1, auto const& cl = core.lemmas().back();
verbose_stream() << m_rule << " v" << v << " ";
for (auto lit : *cl) verbose_stream() << s.lit2cnstr(lit) << " ";
verbose_stream() << "\n");
}
void saturation::perform(pvar v, conflict& core) {
IF_VERBOSE(2, verbose_stream() << "v" << v << " " << core << "\n");
for (auto c : core)
if (perform(v, c, core)) {
IF_VERBOSE(0, auto const& cl = core.lemmas().back();
verbose_stream() << m_rule << " v" << v << " ";
for (auto lit : *cl) verbose_stream() << s.lit2cnstr(lit) << " ";
verbose_stream() << "\n");
if (perform(v, c, core))
return;
}
}
bool saturation::perform(pvar v, signed_constraint const& c, conflict& core) {
if (!c->is_ule())
return false;
if (c.is_currently_true(s))
return false;
auto i = inequality::from_ule(c);
if (try_mul_bounds(v, core, i))
return true;
if (try_parity(v, core, i))
return true;
if (try_parity_diseq(v, core, i))
return true;
if (try_factor_equality(v, core, i))
return true;
if (try_ugt_x(v, core, i))
return true;
if (try_ugt_y(v, core, i))
return true;
if (try_ugt_z(v, core, i))
return true;
if (try_y_l_ax_and_x_l_z(v, core, i))
return true;
if (false && try_tangent(v, core, i))
return true;
if (c->is_ule()) {
auto i = inequality::from_ule(c);
return try_inequality(v, i, core);
}
#if 0
if (c->is_umul_ovfl())
return try_umul_ovfl(v, c, core);
#endif
return false;
}
bool saturation::try_inequality(pvar v, inequality const& i, conflict& core) {
bool prop = false;
if (try_mul_bounds(v, core, i))
prop = true;
if (try_parity(v, core, i))
prop = true;
if (try_parity_diseq(v, core, i))
prop = true;
if (try_transitivity(v, core, i))
prop = true;
if (try_factor_equality(v, core, i))
prop = true;
if (try_ugt_x(v, core, i))
prop = true;
if (try_ugt_y(v, core, i))
prop = true;
if (try_ugt_z(v, core, i))
prop = true;
if (try_y_l_ax_and_x_l_z(v, core, i))
prop = true;
if (false && try_tangent(v, core, i))
prop = true;
return prop;
}
bool saturation::try_umul_ovfl(pvar v, signed_constraint const& c, conflict& core) {
set_rule("[x] ~ovfl(x, y) => y = 0 or x <= x * y");
SASSERT(c->is_umul_ovfl());
if (!c.is_negative())
return false;
auto const& ovfl = c->to_umul_ovfl();
auto V = s.var(v);
auto p = ovfl.p(), q = ovfl.q();
// TODO could relax condition to be that V occurs in p
if (q == V)
std::swap(p, q);
signed_constraint q_eq_0;
if (p == V && is_forced_diseq(q, 0, q_eq_0)) {
// ~ovfl(V,q) => q = 0 or V <= V*q
m_lemma.reset();
m_lemma.insert_eval(q_eq_0);
if (propagate(v, core, c, s.ule(p, p * q)))
return true;
}
return false;
}
signed_constraint saturation::ineq(bool is_strict, pdd const& lhs, pdd const& rhs) {
if (is_strict)
return s.ult(lhs, rhs);
@ -77,7 +117,11 @@ namespace polysat {
return s.ule(lhs, rhs);
}
bool saturation::propagate(conflict& core, inequality const& crit, signed_constraint c) {
bool saturation::propagate(pvar v, conflict& core, inequality const& crit, signed_constraint c) {
return propagate(v, core, crit.as_signed_constraint(), c);
}
bool saturation::propagate(pvar v, conflict& core, signed_constraint const& crit, signed_constraint c) {
if (is_forced_true(c))
return false;
@ -95,25 +139,21 @@ namespace polysat {
// The current assumptions on how conflict lemmas are used do not accomodate propagation it seems.
//
m_lemma.insert(~crit.as_signed_constraint());
IF_VERBOSE(10, verbose_stream() << "propagate " << m_rule << " ";
for (auto lit : m_lemma) verbose_stream() << s.lit2cnstr(lit) << " ";
verbose_stream() << c << "\n";
);
m_lemma.insert(~crit);
SASSERT(all_of(m_lemma, [this](sat::literal lit) { return is_forced_false(s.lit2cnstr(lit)); }));
m_lemma.insert(c);
core.add_lemma(m_rule, m_lemma.build());
log_lemma(v, core);
return true;
}
bool saturation::add_conflict(conflict& core, inequality const& crit1, signed_constraint c) {
return add_conflict(core, crit1, crit1, c);
bool saturation::add_conflict(pvar v, conflict& core, inequality const& crit1, signed_constraint c) {
return add_conflict(v, core, crit1, crit1, c);
}
bool saturation::add_conflict(conflict& core, inequality const& _crit1, inequality const& _crit2, signed_constraint const c) {
bool saturation::add_conflict(pvar v, conflict& core, inequality const& _crit1, inequality const& _crit2, signed_constraint const c) {
auto crit1 = _crit1.as_signed_constraint();
auto crit2 = _crit2.as_signed_constraint();
m_lemma.insert(~crit1);
@ -135,6 +175,7 @@ namespace polysat {
m_lemma.insert_eval(c);
core.add_lemma(m_rule, m_lemma.build());
log_lemma(v, core);
return true;
}
@ -221,8 +262,7 @@ namespace polysat {
*/
bool saturation::is_AxB_l_Y(pvar x, inequality const& i, pdd& a, pdd& b, pdd& y) {
y = i.rhs();
pdd aa = a, bb = b;
return i.lhs().degree(x) == 1 && (i.lhs().factor(x, 1, aa, bb), aa == a && bb == b);
return i.lhs().degree(x) == 1 && (i.lhs().factor(x, 1, a, b), true);
}
bool saturation::verify_AxB_l_Y(pvar x, inequality const& i, pdd const& a, pdd const& b, pdd const& y) {
@ -232,8 +272,7 @@ namespace polysat {
bool saturation::is_Y_l_AxB(pvar x, inequality const& i, pdd& y, pdd& a, pdd& b) {
y = i.lhs();
pdd aa = a, bb = b;
return i.rhs().degree(x) == 1 && (i.rhs().factor(x, 1, aa, bb), aa == a && bb == b);
return i.rhs().degree(x) == 1 && (i.rhs().factor(x, 1, a, b), true);
}
bool saturation::verify_Y_l_AxB(pvar x, inequality const& i, pdd const& y, pdd const& a, pdd& b) {
@ -386,7 +425,7 @@ namespace polysat {
m_lemma.insert_eval(~non_ovfl);
if (!xy_l_xz.is_strict())
m_lemma.insert_eval(s.eq(x));
return add_conflict(core, xy_l_xz, ineq(xy_l_xz.is_strict(), y, z));
return add_conflict(v, core, xy_l_xz, ineq(xy_l_xz.is_strict(), y, z));
}
/**
@ -427,7 +466,7 @@ namespace polysat {
pdd const& z_prime = l_y.lhs();
m_lemma.reset();
m_lemma.insert_eval(~non_ovfl);
return add_conflict(core, l_y, yx_l_zx, ineq(yx_l_zx.is_strict() || l_y.is_strict(), z_prime * x, z * x));
return add_conflict(v, core, l_y, yx_l_zx, ineq(yx_l_zx.is_strict() || l_y.is_strict(), z_prime * x, z * x));
}
/**
@ -467,7 +506,7 @@ namespace polysat {
return false;
m_lemma.reset();
m_lemma.insert_eval(~non_ovfl);
return add_conflict(core, yx_l_zx, z_l_y, ineq(z_l_y.is_strict() || yx_l_zx.is_strict(), y * x, y_prime * x));
return add_conflict(z, core, yx_l_zx, z_l_y, ineq(z_l_y.is_strict() || yx_l_zx.is_strict(), y * x, y_prime * x));
}
/**
@ -508,7 +547,7 @@ namespace polysat {
return false;
m_lemma.reset();
m_lemma.insert_eval(~non_ovfl);
return add_conflict(core, y_l_ax, x_l_z, ineq(x_l_z.is_strict() || y_l_ax.is_strict(), y, a * z));
return add_conflict(x, core, y_l_ax, x_l_z, ineq(x_l_z.is_strict() || y_l_ax.is_strict(), y, a * z));
}
/**
@ -546,7 +585,7 @@ namespace polysat {
m_lemma.insert_eval(~s.eq(y));
m_lemma.insert_eval(x_eq_0);
m_lemma.insert_eval(a_eq_0);
return propagate(core, axb_l_y, c);
return propagate(x, core, axb_l_y, c);
};
auto prop2 = [&](signed_constraint ante, signed_constraint c) {
@ -556,7 +595,7 @@ namespace polysat {
m_lemma.insert_eval(x_eq_0);
m_lemma.insert_eval(a_eq_0);
m_lemma.insert_eval(~ante);
return propagate(core, axb_l_y, c);
return propagate(x, core, axb_l_y, c);
};
pdd minus_a = -a;
@ -612,6 +651,12 @@ namespace polysat {
}
// bench 5
bool saturation::try_mul_eq_bound(pvar x, conflict& core, inequality const& axb_l_y) {
set_rule("[x] 2^k*x = 2^k*y & x < 2^N-k => y = x or y >= 2^{N-k}");
return false;
}
/*
* x*y = 1 & ~ovfl(x,y) => x = 1
* x*y = -1 & ~ovfl(-x,y) => -x = 1
@ -634,9 +679,9 @@ namespace polysat {
m_lemma.insert_eval(~s.eq(b, rational(-1)));
m_lemma.insert_eval(~s.eq(y));
m_lemma.insert_eval(~non_ovfl);
if (propagate(core, axb_l_y, s.eq(X, 1)))
if (propagate(x, core, axb_l_y, s.eq(X, 1)))
return true;
if (propagate(core, axb_l_y, s.eq(a, 1)))
if (propagate(x, core, axb_l_y, s.eq(a, 1)))
return true;
return false;
}
@ -669,8 +714,7 @@ namespace polysat {
auto& m = s.var2pdd(x);
unsigned N = m.power_of_2();
pdd y = m.zero();
pdd a = m.zero();
pdd b = m.zero();
pdd a = y, b = y;
pdd X = s.var(x);
if (!is_AxB_eq_0(x, axb_l_y, a, b, y))
return false;
@ -688,7 +732,7 @@ namespace polysat {
m_lemma.reset();
m_lemma.insert_eval(~s.eq(y));
m_lemma.insert_eval(~premise);
return propagate(core, axb_l_y, conseq);
return propagate(x, core, axb_l_y, conseq);
};
auto propagate2 = [&](signed_constraint premise1, signed_constraint premise2, signed_constraint conseq) {
@ -696,7 +740,7 @@ namespace polysat {
m_lemma.insert_eval(~s.eq(y));
m_lemma.insert_eval(~premise1);
m_lemma.insert_eval(~premise2);
return propagate(core, axb_l_y, conseq);
return propagate(x, core, axb_l_y, conseq);
};
#if 0
LOG_H1("try_parity: " << X << " on: " << lit_pp(s, axb_l_y.as_signed_constraint()));
@ -741,7 +785,7 @@ namespace polysat {
//
// if b has at most b_parity, then a*x has at most b_parity
//
else if (!is_forced_eq(b, 0)) {
if (!is_forced_eq(b, 0)) {
unsigned b_parity = 1;
bool found = false;
for (; b_parity < N; ++b_parity) {
@ -780,7 +824,8 @@ namespace polysat {
auto& m = s.var2pdd(x);
unsigned N = m.power_of_2();
pdd y = m.zero();
pdd a = y, b = y, X = y;
pdd a = y, b = y;
pdd X = s.var(x);
if (!is_AxB_diseq_0(x, axb_l_y, a, b, y))
return false;
if (!is_forced_eq(b, 0))
@ -793,7 +838,7 @@ namespace polysat {
m_lemma.reset();
m_lemma.insert_eval(~s.eq(y));
m_lemma.insert_eval(~s.eq(b));
return propagate(core, axb_l_y, ~s.parity(X, N - k));
return propagate(x, core, axb_l_y, ~s.parity(X, N - k));
}
/**
@ -818,16 +863,52 @@ namespace polysat {
m_lemma.insert_eval(s.eq(y));
m_lemma.insert_eval(~s.eq(b));
m_lemma.insert_eval(a_eq_0);
if (propagate(core, axb_l_y, s.even(X)))
if (propagate(x, core, axb_l_y, s.even(X)))
return true;
if (!is_forced_diseq(X, 0, x_eq_0))
return false;
m_lemma.insert_eval(x_eq_0);
if (propagate(core, axb_l_y, s.even(a)))
if (propagate(x, core, axb_l_y, s.even(a)))
return true;
return false;
}
/**
* TODO If both inequalities are strict, then the implied inequality has a gap of 2
* a < b, b < c => a + 1 < c & a + 1 != 0
*/
bool saturation::try_transitivity(pvar x, conflict& core, inequality const& a_l_b) {
set_rule("[x] q < x & x <= p => q < p");
auto& m = s.var2pdd(x);
pdd p = m.zero();
pdd a = p, b = p, q = p;
// x <= p
if (!is_Ax_l_Y(x, a_l_b, a, p))
return false;
if (!is_forced_eq(a, 1))
return false;
for (auto c : core) {
if (!c->is_ule())
continue;
auto i = inequality::from_ule(c);
if (c == a_l_b.as_signed_constraint())
continue;
if (!is_Y_l_Ax(x, i, b, q))
continue;
if (!is_forced_eq(b, 1))
continue;
m_lemma.reset();
m_lemma.insert_eval(~s.eq(a, 1));
m_lemma.insert_eval(~s.eq(b, 1));
m_lemma.insert(~c);
auto ineq = i.is_strict() || a_l_b.is_strict() ? s.ult(q, p) : s.ule(q, p);
if (propagate(x, core, a_l_b, ineq))
return true;
}
return false;
}
/**
* [x] ax + p <= q, ax + r = 0 => -r + p <= q
* [x] p <= ax + q, ax + r = 0 => p <= -r + q
@ -837,6 +918,7 @@ namespace polysat {
*/
bool saturation::try_factor_equality(pvar x, conflict& core, inequality const& a_l_b) {
set_rule("[x] a1x+p <= a2x + q & a3*x + b3 = 0 => a1*inv(a3)*-b3 + p <= a2*inv(a3)*-b3 + q");
auto& m = s.var2pdd(x);
unsigned N = m.power_of_2();
pdd y1 = m.zero();
@ -846,14 +928,10 @@ namespace polysat {
bool is_axb_l_y = is_AxB_l_Y(x, a_l_b, a1, b1, y1);
bool is_y_l_axb = is_Y_l_AxB(x, a_l_b, y2, a2, b2);
if (!a_l_b.is_strict() && a_l_b.rhs().is_zero())
return false;
if (!is_axb_l_y && !is_y_l_axb)
return false;
if (a1.is_val() && a2.is_val())
return false;
bool factored = false;
for (auto c : core) {
if (!c->is_ule())
@ -865,31 +943,52 @@ namespace polysat {
continue;
if (c == a_l_b.as_signed_constraint())
continue;
pdd lhs = i.lhs();
pdd rhs = i.rhs();
pdd lhs = a_l_b.lhs();
pdd rhs = a_l_b.rhs();
bool change = false;
if (is_axb_l_y && a1 == a3) {
change = true;
lhs = b3 - b1;
lhs = b1 - b3;
}
else if (is_axb_l_y && a1 == -a3) {
change = true;
lhs = b1 + b3;
}
else if (is_axb_l_y && a3.is_val() && a3.val().is_odd()) {
// a3*x + b3 == 0
// a3 is odd => x = inverse(a3)*-b3
change = true;
rational a3_inv;
VERIFY(a3.val().mult_inverse(m.power_of_2(), a3_inv));
lhs = b1 - a1*(b3 * a3_inv);
}
if (is_y_l_axb && a2 == a3) {
change = true;
rhs = b3 - b2;
rhs = b2 - b3;
}
else if (is_y_l_axb && a2 == -a3) {
change = true;
rhs = b2 + b3;
}
else if (is_y_l_axb && a3.is_val() && a3.val().is_odd()) {
change = true;
rational a3_inv;
VERIFY(a3.val().mult_inverse(m.power_of_2(), a3_inv));
rhs = b2 - a2*(b3 * a3_inv);
}
if (!change) {
IF_VERBOSE(0, verbose_stream() << "missed factor equality " << c << " " << a_l_b << "\n");
IF_VERBOSE(1, verbose_stream() << "missed factor equality " << c << " " << a_l_b << "\n");
continue;
}
signed_constraint conseq = i.is_strict() ? s.ult(lhs, rhs) : s.ule(lhs, rhs);
signed_constraint conseq = a_l_b.is_strict() ? s.ult(lhs, rhs) : s.ule(lhs, rhs);
m_lemma.reset();
m_lemma.insert(~s.eq(y3));
m_lemma.insert(~c);
IF_VERBOSE(0, verbose_stream() << "factor equality " << a_l_b << "\n");
if (propagate(core, a_l_b, conseq))
return true;
if (propagate(x, core, a_l_b, conseq))
factored = true;
}
return false;
return factored;
}
/*
* TODO
@ -949,7 +1048,7 @@ namespace polysat {
return false;
m_lemma.insert_eval(~d);
auto conseq = s.ult(r_val, c.rhs());
return add_conflict(core, c, conseq);
return add_conflict(v, core, c, conseq);
}
else {
auto d = s.ule(c.rhs(), r_val);
@ -957,7 +1056,7 @@ namespace polysat {
return false;
m_lemma.insert_eval(~d);
auto conseq = s.ule(c.lhs(), r_val);
return add_conflict(core, c, conseq);
return add_conflict(v, core, c, conseq);
}
}

View file

@ -31,9 +31,11 @@ namespace polysat {
bool is_non_overflow(pdd const& x, pdd const& y, signed_constraint& c);
signed_constraint ineq(bool strict, pdd const& lhs, pdd const& rhs);
bool propagate(conflict& core, inequality const& crit1, signed_constraint c);
bool add_conflict(conflict& core, inequality const& crit1, signed_constraint c);
bool add_conflict(conflict& core, inequality const& crit1, inequality const& crit2, signed_constraint c);
void log_lemma(pvar v, conflict& core);
bool propagate(pvar v, conflict& core, signed_constraint const& crit1, signed_constraint c);
bool propagate(pvar v, conflict& core, inequality const& crit1, signed_constraint c);
bool add_conflict(pvar v, conflict& core, inequality const& crit1, signed_constraint c);
bool add_conflict(pvar v, conflict& core, inequality const& crit1, inequality const& crit2, signed_constraint c);
bool try_ugt_x(pvar v, conflict& core, inequality const& c);
@ -52,6 +54,8 @@ namespace polysat {
bool try_factor_equality(pvar x, conflict& core, inequality const& a_l_b);
bool try_mul_eq_1(pvar x, conflict& core, inequality const& axb_l_y);
bool try_mul_odd(pvar x, conflict& core, inequality const& axb_l_y);
bool try_mul_eq_bound(pvar x, conflict& core, inequality const& axb_l_y);
bool try_transitivity(pvar x, conflict& core, inequality const& axb_l_y);
bool try_tangent(pvar v, conflict& core, inequality const& c);
// c := lhs ~ v
@ -118,6 +122,10 @@ namespace polysat {
bool is_forced_true(signed_constraint const& sc);
bool try_inequality(pvar v, inequality const& i, conflict& core);
bool try_umul_ovfl(pvar v, signed_constraint const& c, conflict& core);
public:
saturation(solver& s);
void perform(pvar v, conflict& core);

View file

@ -99,8 +99,8 @@ namespace polysat {
signed_constraint sc(this, is_positive);
// ¬Omega(p, q) ==> q = 0 \/ p <= p*q
// ¬Omega(p, q) ==> p = 0 \/ q <= p*q
s.add_clause(~sc, /* s.eq(p()), */ s.eq(q()), s.ule(p(), p()*q()), false);
s.add_clause(~sc, s.eq(p()), /* s.eq(q()), */ s.ule(q(), p()*q()), false);
s.add_clause(~sc, s.eq(q()), s.ule(p(), p()*q()), false);
s.add_clause(~sc, s.eq(p()), s.ule(q(), p()*q()), false);
}
}

View file

@ -53,6 +53,7 @@ namespace polysat {
bv = alloc(bv_util, m);
params_ref p;
p.set_bool("bv.polysat", false);
// p.set_bool("smt", true);
s = mk_solver(m, p, false, true, true, symbol::null);
x_decl = m.mk_const_decl("x", bv->mk_sort(bit_width));
x = m.mk_const(x_decl);
@ -66,7 +67,8 @@ namespace polysat {
}
void push_cache() {
model_cache.push_back(model_cache.back());
rational v = model_cache.back();
model_cache.push_back(v);
}
void pop_cache() {
@ -94,6 +96,13 @@ namespace polysat {
return bv->mk_numeral(r, bit_width);
}
bool is_zero(univariate const& p) const {
for (auto n : p)
if (n != 0)
return false;
return true;
}
#if 0
// [d,c,b,a] --> ((a*x + b)*x + c)*x + d
expr* mk_poly(univariate const& p) const {
@ -128,16 +137,18 @@ namespace polysat {
return mk_numeral(rational::zero());
}
else {
expr* e = mk_numeral(p[0]);
expr* xpow = x;
expr* e = p[0] != 0 ? mk_numeral(p[0]) : nullptr;
expr_ref xpow = x;
for (unsigned i = 1; i < p.size(); ++i) {
if (!p[i].is_zero()) {
expr* t = mk_poly_term(p[i], xpow);
e = bv->mk_bv_add(e, t);
e = e ? bv->mk_bv_add(e, t) : t;
}
if (i + 1 < p.size())
xpow = bv->mk_bv_mul(xpow, x);
}
if (!e)
e = mk_numeral(p[0]);
return e;
}
}
@ -147,13 +158,22 @@ namespace polysat {
reset_cache();
if (sign)
e = m.mk_not(e);
expr* a = m.mk_const(m.mk_const_decl(symbol(dep), m.mk_bool_sort()));
s->assert_expr(e, a);
IF_VERBOSE(10, verbose_stream() << "(assert (! " << expr_ref(e, m) << " :named " << expr_ref(a, m) << "))\n");
if (dep == null_dep) {
s->assert_expr(e);
IF_VERBOSE(10, verbose_stream() << "(assert " << expr_ref(e, m) << ")\n");
}
else {
expr* a = m.mk_const(m.mk_const_decl(symbol(dep), m.mk_bool_sort()));
s->assert_expr(e, a);
IF_VERBOSE(10, verbose_stream() << "(assert (! " << expr_ref(e, m) << " :named " << expr_ref(a, m) << "))\n");
}
}
void add_ule(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) override {
add(bv->mk_ule(mk_poly(lhs), mk_poly(rhs)), sign, dep);
if (is_zero(rhs))
add(m.mk_eq(mk_poly(lhs), mk_poly(rhs)), sign, dep);
else
add(bv->mk_ule(mk_poly(lhs), mk_poly(rhs)), sign, dep);
}
void add_umul_ovfl(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) override {
@ -197,7 +217,10 @@ namespace polysat {
}
void add_ule_const(rational const& val, bool sign, dep_t dep) override {
add(bv->mk_ule(x, mk_numeral(val)), sign, dep);
if (val == 0)
add(m.mk_eq(x, mk_numeral(val)), sign, dep);
else
add(bv->mk_ule(x, mk_numeral(val)), sign, dep);
}
void add_uge_const(rational const& val, bool sign, dep_t dep) override {
@ -220,6 +243,7 @@ namespace polysat {
unsigned dep = to_app(a)->get_decl()->get_name().get_num();
deps.push_back(dep);
}
IF_VERBOSE(10, verbose_stream() << "core " << deps << "\n");
SASSERT(deps.size() > 0);
}
@ -245,7 +269,7 @@ namespace polysat {
// try reducing val by setting bits to 0, starting at the msb.
for (unsigned k = bit_width; k-- > 0; ) {
if (!val.get_bit(k)) {
add_bit0(k, 0);
add_bit0(k, null_dep);
continue;
}
// try decreasing k-th bit
@ -258,9 +282,9 @@ namespace polysat {
}
pop(1);
if (result == l_true)
add_bit0(k, 0);
add_bit0(k, null_dep);
else if (result == l_false)
add_bit1(k, 0);
add_bit1(k, null_dep);
else
return false;
}
@ -287,9 +311,9 @@ namespace polysat {
}
pop(1);
if (result == l_true)
add_bit1(k, 0);
add_bit1(k, null_dep);
else if (result == l_false)
add_bit0(k, 0);
add_bit0(k, null_dep);
else
return false;
}
@ -297,6 +321,27 @@ namespace polysat {
return true;
}
bool find_two(rational& out1, rational& out2) {
out1 = model();
bool ok = true;
push();
add(m.mk_eq(mk_numeral(out1), x), true, null_dep);
switch (check()) {
case l_true:
out2 = model();
break;
case l_false:
out2 = out1;
break;
default:
ok = false;
break;
}
pop(1);
IF_VERBOSE(10, verbose_stream() << "viable " << out1 << " " << out2 << "\n");
return ok;
}
std::ostream& display(std::ostream& out) const override {
return out << *s;
}

View file

@ -35,6 +35,8 @@ namespace polysat {
/// e.g., the vector [ c, b, a ] represents a*x^2 + b*x + c.
using univariate = vector<rational>;
const dep_t null_dep = UINT_MAX;
virtual ~univariate_solver() = default;
virtual void push() = 0;
@ -70,6 +72,14 @@ namespace polysat {
*/
virtual bool find_max(rational& out_max) = 0;
/**
* Find up to two viable values.
*
* Precondition: check() returned l_true
* returns: true on success, false on resource out
*/
virtual bool find_two(rational& out1, rational& out2) = 0;
virtual void add_ule(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) = 0;
virtual void add_umul_ovfl(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) = 0;
virtual void add_smul_ovfl(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) = 0;

View file

@ -799,11 +799,7 @@ namespace polysat {
}
lbool viable::query_find_fallback(pvar v, univariate_solver& us, rational& lo, rational& hi) {
if (!us.find_min(lo))
return l_undef;
if (!us.find_max(hi))
return l_undef;
return l_true;
return us.find_two(lo, hi) ? l_true : l_undef;
}
lbool viable::query_min_fallback(pvar v, univariate_solver& us, rational& lo) {