mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 04:03:39 +00:00
array solver fixes
This commit is contained in:
parent
78f4513441
commit
9a975a4523
|
@ -182,30 +182,31 @@ public:
|
||||||
|
|
||||||
bool is_as_array_tree(expr * n);
|
bool is_as_array_tree(expr * n);
|
||||||
|
|
||||||
app * mk_store(unsigned num_args, expr * const * args) {
|
app * mk_store(unsigned num_args, expr * const * args) const {
|
||||||
return m_manager.mk_app(m_fid, OP_STORE, 0, nullptr, num_args, args);
|
return m_manager.mk_app(m_fid, OP_STORE, 0, nullptr, num_args, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
app * mk_store(expr_ref_vector const& args) {
|
app * mk_store(expr_ref_vector const& args) const {
|
||||||
return mk_store(args.size(), args.c_ptr());
|
|
||||||
}
|
|
||||||
app * mk_store(ptr_vector<expr> const& args) {
|
|
||||||
return mk_store(args.size(), args.c_ptr());
|
return mk_store(args.size(), args.c_ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
app * mk_select(unsigned num_args, expr * const * args) {
|
app * mk_store(ptr_vector<expr> const& args) const {
|
||||||
|
return mk_store(args.size(), args.c_ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
app * mk_select(unsigned num_args, expr * const * args) const {
|
||||||
return m_manager.mk_app(m_fid, OP_SELECT, 0, nullptr, num_args, args);
|
return m_manager.mk_app(m_fid, OP_SELECT, 0, nullptr, num_args, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
app * mk_select(ptr_vector<expr> const& args) {
|
app * mk_select(ptr_vector<expr> const& args) const {
|
||||||
return mk_select(args.size(), args.c_ptr());
|
return mk_select(args.size(), args.c_ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
app * mk_select(ptr_buffer<expr> const& args) {
|
app * mk_select(ptr_buffer<expr> const& args) const {
|
||||||
return mk_select(args.size(), args.c_ptr());
|
return mk_select(args.size(), args.c_ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
app * mk_select(expr_ref_vector const& args) {
|
app * mk_select(expr_ref_vector const& args) const {
|
||||||
return mk_select(args.size(), args.c_ptr());
|
return mk_select(args.size(), args.c_ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ z3_add_component(sat_smt
|
||||||
arith_internalize.cpp
|
arith_internalize.cpp
|
||||||
arith_solver.cpp
|
arith_solver.cpp
|
||||||
array_axioms.cpp
|
array_axioms.cpp
|
||||||
|
array_diagnostics.cpp
|
||||||
array_internalize.cpp
|
array_internalize.cpp
|
||||||
array_model.cpp
|
array_model.cpp
|
||||||
array_solver.cpp
|
array_solver.cpp
|
||||||
|
|
|
@ -78,7 +78,7 @@ namespace arith {
|
||||||
}
|
}
|
||||||
|
|
||||||
// clone rows into m_solver, m_nla, m_lia
|
// clone rows into m_solver, m_nla, m_lia
|
||||||
NOT_IMPLEMENTED_YET();
|
// NOT_IMPLEMENTED_YET();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,22 +25,27 @@ namespace array {
|
||||||
void solver::push_axiom(axiom_record const& r) {
|
void solver::push_axiom(axiom_record const& r) {
|
||||||
unsigned idx = m_axiom_trail.size();
|
unsigned idx = m_axiom_trail.size();
|
||||||
m_axiom_trail.push_back(r);
|
m_axiom_trail.push_back(r);
|
||||||
|
TRACE("array", display(tout, r) << " " << m_axioms.contains(idx) << "\n";);
|
||||||
if (m_axioms.contains(idx))
|
if (m_axioms.contains(idx))
|
||||||
m_axiom_trail.pop_back();
|
m_axiom_trail.pop_back();
|
||||||
else
|
else
|
||||||
ctx.push(push_back_vector<svector<axiom_record>>(m_axiom_trail));
|
ctx.push(push_back_vector<svector<axiom_record>>(m_axiom_trail));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool solver::propagate_axiom(unsigned idx) {
|
bool solver::propagate_axiom(unsigned idx) {
|
||||||
if (m_axioms.contains(idx))
|
if (!m_axioms.contains(idx)) {
|
||||||
|
m_axioms.insert(idx);
|
||||||
|
ctx.push(insert_map<axiom_table_t, unsigned>(m_axioms, idx));
|
||||||
|
}
|
||||||
|
else if (!m_axiom_trail[idx].is_delayed())
|
||||||
return false;
|
return false;
|
||||||
m_axioms.insert(idx);
|
|
||||||
ctx.push(insert_map<axiom_table_t, unsigned>(m_axioms, idx));
|
|
||||||
return assert_axiom(idx);
|
return assert_axiom(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool solver::assert_axiom(unsigned idx) {
|
bool solver::assert_axiom(unsigned idx) {
|
||||||
axiom_record& r = m_axiom_trail[idx];
|
axiom_record& r = m_axiom_trail[idx];
|
||||||
|
if (!is_relevant(r))
|
||||||
|
return false;
|
||||||
switch (r.m_kind) {
|
switch (r.m_kind) {
|
||||||
case axiom_record::kind_t::is_store:
|
case axiom_record::kind_t::is_store:
|
||||||
return assert_store_axiom(to_app(r.n->get_expr()));
|
return assert_store_axiom(to_app(r.n->get_expr()));
|
||||||
|
@ -62,8 +67,7 @@ namespace array {
|
||||||
bool solver::assert_default(axiom_record& r) {
|
bool solver::assert_default(axiom_record& r) {
|
||||||
expr* child = r.n->get_expr();
|
expr* child = r.n->get_expr();
|
||||||
SASSERT(can_beta_reduce(r.n));
|
SASSERT(can_beta_reduce(r.n));
|
||||||
if (!ctx.is_relevant(child))
|
|
||||||
return false;
|
|
||||||
TRACE("array", tout << "default-axiom: " << mk_bounded_pp(child, m, 2) << "\n";);
|
TRACE("array", tout << "default-axiom: " << mk_bounded_pp(child, m, 2) << "\n";);
|
||||||
if (a.is_const(child))
|
if (a.is_const(child))
|
||||||
return assert_default_const_axiom(to_app(child));
|
return assert_default_const_axiom(to_app(child));
|
||||||
|
@ -79,30 +83,47 @@ namespace array {
|
||||||
solver& s;
|
solver& s;
|
||||||
unsigned m_idx;
|
unsigned m_idx;
|
||||||
set_delay_bit(solver& s, unsigned idx) : s(s), m_idx(idx) {}
|
set_delay_bit(solver& s, unsigned idx) : s(s), m_idx(idx) {}
|
||||||
void undo(/*euf::solver& euf*/) override {
|
void undo() override {
|
||||||
s.m_axiom_trail[m_idx].m_delayed = false;
|
s.m_axiom_trail[m_idx].m_delayed = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool solver::is_relevant(axiom_record const& r) const {
|
||||||
|
return true;
|
||||||
|
#if 0
|
||||||
|
// relevancy propagation is currently incomplete on terms
|
||||||
|
|
||||||
|
expr* child = r.n->get_expr();
|
||||||
|
switch (r.m_kind) {
|
||||||
|
case axiom_record::kind_t::is_select: {
|
||||||
|
app* select = r.select->get_app();
|
||||||
|
for (unsigned i = 1; i < select->get_num_args(); ++i)
|
||||||
|
if (!ctx.is_relevant(select->get_arg(i)))
|
||||||
|
return false;
|
||||||
|
return ctx.is_relevant(child);
|
||||||
|
}
|
||||||
|
case axiom_record::kind_t::is_default:
|
||||||
|
return ctx.is_relevant(child);
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool solver::assert_select(unsigned idx, axiom_record& r) {
|
bool solver::assert_select(unsigned idx, axiom_record& r) {
|
||||||
expr* child = r.n->get_expr();
|
expr* child = r.n->get_expr();
|
||||||
app* select = r.select->get_app();
|
app* select = r.select->get_app();
|
||||||
SASSERT(a.is_select(select));
|
SASSERT(a.is_select(select));
|
||||||
SASSERT(can_beta_reduce(r.n));
|
SASSERT(can_beta_reduce(r.n));
|
||||||
if (!ctx.is_relevant(child))
|
TRACE("array", display(tout << "select-axiom: ", r) << "\n";);
|
||||||
return false;
|
|
||||||
for (unsigned i = 1; i < select->get_num_args(); ++i)
|
if (get_config().m_array_delay_exp_axiom && r.select->get_arg(0)->get_root() != r.n->get_root() && !r.m_delayed && m_enable_delay) {
|
||||||
if (!ctx.is_relevant(select->get_arg(i)))
|
|
||||||
return false;
|
|
||||||
TRACE("array", tout << "select-axiom: " << mk_bounded_pp(select, m, 2) << " " << mk_bounded_pp(child, m, 2) << "\n";);
|
|
||||||
if (get_config().m_array_delay_exp_axiom && r.select->get_arg(0)->get_root() != r.n->get_root() && !r.m_delayed) {
|
|
||||||
IF_VERBOSE(11, verbose_stream() << "delay: " << mk_bounded_pp(child, m) << " " << mk_bounded_pp(select, m) << "\n");
|
IF_VERBOSE(11, verbose_stream() << "delay: " << mk_bounded_pp(child, m) << " " << mk_bounded_pp(select, m) << "\n");
|
||||||
ctx.push(set_delay_bit(*this, idx));
|
ctx.push(set_delay_bit(*this, idx));
|
||||||
r.m_delayed = true;
|
r.m_delayed = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (r.select->get_arg(0)->get_root() != r.n->get_root() && r.m_delayed)
|
r.m_delayed = false;
|
||||||
return false;
|
|
||||||
if (a.is_const(child))
|
if (a.is_const(child))
|
||||||
return assert_select_const_axiom(select, to_app(child));
|
return assert_select_const_axiom(select, to_app(child));
|
||||||
else if (a.is_as_array(child))
|
else if (a.is_as_array(child))
|
||||||
|
@ -163,8 +184,13 @@ namespace array {
|
||||||
expr_ref sel_eq_e(m.mk_eq(sel1, sel2), m);
|
expr_ref sel_eq_e(m.mk_eq(sel1, sel2), m);
|
||||||
euf::enode* s1 = e_internalize(sel1);
|
euf::enode* s1 = e_internalize(sel1);
|
||||||
euf::enode* s2 = e_internalize(sel2);
|
euf::enode* s2 = e_internalize(sel2);
|
||||||
|
TRACE("array",
|
||||||
|
tout << "select-store " << ctx.bpp(s1) << " " << ctx.bpp(s1->get_root()) << "\n";
|
||||||
|
tout << "select-store " << ctx.bpp(s2) << " " << ctx.bpp(s2->get_root()) << "\n";);
|
||||||
|
|
||||||
if (s1->get_root() == s2->get_root())
|
if (s1->get_root() == s2->get_root())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
sat::literal sel_eq = mk_literal(sel_eq_e);
|
sat::literal sel_eq = mk_literal(sel_eq_e);
|
||||||
if (s().value(sel_eq) == l_true)
|
if (s().value(sel_eq) == l_true)
|
||||||
return false;
|
return false;
|
||||||
|
@ -173,8 +199,8 @@ namespace array {
|
||||||
for (unsigned i = 1; i < num_args; i++) {
|
for (unsigned i = 1; i < num_args; i++) {
|
||||||
expr* idx1 = store->get_arg(i);
|
expr* idx1 = store->get_arg(i);
|
||||||
expr* idx2 = select->get_arg(i);
|
expr* idx2 = select->get_arg(i);
|
||||||
euf::enode* r1 = expr2enode(idx1)->get_root();
|
euf::enode* r1 = expr2enode(idx1);
|
||||||
euf::enode* r2 = expr2enode(idx2)->get_root();
|
euf::enode* r2 = expr2enode(idx2);
|
||||||
if (r1 == r2)
|
if (r1 == r2)
|
||||||
continue;
|
continue;
|
||||||
if (m.are_distinct(r1->get_expr(), r2->get_expr())) {
|
if (m.are_distinct(r1->get_expr(), r2->get_expr())) {
|
||||||
|
@ -186,6 +212,7 @@ namespace array {
|
||||||
if (add_clause(idx_eq, sel_eq))
|
if (add_clause(idx_eq, sel_eq))
|
||||||
new_prop = true;
|
new_prop = true;
|
||||||
}
|
}
|
||||||
|
TRACE("array", tout << "select-stored " << new_prop << "\n";);
|
||||||
return new_prop;
|
return new_prop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,9 +510,11 @@ namespace array {
|
||||||
bool change = false;
|
bool change = false;
|
||||||
unsigned sz = m_axiom_trail.size();
|
unsigned sz = m_axiom_trail.size();
|
||||||
m_delay_qhead = 0;
|
m_delay_qhead = 0;
|
||||||
|
|
||||||
for (; m_delay_qhead < sz; ++m_delay_qhead)
|
for (; m_delay_qhead < sz; ++m_delay_qhead)
|
||||||
if (m_axiom_trail[m_delay_qhead].m_delayed && assert_axiom(m_delay_qhead))
|
if (m_axiom_trail[m_delay_qhead].is_delayed() && assert_axiom(m_delay_qhead))
|
||||||
change = true;
|
change = true;
|
||||||
|
flet<bool> _enable_delay(m_enable_delay, false);
|
||||||
if (unit_propagate())
|
if (unit_propagate())
|
||||||
change = true;
|
change = true;
|
||||||
return change;
|
return change;
|
||||||
|
|
138
src/sat/smt/array_diagnostics.cpp
Normal file
138
src/sat/smt/array_diagnostics.cpp
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2020 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
array_diagnostics.cpp
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
Theory plugin for arrays, diagnostics functions
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
Nikolaj Bjorner (nbjorner) 2020-09-08
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "sat/smt/array_solver.h"
|
||||||
|
#include "sat/smt/euf_solver.h"
|
||||||
|
|
||||||
|
namespace array {
|
||||||
|
std::ostream& solver::display(std::ostream& out) const {
|
||||||
|
if (get_num_vars() > 0)
|
||||||
|
out << "array\n";
|
||||||
|
for (unsigned i = 0; i < get_num_vars(); ++i) {
|
||||||
|
auto& d = get_var_data(i);
|
||||||
|
out << var2enode(i)->get_expr_id() << " " << (d.m_prop_upward?"up":"fx") << " " << mk_bounded_pp(var2expr(i), m, 2) << "\n";
|
||||||
|
display_info(out, "parent lambdas", d.m_parent_lambdas);
|
||||||
|
display_info(out, "parent select", d.m_parent_selects);
|
||||||
|
display_info(out, "lambdas", d.m_lambdas);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& solver::display_info(std::ostream& out, char const* id, euf::enode_vector const& v) const {
|
||||||
|
if (v.empty())
|
||||||
|
return out;
|
||||||
|
out << id << ":\n";
|
||||||
|
for (euf::enode* p : v)
|
||||||
|
out << " " << ctx.bpp(p) << "\n";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream& solver::display(std::ostream& out, axiom_record const& r) const {
|
||||||
|
if (r.is_delayed())
|
||||||
|
out << "delay ";
|
||||||
|
switch (r.m_kind) {
|
||||||
|
case axiom_record::kind_t::is_store:
|
||||||
|
return out << "store " << ctx.bpp(r.n);
|
||||||
|
case axiom_record::kind_t::is_select:
|
||||||
|
return out << "select " << ctx.bpp(r.n) << " " << ctx.bpp(r.select);
|
||||||
|
case axiom_record::kind_t::is_default:
|
||||||
|
return out << "default " << ctx.bpp(r.n);
|
||||||
|
case axiom_record::kind_t::is_extensionality:
|
||||||
|
return out << "extensionality " << ctx.bpp(r.n) << " " << ctx.bpp(r.select);
|
||||||
|
case axiom_record::kind_t::is_congruence:
|
||||||
|
return out << "congruence " << ctx.bpp(r.n) << " " << ctx.bpp(r.select);
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::ostream& solver::display_justification(std::ostream& out, sat::ext_justification_idx idx) const { return out; }
|
||||||
|
std::ostream& solver::display_constraint(std::ostream& out, sat::ext_constraint_idx idx) const { return out; }
|
||||||
|
|
||||||
|
void solver::collect_statistics(statistics& st) const {
|
||||||
|
st.update("array store", m_stats.m_num_store_axiom);
|
||||||
|
st.update("array sel/store", m_stats.m_num_select_store_axiom);
|
||||||
|
st.update("array sel/const", m_stats.m_num_select_const_axiom);
|
||||||
|
st.update("array sel/map", m_stats.m_num_select_map_axiom);
|
||||||
|
st.update("array sel/as array", m_stats.m_num_select_as_array_axiom);
|
||||||
|
st.update("array sel/lambda", m_stats.m_num_select_lambda_axiom);
|
||||||
|
st.update("array def/map", m_stats.m_num_default_map_axiom);
|
||||||
|
st.update("array def/const", m_stats.m_num_default_const_axiom);
|
||||||
|
st.update("array def/store", m_stats.m_num_default_store_axiom);
|
||||||
|
st.update("array ext ax", m_stats.m_num_extensionality_axiom);
|
||||||
|
st.update("array cong ax", m_stats.m_num_congruence_axiom);
|
||||||
|
st.update("array exp ax2", m_stats.m_num_select_store_axiom_delayed);
|
||||||
|
st.update("array splits", m_stats.m_num_eq_splits);
|
||||||
|
}
|
||||||
|
|
||||||
|
void solver::validate_check() const {
|
||||||
|
for (euf::enode* n : ctx.get_egraph().nodes()) {
|
||||||
|
if (!ctx.is_relevant(n))
|
||||||
|
continue;
|
||||||
|
if (a.is_select(n->get_expr()) && a.is_store(n->get_arg(0)->get_expr()))
|
||||||
|
validate_select_store(n);
|
||||||
|
if (is_array(n) && n->is_root() && ctx.is_shared(n)) {
|
||||||
|
for (euf::enode* k : ctx.get_egraph().nodes())
|
||||||
|
if (k->get_expr_id() > n->get_expr_id() && k->is_root() && is_array(k) && ctx.is_shared(k))
|
||||||
|
validate_extensionality(n, k);
|
||||||
|
}
|
||||||
|
expr* x = nullptr, *y = nullptr;
|
||||||
|
if (m.is_eq(n->get_expr(), x, y) && a.is_array(x))
|
||||||
|
std::cout << ctx.bpp(n) << " " << s().value(n->bool_var()) << "\n";
|
||||||
|
if (m.is_eq(n->get_expr(), x, y) && a.is_array(x) && s().value(n->bool_var()) == l_false)
|
||||||
|
validate_extensionality(expr2enode(x), expr2enode(y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void solver::validate_select_store(euf::enode* n) const {
|
||||||
|
SASSERT(a.is_select(n->get_expr()));
|
||||||
|
SASSERT(a.is_store(n->get_arg(0)->get_expr()));
|
||||||
|
bool same_args = true;
|
||||||
|
for (unsigned i = 1; same_args && i < n->num_args(); ++i)
|
||||||
|
same_args = n->get_arg(i)->get_root() == n->get_arg(0)->get_arg(i)->get_root();
|
||||||
|
if (same_args) {
|
||||||
|
VERIFY(n->get_arg(0)->get_arg(n->num_args())->get_root() == n->get_root());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
euf::enode_vector args;
|
||||||
|
ptr_vector<expr> eargs;
|
||||||
|
args.push_back(n->get_arg(0)->get_arg(0));
|
||||||
|
for (unsigned i = 1; i < n->num_args(); ++i)
|
||||||
|
args.push_back(n->get_arg(i));
|
||||||
|
for (euf::enode* n : args)
|
||||||
|
eargs.push_back(n->get_expr());
|
||||||
|
expr_ref sel(a.mk_select(eargs.size(), eargs.c_ptr()), m);
|
||||||
|
euf::enode* n1 = ctx.get_egraph().find(sel, args.size(), args.c_ptr());
|
||||||
|
if (n1 && n1->get_root() == n->get_root())
|
||||||
|
return;
|
||||||
|
IF_VERBOSE(0,
|
||||||
|
verbose_stream() << ctx.bpp(n) << "\n";
|
||||||
|
verbose_stream() << sel << "\n";
|
||||||
|
verbose_stream() << n1 << " " << n->get_root() << "\n";);
|
||||||
|
}
|
||||||
|
|
||||||
|
void solver::validate_extensionality(euf::enode* s, euf::enode* t) const {
|
||||||
|
if (s->get_sort() != t->get_sort())
|
||||||
|
return;
|
||||||
|
IF_VERBOSE(0,
|
||||||
|
verbose_stream() << "extensionality " << ctx.bpp(s) << " " << ctx.bpp(t) << "\n";);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ Copyright (c) 2020 Microsoft Corporation
|
||||||
|
|
||||||
Module Name:
|
Module Name:
|
||||||
|
|
||||||
array_solver.h
|
array_solver.cpp
|
||||||
|
|
||||||
Abstract:
|
Abstract:
|
||||||
|
|
||||||
|
@ -101,6 +101,10 @@ namespace array {
|
||||||
else if (!turn[idx] && add_interface_equalities())
|
else if (!turn[idx] && add_interface_equalities())
|
||||||
return sat::check_result::CR_CONTINUE;
|
return sat::check_result::CR_CONTINUE;
|
||||||
}
|
}
|
||||||
|
if (m_delay_qhead < m_axiom_trail.size())
|
||||||
|
return sat::check_result::CR_CONTINUE;
|
||||||
|
|
||||||
|
// validate_check();
|
||||||
return sat::check_result::CR_DONE;
|
return sat::check_result::CR_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,48 +113,6 @@ namespace array {
|
||||||
m_var_data.resize(get_num_vars());
|
m_var_data.resize(get_num_vars());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& solver::display(std::ostream& out) const {
|
|
||||||
if (get_num_vars() > 0)
|
|
||||||
out << "array\n";
|
|
||||||
for (unsigned i = 0; i < get_num_vars(); ++i) {
|
|
||||||
auto& d = get_var_data(i);
|
|
||||||
out << var2enode(i)->get_expr_id() << " " << mk_bounded_pp(var2expr(i), m, 2) << "\n";
|
|
||||||
display_info(out, "parent lambdas", d.m_parent_lambdas);
|
|
||||||
display_info(out, "parent select", d.m_parent_selects);
|
|
||||||
display_info(out, "lambdas", d.m_lambdas);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& solver::display_info(std::ostream& out, char const* id, euf::enode_vector const& v) const {
|
|
||||||
if (v.empty())
|
|
||||||
return out;
|
|
||||||
out << id << ": ";
|
|
||||||
for (euf::enode* p : v)
|
|
||||||
out << mk_bounded_pp(p->get_expr(), m, 2) << " ";
|
|
||||||
out << "\n";
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& solver::display_justification(std::ostream& out, sat::ext_justification_idx idx) const { return out; }
|
|
||||||
std::ostream& solver::display_constraint(std::ostream& out, sat::ext_constraint_idx idx) const { return out; }
|
|
||||||
|
|
||||||
void solver::collect_statistics(statistics& st) const {
|
|
||||||
st.update("array store", m_stats.m_num_store_axiom);
|
|
||||||
st.update("array sel/store", m_stats.m_num_select_store_axiom);
|
|
||||||
st.update("array sel/const", m_stats.m_num_select_const_axiom);
|
|
||||||
st.update("array sel/map", m_stats.m_num_select_map_axiom);
|
|
||||||
st.update("array sel/as array", m_stats.m_num_select_as_array_axiom);
|
|
||||||
st.update("array sel/lambda", m_stats.m_num_select_lambda_axiom);
|
|
||||||
st.update("array def/map", m_stats.m_num_default_map_axiom);
|
|
||||||
st.update("array def/const", m_stats.m_num_default_const_axiom);
|
|
||||||
st.update("array def/store", m_stats.m_num_default_store_axiom);
|
|
||||||
st.update("array ext ax", m_stats.m_num_extensionality_axiom);
|
|
||||||
st.update("array cong ax", m_stats.m_num_congruence_axiom);
|
|
||||||
st.update("array exp ax2", m_stats.m_num_select_store_axiom_delayed);
|
|
||||||
st.update("array splits", m_stats.m_num_eq_splits);
|
|
||||||
}
|
|
||||||
|
|
||||||
euf::th_solver* solver::clone(euf::solver& dst_ctx) {
|
euf::th_solver* solver::clone(euf::solver& dst_ctx) {
|
||||||
auto* result = alloc(solver, dst_ctx, get_id());
|
auto* result = alloc(solver, dst_ctx, get_id());
|
||||||
for (unsigned i = 0; i < get_num_vars(); ++i)
|
for (unsigned i = 0; i < get_num_vars(); ++i)
|
||||||
|
@ -186,6 +148,7 @@ namespace array {
|
||||||
void solver::merge_eh(theory_var v1, theory_var v2, theory_var, theory_var) {
|
void solver::merge_eh(theory_var v1, theory_var v2, theory_var, theory_var) {
|
||||||
euf::enode* n1 = var2enode(v1);
|
euf::enode* n1 = var2enode(v1);
|
||||||
euf::enode* n2 = var2enode(v2);
|
euf::enode* n2 = var2enode(v2);
|
||||||
|
TRACE("array", tout << "merge: " << ctx.bpp(n1) << " == " << ctx.bpp(n2) << "\n";);
|
||||||
SASSERT(n1->get_root() == n2->get_root());
|
SASSERT(n1->get_root() == n2->get_root());
|
||||||
SASSERT(v1 == find(v1));
|
SASSERT(v1 == find(v1));
|
||||||
expr* e1 = n1->get_expr();
|
expr* e1 = n1->get_expr();
|
||||||
|
@ -207,11 +170,11 @@ namespace array {
|
||||||
void solver::add_parent_select(theory_var v_child, euf::enode* select) {
|
void solver::add_parent_select(theory_var v_child, euf::enode* select) {
|
||||||
SASSERT(a.is_select(select->get_expr()));
|
SASSERT(a.is_select(select->get_expr()));
|
||||||
SASSERT(select->get_arg(0)->get_sort() == var2expr(v_child)->get_sort());
|
SASSERT(select->get_arg(0)->get_sort() == var2expr(v_child)->get_sort());
|
||||||
|
|
||||||
v_child = find(v_child);
|
v_child = find(v_child);
|
||||||
ctx.push_vec(get_var_data(v_child).m_parent_selects, select);
|
ctx.push_vec(get_var_data(v_child).m_parent_selects, select);
|
||||||
euf::enode* child = var2enode(v_child);
|
euf::enode* child = var2enode(v_child);
|
||||||
if (can_beta_reduce(child) && child != select->get_arg(0))
|
TRACE("array", tout << "v" << v_child << " - " << ctx.bpp(select) << " " << ctx.bpp(child) << " prop: " << should_prop_upward(get_var_data(v_child)) << "\n";);
|
||||||
|
if (can_beta_reduce(child))
|
||||||
push_axiom(select_axiom(select, child));
|
push_axiom(select_axiom(select, child));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,7 +223,9 @@ namespace array {
|
||||||
expr* e = var2expr(v);
|
expr* e = var2expr(v);
|
||||||
if (!a.is_array(e))
|
if (!a.is_array(e))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto& d = get_var_data(v);
|
auto& d = get_var_data(v);
|
||||||
|
|
||||||
for (euf::enode* lambda : d.m_parent_lambdas)
|
for (euf::enode* lambda : d.m_parent_lambdas)
|
||||||
propagate_select_axioms(d, lambda);
|
propagate_select_axioms(d, lambda);
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,6 +96,8 @@ namespace array {
|
||||||
bool m_delayed { false };
|
bool m_delayed { false };
|
||||||
axiom_record(kind_t k, euf::enode* n, euf::enode* select = nullptr) : m_kind(k), n(n), select(select) {}
|
axiom_record(kind_t k, euf::enode* n, euf::enode* select = nullptr) : m_kind(k), n(n), select(select) {}
|
||||||
|
|
||||||
|
bool is_delayed() const { return m_delayed; }
|
||||||
|
|
||||||
struct hash {
|
struct hash {
|
||||||
solver& s;
|
solver& s;
|
||||||
hash(solver& s) :s(s) {}
|
hash(solver& s) :s(s) {}
|
||||||
|
@ -122,12 +124,14 @@ namespace array {
|
||||||
svector<axiom_record> m_axiom_trail;
|
svector<axiom_record> m_axiom_trail;
|
||||||
unsigned m_qhead { 0 };
|
unsigned m_qhead { 0 };
|
||||||
unsigned m_delay_qhead { 0 };
|
unsigned m_delay_qhead { 0 };
|
||||||
|
bool m_enable_delay { true };
|
||||||
struct set_delay_bit;
|
struct set_delay_bit;
|
||||||
void push_axiom(axiom_record const& r);
|
void push_axiom(axiom_record const& r);
|
||||||
bool propagate_axiom(unsigned idx);
|
bool propagate_axiom(unsigned idx);
|
||||||
bool assert_axiom(unsigned idx);
|
bool assert_axiom(unsigned idx);
|
||||||
bool assert_select(unsigned idx, axiom_record & r);
|
bool assert_select(unsigned idx, axiom_record & r);
|
||||||
bool assert_default(axiom_record & r);
|
bool assert_default(axiom_record & r);
|
||||||
|
bool is_relevant(axiom_record const& r) const;
|
||||||
|
|
||||||
axiom_record select_axiom(euf::enode* s, euf::enode* n) { return axiom_record(axiom_record::kind_t::is_select, n, s); }
|
axiom_record select_axiom(euf::enode* s, euf::enode* n) { return axiom_record(axiom_record::kind_t::is_select, n, s); }
|
||||||
axiom_record default_axiom(euf::enode* n) { return axiom_record(axiom_record::kind_t::is_default, n); }
|
axiom_record default_axiom(euf::enode* n) { return axiom_record(axiom_record::kind_t::is_default, n); }
|
||||||
|
@ -188,7 +192,11 @@ namespace array {
|
||||||
bool have_different_model_values(theory_var v1, theory_var v2);
|
bool have_different_model_values(theory_var v1, theory_var v2);
|
||||||
|
|
||||||
// diagnostics
|
// diagnostics
|
||||||
std::ostream& display_info(std::ostream& out, char const* id, euf::enode_vector const& v) const;
|
std::ostream& display_info(std::ostream& out, char const* id, euf::enode_vector const& v) const;
|
||||||
|
std::ostream& display(std::ostream& out, axiom_record const& r) const;
|
||||||
|
void validate_check() const;
|
||||||
|
void validate_select_store(euf::enode* n) const;
|
||||||
|
void validate_extensionality(euf::enode* s, euf::enode* t) const;
|
||||||
public:
|
public:
|
||||||
solver(euf::solver& ctx, theory_id id);
|
solver(euf::solver& ctx, theory_id id);
|
||||||
~solver() override;
|
~solver() override;
|
||||||
|
|
|
@ -236,13 +236,16 @@ namespace euf {
|
||||||
expr* e = n->get_expr();
|
expr* e = n->get_expr();
|
||||||
if (!m.is_bool(e))
|
if (!m.is_bool(e))
|
||||||
continue;
|
continue;
|
||||||
unsigned id = n->get_root_id();
|
if (!is_relevant(n))
|
||||||
if (!m_values.get(id))
|
|
||||||
continue;
|
continue;
|
||||||
bool tt = m.is_true(m_values.get(id));
|
bool tt = l_true == s().value(n->bool_var());
|
||||||
if (mdl.is_true(e) != tt) {
|
if (tt && mdl.is_false(e)) {
|
||||||
IF_VERBOSE(0, verbose_stream() << "Failed to evaluate " << id << " " << mk_bounded_pp(e, m) << " " << mdl(e) << " " << mk_bounded_pp(m_values.get(id), m) << "\n");
|
IF_VERBOSE(0, verbose_stream() << "Failed to validate " << bpp(n) << " " << mdl(e) << "\n");
|
||||||
|
for (auto* arg : euf::enode_args(n))
|
||||||
|
IF_VERBOSE(0, verbose_stream() << bpp(arg) << "\n" << mdl(arg->get_expr()) << "\n");
|
||||||
}
|
}
|
||||||
|
if (!tt && mdl.is_true(e))
|
||||||
|
IF_VERBOSE(0, verbose_stream() << "Failed to validate " << bpp(n) << " " << mdl(e) << "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -359,6 +359,7 @@ namespace euf {
|
||||||
bool relevancy_enabled() const { return get_config().m_relevancy_lvl > 0; }
|
bool relevancy_enabled() const { return get_config().m_relevancy_lvl > 0; }
|
||||||
void add_root(unsigned n, sat::literal const* lits);
|
void add_root(unsigned n, sat::literal const* lits);
|
||||||
void add_aux(unsigned n, sat::literal const* lits);
|
void add_aux(unsigned n, sat::literal const* lits);
|
||||||
|
void add_aux(sat::literal a, sat::literal b) { sat::literal lits[2] = {a, b}; add_aux(2, lits); }
|
||||||
void track_relevancy(sat::bool_var v);
|
void track_relevancy(sat::bool_var v);
|
||||||
bool is_relevant(expr* e) const;
|
bool is_relevant(expr* e) const;
|
||||||
bool is_relevant(enode* n) const;
|
bool is_relevant(enode* n) const;
|
||||||
|
|
|
@ -59,23 +59,6 @@ struct theory_array_params {
|
||||||
|
|
||||||
void updt_params(params_ref const & _p);
|
void updt_params(params_ref const & _p);
|
||||||
|
|
||||||
#if 0
|
|
||||||
void register_params(ini_params & p) {
|
|
||||||
p.register_int_param("array_solver", 0, 3, reinterpret_cast<int&>(m_array_mode), "0 - no array, 1 - simple, 2 - model based, 3 - full");
|
|
||||||
p.register_bool_param("array_weak", m_array_weak);
|
|
||||||
p.register_bool_param("array_extensional", m_array_extensional);
|
|
||||||
p.register_unsigned_param("array_laziness", m_array_laziness);
|
|
||||||
p.register_bool_param("array_delay_exp_axiom", m_array_delay_exp_axiom);
|
|
||||||
p.register_bool_param("array_cg", m_array_cg);
|
|
||||||
p.register_bool_param("array_always_prop_upward", m_array_always_prop_upward,
|
|
||||||
"Disable the built-in filter upwards propagation");
|
|
||||||
p.register_bool_param("array_lazy_ieq", m_array_lazy_ieq);
|
|
||||||
p.register_unsigned_param("array_lazy_ieq_delay", m_array_lazy_ieq_delay);
|
|
||||||
p.register_bool_param("array_canonize", m_array_canonize_simplify,
|
|
||||||
"Normalize arrays into normal form during simplification");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void display(std::ostream & out) const;
|
void display(std::ostream & out) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue