#include "ast/ast_pp.h"
#include "ast/ast_ll_pp.h"
#include "ast/ast_util.h"
#include "ast/arith_decl_plugin.h"
#include "ast/seq_decl_plugin.h"
#include "ast/pb_decl_plugin.h"
#include "ast/rewriter/seq_rewriter.h"
#include "ast/converters/expr_inverter.h"
class basic_expr_inverter : public iexpr_inverter {
iexpr_inverter& inv;
bool process_eq(func_decl* f, expr* arg1, expr* arg2, expr_ref& r) {
expr* v;
expr* t;
if (uncnstr(arg1))
v = arg1, t = arg2;
else if (uncnstr(arg2))
v = arg2, t = arg1;
else
return false;
expr_ref d(m);
if (!inv.mk_diff(t, d))
return false;
mk_fresh_uncnstr_var_for(f, r);
if (m_mc)
add_def(v, m.mk_ite(r, t, d));
return true;
}
public:
basic_expr_inverter(ast_manager& m, iexpr_inverter& inv) : iexpr_inverter(m), inv(inv) {}
family_id get_fid() const override { return m.get_basic_family_id(); }
bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r) override {
SASSERT(f->get_family_id() == m.get_basic_family_id());
switch (f->get_decl_kind()) {
case OP_ITE:
SASSERT(num == 3);
if (uncnstr(args[1]) && uncnstr(args[2])) {
mk_fresh_uncnstr_var_for(f, r);
add_def(args[1], r);
add_def(args[2], r);
return true;
}
if (uncnstr(args[0]) && uncnstr(args[1])) {
mk_fresh_uncnstr_var_for(f, r);
add_def(args[0], m.mk_true());
add_def(args[1], r);
return true;
}
if (uncnstr(args[0]) && uncnstr(args[2])) {
mk_fresh_uncnstr_var_for(f, r);
add_def(args[0], m.mk_false());
add_def(args[2], r);
return true;
}
return false;
case OP_NOT:
SASSERT(num == 1);
if (uncnstr(args[0])) {
mk_fresh_uncnstr_var_for(f, r);
add_def(args[0], m.mk_not(r));
return true;
}
return false;
case OP_AND:
if (num > 0 && uncnstr(num, args)) {
mk_fresh_uncnstr_var_for(f, r);
add_defs(num, args, r, m.mk_true());
return true;
}
return false;
case OP_OR:
if (num > 0 && uncnstr(num, args)) {
mk_fresh_uncnstr_var_for(f, r);
add_defs(num, args, r, m.mk_false());
return true;
}
return false;
case OP_EQ:
SASSERT(num == 2);
return process_eq(f, args[0], args[1], r);
default:
return false;
}
return false;
}
bool mk_diff(expr* t, expr_ref& r) override {
SASSERT(m.is_bool(t));
r = mk_not(m, t);
return true;
}
};
class arith_expr_inverter : public iexpr_inverter {
arith_util a;
public:
arith_expr_inverter(ast_manager& m) : iexpr_inverter(m), a(m) {}
family_id get_fid() const override { return a.get_family_id(); }
bool process_le_ge(func_decl* f, expr* arg1, expr* arg2, bool le, expr_ref& r) {
expr* v;
expr* t;
if (uncnstr(arg1)) {
v = arg1;
t = arg2;
}
else if (uncnstr(arg2)) {
v = arg2;
t = arg1;
le = !le;
}
else
return false;
mk_fresh_uncnstr_var_for(f, r);
if (m_mc) {
add_def(v, m.mk_ite(r, t, a.mk_add(t, a.mk_numeral(rational(le ? 1 : -1), arg1->get_sort()))));
}
return true;
}
bool process_add(unsigned num, expr* const* args, expr_ref& u) {
if (num == 0)
return false;
unsigned i;
expr* v = nullptr;
for (i = 0; i < num; ++i) {
expr* arg = args[i];
if (uncnstr(arg)) {
v = arg;
break;
}
}
if (v == nullptr)
return false;
mk_fresh_uncnstr_var_for(v->get_sort(), u);
if (!m_mc)
return true;
ptr_buffer<expr> new_args;
for (unsigned j = 0; j < num; ++j)
if (j != i)
new_args.push_back(args[j]);
if (new_args.empty())
add_def(v, u);
else {
expr* rest = a.mk_add(new_args);
add_def(v, a.mk_sub(u, rest));
}
return true;
}
bool process_arith_mul(unsigned num, expr* const* args, expr_ref & u) {
if (num == 0)
return false;
sort* s = args[0]->get_sort();
if (uncnstr(num, args)) {
mk_fresh_uncnstr_var_for(s, u);
if (m_mc)
add_defs(num, args, u, a.mk_numeral(rational(1), s));
return true;
}
bool is_int;
rational val;
if (num == 2 && uncnstr(args[1]) && a.is_numeral(args[0], val, is_int) && !is_int) {
if (val.is_zero())
return false;
mk_fresh_uncnstr_var_for(s, u);
if (m_mc) {
val = rational(1) / val;
add_def(args[1], a.mk_mul(a.mk_numeral(val, false), u));
}
return true;
}
return false;
}
bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r) override {
SASSERT(f->get_family_id() == a.get_family_id());
switch (f->get_decl_kind()) {
case OP_ADD:
return process_add(num, args, r);
case OP_MUL:
return process_arith_mul(num, args, r);
case OP_LE:
SASSERT(num == 2);
return process_le_ge(f, args[0], args[1], true, r);
case OP_GE:
SASSERT(num == 2);
return process_le_ge(f, args[0], args[1], false, r);
default:
return false;
}
}
bool mk_diff(expr* t, expr_ref& r) override {
SASSERT(a.is_int_real(t));
r = a.mk_add(t, a.mk_numeral(rational(1), a.is_int(t)));
return true;
}
};
class bv_expr_inverter : public iexpr_inverter {
bv_util bv;
bool process_add(unsigned num, expr* const* args, expr_ref& u) {
if (num == 0)
return false;
unsigned i;
expr* v = nullptr;
for (i = 0; i < num; ++i) {
expr* arg = args[i];
if (uncnstr(arg)) {
v = arg;
break;
}
}
if (!v)
return false;
mk_fresh_uncnstr_var_for(v->get_sort(), u);
if (!m_mc)
return true;
ptr_buffer<expr> new_args;
for (unsigned j = 0; j < num; ++j)
if (j != i)
new_args.push_back(args[j]);
if (new_args.empty())
add_def(v, u);
else {
expr* rest = bv.mk_bv_add(new_args);
add_def(v, bv.mk_bv_sub(u, rest));
}
return true;
}
bool process_bv_mul(func_decl* f, unsigned num, expr* const* args, expr_ref& r) {
if (num == 0)
return false;
if (uncnstr(num, args)) {
sort* s = args[0]->get_sort();
mk_fresh_uncnstr_var_for(f, r);
if (m_mc)
add_defs(num, args, r, bv.mk_one(s));
return true;
}
unsigned sz;
rational val;
rational inv;
if (num == 2 &&
uncnstr(args[1]) &&
bv.is_numeral(args[0], val, sz) &&
val.mult_inverse(sz, inv)) {
mk_fresh_uncnstr_var_for(f, r);
if (m_mc)
add_def(args[1], bv.mk_bv_mul(bv.mk_numeral(inv, sz), r));
return true;
}
if (num == 2 &&
uncnstr(args[1]) &&
bv.is_numeral(args[0], val, sz) &&
val.is_pos()) {
unsigned sh = 0;
while (val.is_even()) {
val /= rational(2);
++sh;
}
mk_fresh_uncnstr_var_for(f, r);
if (sh > 0)
r = bv.mk_concat(bv.mk_extract(sz - sh - 1, 0, r), bv.mk_zero(sh));
if (m_mc) {
rational inv_r;
VERIFY(val.mult_inverse(sz, inv_r));
add_def(args[1], bv.mk_bv_mul(bv.mk_numeral(inv_r, sz), r));
}
return true;
}
#if 0#endif
return false;
}
bool process_extract(func_decl* f, expr* arg, expr_ref& r) {
if (!uncnstr(arg))
return false;
mk_fresh_uncnstr_var_for(f, r);
if (!m_mc)
return true;
unsigned high = bv.get_extract_high(f);
unsigned low = bv.get_extract_low(f);
unsigned bv_size = bv.get_bv_size(arg->get_sort());
if (bv_size == high - low + 1)
add_def(arg, r);
else {
ptr_buffer<expr> args;
if (high < bv_size - 1)
args.push_back(bv.mk_zero(bv_size - high - 1));
args.push_back(r);
if (low > 0)
args.push_back(bv.mk_zero(low));
add_def(arg, bv.mk_concat(args.size(), args.data()));
}
return true;
}
bool process_bv_div(func_decl* f, expr* arg1, expr* arg2, expr_ref& r) {
if (uncnstr(arg1) && uncnstr(arg2)) {
sort* s = arg1->get_sort();
mk_fresh_uncnstr_var_for(f, r);
if (m_mc) {
add_def(arg1, r);
add_def(arg2, bv.mk_one(s));
}
return true;
}
return false;
}
bool process_concat(func_decl* f, unsigned num, expr* const* args, expr_ref& r) {
if (num == 0)
return false;
if (!uncnstr(num, args))
return false;
mk_fresh_uncnstr_var_for(f, r);
if (m_mc) {
unsigned i = num;
unsigned low = 0;
while (i > 0) {
--i;
expr* arg = args[i];
unsigned sz = bv.get_bv_size(arg);
add_def(arg, bv.mk_extract(low + sz - 1, low, r));
low += sz;
}
}
return true;
}
bool process_bv_le(func_decl* f, expr* arg1, expr* arg2, bool is_signed, expr_ref& r) {
unsigned bv_sz = bv.get_bv_size(arg1);
if (uncnstr(arg1) && uncnstr(arg2)) {
mk_fresh_uncnstr_var_for(f, r);
if (m_mc) {
add_def(arg1, m.mk_ite(r, bv.mk_zero(bv_sz), bv.mk_one(bv_sz)));
add_def(arg2, bv.mk_zero(bv_sz));
}
return true;
}
if (uncnstr(arg1)) {
expr* v = arg1;
expr* t = arg2;
rational MAX;
if (is_signed)
MAX = rational::power_of_two(bv_sz - 1) - rational(1);
else
MAX = rational::power_of_two(bv_sz) - rational(1);
mk_fresh_uncnstr_var_for(f, r);
r = m.mk_or(r, m.mk_eq(t, bv.mk_numeral(MAX, bv_sz)));
if (m_mc)
add_def(v, m.mk_ite(r, t, bv.mk_bv_add(t, bv.mk_one(bv_sz))));
return true;
}
if (uncnstr(arg2)) {
expr* v = arg2;
expr* t = arg1;
rational MIN;
if (is_signed)
MIN = -rational::power_of_two(bv_sz - 1);
else
MIN = rational(0);
mk_fresh_uncnstr_var_for(f, r);
r = m.mk_or(r, m.mk_eq(t, bv.mk_numeral(MIN, bv_sz)));
if (m_mc)
add_def(v, m.mk_ite(r, t, bv.mk_bv_sub(t, bv.mk_one(bv_sz))));
return true;
}
return false;
}
bool process_bvnot(expr* e, expr_ref& r) {
if (!uncnstr(e))
return false;
mk_fresh_uncnstr_var_for(e->get_sort(), r);
if (m_mc)
add_def(e, bv.mk_bv_not(r));
return true;
}
bool process_shift(func_decl* f, expr* arg1, expr* arg2, expr_ref& r) {
if (uncnstr(arg1) && uncnstr(arg2)) {
mk_fresh_uncnstr_var_for(f, r);
if (m_mc) {
add_def(arg1, r);
add_def(arg2, bv.mk_zero(arg2->get_sort()));
}
return true;
}
return false;
}
public:
bv_expr_inverter(ast_manager& m) : iexpr_inverter(m), bv(m) {}
family_id get_fid() const override { return bv.get_family_id(); }
bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r) override {
SASSERT(f->get_family_id() == bv.get_family_id());
switch (f->get_decl_kind()) {
case OP_BADD:
return process_add(num, args, r);
case OP_BMUL:
return process_bv_mul(f, num, args, r);
case OP_BSDIV:
case OP_BUDIV:
case OP_BSDIV_I:
case OP_BUDIV_I:
SASSERT(num == 2);
return process_bv_div(f, args[0], args[1], r);
case OP_SLEQ:
SASSERT(num == 2);
return process_bv_le(f, args[0], args[1], true, r);
case OP_ULEQ:
SASSERT(num == 2);
return process_bv_le(f, args[0], args[1], false, r);
case OP_CONCAT:
return process_concat(f, num, args, r);
case OP_EXTRACT:
SASSERT(num == 1);
return process_extract(f, args[0], r);
case OP_BNOT:
SASSERT(num == 1);
return process_bvnot(args[0], r);
case OP_BOR:
if (num > 0 && uncnstr(num, args)) {
sort* s = args[0]->get_sort();
mk_fresh_uncnstr_var_for(f, r);
if (m_mc)
add_defs(num, args, r, bv.mk_zero(s));
return true;
}
return false;
case OP_BAND:
if (num > 0 && uncnstr(num, args)) {
sort* s = args[0]->get_sort();
mk_fresh_uncnstr_var_for(f, r);
if (m_mc)
add_defs(num, args, r, bv.mk_numeral(rational::power_of_two(bv.get_bv_size(s)) - 1, s));
return true;
}
return false;
case OP_BSHL:
case OP_BASHR:
case OP_BLSHR:
return process_shift(f, args[0], args[1], r);
default:
return false;
}
}
bool mk_diff(expr* t, expr_ref& r) override {
SASSERT(bv.is_bv(t));
r = bv.mk_bv_not(t);
return true;
}
};
class array_expr_inverter : public iexpr_inverter {
array_util a;
iexpr_inverter& inv;
public:
array_expr_inverter(ast_manager& m, iexpr_inverter& s) : iexpr_inverter(m), a(m), inv(s) {}
family_id get_fid() const override { return a.get_family_id(); }
bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r) override {
SASSERT(f->get_family_id() == a.get_family_id());
switch (f->get_decl_kind()) {
case OP_SELECT:
if (uncnstr(args[0])) {
mk_fresh_uncnstr_var_for(f, r);
sort* s = args[0]->get_sort();
if (m_mc)
add_def(args[0], a.mk_const_array(s, r));
return true;
}
return false;
case OP_STORE:
if (uncnstr(args[0]) && uncnstr(args[num - 1])) {
mk_fresh_uncnstr_var_for(f, r);
if (m_mc) {
add_def(args[num - 1], m.mk_app(a.get_family_id(), OP_SELECT, num - 1, args));
add_def(args[0], r);
}
return true;
}
return false;
default:
return false;
}
}
bool mk_diff(expr* t, expr_ref& r) override {
sort* s = t->get_sort();
SASSERT(a.is_array(s));
if (m.is_uninterp(get_array_range(s)))
return false;
unsigned arity = get_array_arity(s);
for (unsigned i = 0; i < arity; ++i)
if (m.is_uninterp(get_array_domain(s, i)))
return false;
expr_ref_vector new_args(m);
new_args.push_back(t);
for (unsigned i = 0; i < arity; ++i)
new_args.push_back(m.get_some_value(get_array_domain(s, i)));
expr_ref sel(m);
sel = a.mk_select(new_args);
expr_ref diff_sel(m);
if (!inv.mk_diff(sel, diff_sel))
return false;
new_args.push_back(diff_sel);
r = a.mk_store(new_args);
return true;
}
};
class dt_expr_inverter : public iexpr_inverter {
datatype_util dt;
public:
dt_expr_inverter(ast_manager& m) : iexpr_inverter(m), dt(m) {}
family_id get_fid() const override { return dt.get_family_id(); }
bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r) override {
if (dt.is_accessor(f)) {
SASSERT(num == 1);
if (uncnstr(args[0])) {
if (!m_mc) {
mk_fresh_uncnstr_var_for(f, r);
return true;
}
func_decl* c = dt.get_accessor_constructor(f);
for (unsigned i = 0; i < c->get_arity(); ++i)
if (!m.is_fully_interp(c->get_domain(i)))
return false;
mk_fresh_uncnstr_var_for(f, r);
ptr_vector<func_decl> const& accs = *dt.get_constructor_accessors(c);
ptr_buffer<expr> new_args;
for (unsigned i = 0; i < accs.size(); ++i) {
if (accs[i] == f)
new_args.push_back(r);
else
new_args.push_back(m.get_some_value(c->get_domain(i)));
}
add_def(args[0], m.mk_app(c, new_args));
return true;
}
}
return false;
}
bool mk_diff(expr* t, expr_ref& r) override {
sort* s = t->get_sort();
ptr_vector<func_decl> const& constructors = *dt.get_datatype_constructors(s);
for (func_decl* constructor : constructors) {
unsigned num = constructor->get_arity();
unsigned target = UINT_MAX;
for (unsigned i = 0; i < num; ++i) {
sort* s_arg = constructor->get_domain(i);
if (s == s_arg) {
target = i;
continue;
}
if (m.is_uninterp(s_arg))
break;
}
if (target == UINT_MAX)
continue;
ptr_buffer<expr> new_args;
for (unsigned i = 0; i < num; ++i) {
if (i == target)
new_args.push_back(t);
else
new_args.push_back(m.get_some_value(constructor->get_domain(i)));
}
r = m.mk_app(constructor, new_args);
return true;
}
return false;
}
};
#if 0#endif
class seq_expr_inverter : public iexpr_inverter {
seq_util seq;
seq_rewriter rw;
public:
seq_expr_inverter(ast_manager& m) : iexpr_inverter(m), seq(m), rw(m) {}
family_id get_fid() const override { return seq.get_family_id(); }
bool operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& r) override {
switch (f->get_decl_kind()) {
case _OP_STRING_CONCAT:
case OP_SEQ_CONCAT: {
expr* x, *y;
if (uncnstr(args[0]) && num == 2 &&
args[1]->get_ref_count() == 1 &&
seq.str.is_concat(args[1], x, y) &&
uncnstr(x)) {
mk_fresh_uncnstr_var_for(f, r);
if (m_mc) {
add_def(args[0], seq.str.mk_empty(args[0]->get_sort()));
add_def(x, r);
}
r = seq.str.mk_concat(r, y);
return true;
}
if (!uncnstr(num, args))
return false;
mk_fresh_uncnstr_var_for(f, r);
if (m_mc) {
add_def(args[0], r);
for (unsigned i = 1; i < num; ++i)
add_def(args[i], seq.str.mk_empty(args[0]->get_sort()));
}
return true;
}
case OP_SEQ_CONTAINS:
if (uncnstr(args[0])) {
mk_fresh_uncnstr_var_for(f, r);
expr_ref emp(seq.str.mk_is_empty(args[0]), m);
if (m_mc)
add_def(args[0], m.mk_ite(r, args[1], seq.str.mk_empty(args[0]->get_sort())));
r = m.mk_or(r, emp);
return true;
}
if (uncnstr(args[1]) && seq.is_string(args[0]->get_sort())) {
mk_fresh_uncnstr_var_for(f, r);
if (m_mc)
add_def(args[1], m.mk_ite(r, args[0], seq.str.mk_concat(args[0], args[0], seq.str.mk_string(zstring("a")))));
return true;
}
return false;
case OP_SEQ_IN_RE:
if (uncnstr(args[0]) && seq.re.is_ground(args[1]) && seq.is_string(args[0]->get_sort())) {
zstring s1;
expr* re = args[1];
if (l_true != rw.some_string_in_re(re, s1))
return false;
zstring s2;
expr_ref not_re(seq.re.mk_complement(re), m);
if (l_true != rw.some_string_in_re(not_re, s2))
return false;
mk_fresh_uncnstr_var_for(f, r);
expr_ref witness1 = expr_ref(seq.str.mk_string(s1), m);
expr_ref witness2 = expr_ref(seq.str.mk_string(s2), m);
if (m_mc)
add_def(args[0], m.mk_ite(r, witness1, witness2));
return true;
}
return false;
default:
verbose_stream() << mk_pp(f, m) << "\n";
return false;
}
}
bool mk_diff(expr* t, expr_ref& r) override {
if (seq.is_string(t->get_sort())) {
r = seq.str.mk_concat(t, seq.str.mk_string(zstring("a")));
return true;
}
return false;
}
};
expr_inverter::~expr_inverter() {
for (auto* v : m_inverters)
dealloc(v);
}
bool iexpr_inverter::uncnstr(unsigned num, expr * const * args) const {
for (unsigned i = 0; i < num; ++i)
if (!m_is_var(args[i]))
return false;
return true;
}
void iexpr_inverter::mk_fresh_uncnstr_var_for(sort * s, expr_ref & v) {
v = m.mk_fresh_const(nullptr, s);
if (m_mc)
m_mc->hide(v);
}
void iexpr_inverter::add_def(expr * v, expr * def) {
expr_ref _v(v, m);
expr_ref _d(def, m);
if (!m_mc)
return;
SASSERT(uncnstr(v));
SASSERT(to_app(v)->get_num_args() == 0);
m_mc->add(v, def);
}
void iexpr_inverter::add_defs(unsigned num, expr* const* args, expr* u, expr* identity) {
expr_ref _id(identity, m);
if (!m_mc)
return;
add_def(args[0], u);
for (unsigned i = 1; i < num; ++i)
add_def(args[i], identity);
}
expr_inverter::expr_inverter(ast_manager& m): iexpr_inverter(m) {
auto add = [&](iexpr_inverter* i) {
m_inverters.setx(i->get_fid(), i, nullptr);
};
add(alloc(arith_expr_inverter, m));
add(alloc(bv_expr_inverter, m));
add(alloc(array_expr_inverter, m, *this));
add(alloc(dt_expr_inverter, m));
add(alloc(basic_expr_inverter, m, *this));
add(alloc(seq_expr_inverter, m));
}
bool expr_inverter::operator()(func_decl* f, unsigned num, expr* const* args, expr_ref& new_expr) {
if (num == 0)
return false;
for (unsigned i = 0; i < num; ++i)
if (!is_ground(args[i]))
return false;
family_id fid = f->get_family_id();
if (fid == null_family_id)
return false;
auto* p = m_inverters.get(fid, nullptr);
return p && (*p)(f, num, args, new_expr);
}
bool expr_inverter::mk_diff(expr* t, expr_ref& r) {
sort * s = t->get_sort();
if (!m.is_fully_interp(s))
return false;
sort_size sz = s->get_num_elements();
if (sz.is_finite() && sz.size() <= 1)
return false;
if (!m_mc) {
mk_fresh_uncnstr_var_for(s, r);
return true;
}
family_id fid = s->get_family_id();
auto* p = m_inverters.get(fid, nullptr);
return p && p->mk_diff(t, r);
}
void expr_inverter::set_is_var(std::function<bool(expr*)>& is_var) {
for (auto* p : m_inverters)
if (p)
p->set_is_var(is_var);
}
void expr_inverter::set_model_converter(generic_model_converter* mc) {
m_mc = mc;
for (auto* p : m_inverters)
if (p)
p->set_model_converter(mc);
}
void expr_inverter::set_produce_proofs(bool pr) {
m_produce_proofs = pr;
for (auto* p : m_inverters)
if (p)
p->set_produce_proofs(pr);
}