3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-08-20 18:20:22 +00:00

dt updates

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2024-10-15 09:36:07 -07:00
parent b551f22aca
commit a4275dfb15
6 changed files with 147 additions and 20 deletions

View file

@ -341,8 +341,10 @@ namespace datatype {
ast_manager & get_manager() const { return m; } ast_manager & get_manager() const { return m; }
// sort * mk_datatype_sort(symbol const& name, unsigned n, sort* const* params); // sort * mk_datatype_sort(symbol const& name, unsigned n, sort* const* params);
bool is_datatype(sort const* s) const { return is_sort_of(s, fid(), DATATYPE_SORT); } bool is_datatype(sort const* s) const { return is_sort_of(s, fid(), DATATYPE_SORT); }
bool is_datatype(expr* e) const { return is_datatype(e->get_sort()); }
bool is_enum_sort(sort* s); bool is_enum_sort(sort* s);
bool is_recursive(sort * ty); bool is_recursive(sort * ty);
bool is_recursive(expr* e) { return is_recursive(e->get_sort()); }
bool is_recursive_nested(sort * ty); bool is_recursive_nested(sort * ty);
bool is_constructor(func_decl * f) const { return is_decl_of(f, fid(), OP_DT_CONSTRUCTOR); } bool is_constructor(func_decl * f) const { return is_decl_of(f, fid(), OP_DT_CONSTRUCTOR); }
bool is_recognizer(func_decl * f) const { return is_recognizer0(f) || is_is(f); } bool is_recognizer(func_decl * f) const { return is_recognizer0(f) || is_is(f); }

View file

@ -69,6 +69,16 @@ namespace sls {
verbose_stream() << "did not find plugin for " << fid << "\n"; verbose_stream() << "did not find plugin for " << fid << "\n";
} }
scoped_ptr<euf::egraph>& context::ensure_euf() {
auto fid = user_sort_family_id;
auto p = m_plugins.get(fid, nullptr);
if (!p) {
p = alloc(euf_plugin, *this);
register_plugin(p);
}
return dynamic_cast<euf_plugin*>(p)->egraph();
}
void context::ensure_plugin(expr* e) { void context::ensure_plugin(expr* e) {
auto fid = get_fid(e); auto fid = get_fid(e);
ensure_plugin(fid); ensure_plugin(fid);

View file

@ -20,6 +20,7 @@ Author:
#include "util/sat_sls.h" #include "util/sat_sls.h"
#include "util/statistics.h" #include "util/statistics.h"
#include "ast/ast.h" #include "ast/ast.h"
#include "ast/euf/euf_egraph.h"
#include "model/model.h" #include "model/model.h"
#include "util/scoped_ptr_vector.h" #include "util/scoped_ptr_vector.h"
#include "util/obj_hashtable.h" #include "util/obj_hashtable.h"
@ -195,6 +196,7 @@ namespace sls {
ast_manager& get_manager() { return m; } ast_manager& get_manager() { return m; }
std::ostream& display(std::ostream& out) const; std::ostream& display(std::ostream& out) const;
std::ostream& display_all(std::ostream& out) const { return s.display(out); } std::ostream& display_all(std::ostream& out) const { return s.display(out); }
scoped_ptr<euf::egraph>& ensure_euf();
void collect_statistics(statistics& st) const; void collect_statistics(statistics& st) const;
void reset_statistics(); void reset_statistics();

View file

@ -40,6 +40,14 @@ Axioms:
forced. forced.
If this is incorrect, include is-c(t) assumptions in path axioms. If this is incorrect, include is-c(t) assumptions in path axioms.
Is P sufficient? Should we just consider all possible paths of depth at most k to be safe?
Example:
C(acc(t)) == C(s)
triggers equation acc(t) = s, but the equation is implicit, so acc(t) and s are not directly
connected.
Even, the axioms extracted from P don't consider transitivity of =.
So the can-be-equal alias approximation is currently too strong.
--*/ --*/
#include "ast/sls/sls_datatype_plugin.h" #include "ast/sls/sls_datatype_plugin.h"
@ -48,7 +56,10 @@ namespace sls {
datatype_plugin::datatype_plugin(context& c): datatype_plugin::datatype_plugin(context& c):
plugin(c), plugin(c),
dt(m) { g(c.ensure_euf()),
dt(m),
m_axioms(m),
m_values(m) {
m_fid = dt.get_family_id(); m_fid = dt.get_family_id();
} }
@ -56,9 +67,14 @@ namespace sls {
void datatype_plugin::collect_path_axioms() { void datatype_plugin::collect_path_axioms() {
expr* t = nullptr, *z = nullptr; expr* t = nullptr, *z = nullptr;
for (auto s : ctx.subterms()) for (auto s : ctx.subterms()) {
if (dt.is_accessor(s, t) && dt.is_recursive(t->get_sort())) if (dt.is_accessor(s, t) && dt.is_recursive(t) && dt.is_recursive(s))
add_edge(s, t, sat::null_literal); add_edge(s, t, sat::null_literal);
if (dt.is_constructor(s) && dt.is_recursive(s)) {
for (auto arg : *to_app(s))
add_edge(arg, s, sat::null_literal);
}
}
expr* x = nullptr, *y = nullptr; expr* x = nullptr, *y = nullptr;
for (sat::bool_var v = 0; v < ctx.num_bool_vars(); ++v) { for (sat::bool_var v = 0; v < ctx.num_bool_vars(); ++v) {
expr* e = ctx.atom(v); expr* e = ctx.atom(v);
@ -66,8 +82,10 @@ namespace sls {
continue; continue;
if (!m.is_eq(e, x, y)) if (!m.is_eq(e, x, y))
continue; continue;
if (!dt.is_recursive(x))
continue;
sat::literal lp(v, false), ln(v, true); sat::literal lp(v, false), ln(v, true);
if (dt.is_accessor(x, z) && dt.is_recursive(z->get_sort())) { if (dt.is_accessor(x, z) && dt.is_recursive(z)) {
if (ctx.is_unit(lp)) if (ctx.is_unit(lp))
add_edge(y, z, sat::null_literal); add_edge(y, z, sat::null_literal);
else if (ctx.is_unit(ln)) else if (ctx.is_unit(ln))
@ -75,7 +93,7 @@ namespace sls {
else else
add_edge(y, z, lp); add_edge(y, z, lp);
} }
if (dt.is_accessor(y, z) && dt.is_recursive(z->get_sort())) { if (dt.is_accessor(y, z) && dt.is_recursive(z)) {
if (ctx.is_unit(lp)) if (ctx.is_unit(lp))
add_edge(x, z, sat::null_literal); add_edge(x, z, sat::null_literal);
else if (ctx.is_unit(ln)) else if (ctx.is_unit(ln))
@ -107,6 +125,8 @@ namespace sls {
if (lit != sat::null_literal) if (lit != sat::null_literal)
lits.push_back(~lit); lits.push_back(~lit);
if (children.contains(parent)) { if (children.contains(parent)) {
// only assert loop clauses for proper loops
if (parent == children[0])
ctx.add_clause(lits); ctx.add_clause(lits);
if (lit != sat::null_literal) if (lit != sat::null_literal)
lits.pop_back(); lits.pop_back();
@ -144,17 +164,17 @@ namespace sls {
if (dt.is_constructor(t)) { if (dt.is_constructor(t)) {
auto r = dt.get_constructor_recognizer(f); auto r = dt.get_constructor_recognizer(f);
axioms.push_back(m.mk_app(r, t)); m_axioms.push_back(m.mk_app(r, t));
auto& acc = *dt.get_constructor_accessors(f); auto& acc = *dt.get_constructor_accessors(f);
for (unsigned i = 0; i < ta->get_num_args(); ++i) { for (unsigned i = 0; i < ta->get_num_args(); ++i) {
auto ti = ta->get_arg(i); auto ti = ta->get_arg(i);
axioms.push_back(m.mk_eq(ti, m.mk_app(acc[i], t))); m_axioms.push_back(m.mk_eq(ti, m.mk_app(acc[i], t)));
} }
auto& cns = *dt.get_datatype_constructors(s); auto& cns = *dt.get_datatype_constructors(s);
for (auto c : cns) { for (auto c : cns) {
if (c != f) { if (c != f) {
auto r2 = dt.get_constructor_recognizer(c); auto r2 = dt.get_constructor_recognizer(c);
axioms.push_back(m.mk_not(m.mk_app(r2, t))); m_axioms.push_back(m.mk_not(m.mk_app(r2, t)));
} }
} }
continue; continue;
@ -166,7 +186,7 @@ namespace sls {
expr_ref_vector args(m); expr_ref_vector args(m);
for (auto a : acc) for (auto a : acc)
args.push_back(m.mk_app(a, u)); args.push_back(m.mk_app(a, u));
axioms.push_back(m.mk_implies(m.mk_app(r, u), m.mk_eq(u, m.mk_app(c, args)))); m_axioms.push_back(m.mk_implies(m.mk_app(r, u), m.mk_eq(u, m.mk_app(c, args))));
} }
if (dt.is_datatype(s)) { if (dt.is_datatype(s)) {
@ -176,18 +196,18 @@ namespace sls {
auto r = dt.get_constructor_recognizer(c); auto r = dt.get_constructor_recognizer(c);
ors.push_back(m.mk_app(r, t)); ors.push_back(m.mk_app(r, t));
} }
axioms.push_back(m.mk_or(ors)); m_axioms.push_back(m.mk_or(ors));
for (unsigned i = 0; i < cns.size(); ++i) { for (unsigned i = 0; i < cns.size(); ++i) {
auto r1 = dt.get_constructor_recognizer(cns[i]); auto r1 = dt.get_constructor_recognizer(cns[i]);
for (unsigned j = i + 1; j < cns.size(); ++j) { for (unsigned j = i + 1; j < cns.size(); ++j) {
auto r2 = dt.get_constructor_recognizer(cns[j]); auto r2 = dt.get_constructor_recognizer(cns[j]);
axioms.push_back(m.mk_or(m.mk_not(m.mk_app(r1, t)), m.mk_not(m.mk_app(r2, t)))); m_axioms.push_back(m.mk_or(m.mk_not(m.mk_app(r1, t)), m.mk_not(m.mk_app(r2, t))));
} }
} }
for (auto c : cns) { for (auto c : cns) {
if (c->get_arity() == 0) { if (c->get_arity() == 0) {
auto r = dt.get_constructor_recognizer(c); auto r = dt.get_constructor_recognizer(c);
axioms.push_back(m.mk_iff(m.mk_app(r, t), m.mk_eq(t, m.mk_const(c)))); m_axioms.push_back(m.mk_iff(m.mk_app(r, t), m.mk_eq(t, m.mk_const(c))));
} }
} }
@ -203,19 +223,104 @@ namespace sls {
collect_path_axioms(); collect_path_axioms();
} }
expr_ref datatype_plugin::get_value(expr* e) { return expr_ref(m); } void datatype_plugin::initialize() {
void datatype_plugin::initialize() {} add_axioms();
void datatype_plugin::start_propagation() {} }
expr_ref datatype_plugin::get_value(expr* e) {
if (!dt.is_datatype(e))
return expr_ref(m);
init_values();
return expr_ref(m_values.get(g->find(e)->get_root_id()), m);
}
void datatype_plugin::init_values() {
if (!m_values.empty())
return;
// retrieve e-graph from sls_euf_solver: add bridge in sls_context to share e-graph
SASSERT(g);
// build top_sort<euf::enode> similar to dt_solver.cpp
top_sort<euf::enode> deps;
for (auto* n : g->nodes())
if (n->is_root())
add_dep(n, deps);
deps.topological_sort();
expr_ref_vector args(m);
// walk topological sort in order of leaves to roots, attaching values to nodes.
for (euf::enode* n : deps.top_sorted()) {
SASSERT(n->is_root());
unsigned id = n->get_id();
if (m_values.get(id, nullptr))
continue;
expr* e = n->get_expr();
m_values.reserve(id + 1);
if (!dt.is_datatype(e))
continue;
euf::enode* con = nullptr;
for (auto sib : euf::enode_class(n)) {
if (dt.is_constructor(sib->get_expr())) {
con = sib;
break;
}
}
if (con) {
auto f = con->get_decl();
args.reset();
for (auto arg : euf::enode_args(con)) {
if (dt.is_datatype(arg->get_sort()))
args.push_back(m_values.get(arg->get_root_id()));
else
args.push_back(ctx.get_value(arg->get_expr()));
}
m_values.setx(n->get_id(), m.mk_app(f, args));
}
else {
NOT_IMPLEMENTED_YET();
}
}
}
void datatype_plugin::add_dep(euf::enode* n, top_sort<euf::enode>& dep) {
if (!dt.is_datatype(n->get_expr()))
return;
euf::enode* con = nullptr;
for (auto sib : euf::enode_class(n)) {
if (dt.is_constructor(sib->get_expr())) {
con = sib;
break;
}
}
TRACE("dt", display(tout) << g->bpp(n) << " con: " << g->bpp(con) << "\n";);
if (!con)
dep.insert(n, nullptr);
else if (con->num_args() == 0)
dep.insert(n, nullptr);
for (euf::enode* arg : euf::enode_args(con))
dep.add(n, arg->get_root());
}
void datatype_plugin::start_propagation() {
m_values.reset();
}
void datatype_plugin::propagate_literal(sat::literal lit) {} void datatype_plugin::propagate_literal(sat::literal lit) {}
bool datatype_plugin::propagate() { return false; } bool datatype_plugin::propagate() { return false; }
bool datatype_plugin::is_sat() { return true; } bool datatype_plugin::is_sat() { return true; }
void datatype_plugin::register_term(expr* e) {} void datatype_plugin::register_term(expr* e) {}
std::ostream& datatype_plugin::display(std::ostream& out) const { std::ostream& datatype_plugin::display(std::ostream& out) const {
for (auto a : m_axioms)
out << mk_bounded_pp(a, m, 3) << "\n";
return out; return out;
} }
void datatype_plugin::mk_model(model& mdl) {} void datatype_plugin::mk_model(model& mdl) {
}
void datatype_plugin::collect_statistics(statistics& st) const {
st.update("sls-dt-axioms", m_axioms.size());
}
void datatype_plugin::collect_statistics(statistics& st) const {}
void datatype_plugin::reset_statistics() {} void datatype_plugin::reset_statistics() {}
} }

View file

@ -18,6 +18,7 @@ Author:
#include "ast/sls/sls_context.h" #include "ast/sls/sls_context.h"
#include "ast/datatype_decl_plugin.h" #include "ast/datatype_decl_plugin.h"
#include "util/top_sort.h"
namespace sls { namespace sls {
@ -30,10 +31,12 @@ namespace sls {
expr* parent; expr* parent;
sat::literal lit; sat::literal lit;
}; };
scoped_ptr<euf::egraph>& g;
obj_map<sort, ptr_vector<expr>> m_dts; obj_map<sort, ptr_vector<expr>> m_dts;
obj_map<expr, svector<parent_t>> m_parents; obj_map<expr, svector<parent_t>> m_parents;
datatype_util dt; datatype_util dt;
expr_ref_vector m_axioms, m_values;
stats m_stats; stats m_stats;
void collect_path_axioms(); void collect_path_axioms();
@ -42,6 +45,9 @@ namespace sls {
void add_path_axioms(ptr_vector<expr>& children, sat::literal_vector& lits, svector<parent_t> const& parents); void add_path_axioms(ptr_vector<expr>& children, sat::literal_vector& lits, svector<parent_t> const& parents);
void add_axioms(); void add_axioms();
void init_values();
void add_dep(euf::enode* n, top_sort<euf::enode>& dep);
public: public:
datatype_plugin(context& c); datatype_plugin(context& c);
~datatype_plugin() override; ~datatype_plugin() override;

View file

@ -87,6 +87,8 @@ namespace sls {
void collect_statistics(statistics& st) const override; void collect_statistics(statistics& st) const override;
void reset_statistics() override; void reset_statistics() override;
scoped_ptr<euf::egraph>& egraph() { return m_g; }
}; };
} }