mirror of
https://github.com/Z3Prover/z3
synced 2025-06-22 22:03:39 +00:00
add int-blast experiment
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
3796770e46
commit
a82408e89b
2 changed files with 338 additions and 59 deletions
|
@ -32,13 +32,70 @@ namespace polysat {
|
||||||
return deps;
|
return deps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool univariate_solver::find_min(rational& val) {
|
||||||
|
val = model();
|
||||||
|
push();
|
||||||
|
// 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, null_dep);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// try decreasing k-th bit
|
||||||
|
push();
|
||||||
|
add_bit0(k, 0);
|
||||||
|
lbool result = check();
|
||||||
|
if (result == l_true) {
|
||||||
|
SASSERT(model() < val);
|
||||||
|
val = model();
|
||||||
|
}
|
||||||
|
pop(1);
|
||||||
|
if (result == l_true)
|
||||||
|
add_bit0(k, null_dep);
|
||||||
|
else if (result == l_false)
|
||||||
|
add_bit1(k, null_dep);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pop(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool univariate_solver::find_max(rational& val) {
|
||||||
|
val = model();
|
||||||
|
push();
|
||||||
|
// try increasing val by setting bits to 1, starting at the msb.
|
||||||
|
for (unsigned k = bit_width; k-- > 0; ) {
|
||||||
|
if (val.get_bit(k)) {
|
||||||
|
add_bit1(k, 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// try increasing k-th bit
|
||||||
|
push();
|
||||||
|
add_bit1(k, 0);
|
||||||
|
lbool result = check();
|
||||||
|
if (result == l_true) {
|
||||||
|
SASSERT(model() > val);
|
||||||
|
val = model();
|
||||||
|
}
|
||||||
|
pop(1);
|
||||||
|
if (result == l_true)
|
||||||
|
add_bit1(k, null_dep);
|
||||||
|
else if (result == l_false)
|
||||||
|
add_bit0(k, null_dep);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pop(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
class univariate_bitblast_solver : public univariate_solver {
|
class univariate_bitblast_solver : public univariate_solver {
|
||||||
// TODO: does it make sense to share m and bv between different solver instances?
|
// TODO: does it make sense to share m and bv between different solver instances?
|
||||||
// TODO: consider pooling solvers to save setup overhead, see if solver/solver_pool.h can be used
|
// TODO: consider pooling solvers to save setup overhead, see if solver/solver_pool.h can be used
|
||||||
ast_manager m;
|
ast_manager m;
|
||||||
scoped_ptr<bv_util> bv;
|
scoped_ptr<bv_util> bv;
|
||||||
scoped_ptr<solver> s;
|
scoped_ptr<solver> s;
|
||||||
unsigned bit_width;
|
|
||||||
unsigned m_scope_level = 0;
|
unsigned m_scope_level = 0;
|
||||||
func_decl_ref x_decl;
|
func_decl_ref x_decl;
|
||||||
expr_ref x;
|
expr_ref x;
|
||||||
|
@ -46,7 +103,7 @@ namespace polysat {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
univariate_bitblast_solver(solver_factory& mk_solver, unsigned bit_width) :
|
univariate_bitblast_solver(solver_factory& mk_solver, unsigned bit_width) :
|
||||||
bit_width(bit_width),
|
univariate_solver(bit_width),
|
||||||
x_decl(m),
|
x_decl(m),
|
||||||
x(m) {
|
x(m) {
|
||||||
reg_decl_plugins(m);
|
reg_decl_plugins(m);
|
||||||
|
@ -329,71 +386,289 @@ namespace polysat {
|
||||||
s->get_model(model);
|
s->get_model(model);
|
||||||
SASSERT(model);
|
SASSERT(model);
|
||||||
app* val = to_app(model->get_const_interp(x_decl));
|
app* val = to_app(model->get_const_interp(x_decl));
|
||||||
SASSERT(val->get_decl_kind() == OP_BV_NUM);
|
unsigned sz;
|
||||||
SASSERT(val->get_num_parameters() == 2);
|
VERIFY(bv->is_numeral(val, cached_model, sz));
|
||||||
auto const& p = val->get_parameter(0);
|
|
||||||
SASSERT(p.is_rational());
|
|
||||||
cached_model = p.get_rational();
|
|
||||||
}
|
}
|
||||||
return cached_model;
|
return cached_model;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool find_min(rational& val) override {
|
|
||||||
val = model();
|
|
||||||
|
bool find_two(rational& out1, rational& out2) override {
|
||||||
|
out1 = model();
|
||||||
|
bool ok = true;
|
||||||
push();
|
push();
|
||||||
// try reducing val by setting bits to 0, starting at the msb.
|
add(m.mk_eq(mk_numeral(out1), x), true, null_dep);
|
||||||
for (unsigned k = bit_width; k-- > 0; ) {
|
switch (check()) {
|
||||||
if (!val.get_bit(k)) {
|
case l_true:
|
||||||
add_bit0(k, null_dep);
|
out2 = model();
|
||||||
continue;
|
break;
|
||||||
}
|
case l_false:
|
||||||
// try decreasing k-th bit
|
out2 = out1;
|
||||||
push();
|
break;
|
||||||
add_bit0(k, 0);
|
default:
|
||||||
lbool result = check();
|
ok = false;
|
||||||
if (result == l_true) {
|
break;
|
||||||
SASSERT(model() < val);
|
|
||||||
val = model();
|
|
||||||
}
|
|
||||||
pop(1);
|
|
||||||
if (result == l_true)
|
|
||||||
add_bit0(k, null_dep);
|
|
||||||
else if (result == l_false)
|
|
||||||
add_bit1(k, null_dep);
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
pop(1);
|
pop(1);
|
||||||
|
IF_VERBOSE(10, verbose_stream() << "viable " << out1 << " " << out2 << "\n");
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::ostream& display(std::ostream& out) const override {
|
||||||
|
return out << *s;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// stub for alternative int-blast solver.
|
||||||
|
class univariate_intblast_solver : public univariate_solver {
|
||||||
|
ast_manager m;
|
||||||
|
scoped_ptr<arith_util> a;
|
||||||
|
scoped_ptr<solver> s;
|
||||||
|
rational m_mod;
|
||||||
|
unsigned m_scope_level = 0;
|
||||||
|
func_decl_ref x_decl;
|
||||||
|
expr_ref x;
|
||||||
|
vector<rational> model_cache;
|
||||||
|
|
||||||
|
void add(expr* e, bool sign, dep_t dep) {
|
||||||
|
reset_cache();
|
||||||
|
if (sign)
|
||||||
|
e = m.mk_not(e);
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_zero(univariate const& p) const {
|
||||||
|
for (auto n : p)
|
||||||
|
if (n != 0)
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool find_max(rational& val) override {
|
bool is_zero(rational const& p) const {
|
||||||
val = model();
|
return p.is_zero();
|
||||||
push();
|
}
|
||||||
// try increasing val by setting bits to 1, starting at the msb.
|
|
||||||
for (unsigned k = bit_width; k-- > 0; ) {
|
public:
|
||||||
if (val.get_bit(k)) {
|
univariate_intblast_solver(solver_factory& mk_solver, unsigned bit_width) :
|
||||||
add_bit1(k, 0);
|
univariate_solver(bit_width),
|
||||||
continue;
|
m_mod(rational::power_of_two(bit_width)),
|
||||||
|
x_decl(m),
|
||||||
|
x(m) {
|
||||||
|
reg_decl_plugins(m);
|
||||||
|
a = alloc(arith_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", a->mk_int());
|
||||||
|
x = m.mk_const(x_decl);
|
||||||
|
model_cache.push_back(rational(-1));
|
||||||
|
s->assert_expr(a->mk_le(mk_numeral(0), x));
|
||||||
|
s->assert_expr(a->mk_lt(x, mk_numeral(m_mod)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
~univariate_intblast_solver() override = default;
|
||||||
|
|
||||||
|
void reset_cache() {
|
||||||
|
model_cache.back() = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_cache() {
|
||||||
|
rational v = model_cache.back();
|
||||||
|
model_cache.push_back(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_cache() {
|
||||||
|
model_cache.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
void push() override {
|
||||||
|
m_scope_level++;
|
||||||
|
push_cache();
|
||||||
|
s->push();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop(unsigned n) override {
|
||||||
|
SASSERT(scope_level() >= n);
|
||||||
|
m_scope_level -= n;
|
||||||
|
pop_cache();
|
||||||
|
s->pop(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned scope_level() const override {
|
||||||
|
return m_scope_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr* mk_numeral(rational const& r) const {
|
||||||
|
// assert 0 <= r < 2^bit-width
|
||||||
|
return a->mk_int(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
expr* mk_numeral(uint64_t u) const {
|
||||||
|
// assert u < 2^bit-width
|
||||||
|
return a->mk_int(rational(u, rational::ui64()));
|
||||||
|
}
|
||||||
|
|
||||||
|
lbool check() override {
|
||||||
|
return s->check_sat();
|
||||||
|
}
|
||||||
|
|
||||||
|
expr_ref mk_poly(rational const& p) {
|
||||||
|
return {mk_numeral(p), m};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 2^k*x --> x << k
|
||||||
|
// n*x --> n * x
|
||||||
|
expr* mk_poly_term(rational const& coeff, expr* xpow) const {
|
||||||
|
SASSERT(!coeff.is_zero());
|
||||||
|
if (coeff.is_one())
|
||||||
|
return xpow;
|
||||||
|
return a->mk_mul(mk_numeral(coeff), xpow);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [d,c,b,a] --> d + c*x + b*(x*x) + a*(x*x*x)
|
||||||
|
expr_ref mk_poly(univariate const& p) {
|
||||||
|
expr_ref e(m);
|
||||||
|
if (p.empty())
|
||||||
|
e = mk_numeral(rational::zero());
|
||||||
|
else {
|
||||||
|
if (!p[0].is_zero())
|
||||||
|
e = mk_numeral(p[0]);
|
||||||
|
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 = e ? a->mk_add(e, t) : t;
|
||||||
|
}
|
||||||
|
if (i + 1 < p.size())
|
||||||
|
xpow = a->mk_mul(xpow, x);
|
||||||
}
|
}
|
||||||
// try increasing k-th bit
|
if (!e)
|
||||||
push();
|
e = mk_numeral(p[0]);
|
||||||
add_bit1(k, 0);
|
|
||||||
lbool result = check();
|
|
||||||
if (result == l_true) {
|
|
||||||
SASSERT(model() > val);
|
|
||||||
val = model();
|
|
||||||
}
|
|
||||||
pop(1);
|
|
||||||
if (result == l_true)
|
|
||||||
add_bit1(k, null_dep);
|
|
||||||
else if (result == l_false)
|
|
||||||
add_bit0(k, null_dep);
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
pop(1);
|
if (!a->is_numeral(e) && e != x)
|
||||||
return true;
|
e = a->mk_mod(e, mk_numeral(m_mod));
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename lhs_t, typename rhs_t>
|
||||||
|
void add_ule_impl(lhs_t const& lhs, rhs_t const& rhs, bool sign, dep_t dep) {
|
||||||
|
// todo: simplify x - k == 0 into x = k
|
||||||
|
// or ensure that bounds simplification tactic is enabled.
|
||||||
|
// without bounds simplification, int-blasting doesnt work.
|
||||||
|
if (is_zero(rhs))
|
||||||
|
add(m.mk_eq(mk_poly(lhs), mk_poly(rhs)), sign, dep);
|
||||||
|
else
|
||||||
|
add(a->mk_le(mk_poly(lhs), mk_poly(rhs)), sign, dep);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_ule(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) override { add_ule_impl(lhs, rhs, sign, dep); }
|
||||||
|
void add_ule(univariate const& lhs, rational const& rhs, bool sign, dep_t dep) override { add_ule_impl(lhs, rhs, sign, dep); }
|
||||||
|
void add_ule(rational const& lhs, univariate const& rhs, bool sign, dep_t dep) override { add_ule_impl(lhs, rhs, sign, dep); }
|
||||||
|
|
||||||
|
void add_umul_ovfl(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) override {
|
||||||
|
auto c = a->mk_mul(mk_poly(lhs), mk_poly(rhs));
|
||||||
|
if (sign) // or the other way around?
|
||||||
|
add(a->mk_lt(c, mk_numeral(m_mod)), sign, dep);
|
||||||
|
else
|
||||||
|
add(a->mk_ge(c, mk_numeral(m_mod)), sign, dep);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_smul_ovfl(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) override {
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_smul_udfl(univariate const& lhs, univariate const& rhs, bool sign, dep_t dep) override {
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_lshr(univariate const& in1, univariate const& in2, univariate const& out, bool sign, dep_t dep) override {
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_ashr(univariate const& in1, univariate const& in2, univariate const& out, bool sign, dep_t dep) override {
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_shl(univariate const& in1, univariate const& in2, univariate const& out, bool sign, dep_t dep) override {
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_and(univariate const& in1, univariate const& in2, univariate const& out, bool sign, dep_t dep) override {
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_or(univariate const& in1, univariate const& in2, univariate const& out, bool sign, dep_t dep) override {
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_xor(univariate const& in1, univariate const& in2, univariate const& out, bool sign, dep_t dep) override {
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_not(univariate const& in, univariate const& out, bool sign, dep_t dep) override {
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_inv(univariate const& in, univariate const& out, bool sign, dep_t dep) override {
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_udiv(univariate const& in1, univariate const& in2, univariate const& out, bool sign, dep_t dep) override {
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_urem(univariate const& in1, univariate const& in2, univariate const& out, bool sign, dep_t dep) override {
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_ule_const(rational const& val, bool sign, dep_t dep) override {
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_uge_const(rational const& val, bool sign, dep_t dep) override {
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_bit(unsigned idx, bool sign, dep_t dep) override {
|
||||||
|
add(m.mk_eq(mk_numeral(m_mod/2), a->mk_mul(mk_numeral(rational::power_of_two(bit_width - idx - 1)), x)), sign, dep);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unsat_core(dep_vector& deps) override {
|
||||||
|
deps.reset();
|
||||||
|
expr_ref_vector core(m);
|
||||||
|
s->get_unsat_core(core);
|
||||||
|
for (expr* a : core) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
rational model() override {
|
||||||
|
rational& cached_model = model_cache.back();
|
||||||
|
if (cached_model.is_neg()) {
|
||||||
|
model_ref model;
|
||||||
|
s->get_model(model);
|
||||||
|
SASSERT(model);
|
||||||
|
app* val = to_app(model->get_const_interp(x_decl));
|
||||||
|
VERIFY(a->is_numeral(val, cached_model));
|
||||||
|
}
|
||||||
|
return cached_model;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool find_two(rational& out1, rational& out2) override {
|
bool find_two(rational& out1, rational& out2) override {
|
||||||
|
|
|
@ -24,6 +24,8 @@ Author:
|
||||||
namespace polysat {
|
namespace polysat {
|
||||||
|
|
||||||
class univariate_solver {
|
class univariate_solver {
|
||||||
|
protected:
|
||||||
|
unsigned bit_width;
|
||||||
public:
|
public:
|
||||||
using dep_t = unsigned;
|
using dep_t = unsigned;
|
||||||
using dep_vector = svector<dep_t>;
|
using dep_vector = svector<dep_t>;
|
||||||
|
@ -34,6 +36,8 @@ namespace polysat {
|
||||||
|
|
||||||
const dep_t null_dep = UINT_MAX;
|
const dep_t null_dep = UINT_MAX;
|
||||||
|
|
||||||
|
univariate_solver(unsigned bit_width) : bit_width(bit_width) {}
|
||||||
|
|
||||||
virtual ~univariate_solver() = default;
|
virtual ~univariate_solver() = default;
|
||||||
|
|
||||||
virtual void push() = 0;
|
virtual void push() = 0;
|
||||||
|
@ -59,7 +63,7 @@ namespace polysat {
|
||||||
* Precondition: check() returned l_true
|
* Precondition: check() returned l_true
|
||||||
* Returns: true on success, false on resource out.
|
* Returns: true on success, false on resource out.
|
||||||
*/
|
*/
|
||||||
virtual bool find_min(rational& out_min) = 0;
|
bool find_min(rational& out_min);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find maximal model.
|
* Find maximal model.
|
||||||
|
@ -67,7 +71,7 @@ namespace polysat {
|
||||||
* Precondition: check() returned l_true
|
* Precondition: check() returned l_true
|
||||||
* Returns: true on success, false on resource out.
|
* Returns: true on success, false on resource out.
|
||||||
*/
|
*/
|
||||||
virtual bool find_max(rational& out_max) = 0;
|
bool find_max(rational& out_max);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find up to two viable values.
|
* Find up to two viable values.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue