z3-z3-4.13.0.src.qe.qe_array_plugin.cpp Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2015 Microsoft Corporation
--*/
#include "qe/qe.h"
#include "ast/array_decl_plugin.h"
#include "ast/rewriter/expr_safe_replace.h"
#include "ast/ast_pp.h"
#include "ast/arith_decl_plugin.h"
namespace qe {
// ---------------------
// arrays
class array_plugin : public qe_solver_plugin {
expr_safe_replace m_replace;
public:
array_plugin(i_solver_context& ctx, ast_manager& m) :
qe_solver_plugin(m, m.mk_family_id("array"), ctx),
m_replace(m)
{
}
void assign(contains_app& x, expr* fml, rational const& vl) override {
UNREACHABLE();
}
bool get_num_branches( contains_app& x, expr* fml, rational& num_branches) override {
return false;
}
void subst(contains_app& x, rational const& vl, expr_ref& fml, expr_ref* def) override {
UNREACHABLE();
}
bool solve(conj_enum& conjs, expr* fml) override {
conj_enum::iterator it = conjs.begin(), end = conjs.end();
for (; it != end; ++it) {
expr* e = *it;
if (m.is_eq(e) && solve_eq(to_app(e), fml)) {
return true;
}
}
expr_ref_vector eqs(m);
conjs.extract_equalities(eqs);
for (unsigned i = 0; i < eqs.size(); ++i) {
TRACE("qe_verbose",
tout << mk_pp(eqs[i].get(), m) << "\n";);
expr* e = eqs[i].get();
if (solve_eq_zero(e, fml)) {
return true;
}
}
return false;
}
bool is_uninterpreted(app* f) override {
return true;
}
private:
bool solve_eq(app* eq, expr* fml) {
SASSERT(m.is_eq(eq));
expr* arg1 = eq->get_arg(0);
expr* arg2 = eq->get_arg(1);
return solve_eq(arg1, arg2, fml) || solve_eq(arg2, arg1, fml);
}
bool solve_eq_zero(expr* e, expr* fml) {
arith_util arith(m);
if (arith.is_add(e)) {
app* a = to_app(e);
expr* e1, *e2;
unsigned sz = a->get_num_args();
expr_ref_vector args(m);
expr_ref lhs(m), rhs(m);
rational r;
args.append(sz, a->get_args());
for (unsigned i = 0; i < sz; ++i) {
expr_ref save(m);
save = lhs = args[i].get();
args[i] = arith.mk_numeral(rational(0), lhs->get_sort());
rhs = arith.mk_uminus(arith.mk_add(args.size(), args.data()));
if (arith.is_mul(lhs, e1, e2) &&
arith.is_numeral(e1, r) &&
r.is_minus_one()) {
lhs = to_app(e2);
rhs = arith.mk_uminus(rhs);
}
if (solve_eq(lhs, rhs, fml)) {
return true;
}
args[i] = save;
}
}
return false;
}
bool solve_eq(expr* lhs, expr* rhs, expr* fml) {
if (!is_app(lhs)) {
return false;
}
TRACE("qe_verbose",
tout << mk_pp(lhs, m) <<
" == " << mk_pp(rhs, m) << "\n";);
expr_ref tmp(m);
app* a = to_app(lhs);
//
// A = t, A not in t.
//
unsigned idx = 0;
if (m_ctx.is_var(a, idx) &&
!m_ctx.contains(idx)(rhs)) {
expr_ref result(fml, m);
m_replace.apply_substitution(a, rhs, result);
m_ctx.elim_var(idx, result, rhs);
return true;
}
if (solve_store(a, rhs, fml)) {
return true;
}
if (solve_select(a, rhs, fml)) {
return true;
}
return false;
}
bool solve_select2(app* lhs, expr* rhs, expr* fml) {
//
// (select (select A i) j) = t, A not in i, j, t
// A |-> (store B' j (store B i t)), where B, B' are fresh.
//
// TBD
return false;
}
bool solve_select(app* lhs, expr* rhs, expr* fml) {
//
// (select A i) = t, A not in i, v, t
// A |-> (store B i t), where B is fresh.
//
unsigned idx = 0;
vector > args;
if (is_select(lhs, idx, rhs, args) && args.size() == 1) {
contains_app& contains_A = m_ctx.contains(idx);
app* A = contains_A.x();
app_ref B(m);
expr_ref store_B_i_t(m);
unsigned num_args = args[0].size();
B = m.mk_fresh_const("B", A->get_sort());
ptr_buffer args2;
args2.push_back(B);
for (unsigned i = 0; i < num_args; ++i) {
args2.push_back(args[0][i]);
}
args2.push_back(rhs);
store_B_i_t = m.mk_app(m_fid, OP_STORE, args2.size(), args2.data());
TRACE("qe",
tout << "fml: " << mk_pp(fml, m) << "\n";
tout << "solved form: " << mk_pp(store_B_i_t, m) << "\n";
tout << "eq: " << mk_pp(lhs, m) << " == " << mk_pp(rhs, m) << "\n";
);
expr_ref result(fml, m);
m_replace.apply_substitution(A, store_B_i_t, result);
m_ctx.add_var(B);
m_ctx.elim_var(idx, result, store_B_i_t);
return true;
}
return false;
}
bool is_array_app_of(app* a, unsigned& idx, expr* t, decl_kind k) {
if (!is_app_of(a, m_fid, k)) {
return false;
}
expr* v = a->get_arg(0);
if (!m_ctx.is_var(v, idx)) {
return false;
}
contains_app& contains_v = m_ctx.contains(idx);
for (unsigned i = 1; i < a->get_num_args(); ++i) {
if (contains_v(a->get_arg(i))) {
return false;
}
}
if (contains_v(t)) {
return false;
}
return true;
}
bool solve_store(app* lhs, expr* rhs, expr* fml) {
//
// store(store(A, j, u), i, v) = t, A not in i, j, u, v, t
// ->
// A |-> store(store(t, i, w), j, w') where w, w' are fresh.
// t[i] = v
// store(t, i, v)[j] = u
//
unsigned idx = 0;
vector > args;
if (is_store_update(lhs, idx, rhs, args)) {
contains_app& contains_A = m_ctx.contains(idx);
app* A = contains_A.x();
app_ref w(m);
expr_ref store_t(rhs, m), store_T(rhs, m), select_t(m);
ptr_vector args2;
for (unsigned i = args.size(); i > 0; ) {
--i;
args2.reset();
w = m.mk_fresh_const("w", args[i].back()->get_sort());
args2.push_back(store_T);
args2.append(args[i]);
select_t = m.mk_app(m_fid, OP_SELECT, args2.size()-1, args2.data());
fml = m.mk_and(fml, m.mk_eq(select_t, args2.back()));
store_T = m.mk_app(m_fid, OP_STORE, args2.size(), args2.data());
args2[0] = store_t;
args2.back() = w;
store_t = m.mk_app(m_fid, OP_STORE, args2.size(), args2.data());
m_ctx.add_var(w);
}
TRACE("qe",
tout << "Variable: " << mk_pp(A, m) << "\n";
tout << "fml: " << mk_pp(fml, m) << "\n";
tout << "solved form: " << mk_pp(store_t, m) << "\n";
tout << "eq: " << mk_pp(lhs, m) << " == " << mk_pp(rhs, m) << "\n";
);
expr_ref result(fml, m);
m_replace.apply_substitution(A, store_t, result);
m_ctx.elim_var(idx, result, store_t);
return true;
}
return false;
}
bool is_array_app_of(app* a, unsigned& idx, expr* t, decl_kind k, vector >& args) {
if (m_ctx.is_var(a, idx)) {
contains_app& contains_v = m_ctx.contains(idx);
if (args.empty() || contains_v(t))
return false;
for (auto const& vs : args)
for (auto v : vs)
if (contains_v(v))
return false;
return true;
}
if (!is_app_of(a, m_fid, k))
return false;
args.push_back(ptr_vector());
for (unsigned i = 1; i < a->get_num_args(); ++i) {
args.back().push_back(a->get_arg(i));
}
if (!is_app(a->get_arg(0))) {
return false;
}
return is_array_app_of(to_app(a->get_arg(0)), idx, t, k, args);
}
bool is_store_update(app* a, unsigned& idx, expr* t, vector >& args) {
return is_array_app_of(a, idx, t, OP_STORE, args);
}
bool is_select(app* a, unsigned& idx, expr* t, vector >& args) {
return is_array_app_of(a, idx, t, OP_SELECT, args);
}
};
qe_solver_plugin* mk_array_plugin(i_solver_context& ctx) {
return alloc(array_plugin, ctx, ctx.get_manager());
}
}