mirror of
https://github.com/Z3Prover/z3
synced 2026-02-14 04:41:48 +00:00
merge with master
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
commit
3533bf486f
223 changed files with 7175 additions and 2167 deletions
|
|
@ -281,14 +281,19 @@ namespace datalog {
|
|||
return get_max_var(has_var);
|
||||
}
|
||||
|
||||
void del_rule(horn_subsume_model_converter* mc, rule& r, bool unreachable) {
|
||||
void del_rule(horn_subsume_model_converter* mc, rule& r, lbool unreachable) {
|
||||
if (mc) {
|
||||
ast_manager& m = mc->get_manager();
|
||||
expr_ref_vector body(m);
|
||||
if (unreachable) {
|
||||
TRACE("dl", tout << "unreachable: " << unreachable << " " << r.get_decl()->get_name() << "\n");
|
||||
switch (unreachable) {
|
||||
case l_true:
|
||||
body.push_back(m.mk_true());
|
||||
break;
|
||||
case l_false:
|
||||
body.push_back(m.mk_false());
|
||||
}
|
||||
else {
|
||||
break;
|
||||
default:
|
||||
for (unsigned i = 0; i < r.get_tail_size(); ++i) {
|
||||
if (r.is_neg_tail(i)) {
|
||||
body.push_back(m.mk_not(r.get_tail(i)));
|
||||
|
|
@ -297,11 +302,12 @@ namespace datalog {
|
|||
body.push_back(r.get_tail(i));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
TRACE("dl_dr",
|
||||
TRACE("dl",
|
||||
tout << mk_pp(r.get_head(), m) << " :- \n";
|
||||
for (unsigned i = 0; i < body.size(); ++i) {
|
||||
tout << mk_pp(body[i].get(), m) << "\n";
|
||||
tout << mk_pp(body.get(i), m) << "\n";
|
||||
});
|
||||
|
||||
mc->insert(r.get_head(), body.size(), body.data());
|
||||
|
|
|
|||
|
|
@ -353,7 +353,7 @@ namespace datalog {
|
|||
unsigned get_max_rule_var(const rule& r);
|
||||
};
|
||||
|
||||
void del_rule(horn_subsume_model_converter* mc, rule& r, bool unreachable);
|
||||
void del_rule(horn_subsume_model_converter* mc, rule& r, lbool unreachable);
|
||||
|
||||
void resolve_rule(rule_manager& rm,
|
||||
replace_proof_converter* pc, rule const& r1, rule const& r2, unsigned idx,
|
||||
|
|
|
|||
|
|
@ -210,19 +210,35 @@ bool rule_properties::check_accessor(app* n) {
|
|||
SASSERT(m_dt.is_datatype(s));
|
||||
if (m_dt.get_datatype_constructors(s)->size() <= 1)
|
||||
return true;
|
||||
|
||||
|
||||
func_decl* f = n->get_decl();
|
||||
func_decl * c = m_dt.get_accessor_constructor(f);
|
||||
func_decl* c = m_dt.get_accessor_constructor(f);
|
||||
unsigned ut_size = m_rule->get_uninterpreted_tail_size();
|
||||
unsigned t_size = m_rule->get_tail_size();
|
||||
ptr_vector<func_decl> ctors;
|
||||
|
||||
// add recognizer constructor to ctors
|
||||
auto add_recognizer = [&](expr* r) {
|
||||
if (!m_dt.is_recognizer(r))
|
||||
return;
|
||||
if (n->get_arg(0) != to_app(r)->get_arg(0))
|
||||
return;
|
||||
auto* c2 = m_dt.get_recognizer_constructor(to_app(r)->get_decl());
|
||||
if (c == c2)
|
||||
return;
|
||||
ctors.push_back(c2);
|
||||
};
|
||||
auto add_not_recognizer = [&](expr* r) {
|
||||
if (m.is_not(r, r))
|
||||
add_recognizer(r);
|
||||
};
|
||||
|
||||
// t is a recognizer for n
|
||||
auto is_recognizer_base = [&](expr* t) {
|
||||
return m_dt.is_recognizer(t) &&
|
||||
to_app(t)->get_arg(0) == n->get_arg(0) &&
|
||||
m_dt.get_recognizer_constructor(to_app(t)->get_decl()) == c;
|
||||
};
|
||||
|
||||
auto is_recognizer = [&](expr* t) {
|
||||
if (m.is_and(t))
|
||||
for (expr* arg : *to_app(t))
|
||||
|
|
@ -231,43 +247,78 @@ bool rule_properties::check_accessor(app* n) {
|
|||
return is_recognizer_base(t);
|
||||
};
|
||||
|
||||
|
||||
for (unsigned i = ut_size; i < t_size; ++i)
|
||||
if (is_recognizer(m_rule->get_tail(i)))
|
||||
for (unsigned i = ut_size; i < t_size; ++i) {
|
||||
auto* tail = m_rule->get_tail(i);
|
||||
if (is_recognizer(tail))
|
||||
return true;
|
||||
|
||||
add_not_recognizer(tail);
|
||||
}
|
||||
|
||||
// create parent use list for every sub-expression in the rule
|
||||
obj_map<expr, ptr_vector<expr>> use_list;
|
||||
for (unsigned i = ut_size; i < t_size; ++i) {
|
||||
app* t = m_rule->get_tail(i);
|
||||
use_list.insert_if_not_there(t, ptr_vector<expr>()).push_back(nullptr); // add marker for top-level expression.
|
||||
for (expr* sub : subterms::all(expr_ref(t, m)))
|
||||
for (expr* sub : subterms::all(expr_ref(t, m)))
|
||||
if (is_app(sub))
|
||||
for (expr* arg : *to_app(sub))
|
||||
use_list.insert_if_not_there(arg, ptr_vector<expr>()).push_back(sub);
|
||||
}
|
||||
|
||||
// walk parents of n to check that each path is guarded by a recognizer.
|
||||
ptr_vector<expr> todo;
|
||||
todo.push_back(n);
|
||||
for (unsigned i = 0; i < todo.size(); ++i) {
|
||||
expr* e = todo[i];
|
||||
// walk parents of n depth first to check that each path is guarded by a recognizer.
|
||||
vector<std::tuple<expr *, unsigned int, bool>> todo;
|
||||
todo.push_back({n, ctors.size(), false});
|
||||
while(!todo.empty()) {
|
||||
auto [e, ctors_size, visited] = todo.back();
|
||||
if (visited) {
|
||||
todo.pop_back();
|
||||
while (ctors.size() > ctors_size) ctors.pop_back();
|
||||
continue;
|
||||
}
|
||||
std::get<2>(todo.back()) = true; // set visited
|
||||
|
||||
if (!use_list.contains(e))
|
||||
return false;
|
||||
for (expr* parent : use_list[e]) {
|
||||
if (!parent)
|
||||
return false; // top-level expressions are not guarded
|
||||
if (is_recognizer(parent))
|
||||
if (!parent) { // top-level expression
|
||||
// check if n is an unguarded "else" branch
|
||||
ptr_vector<func_decl> diff;
|
||||
for (auto* dtc : *m_dt.get_datatype_constructors(s))
|
||||
if (!ctors.contains(dtc))
|
||||
diff.push_back(dtc);
|
||||
// the only unguarded constructor for s is c:
|
||||
// all the others are guarded and we are in an "else" branch so the accessor is safe
|
||||
if (diff.size() == 1 && diff[0] == c)
|
||||
continue;
|
||||
return false; // the accessor is not safe
|
||||
}
|
||||
if (is_recognizer(parent))
|
||||
continue;
|
||||
if (m.is_ite(parent) && to_app(parent)->get_arg(1) == e && is_recognizer(to_app(parent)->get_arg(0)))
|
||||
continue;
|
||||
todo.push_back(parent);
|
||||
|
||||
expr *cnd, *thn, *els;
|
||||
if (m.is_ite(parent, cnd, thn, els)) {
|
||||
if (thn == e) {
|
||||
if (is_recognizer(cnd) && els != e)
|
||||
continue; // e is guarded
|
||||
}
|
||||
add_recognizer(cnd);
|
||||
}
|
||||
if (m.is_and(parent))
|
||||
for (expr* arg : *to_app(parent))
|
||||
add_not_recognizer(arg);
|
||||
if (m.is_or(parent))
|
||||
for (expr* arg : *to_app(parent)) {
|
||||
add_recognizer(arg);
|
||||
// if one branch is not(recognizer) then the accessor is safe
|
||||
if (m.is_not(arg, arg) && is_recognizer(arg))
|
||||
goto _continue;
|
||||
}
|
||||
todo.push_back({parent, ctors.size(), false});
|
||||
_continue:;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void rule_properties::operator()(app* n) {
|
||||
|
|
|
|||
|
|
@ -777,6 +777,7 @@ protected:
|
|||
// Sym ::= String | NUM | Var
|
||||
//
|
||||
dtoken parse_infix(dtoken tok1, char const* td, app_ref& pred) {
|
||||
std::string td1_(td);
|
||||
symbol td1(td);
|
||||
expr_ref v1(m), v2(m);
|
||||
sort* s = nullptr;
|
||||
|
|
@ -793,12 +794,12 @@ protected:
|
|||
|
||||
if (tok1 == TK_ID) {
|
||||
expr* _v1 = nullptr;
|
||||
m_vars.find(td1.bare_str(), _v1);
|
||||
m_vars.find(td1_, _v1);
|
||||
v1 = _v1;
|
||||
}
|
||||
if (tok3 == TK_ID) {
|
||||
expr* _v2 = nullptr;
|
||||
m_vars.find(td2.bare_str(), _v2);
|
||||
m_vars.find(td, _v2);
|
||||
v2 = _v2;
|
||||
}
|
||||
if (!v1 && !v2) {
|
||||
|
|
@ -950,18 +951,19 @@ protected:
|
|||
break;
|
||||
}
|
||||
case TK_ID: {
|
||||
symbol data (m_lexer->get_token_data());
|
||||
if (is_var(data.bare_str())) {
|
||||
char const* d = m_lexer->get_token_data();
|
||||
symbol data (d);
|
||||
if (is_var(d)) {
|
||||
unsigned idx = 0;
|
||||
expr* v = nullptr;
|
||||
if (!m_vars.find(data.bare_str(), v)) {
|
||||
if (!m_vars.find(d, v)) {
|
||||
idx = m_num_vars++;
|
||||
v = m.mk_var(idx, s);
|
||||
m_vars.insert(data.bare_str(), v);
|
||||
m_vars.insert(d, v);
|
||||
}
|
||||
else if (s != v->get_sort()) {
|
||||
throw default_exception(default_exception::fmt(), "sort: %s expected, but got: %s\n",
|
||||
s->get_name().bare_str(), v->get_sort()->get_name().bare_str());
|
||||
s->get_name().str().c_str(), v->get_sort()->get_name().str().c_str());
|
||||
}
|
||||
args.push_back(v);
|
||||
}
|
||||
|
|
@ -1075,21 +1077,21 @@ protected:
|
|||
}
|
||||
|
||||
sort * register_finite_sort(symbol name, uint64_t domain_size, context::sort_kind k) {
|
||||
if(m_sort_dict.contains(name.bare_str())) {
|
||||
throw default_exception(default_exception::fmt(), "sort %s already declared", name.bare_str());
|
||||
if(m_sort_dict.contains(name.str().c_str())) {
|
||||
throw default_exception(default_exception::fmt(), "sort %s already declared", name.str().c_str());
|
||||
}
|
||||
sort * s = m_decl_util.mk_sort(name, domain_size);
|
||||
m_context.register_finite_sort(s, k);
|
||||
m_sort_dict.insert(name.bare_str(), s);
|
||||
m_sort_dict.insert(name.str(), s);
|
||||
return s;
|
||||
}
|
||||
|
||||
sort * register_int_sort(symbol name) {
|
||||
if(m_sort_dict.contains(name.bare_str())) {
|
||||
throw default_exception(default_exception::fmt(), "sort %s already declared", name.bare_str());
|
||||
if(m_sort_dict.contains(name.str().c_str())) {
|
||||
throw default_exception(default_exception::fmt(), "sort %s already declared", name.str().c_str());
|
||||
}
|
||||
sort * s = m_arith.mk_int();
|
||||
m_sort_dict.insert(name.bare_str(), s);
|
||||
m_sort_dict.insert(name.str(), s);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
@ -1105,8 +1107,8 @@ protected:
|
|||
app * res;
|
||||
if(m_arith.is_int(s)) {
|
||||
uint64_t val;
|
||||
if (!string_to_uint64(name.bare_str(), val)) {
|
||||
throw default_exception(default_exception::fmt(), "Invalid integer: \"%s\"", name.bare_str());
|
||||
if (!string_to_uint64(name.str().c_str(), val)) {
|
||||
throw default_exception(default_exception::fmt(), "Invalid integer: \"%s\"", name.str().c_str());
|
||||
}
|
||||
res = m_arith.mk_numeral(rational(val, rational::ui64()), s);
|
||||
}
|
||||
|
|
@ -1288,7 +1290,7 @@ private:
|
|||
uint64_set & sort_content = *e->get_data().m_value;
|
||||
if(!sort_content.contains(num)) {
|
||||
warning_msg("symbol number %I64u on line %d in file %s does not belong to sort %s",
|
||||
num, m_current_line, m_current_file.c_str(), s->get_name().bare_str());
|
||||
num, m_current_line, m_current_file.c_str(), s->get_name().str().c_str());
|
||||
return false;
|
||||
}
|
||||
if(!m_use_map_names) {
|
||||
|
|
@ -1366,7 +1368,7 @@ private:
|
|||
func_decl * pred = m_context.try_get_predicate_decl(predicate_name);
|
||||
if(!pred) {
|
||||
throw default_exception(default_exception::fmt(), "tuple file %s for undeclared predicate %s",
|
||||
m_current_file.c_str(), predicate_name.bare_str());
|
||||
m_current_file.c_str(), predicate_name.str().c_str());
|
||||
}
|
||||
unsigned pred_arity = pred->get_arity();
|
||||
sort * const * arg_sorts = pred->get_domain();
|
||||
|
|
@ -1531,9 +1533,9 @@ private:
|
|||
|
||||
if(m_use_map_names) {
|
||||
auto const & value = m_number_names.insert_if_not_there(num, el_name);
|
||||
if (value!=el_name) {
|
||||
if (value != el_name) {
|
||||
warning_msg("mismatch of number names on line %d in file %s. old: \"%s\" new: \"%s\"",
|
||||
m_current_line, fname.c_str(), value.bare_str(), el_name.bare_str());
|
||||
m_current_line, fname.c_str(), value.str().c_str(), el_name.str().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ class horn_tactic : public tactic {
|
|||
verify(q, g, result, mc, pc);
|
||||
}
|
||||
g->set(pc.get());
|
||||
g->set(mc.get());
|
||||
g->add(mc.get());
|
||||
}
|
||||
|
||||
void verify(expr* q,
|
||||
|
|
@ -282,12 +282,11 @@ class horn_tactic : public tactic {
|
|||
}
|
||||
case l_false: {
|
||||
// goal is sat
|
||||
mc = concat(g->mc(), mc.get());
|
||||
g->reset();
|
||||
if (produce_models) {
|
||||
model_ref md = m_ctx.get_model();
|
||||
model_converter_ref mc2 = model2model_converter(md.get());
|
||||
mc = concat(mc.get(), mc2.get());
|
||||
mc = mc2.get();
|
||||
TRACE("dl", mc->display(tout << *md << "\n"););
|
||||
}
|
||||
break;
|
||||
|
|
@ -345,6 +344,7 @@ class horn_tactic : public tactic {
|
|||
g->assert_expr(fml);
|
||||
}
|
||||
g->set_prec(goal::UNDER_OVER);
|
||||
mc = g->mc();
|
||||
}
|
||||
|
||||
void check_parameters() {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ namespace datalog {
|
|||
}
|
||||
|
||||
symbol finite_product_relation_plugin::get_name(relation_plugin & inner_plugin) {
|
||||
std::string str = std::string("fpr_")+inner_plugin.get_name().bare_str();
|
||||
std::string str = std::string("fpr_")+inner_plugin.get_name().str();
|
||||
return symbol(str.c_str());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -213,10 +213,10 @@ namespace datalog {
|
|||
return true;
|
||||
}
|
||||
void make_annotations(execution_context & ctx) override {
|
||||
ctx.set_register_annotation(m_reg, m_pred->get_name().bare_str());
|
||||
ctx.set_register_annotation(m_reg, m_pred->get_name().str().c_str());
|
||||
}
|
||||
std::ostream& display_head_impl(execution_context const& ctx, std::ostream & out) const override {
|
||||
const char * rel_name = m_pred->get_name().bare_str();
|
||||
auto rel_name = m_pred->get_name();
|
||||
if (m_store) {
|
||||
return out << "store " << m_reg << " into " << rel_name;
|
||||
}
|
||||
|
|
@ -378,7 +378,7 @@ namespace datalog {
|
|||
if (!fn) {
|
||||
throw default_exception(default_exception::fmt(),
|
||||
"trying to perform unsupported join operation on relations of kinds %s and %s",
|
||||
r1.get_plugin().get_name().bare_str(), r2.get_plugin().get_name().bare_str());
|
||||
r1.get_plugin().get_name().str().c_str(), r2.get_plugin().get_name().str().c_str());
|
||||
}
|
||||
store_fn(r1, r2, fn);
|
||||
}
|
||||
|
|
@ -441,7 +441,7 @@ namespace datalog {
|
|||
if (!fn) {
|
||||
throw default_exception(default_exception::fmt(),
|
||||
"trying to perform unsupported filter_equal operation on a relation of kind %s",
|
||||
r.get_plugin().get_name().bare_str());
|
||||
r.get_plugin().get_name().str().c_str());
|
||||
}
|
||||
store_fn(r, fn);
|
||||
}
|
||||
|
|
@ -490,7 +490,7 @@ namespace datalog {
|
|||
if (!fn) {
|
||||
throw default_exception(default_exception::fmt(),
|
||||
"trying to perform unsupported filter_identical operation on a relation of kind %s",
|
||||
r.get_plugin().get_name().bare_str());
|
||||
r.get_plugin().get_name().str().c_str());
|
||||
}
|
||||
store_fn(r, fn);
|
||||
}
|
||||
|
|
@ -537,7 +537,7 @@ namespace datalog {
|
|||
if (!fn) {
|
||||
throw default_exception(default_exception::fmt(),
|
||||
"trying to perform unsupported filter_interpreted operation on a relation of kind %s",
|
||||
r.get_plugin().get_name().bare_str());
|
||||
r.get_plugin().get_name().str().c_str());
|
||||
}
|
||||
store_fn(r, fn);
|
||||
}
|
||||
|
|
@ -594,7 +594,7 @@ namespace datalog {
|
|||
if (!fn) {
|
||||
throw default_exception(default_exception::fmt(),
|
||||
"trying to perform unsupported filter_interpreted_and_project operation on a relation of kind %s",
|
||||
reg.get_plugin().get_name().bare_str());
|
||||
reg.get_plugin().get_name().str().c_str());
|
||||
}
|
||||
store_fn(reg, fn);
|
||||
}
|
||||
|
|
@ -837,7 +837,7 @@ namespace datalog {
|
|||
if (!fn) {
|
||||
throw default_exception(default_exception::fmt(),
|
||||
"trying to perform unsupported join-project operation on relations of kinds %s and %s",
|
||||
r1.get_plugin().get_name().bare_str(), r2.get_plugin().get_name().bare_str());
|
||||
r1.get_plugin().get_name().str().c_str(), r2.get_plugin().get_name().str().c_str());
|
||||
}
|
||||
store_fn(r1, r2, fn);
|
||||
}
|
||||
|
|
@ -910,7 +910,7 @@ namespace datalog {
|
|||
if (!fn) {
|
||||
throw default_exception(default_exception::fmt(),
|
||||
"trying to perform unsupported select_equal_and_project operation on a relation of kind %s",
|
||||
r.get_plugin().get_name().bare_str());
|
||||
r.get_plugin().get_name().str().c_str());
|
||||
}
|
||||
store_fn(r, fn);
|
||||
}
|
||||
|
|
@ -1076,7 +1076,7 @@ namespace datalog {
|
|||
return true;
|
||||
}
|
||||
std::ostream& display_head_impl(execution_context const& ctx, std::ostream & out) const override {
|
||||
return out << "mark_saturated " << m_pred->get_name().bare_str();
|
||||
return out << "mark_saturated " << m_pred->get_name();
|
||||
}
|
||||
void make_annotations(execution_context & ctx) override {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -370,7 +370,7 @@ namespace datalog {
|
|||
rule * one_parent = inf.m_rules.back();
|
||||
|
||||
func_decl* parent_head = one_parent->get_decl();
|
||||
const char * one_parent_name = parent_head->get_name().bare_str();
|
||||
std::string one_parent_name = parent_head->get_name().str();
|
||||
std::string parent_name;
|
||||
if (inf.m_rules.size() > 1) {
|
||||
parent_name = one_parent_name + std::string("_and_") + to_string(inf.m_rules.size()-1);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace datalog {
|
|||
// -----------------------------------
|
||||
|
||||
symbol table_relation_plugin::create_plugin_name(const table_plugin &p) {
|
||||
std::string name = std::string("tr_") + p.get_name().bare_str();
|
||||
std::string name = std::string("tr_") + p.get_name().str();
|
||||
return symbol(name.c_str());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ namespace datalog {
|
|||
//IF_VERBOSE(3, m_context.display_smt2(0,0,verbose_stream()););
|
||||
|
||||
if (m_context.print_aig().is_non_empty_string()) {
|
||||
const char *filename = m_context.print_aig().bare_str();
|
||||
std::string filename = m_context.print_aig().str();
|
||||
aig_exporter aig(m_context.get_rules(), get_context(), &m_table_facts);
|
||||
std::ofstream strm(filename, std::ios_base::binary);
|
||||
aig(strm);
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ public:
|
|||
void move_to_front(expr* e) override { m_solver.move_to_front(e); }
|
||||
expr_ref_vector cube(expr_ref_vector&, unsigned) override { return expr_ref_vector(m); }
|
||||
void get_levels(ptr_vector<expr> const& vars, unsigned_vector& depth) override { m_solver.get_levels(vars, depth); }
|
||||
expr_ref_vector get_trail() override { return m_solver.get_trail(); }
|
||||
expr_ref_vector get_trail(unsigned max_level) override { return m_solver.get_trail(max_level); }
|
||||
|
||||
void push() override;
|
||||
void pop(unsigned n) override;
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ namespace datalog {
|
|||
}
|
||||
|
||||
rule_set * mk_coi_filter::top_down(rule_set const & source) {
|
||||
func_decl_set pruned_preds;
|
||||
func_decl_set pruned_preds, seen;
|
||||
dataflow_engine<reachability_info> engine(source.get_manager(), source);
|
||||
engine.run_top_down();
|
||||
scoped_ptr<rule_set> res = alloc(rule_set, m_context);
|
||||
|
|
@ -126,37 +126,51 @@ namespace datalog {
|
|||
|
||||
for (rule * r : source) {
|
||||
func_decl * pred = r->get_decl();
|
||||
if (engine.get_fact(pred).is_reachable()) {
|
||||
res->add_rule(r);
|
||||
}
|
||||
bool should_keep = false;
|
||||
if (seen.contains(pred))
|
||||
continue;
|
||||
seen.insert(pred);
|
||||
if (engine.get_fact(pred).is_reachable())
|
||||
should_keep = true;
|
||||
else if (m_context.get_model_converter()) {
|
||||
pruned_preds.insert(pred);
|
||||
for (rule* pr : source.get_predicate_rules(pred))
|
||||
for (unsigned i = 0; i < pr->get_uninterpreted_tail_size(); ++i)
|
||||
if (pr->get_tail(i)->get_decl() != pred)
|
||||
// don't try to eliminate across predicates
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
|
||||
if (should_keep)
|
||||
for (rule* pr : source.get_predicate_rules(pred))
|
||||
res->add_rule(pr);
|
||||
else
|
||||
pruned_preds.insert(pred);
|
||||
}
|
||||
|
||||
if (res->get_num_rules() == source.get_num_rules()) {
|
||||
TRACE("dl", tout << "No transformation\n";);
|
||||
res = nullptr;
|
||||
}
|
||||
if (res && m_context.get_model_converter()) {
|
||||
generic_model_converter* mc0 = alloc(generic_model_converter, m, "dl_coi");
|
||||
for (func_decl* f : pruned_preds) {
|
||||
if (res && m_context.get_model_converter() && !pruned_preds.empty()) {
|
||||
auto* mc0 = alloc(generic_model_converter, m, "dl_coi");
|
||||
horn_subsume_model_converter hmc(m);
|
||||
|
||||
for (func_decl* f : pruned_preds) {
|
||||
const rule_vector& rules = source.get_predicate_rules(f);
|
||||
expr_ref_vector fmls(m);
|
||||
for (rule * r : rules) {
|
||||
app* head = r->get_head();
|
||||
expr_ref_vector conj(m);
|
||||
for (unsigned j = 0; j < head->get_num_args(); ++j) {
|
||||
expr* arg = head->get_arg(j);
|
||||
if (!is_var(arg)) {
|
||||
conj.push_back(m.mk_eq(m.mk_var(j, arg->get_sort()), arg));
|
||||
}
|
||||
}
|
||||
fmls.push_back(mk_and(conj));
|
||||
for (rule* r : rules) {
|
||||
expr_ref_vector constraints(m);
|
||||
expr_ref body_res(m);
|
||||
func_decl_ref pred(m);
|
||||
for (unsigned i = r->get_uninterpreted_tail_size(); i < r->get_tail_size(); ++i)
|
||||
constraints.push_back(r->get_tail(i));
|
||||
expr_ref body = mk_and(constraints);
|
||||
VERIFY(hmc.mk_horn(r->get_head(), body, pred, body_res));
|
||||
fmls.push_back(body_res);
|
||||
}
|
||||
expr_ref fml(m);
|
||||
fml = m.mk_or(fmls.size(), fmls.data());
|
||||
mc0->add(f, fml);
|
||||
mc0->add(f, mk_or(fmls));
|
||||
}
|
||||
m_context.add_model_converter(mc0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,11 @@ Subsumption transformation (remove rule):
|
|||
P(x) := P(x) or (exists y . Q(y) & phi(x,y))
|
||||
|
||||
|
||||
For plan_inlining:
|
||||
TODO: order of rule inlining would affect model converter?
|
||||
so shouldn't model converter process inlined rules in a specific (topopologial) order?
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
|
|
@ -377,18 +382,15 @@ namespace datalog {
|
|||
return something_forbidden;
|
||||
}
|
||||
|
||||
void mk_rule_inliner::plan_inlining(rule_set const & orig)
|
||||
{
|
||||
void mk_rule_inliner::plan_inlining(rule_set const & orig) {
|
||||
count_pred_occurrences(orig);
|
||||
|
||||
scoped_ptr<rule_set> candidate_inlined_set = create_allowed_rule_set(orig);
|
||||
while (forbid_preds_from_cycles(*candidate_inlined_set)) {
|
||||
while (forbid_preds_from_cycles(*candidate_inlined_set))
|
||||
candidate_inlined_set = create_allowed_rule_set(orig);
|
||||
}
|
||||
|
||||
if (forbid_multiple_multipliers(orig, *candidate_inlined_set)) {
|
||||
if (forbid_multiple_multipliers(orig, *candidate_inlined_set))
|
||||
candidate_inlined_set = create_allowed_rule_set(orig);
|
||||
}
|
||||
|
||||
TRACE("dl", tout<<"rules to be inlined:\n" << (*candidate_inlined_set); );
|
||||
|
||||
|
|
@ -402,16 +404,13 @@ namespace datalog {
|
|||
for (rule_stratifier::item_set * stratum : comps) {
|
||||
SASSERT(stratum->size() == 1);
|
||||
func_decl * pred = *stratum->begin();
|
||||
for (rule * r : candidate_inlined_set->get_predicate_rules(pred)) {
|
||||
for (rule * r : candidate_inlined_set->get_predicate_rules(pred))
|
||||
transform_rule(orig, r, m_inlined_rules);
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("dl", tout << "inlined rules after mutual inlining:\n" << m_inlined_rules; );
|
||||
for (rule * r : m_inlined_rules)
|
||||
datalog::del_rule(m_mc, *r, l_undef);
|
||||
|
||||
for (rule * r : m_inlined_rules) {
|
||||
datalog::del_rule(m_mc, *r, false);
|
||||
}
|
||||
}
|
||||
|
||||
bool mk_rule_inliner::transform_rule(rule_set const& orig, rule * r0, rule_set& tgt) {
|
||||
|
|
@ -437,20 +436,19 @@ namespace datalog {
|
|||
tgt.add_rule(r);
|
||||
continue;
|
||||
}
|
||||
|
||||
modified = true;
|
||||
|
||||
func_decl * pred = r->get_decl(i);
|
||||
const rule_vector& pred_rules = m_inlined_rules.get_predicate_rules(pred);
|
||||
for (rule * inl_rule : pred_rules) {
|
||||
rule_ref inl_result(m_rm);
|
||||
if (try_to_inline_rule(*r.get(), *inl_rule, i, inl_result)) {
|
||||
if (try_to_inline_rule(*r.get(), *inl_rule, i, inl_result))
|
||||
todo.push_back(inl_result);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (modified) {
|
||||
datalog::del_rule(m_mc, *r0, true);
|
||||
}
|
||||
if (modified)
|
||||
datalog::del_rule(m_mc, *r0, l_undef);
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
|
@ -473,7 +471,7 @@ namespace datalog {
|
|||
if (something_done && m_mc) {
|
||||
for (rule* r : orig) {
|
||||
if (inlining_allowed(orig, r->get_decl())) {
|
||||
datalog::del_rule(m_mc, *r, true);
|
||||
datalog::del_rule(m_mc, *r, l_undef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -558,7 +556,7 @@ namespace datalog {
|
|||
// nothing unifies with the tail atom, therefore the rule is unsatisfiable
|
||||
// (we can say this because relation pred doesn't have any ground facts either)
|
||||
res = nullptr;
|
||||
datalog::del_rule(m_mc, *r, false);
|
||||
datalog::del_rule(m_mc, *r, l_false);
|
||||
return true;
|
||||
}
|
||||
if (!is_oriented_rewriter(inlining_candidate, strat)) {
|
||||
|
|
@ -568,7 +566,7 @@ namespace datalog {
|
|||
goto process_next_tail;
|
||||
}
|
||||
if (!try_to_inline_rule(*r, *inlining_candidate, ti, res)) {
|
||||
datalog::del_rule(m_mc, *r, false);
|
||||
datalog::del_rule(m_mc, *r, l_false);
|
||||
res = nullptr;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -768,7 +766,7 @@ namespace datalog {
|
|||
break;
|
||||
}
|
||||
|
||||
rule* r2 = acc[j].get();
|
||||
rule* r2 = acc.get(j);
|
||||
|
||||
// check that the head of r2 only unifies with this single body position.
|
||||
TRACE("dl", output_predicate(m_context, r2->get_head(), tout << "unify head: "); tout << "\n";);
|
||||
|
|
@ -801,7 +799,7 @@ namespace datalog {
|
|||
if (num_tail_unifiers == 1) {
|
||||
TRACE("dl", tout << "setting invalid: " << j << "\n";);
|
||||
valid.set(j, false);
|
||||
datalog::del_rule(m_mc, *r2, true);
|
||||
datalog::del_rule(m_mc, *r2, l_undef);
|
||||
del_rule(r2, j);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue