3
0
Fork 0
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:
Jakob Rath 2023-02-01 16:28:57 +01:00
commit 20b5455d08
669 changed files with 26145 additions and 20652 deletions

View file

@ -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
)

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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); }
};

View file

@ -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);
}

View file

@ -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());

View file

@ -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)) {

View file

@ -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;

View 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

View file

@ -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;

View file

@ -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

View file

@ -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);

View 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);
}

View 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);

View file

@ -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);

View file

@ -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;

View file

@ -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;
}

View file

@ -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 {

View 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;
}

View 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);
};

View file

@ -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

View file

@ -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(); }

View file

@ -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);

View file

@ -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)) {

View file

@ -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(); }

View file

@ -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);
}

View file

@ -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,