mirror of
https://github.com/Z3Prover/z3
synced 2025-10-04 15:03:57 +00:00
Merge branch 'master' into polysat
This commit is contained in:
commit
20b5455d08
669 changed files with 26145 additions and 20652 deletions
|
@ -14,6 +14,7 @@ z3_add_component(rewriter
|
|||
der.cpp
|
||||
distribute_forall.cpp
|
||||
dl_rewriter.cpp
|
||||
dom_simplifier.cpp
|
||||
elim_bounds.cpp
|
||||
enum2bv_rewriter.cpp
|
||||
expr_replacer.cpp
|
||||
|
@ -25,6 +26,7 @@ z3_add_component(rewriter
|
|||
hoist_rewriter.cpp
|
||||
inj_axiom.cpp
|
||||
label_rewriter.cpp
|
||||
macro_replacer.cpp
|
||||
maximize_ac_sharing.cpp
|
||||
mk_simplified_app.cpp
|
||||
pb_rewriter.cpp
|
||||
|
@ -45,5 +47,6 @@ z3_add_component(rewriter
|
|||
ast
|
||||
params
|
||||
automata
|
||||
interval
|
||||
polynomial
|
||||
)
|
||||
|
|
|
@ -23,9 +23,8 @@ Notes:
|
|||
#include "ast/ast_pp.h"
|
||||
|
||||
seq_util& arith_rewriter_core::seq() {
|
||||
if (!m_seq) {
|
||||
m_seq = alloc(seq_util, m());
|
||||
}
|
||||
if (!m_seq)
|
||||
m_seq = alloc(seq_util, m);
|
||||
return *m_seq;
|
||||
}
|
||||
|
||||
|
@ -93,9 +92,9 @@ br_status arith_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c
|
|||
case OP_TANH: SASSERT(num_args == 1); st = mk_tanh_core(args[0], result); break;
|
||||
default: st = BR_FAILED; break;
|
||||
}
|
||||
CTRACE("arith_rewriter", st != BR_FAILED, tout << st << ": " << mk_pp(f, m());
|
||||
for (unsigned i = 0; i < num_args; ++i) tout << mk_pp(args[i], m()) << " ";
|
||||
tout << "\n==>\n" << mk_pp(result.get(), m()) << "\n";
|
||||
CTRACE("arith_rewriter", st != BR_FAILED, tout << st << ": " << mk_pp(f, m);
|
||||
for (unsigned i = 0; i < num_args; ++i) tout << mk_pp(args[i], m) << " ";
|
||||
tout << "\n==>\n" << mk_pp(result.get(), m) << "\n";
|
||||
if (is_app(result)) tout << "args: " << to_app(result)->get_num_args() << "\n";
|
||||
);
|
||||
return st;
|
||||
|
@ -133,7 +132,7 @@ bool arith_rewriter::div_polynomial(expr * t, numeral const & g, const_treatment
|
|||
SASSERT(!g.is_one());
|
||||
unsigned sz;
|
||||
expr * const * ms = get_monomials(t, sz);
|
||||
expr_ref_buffer new_args(m());
|
||||
expr_ref_buffer new_args(m);
|
||||
numeral a;
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * arg = ms[i];
|
||||
|
@ -196,10 +195,10 @@ bool arith_rewriter::is_bound(expr * arg1, expr * arg2, op_kind kind, expr_ref &
|
|||
switch (kind) {
|
||||
case LE: c = floor(c); break;
|
||||
case GE: c = ceil(c); break;
|
||||
case EQ: result = m().mk_false(); return true;
|
||||
case EQ: result = m.mk_false(); return true;
|
||||
}
|
||||
}
|
||||
expr_ref k(m_util.mk_numeral(c, is_int), m());
|
||||
expr_ref k(m_util.mk_numeral(c, is_int), m);
|
||||
switch (kind) {
|
||||
case LE: result = m_util.mk_le(pp, k); return true;
|
||||
case GE: result = m_util.mk_ge(pp, k); return true;
|
||||
|
@ -223,24 +222,24 @@ bool arith_rewriter::is_bound(expr * arg1, expr * arg2, op_kind kind, expr_ref &
|
|||
if (c.is_neg()) {
|
||||
switch (kind) {
|
||||
case EQ:
|
||||
case LE: result = m().mk_false(); return true;
|
||||
case GE: result = m().mk_true(); return true;
|
||||
case LE: result = m.mk_false(); return true;
|
||||
case GE: result = m.mk_true(); return true;
|
||||
}
|
||||
}
|
||||
if (c.is_zero() && kind == GE) {
|
||||
result = m().mk_true();
|
||||
result = m.mk_true();
|
||||
return true;
|
||||
}
|
||||
if (c.is_pos() && c >= abs(b)) {
|
||||
switch (kind) {
|
||||
case LE: result = m().mk_true(); return true;
|
||||
case LE: result = m.mk_true(); return true;
|
||||
case EQ:
|
||||
case GE: result = m().mk_false(); return true;
|
||||
case GE: result = m.mk_false(); return true;
|
||||
}
|
||||
}
|
||||
// mod x b <= b - 1
|
||||
if (c + rational::one() == abs(b) && kind == LE) {
|
||||
result = m().mk_true();
|
||||
result = m.mk_true();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +303,7 @@ br_status arith_rewriter::is_separated(expr* arg1, expr* arg2, op_kind kind, exp
|
|||
if (kind != LE && kind != GE)
|
||||
return BR_FAILED;
|
||||
rational bound(0), r1, r2;
|
||||
expr_ref narg(m());
|
||||
expr_ref narg(m);
|
||||
bool has_bound = true;
|
||||
if (!m_util.is_numeral(arg2, r2))
|
||||
return BR_FAILED;
|
||||
|
@ -335,47 +334,47 @@ br_status arith_rewriter::is_separated(expr* arg1, expr* arg2, op_kind kind, exp
|
|||
if (kind == GE && r1 > r2)
|
||||
return BR_FAILED;
|
||||
if (kind == LE && r1 > r2) {
|
||||
result = m().mk_false();
|
||||
result = m.mk_false();
|
||||
return BR_DONE;
|
||||
}
|
||||
if (kind == GE && r1 < r2) {
|
||||
result = m().mk_false();
|
||||
result = m.mk_false();
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
SASSERT(r1 == r2);
|
||||
expr_ref zero(m_util.mk_numeral(rational(0), arg1->get_sort()), m());
|
||||
expr_ref zero(m_util.mk_numeral(rational(0), arg1->get_sort()), m);
|
||||
|
||||
if (r1.is_zero() && m_util.is_mul(arg1)) {
|
||||
expr_ref_buffer eqs(m());
|
||||
expr_ref_buffer eqs(m);
|
||||
ptr_buffer<expr> args;
|
||||
flat_mul(arg1, args);
|
||||
for (expr* arg : args) {
|
||||
if (m_util.is_numeral(arg))
|
||||
continue;
|
||||
eqs.push_back(m().mk_eq(arg, zero));
|
||||
eqs.push_back(m.mk_eq(arg, zero));
|
||||
}
|
||||
result = m().mk_or(eqs);
|
||||
result = m.mk_or(eqs);
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
if (kind == LE && m_util.is_add(arg1)) {
|
||||
expr_ref_buffer leqs(m());
|
||||
expr_ref_buffer leqs(m);
|
||||
for (expr* arg : *to_app(arg1)) {
|
||||
if (!m_util.is_numeral(arg))
|
||||
leqs.push_back(m_util.mk_le(arg, zero));
|
||||
}
|
||||
result = m().mk_and(leqs);
|
||||
result = m.mk_and(leqs);
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
if (kind == GE && m_util.is_add(arg1)) {
|
||||
expr_ref_buffer geqs(m());
|
||||
expr_ref_buffer geqs(m);
|
||||
for (expr* arg : *to_app(arg1)) {
|
||||
if (!m_util.is_numeral(arg))
|
||||
geqs.push_back(m_util.mk_ge(arg, zero));
|
||||
}
|
||||
result = m().mk_and(geqs);
|
||||
result = m.mk_and(geqs);
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
|
@ -399,8 +398,8 @@ bool arith_rewriter::elim_to_real_var(expr * var, expr_ref & new_var) {
|
|||
|
||||
bool arith_rewriter::elim_to_real_mon(expr * monomial, expr_ref & new_monomial) {
|
||||
if (m_util.is_mul(monomial)) {
|
||||
expr_ref_buffer new_vars(m());
|
||||
expr_ref new_var(m());
|
||||
expr_ref_buffer new_vars(m);
|
||||
expr_ref new_var(m);
|
||||
unsigned num = to_app(monomial)->get_num_args();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
if (!elim_to_real_var(to_app(monomial)->get_arg(i), new_var))
|
||||
|
@ -417,8 +416,8 @@ bool arith_rewriter::elim_to_real_mon(expr * monomial, expr_ref & new_monomial)
|
|||
|
||||
bool arith_rewriter::elim_to_real_pol(expr * p, expr_ref & new_p) {
|
||||
if (m_util.is_add(p)) {
|
||||
expr_ref_buffer new_monomials(m());
|
||||
expr_ref new_monomial(m());
|
||||
expr_ref_buffer new_monomials(m);
|
||||
expr_ref new_monomial(m);
|
||||
for (expr* arg : *to_app(p)) {
|
||||
if (!elim_to_real_mon(arg, new_monomial))
|
||||
return false;
|
||||
|
@ -507,14 +506,14 @@ br_status arith_rewriter::reduce_power(expr * arg1, expr * arg2, op_kind kind, e
|
|||
switch (kind) {
|
||||
case LE: result = m_util.mk_le(new_arg1, new_arg2); return BR_REWRITE1;
|
||||
case GE: result = m_util.mk_ge(new_arg1, new_arg2); return BR_REWRITE1;
|
||||
default: result = m().mk_eq(new_arg1, new_arg2); return BR_REWRITE1;
|
||||
default: result = m.mk_eq(new_arg1, new_arg2); return BR_REWRITE1;
|
||||
}
|
||||
}
|
||||
|
||||
br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kind, expr_ref & result) {
|
||||
expr *orig_arg1 = arg1, *orig_arg2 = arg2;
|
||||
expr_ref new_arg1(m());
|
||||
expr_ref new_arg2(m());
|
||||
expr_ref new_arg1(m);
|
||||
expr_ref new_arg2(m);
|
||||
if ((is_zero(arg1) && is_reduce_power_target(arg2, kind == EQ)) ||
|
||||
(is_zero(arg2) && is_reduce_power_target(arg1, kind == EQ)))
|
||||
return reduce_power(arg1, arg2, kind, result);
|
||||
|
@ -524,29 +523,29 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin
|
|||
arg1 = new_arg1;
|
||||
arg2 = new_arg2;
|
||||
}
|
||||
expr_ref new_new_arg1(m());
|
||||
expr_ref new_new_arg2(m());
|
||||
expr_ref new_new_arg1(m);
|
||||
expr_ref new_new_arg2(m);
|
||||
if (m_elim_to_real && elim_to_real(arg1, arg2, new_new_arg1, new_new_arg2)) {
|
||||
arg1 = new_new_arg1;
|
||||
arg2 = new_new_arg2;
|
||||
CTRACE("elim_to_real", m_elim_to_real, tout << "after_elim_to_real\n" << mk_ismt2_pp(arg1, m()) << "\n" << mk_ismt2_pp(arg2, m()) << "\n";);
|
||||
CTRACE("elim_to_real", m_elim_to_real, tout << "after_elim_to_real\n" << mk_ismt2_pp(arg1, m) << "\n" << mk_ismt2_pp(arg2, m) << "\n";);
|
||||
if (st == BR_FAILED)
|
||||
st = BR_DONE;
|
||||
}
|
||||
numeral a1, a2;
|
||||
if (is_numeral(arg1, a1) && is_numeral(arg2, a2)) {
|
||||
switch (kind) {
|
||||
case LE: result = a1 <= a2 ? m().mk_true() : m().mk_false(); return BR_DONE;
|
||||
case GE: result = a1 >= a2 ? m().mk_true() : m().mk_false(); return BR_DONE;
|
||||
default: result = a1 == a2 ? m().mk_true() : m().mk_false(); return BR_DONE;
|
||||
case LE: result = a1 <= a2 ? m.mk_true() : m.mk_false(); return BR_DONE;
|
||||
case GE: result = a1 >= a2 ? m.mk_true() : m.mk_false(); return BR_DONE;
|
||||
default: result = a1 == a2 ? m.mk_true() : m.mk_false(); return BR_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
#define ANUM_LE_GE_EQ() { \
|
||||
switch (kind) { \
|
||||
case LE: result = am.le(v1, v2) ? m().mk_true() : m().mk_false(); return BR_DONE; \
|
||||
case GE: result = am.ge(v1, v2) ? m().mk_true() : m().mk_false(); return BR_DONE; \
|
||||
default: result = am.eq(v1, v2) ? m().mk_true() : m().mk_false(); return BR_DONE; \
|
||||
case LE: result = am.le(v1, v2) ? m.mk_true() : m.mk_false(); return BR_DONE; \
|
||||
case GE: result = am.ge(v1, v2) ? m.mk_true() : m.mk_false(); return BR_DONE; \
|
||||
default: result = am.eq(v1, v2) ? m.mk_true() : m.mk_false(); return BR_DONE; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
@ -593,12 +592,12 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin
|
|||
if (!first && !g.is_one() && num_consts <= 1) {
|
||||
bool is_sat = div_polynomial(arg1, g, (kind == LE ? CT_CEIL : (kind == GE ? CT_FLOOR : CT_FALSE)), new_arg1);
|
||||
if (!is_sat) {
|
||||
result = m().mk_false();
|
||||
result = m.mk_false();
|
||||
return BR_DONE;
|
||||
}
|
||||
is_sat = div_polynomial(arg2, g, (kind == LE ? CT_FLOOR : (kind == GE ? CT_CEIL : CT_FALSE)), new_arg2);
|
||||
if (!is_sat) {
|
||||
result = m().mk_false();
|
||||
result = m.mk_false();
|
||||
return BR_DONE;
|
||||
}
|
||||
arg1 = new_arg1.get();
|
||||
|
@ -607,25 +606,25 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin
|
|||
}
|
||||
}
|
||||
expr* c = nullptr, *t = nullptr, *e = nullptr;
|
||||
if (m().is_ite(arg1, c, t, e) && is_numeral(t, a1) && is_numeral(arg2, a2)) {
|
||||
if (m.is_ite(arg1, c, t, e) && is_numeral(t, a1) && is_numeral(arg2, a2)) {
|
||||
switch (kind) {
|
||||
case LE: result = a1 <= a2 ? m().mk_or(c, m_util.mk_le(e, arg2)) : m().mk_and(m().mk_not(c), m_util.mk_le(e, arg2)); return BR_REWRITE2;
|
||||
case GE: result = a1 >= a2 ? m().mk_or(c, m_util.mk_ge(e, arg2)) : m().mk_and(m().mk_not(c), m_util.mk_ge(e, arg2)); return BR_REWRITE2;
|
||||
case EQ: result = a1 == a2 ? m().mk_or(c, m().mk_eq(e, arg2)) : m().mk_and(m().mk_not(c), m_util.mk_eq(e, arg2)); return BR_REWRITE2;
|
||||
case LE: result = a1 <= a2 ? m.mk_or(c, m_util.mk_le(e, arg2)) : m.mk_and(m.mk_not(c), m_util.mk_le(e, arg2)); return BR_REWRITE2;
|
||||
case GE: result = a1 >= a2 ? m.mk_or(c, m_util.mk_ge(e, arg2)) : m.mk_and(m.mk_not(c), m_util.mk_ge(e, arg2)); return BR_REWRITE2;
|
||||
case EQ: result = a1 == a2 ? m.mk_or(c, m.mk_eq(e, arg2)) : m.mk_and(m.mk_not(c), m_util.mk_eq(e, arg2)); return BR_REWRITE2;
|
||||
}
|
||||
}
|
||||
if (m().is_ite(arg1, c, t, e) && is_numeral(e, a1) && is_numeral(arg2, a2)) {
|
||||
if (m.is_ite(arg1, c, t, e) && is_numeral(e, a1) && is_numeral(arg2, a2)) {
|
||||
switch (kind) {
|
||||
case LE: result = a1 <= a2 ? m().mk_or(m().mk_not(c), m_util.mk_le(t, arg2)) : m().mk_and(c, m_util.mk_le(t, arg2)); return BR_REWRITE2;
|
||||
case GE: result = a1 >= a2 ? m().mk_or(m().mk_not(c), m_util.mk_ge(t, arg2)) : m().mk_and(c, m_util.mk_ge(t, arg2)); return BR_REWRITE2;
|
||||
case EQ: result = a1 == a2 ? m().mk_or(m().mk_not(c), m().mk_eq(t, arg2)) : m().mk_and(c, m_util.mk_eq(t, arg2)); return BR_REWRITE2;
|
||||
case LE: result = a1 <= a2 ? m.mk_or(m.mk_not(c), m_util.mk_le(t, arg2)) : m.mk_and(c, m_util.mk_le(t, arg2)); return BR_REWRITE2;
|
||||
case GE: result = a1 >= a2 ? m.mk_or(m.mk_not(c), m_util.mk_ge(t, arg2)) : m.mk_and(c, m_util.mk_ge(t, arg2)); return BR_REWRITE2;
|
||||
case EQ: result = a1 == a2 ? m.mk_or(m.mk_not(c), m.mk_eq(t, arg2)) : m.mk_and(c, m_util.mk_eq(t, arg2)); return BR_REWRITE2;
|
||||
}
|
||||
}
|
||||
if (m().is_ite(arg1, c, t, e) && arg1->get_ref_count() == 1) {
|
||||
if (m.is_ite(arg1, c, t, e) && arg1->get_ref_count() == 1) {
|
||||
switch (kind) {
|
||||
case LE: result = m().mk_ite(c, m_util.mk_le(t, arg2), m_util.mk_le(e, arg2)); return BR_REWRITE2;
|
||||
case GE: result = m().mk_ite(c, m_util.mk_ge(t, arg2), m_util.mk_ge(e, arg2)); return BR_REWRITE2;
|
||||
case EQ: result = m().mk_ite(c, m().mk_eq(t, arg2), m().mk_eq(e, arg2)); return BR_REWRITE2;
|
||||
case LE: result = m.mk_ite(c, m_util.mk_le(t, arg2), m_util.mk_le(e, arg2)); return BR_REWRITE2;
|
||||
case GE: result = m.mk_ite(c, m_util.mk_ge(t, arg2), m_util.mk_ge(e, arg2)); return BR_REWRITE2;
|
||||
case EQ: result = m.mk_ite(c, m.mk_eq(t, arg2), m.mk_eq(e, arg2)); return BR_REWRITE2;
|
||||
}
|
||||
}
|
||||
if (m_util.is_to_int(arg2) && is_numeral(arg1)) {
|
||||
|
@ -642,7 +641,7 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin
|
|||
return BR_REWRITE1;
|
||||
case EQ:
|
||||
result = m_util.mk_ge(t, m_util.mk_numeral(a2, false));
|
||||
result = m().mk_and(m_util.mk_lt(t, m_util.mk_numeral(a2+1, false)), result);
|
||||
result = m.mk_and(m_util.mk_lt(t, m_util.mk_numeral(a2+1, false)), result);
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
}
|
||||
|
@ -663,7 +662,7 @@ br_status arith_rewriter::mk_le_ge_eq_core(expr * arg1, expr * arg2, op_kind kin
|
|||
switch (kind) {
|
||||
case LE: result = m_util.mk_le(arg1, arg2); return BR_DONE;
|
||||
case GE: result = m_util.mk_ge(arg1, arg2); return BR_DONE;
|
||||
default: result = m().mk_eq(arg1, arg2); return BR_DONE;
|
||||
default: result = m.mk_eq(arg1, arg2); return BR_DONE;
|
||||
}
|
||||
}
|
||||
return BR_FAILED;
|
||||
|
@ -674,7 +673,7 @@ br_status arith_rewriter::mk_le_core(expr * arg1, expr * arg2, expr_ref & result
|
|||
}
|
||||
|
||||
br_status arith_rewriter::mk_lt_core(expr * arg1, expr * arg2, expr_ref & result) {
|
||||
result = m().mk_not(m_util.mk_le(arg2, arg1));
|
||||
result = m.mk_not(m_util.mk_le(arg2, arg1));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
|
@ -683,7 +682,7 @@ br_status arith_rewriter::mk_ge_core(expr * arg1, expr * arg2, expr_ref & result
|
|||
}
|
||||
|
||||
br_status arith_rewriter::mk_gt_core(expr * arg1, expr * arg2, expr_ref & result) {
|
||||
result = m().mk_not(m_util.mk_le(arg1, arg2));
|
||||
result = m.mk_not(m_util.mk_le(arg1, arg2));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
|
@ -694,7 +693,7 @@ bool arith_rewriter::is_arith_term(expr * n) const {
|
|||
br_status arith_rewriter::mk_eq_core(expr * arg1, expr * arg2, expr_ref & result) {
|
||||
br_status st = BR_FAILED;
|
||||
if (m_eq2ineq) {
|
||||
result = m().mk_and(m_util.mk_le(arg1, arg2), m_util.mk_ge(arg1, arg2));
|
||||
result = m.mk_and(m_util.mk_le(arg1, arg2), m_util.mk_ge(arg1, arg2));
|
||||
st = BR_REWRITE2;
|
||||
}
|
||||
else if (m_arith_lhs || is_arith_term(arg1) || is_arith_term(arg2)) {
|
||||
|
@ -724,7 +723,7 @@ br_status arith_rewriter::mk_and_core(unsigned n, expr* const* args, expr_ref& r
|
|||
}
|
||||
if (rest.size() < n - 1) {
|
||||
rest.push_back(arg0);
|
||||
result = m().mk_and(rest);
|
||||
result = m.mk_and(rest);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
}
|
||||
|
@ -742,8 +741,8 @@ bool arith_rewriter::mk_eq_mod(expr* arg1, expr* arg2, expr_ref& result) {
|
|||
rational a, b;
|
||||
rational g = gcd(p, k, a, b);
|
||||
if (g == 1) {
|
||||
expr_ref nb(m_util.mk_numeral(b, true), m());
|
||||
result = m().mk_eq(m_util.mk_mod(u, y),
|
||||
expr_ref nb(m_util.mk_numeral(b, true), m);
|
||||
result = m.mk_eq(m_util.mk_mod(u, y),
|
||||
m_util.mk_mod(m_util.mk_mul(nb, arg2), y));
|
||||
return true;
|
||||
}
|
||||
|
@ -752,7 +751,7 @@ bool arith_rewriter::mk_eq_mod(expr* arg1, expr* arg2, expr_ref& result) {
|
|||
}
|
||||
|
||||
expr_ref arith_rewriter::neg_monomial(expr* e) const {
|
||||
expr_ref_vector args(m());
|
||||
expr_ref_vector args(m);
|
||||
rational a1;
|
||||
if (m_util.is_numeral(e, a1))
|
||||
args.push_back(m_util.mk_numeral(-a1, e->get_sort()));
|
||||
|
@ -773,10 +772,10 @@ expr_ref arith_rewriter::neg_monomial(expr* e) const {
|
|||
args.push_back(e);
|
||||
}
|
||||
if (args.size() == 1) {
|
||||
return expr_ref(args.back(), m());
|
||||
return expr_ref(args.back(), m);
|
||||
}
|
||||
else {
|
||||
return expr_ref(m_util.mk_mul(args.size(), args.data()), m());
|
||||
return expr_ref(m_util.mk_mul(args.size(), args.data()), m);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -793,7 +792,7 @@ bool arith_rewriter::is_neg_poly(expr* t, expr_ref& neg) const {
|
|||
expr * t2 = to_app(t)->get_arg(0);
|
||||
|
||||
if (m_util.is_mul(t2) && is_numeral(to_app(t2)->get_arg(0), r) && r.is_neg()) {
|
||||
expr_ref_vector args1(m());
|
||||
expr_ref_vector args1(m);
|
||||
for (expr* e1 : *to_app(t)) {
|
||||
args1.push_back(neg_monomial(e1));
|
||||
}
|
||||
|
@ -826,7 +825,7 @@ bool arith_rewriter::is_anum_simp_target(unsigned num_args, expr * const * args)
|
|||
|
||||
br_status arith_rewriter::mk_add_core(unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
if (is_anum_simp_target(num_args, args)) {
|
||||
expr_ref_buffer new_args(m());
|
||||
expr_ref_buffer new_args(m);
|
||||
anum_manager & am = m_util.am();
|
||||
scoped_anum r(am);
|
||||
scoped_anum arg(am);
|
||||
|
@ -864,7 +863,7 @@ br_status arith_rewriter::mk_add_core(unsigned num_args, expr * const * args, ex
|
|||
new_args.push_back(m_util.mk_numeral(am, r, false));
|
||||
br_status st = poly_rewriter<arith_rewriter_core>::mk_add_core(new_args.size(), new_args.data(), result);
|
||||
if (st == BR_FAILED) {
|
||||
result = m().mk_app(get_fid(), OP_ADD, new_args.size(), new_args.data());
|
||||
result = m.mk_app(get_fid(), OP_ADD, new_args.size(), new_args.data());
|
||||
return BR_DONE;
|
||||
}
|
||||
return st;
|
||||
|
@ -876,7 +875,7 @@ br_status arith_rewriter::mk_add_core(unsigned num_args, expr * const * args, ex
|
|||
|
||||
br_status arith_rewriter::mk_mul_core(unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
if (is_anum_simp_target(num_args, args)) {
|
||||
expr_ref_buffer new_args(m());
|
||||
expr_ref_buffer new_args(m);
|
||||
anum_manager & am = m_util.am();
|
||||
scoped_anum r(am);
|
||||
scoped_anum arg(am);
|
||||
|
@ -913,7 +912,7 @@ br_status arith_rewriter::mk_mul_core(unsigned num_args, expr * const * args, ex
|
|||
|
||||
br_status st = poly_rewriter<arith_rewriter_core>::mk_mul_core(new_args.size(), new_args.data(), result);
|
||||
if (st == BR_FAILED) {
|
||||
result = m().mk_app(get_fid(), OP_MUL, new_args.size(), new_args.data());
|
||||
result = m.mk_app(get_fid(), OP_MUL, new_args.size(), new_args.data());
|
||||
return BR_DONE;
|
||||
}
|
||||
return st;
|
||||
|
@ -998,7 +997,7 @@ br_status arith_rewriter::mk_div_core(expr * arg1, expr * arg2, expr_ref & resul
|
|||
else {
|
||||
numeral k(1);
|
||||
k /= v2;
|
||||
result = m().mk_app(get_fid(), OP_MUL,
|
||||
result = m.mk_app(get_fid(), OP_MUL,
|
||||
m_util.mk_numeral(k, false),
|
||||
arg1);
|
||||
return BR_REWRITE1;
|
||||
|
@ -1028,8 +1027,8 @@ br_status arith_rewriter::mk_div_core(expr * arg1, expr * arg2, expr_ref & resul
|
|||
v1 /= v2;
|
||||
result = m_util.mk_mul(m_util.mk_numeral(v1, false),
|
||||
m_util.mk_div(b, d));
|
||||
expr_ref z(m_util.mk_real(0), m());
|
||||
result = m().mk_ite(m().mk_eq(d, z), m_util.mk_div(arg1, z), result);
|
||||
expr_ref z(m_util.mk_real(0), m);
|
||||
result = m.mk_ite(m.mk_eq(d, z), m_util.mk_div(arg1, z), result);
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
}
|
||||
|
@ -1039,7 +1038,7 @@ br_status arith_rewriter::mk_div_core(expr * arg1, expr * arg2, expr_ref & resul
|
|||
}
|
||||
|
||||
br_status arith_rewriter::mk_idivides(unsigned k, expr * arg, expr_ref & result) {
|
||||
result = m().mk_eq(m_util.mk_mod(arg, m_util.mk_int(k)), m_util.mk_int(0));
|
||||
result = m.mk_eq(m_util.mk_mod(arg, m_util.mk_int(k)), m_util.mk_int(0));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
|
@ -1063,12 +1062,12 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu
|
|||
return BR_FAILED;
|
||||
}
|
||||
if (arg1 == arg2) {
|
||||
expr_ref zero(m_util.mk_int(0), m());
|
||||
result = m().mk_ite(m().mk_eq(arg1, zero), m_util.mk_idiv(zero, zero), m_util.mk_int(1));
|
||||
expr_ref zero(m_util.mk_int(0), m);
|
||||
result = m.mk_ite(m.mk_eq(arg1, zero), m_util.mk_idiv(zero, zero), m_util.mk_int(1));
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
if (m_util.is_numeral(arg2, v2, is_int) && v2.is_pos() && m_util.is_add(arg1)) {
|
||||
expr_ref_buffer args(m());
|
||||
expr_ref_buffer args(m);
|
||||
bool change = false;
|
||||
rational add(0);
|
||||
for (expr* arg : *to_app(arg1)) {
|
||||
|
@ -1083,15 +1082,15 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu
|
|||
}
|
||||
}
|
||||
if (change) {
|
||||
result = m_util.mk_idiv(m().mk_app(to_app(arg1)->get_decl(), args.size(), args.data()), arg2);
|
||||
result = m_util.mk_idiv(m.mk_app(to_app(arg1)->get_decl(), args.size(), args.data()), arg2);
|
||||
result = m_util.mk_add(m_util.mk_numeral(add, true), result);
|
||||
TRACE("div_bug", tout << "mk_div result: " << result << "\n";);
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
}
|
||||
if (divides(arg1, arg2, result)) {
|
||||
expr_ref zero(m_util.mk_int(0), m());
|
||||
result = m().mk_ite(m().mk_eq(zero, arg2), m_util.mk_idiv(arg1, zero), result);
|
||||
expr_ref zero(m_util.mk_int(0), m);
|
||||
result = m.mk_ite(m.mk_eq(zero, arg2), m_util.mk_idiv(arg1, zero), result);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
return BR_FAILED;
|
||||
|
@ -1150,17 +1149,17 @@ expr_ref arith_rewriter::remove_divisor(expr* arg, expr* num, expr* den) {
|
|||
flat_mul(den, args2);
|
||||
remove_divisor(arg, args1);
|
||||
remove_divisor(arg, args2);
|
||||
expr_ref zero(m_util.mk_int(0), m());
|
||||
expr_ref zero(m_util.mk_int(0), m);
|
||||
num = args1.empty() ? m_util.mk_int(1) : m_util.mk_mul(args1.size(), args1.data());
|
||||
den = args2.empty() ? m_util.mk_int(1) : m_util.mk_mul(args2.size(), args2.data());
|
||||
expr_ref d(m_util.mk_idiv(num, den), m());
|
||||
expr_ref nd(m_util.mk_idiv(m_util.mk_uminus(num), m_util.mk_uminus(den)), m());
|
||||
return expr_ref(m().mk_ite(m().mk_eq(zero, arg),
|
||||
expr_ref d(m_util.mk_idiv(num, den), m);
|
||||
expr_ref nd(m_util.mk_idiv(m_util.mk_uminus(num), m_util.mk_uminus(den)), m);
|
||||
return expr_ref(m.mk_ite(m.mk_eq(zero, arg),
|
||||
m_util.mk_idiv(zero, zero),
|
||||
m().mk_ite(m_util.mk_ge(arg, zero),
|
||||
m.mk_ite(m_util.mk_ge(arg, zero),
|
||||
d,
|
||||
nd)),
|
||||
m());
|
||||
m);
|
||||
}
|
||||
|
||||
void arith_rewriter::flat_mul(expr* e, ptr_buffer<expr>& args) {
|
||||
|
@ -1208,8 +1207,8 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul
|
|||
}
|
||||
|
||||
if (arg1 == arg2 && !m_util.is_numeral(arg2)) {
|
||||
expr_ref zero(m_util.mk_int(0), m());
|
||||
result = m().mk_ite(m().mk_eq(arg2, zero), m_util.mk_mod(zero, zero), zero);
|
||||
expr_ref zero(m_util.mk_int(0), m);
|
||||
result = m.mk_ite(m.mk_eq(arg2, zero), m_util.mk_mod(zero, zero), zero);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
|
@ -1222,8 +1221,8 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul
|
|||
|
||||
// propagate mod inside only if there is something to reduce.
|
||||
if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_pos() && (is_add(arg1) || is_mul(arg1))) {
|
||||
TRACE("mod_bug", tout << "mk_mod:\n" << mk_ismt2_pp(arg1, m()) << "\n" << mk_ismt2_pp(arg2, m()) << "\n";);
|
||||
expr_ref_buffer args(m());
|
||||
TRACE("mod_bug", tout << "mk_mod:\n" << mk_ismt2_pp(arg1, m) << "\n" << mk_ismt2_pp(arg2, m) << "\n";);
|
||||
expr_ref_buffer args(m);
|
||||
bool change = false;
|
||||
for (expr* arg : *to_app(arg1)) {
|
||||
rational arg_v;
|
||||
|
@ -1246,8 +1245,8 @@ br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & resul
|
|||
if (!change) {
|
||||
return BR_FAILED; // did not find any target for applying simplification
|
||||
}
|
||||
result = m_util.mk_mod(m().mk_app(to_app(arg1)->get_decl(), args.size(), args.data()), arg2);
|
||||
TRACE("mod_bug", tout << "mk_mod result: " << mk_ismt2_pp(result, m()) << "\n";);
|
||||
result = m_util.mk_mod(m.mk_app(to_app(arg1)->get_decl(), args.size(), args.data()), arg2);
|
||||
TRACE("mod_bug", tout << "mk_mod result: " << mk_ismt2_pp(result, m) << "\n";);
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
|
||||
|
@ -1290,10 +1289,10 @@ br_status arith_rewriter::mk_rem_core(expr * arg1, expr * arg2, expr_ref & resul
|
|||
}
|
||||
else if (m_elim_rem) {
|
||||
expr * mod = m_util.mk_mod(arg1, arg2);
|
||||
result = m().mk_ite(m_util.mk_ge(arg2, m_util.mk_numeral(rational(0), true)),
|
||||
result = m.mk_ite(m_util.mk_ge(arg2, m_util.mk_numeral(rational(0), true)),
|
||||
mod,
|
||||
m_util.mk_uminus(mod));
|
||||
TRACE("elim_rem", tout << "result: " << mk_ismt2_pp(result, m()) << "\n";);
|
||||
TRACE("elim_rem", tout << "result: " << mk_ismt2_pp(result, m) << "\n";);
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
return BR_FAILED;
|
||||
|
@ -1322,7 +1321,7 @@ br_status arith_rewriter::mk_power_core(expr * arg1, expr * arg2, expr_ref & res
|
|||
bool is_num_y = m_util.is_numeral(arg2, y);
|
||||
auto ensure_real = [&](expr* e) { return m_util.is_int(e) ? m_util.mk_to_real(e) : e; };
|
||||
|
||||
TRACE("arith", tout << mk_pp(arg1, m()) << " " << mk_pp(arg2, m()) << "\n";);
|
||||
TRACE("arith", tout << mk_bounded_pp(arg1, m) << " " << mk_bounded_pp(arg2, m) << "\n";);
|
||||
if (is_num_x && x.is_one()) {
|
||||
result = m_util.mk_numeral(x, false);
|
||||
return BR_DONE;
|
||||
|
@ -1377,7 +1376,7 @@ br_status arith_rewriter::mk_power_core(expr * arg1, expr * arg2, expr_ref & res
|
|||
|
||||
if (is_num_y && y.is_minus_one()) {
|
||||
result = m_util.mk_div(m_util.mk_real(1), ensure_real(arg1));
|
||||
result = m().mk_ite(m().mk_eq(arg1, m_util.mk_numeral(rational(0), m_util.is_int(arg1))),
|
||||
result = m.mk_ite(m.mk_eq(arg1, m_util.mk_numeral(rational(0), m_util.is_int(arg1))),
|
||||
m_util.mk_real(0),
|
||||
result);
|
||||
return BR_REWRITE2;
|
||||
|
@ -1387,7 +1386,7 @@ br_status arith_rewriter::mk_power_core(expr * arg1, expr * arg2, expr_ref & res
|
|||
// (^ t -k) --> (^ (/ 1 t) k)
|
||||
result = m_util.mk_power(m_util.mk_div(m_util.mk_numeral(rational(1), false), arg1),
|
||||
m_util.mk_numeral(-y, false));
|
||||
result = m().mk_ite(m().mk_eq(arg1, m_util.mk_numeral(rational(0), m_util.is_int(arg1))),
|
||||
result = m.mk_ite(m.mk_eq(arg1, m_util.mk_numeral(rational(0), m_util.is_int(arg1))),
|
||||
m_util.mk_real(0),
|
||||
result);
|
||||
return BR_REWRITE3;
|
||||
|
@ -1504,7 +1503,7 @@ br_status arith_rewriter::mk_to_int_core(expr * arg, expr_ref & result) {
|
|||
// Try to apply simplifications such as:
|
||||
// (to_int (+ 1.0 (to_real x)) y) --> (+ 1 x (to_int y))
|
||||
|
||||
expr_ref_buffer int_args(m()), real_args(m());
|
||||
expr_ref_buffer int_args(m), real_args(m);
|
||||
for (expr* c : *to_app(arg)) {
|
||||
if (m_util.is_numeral(c, a) && a.is_int()) {
|
||||
int_args.push_back(m_util.mk_numeral(a, true));
|
||||
|
@ -1520,17 +1519,17 @@ br_status arith_rewriter::mk_to_int_core(expr * arg, expr_ref & result) {
|
|||
return BR_FAILED;
|
||||
|
||||
if (real_args.empty()) {
|
||||
result = m().mk_app(get_fid(), to_app(arg)->get_decl()->get_decl_kind(), int_args.size(), int_args.data());
|
||||
result = m.mk_app(get_fid(), to_app(arg)->get_decl()->get_decl_kind(), int_args.size(), int_args.data());
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
if (!int_args.empty() && m_util.is_add(arg)) {
|
||||
decl_kind k = to_app(arg)->get_decl()->get_decl_kind();
|
||||
expr_ref t1(m().mk_app(get_fid(), k, int_args.size(), int_args.data()), m());
|
||||
expr_ref t2(m().mk_app(get_fid(), k, real_args.size(), real_args.data()), m());
|
||||
expr_ref t1(m.mk_app(get_fid(), k, int_args.size(), int_args.data()), m);
|
||||
expr_ref t2(m.mk_app(get_fid(), k, real_args.size(), real_args.data()), m);
|
||||
int_args.reset();
|
||||
int_args.push_back(t1);
|
||||
int_args.push_back(m_util.mk_to_int(t2));
|
||||
result = m().mk_app(get_fid(), k, int_args.size(), int_args.data());
|
||||
result = m.mk_app(get_fid(), k, int_args.size(), int_args.data());
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
}
|
||||
|
@ -1550,9 +1549,9 @@ br_status arith_rewriter::mk_to_real_core(expr * arg, expr_ref & result) {
|
|||
for (expr* e : *to_app(arg))
|
||||
new_args.push_back(m_util.mk_to_real(e));
|
||||
if (m_util.is_add(arg))
|
||||
result = m().mk_app(get_fid(), OP_ADD, new_args.size(), new_args.data());
|
||||
result = m.mk_app(get_fid(), OP_ADD, new_args.size(), new_args.data());
|
||||
else
|
||||
result = m().mk_app(get_fid(), OP_MUL, new_args.size(), new_args.data());
|
||||
result = m.mk_app(get_fid(), OP_MUL, new_args.size(), new_args.data());
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
}
|
||||
|
@ -1562,23 +1561,23 @@ br_status arith_rewriter::mk_to_real_core(expr * arg, expr_ref & result) {
|
|||
br_status arith_rewriter::mk_is_int(expr * arg, expr_ref & result) {
|
||||
numeral a;
|
||||
if (m_util.is_numeral(arg, a)) {
|
||||
result = a.is_int() ? m().mk_true() : m().mk_false();
|
||||
result = a.is_int() ? m.mk_true() : m.mk_false();
|
||||
return BR_DONE;
|
||||
}
|
||||
else if (m_util.is_to_real(arg)) {
|
||||
result = m().mk_true();
|
||||
result = m.mk_true();
|
||||
return BR_DONE;
|
||||
}
|
||||
else {
|
||||
result = m().mk_eq(m().mk_app(get_fid(), OP_TO_REAL,
|
||||
m().mk_app(get_fid(), OP_TO_INT, arg)),
|
||||
result = m.mk_eq(m.mk_app(get_fid(), OP_TO_REAL,
|
||||
m.mk_app(get_fid(), OP_TO_INT, arg)),
|
||||
arg);
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
}
|
||||
|
||||
br_status arith_rewriter::mk_abs_core(expr * arg, expr_ref & result) {
|
||||
result = m().mk_ite(m_util.mk_ge(arg, m_util.mk_numeral(rational(0), m_util.is_int(arg))), arg, m_util.mk_uminus(arg));
|
||||
result = m.mk_ite(m_util.mk_ge(arg, m_util.mk_numeral(rational(0), m_util.is_int(arg))), arg, m_util.mk_uminus(arg));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
|
@ -1647,9 +1646,9 @@ bool arith_rewriter::is_pi_integer(expr * t) {
|
|||
a = c;
|
||||
b = d;
|
||||
}
|
||||
TRACE("tan", tout << "is_pi_integer " << mk_ismt2_pp(t, m()) << "\n";
|
||||
tout << "a: " << mk_ismt2_pp(a, m()) << "\n";
|
||||
tout << "b: " << mk_ismt2_pp(b, m()) << "\n";);
|
||||
TRACE("tan", tout << "is_pi_integer " << mk_ismt2_pp(t, m) << "\n";
|
||||
tout << "a: " << mk_ismt2_pp(a, m) << "\n";
|
||||
tout << "b: " << mk_ismt2_pp(b, m) << "\n";);
|
||||
return
|
||||
(m_util.is_pi(a) && m_util.is_to_real(b)) ||
|
||||
(m_util.is_to_real(a) && m_util.is_pi(b));
|
||||
|
@ -1861,7 +1860,7 @@ br_status arith_rewriter::mk_tan_core(expr * arg, expr_ref & result) {
|
|||
}
|
||||
|
||||
if (is_pi_multiple(arg, k)) {
|
||||
expr_ref n(m()), d(m());
|
||||
expr_ref n(m), d(m);
|
||||
n = mk_sin_value(k);
|
||||
if (n.get() == nullptr)
|
||||
goto end;
|
||||
|
|
|
@ -25,13 +25,13 @@ Notes:
|
|||
class arith_rewriter_core {
|
||||
protected:
|
||||
typedef rational numeral;
|
||||
ast_manager& m;
|
||||
arith_util m_util;
|
||||
scoped_ptr<seq_util> m_seq;
|
||||
bool m_expand_power{ false };
|
||||
bool m_mul2power{ false };
|
||||
bool m_expand_tan{ false };
|
||||
bool m_expand_power = false;
|
||||
bool m_mul2power = false;
|
||||
bool m_expand_tan = false;
|
||||
|
||||
ast_manager & m() const { return m_util.get_manager(); }
|
||||
family_id get_fid() const { return m_util.get_family_id(); }
|
||||
seq_util& seq();
|
||||
|
||||
|
@ -47,7 +47,7 @@ protected:
|
|||
app* mk_power(expr* x, rational const& r, sort* s);
|
||||
expr* coerce(expr* x, sort* s);
|
||||
public:
|
||||
arith_rewriter_core(ast_manager & m):m_util(m) {}
|
||||
arith_rewriter_core(ast_manager & m):m(m), m_util(m) {}
|
||||
bool is_zero(expr * n) const { return m_util.is_zero(n); }
|
||||
};
|
||||
|
||||
|
@ -120,7 +120,7 @@ public:
|
|||
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
|
||||
void mk_app(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
if (mk_app_core(f, num_args, args, result) == BR_FAILED)
|
||||
result = m().mk_app(f, num_args, args);
|
||||
result = m.mk_app(f, num_args, args);
|
||||
}
|
||||
|
||||
br_status mk_eq_core(expr * arg1, expr * arg2, expr_ref & result);
|
||||
|
@ -159,30 +159,30 @@ public:
|
|||
br_status mk_power_core(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)
|
||||
result = m().mk_app(get_fid(), OP_DIV, arg1, arg2);
|
||||
result = m.mk_app(get_fid(), OP_DIV, arg1, arg2);
|
||||
}
|
||||
void mk_idiv(expr * arg1, expr * arg2, expr_ref & result) {
|
||||
if (mk_idiv_core(arg1, arg2, result) == BR_FAILED)
|
||||
result = m().mk_app(get_fid(), OP_IDIV, arg1, arg2);
|
||||
result = m.mk_app(get_fid(), OP_IDIV, arg1, arg2);
|
||||
}
|
||||
void mk_mod(expr * arg1, expr * arg2, expr_ref & result) {
|
||||
if (mk_mod_core(arg1, arg2, result) == BR_FAILED)
|
||||
result = m().mk_app(get_fid(), OP_MOD, arg1, arg2);
|
||||
result = m.mk_app(get_fid(), OP_MOD, arg1, arg2);
|
||||
}
|
||||
void mk_rem(expr * arg1, expr * arg2, expr_ref & result) {
|
||||
if (mk_rem_core(arg1, arg2, result) == BR_FAILED)
|
||||
result = m().mk_app(get_fid(), OP_REM, arg1, arg2);
|
||||
result = m.mk_app(get_fid(), OP_REM, arg1, arg2);
|
||||
}
|
||||
|
||||
br_status mk_to_int_core(expr * arg, expr_ref & result);
|
||||
br_status mk_to_real_core(expr * arg, expr_ref & result);
|
||||
void mk_to_int(expr * arg, expr_ref & result) {
|
||||
if (mk_to_int_core(arg, result) == BR_FAILED)
|
||||
result = m().mk_app(get_fid(), OP_TO_INT, 1, &arg);
|
||||
result = m.mk_app(get_fid(), OP_TO_INT, 1, &arg);
|
||||
}
|
||||
void mk_to_real(expr * arg, expr_ref & result) {
|
||||
if (mk_to_real_core(arg, result) == BR_FAILED)
|
||||
result = m().mk_app(get_fid(), OP_TO_REAL, 1, &arg);
|
||||
result = m.mk_app(get_fid(), OP_TO_REAL, 1, &arg);
|
||||
}
|
||||
br_status mk_is_int(expr * arg, expr_ref & result);
|
||||
|
||||
|
|
|
@ -196,15 +196,103 @@ bool array_rewriter::squash_store(unsigned n, expr* const* args, expr_ref& resul
|
|||
}
|
||||
|
||||
|
||||
br_status array_rewriter::mk_select_same_store(unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
expr_ref tmp(m());
|
||||
expr *arg0 = args[0];
|
||||
bool first = true;
|
||||
|
||||
#define RET(x, status) \
|
||||
tmp = x; \
|
||||
if (first || tmp == result) { \
|
||||
result = std::move(tmp); \
|
||||
return status; \
|
||||
} \
|
||||
return BR_FAILED;
|
||||
|
||||
while (true) {
|
||||
if (m_util.is_store(arg0)) {
|
||||
SASSERT(to_app(arg0)->get_num_args() == num_args+1);
|
||||
switch (compare_args(num_args - 1, args+1, to_app(arg0)->get_args()+1)) {
|
||||
case l_true:
|
||||
// select(store(a, I, v), I) --> v
|
||||
RET(to_app(arg0)->get_arg(num_args), BR_DONE);
|
||||
|
||||
case l_false:
|
||||
// select(store(a, I, v), J) --> select(a, J) if I != J
|
||||
arg0 = to_app(arg0)->get_arg(0);
|
||||
continue;
|
||||
|
||||
case l_undef:
|
||||
// check if loading from subsequent arrays yields the same value
|
||||
if (first) {
|
||||
result = to_app(arg0)->get_arg(num_args);
|
||||
first = false;
|
||||
}
|
||||
else if (result != to_app(arg0)->get_arg(num_args))
|
||||
return BR_FAILED;
|
||||
arg0 = to_app(arg0)->get_arg(0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_util.is_const(arg0)) {
|
||||
// select(const(v), I) --> v
|
||||
RET(to_app(arg0)->get_arg(0), BR_DONE);
|
||||
}
|
||||
|
||||
if (is_lambda(arg0)) {
|
||||
// anywhere lambda reduction as opposed to whnf
|
||||
// select(lambda(X) M, N) -> M[N/X]
|
||||
quantifier* q = to_quantifier(arg0);
|
||||
SASSERT(q->get_num_decls() == num_args - 1);
|
||||
var_subst subst(m());
|
||||
expr_ref_vector _args(m());
|
||||
var_shifter sh(m());
|
||||
for (unsigned i = 1; i < num_args; ++i) {
|
||||
sh(args[i], num_args-1, result);
|
||||
_args.push_back(result);
|
||||
}
|
||||
expr_ref tmp2 = subst(q->get_expr(), _args.size(), _args.data());
|
||||
inv_var_shifter invsh(m());
|
||||
invsh(tmp2, _args.size(), tmp2);
|
||||
RET(std::move(tmp2), BR_REWRITE_FULL);
|
||||
}
|
||||
|
||||
if (m_util.is_map(arg0)) {
|
||||
app* a = to_app(arg0);
|
||||
func_decl* f0 = m_util.get_map_func_decl(a);
|
||||
expr_ref_vector args0(m());
|
||||
for (expr* arg : *a) {
|
||||
ptr_vector<expr> args1;
|
||||
args1.push_back(arg);
|
||||
args1.append(num_args-1, args + 1);
|
||||
args0.push_back(m_util.mk_select(args1.size(), args1.data()));
|
||||
}
|
||||
RET(m().mk_app(f0, args0.size(), args0.data()), BR_REWRITE2);
|
||||
}
|
||||
|
||||
if (m_util.is_as_array(arg0)) {
|
||||
// select(as-array[f], I) --> f(I)
|
||||
func_decl * f = m_util.get_as_array_func_decl(to_app(arg0));
|
||||
RET(m().mk_app(f, num_args - 1, args + 1), BR_REWRITE1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num_args >= 2);
|
||||
br_status st = mk_select_same_store(num_args, args, result);
|
||||
if (st != BR_FAILED)
|
||||
return st;
|
||||
result.reset();
|
||||
|
||||
if (m_util.is_store(args[0])) {
|
||||
SASSERT(to_app(args[0])->get_num_args() == num_args+1);
|
||||
switch (compare_args(num_args - 1, args+1, to_app(args[0])->get_args()+1)) {
|
||||
case l_true:
|
||||
// select(store(a, I, v), I) --> v
|
||||
result = to_app(args[0])->get_arg(num_args);
|
||||
return BR_DONE;
|
||||
UNREACHABLE();
|
||||
case l_false: {
|
||||
expr* arg0 = to_app(args[0])->get_arg(0);
|
||||
while (m_util.is_store(arg0) && compare_args(num_args-1, args + 1, to_app(arg0)->get_args() + 1) == l_false) {
|
||||
|
@ -228,14 +316,17 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args,
|
|||
}
|
||||
return true;
|
||||
};
|
||||
expr *array = to_app(args[0])->get_arg(0);
|
||||
bool is_leaf = m_util.is_const(array);
|
||||
bool should_expand =
|
||||
m_blast_select_store ||
|
||||
is_leaf ||
|
||||
are_values() ||
|
||||
(m_expand_select_store && to_app(args[0])->get_arg(0)->get_ref_count() == 1);
|
||||
(m_expand_select_store && array->get_ref_count() == 1);
|
||||
if (should_expand) {
|
||||
// select(store(a, I, v), J) --> ite(I=J, v, select(a, J))
|
||||
ptr_buffer<expr> new_args;
|
||||
new_args.push_back(to_app(args[0])->get_arg(0));
|
||||
new_args.push_back(array);
|
||||
new_args.append(num_args-1, args+1);
|
||||
expr * sel_a_j = m().mk_app(get_fid(), OP_SELECT, num_args, new_args.data());
|
||||
expr * v = to_app(args[0])->get_arg(num_args);
|
||||
|
@ -258,51 +349,6 @@ br_status array_rewriter::mk_select_core(unsigned num_args, expr * const * args,
|
|||
}
|
||||
}
|
||||
|
||||
if (m_util.is_const(args[0])) {
|
||||
// select(const(v), I) --> v
|
||||
result = to_app(args[0])->get_arg(0);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
if (is_lambda(args[0])) {
|
||||
// anywhere lambda reduction as opposed to whnf
|
||||
// select(lambda(X) M, N) -> M[N/X]
|
||||
quantifier* q = to_quantifier(args[0]);
|
||||
SASSERT(q->get_num_decls() == num_args - 1);
|
||||
var_subst subst(m());
|
||||
expr_ref_vector _args(m());
|
||||
var_shifter sh(m());
|
||||
for (unsigned i = 1; i < num_args; ++i) {
|
||||
sh(args[i], num_args-1, result);
|
||||
_args.push_back(result);
|
||||
}
|
||||
result = subst(q->get_expr(), _args.size(), _args.data());
|
||||
inv_var_shifter invsh(m());
|
||||
invsh(result, _args.size(), result);
|
||||
return BR_REWRITE_FULL;
|
||||
}
|
||||
|
||||
if (m_util.is_map(args[0])) {
|
||||
app* a = to_app(args[0]);
|
||||
func_decl* f0 = m_util.get_map_func_decl(a);
|
||||
expr_ref_vector args0(m());
|
||||
for (expr* arg : *a) {
|
||||
ptr_vector<expr> args1;
|
||||
args1.push_back(arg);
|
||||
args1.append(num_args-1, args + 1);
|
||||
args0.push_back(m_util.mk_select(args1.size(), args1.data()));
|
||||
}
|
||||
result = m().mk_app(f0, args0.size(), args0.data());
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
if (m_util.is_as_array(args[0])) {
|
||||
// select(as-array[f], I) --> f(I)
|
||||
func_decl * f = m_util.get_as_array_func_decl(to_app(args[0]));
|
||||
result = m().mk_app(f, num_args - 1, args + 1);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
|
||||
expr* c, *th, *el;
|
||||
if (m().is_ite(args[0], c, th, el) && (m_expand_select_ite || (th->get_ref_count() == 1 || el->get_ref_count() == 1))) {
|
||||
ptr_vector<expr> args1, args2;
|
||||
|
|
|
@ -46,6 +46,11 @@ class array_rewriter {
|
|||
expr_ref expand_store(expr* s);
|
||||
|
||||
bool squash_store(unsigned n, expr* const* args, expr_ref& result);
|
||||
|
||||
br_status mk_store_core(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
br_status mk_select_core(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
br_status mk_select_same_store(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
br_status mk_map_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
|
||||
|
||||
public:
|
||||
array_rewriter(ast_manager & m, params_ref const & p = params_ref()):
|
||||
|
@ -63,10 +68,6 @@ public:
|
|||
|
||||
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
|
||||
|
||||
br_status mk_store_core(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
br_status mk_select_core(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
br_status mk_map_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
|
||||
|
||||
void mk_store(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
void mk_select(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
void mk_map(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
|
||||
|
|
|
@ -59,7 +59,7 @@ class bit_blaster : public bit_blaster_tpl<bit_blaster_cfg> {
|
|||
public:
|
||||
bit_blaster(ast_manager & m, bit_blaster_params const & params);
|
||||
bit_blaster_params const & get_params() const { return this->m_params; }
|
||||
void set_flat(bool f) { m_rw.set_flat(f); }
|
||||
void set_flat_and_or(bool f) { m_rw.set_flat_and_or(f); }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ public:
|
|||
bit_blaster_tpl<blaster_cfg>(blaster_cfg(m_rewriter, m_util)),
|
||||
m_rewriter(m),
|
||||
m_util(m) {
|
||||
m_rewriter.set_flat(false);
|
||||
m_rewriter.set_flat_and_or(false);
|
||||
m_rewriter.set_elim_and(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ Revision History:
|
|||
|
||||
template<typename Cfg>
|
||||
void bit_blaster_tpl<Cfg>::checkpoint() {
|
||||
if (memory::get_allocation_size() > m_max_memory)
|
||||
if (memory::get_allocation_size() > m_max_memory || memory::above_high_watermark())
|
||||
throw rewriter_exception(Z3_MAX_MEMORY_MSG);
|
||||
if (!m().inc())
|
||||
throw rewriter_exception(m().limit().get_cancel_msg());
|
||||
|
|
|
@ -24,7 +24,7 @@ Notes:
|
|||
|
||||
void bool_rewriter::updt_params(params_ref const & _p) {
|
||||
bool_rewriter_params p(_p);
|
||||
m_flat = p.flat();
|
||||
m_flat_and_or = p.flat_and_or();
|
||||
m_elim_and = p.elim_and();
|
||||
m_elim_ite = p.elim_ite();
|
||||
m_local_ctx = p.local_ctx();
|
||||
|
@ -244,10 +244,38 @@ br_status bool_rewriter::mk_nflat_or_core(unsigned num_args, expr * const * args
|
|||
result = buffer.back();
|
||||
return BR_DONE;
|
||||
default:
|
||||
#if 0
|
||||
// stupid or removal. A very special case of circuit optimization.
|
||||
expr* x, * y, * z, * u;
|
||||
auto is_complement = [&](expr* a, expr* b) {
|
||||
expr* c;
|
||||
if (m().is_not(a, c) && c == b)
|
||||
return true;
|
||||
if (m().is_not(b, c) && c == a)
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
if (sz == 2 && m().is_and(buffer[0], x, y) && m().is_and(buffer[1], z, u) && x == z && is_complement(y, u)) {
|
||||
result = x;
|
||||
return BR_DONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_local_ctx && m_local_ctx_cost <= m_local_ctx_limit) {
|
||||
if (local_ctx_simp(sz, buffer.data(), result))
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
#if 1
|
||||
br_status st;
|
||||
st = m_hoist.mk_or(buffer.size(), buffer.data(), result);
|
||||
if (st == BR_DONE)
|
||||
return BR_REWRITE1;
|
||||
if (st != BR_FAILED)
|
||||
return st;
|
||||
#endif
|
||||
|
||||
if (s) {
|
||||
ast_lt lt;
|
||||
std::sort(buffer.begin(), buffer.end(), lt);
|
||||
|
@ -290,7 +318,7 @@ br_status bool_rewriter::mk_flat_or_core(unsigned num_args, expr * const * args,
|
|||
ast_lt lt;
|
||||
std::sort(flat_args.begin(), flat_args.end(), lt);
|
||||
}
|
||||
result = m().mk_or(flat_args);
|
||||
result = mk_or_app(flat_args.size(), flat_args.data());
|
||||
}
|
||||
return BR_DONE;
|
||||
}
|
||||
|
@ -555,10 +583,8 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_
|
|||
result = arg; \
|
||||
return true; \
|
||||
} \
|
||||
if (m_flat && m().is_or(arg)) { \
|
||||
unsigned sz = to_app(arg)->get_num_args(); \
|
||||
for (unsigned j = 0; j < sz; j++) { \
|
||||
expr * arg_arg = to_app(arg)->get_arg(j); \
|
||||
if (m_flat_and_or && m().is_or(arg)) { \
|
||||
for (expr * arg_arg : *to_app(arg)) { \
|
||||
push_new_arg(arg_arg, new_args, neg_lits, pos_lits); \
|
||||
} \
|
||||
} \
|
||||
|
@ -621,11 +647,13 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result)
|
|||
SASSERT(m().is_value(val));
|
||||
|
||||
if (m().are_distinct(val, e)) {
|
||||
result = m().mk_and(mk_eq(t, val), cond);
|
||||
mk_eq(t, val, result);
|
||||
result = m().mk_and(result, cond);
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
if (m().are_distinct(val, t)) {
|
||||
result = m().mk_and(mk_eq(e, val), m().mk_not(cond));
|
||||
mk_eq(e, val, result);
|
||||
result = m().mk_and(result, m().mk_not(cond));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
if (m().are_equal(val, t)) {
|
||||
|
@ -634,12 +662,14 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result)
|
|||
return BR_DONE;
|
||||
}
|
||||
else {
|
||||
result = m().mk_or(mk_eq(e, val), cond);
|
||||
mk_eq(e, val, result);
|
||||
result = m().mk_or(result, cond);
|
||||
}
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
if (m().are_equal(val, e)) {
|
||||
result = m().mk_or(mk_eq(t, val), m().mk_not(cond));
|
||||
mk_eq(t, val, result);
|
||||
result = m().mk_or(result, m().mk_not(cond));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
||||
|
@ -660,8 +690,10 @@ br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result)
|
|||
|
||||
|
||||
app* bool_rewriter::mk_eq(expr* lhs, expr* rhs) {
|
||||
// degrades simplification
|
||||
// if (lhs->get_id() > rhs->get_id()) std::swap(lhs, rhs);
|
||||
if (m().are_equal(lhs, rhs))
|
||||
return m().mk_true();
|
||||
if (m().are_distinct(lhs, rhs))
|
||||
return m().mk_false();
|
||||
return m().mk_eq(lhs, rhs);
|
||||
}
|
||||
|
||||
|
@ -731,7 +763,7 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
|
|||
}
|
||||
|
||||
if (unfolded) {
|
||||
result = mk_eq(lhs, rhs);
|
||||
result = m().mk_eq(lhs, rhs);
|
||||
return BR_REWRITE1;
|
||||
}
|
||||
|
||||
|
@ -748,6 +780,10 @@ br_status bool_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (m_order_eq && lhs->get_id() > rhs->get_id()) {
|
||||
result = m().mk_eq(rhs, lhs);
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
|
@ -759,7 +795,8 @@ br_status bool_rewriter::mk_distinct_core(unsigned num_args, expr * const * args
|
|||
|
||||
if (num_args == 2) {
|
||||
expr_ref tmp(m());
|
||||
result = m().mk_not(mk_eq(args[0], args[1]));
|
||||
mk_eq(args[0], args[1], tmp);
|
||||
mk_not(tmp, result);
|
||||
return BR_REWRITE2; // mk_eq may be dispatched to other rewriters.
|
||||
}
|
||||
|
||||
|
@ -798,10 +835,10 @@ br_status bool_rewriter::mk_distinct_core(unsigned num_args, expr * const * args
|
|||
}
|
||||
|
||||
if (m_blast_distinct && num_args < m_blast_distinct_threshold) {
|
||||
ptr_buffer<expr> new_diseqs;
|
||||
expr_ref_vector new_diseqs(m());
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
for (unsigned j = i + 1; j < num_args; j++)
|
||||
new_diseqs.push_back(m().mk_not(mk_eq(args[i], args[j])));
|
||||
new_diseqs.push_back(m().mk_not(m().mk_eq(args[i], args[j])));
|
||||
}
|
||||
result = m().mk_and(new_diseqs);
|
||||
return BR_REWRITE3;
|
||||
|
@ -820,6 +857,7 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re
|
|||
s = true;
|
||||
}
|
||||
|
||||
|
||||
// (ite c (ite c t1 t2) t3) ==> (ite c t1 t3
|
||||
if (m().is_ite(t) && to_app(t)->get_arg(0) == c) {
|
||||
// Remark: (ite c (ite (not c) t1 t2) t3) ==> (ite c t2 t3) does not happen if applying rewrites bottom up
|
||||
|
@ -906,23 +944,24 @@ br_status bool_rewriter::mk_ite_core(expr * c, expr * t, expr * e, expr_ref & re
|
|||
}
|
||||
|
||||
#if 0
|
||||
expr* t1, *t2;
|
||||
// (ite c (not (= t1 t2)) t1) ==> (not (= t1 (and c t2)))
|
||||
if (m().is_not(t, t1) && m().is_eq(t1, t1, t2) && e == t1) {
|
||||
expr_ref a(m());
|
||||
mk_and(c, t2, a);
|
||||
result = m().mk_not(m().mk_eq(t1, a));
|
||||
result = mk_not(mk_eq(t1, a));
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
if (m().is_not(t, t1) && m().is_eq(t1, t2, t1) && e == t1) {
|
||||
expr_ref a(m());
|
||||
mk_and(c, t2, a);
|
||||
result = m().mk_eq(t1, a);
|
||||
result = mk_eq(t1, a);
|
||||
return BR_REWRITE3;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
if (m().is_ite(t) && m_ite_extra_rules && m_elim_ite) {
|
||||
// (ite c1 (ite c2 t1 t2) t1) ==> (ite (and c1 (not c2)) t2 t1)
|
||||
if (e == to_app(t)->get_arg(1)) {
|
||||
|
|
|
@ -20,6 +20,7 @@ Notes:
|
|||
|
||||
#include "ast/ast.h"
|
||||
#include "ast/rewriter/rewriter.h"
|
||||
#include "ast/rewriter/hoist_rewriter.h"
|
||||
#include "util/params.h"
|
||||
|
||||
/**
|
||||
|
@ -50,10 +51,12 @@ Notes:
|
|||
*/
|
||||
class bool_rewriter {
|
||||
ast_manager & m_manager;
|
||||
bool m_flat;
|
||||
bool m_local_ctx;
|
||||
bool m_elim_and;
|
||||
bool m_blast_distinct;
|
||||
hoist_rewriter m_hoist;
|
||||
bool m_flat_and_or = false;
|
||||
bool m_local_ctx = false;
|
||||
bool m_elim_and = false;
|
||||
bool m_blast_distinct = false;
|
||||
bool m_order_eq = false;
|
||||
unsigned m_blast_distinct_threshold;
|
||||
bool m_ite_extra_rules;
|
||||
unsigned m_local_ctx_limit;
|
||||
|
@ -78,16 +81,17 @@ class bool_rewriter {
|
|||
void push_new_arg(expr* arg, expr_ref_vector& new_args, expr_fast_mark1& neg_lits, expr_fast_mark2& pos_lits);
|
||||
|
||||
public:
|
||||
bool_rewriter(ast_manager & m, params_ref const & p = params_ref()):m_manager(m), m_local_ctx_cost(0) { updt_params(p); }
|
||||
bool_rewriter(ast_manager & m, params_ref const & p = params_ref()):m_manager(m), m_hoist(m), m_local_ctx_cost(0) { updt_params(p); }
|
||||
ast_manager & m() const { return m_manager; }
|
||||
family_id get_fid() const { return m().get_basic_family_id(); }
|
||||
bool is_eq(expr * t) const { return m().is_eq(t); }
|
||||
|
||||
bool flat() const { return m_flat; }
|
||||
void set_flat(bool f) { m_flat = f; }
|
||||
bool flat_and_or() const { return m_flat_and_or; }
|
||||
void set_flat_and_or(bool f) { m_flat_and_or = f; }
|
||||
bool elim_and() const { return m_elim_and; }
|
||||
void set_elim_and(bool f) { m_elim_and = f; }
|
||||
void reset_local_ctx_cost() { m_local_ctx_cost = 0; }
|
||||
void set_order_eq(bool f) { m_order_eq = f; }
|
||||
|
||||
void updt_params(params_ref const & p);
|
||||
|
||||
|
@ -111,7 +115,7 @@ public:
|
|||
mk_and_as_or(num_args, args, result);
|
||||
return BR_DONE;
|
||||
}
|
||||
else if (m_flat) {
|
||||
else if (m_flat_and_or) {
|
||||
return mk_flat_and_core(num_args, args, result);
|
||||
}
|
||||
else {
|
||||
|
@ -119,7 +123,7 @@ public:
|
|||
}
|
||||
}
|
||||
br_status mk_or_core(unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
return m_flat ?
|
||||
return m_flat_and_or ?
|
||||
mk_flat_or_core(num_args, args, result) :
|
||||
mk_nflat_or_core(num_args, args, result);
|
||||
}
|
||||
|
@ -234,7 +238,7 @@ public:
|
|||
|
||||
struct bool_rewriter_cfg : public default_rewriter_cfg {
|
||||
bool_rewriter m_r;
|
||||
bool flat_assoc(func_decl * f) const { return m_r.flat() && (m_r.m().is_and(f) || m_r.m().is_or(f)); }
|
||||
bool flat_assoc(func_decl * f) const { return m_r.flat_and_or() && (m_r.m().is_and(f) || m_r.m().is_or(f)); }
|
||||
bool rewrite_patterns() const { return false; }
|
||||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
|
||||
result_pr = nullptr;
|
||||
|
|
349
src/ast/rewriter/bv_bounds_base.h
Normal file
349
src/ast/rewriter/bv_bounds_base.h
Normal file
|
@ -0,0 +1,349 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
bv_bounds_simplifier.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Context dependent simplification for bit-vectors
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj and Nuno
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "math/interval/mod_interval.h"
|
||||
|
||||
namespace bv {
|
||||
|
||||
|
||||
struct undo_bound {
|
||||
expr* e = nullptr;
|
||||
interval b;
|
||||
bool fresh = false;
|
||||
undo_bound(expr* e, const interval& b, bool fresh) : e(e), b(b), fresh(fresh) {}
|
||||
};
|
||||
|
||||
struct bv_bounds_base {
|
||||
typedef obj_map<expr, interval> map;
|
||||
typedef obj_map<expr, bool> expr_set;
|
||||
typedef obj_map<expr, unsigned> expr_cnt;
|
||||
|
||||
ast_manager& m;
|
||||
bv_util m_bv;
|
||||
vector<undo_bound> m_scopes;
|
||||
svector<expr_set*> m_expr_vars;
|
||||
svector<expr_cnt*> m_bound_exprs;
|
||||
map m_bound;
|
||||
bool m_propagate_eq = false;
|
||||
ptr_vector<expr> m_args;
|
||||
|
||||
bv_bounds_base(ast_manager& m):m(m), m_bv(m) {}
|
||||
|
||||
virtual ~bv_bounds_base() {
|
||||
for (auto* e : m_expr_vars)
|
||||
dealloc(e);
|
||||
for (auto* b : m_bound_exprs)
|
||||
dealloc(b);
|
||||
}
|
||||
|
||||
bool is_bound(expr *e, expr*& v, interval& b) const {
|
||||
rational r;
|
||||
expr *lhs = nullptr, *rhs = nullptr;
|
||||
unsigned sz;
|
||||
|
||||
if (m_bv.is_bv_ule(e, lhs, rhs)) {
|
||||
if (m_bv.is_numeral(lhs, r, sz)) { // C ule x <=> x uge C
|
||||
if (m_bv.is_numeral(rhs))
|
||||
return false;
|
||||
b = interval(r, rational::power_of_two(sz) - 1, sz, true);
|
||||
v = rhs;
|
||||
return true;
|
||||
}
|
||||
if (m_bv.is_numeral(rhs, r, sz)) { // x ule C
|
||||
b = interval(rational::zero(), r, sz, true);
|
||||
v = lhs;
|
||||
return true;
|
||||
}
|
||||
// TBD: x + s <= x + q
|
||||
// x + s <= x
|
||||
// x <= x + q
|
||||
}
|
||||
else if (m_bv.is_bv_sle(e, lhs, rhs)) {
|
||||
if (m_bv.is_numeral(lhs, r, sz)) { // C sle x <=> x sge C
|
||||
if (m_bv.is_numeral(rhs))
|
||||
return false;
|
||||
b = interval(r, rational::power_of_two(sz-1) - 1, sz, true);
|
||||
v = rhs;
|
||||
return true;
|
||||
}
|
||||
if (m_bv.is_numeral(rhs, r, sz)) { // x sle C
|
||||
b = interval(rational::power_of_two(sz-1), r, sz, true);
|
||||
v = lhs;
|
||||
return true;
|
||||
}
|
||||
// TBD: other cases for forbidden intervals
|
||||
}
|
||||
else if (m.is_eq(e, lhs, rhs)) {
|
||||
if (m_bv.is_numeral(rhs))
|
||||
std::swap(lhs, rhs);
|
||||
if (m_bv.is_numeral(rhs))
|
||||
return false;
|
||||
if (m_bv.is_numeral(lhs, r, sz)) {
|
||||
unsigned lo, hi;
|
||||
expr* rhs2;
|
||||
if (m_bv.is_extract(rhs, lo, hi, rhs2) && r == 0) {
|
||||
unsigned sz2 = m_bv.get_bv_size(rhs2);
|
||||
if (sz2 - 1 == hi) {
|
||||
b = interval(rational::zero(), rational::power_of_two(lo) - 1, sz2, false);
|
||||
v = rhs2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
b = interval(r, r, sz, true);
|
||||
v = rhs;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool assert_expr_core(expr * t, bool sign) {
|
||||
while (m.is_not(t, t))
|
||||
sign = !sign;
|
||||
|
||||
interval b;
|
||||
expr* t1;
|
||||
if (is_bound(t, t1, b)) {
|
||||
SASSERT(m_bv.get_bv_size(t1) == b.size());
|
||||
SASSERT(!m_bv.is_numeral(t1));
|
||||
if (sign && !b.negate(b))
|
||||
return false;
|
||||
|
||||
TRACE("bv", tout << (sign?"(not ":"") << mk_pp(t, m) << (sign ? ")" : "") << ": " << mk_pp(t1, m) << " in " << b << "\n";);
|
||||
map::obj_map_entry* e = m_bound.find_core(t1);
|
||||
if (e) {
|
||||
interval& old = e->get_data().m_value;
|
||||
interval intr;
|
||||
if (!old.intersect(b, intr))
|
||||
return false;
|
||||
if (old == intr)
|
||||
return true;
|
||||
m_scopes.push_back(undo_bound(t1, old, false));
|
||||
old = intr;
|
||||
SASSERT(old.size() == m_bv.get_bv_size(t1));
|
||||
}
|
||||
else {
|
||||
SASSERT(b.size() == m_bv.get_bv_size(t1));
|
||||
m_bound.insert(t1, b);
|
||||
m_scopes.push_back(undo_bound(t1, interval(), true));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// x + q <= s <=> x not in [s - q + 1, -q[
|
||||
// <=> x in [-q, s - q], s != -1
|
||||
//
|
||||
// x in [lo, hi]
|
||||
// q = -lo
|
||||
// hi = s + lo => s = hi - lo
|
||||
// hi - lo != -1
|
||||
//
|
||||
|
||||
expr_ref mk_bound(expr* t, rational const& lo, rational const& hi) {
|
||||
sort* s = t->get_sort();
|
||||
|
||||
if (lo == hi + 1)
|
||||
return expr_ref(m.mk_true(), m);
|
||||
else
|
||||
return expr_ref(m_bv.mk_ule(m_bv.mk_bv_add(t, m_bv.mk_numeral(-lo, s)), m_bv.mk_numeral(hi - lo, s)), m);
|
||||
}
|
||||
|
||||
//
|
||||
// use interval information to rewrite sub-terms x to (0 ++ x[hi:0])
|
||||
// in other words, identify leading 0s.
|
||||
//
|
||||
bool zero_patch(expr* t, expr_ref& result) {
|
||||
if (!is_app(t))
|
||||
return false;
|
||||
|
||||
if (m_bv.is_extract(t))
|
||||
return false;
|
||||
|
||||
m_args.reset();
|
||||
bool simplified = false;
|
||||
interval b;
|
||||
for (expr* arg : *to_app(t)) {
|
||||
if (!m_bv.is_bv(arg)) {
|
||||
m_args.push_back(arg);
|
||||
continue;
|
||||
}
|
||||
if (!m_bv.is_extract(arg) && m_bound.find(arg, b)) {
|
||||
unsigned num_bits = b.hi().get_num_bits();
|
||||
unsigned bv_size = m_bv.get_bv_size(arg);
|
||||
if (0 < num_bits && num_bits < bv_size) {
|
||||
m_args.push_back(m_bv.mk_concat(m_bv.mk_zero(bv_size - num_bits),
|
||||
m_bv.mk_extract(num_bits - 1, 0, arg)));
|
||||
simplified = true;
|
||||
}
|
||||
else
|
||||
m_args.push_back(arg);
|
||||
}
|
||||
else
|
||||
m_args.push_back(arg);
|
||||
}
|
||||
|
||||
if (simplified) {
|
||||
result = m.mk_app(to_app(t)->get_decl(), m_args);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool simplify_core(expr* t, expr_ref& result) {
|
||||
expr* t1;
|
||||
interval b;
|
||||
|
||||
if (m_bound.find(t, b) && b.is_singleton()) {
|
||||
result = m_bv.mk_numeral(b.lo(), m_bv.get_bv_size(t));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (zero_patch(t, result))
|
||||
return result;
|
||||
|
||||
if (!m.is_bool(t))
|
||||
return false;
|
||||
|
||||
bool sign = false;
|
||||
while (m.is_not(t, t))
|
||||
sign = !sign;
|
||||
|
||||
if (!is_bound(t, t1, b))
|
||||
return false;
|
||||
|
||||
if (sign && b.tight()) {
|
||||
sign = false;
|
||||
if (!b.negate(b)) {
|
||||
result = m.mk_false();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
interval ctx, intr;
|
||||
result = nullptr;
|
||||
|
||||
if (b.is_full() && b.tight())
|
||||
result = m.mk_true();
|
||||
else if (!m_bound.find(t1, ctx)) {
|
||||
}
|
||||
else if (ctx.implies(b))
|
||||
result = m.mk_true();
|
||||
else if (!b.intersect(ctx, intr))
|
||||
result = m.mk_false();
|
||||
else if (m_propagate_eq && intr.is_singleton())
|
||||
result = m.mk_eq(t1, m_bv.mk_numeral(intr.lo(), t1->get_sort()));
|
||||
else if (false && intr != b)
|
||||
result = mk_bound(t1, intr.lo(), intr.hi());
|
||||
else {
|
||||
TRACE("bv", tout << mk_pp(t, m) << " b: " << b << " ctx: " << ctx << " intr " << intr << "\n");
|
||||
}
|
||||
|
||||
CTRACE("bv", result, tout << mk_pp(t, m) << " " << b << " (ctx: " << ctx << ") (intr: " << intr << "): " << result << "\n";);
|
||||
if (sign && result)
|
||||
result = m.mk_not(result);
|
||||
return result != nullptr;
|
||||
}
|
||||
|
||||
// check if t contains v
|
||||
ptr_vector<expr> todo;
|
||||
bool contains(expr* t, expr* v) {
|
||||
ast_fast_mark1 mark;
|
||||
todo.push_back(t);
|
||||
while (!todo.empty()) {
|
||||
t = todo.back();
|
||||
todo.pop_back();
|
||||
if (mark.is_marked(t))
|
||||
continue;
|
||||
if (t == v) {
|
||||
todo.reset();
|
||||
return true;
|
||||
}
|
||||
mark.mark(t);
|
||||
|
||||
if (!is_app(t))
|
||||
continue;
|
||||
app* a = to_app(t);
|
||||
todo.append(a->get_num_args(), a->get_args());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool contains_bound(expr* t) {
|
||||
ast_fast_mark1 mark1;
|
||||
ast_fast_mark2 mark2;
|
||||
|
||||
todo.push_back(t);
|
||||
while (!todo.empty()) {
|
||||
t = todo.back();
|
||||
todo.pop_back();
|
||||
if (mark1.is_marked(t)) {
|
||||
continue;
|
||||
}
|
||||
mark1.mark(t);
|
||||
|
||||
if (!is_app(t)) {
|
||||
continue;
|
||||
}
|
||||
interval b;
|
||||
expr* e;
|
||||
if (is_bound(t, e, b)) {
|
||||
if (mark2.is_marked(e)) {
|
||||
todo.reset();
|
||||
return true;
|
||||
}
|
||||
mark2.mark(e);
|
||||
if (m_bound.contains(e)) {
|
||||
todo.reset();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
app* a = to_app(t);
|
||||
todo.append(a->get_num_args(), a->get_args());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void pop_core(unsigned num_scopes) {
|
||||
TRACE("bv", tout << "pop: " << num_scopes << "\n";);
|
||||
if (m_scopes.empty())
|
||||
return;
|
||||
unsigned target = m_scopes.size() - num_scopes;
|
||||
if (target == 0) {
|
||||
m_bound.reset();
|
||||
m_scopes.reset();
|
||||
return;
|
||||
}
|
||||
for (unsigned i = m_scopes.size(); i-- > target; ) {
|
||||
undo_bound& undo = m_scopes[i];
|
||||
SASSERT(m_bound.contains(undo.e));
|
||||
if (undo.fresh)
|
||||
m_bound.erase(undo.e);
|
||||
else
|
||||
m_bound.insert(undo.e, undo.b);
|
||||
}
|
||||
m_scopes.shrink(target);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -25,10 +25,11 @@ Notes:
|
|||
|
||||
class bv_rewriter_core {
|
||||
protected:
|
||||
ast_manager& m;
|
||||
typedef rational numeral;
|
||||
bv_util m_util;
|
||||
ast_manager & m() const { return m_util.get_manager(); }
|
||||
family_id get_fid() const { return m_util.get_family_id(); }
|
||||
expr_ref m_bit1;
|
||||
|
||||
bool is_numeral(expr * n) const { return m_util.is_numeral(n); }
|
||||
bool is_numeral(expr * n, numeral & r) const { unsigned sz; return m_util.is_numeral(n, r, sz); }
|
||||
|
@ -44,7 +45,7 @@ protected:
|
|||
decl_kind power_decl_kind() const { UNREACHABLE(); return static_cast<decl_kind>(UINT_MAX); }
|
||||
|
||||
public:
|
||||
bv_rewriter_core(ast_manager & m):m_util(m) {}
|
||||
bv_rewriter_core(ast_manager & m):m(m), m_util(m), m_bit1(m) {}
|
||||
};
|
||||
|
||||
class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
|
||||
|
@ -100,6 +101,7 @@ class bv_rewriter : public poly_rewriter<bv_rewriter_core> {
|
|||
br_status mk_bv_mul(expr* a, expr* b, expr_ref& result) { expr* args[2] = { a, b }; return mk_bv_mul(2, args, result); }
|
||||
br_status mk_bv_add(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
br_status mk_bv_mul(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
br_status mk_mul_hoist(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
br_status mk_bv_shl(expr * arg1, expr * arg2, expr_ref & result);
|
||||
br_status mk_bv_lshr(expr * arg1, expr * arg2, expr_ref & result);
|
||||
br_status mk_bv_ashr(expr * arg1, expr * arg2, expr_ref & result);
|
||||
|
@ -171,11 +173,15 @@ public:
|
|||
bool is_bv(expr * t) const { return m_util.is_bv(t); }
|
||||
expr * mk_numeral(numeral const & v, unsigned sz) { return m_util.mk_numeral(v, sz); }
|
||||
expr * mk_numeral(unsigned v, unsigned sz) { return m_util.mk_numeral(numeral(v), sz); }
|
||||
app * mk_zero(sort* s) { return m_util.mk_zero(s); }
|
||||
app * mk_one(sort* s) { return m_util.mk_one(s); }
|
||||
app * mk_zero(unsigned sz) { return m_util.mk_zero(sz); }
|
||||
app * mk_one(unsigned sz) { return m_util.mk_one(sz); }
|
||||
|
||||
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
|
||||
void mk_app(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
|
||||
if (mk_app_core(f, num_args, args, result) == BR_FAILED)
|
||||
result = m().mk_app(f, num_args, args);
|
||||
result = m.mk_app(f, num_args, args);
|
||||
}
|
||||
|
||||
bool is_urem_any(expr * e, expr * & dividend, expr * & divisor);
|
||||
|
@ -187,16 +193,26 @@ public:
|
|||
|
||||
bv_util & get_util() { return m_util; }
|
||||
|
||||
// Return true if t is of the form
|
||||
// (= t #b0)
|
||||
// (= t #b1)
|
||||
// (= #b0 t)
|
||||
// (= #b1 t)
|
||||
bool is_eq_bit(expr* t, expr*& x, unsigned& val);
|
||||
|
||||
// return true if t is #b0 or #b1
|
||||
bool is_bit(expr* t, unsigned& val);
|
||||
|
||||
#define MK_BV_BINARY(OP) \
|
||||
expr_ref OP(expr* a, expr* b) { \
|
||||
expr_ref result(m()); \
|
||||
expr_ref result(m); \
|
||||
if (BR_FAILED == OP(a, b, result)) \
|
||||
result = m_util.OP(a, b); \
|
||||
return result; \
|
||||
} \
|
||||
|
||||
expr_ref mk_zero_extend(unsigned n, expr * arg) {
|
||||
expr_ref result(m());
|
||||
expr_ref result(m);
|
||||
if (BR_FAILED == mk_zero_extend(n, arg, result))
|
||||
result = m_util.mk_zero_extend(n, arg);
|
||||
return result;
|
||||
|
@ -210,7 +226,7 @@ public:
|
|||
|
||||
|
||||
expr_ref mk_bv2int(expr* a) {
|
||||
expr_ref result(m());
|
||||
expr_ref result(m);
|
||||
if (BR_FAILED == mk_bv2int(a, result))
|
||||
result = m_util.mk_bv2int(a);
|
||||
return result;
|
||||
|
|
|
@ -81,14 +81,54 @@ bool der::is_var_diseq(expr * e, unsigned num_decls, var * & v, expr_ref & t) {
|
|||
}
|
||||
|
||||
// VAR
|
||||
if (is_var(e, num_decls)) {
|
||||
if (is_var(e, num_decls))
|
||||
return set_result(to_var(e), m.mk_false());
|
||||
}
|
||||
|
||||
|
||||
// (not VAR)
|
||||
if (is_neg_var(m, e, v, num_decls)) {
|
||||
if (is_neg_var(m, e, v, num_decls))
|
||||
return set_result(v, m.mk_true());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool der::is_var_eq(expr* e, unsigned num_decls, var*& v, expr_ref& t) {
|
||||
expr* lhs, * rhs;
|
||||
auto set_result = [&](var* w, expr* s) {
|
||||
v = w;
|
||||
t = s;
|
||||
TRACE("der", tout << mk_pp(e, m) << "\n";);
|
||||
return true;
|
||||
};
|
||||
|
||||
// (= VAR t)
|
||||
if (m.is_eq(e, lhs, rhs)) {
|
||||
if (!is_var(lhs, num_decls))
|
||||
std::swap(lhs, rhs);
|
||||
if (!is_var(lhs, num_decls))
|
||||
return false;
|
||||
return set_result(to_var(lhs), rhs);
|
||||
}
|
||||
|
||||
if (m.is_eq(e, lhs, rhs) && m.is_bool(lhs)) {
|
||||
// (iff VAR t) case
|
||||
if (!is_var(lhs, num_decls))
|
||||
std::swap(lhs, rhs);
|
||||
if (is_var(lhs, num_decls)) {
|
||||
m_new_exprs.push_back(rhs);
|
||||
return set_result(to_var(lhs), rhs);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// VAR
|
||||
if (is_var(e, num_decls))
|
||||
return set_result(to_var(e), m.mk_true());
|
||||
|
||||
// (not VAR)
|
||||
if (is_neg_var(m, e, v, num_decls))
|
||||
return set_result(v, m.mk_false());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -99,6 +139,7 @@ void der::operator()(quantifier * q, expr_ref & r, proof_ref & pr) {
|
|||
|
||||
TRACE("der", tout << mk_pp(q, m) << "\n";);
|
||||
|
||||
auto k = q->get_kind();
|
||||
// Keep applying it until r doesn't change anymore
|
||||
do {
|
||||
proof_ref curr_pr(m);
|
||||
|
@ -106,14 +147,13 @@ void der::operator()(quantifier * q, expr_ref & r, proof_ref & pr) {
|
|||
reduce1(q, r, curr_pr);
|
||||
if (q != r)
|
||||
reduced = true;
|
||||
if (m.proofs_enabled()) {
|
||||
pr = m.mk_transitivity(pr, curr_pr);
|
||||
}
|
||||
if (m.proofs_enabled())
|
||||
pr = m.mk_transitivity(pr, curr_pr);
|
||||
}
|
||||
while (q != r && is_quantifier(r));
|
||||
|
||||
// Eliminate variables that have become unused
|
||||
if (reduced && is_forall(r)) {
|
||||
if (reduced && is_quantifier(r) && k == to_quantifier(r)->get_kind()) {
|
||||
quantifier * q = to_quantifier(r);
|
||||
r = elim_unused_vars(m, q, params_ref());
|
||||
if (m.proofs_enabled()) {
|
||||
|
@ -125,7 +165,7 @@ void der::operator()(quantifier * q, expr_ref & r, proof_ref & pr) {
|
|||
}
|
||||
|
||||
void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
|
||||
if (!is_forall(q)) {
|
||||
if (!is_forall(q) && !is_exists(q)) {
|
||||
pr = nullptr;
|
||||
r = q;
|
||||
return;
|
||||
|
@ -136,14 +176,20 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
|
|||
var * v = nullptr;
|
||||
expr_ref t(m);
|
||||
|
||||
if (is_var_diseq(e, num_decls, v, t) && !occurs(v, t))
|
||||
if (is_forall(q) && is_var_diseq(e, num_decls, v, t) && !occurs(v, t))
|
||||
r = m.mk_false();
|
||||
else if (is_exists(q) && is_var_eq(e, num_decls, v, t) && !occurs(v, t))
|
||||
r = m.mk_true();
|
||||
else {
|
||||
expr_ref_vector ors(m);
|
||||
flatten_or(e, ors);
|
||||
unsigned num_args = ors.size();
|
||||
expr_ref_vector literals(m);
|
||||
if (is_forall(q))
|
||||
flatten_or(e, literals);
|
||||
else
|
||||
flatten_and(e, literals);
|
||||
unsigned num_args = literals.size();
|
||||
unsigned diseq_count = 0;
|
||||
unsigned largest_vinx = 0;
|
||||
bool is_eq = false;
|
||||
|
||||
m_map.reset();
|
||||
m_pos2var.reset();
|
||||
|
@ -153,7 +199,8 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
|
|||
|
||||
// Find all disequalities
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
if (is_var_diseq(ors.get(i), num_decls, v, t)) {
|
||||
is_eq = is_forall(q) ? is_var_diseq(literals.get(i), num_decls, v, t) : is_var_eq(literals.get(i), num_decls, v, t);
|
||||
if (is_eq) {
|
||||
unsigned idx = v->get_idx();
|
||||
if (m_map.get(idx, nullptr) == nullptr) {
|
||||
m_map.reserve(idx + 1);
|
||||
|
@ -174,7 +221,7 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
|
|||
|
||||
if (!m_order.empty()) {
|
||||
create_substitution(largest_vinx + 1);
|
||||
apply_substitution(q, ors, r);
|
||||
apply_substitution(q, literals, is_forall(q), r);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -185,9 +232,9 @@ void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
|
|||
// Remark: get_elimination_order/top-sort checks for cycles, but it is not invoked for unit clauses.
|
||||
// So, we must perform a occurs check here.
|
||||
|
||||
if (m.proofs_enabled()) {
|
||||
if (m.proofs_enabled())
|
||||
pr = r == q ? nullptr : m.mk_der(q, r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void der_sort_vars(ptr_vector<var> & vars, expr_ref_vector & definitions, unsigned_vector & order) {
|
||||
|
@ -326,20 +373,20 @@ void der::create_substitution(unsigned sz) {
|
|||
}
|
||||
}
|
||||
|
||||
void der::apply_substitution(quantifier * q, expr_ref_vector& ors, expr_ref & r) {
|
||||
unsigned num_args = ors.size();
|
||||
void der::apply_substitution(quantifier * q, expr_ref_vector& literals, bool is_or, expr_ref & r) {
|
||||
unsigned num_args = literals.size();
|
||||
|
||||
// get a new expression
|
||||
m_new_args.reset();
|
||||
for(unsigned i = 0; i < num_args; i++) {
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
int x = m_pos2var[i];
|
||||
if (x != -1 && m_map.get(x) != nullptr)
|
||||
continue; // this is a disequality with definition (vanishes)
|
||||
|
||||
m_new_args.push_back(ors.get(i));
|
||||
m_new_args.push_back(literals.get(i));
|
||||
}
|
||||
|
||||
expr_ref t(mk_or(m, m_new_args.size(), m_new_args.data()), m);
|
||||
expr_ref t(is_or ? mk_or(m_new_args) : mk_and(m_new_args), m);
|
||||
expr_ref new_e = m_subst(t, m_subst_map);
|
||||
|
||||
// don't forget to update the quantifier patterns
|
||||
|
|
|
@ -131,7 +131,7 @@ class der {
|
|||
ptr_vector<var> m_inx2var;
|
||||
unsigned_vector m_order;
|
||||
expr_ref_vector m_subst_map;
|
||||
expr_ref_buffer m_new_args;
|
||||
expr_ref_vector m_new_args;
|
||||
|
||||
/**
|
||||
\brief Return true if e can be viewed as a variable disequality.
|
||||
|
@ -145,9 +145,11 @@ class der {
|
|||
*/
|
||||
bool is_var_diseq(expr * e, unsigned num_decls, var *& v, expr_ref & t);
|
||||
|
||||
bool is_var_eq(expr* e, unsigned num_decls, var*& v, expr_ref& t);
|
||||
|
||||
void get_elimination_order();
|
||||
void create_substitution(unsigned sz);
|
||||
void apply_substitution(quantifier * q, expr_ref_vector& ors, expr_ref & r);
|
||||
void apply_substitution(quantifier * q, expr_ref_vector& lits, bool is_or, expr_ref & r);
|
||||
|
||||
void reduce1(quantifier * q, expr_ref & r, proof_ref & pr);
|
||||
|
||||
|
|
325
src/ast/rewriter/dom_simplifier.cpp
Normal file
325
src/ast/rewriter/dom_simplifier.cpp
Normal file
|
@ -0,0 +1,325 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dom_simplifier.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Dominator-based context simplifer.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj and Nuno
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "ast/ast_util.h"
|
||||
#include "ast/ast_pp.h"
|
||||
#include "ast/ast_ll_pp.h"
|
||||
#include "ast/rewriter/dom_simplifier.h"
|
||||
|
||||
/**
|
||||
\brief compute a post-order traversal for e.
|
||||
Also populate the set of parents
|
||||
*/
|
||||
void expr_dominators::compute_post_order() {
|
||||
unsigned post_num = 0;
|
||||
SASSERT(m_post2expr.empty());
|
||||
SASSERT(m_expr2post.empty());
|
||||
ast_mark mark;
|
||||
ptr_vector<expr> todo;
|
||||
todo.push_back(m_root);
|
||||
while (!todo.empty()) {
|
||||
expr* e = todo.back();
|
||||
if (mark.is_marked(e)) {
|
||||
todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
if (is_app(e)) {
|
||||
app* a = to_app(e);
|
||||
bool done = true;
|
||||
for (expr* arg : *a) {
|
||||
if (!mark.is_marked(arg)) {
|
||||
todo.push_back(arg);
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
if (done) {
|
||||
mark.mark(e, true);
|
||||
m_expr2post.insert(e, post_num++);
|
||||
m_post2expr.push_back(e);
|
||||
todo.pop_back();
|
||||
for (expr* arg : *a) {
|
||||
add_edge(m_parents, arg, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
mark.mark(e, true);
|
||||
todo.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expr* expr_dominators::intersect(expr* x, expr * y) {
|
||||
unsigned n1 = m_expr2post[x];
|
||||
unsigned n2 = m_expr2post[y];
|
||||
while (n1 != n2) {
|
||||
if (n1 < n2) {
|
||||
x = m_doms[x];
|
||||
n1 = m_expr2post[x];
|
||||
}
|
||||
else if (n1 > n2) {
|
||||
y = m_doms[y];
|
||||
n2 = m_expr2post[y];
|
||||
}
|
||||
}
|
||||
SASSERT(x == y);
|
||||
return x;
|
||||
}
|
||||
|
||||
bool expr_dominators::compute_dominators() {
|
||||
expr * e = m_root;
|
||||
SASSERT(m_doms.empty());
|
||||
m_doms.insert(e, e);
|
||||
bool change = true;
|
||||
unsigned iterations = 1;
|
||||
while (change) {
|
||||
change = false;
|
||||
TRACE("simplify",
|
||||
for (auto & kv : m_doms) {
|
||||
tout << mk_bounded_pp(kv.m_key, m) << " |-> " << mk_bounded_pp(kv.m_value, m) << "\n";
|
||||
});
|
||||
|
||||
SASSERT(m_post2expr.empty() || m_post2expr.back() == e);
|
||||
for (unsigned i = 0; i + 1 < m_post2expr.size(); ++i) {
|
||||
expr * child = m_post2expr[i];
|
||||
ptr_vector<expr> const& p = m_parents[child];
|
||||
expr * new_idom = nullptr, *idom2 = nullptr;
|
||||
|
||||
for (expr * pred : p) {
|
||||
if (m_doms.contains(pred)) {
|
||||
new_idom = !new_idom ? pred : intersect(new_idom, pred);
|
||||
}
|
||||
}
|
||||
if (!new_idom) {
|
||||
m_doms.insert(child, p[0]);
|
||||
change = true;
|
||||
}
|
||||
else if (!m_doms.find(child, idom2) || idom2 != new_idom) {
|
||||
m_doms.insert(child, new_idom);
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
iterations *= 2;
|
||||
if (change && iterations > m_post2expr.size()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void expr_dominators::extract_tree() {
|
||||
for (auto const& kv : m_doms) {
|
||||
add_edge(m_tree, kv.m_value, kv.m_key);
|
||||
}
|
||||
}
|
||||
|
||||
bool expr_dominators::compile(expr * e) {
|
||||
reset();
|
||||
m_root = e;
|
||||
compute_post_order();
|
||||
if (!compute_dominators()) return false;
|
||||
extract_tree();
|
||||
TRACE("simplify", display(tout););
|
||||
return true;
|
||||
}
|
||||
|
||||
bool expr_dominators::compile(unsigned sz, expr * const* es) {
|
||||
expr_ref e(m.mk_and(sz, es), m);
|
||||
return compile(e);
|
||||
}
|
||||
|
||||
void expr_dominators::reset() {
|
||||
m_expr2post.reset();
|
||||
m_post2expr.reset();
|
||||
m_parents.reset();
|
||||
m_doms.reset();
|
||||
m_tree.reset();
|
||||
m_root.reset();
|
||||
}
|
||||
|
||||
std::ostream& expr_dominators::display(std::ostream& out) {
|
||||
return display(out, 0, m_root);
|
||||
}
|
||||
|
||||
std::ostream& expr_dominators::display(std::ostream& out, unsigned indent, expr* r) {
|
||||
for (unsigned i = 0; i < indent; ++i) out << " ";
|
||||
out << r->get_id() << ": " << mk_bounded_pp(r, m, 1) << "\n";
|
||||
if (m_tree.contains(r)) {
|
||||
for (expr* child : m_tree[r]) {
|
||||
if (child != r)
|
||||
display(out, indent + 1, child);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------
|
||||
// expr_substitution_simplifier
|
||||
namespace {
|
||||
|
||||
class expr_substitution_simplifier : public dom_simplifier {
|
||||
ast_manager& m;
|
||||
expr_substitution m_subst;
|
||||
scoped_expr_substitution m_scoped_substitution;
|
||||
obj_map<expr, unsigned> m_expr2depth;
|
||||
expr_ref_vector m_trail;
|
||||
|
||||
// move from asserted_formulas to here..
|
||||
void compute_depth(expr* e) {
|
||||
ptr_vector<expr> todo;
|
||||
todo.push_back(e);
|
||||
while (!todo.empty()) {
|
||||
e = todo.back();
|
||||
unsigned d = 0;
|
||||
if (m_expr2depth.contains(e)) {
|
||||
todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
if (is_app(e)) {
|
||||
app* a = to_app(e);
|
||||
bool visited = true;
|
||||
for (expr* arg : *a) {
|
||||
unsigned d1 = 0;
|
||||
if (m_expr2depth.find(arg, d1)) {
|
||||
d = std::max(d, d1);
|
||||
}
|
||||
else {
|
||||
visited = false;
|
||||
todo.push_back(arg);
|
||||
}
|
||||
}
|
||||
if (!visited) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
todo.pop_back();
|
||||
m_expr2depth.insert(e, d + 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_gt(expr* lhs, expr* rhs) {
|
||||
if (lhs == rhs) {
|
||||
return false;
|
||||
}
|
||||
if (m.is_value(rhs)) {
|
||||
return true;
|
||||
}
|
||||
SASSERT(is_ground(lhs) && is_ground(rhs));
|
||||
if (depth(lhs) > depth(rhs)) {
|
||||
return true;
|
||||
}
|
||||
if (depth(lhs) == depth(rhs) && is_app(lhs) && is_app(rhs)) {
|
||||
app* l = to_app(lhs);
|
||||
app* r = to_app(rhs);
|
||||
if (l->get_decl()->get_id() != r->get_decl()->get_id()) {
|
||||
return l->get_decl()->get_id() > r->get_decl()->get_id();
|
||||
}
|
||||
if (l->get_num_args() != r->get_num_args()) {
|
||||
return l->get_num_args() > r->get_num_args();
|
||||
}
|
||||
for (unsigned i = 0; i < l->get_num_args(); ++i) {
|
||||
if (l->get_arg(i) != r->get_arg(i)) {
|
||||
return is_gt(l->get_arg(i), r->get_arg(i));
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned depth(expr* e) { return m_expr2depth[e]; }
|
||||
|
||||
public:
|
||||
expr_substitution_simplifier(ast_manager& m): m(m), m_subst(m), m_scoped_substitution(m_subst), m_trail(m) {}
|
||||
|
||||
void updt_params(params_ref const & p) override {}
|
||||
|
||||
void collect_param_descrs(param_descrs& r) override {}
|
||||
|
||||
bool assert_expr(expr * t, bool sign) override {
|
||||
expr* tt;
|
||||
if (m.is_not(t, tt))
|
||||
return assert_expr(tt, !sign);
|
||||
if (m.is_false(t))
|
||||
return sign;
|
||||
if (m.is_true(t))
|
||||
return !sign;
|
||||
|
||||
TRACE("simplify", tout << t->get_id() << ": " << mk_bounded_pp(t, m) << " " << (sign?" - neg":" - pos") << "\n";);
|
||||
|
||||
m_scoped_substitution.push();
|
||||
if (!sign) {
|
||||
update_substitution(t, nullptr);
|
||||
}
|
||||
else {
|
||||
expr_ref nt(m.mk_not(t), m);
|
||||
update_substitution(nt, nullptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void update_substitution(expr* n, proof* pr) {
|
||||
expr* lhs, *rhs, *n1;
|
||||
if (is_ground(n) && m.is_eq(n, lhs, rhs)) {
|
||||
compute_depth(lhs);
|
||||
compute_depth(rhs);
|
||||
m_trail.push_back(lhs);
|
||||
m_trail.push_back(rhs);
|
||||
if (is_gt(lhs, rhs)) {
|
||||
TRACE("propagate_values", tout << "insert " << mk_pp(lhs, m) << " -> " << mk_pp(rhs, m) << "\n";);
|
||||
m_scoped_substitution.insert(lhs, rhs, pr);
|
||||
return;
|
||||
}
|
||||
if (is_gt(rhs, lhs)) {
|
||||
TRACE("propagate_values", tout << "insert " << mk_pp(rhs, m) << " -> " << mk_pp(lhs, m) << "\n";);
|
||||
m_scoped_substitution.insert(rhs, lhs, m.mk_symmetry(pr));
|
||||
return;
|
||||
}
|
||||
TRACE("propagate_values", tout << "incompatible " << mk_pp(n, m) << "\n";);
|
||||
}
|
||||
if (m.is_not(n, n1)) {
|
||||
m_scoped_substitution.insert(n1, m.mk_false(), m.mk_iff_false(pr));
|
||||
}
|
||||
else {
|
||||
m_scoped_substitution.insert(n, m.mk_true(), m.mk_iff_true(pr));
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(expr_ref& r) override { r = m_scoped_substitution.find(r); }
|
||||
|
||||
void pop(unsigned num_scopes) override { m_scoped_substitution.pop(num_scopes); }
|
||||
|
||||
unsigned scope_level() const override { return m_scoped_substitution.scope_level(); }
|
||||
|
||||
dom_simplifier * translate(ast_manager & m) override {
|
||||
SASSERT(m_subst.empty());
|
||||
return alloc(expr_substitution_simplifier, m);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
dom_simplifier* mk_expr_substitution_simplifier(ast_manager& m) {
|
||||
return alloc(expr_substitution_simplifier, m);
|
||||
}
|
||||
|
||||
|
||||
|
86
src/ast/rewriter/dom_simplifier.h
Normal file
86
src/ast/rewriter/dom_simplifier.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dom_simplifier.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Dominator-based context simplifer.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj and Nuno
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ast/ast.h"
|
||||
#include "ast/expr_substitution.h"
|
||||
#include "util/obj_pair_hashtable.h"
|
||||
|
||||
class expr_dominators {
|
||||
public:
|
||||
typedef obj_map<expr, ptr_vector<expr>> tree_t;
|
||||
private:
|
||||
ast_manager& m;
|
||||
expr_ref m_root;
|
||||
obj_map<expr, unsigned> m_expr2post; // reverse post-order number
|
||||
ptr_vector<expr> m_post2expr;
|
||||
tree_t m_parents;
|
||||
obj_map<expr, expr*> m_doms;
|
||||
tree_t m_tree;
|
||||
|
||||
void add_edge(tree_t& tree, expr * src, expr* dst) {
|
||||
tree.insert_if_not_there(src, ptr_vector<expr>()).push_back(dst);
|
||||
}
|
||||
|
||||
void compute_post_order();
|
||||
expr* intersect(expr* x, expr * y);
|
||||
bool compute_dominators();
|
||||
void extract_tree();
|
||||
|
||||
std::ostream& display(std::ostream& out, unsigned indent, expr* r);
|
||||
|
||||
public:
|
||||
expr_dominators(ast_manager& m): m(m), m_root(m) {}
|
||||
|
||||
bool compile(expr * e);
|
||||
bool compile(unsigned sz, expr * const* es);
|
||||
tree_t const& get_tree() { return m_tree; }
|
||||
void reset();
|
||||
expr* idom(expr *e) const { return m_doms[e]; }
|
||||
|
||||
std::ostream& display(std::ostream& out);
|
||||
};
|
||||
|
||||
class dom_simplifier {
|
||||
public:
|
||||
virtual ~dom_simplifier() = default;
|
||||
/**
|
||||
\brief assert_expr performs an implicit push
|
||||
*/
|
||||
virtual bool assert_expr(expr * t, bool sign) = 0;
|
||||
|
||||
/**
|
||||
\brief apply simplification.
|
||||
*/
|
||||
virtual void operator()(expr_ref& r) = 0;
|
||||
|
||||
/**
|
||||
\brief pop scopes accumulated from assertions.
|
||||
*/
|
||||
virtual void pop(unsigned num_scopes) = 0;
|
||||
|
||||
virtual dom_simplifier * translate(ast_manager & m) = 0;
|
||||
|
||||
virtual unsigned scope_level() const = 0;
|
||||
|
||||
virtual void updt_params(params_ref const & p) = 0;
|
||||
|
||||
virtual void collect_param_descrs(param_descrs& r) = 0;
|
||||
};
|
||||
|
||||
dom_simplifier* mk_expr_substitution_simplifier(ast_manager& m);
|
|
@ -25,6 +25,11 @@ void expr_replacer::operator()(expr * t, expr_ref & result, proof_ref & result_p
|
|||
operator()(t, result, result_pr, result_dep);
|
||||
}
|
||||
|
||||
void expr_replacer::operator()(expr* t, expr_ref& result, expr_dependency_ref& result_dep) {
|
||||
proof_ref result_pr(m());
|
||||
operator()(t, result, result_pr, result_dep);
|
||||
}
|
||||
|
||||
void expr_replacer::operator()(expr * t, expr_ref & result) {
|
||||
proof_ref pr(m());
|
||||
operator()(t, result, pr);
|
||||
|
|
|
@ -34,9 +34,12 @@ public:
|
|||
virtual void set_substitution(expr_substitution * s) = 0;
|
||||
|
||||
virtual void operator()(expr * t, expr_ref & result, proof_ref & result_pr, expr_dependency_ref & deps) = 0;
|
||||
virtual void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
|
||||
virtual void operator()(expr * t, expr_ref & result);
|
||||
virtual void operator()(expr_ref & t) { expr_ref s(t, m()); (*this)(s, t); }
|
||||
void operator()(expr* t, expr_ref& result, expr_dependency_ref& deps);
|
||||
void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
|
||||
void operator()(expr * t, expr_ref & result);
|
||||
void operator()(expr_ref & t) { expr_ref s(t, m()); (*this)(s, t); }
|
||||
void operator()(expr_ref_vector& v) { expr_ref t(m()); for (unsigned i = 0; i < v.size(); ++i) (*this)(v.get(i), t), v[i] = t; }
|
||||
std::pair<expr_ref, expr_dependency_ref> replace_with_dep(expr* t) { expr_ref r(m()); expr_dependency_ref d(m()); (*this)(t, r, d); return { r, d }; }
|
||||
|
||||
virtual unsigned get_num_steps() const { return 0; }
|
||||
virtual void reset() = 0;
|
||||
|
|
|
@ -13,8 +13,6 @@ Author:
|
|||
|
||||
Nikolaj Bjorner (nbjorner) 2019-2-4
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
|
@ -25,19 +23,17 @@ Notes:
|
|||
|
||||
|
||||
hoist_rewriter::hoist_rewriter(ast_manager & m, params_ref const & p):
|
||||
m_manager(m), m_args1(m), m_args2(m), m_subst(m) {
|
||||
m(m), m_args1(m), m_args2(m), m_subst(m) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref & result) {
|
||||
if (num_args < 2) {
|
||||
if (num_args < 2)
|
||||
return BR_FAILED;
|
||||
}
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
if (!is_and(es[i], nullptr)) {
|
||||
|
||||
for (unsigned i = 0; i < num_args; ++i)
|
||||
if (!is_and(es[i], nullptr))
|
||||
return BR_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
bool turn = false;
|
||||
m_preds1.reset();
|
||||
|
@ -52,12 +48,10 @@ br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref &
|
|||
VERIFY(is_and(es[0], args[turn]));
|
||||
expr* e1, *e2;
|
||||
for (expr* e : *(args[turn])) {
|
||||
if (m().is_eq(e, e1, e2)) {
|
||||
if (m.is_eq(e, e1, e2))
|
||||
(*uf)[turn].merge(mk_var(e1), mk_var(e2));
|
||||
}
|
||||
else {
|
||||
else
|
||||
(*preds)[turn].insert(e);
|
||||
}
|
||||
}
|
||||
unsigned round = 0;
|
||||
for (unsigned j = 1; j < num_args; ++j) {
|
||||
|
@ -72,44 +66,39 @@ br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref &
|
|||
VERIFY(is_and(es[j], args[turn]));
|
||||
|
||||
for (expr* e : *args[turn]) {
|
||||
if (m().is_eq(e, e1, e2)) {
|
||||
if (m.is_eq(e, e1, e2)) {
|
||||
m_es.push_back(e1);
|
||||
m_uf0.merge(mk_var(e1), mk_var(e2));
|
||||
}
|
||||
else if ((*preds)[last].contains(e)) {
|
||||
else if ((*preds)[last].contains(e))
|
||||
(*preds)[turn].insert(e);
|
||||
}
|
||||
}
|
||||
|
||||
if ((*preds)[turn].empty() && m_es.empty()) {
|
||||
if ((*preds)[turn].empty() && m_es.empty())
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
m_eqs.reset();
|
||||
for (expr* e : m_es) {
|
||||
if (m_mark.is_marked(e)) {
|
||||
if (m_mark.is_marked(e))
|
||||
continue;
|
||||
}
|
||||
unsigned u = mk_var(e);
|
||||
unsigned v = u;
|
||||
m_roots.reset();
|
||||
do {
|
||||
m_mark.mark(e);
|
||||
unsigned r = (*uf)[last].find(v);
|
||||
if (m_roots.find(r, e2)) {
|
||||
m_eqs.push_back(std::make_pair(e, e2));
|
||||
}
|
||||
else {
|
||||
if (m_roots.find(r, e2))
|
||||
m_eqs.push_back({e, e2});
|
||||
else
|
||||
m_roots.insert(r, e);
|
||||
}
|
||||
v = m_uf0.next(v);
|
||||
e = mk_expr(v);
|
||||
}
|
||||
while (u != v);
|
||||
}
|
||||
reset((*uf)[turn]);
|
||||
for (auto const& p : m_eqs)
|
||||
(*uf)[turn].merge(mk_var(p.first), mk_var(p.second));
|
||||
for (auto const& [e1, e2] : m_eqs)
|
||||
(*uf)[turn].merge(mk_var(e1), mk_var(e2));
|
||||
if ((*preds)[turn].empty() && m_eqs.empty())
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
@ -118,25 +107,23 @@ br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref &
|
|||
return BR_DONE;
|
||||
}
|
||||
// p & eqs & (or fmls)
|
||||
expr_ref_vector fmls(m());
|
||||
expr_ref_vector fmls(m);
|
||||
m_subst.reset();
|
||||
for (expr * p : (*preds)[turn]) {
|
||||
expr* q = nullptr;
|
||||
if (m().is_not(p, q)) {
|
||||
m_subst.insert(q, m().mk_false());
|
||||
}
|
||||
else {
|
||||
m_subst.insert(p, m().mk_true());
|
||||
}
|
||||
if (m.is_not(p, q))
|
||||
m_subst.insert(q, m.mk_false());
|
||||
else
|
||||
m_subst.insert(p, m.mk_true());
|
||||
fmls.push_back(p);
|
||||
}
|
||||
for (auto& p : m_eqs) {
|
||||
if (m().is_value(p.first))
|
||||
if (m.is_value(p.first))
|
||||
std::swap(p.first, p.second);
|
||||
m_subst.insert(p.first, p.second);
|
||||
fmls.push_back(m().mk_eq(p.first, p.second));
|
||||
fmls.push_back(m.mk_eq(p.first, p.second));
|
||||
}
|
||||
expr_ref ors(::mk_or(m(), num_args, es), m());
|
||||
expr_ref ors(::mk_or(m, num_args, es), m);
|
||||
m_subst(ors);
|
||||
fmls.push_back(ors);
|
||||
result = mk_and(fmls);
|
||||
|
@ -146,9 +133,8 @@ br_status hoist_rewriter::mk_or(unsigned num_args, expr * const * es, expr_ref &
|
|||
|
||||
unsigned hoist_rewriter::mk_var(expr* e) {
|
||||
unsigned v = 0;
|
||||
if (m_expr2var.find(e, v)) {
|
||||
if (m_expr2var.find(e, v))
|
||||
return v;
|
||||
}
|
||||
m_uf1.mk_var();
|
||||
v = m_uf2.mk_var();
|
||||
SASSERT(v == m_var2expr.size());
|
||||
|
@ -158,15 +144,14 @@ unsigned hoist_rewriter::mk_var(expr* e) {
|
|||
}
|
||||
|
||||
expr_ref hoist_rewriter::hoist_predicates(obj_hashtable<expr> const& preds, unsigned num_args, expr* const* es) {
|
||||
expr_ref result(m());
|
||||
expr_ref_vector args(m()), fmls(m());
|
||||
expr_ref result(m);
|
||||
expr_ref_vector args(m), fmls(m);
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
VERIFY(is_and(es[i], &m_args1));
|
||||
fmls.reset();
|
||||
for (expr* e : m_args1) {
|
||||
for (expr* e : m_args1)
|
||||
if (!preds.contains(e))
|
||||
fmls.push_back(e);
|
||||
}
|
||||
args.push_back(::mk_and(fmls));
|
||||
}
|
||||
fmls.reset();
|
||||
|
@ -188,19 +173,18 @@ br_status hoist_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c
|
|||
}
|
||||
|
||||
bool hoist_rewriter::is_and(expr * e, expr_ref_vector* args) {
|
||||
if (m().is_and(e)) {
|
||||
if (m.is_and(e)) {
|
||||
if (args) {
|
||||
args->reset();
|
||||
args->append(to_app(e)->get_num_args(), to_app(e)->get_args());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (m().is_not(e, e) && m().is_or(e)) {
|
||||
if (m.is_not(e, e) && m.is_or(e)) {
|
||||
if (args) {
|
||||
args->reset();
|
||||
for (expr* arg : *to_app(e)) {
|
||||
args->push_back(::mk_not(m(), arg));
|
||||
}
|
||||
for (expr* arg : *to_app(e))
|
||||
args->push_back(::mk_not(m, arg));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ Notes:
|
|||
#include "util/obj_hashtable.h"
|
||||
|
||||
class hoist_rewriter {
|
||||
ast_manager & m_manager;
|
||||
ast_manager & m;
|
||||
expr_ref_vector m_args1, m_args2;
|
||||
obj_hashtable<expr> m_preds1, m_preds2;
|
||||
basic_union_find m_uf1, m_uf2, m_uf0;
|
||||
|
@ -34,11 +34,9 @@ class hoist_rewriter {
|
|||
svector<std::pair<expr*,expr*>> m_eqs;
|
||||
u_map<expr*> m_roots;
|
||||
expr_safe_replace m_subst;
|
||||
obj_map<expr, unsigned> m_expr2var;
|
||||
ptr_vector<expr> m_var2expr;
|
||||
expr_mark m_mark;
|
||||
|
||||
br_status mk_or(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
obj_map<expr, unsigned> m_expr2var;
|
||||
ptr_vector<expr> m_var2expr;
|
||||
expr_mark m_mark;
|
||||
|
||||
bool is_and(expr* e, expr_ref_vector* args);
|
||||
|
||||
|
@ -52,12 +50,12 @@ class hoist_rewriter {
|
|||
|
||||
public:
|
||||
hoist_rewriter(ast_manager & m, params_ref const & p = params_ref());
|
||||
ast_manager& m() const { return m_manager; }
|
||||
family_id get_fid() const { return m().get_basic_family_id(); }
|
||||
bool is_eq(expr * t) const { return m().is_eq(t); }
|
||||
family_id get_fid() const { return m.get_basic_family_id(); }
|
||||
bool is_eq(expr * t) const { return m.is_eq(t); }
|
||||
void updt_params(params_ref const & p) {}
|
||||
static void get_param_descrs(param_descrs & r) {}
|
||||
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
|
||||
br_status mk_or(unsigned num_args, expr * const * args, expr_ref & result);
|
||||
};
|
||||
|
||||
struct hoist_rewriter_cfg : public default_rewriter_cfg {
|
||||
|
|
160
src/ast/rewriter/macro_replacer.cpp
Normal file
160
src/ast/rewriter/macro_replacer.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
/*++
|
||||
Copyright (c) 2022 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
macro_replacer.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Abstract (functor) for applying macro replacement.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2022-11-24
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
|
||||
#include "ast/rewriter/macro_replacer.h"
|
||||
#include "ast/rewriter/rewriter_def.h"
|
||||
#include "ast/rewriter/var_subst.h"
|
||||
|
||||
/**
|
||||
* Rewriting formulas using macro definitions.
|
||||
*/
|
||||
struct macro_replacer::macro_replacer_cfg : public default_rewriter_cfg {
|
||||
ast_manager& m;
|
||||
macro_replacer& ep;
|
||||
expr_dependency_ref& m_used_macro_dependencies;
|
||||
expr_ref_vector m_trail;
|
||||
|
||||
macro_replacer_cfg(ast_manager& m, macro_replacer& ep, expr_dependency_ref& deps) :
|
||||
m(m),
|
||||
ep(ep),
|
||||
m_used_macro_dependencies(deps),
|
||||
m_trail(m)
|
||||
{}
|
||||
|
||||
bool rewrite_patterns() const { return false; }
|
||||
bool flat_assoc(func_decl* f) const { return false; }
|
||||
br_status reduce_app(func_decl* f, unsigned num, expr* const* args, expr_ref& result, proof_ref& result_pr) {
|
||||
result_pr = nullptr;
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* adapted from macro_manager.cpp
|
||||
* Perhaps hoist and combine?
|
||||
*/
|
||||
bool reduce_quantifier(quantifier* old_q,
|
||||
expr* new_body,
|
||||
expr* const* new_patterns,
|
||||
expr* const* new_no_patterns,
|
||||
expr_ref& result,
|
||||
proof_ref& result_pr) {
|
||||
|
||||
bool erase_patterns = false;
|
||||
for (unsigned i = 0; !erase_patterns && i < old_q->get_num_patterns(); i++)
|
||||
if (old_q->get_pattern(i) != new_patterns[i])
|
||||
erase_patterns = true;
|
||||
|
||||
for (unsigned i = 0; !erase_patterns && i < old_q->get_num_no_patterns(); i++)
|
||||
if (old_q->get_no_pattern(i) != new_no_patterns[i])
|
||||
erase_patterns = true;
|
||||
|
||||
if (erase_patterns)
|
||||
result = m.update_quantifier(old_q, 0, nullptr, 0, nullptr, new_body);
|
||||
|
||||
if (erase_patterns && m.proofs_enabled())
|
||||
result_pr = m.mk_rewrite(old_q, result);
|
||||
|
||||
return erase_patterns;
|
||||
}
|
||||
|
||||
bool get_subst(expr* _n, expr*& r, proof*& p) {
|
||||
if (!is_app(_n))
|
||||
return false;
|
||||
p = nullptr;
|
||||
app* n = to_app(_n);
|
||||
func_decl* d = n->get_decl();
|
||||
app_ref head(m);
|
||||
expr_ref def(m);
|
||||
expr_dependency_ref dep(m);
|
||||
if (ep.has_macro(d, head, def, dep)) {
|
||||
unsigned num = head->get_num_args();
|
||||
ptr_buffer<expr> subst_args;
|
||||
subst_args.resize(num, 0);
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
var* v = to_var(head->get_arg(i));
|
||||
VERIFY(v->get_idx() < num);
|
||||
unsigned nidx = num - v->get_idx() - 1;
|
||||
SASSERT(!subst_args[nidx]);
|
||||
subst_args[nidx] = n->get_arg(i);
|
||||
}
|
||||
var_subst s(m);
|
||||
expr_ref rr = s(def, num, subst_args.data());
|
||||
r = rr;
|
||||
m_trail.push_back(rr);
|
||||
m_used_macro_dependencies = m.mk_join(m_used_macro_dependencies, dep);
|
||||
// skip proof terms for simplifiers
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct macro_replacer::macro_replacer_rw : public rewriter_tpl<macro_replacer::macro_replacer_cfg> {
|
||||
macro_replacer::macro_replacer_cfg m_cfg;
|
||||
|
||||
macro_replacer_rw(ast_manager& m, macro_replacer& ep, expr_dependency_ref& deps) :
|
||||
rewriter_tpl<macro_replacer::macro_replacer_cfg>(m, false, m_cfg),
|
||||
m_cfg(m, ep, deps)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
void macro_replacer::insert(app* head, expr* def, expr_dependency* dep) {
|
||||
func_decl* f = head->get_decl();
|
||||
m_trail.push_back(head);
|
||||
m_trail.push_back(def);
|
||||
m_deps.push_back(dep);
|
||||
m_map.insert(f, std::tuple(head, def, dep));
|
||||
}
|
||||
|
||||
void macro_replacer::operator()(expr* t, expr_dependency* dep_in, expr_ref& result, expr_dependency_ref& dep_out) {
|
||||
expr_dependency_ref _dep_in(dep_in, m);
|
||||
macro_replacer_rw exp(m, *this, dep_out);
|
||||
exp(t, result);
|
||||
if (!dep_in)
|
||||
return;
|
||||
// update dependencies if needed
|
||||
m_dep_exprs.reset();
|
||||
m.linearize(dep_in, m_dep_exprs);
|
||||
unsigned sz = m_trail.size();
|
||||
for (expr*& d : m_dep_exprs) {
|
||||
exp(d, result);
|
||||
if (result != d) {
|
||||
d = result.get();
|
||||
m_trail.push_back(result);
|
||||
}
|
||||
}
|
||||
if (sz != m_trail.size()) {
|
||||
dep_in = m.mk_join(m_dep_exprs.size(), m_dep_exprs.data());
|
||||
m_trail.shrink(sz);
|
||||
}
|
||||
dep_out = m.mk_join(dep_in, dep_out);
|
||||
}
|
||||
|
||||
bool macro_replacer::has_macro(func_decl* f, app_ref& head, expr_ref& def, expr_dependency_ref& dep) {
|
||||
std::tuple<app*,expr*,expr_dependency*> v;
|
||||
if (!m_map.find(f, v))
|
||||
return false;
|
||||
auto const& [h, d, dp] = v;
|
||||
head = h;
|
||||
def = d;
|
||||
dep = dp;
|
||||
return true;
|
||||
}
|
45
src/ast/rewriter/macro_replacer.h
Normal file
45
src/ast/rewriter/macro_replacer.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*++
|
||||
Copyright (c) 2022 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
macro_replacer.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Abstract (functor) for applying macro replacement.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2022-11-24
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "ast/ast.h"
|
||||
#include "util/obj_hashtable.h"
|
||||
|
||||
|
||||
class macro_replacer {
|
||||
ast_manager& m;
|
||||
ast_ref_vector m_trail;
|
||||
expr_dependency_ref_vector m_deps;
|
||||
ptr_vector<expr> m_dep_exprs;
|
||||
obj_map<func_decl, std::tuple<app*, expr*, expr_dependency*>> m_map;
|
||||
struct macro_replacer_cfg;
|
||||
struct macro_replacer_rw;
|
||||
|
||||
public:
|
||||
|
||||
macro_replacer(ast_manager& m): m(m), m_trail(m), m_deps(m) {}
|
||||
|
||||
void insert(app* head, expr* def, expr_dependency* dep);
|
||||
void operator()(expr* t, expr_dependency* d, expr_ref& result, expr_dependency_ref& dep);
|
||||
void operator()(expr* t, expr_ref & result) { expr_dependency_ref dep(m); (*this)(t, nullptr, result, dep); }
|
||||
void operator()(expr_ref & t) { expr_ref s(t, m); (*this)(s, t); }
|
||||
|
||||
bool has_macro(func_decl* f, app_ref& head, expr_ref& def, expr_dependency_ref& d);
|
||||
};
|
||||
|
|
@ -32,8 +32,15 @@ mk_extract_proc::~mk_extract_proc() {
|
|||
}
|
||||
|
||||
app * mk_extract_proc::operator()(unsigned high, unsigned low, expr * arg) {
|
||||
unsigned l, h;
|
||||
while (m_util.is_extract(arg, l, h, arg)) {
|
||||
low += l;
|
||||
high += l;
|
||||
}
|
||||
ast_manager & m = m_util.get_manager();
|
||||
sort * s = arg->get_sort();
|
||||
if (low == 0 && high + 1 == m_util.get_bv_size(arg) && is_app(arg))
|
||||
return to_app(arg);
|
||||
if (m_low == low && m_high == high && m_domain == s)
|
||||
return m.mk_app(m_f_cached, arg);
|
||||
// m_f_cached has a reference to m_domain, so, I don't need to inc_ref m_domain
|
||||
|
|
|
@ -200,7 +200,7 @@ struct pb2bv_rewriter::imp {
|
|||
}
|
||||
|
||||
if (m_pb_solver == "segmented") {
|
||||
throw default_exception("segmented encoding is disabled, use a different value for pb.solver");
|
||||
throw default_exception("segmented encoding is disabled, use a different value for pb.solver");
|
||||
switch (is_le) {
|
||||
case l_true: return mk_seg_le(k);
|
||||
case l_false: return mk_seg_ge(k);
|
||||
|
@ -1077,9 +1077,9 @@ struct pb2bv_rewriter::imp {
|
|||
}
|
||||
|
||||
void collect_param_descrs(param_descrs& r) const {
|
||||
r.insert("keep_cardinality_constraints", CPK_BOOL, "(default: false) retain cardinality constraints (don't bit-blast them) and use built-in cardinality solver");
|
||||
r.insert("pb.solver", CPK_SYMBOL, "(default: solver) retain pb constraints (don't bit-blast them) and use built-in pb solver");
|
||||
r.insert("cardinality.encoding", CPK_SYMBOL, "(default: none) grouped, bimander, ordered, unate, circuit");
|
||||
r.insert("keep_cardinality_constraints", CPK_BOOL, "retain cardinality constraints (don't bit-blast them) and use built-in cardinality solver", "false");
|
||||
r.insert("pb.solver", CPK_SYMBOL, "encoding used for Pseudo-Boolean constraints: totalizer, sorting, binary_merge, bv, solver. PB constraints are retained if set to 'solver'", "solver");
|
||||
r.insert("cardinality.encoding", CPK_SYMBOL, "encoding used for cardinality constraints: grouped, bimander, ordered, unate, circuit", "none");
|
||||
}
|
||||
|
||||
unsigned get_num_steps() const { return m_rw.get_num_steps(); }
|
||||
|
|
|
@ -36,6 +36,7 @@ protected:
|
|||
bool m_hoist_mul;
|
||||
bool m_ast_order;
|
||||
bool m_hoist_ite;
|
||||
ast_manager& M() { return Config::m; }
|
||||
|
||||
bool is_numeral(expr * n) const { return Config::is_numeral(n); }
|
||||
bool is_numeral(expr * n, numeral & r) const { return Config::is_numeral(n, r); }
|
||||
|
@ -106,7 +107,6 @@ public:
|
|||
SASSERT(!m_som || !m_hoist_mul); // som is mutually exclusive with hoisting multiplication.
|
||||
}
|
||||
|
||||
ast_manager & m() const { return Config::m(); }
|
||||
family_id get_fid() const { return Config::get_fid(); }
|
||||
|
||||
void updt_params(params_ref const & p);
|
||||
|
|
|
@ -51,7 +51,7 @@ expr * poly_rewriter<Config>::mk_add_app(unsigned num_args, expr * const * args)
|
|||
switch (num_args) {
|
||||
case 0: return mk_numeral(numeral(0));
|
||||
case 1: return args[0];
|
||||
default: return m().mk_app(get_fid(), add_decl_kind(), num_args, args);
|
||||
default: return M().mk_app(get_fid(), add_decl_kind(), num_args, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ expr * poly_rewriter<Config>::mk_mul_app(unsigned num_args, expr * const * args)
|
|||
if (new_args.size() > 2 && is_numeral(new_args.get(0), a)) {
|
||||
return mk_mul_app(a, mk_mul_app(new_args.size() - 1, new_args.data() + 1));
|
||||
}
|
||||
return m().mk_app(get_fid(), mul_decl_kind(), new_args.size(), new_args.data());
|
||||
return M().mk_app(get_fid(), mul_decl_kind(), new_args.size(), new_args.data());
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -127,7 +127,7 @@ expr * poly_rewriter<Config>::mk_mul_app(unsigned num_args, expr * const * args)
|
|||
if (num_args > 2 && is_numeral(args[0], a)) {
|
||||
return mk_mul_app(a, mk_mul_app(num_args - 1, args + 1));
|
||||
}
|
||||
return m().mk_app(get_fid(), mul_decl_kind(), num_args, args);
|
||||
return M().mk_app(get_fid(), mul_decl_kind(), num_args, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,9 +189,9 @@ br_status poly_rewriter<Config>::mk_flat_mul_core(unsigned num_args, expr * cons
|
|||
br_status st = mk_nflat_mul_core(flat_args.size(), flat_args.data(), result);
|
||||
TRACE("poly_rewriter",
|
||||
tout << "flat mul:\n";
|
||||
for (unsigned i = 0; i < num_args; i++) tout << mk_bounded_pp(args[i], m()) << "\n";
|
||||
for (unsigned i = 0; i < num_args; i++) tout << mk_bounded_pp(args[i], M()) << "\n";
|
||||
tout << "---->\n";
|
||||
for (unsigned i = 0; i < flat_args.size(); i++) tout << mk_bounded_pp(flat_args[i], m()) << "\n";
|
||||
for (unsigned i = 0; i < flat_args.size(); i++) tout << mk_bounded_pp(flat_args[i], M()) << "\n";
|
||||
tout << st << "\n";
|
||||
);
|
||||
if (st == BR_FAILED) {
|
||||
|
@ -292,7 +292,7 @@ br_status poly_rewriter<Config>::mk_nflat_mul_core(unsigned num_args, expr * con
|
|||
new_add_args.push_back(mk_mul_app(c, to_app(var)->get_arg(i)));
|
||||
}
|
||||
result = mk_add_app(new_add_args.size(), new_add_args.data());
|
||||
TRACE("mul_bug", tout << "result: " << mk_bounded_pp(result, m(),5) << "\n";);
|
||||
TRACE("mul_bug", tout << "result: " << mk_bounded_pp(result, M(), 5) << "\n";);
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
}
|
||||
|
@ -328,7 +328,7 @@ br_status poly_rewriter<Config>::mk_nflat_mul_core(unsigned num_args, expr * con
|
|||
for (unsigned i = 0; i < new_args.size(); i++) {
|
||||
if (i > 0)
|
||||
tout << (lt(new_args[i-1], new_args[i]) ? " < " : " !< ");
|
||||
tout << mk_ismt2_pp(new_args[i], m());
|
||||
tout << mk_ismt2_pp(new_args[i], M());
|
||||
}
|
||||
tout << "\nordered: " << ordered << "\n";);
|
||||
if (ordered && num_coeffs == 0 && !use_power())
|
||||
|
@ -340,7 +340,7 @@ br_status poly_rewriter<Config>::mk_nflat_mul_core(unsigned num_args, expr * con
|
|||
for (unsigned i = 0; i < new_args.size(); i++) {
|
||||
if (i > 0)
|
||||
tout << (lt(new_args[i-1], new_args[i]) ? " < " : " !< ");
|
||||
tout << mk_ismt2_pp(new_args[i], m());
|
||||
tout << mk_ismt2_pp(new_args[i], M());
|
||||
}
|
||||
tout << "\n";);
|
||||
}
|
||||
|
@ -349,8 +349,8 @@ br_status poly_rewriter<Config>::mk_nflat_mul_core(unsigned num_args, expr * con
|
|||
result = mk_mul_app(c, result);
|
||||
TRACE("poly_rewriter",
|
||||
for (unsigned i = 0; i < num_args; ++i)
|
||||
tout << mk_ismt2_pp(args[i], m()) << " ";
|
||||
tout << "\nmk_nflat_mul_core result:\n" << mk_ismt2_pp(result, m()) << "\n";);
|
||||
tout << mk_ismt2_pp(args[i], M()) << " ";
|
||||
tout << "\nmk_nflat_mul_core result:\n" << mk_ismt2_pp(result, M()) << "\n";);
|
||||
return BR_DONE;
|
||||
}
|
||||
|
||||
|
@ -373,9 +373,9 @@ br_status poly_rewriter<Config>::mk_nflat_mul_core(unsigned num_args, expr * con
|
|||
}
|
||||
}
|
||||
unsigned orig_size = sums.size();
|
||||
expr_ref_buffer sum(m()); // must be ref_buffer because we may throw an exception
|
||||
expr_ref_buffer sum(M()); // must be ref_buffer because we may throw an exception
|
||||
ptr_buffer<expr> m_args;
|
||||
TRACE("som", tout << "starting som...\n";);
|
||||
TRACE("som", tout << "starting soM()...\n";);
|
||||
do {
|
||||
TRACE("som", for (unsigned i = 0; i < it.size(); i++) tout << it[i] << " ";
|
||||
tout << "\n";);
|
||||
|
@ -566,7 +566,7 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con
|
|||
SASSERT(m_sort_sums || ordered);
|
||||
TRACE("rewriter",
|
||||
tout << "ordered: " << ordered << " sort sums: " << m_sort_sums << "\n";
|
||||
for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], m()) << "\n";);
|
||||
for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(args[i], M()) << "\n";);
|
||||
|
||||
if (has_multiple) {
|
||||
// expensive case
|
||||
|
@ -589,7 +589,7 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con
|
|||
coeffs.push_back(a);
|
||||
}
|
||||
}
|
||||
expr_ref_buffer new_args(m());
|
||||
expr_ref_buffer new_args(M());
|
||||
if (!c.is_zero()) {
|
||||
new_args.push_back(mk_numeral(c));
|
||||
}
|
||||
|
@ -639,7 +639,7 @@ br_status poly_rewriter<Config>::mk_nflat_add_core(unsigned num_args, expr * con
|
|||
if (num_coeffs == 1 && is_numeral(args[0], a) && !a.is_zero())
|
||||
return BR_FAILED;
|
||||
}
|
||||
expr_ref_buffer new_args(m());
|
||||
expr_ref_buffer new_args(M());
|
||||
if (!c.is_zero())
|
||||
new_args.push_back(mk_numeral(c));
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
|
@ -690,8 +690,8 @@ br_status poly_rewriter<Config>::mk_sub(unsigned num_args, expr * const * args,
|
|||
return BR_DONE;
|
||||
}
|
||||
set_curr_sort(args[0]->get_sort());
|
||||
expr_ref minus_one(mk_numeral(numeral(-1)), m());
|
||||
expr_ref_buffer new_args(m());
|
||||
expr_ref minus_one(mk_numeral(numeral(-1)), M());
|
||||
expr_ref_buffer new_args(M());
|
||||
new_args.push_back(args[0]);
|
||||
for (unsigned i = 1; i < num_args; i++) {
|
||||
if (is_zero(args[i])) continue;
|
||||
|
@ -984,11 +984,11 @@ bool poly_rewriter<Config>::hoist_ite(expr_ref& e) {
|
|||
return false;
|
||||
obj_hashtable<expr> shared;
|
||||
ptr_buffer<expr> adds;
|
||||
expr_ref_vector bs(m()), pinned(m());
|
||||
expr_ref_vector bs(M()), pinned(M());
|
||||
TO_BUFFER(is_add, adds, e);
|
||||
unsigned i = 0;
|
||||
for (expr* a : adds) {
|
||||
if (m().is_ite(a)) {
|
||||
if (M().is_ite(a)) {
|
||||
shared.reset();
|
||||
numeral g(0);
|
||||
if (hoist_ite(a, shared, g) && (is_nontrivial_gcd(g) || !shared.empty())) {
|
||||
|
@ -1026,7 +1026,7 @@ bool poly_rewriter<Config>::hoist_ite(expr_ref& e) {
|
|||
template<typename Config>
|
||||
bool poly_rewriter<Config>::hoist_ite(expr* a, obj_hashtable<expr>& shared, numeral& g) {
|
||||
expr* c = nullptr, *t = nullptr, *e = nullptr;
|
||||
if (m().is_ite(a, c, t, e)) {
|
||||
if (M().is_ite(a, c, t, e)) {
|
||||
return hoist_ite(t, shared, g) && hoist_ite(e, shared, g);
|
||||
}
|
||||
rational k, g1;
|
||||
|
@ -1064,8 +1064,8 @@ bool poly_rewriter<Config>::hoist_ite(expr* a, obj_hashtable<expr>& shared, nume
|
|||
template<typename Config>
|
||||
expr* poly_rewriter<Config>::apply_hoist(expr* a, numeral const& g, obj_hashtable<expr> const& shared) {
|
||||
expr* c = nullptr, *t = nullptr, *e = nullptr;
|
||||
if (m().is_ite(a, c, t, e)) {
|
||||
return m().mk_ite(c, apply_hoist(t, g, shared), apply_hoist(e, g, shared));
|
||||
if (M().is_ite(a, c, t, e)) {
|
||||
return M().mk_ite(c, apply_hoist(t, g, shared), apply_hoist(e, g, shared));
|
||||
}
|
||||
rational k;
|
||||
if (is_nontrivial_gcd(g) && is_int_numeral(a, k)) {
|
||||
|
|
|
@ -354,7 +354,7 @@ class seq_rewriter {
|
|||
|
||||
public:
|
||||
seq_rewriter(ast_manager & m, params_ref const & p = params_ref()):
|
||||
m_util(m), m_autil(m), m_br(m), m_re2aut(m), m_op_cache(m), m_es(m),
|
||||
m_util(m), m_autil(m), m_br(m, p), m_re2aut(m), m_op_cache(m), m_es(m),
|
||||
m_lhs(m), m_rhs(m), m_coalesce_chars(true) {
|
||||
}
|
||||
ast_manager & m() const { return m_util.get_manager(); }
|
||||
|
|
|
@ -125,36 +125,6 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
return num_steps > m_max_steps;
|
||||
}
|
||||
|
||||
// Return true if t is of the form
|
||||
// (= t #b0)
|
||||
// (= t #b1)
|
||||
// (= #b0 t)
|
||||
// (= #b1 t)
|
||||
bool is_eq_bit(expr * t, expr * & x, unsigned & val) {
|
||||
if (!m().is_eq(t))
|
||||
return false;
|
||||
expr * lhs = to_app(t)->get_arg(0);
|
||||
if (!m_bv_rw.is_bv(lhs))
|
||||
return false;
|
||||
if (m_bv_rw.get_bv_size(lhs) != 1)
|
||||
return false;
|
||||
expr * rhs = to_app(t)->get_arg(1);
|
||||
rational v;
|
||||
unsigned sz;
|
||||
if (m_bv_rw.is_numeral(lhs, v, sz)) {
|
||||
x = rhs;
|
||||
val = v.get_unsigned();
|
||||
SASSERT(val == 0 || val == 1);
|
||||
return true;
|
||||
}
|
||||
if (m_bv_rw.is_numeral(rhs, v, sz)) {
|
||||
x = lhs;
|
||||
val = v.get_unsigned();
|
||||
SASSERT(val == 0 || val == 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// (iff (= x bit1) A)
|
||||
// --->
|
||||
|
@ -162,11 +132,11 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
br_status apply_tamagotchi(expr * lhs, expr * rhs, expr_ref & result) {
|
||||
expr * x;
|
||||
unsigned val;
|
||||
if (is_eq_bit(lhs, x, val)) {
|
||||
if (m_bv_rw.is_eq_bit(lhs, x, val)) {
|
||||
result = m().mk_eq(x, m().mk_ite(rhs, m_bv_rw.mk_numeral(val, 1), m_bv_rw.mk_numeral(1-val, 1)));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
if (is_eq_bit(rhs, x, val)) {
|
||||
if (m_bv_rw.is_eq_bit(rhs, x, val)) {
|
||||
result = m().mk_eq(x, m().mk_ite(lhs, m_bv_rw.mk_numeral(val, 1), m_bv_rw.mk_numeral(1-val, 1)));
|
||||
return BR_REWRITE2;
|
||||
}
|
||||
|
@ -183,22 +153,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
if (k == OP_EQ) {
|
||||
// theory dispatch for =
|
||||
SASSERT(num == 2);
|
||||
family_id s_fid = args[0]->get_sort()->get_family_id();
|
||||
if (s_fid == m_a_rw.get_fid())
|
||||
st = m_a_rw.mk_eq_core(args[0], args[1], result);
|
||||
else if (s_fid == m_bv_rw.get_fid())
|
||||
st = m_bv_rw.mk_eq_core(args[0], args[1], result);
|
||||
else if (s_fid == m_dt_rw.get_fid())
|
||||
st = m_dt_rw.mk_eq_core(args[0], args[1], result);
|
||||
else if (s_fid == m_f_rw.get_fid())
|
||||
st = m_f_rw.mk_eq_core(args[0], args[1], result);
|
||||
else if (s_fid == m_ar_rw.get_fid())
|
||||
st = m_ar_rw.mk_eq_core(args[0], args[1], result);
|
||||
else if (s_fid == m_seq_rw.get_fid())
|
||||
st = m_seq_rw.mk_eq_core(args[0], args[1], result);
|
||||
if (st != BR_FAILED)
|
||||
return st;
|
||||
st = apply_tamagotchi(args[0], args[1], result);
|
||||
st = reduce_eq(args[0], args[1], result);
|
||||
if (st != BR_FAILED)
|
||||
return st;
|
||||
}
|
||||
|
@ -695,9 +650,38 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args) {
|
||||
expr_ref result(m());
|
||||
proof_ref pr(m());
|
||||
if (BR_FAILED == reduce_app(f, num_args, args, result, pr)) {
|
||||
if (BR_FAILED == reduce_app(f, num_args, args, result, pr))
|
||||
result = m().mk_app(f, num_args, args);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
br_status reduce_eq(expr* a, expr* b, expr_ref& result) {
|
||||
family_id s_fid = a->get_sort()->get_family_id();
|
||||
br_status st = BR_FAILED;
|
||||
if (s_fid == m_a_rw.get_fid())
|
||||
st = m_a_rw.mk_eq_core(a, b, result);
|
||||
else if (s_fid == m_bv_rw.get_fid())
|
||||
st = m_bv_rw.mk_eq_core(a, b, result);
|
||||
else if (s_fid == m_dt_rw.get_fid())
|
||||
st = m_dt_rw.mk_eq_core(a, b, result);
|
||||
else if (s_fid == m_f_rw.get_fid())
|
||||
st = m_f_rw.mk_eq_core(a, b, result);
|
||||
else if (s_fid == m_ar_rw.get_fid())
|
||||
st = m_ar_rw.mk_eq_core(a, b, result);
|
||||
else if (s_fid == m_seq_rw.get_fid())
|
||||
st = m_seq_rw.mk_eq_core(a, b, result);
|
||||
if (st != BR_FAILED)
|
||||
return st;
|
||||
return apply_tamagotchi(a, b, result);
|
||||
}
|
||||
|
||||
expr_ref mk_eq(expr* a, expr* b) {
|
||||
expr_ref result(m());
|
||||
br_status st = reduce_eq(a, b, result);
|
||||
if (BR_FAILED == st)
|
||||
st = m_b_rw.mk_eq_core(a, b, result);
|
||||
if (BR_FAILED == st)
|
||||
result = m().mk_eq(a, b);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -826,7 +810,6 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
result = elim_unused_vars(m(), q1, params_ref());
|
||||
|
||||
|
||||
TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << result << "\n";);
|
||||
|
||||
result_pr = nullptr;
|
||||
if (m().proofs_enabled()) {
|
||||
|
@ -835,6 +818,9 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
p2 = m().mk_elim_unused_vars(q1, result);
|
||||
result_pr = m().mk_transitivity(p1, p2);
|
||||
}
|
||||
|
||||
TRACE("reduce_quantifier", tout << "after elim_unused_vars:\n" << result << " " << result_pr << "\n" ;);
|
||||
|
||||
SASSERT(old_q->get_sort() == result->get_sort());
|
||||
return true;
|
||||
}
|
||||
|
@ -848,7 +834,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
|
|||
m_f_rw(m, p),
|
||||
m_dl_rw(m),
|
||||
m_pb_rw(m),
|
||||
m_seq_rw(m),
|
||||
m_seq_rw(m, p),
|
||||
m_char_rw(m),
|
||||
m_rec_rw(m),
|
||||
m_a_util(m),
|
||||
|
@ -895,6 +881,10 @@ struct th_rewriter::imp : public rewriter_tpl<th_rewriter_cfg> {
|
|||
return m_cfg.mk_app(f, sz, args);
|
||||
}
|
||||
|
||||
expr_ref mk_eq(expr* a, expr* b) {
|
||||
return m_cfg.mk_eq(a, b);
|
||||
}
|
||||
|
||||
void set_solver(expr_solver* solver) {
|
||||
m_cfg.m_seq_rw.set_solver(solver);
|
||||
}
|
||||
|
@ -922,6 +912,14 @@ void th_rewriter::get_param_descrs(param_descrs & r) {
|
|||
rewriter_params::collect_param_descrs(r);
|
||||
}
|
||||
|
||||
void th_rewriter::set_flat_and_or(bool f) {
|
||||
m_imp->cfg().m_b_rw.set_flat_and_or(f);
|
||||
}
|
||||
|
||||
void th_rewriter::set_order_eq(bool f) {
|
||||
m_imp->cfg().m_b_rw.set_order_eq(f);
|
||||
}
|
||||
|
||||
th_rewriter::~th_rewriter() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
@ -934,7 +932,6 @@ unsigned th_rewriter::get_num_steps() const {
|
|||
return m_imp->get_num_steps();
|
||||
}
|
||||
|
||||
|
||||
void th_rewriter::cleanup() {
|
||||
ast_manager & m = m_imp->m();
|
||||
m_imp->~imp();
|
||||
|
@ -984,6 +981,10 @@ expr_ref th_rewriter::mk_app(func_decl* f, unsigned num_args, expr* const* args)
|
|||
return m_imp->mk_app(f, num_args, args);
|
||||
}
|
||||
|
||||
expr_ref th_rewriter::mk_eq(expr* a, expr* b) {
|
||||
return m_imp->mk_eq(a, b);
|
||||
}
|
||||
|
||||
void th_rewriter::set_solver(expr_solver* solver) {
|
||||
m_imp->set_solver(solver);
|
||||
}
|
||||
|
|
|
@ -38,6 +38,10 @@ public:
|
|||
|
||||
void updt_params(params_ref const & p);
|
||||
static void get_param_descrs(param_descrs & r);
|
||||
|
||||
void set_flat_and_or(bool f);
|
||||
void set_order_eq(bool f);
|
||||
|
||||
unsigned get_cache_size() const;
|
||||
unsigned get_num_steps() const;
|
||||
|
||||
|
@ -47,6 +51,9 @@ public:
|
|||
expr_ref operator()(expr * n, unsigned num_bindings, expr * const * bindings);
|
||||
|
||||
expr_ref mk_app(func_decl* f, unsigned num_args, expr* const* args);
|
||||
expr_ref mk_app(func_decl* f, ptr_vector<expr> const& args) { return mk_app(f, args.size(), args.data()); }
|
||||
expr_ref mk_app(func_decl* f, expr_ref_vector const& args) { return mk_app(f, args.size(), args.data()); }
|
||||
expr_ref mk_eq(expr* a, expr* b);
|
||||
|
||||
bool reduce_quantifier(quantifier * old_q,
|
||||
expr * new_body,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue