mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 12:08:18 +00:00
intblast with lazy expansion of shl, ashr, lshr
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
50e0fd3ba6
commit
d0a59f3740
|
@ -508,6 +508,19 @@ static bool is_const_op(decl_kind k) {
|
||||||
//k == OP_0_PW_0_REAL;
|
//k == OP_0_PW_0_REAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
symbol arith_decl_plugin::bv_symbol(decl_kind k) const {
|
||||||
|
switch (k) {
|
||||||
|
case OP_ARITH_BAND: return symbol("band");
|
||||||
|
case OP_ARITH_SHL: return symbol("shl");
|
||||||
|
case OP_ARITH_ASHR: return symbol("ashr");
|
||||||
|
case OP_ARITH_LSHR: return symbol("lshr");
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return symbol();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||||
unsigned arity, sort * const * domain, sort * range) {
|
unsigned arity, sort * const * domain, sort * range) {
|
||||||
if (k == OP_NUM)
|
if (k == OP_NUM)
|
||||||
|
@ -523,10 +536,10 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
|
||||||
return m_manager->mk_func_decl(symbol("divisible"), 1, &m_int_decl, m_manager->mk_bool_sort(),
|
return m_manager->mk_func_decl(symbol("divisible"), 1, &m_int_decl, m_manager->mk_bool_sort(),
|
||||||
func_decl_info(m_family_id, k, num_parameters, parameters));
|
func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||||
}
|
}
|
||||||
if (k == OP_ARITH_BAND) {
|
if (k == OP_ARITH_BAND || k == OP_ARITH_SHL || k == OP_ARITH_ASHR || k == OP_ARITH_LSHR) {
|
||||||
if (arity != 2 || domain[0] != m_int_decl || domain[1] != m_int_decl || num_parameters != 1 || !parameters[0].is_int())
|
if (arity != 2 || domain[0] != m_int_decl || domain[1] != m_int_decl || num_parameters != 1 || !parameters[0].is_int())
|
||||||
m_manager->raise_exception("invalid bitwise and application. Expects integer parameter and two arguments of sort integer");
|
m_manager->raise_exception("invalid bitwise and application. Expects integer parameter and two arguments of sort integer");
|
||||||
return m_manager->mk_func_decl(symbol("band"), 2, domain, m_int_decl,
|
return m_manager->mk_func_decl(bv_symbol(k), 2, domain, m_int_decl,
|
||||||
func_decl_info(m_family_id, k, num_parameters, parameters));
|
func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -554,11 +567,11 @@ func_decl * arith_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters
|
||||||
return m_manager->mk_func_decl(symbol("divisible"), 1, &m_int_decl, m_manager->mk_bool_sort(),
|
return m_manager->mk_func_decl(symbol("divisible"), 1, &m_int_decl, m_manager->mk_bool_sort(),
|
||||||
func_decl_info(m_family_id, k, num_parameters, parameters));
|
func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||||
}
|
}
|
||||||
if (k == OP_ARITH_BAND) {
|
if (k == OP_ARITH_BAND || k == OP_ARITH_SHL || k == OP_ARITH_ASHR || k == OP_ARITH_LSHR) {
|
||||||
if (num_args != 2 || args[0]->get_sort() != m_int_decl || args[1]->get_sort() != m_int_decl || num_parameters != 1 || !parameters[0].is_int())
|
if (num_args != 2 || args[0]->get_sort() != m_int_decl || args[1]->get_sort() != m_int_decl || num_parameters != 1 || !parameters[0].is_int())
|
||||||
m_manager->raise_exception("invalid bitwise and application. Expects integer parameter and two arguments of sort integer");
|
m_manager->raise_exception("invalid bitwise and application. Expects integer parameter and two arguments of sort integer");
|
||||||
sort* domain[2] = { m_int_decl, m_int_decl };
|
sort* domain[2] = { m_int_decl, m_int_decl };
|
||||||
return m_manager->mk_func_decl(symbol("band"), 2, domain, m_int_decl,
|
return m_manager->mk_func_decl(bv_symbol(k), 2, domain, m_int_decl,
|
||||||
func_decl_info(m_family_id, k, num_parameters, parameters));
|
func_decl_info(m_family_id, k, num_parameters, parameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,9 @@ enum arith_op_kind {
|
||||||
OP_ATANH,
|
OP_ATANH,
|
||||||
// Bit-vector functions
|
// Bit-vector functions
|
||||||
OP_ARITH_BAND,
|
OP_ARITH_BAND,
|
||||||
|
OP_ARITH_SHL,
|
||||||
|
OP_ARITH_ASHR,
|
||||||
|
OP_ARITH_LSHR,
|
||||||
// constants
|
// constants
|
||||||
OP_PI,
|
OP_PI,
|
||||||
OP_E,
|
OP_E,
|
||||||
|
@ -150,6 +153,8 @@ protected:
|
||||||
|
|
||||||
bool m_convert_int_numerals_to_real;
|
bool m_convert_int_numerals_to_real;
|
||||||
|
|
||||||
|
symbol bv_symbol(decl_kind k) const;
|
||||||
|
|
||||||
func_decl * mk_func_decl(decl_kind k, bool is_real);
|
func_decl * mk_func_decl(decl_kind k, bool is_real);
|
||||||
void set_manager(ast_manager * m, family_id id) override;
|
void set_manager(ast_manager * m, family_id id) override;
|
||||||
decl_kind fix_kind(decl_kind k, unsigned arity);
|
decl_kind fix_kind(decl_kind k, unsigned arity);
|
||||||
|
@ -233,6 +238,14 @@ public:
|
||||||
executed in different threads.
|
executed in different threads.
|
||||||
*/
|
*/
|
||||||
class arith_recognizers {
|
class arith_recognizers {
|
||||||
|
bool is_arith_op(expr const* n, decl_kind k, unsigned& sz, expr*& x, expr*& y) {
|
||||||
|
if (!is_app_of(n, arith_family_id, k))
|
||||||
|
return false;
|
||||||
|
x = to_app(n)->get_arg(0);
|
||||||
|
y = to_app(n)->get_arg(1);
|
||||||
|
sz = to_app(n)->get_parameter(0).get_int();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
family_id get_family_id() const { return arith_family_id; }
|
family_id get_family_id() const { return arith_family_id; }
|
||||||
|
|
||||||
|
@ -296,14 +309,13 @@ public:
|
||||||
bool is_int_real(expr const * n) const { return is_int_real(n->get_sort()); }
|
bool is_int_real(expr const * n) const { return is_int_real(n->get_sort()); }
|
||||||
|
|
||||||
bool is_band(expr const* n) const { return is_app_of(n, arith_family_id, OP_ARITH_BAND); }
|
bool is_band(expr const* n) const { return is_app_of(n, arith_family_id, OP_ARITH_BAND); }
|
||||||
bool is_band(expr const* n, unsigned& sz, expr*& x, expr*& y) {
|
bool is_band(expr const* n, unsigned& sz, expr*& x, expr*& y) { return is_arith_op(n, OP_ARITH_BAND, sz, x, y); }
|
||||||
if (!is_band(n))
|
bool is_shl(expr const* n) const { return is_app_of(n, arith_family_id, OP_ARITH_SHL); }
|
||||||
return false;
|
bool is_shl(expr const* n, unsigned& sz, expr*& x, expr*& y) { return is_arith_op(n, OP_ARITH_SHL, sz, x, y); }
|
||||||
x = to_app(n)->get_arg(0);
|
bool is_lshr(expr const* n) const { return is_app_of(n, arith_family_id, OP_ARITH_LSHR); }
|
||||||
y = to_app(n)->get_arg(1);
|
bool is_lshr(expr const* n, unsigned& sz, expr*& x, expr*& y) { return is_arith_op(n, OP_ARITH_LSHR, sz, x, y); }
|
||||||
sz = to_app(n)->get_parameter(0).get_int();
|
bool is_ashr(expr const* n) const { return is_app_of(n, arith_family_id, OP_ARITH_ASHR); }
|
||||||
return true;
|
bool is_ashr(expr const* n, unsigned& sz, expr*& x, expr*& y) { return is_arith_op(n, OP_ARITH_ASHR, sz, x, y); }
|
||||||
}
|
|
||||||
|
|
||||||
bool is_sin(expr const* n) const { return is_app_of(n, arith_family_id, OP_SIN); }
|
bool is_sin(expr const* n) const { return is_app_of(n, arith_family_id, OP_SIN); }
|
||||||
bool is_cos(expr const* n) const { return is_app_of(n, arith_family_id, OP_COS); }
|
bool is_cos(expr const* n) const { return is_app_of(n, arith_family_id, OP_COS); }
|
||||||
|
@ -487,6 +499,9 @@ public:
|
||||||
app * mk_power0(expr* arg1, expr* arg2) { return m_manager.mk_app(arith_family_id, OP_POWER0, arg1, arg2); }
|
app * mk_power0(expr* arg1, expr* arg2) { return m_manager.mk_app(arith_family_id, OP_POWER0, arg1, arg2); }
|
||||||
|
|
||||||
app* mk_band(unsigned n, expr* arg1, expr* arg2) { parameter p(n); expr* args[2] = { arg1, arg2 }; return m_manager.mk_app(arith_family_id, OP_ARITH_BAND, 1, &p, 2, args); }
|
app* mk_band(unsigned n, expr* arg1, expr* arg2) { parameter p(n); expr* args[2] = { arg1, arg2 }; return m_manager.mk_app(arith_family_id, OP_ARITH_BAND, 1, &p, 2, args); }
|
||||||
|
app* mk_shl(unsigned n, expr* arg1, expr* arg2) { parameter p(n); expr* args[2] = { arg1, arg2 }; return m_manager.mk_app(arith_family_id, OP_ARITH_SHL, 1, &p, 2, args); }
|
||||||
|
app* mk_ashr(unsigned n, expr* arg1, expr* arg2) { parameter p(n); expr* args[2] = { arg1, arg2 }; return m_manager.mk_app(arith_family_id, OP_ARITH_ASHR, 1, &p, 2, args); }
|
||||||
|
app* mk_lshr(unsigned n, expr* arg1, expr* arg2) { parameter p(n); expr* args[2] = { arg1, arg2 }; return m_manager.mk_app(arith_family_id, OP_ARITH_LSHR, 1, &p, 2, args); }
|
||||||
|
|
||||||
app * mk_sin(expr * arg) { return m_manager.mk_app(arith_family_id, OP_SIN, arg); }
|
app * mk_sin(expr * arg) { return m_manager.mk_app(arith_family_id, OP_SIN, arg); }
|
||||||
app * mk_cos(expr * arg) { return m_manager.mk_app(arith_family_id, OP_COS, arg); }
|
app * mk_cos(expr * arg) { return m_manager.mk_app(arith_family_id, OP_COS, arg); }
|
||||||
|
|
|
@ -92,6 +92,9 @@ br_status arith_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c
|
||||||
case OP_COSH: SASSERT(num_args == 1); st = mk_cosh_core(args[0], result); break;
|
case OP_COSH: SASSERT(num_args == 1); st = mk_cosh_core(args[0], result); break;
|
||||||
case OP_TANH: SASSERT(num_args == 1); st = mk_tanh_core(args[0], result); break;
|
case OP_TANH: SASSERT(num_args == 1); st = mk_tanh_core(args[0], result); break;
|
||||||
case OP_ARITH_BAND: SASSERT(num_args == 2); st = mk_band_core(f->get_parameter(0).get_int(), args[0], args[1], result); break;
|
case OP_ARITH_BAND: SASSERT(num_args == 2); st = mk_band_core(f->get_parameter(0).get_int(), args[0], args[1], result); break;
|
||||||
|
case OP_ARITH_SHL: SASSERT(num_args == 2); st = mk_shl_core(f->get_parameter(0).get_int(), args[0], args[1], result); break;
|
||||||
|
case OP_ARITH_ASHR: SASSERT(num_args == 2); st = mk_ashr_core(f->get_parameter(0).get_int(), args[0], args[1], result); break;
|
||||||
|
case OP_ARITH_LSHR: SASSERT(num_args == 2); st = mk_lshr_core(f->get_parameter(0).get_int(), args[0], args[1], result); break;
|
||||||
default: st = BR_FAILED; break;
|
default: st = BR_FAILED; break;
|
||||||
}
|
}
|
||||||
CTRACE("arith_rewriter", st != BR_FAILED, tout << st << ": " << mk_pp(f, m);
|
CTRACE("arith_rewriter", st != BR_FAILED, tout << st << ": " << mk_pp(f, m);
|
||||||
|
@ -1350,6 +1353,98 @@ app* arith_rewriter_core::mk_power(expr* x, rational const& r, sort* s) {
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
br_status arith_rewriter::mk_shl_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result) {
|
||||||
|
numeral x, y, N;
|
||||||
|
bool is_num_x = m_util.is_numeral(arg1, x);
|
||||||
|
bool is_num_y = m_util.is_numeral(arg2, y);
|
||||||
|
N = rational::power_of_two(sz);
|
||||||
|
if (is_num_x)
|
||||||
|
x = mod(x, N);
|
||||||
|
if (is_num_y)
|
||||||
|
y = mod(y, N);
|
||||||
|
if (is_num_x && is_num_y) {
|
||||||
|
if (y >= sz)
|
||||||
|
result = m_util.mk_int(0);
|
||||||
|
else
|
||||||
|
result = m_util.mk_int(mod(x * rational::power_of_two(y.get_unsigned()), N));
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
if (is_num_y) {
|
||||||
|
if (y >= sz)
|
||||||
|
result = m_util.mk_int(0);
|
||||||
|
else
|
||||||
|
result = m_util.mk_mod(m_util.mk_mul(arg1, m_util.mk_int(rational::power_of_two(y.get_unsigned()))), m_util.mk_int(N));
|
||||||
|
return BR_REWRITE1;
|
||||||
|
}
|
||||||
|
if (is_num_x && x == 0) {
|
||||||
|
result = m_util.mk_int(0);
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
return BR_FAILED;
|
||||||
|
}
|
||||||
|
br_status arith_rewriter::mk_ashr_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result) {
|
||||||
|
numeral x, y, N;
|
||||||
|
bool is_num_x = m_util.is_numeral(arg1, x);
|
||||||
|
bool is_num_y = m_util.is_numeral(arg2, y);
|
||||||
|
N = rational::power_of_two(sz);
|
||||||
|
if (is_num_x)
|
||||||
|
x = mod(x, N);
|
||||||
|
if (is_num_y)
|
||||||
|
y = mod(y, N);
|
||||||
|
if (is_num_x && x == 0) {
|
||||||
|
result = m_util.mk_int(0);
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
if (is_num_x && is_num_y) {
|
||||||
|
bool signx = x >= N/2;
|
||||||
|
rational d = div(x, rational::power_of_two(y.get_unsigned()));
|
||||||
|
SASSERT(y >= 0);
|
||||||
|
if (signx) {
|
||||||
|
if (y >= sz)
|
||||||
|
result = m_util.mk_int(N-1);
|
||||||
|
else
|
||||||
|
result = m_util.mk_int(d);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (y >= sz)
|
||||||
|
result = m_util.mk_int(0);
|
||||||
|
else
|
||||||
|
result = m_util.mk_int(mod(d - rational::power_of_two(sz - y.get_unsigned()), N));
|
||||||
|
}
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
return BR_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
br_status arith_rewriter::mk_lshr_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result) {
|
||||||
|
numeral x, y, N;
|
||||||
|
bool is_num_x = m_util.is_numeral(arg1, x);
|
||||||
|
bool is_num_y = m_util.is_numeral(arg2, y);
|
||||||
|
N = rational::power_of_two(sz);
|
||||||
|
if (is_num_x)
|
||||||
|
x = mod(x, N);
|
||||||
|
if (is_num_y)
|
||||||
|
y = mod(y, N);
|
||||||
|
if (is_num_x && x == 0) {
|
||||||
|
result = m_util.mk_int(0);
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
if (is_num_y && y == 0) {
|
||||||
|
result = arg1;
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
if (is_num_x && is_num_y) {
|
||||||
|
if (y >= sz)
|
||||||
|
result = m_util.mk_int(N-1);
|
||||||
|
else {
|
||||||
|
rational d = div(x, rational::power_of_two(y.get_unsigned()));
|
||||||
|
result = m_util.mk_int(d);
|
||||||
|
}
|
||||||
|
return BR_DONE;
|
||||||
|
}
|
||||||
|
return BR_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
br_status arith_rewriter::mk_band_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result) {
|
br_status arith_rewriter::mk_band_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result) {
|
||||||
numeral x, y, N;
|
numeral x, y, N;
|
||||||
bool is_num_x = m_util.is_numeral(arg1, x);
|
bool is_num_x = m_util.is_numeral(arg1, x);
|
||||||
|
@ -1375,6 +1470,14 @@ br_status arith_rewriter::mk_band_core(unsigned sz, expr* arg1, expr* arg2, expr
|
||||||
result = m_util.mk_int(r);
|
result = m_util.mk_int(r);
|
||||||
return BR_DONE;
|
return BR_DONE;
|
||||||
}
|
}
|
||||||
|
if (is_num_x && (x + 1).is_power_of_two()) {
|
||||||
|
result = m_util.mk_mod(arg2, m_util.mk_int(x + 1));
|
||||||
|
return BR_REWRITE1;
|
||||||
|
}
|
||||||
|
if (is_num_y && (y + 1).is_power_of_two()) {
|
||||||
|
result = m_util.mk_mod(arg1, m_util.mk_int(y + 1));
|
||||||
|
return BR_REWRITE1;
|
||||||
|
}
|
||||||
return BR_FAILED;
|
return BR_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,9 @@ public:
|
||||||
br_status mk_rem_core(expr * arg1, expr * arg2, expr_ref & result);
|
br_status mk_rem_core(expr * arg1, expr * arg2, expr_ref & result);
|
||||||
br_status mk_power_core(expr* arg1, expr* arg2, expr_ref & result);
|
br_status mk_power_core(expr* arg1, expr* arg2, expr_ref & result);
|
||||||
br_status mk_band_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result);
|
br_status mk_band_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result);
|
||||||
|
br_status mk_shl_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result);
|
||||||
|
br_status mk_lshr_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result);
|
||||||
|
br_status mk_ashr_core(unsigned sz, expr* arg1, expr* arg2, expr_ref& result);
|
||||||
void mk_div(expr * arg1, expr * arg2, expr_ref & result) {
|
void mk_div(expr * arg1, expr * arg2, expr_ref & result) {
|
||||||
if (mk_div_core(arg1, arg2, result) == BR_FAILED)
|
if (mk_div_core(arg1, arg2, result) == BR_FAILED)
|
||||||
result = m.mk_app(get_fid(), OP_DIV, arg1, arg2);
|
result = m.mk_app(get_fid(), OP_DIV, arg1, arg2);
|
||||||
|
|
|
@ -108,7 +108,7 @@ namespace lp_api {
|
||||||
unsigned m_gomory_cuts;
|
unsigned m_gomory_cuts;
|
||||||
unsigned m_assume_eqs;
|
unsigned m_assume_eqs;
|
||||||
unsigned m_branch;
|
unsigned m_branch;
|
||||||
unsigned m_band_axioms;
|
unsigned m_bv_axioms;
|
||||||
stats() { reset(); }
|
stats() { reset(); }
|
||||||
void reset() {
|
void reset() {
|
||||||
memset(this, 0, sizeof(*this));
|
memset(this, 0, sizeof(*this));
|
||||||
|
@ -129,7 +129,7 @@ namespace lp_api {
|
||||||
st.update("arith-gomory-cuts", m_gomory_cuts);
|
st.update("arith-gomory-cuts", m_gomory_cuts);
|
||||||
st.update("arith-assume-eqs", m_assume_eqs);
|
st.update("arith-assume-eqs", m_assume_eqs);
|
||||||
st.update("arith-branch", m_branch);
|
st.update("arith-branch", m_branch);
|
||||||
st.update("arith-band-axioms", m_band_axioms);
|
st.update("arith-bv-axioms", m_bv_axioms);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -205,58 +205,117 @@ namespace arith {
|
||||||
add_clause(dgez, neg);
|
add_clause(dgez, neg);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool solver::check_band_term(app* n) {
|
bool solver::check_bv_term(app* n) {
|
||||||
unsigned sz;
|
unsigned sz;
|
||||||
expr* x, * y;
|
expr* _x, * _y;
|
||||||
if (!ctx.is_relevant(expr2enode(n)))
|
if (!ctx.is_relevant(expr2enode(n)))
|
||||||
return true;
|
return true;
|
||||||
VERIFY(a.is_band(n, sz, x, y));
|
|
||||||
expr_ref vx(m), vy(m),vn(m);
|
expr_ref vx(m), vy(m),vn(m);
|
||||||
if (!get_value(expr2enode(x), vx) || !get_value(expr2enode(y), vy) || !get_value(expr2enode(n), vn)) {
|
rational valn, valx, valy;
|
||||||
|
bool is_int;
|
||||||
|
VERIFY(a.is_band(n, sz, _x, _y) || a.is_shl(n, sz, _x, _y) || a.is_ashr(n, sz, _x, _y) || a.is_lshr(n, sz, _x, _y));
|
||||||
|
if (!get_value(expr2enode(_x), vx) || !get_value(expr2enode(_y), vy) || !get_value(expr2enode(n), vn)) {
|
||||||
IF_VERBOSE(2, verbose_stream() << "could not get value of " << mk_pp(n, m) << "\n");
|
IF_VERBOSE(2, verbose_stream() << "could not get value of " << mk_pp(n, m) << "\n");
|
||||||
found_unsupported(n);
|
found_unsupported(n);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
rational valn, valx, valy;
|
|
||||||
bool is_int;
|
|
||||||
if (!a.is_numeral(vn, valn, is_int) || !is_int || !a.is_numeral(vx, valx, is_int) || !is_int || !a.is_numeral(vy, valy, is_int) || !is_int) {
|
if (!a.is_numeral(vn, valn, is_int) || !is_int || !a.is_numeral(vx, valx, is_int) || !is_int || !a.is_numeral(vy, valy, is_int) || !is_int) {
|
||||||
IF_VERBOSE(2, verbose_stream() << "could not get value of " << mk_pp(n, m) << "\n");
|
IF_VERBOSE(2, verbose_stream() << "could not get value of " << mk_pp(n, m) << "\n");
|
||||||
found_unsupported(n);
|
found_unsupported(n);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// verbose_stream() << "band: " << mk_pp(n, m) << " " << valn << " := " << valx << "&" << valy << "\n";
|
|
||||||
rational N = rational::power_of_two(sz);
|
rational N = rational::power_of_two(sz);
|
||||||
valx = mod(valx, N);
|
valx = mod(valx, N);
|
||||||
valy = mod(valy, N);
|
valy = mod(valy, N);
|
||||||
|
expr_ref x(a.mk_mod(_x, a.mk_int(N)), m);
|
||||||
|
expr_ref y(a.mk_mod(_y, a.mk_int(N)), m);
|
||||||
SASSERT(0 <= valn && valn < N);
|
SASSERT(0 <= valn && valn < N);
|
||||||
|
|
||||||
// x mod 2^{i + 1} >= 2^i means the i'th bit is 1.
|
// x mod 2^{i + 1} >= 2^i means the i'th bit is 1.
|
||||||
auto bitof = [&](expr* x, unsigned i) {
|
auto bitof = [&](expr* x, unsigned i) {
|
||||||
expr_ref r(m);
|
expr_ref r(m);
|
||||||
r = a.mk_ge(a.mk_mod(x, a.mk_int(rational::power_of_two(i+1))), a.mk_int(rational::power_of_two(i)));
|
r = a.mk_ge(a.mk_mod(x, a.mk_int(rational::power_of_two(i+1))), a.mk_int(rational::power_of_two(i)));
|
||||||
return mk_literal(r);
|
return mk_literal(r);
|
||||||
};
|
};
|
||||||
for (unsigned i = 0; i < sz; ++i) {
|
|
||||||
bool xb = valx.get_bit(i);
|
if (a.is_band(n)) {
|
||||||
bool yb = valy.get_bit(i);
|
IF_VERBOSE(2, verbose_stream() << "band: " << mk_bounded_pp(n, m) << " " << valn << " := " << valx << "&" << valy << "\n");
|
||||||
bool nb = valn.get_bit(i);
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
if (xb && yb && !nb)
|
bool xb = valx.get_bit(i);
|
||||||
add_clause(~bitof(x, i), ~bitof(y, i), bitof(n, i));
|
bool yb = valy.get_bit(i);
|
||||||
else if (nb && !xb)
|
bool nb = valn.get_bit(i);
|
||||||
add_clause(~bitof(n, i), bitof(x, i));
|
if (xb && yb && !nb)
|
||||||
else if (nb && !yb)
|
add_clause(~bitof(x, i), ~bitof(y, i), bitof(n, i));
|
||||||
add_clause(~bitof(n, i), bitof(y, i));
|
else if (nb && !xb)
|
||||||
else
|
add_clause(~bitof(n, i), bitof(x, i));
|
||||||
continue;
|
else if (nb && !yb)
|
||||||
|
add_clause(~bitof(n, i), bitof(y, i));
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (a.is_shl(n)) {
|
||||||
|
SASSERT(valy >= 0);
|
||||||
|
if (valy >= sz || valy == 0)
|
||||||
|
return true;
|
||||||
|
unsigned k = valy.get_unsigned();
|
||||||
|
sat::literal eq = eq_internalize(n, a.mk_mod(a.mk_mul(_x, a.mk_int(rational::power_of_two(k))), a.mk_int(N)));
|
||||||
|
if (s().value(eq) == l_true)
|
||||||
|
return true;
|
||||||
|
add_clause(~eq_internalize(y, a.mk_int(k)), eq);
|
||||||
|
IF_VERBOSE(2, verbose_stream() << "shl: " << mk_bounded_pp(n, m) << " " << valn << " := " << valx << " << " << valy << "\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (a.is_lshr(n)) {
|
||||||
|
SASSERT(valy >= 0);
|
||||||
|
if (valy >= sz || valy == 0)
|
||||||
|
return true;
|
||||||
|
unsigned k = valy.get_unsigned();
|
||||||
|
sat::literal eq = eq_internalize(n, a.mk_idiv(x, a.mk_int(rational::power_of_two(k))));
|
||||||
|
if (s().value(eq) == l_true)
|
||||||
|
return true;
|
||||||
|
add_clause(~eq_internalize(y, a.mk_int(k)), eq);
|
||||||
|
IF_VERBOSE(2, verbose_stream() << "lshr: " << mk_bounded_pp(n, m) << " " << valn << " := " << valx << " >>l " << valy << "\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (a.is_ashr(n)) {
|
||||||
|
SASSERT(valy >= 0);
|
||||||
|
if (valy >= sz || valy == 0)
|
||||||
|
return true;
|
||||||
|
unsigned k = valy.get_unsigned();
|
||||||
|
sat::literal signx = mk_literal(a.mk_ge(x, a.mk_int(N/2)));
|
||||||
|
sat::literal eq;
|
||||||
|
expr* xdiv2k;
|
||||||
|
switch (s().value(signx)) {
|
||||||
|
case l_true:
|
||||||
|
// x < 0 & y = k -> n = (x div 2^k - 2^{N-k}) mod 2^N
|
||||||
|
xdiv2k = a.mk_idiv(x, a.mk_int(rational::power_of_two(k)));
|
||||||
|
eq = eq_internalize(n, a.mk_mod(a.mk_add(xdiv2k, a.mk_int(-rational::power_of_two(sz - k))), a.mk_int(N)));
|
||||||
|
if (s().value(eq) == l_true)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case l_false:
|
||||||
|
// x >= 0 & y = k -> n = x div 2^k
|
||||||
|
xdiv2k = a.mk_idiv(x, a.mk_int(rational::power_of_two(k)));
|
||||||
|
eq = eq_internalize(n, xdiv2k);
|
||||||
|
if (s().value(eq) == l_true)
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case l_undef:
|
||||||
|
ctx.mark_relevant(signx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
add_clause(~eq_internalize(y, a.mk_int(k)), ~signx, eq);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool solver::check_band_terms() {
|
bool solver::check_bv_terms() {
|
||||||
for (app* n : m_band_terms) {
|
for (app* n : m_bv_terms) {
|
||||||
if (!check_band_term(n)) {
|
if (!check_bv_term(n)) {
|
||||||
++m_stats.m_band_axioms;
|
++m_stats.m_bv_axioms;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,15 +327,43 @@ namespace arith {
|
||||||
* x&y <= x
|
* x&y <= x
|
||||||
* x&y <= y
|
* x&y <= y
|
||||||
*/
|
*/
|
||||||
void solver::mk_band_axiom(app* n) {
|
void solver::mk_bv_axiom(app* n) {
|
||||||
unsigned sz;
|
unsigned sz;
|
||||||
expr* x, * y;
|
expr* _x, * _y;
|
||||||
VERIFY(a.is_band(n, sz, x, y));
|
VERIFY(a.is_band(n, sz, _x, _y) || a.is_shl(n, sz, _x, _y) || a.is_ashr(n, sz, _x, _y) || a.is_lshr(n, sz, _x, _y));
|
||||||
rational N = rational::power_of_two(sz);
|
rational N = rational::power_of_two(sz);
|
||||||
add_clause(mk_literal(a.mk_ge(n, a.mk_int(0))));
|
expr_ref x(a.mk_mod(_x, a.mk_int(N)), m);
|
||||||
add_clause(mk_literal(a.mk_le(n, a.mk_int(N - 1))));
|
expr_ref y(a.mk_mod(_y, a.mk_int(N)), m);
|
||||||
add_clause(mk_literal(a.mk_le(n, a.mk_mod(x, a.mk_int(N)))));
|
|
||||||
add_clause(mk_literal(a.mk_le(n, a.mk_mod(y, a.mk_int(N)))));
|
if (a.is_band(n)) {
|
||||||
|
add_clause(mk_literal(a.mk_ge(n, a.mk_int(0))));
|
||||||
|
add_clause(mk_literal(a.mk_le(n, a.mk_int(N - 1))));
|
||||||
|
add_clause(mk_literal(a.mk_le(n, x)));
|
||||||
|
add_clause(mk_literal(a.mk_le(n, y)));
|
||||||
|
}
|
||||||
|
else if (a.is_shl(n)) {
|
||||||
|
// y >= sz => n = 0
|
||||||
|
// y = 0 => n = x
|
||||||
|
add_clause(~mk_literal(a.mk_ge(y, a.mk_int(sz))), mk_literal(m.mk_eq(n, a.mk_int(0))));
|
||||||
|
add_clause(~mk_literal(a.mk_eq(y, a.mk_int(0))), mk_literal(m.mk_eq(n, x)));
|
||||||
|
}
|
||||||
|
else if (a.is_lshr(n)) {
|
||||||
|
// y >= sz => n = 0
|
||||||
|
// y = 0 => n = x
|
||||||
|
add_clause(~mk_literal(a.mk_ge(y, a.mk_int(sz))), mk_literal(m.mk_eq(n, a.mk_int(0))));
|
||||||
|
add_clause(~mk_literal(a.mk_eq(y, a.mk_int(0))), mk_literal(m.mk_eq(n, x)));
|
||||||
|
}
|
||||||
|
else if (a.is_ashr(n)) {
|
||||||
|
// y >= sz & x < 2^{sz-1} => n = 0
|
||||||
|
// y >= sz & x >= 2^{sz-1} => n = -1
|
||||||
|
// y = 0 => n = x
|
||||||
|
auto signx = mk_literal(a.mk_ge(x, a.mk_int(N/2)));
|
||||||
|
add_clause(~mk_literal(a.mk_ge(a.mk_mod(y, a.mk_int(N)), a.mk_int(sz))), signx, mk_literal(m.mk_eq(n, a.mk_int(0))));
|
||||||
|
add_clause(~mk_literal(a.mk_ge(a.mk_mod(y, a.mk_int(N)), a.mk_int(sz))), ~signx, mk_literal(m.mk_eq(n, a.mk_int(N-1))));
|
||||||
|
add_clause(~mk_literal(a.mk_eq(a.mk_mod(y, a.mk_int(N)), a.mk_int(0))), mk_literal(m.mk_eq(n, x)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
|
||||||
void solver::mk_bound_axioms(api_bound& b) {
|
void solver::mk_bound_axioms(api_bound& b) {
|
||||||
|
|
|
@ -252,10 +252,10 @@ namespace arith {
|
||||||
st.to_ensure_var().push_back(n1);
|
st.to_ensure_var().push_back(n1);
|
||||||
st.to_ensure_var().push_back(n2);
|
st.to_ensure_var().push_back(n2);
|
||||||
}
|
}
|
||||||
else if (a.is_band(n)) {
|
else if (a.is_band(n) || a.is_shl(n) || a.is_ashr(n) || a.is_lshr(n)) {
|
||||||
m_band_terms.push_back(to_app(n));
|
m_bv_terms.push_back(to_app(n));
|
||||||
mk_band_axiom(to_app(n));
|
ctx.push(push_back_vector(m_bv_terms));
|
||||||
ctx.push(push_back_vector(m_band_terms));
|
mk_bv_axiom(to_app(n));
|
||||||
ensure_arg_vars(to_app(n));
|
ensure_arg_vars(to_app(n));
|
||||||
}
|
}
|
||||||
else if (!a.is_div0(n) && !a.is_mod0(n) && !a.is_idiv0(n) && !a.is_rem0(n) && !a.is_power0(n)) {
|
else if (!a.is_div0(n) && !a.is_mod0(n) && !a.is_idiv0(n) && !a.is_rem0(n) && !a.is_power0(n)) {
|
||||||
|
|
|
@ -1053,7 +1053,7 @@ namespace arith {
|
||||||
if (!check_delayed_eqs())
|
if (!check_delayed_eqs())
|
||||||
return sat::check_result::CR_CONTINUE;
|
return sat::check_result::CR_CONTINUE;
|
||||||
|
|
||||||
if (!int_undef && !check_band_terms())
|
if (!int_undef && !check_bv_terms())
|
||||||
return sat::check_result::CR_CONTINUE;
|
return sat::check_result::CR_CONTINUE;
|
||||||
|
|
||||||
if (ctx.get_config().m_arith_ignore_int && int_undef)
|
if (ctx.get_config().m_arith_ignore_int && int_undef)
|
||||||
|
|
|
@ -214,7 +214,7 @@ namespace arith {
|
||||||
expr* m_not_handled = nullptr;
|
expr* m_not_handled = nullptr;
|
||||||
ptr_vector<app> m_underspecified;
|
ptr_vector<app> m_underspecified;
|
||||||
ptr_vector<expr> m_idiv_terms;
|
ptr_vector<expr> m_idiv_terms;
|
||||||
ptr_vector<app> m_band_terms;
|
ptr_vector<app> m_bv_terms;
|
||||||
vector<ptr_vector<api_bound> > m_use_list; // bounds where variables are used.
|
vector<ptr_vector<api_bound> > m_use_list; // bounds where variables are used.
|
||||||
|
|
||||||
// attributes for incremental version:
|
// attributes for incremental version:
|
||||||
|
@ -318,7 +318,7 @@ namespace arith {
|
||||||
void mk_bound_axioms(api_bound& b);
|
void mk_bound_axioms(api_bound& b);
|
||||||
void mk_bound_axiom(api_bound& b1, api_bound& b2);
|
void mk_bound_axiom(api_bound& b1, api_bound& b2);
|
||||||
void mk_power0_axioms(app* t, app* n);
|
void mk_power0_axioms(app* t, app* n);
|
||||||
void mk_band_axiom(app* n);
|
void mk_bv_axiom(app* n);
|
||||||
void flush_bound_axioms();
|
void flush_bound_axioms();
|
||||||
void add_farkas_clause(sat::literal l1, sat::literal l2);
|
void add_farkas_clause(sat::literal l1, sat::literal l2);
|
||||||
|
|
||||||
|
@ -410,8 +410,8 @@ namespace arith {
|
||||||
bool check_delayed_eqs();
|
bool check_delayed_eqs();
|
||||||
lbool check_lia();
|
lbool check_lia();
|
||||||
lbool check_nla();
|
lbool check_nla();
|
||||||
bool check_band_terms();
|
bool check_bv_terms();
|
||||||
bool check_band_term(app* n);
|
bool check_bv_term(app* n);
|
||||||
void add_lemmas();
|
void add_lemmas();
|
||||||
void propagate_nla();
|
void propagate_nla();
|
||||||
void add_equality(lpvar v, rational const& k, lp::explanation const& exp);
|
void add_equality(lpvar v, rational const& k, lp::explanation const& exp);
|
||||||
|
|
|
@ -656,24 +656,58 @@ namespace intblast {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_BSHL: {
|
case OP_BSHL: {
|
||||||
expr* x = arg(0), * y = umod(e, 1);
|
if (!a.is_numeral(arg(0)) && !a.is_numeral(arg(1)))
|
||||||
r = a.mk_int(0);
|
r = a.mk_shl(bv.get_bv_size(e), arg(0),arg(1));
|
||||||
for (unsigned i = 0; i < bv.get_bv_size(e); ++i)
|
else {
|
||||||
r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), a.mk_mul(x, a.mk_int(rational::power_of_two(i))), r);
|
expr* x = arg(0), * y = umod(e, 1);
|
||||||
|
r = a.mk_int(0);
|
||||||
|
IF_VERBOSE(2, verbose_stream() << "shl " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n");
|
||||||
|
for (unsigned i = 0; i < bv.get_bv_size(e); ++i)
|
||||||
|
r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), a.mk_mul(x, a.mk_int(rational::power_of_two(i))), r);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_BNOT:
|
case OP_BNOT:
|
||||||
r = bnot(arg(0));
|
r = bnot(arg(0));
|
||||||
break;
|
break;
|
||||||
case OP_BLSHR: {
|
case OP_BLSHR:
|
||||||
expr* x = arg(0), * y = umod(e, 1);
|
if (!a.is_numeral(arg(0)) && !a.is_numeral(arg(1)))
|
||||||
r = a.mk_int(0);
|
r = a.mk_lshr(bv.get_bv_size(e), arg(0), arg(1));
|
||||||
for (unsigned i = 0; i < bv.get_bv_size(e); ++i)
|
else {
|
||||||
r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), a.mk_idiv(x, a.mk_int(rational::power_of_two(i))), r);
|
expr* x = arg(0), * y = umod(e, 1);
|
||||||
|
r = a.mk_int(0);
|
||||||
|
IF_VERBOSE(2, verbose_stream() << "lshr " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n");
|
||||||
|
for (unsigned i = 0; i < bv.get_bv_size(e); ++i)
|
||||||
|
r = m.mk_ite(m.mk_eq(y, a.mk_int(i)), a.mk_idiv(x, a.mk_int(rational::power_of_two(i))), r);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OP_BASHR:
|
||||||
|
if (!a.is_numeral(arg(1)))
|
||||||
|
r = a.mk_ashr(bv.get_bv_size(e), arg(0), arg(1));
|
||||||
|
else {
|
||||||
|
|
||||||
|
//
|
||||||
|
// ashr(x, y)
|
||||||
|
// if y = k & x >= 0 -> x / 2^k
|
||||||
|
// if y = k & x < 0 -> (x / 2^k) - 2^{N-k}
|
||||||
|
//
|
||||||
|
unsigned sz = bv.get_bv_size(e);
|
||||||
|
rational N = bv_size(e);
|
||||||
|
expr* x = umod(e, 0), *y = umod(e, 1);
|
||||||
|
expr* signx = a.mk_ge(x, a.mk_int(N / 2));
|
||||||
|
r = m.mk_ite(signx, a.mk_int(- 1), a.mk_int(0));
|
||||||
|
IF_VERBOSE(1, verbose_stream() << "ashr " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n");
|
||||||
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
|
expr* d = a.mk_idiv(x, a.mk_int(rational::power_of_two(i)));
|
||||||
|
r = m.mk_ite(m.mk_eq(y, a.mk_int(i)),
|
||||||
|
m.mk_ite(signx, a.mk_add(d, a.mk_int(- rational::power_of_two(sz-i))), d),
|
||||||
|
r);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case OP_BOR: {
|
case OP_BOR: {
|
||||||
// p | q := (p + q) - band(p, q)
|
// p | q := (p + q) - band(p, q)
|
||||||
|
IF_VERBOSE(2, verbose_stream() << "bor " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n");
|
||||||
r = arg(0);
|
r = arg(0);
|
||||||
for (unsigned i = 1; i < args.size(); ++i)
|
for (unsigned i = 1; i < args.size(); ++i)
|
||||||
r = a.mk_sub(a.mk_add(r, arg(i)), a.mk_band(bv.get_bv_size(e), r, arg(i)));
|
r = a.mk_sub(a.mk_add(r, arg(i)), a.mk_band(bv.get_bv_size(e), r, arg(i)));
|
||||||
|
@ -683,12 +717,14 @@ namespace intblast {
|
||||||
r = bnot(band(args));
|
r = bnot(band(args));
|
||||||
break;
|
break;
|
||||||
case OP_BAND:
|
case OP_BAND:
|
||||||
|
IF_VERBOSE(2, verbose_stream() << "band " << mk_bounded_pp(e, m) << " " << bv.get_bv_size(e) << "\n");
|
||||||
r = band(args);
|
r = band(args);
|
||||||
break;
|
break;
|
||||||
case OP_BXNOR:
|
case OP_BXNOR:
|
||||||
case OP_BXOR: {
|
case OP_BXOR: {
|
||||||
// p ^ q := (p + q) - 2*band(p, q);
|
// p ^ q := (p + q) - 2*band(p, q);
|
||||||
unsigned sz = bv.get_bv_size(e);
|
unsigned sz = bv.get_bv_size(e);
|
||||||
|
IF_VERBOSE(2, verbose_stream() << "bxor " << bv.get_bv_size(e) << "\n");
|
||||||
r = arg(0);
|
r = arg(0);
|
||||||
for (unsigned i = 1; i < args.size(); ++i) {
|
for (unsigned i = 1; i < args.size(); ++i) {
|
||||||
expr* q = arg(i);
|
expr* q = arg(i);
|
||||||
|
@ -698,25 +734,6 @@ namespace intblast {
|
||||||
r = bnot(r);
|
r = bnot(r);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_BASHR: {
|
|
||||||
//
|
|
||||||
// ashr(x, y)
|
|
||||||
// if y = k & x >= 0 -> x / 2^k
|
|
||||||
// if y = k & x < 0 -> (x / 2^k) - 1 + 2^{N-k}
|
|
||||||
//
|
|
||||||
unsigned sz = bv.get_bv_size(e);
|
|
||||||
rational N = bv_size(e);
|
|
||||||
expr* x = umod(e, 0), *y = umod(e, 1);
|
|
||||||
expr* signx = a.mk_ge(x, a.mk_int(N / 2));
|
|
||||||
r = m.mk_ite(signx, a.mk_int(- 1), a.mk_int(0));
|
|
||||||
for (unsigned i = 0; i < sz; ++i) {
|
|
||||||
expr* d = a.mk_idiv(x, a.mk_int(rational::power_of_two(i)));
|
|
||||||
r = m.mk_ite(m.mk_eq(y, a.mk_int(i)),
|
|
||||||
m.mk_ite(signx, a.mk_add(d, a.mk_int(- rational::power_of_two(sz-i))), d),
|
|
||||||
r);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OP_ZERO_EXT:
|
case OP_ZERO_EXT:
|
||||||
bv_expr = e->get_arg(0);
|
bv_expr = e->get_arg(0);
|
||||||
r = umod(bv_expr, 0);
|
r = umod(bv_expr, 0);
|
||||||
|
|
Loading…
Reference in a new issue