3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-23 06:13:40 +00:00

reorganization of rule_set structure

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2013-04-08 13:50:56 -07:00
parent 5915533170
commit 8f46179def
65 changed files with 778 additions and 10668 deletions

View file

@ -636,6 +636,10 @@ namespace datalog {
app* dl_decl_util::mk_numeral(uint64 value, sort* s) { app* dl_decl_util::mk_numeral(uint64 value, sort* s) {
if (is_finite_sort(s)) { if (is_finite_sort(s)) {
uint64 sz = 0;
if (try_get_size(s, sz) && sz <= value) {
m.raise_exception("value is out of bounds");
}
parameter params[2] = { parameter(rational(value, rational::ui64())), parameter(s) }; parameter params[2] = { parameter(rational(value, rational::ui64())), parameter(s) };
return m.mk_const(m.mk_func_decl(m_fid, OP_DL_CONSTANT, 2, params, 0, (sort*const*)0)); return m.mk_const(m.mk_func_decl(m_fid, OP_DL_CONSTANT, 2, params, 0, (sort*const*)0));
} }

View file

@ -37,6 +37,8 @@ namespace datalog {
ast_manager & get_ast_manager_from_rel_manager(const relation_manager & rm); ast_manager & get_ast_manager_from_rel_manager(const relation_manager & rm);
context & get_context_from_rel_manager(const relation_manager & rm); context & get_context_from_rel_manager(const relation_manager & rm);
typedef func_decl_set decl_set;
#if DL_LEAK_HUNTING #if DL_LEAK_HUNTING
void leak_guard_check(const symbol & s); void leak_guard_check(const symbol & s);
#endif #endif

View file

@ -44,7 +44,6 @@ namespace datalog {
public: public:
qlinear(bmc& b): b(b), m(b.m), m_bv(m), m_bit_width(1) {} qlinear(bmc& b): b(b), m(b.m), m_bv(m), m_bit_width(1) {}
lbool check() { lbool check() {
setup(); setup();
m_bit_width = 4; m_bit_width = 4;
@ -1416,19 +1415,12 @@ namespace datalog {
lbool bmc::query(expr* query) { lbool bmc::query(expr* query) {
m_solver.reset(); m_solver.reset();
m_answer = 0; m_answer = 0;
m_ctx.ensure_opened(); m_ctx.ensure_opened();
m_rules.reset(); m_rules.reset();
datalog::rule_manager& rule_manager = m_ctx.get_rule_manager(); datalog::rule_manager& rule_manager = m_ctx.get_rule_manager();
datalog::rule_set old_rules(m_ctx.get_rules()); datalog::rule_set old_rules(m_ctx.get_rules());
datalog::rule_ref_vector query_rules(rule_manager); rule_manager.mk_query(query, m_ctx.get_rules());
datalog::rule_ref query_rule(rule_manager);
rule_manager.mk_query(query, m_query_pred, query_rules, query_rule);
m_ctx.add_rules(query_rules);
expr_ref bg_assertion = m_ctx.get_background_assertion(); expr_ref bg_assertion = m_ctx.get_background_assertion();
m_ctx.set_output_predicate(m_query_pred);
m_ctx.apply_default_transformation(); m_ctx.apply_default_transformation();
if (m_ctx.get_params().slice()) { if (m_ctx.get_params().slice()) {
@ -1436,10 +1428,9 @@ namespace datalog {
datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx);
transformer.register_plugin(slice); transformer.register_plugin(slice);
m_ctx.transform_rules(transformer); m_ctx.transform_rules(transformer);
m_query_pred = slice->get_predicate(m_query_pred.get());
m_ctx.set_output_predicate(m_query_pred);
} }
m_rules.add_rules(m_ctx.get_rules()); m_query_pred = m_ctx.get_rules().get_output_predicate();
m_rules.replace_rules(m_ctx.get_rules());
m_rules.close(); m_rules.close();
m_ctx.reopen(); m_ctx.reopen();
m_ctx.replace_rules(old_rules); m_ctx.replace_rules(old_rules);

View file

@ -445,40 +445,8 @@ public:
ctx.insert(var); ctx.insert(var);
m_dl_ctx->dlctx().register_variable(var); m_dl_ctx->dlctx().register_variable(var);
} }
}; };
class dl_push_cmd : public cmd {
ref<dl_context> m_ctx;
public:
dl_push_cmd(dl_context* ctx):
cmd("fixedpoint-push"),
m_ctx(ctx)
{}
virtual char const * get_usage() const { return ""; }
virtual char const * get_descr(cmd_context & ctx) const { return "push context on the fixedpoint engine"; }
virtual void execute(cmd_context& ctx) {
m_ctx->push();
}
};
class dl_pop_cmd : public cmd {
ref<dl_context> m_ctx;
public:
dl_pop_cmd(dl_context* ctx):
cmd("fixedpoint-pop"),
m_ctx(ctx)
{}
virtual char const * get_usage() const { return ""; }
virtual char const * get_descr(cmd_context & ctx) const { return "pop context on the fixedpoint engine"; }
virtual void execute(cmd_context& ctx) {
m_ctx->pop();
}
};
static void install_dl_cmds_aux(cmd_context& ctx, dl_collected_cmds* collected_cmds) { static void install_dl_cmds_aux(cmd_context& ctx, dl_collected_cmds* collected_cmds) {
dl_context * dl_ctx = alloc(dl_context, ctx, collected_cmds); dl_context * dl_ctx = alloc(dl_context, ctx, collected_cmds);
@ -486,10 +454,6 @@ static void install_dl_cmds_aux(cmd_context& ctx, dl_collected_cmds* collected_c
ctx.insert(alloc(dl_query_cmd, dl_ctx)); ctx.insert(alloc(dl_query_cmd, dl_ctx));
ctx.insert(alloc(dl_declare_rel_cmd, dl_ctx)); ctx.insert(alloc(dl_declare_rel_cmd, dl_ctx));
ctx.insert(alloc(dl_declare_var_cmd, dl_ctx)); ctx.insert(alloc(dl_declare_var_cmd, dl_ctx));
#ifndef _EXTERNAL_RELEASE
ctx.insert(alloc(dl_push_cmd, dl_ctx)); // not exposed to keep command-extensions simple.
ctx.insert(alloc(dl_pop_cmd, dl_ctx));
#endif
} }
void install_dl_cmds(cmd_context & ctx) { void install_dl_cmds(cmd_context & ctx) {

View file

@ -760,7 +760,7 @@ namespace datalog {
typedef svector<tail_delta_info> tail_delta_infos; typedef svector<tail_delta_info> tail_delta_infos;
unsigned rule_len = r->get_uninterpreted_tail_size(); unsigned rule_len = r->get_uninterpreted_tail_size();
reg_idx head_reg = m_pred_regs.find(r->get_head()->get_decl()); reg_idx head_reg = m_pred_regs.find(r->get_decl());
svector<reg_idx> tail_regs; svector<reg_idx> tail_regs;
tail_delta_infos tail_deltas; tail_delta_infos tail_deltas;
@ -884,7 +884,7 @@ namespace datalog {
rule_vector::const_iterator rend = pred_rules.end(); rule_vector::const_iterator rend = pred_rules.end();
for(; rit!=rend; ++rit) { for(; rit!=rend; ++rit) {
rule * r = *rit; rule * r = *rit;
SASSERT(head_pred==r->get_head()->get_decl()); SASSERT(head_pred==r->get_decl());
compile_rule_evaluation(r, input_deltas, d_head_reg, widen_predicate_in_loop, acc); compile_rule_evaluation(r, input_deltas, d_head_reg, widen_predicate_in_loop, acc);
} }
@ -1039,7 +1039,7 @@ namespace datalog {
rule_vector::const_iterator end = rules.end(); rule_vector::const_iterator end = rules.end();
for (; it != end; ++it) { for (; it != end; ++it) {
rule * r = *it; rule * r = *it;
SASSERT(r->get_head()->get_decl()==head_pred); SASSERT(r->get_decl()==head_pred);
compile_rule_evaluation(r, input_deltas, output_delta, false, acc); compile_rule_evaluation(r, input_deltas, output_delta, false, acc);
} }
@ -1112,7 +1112,7 @@ namespace datalog {
//load predicate data //load predicate data
for(unsigned i=0;i<rule_cnt;i++) { for(unsigned i=0;i<rule_cnt;i++) {
const rule * r = m_rule_set.get_rule(i); const rule * r = m_rule_set.get_rule(i);
ensure_predicate_loaded(r->get_head()->get_decl(), acc); ensure_predicate_loaded(r->get_decl(), acc);
unsigned rule_len = r->get_uninterpreted_tail_size(); unsigned rule_len = r->get_uninterpreted_tail_size();
for(unsigned j=0;j<rule_len;j++) { for(unsigned j=0;j<rule_len;j++) {

View file

@ -270,15 +270,11 @@ namespace datalog {
} }
context::sort_domain & context::get_sort_domain(relation_sort s) { context::sort_domain & context::get_sort_domain(relation_sort s) {
sort_domain * dom; return *m_sorts.find(s);
TRUSTME( m_sorts.find(s, dom) );
return *dom;
} }
const context::sort_domain & context::get_sort_domain(relation_sort s) const { const context::sort_domain & context::get_sort_domain(relation_sort s) const {
sort_domain * dom; return *m_sorts.find(s);
TRUSTME( m_sorts.find(s, dom) );
return *dom;
} }
void context::register_finite_sort(sort * s, sort_kind k) { void context::register_finite_sort(sort * s, sort_kind k) {
@ -298,10 +294,6 @@ namespace datalog {
m_sorts.insert(s, dom); m_sorts.insert(s, dom);
} }
bool context::is_predicate(func_decl * pred) const {
return m_preds.contains(pred);
}
void context::register_variable(func_decl* var) { void context::register_variable(func_decl* var) {
m_vars.push_back(m.mk_const(var)); m_vars.push_back(m.mk_const(var));
} }
@ -347,13 +339,20 @@ namespace datalog {
} }
void context::register_predicate(func_decl * decl, bool named) { void context::register_predicate(func_decl * decl, bool named) {
if (m_preds.contains(decl)) { if (!is_predicate(decl)) {
return; m_pinned.push_back(decl);
m_preds.insert(decl);
if (named) {
m_preds_by_name.insert(decl->get_name(), decl);
}
} }
m_pinned.push_back(decl); }
m_preds.insert(decl);
if (named) { void context::restrict_predicates(func_decl_set const& preds) {
m_preds_by_name.insert(decl->get_name(), decl); m_preds.reset();
func_decl_set::iterator it = preds.begin(), end = preds.end();
for (; it != end; ++it) {
m_preds.insert(*it);
} }
} }
@ -447,21 +446,6 @@ namespace datalog {
return new_pred; return new_pred;
} }
void context::set_output_predicate(func_decl * pred) {
ensure_rel();
m_rel->set_output_predicate(pred);
}
bool context::is_output_predicate(func_decl * pred) {
ensure_rel();
return m_rel->is_output_predicate(pred);
}
const decl_set & context::get_output_predicates() {
ensure_rel();
return m_rel->get_output_predicates();
}
void context::add_rule(expr* rl, symbol const& name) { void context::add_rule(expr* rl, symbol const& name) {
m_rule_fmls.push_back(rl); m_rule_fmls.push_back(rl);
m_rule_names.push_back(name); m_rule_names.push_back(name);
@ -469,14 +453,12 @@ namespace datalog {
void context::flush_add_rules() { void context::flush_add_rules() {
datalog::rule_manager& rm = get_rule_manager(); datalog::rule_manager& rm = get_rule_manager();
datalog::rule_ref_vector rules(rm);
scoped_proof_mode _scp(m, generate_proof_trace()?PGM_FINE:PGM_DISABLED); scoped_proof_mode _scp(m, generate_proof_trace()?PGM_FINE:PGM_DISABLED);
for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { for (unsigned i = 0; i < m_rule_fmls.size(); ++i) {
expr* fml = m_rule_fmls[i].get(); expr* fml = m_rule_fmls[i].get();
proof* p = generate_proof_trace()?m.mk_asserted(fml):0; proof* p = generate_proof_trace()?m.mk_asserted(fml):0;
rm.mk_rule(fml, p, rules, m_rule_names[i]); rm.mk_rule(fml, p, m_rule_set, m_rule_names[i]);
} }
add_rules(rules);
m_rule_fmls.reset(); m_rule_fmls.reset();
m_rule_names.reset(); m_rule_names.reset();
} }
@ -487,25 +469,28 @@ namespace datalog {
// //
void context::update_rule(expr* rl, symbol const& name) { void context::update_rule(expr* rl, symbol const& name) {
datalog::rule_manager& rm = get_rule_manager(); datalog::rule_manager& rm = get_rule_manager();
datalog::rule_ref_vector rules(rm);
proof* p = 0; proof* p = 0;
if (generate_proof_trace()) { if (generate_proof_trace()) {
p = m.mk_asserted(rl); p = m.mk_asserted(rl);
} }
rm.mk_rule(rl, p, rules, name); unsigned size_before = m_rule_set.get_num_rules();
if (rules.size() != 1) { rm.mk_rule(rl, p, m_rule_set, name);
unsigned size_after = m_rule_set.get_num_rules();
if (size_before + 1 != size_after) {
std::stringstream strm; std::stringstream strm;
strm << "Rule " << name << " has a non-trivial body. It cannot be modified"; strm << "Rule " << name << " has a non-trivial body. It cannot be modified";
throw default_exception(strm.str()); throw default_exception(strm.str());
} }
rule_ref r(rules[0].get(), rm); // The new rule is inserted last:
rule_ref r(m_rule_set.get_rule(size_before), rm);
rule_ref_vector const& rls = m_rule_set.get_rules(); rule_ref_vector const& rls = m_rule_set.get_rules();
rule* old_rule = 0; rule* old_rule = 0;
for (unsigned i = 0; i < rls.size(); ++i) { for (unsigned i = 0; i < size_before; ++i) {
if (rls[i]->name() == name) { if (rls[i]->name() == name) {
if (old_rule) { if (old_rule) {
std::stringstream strm; std::stringstream strm;
strm << "Rule " << name << " occurs twice. It cannot be modified"; strm << "Rule " << name << " occurs twice. It cannot be modified";
m_rule_set.del_rule(r);
throw default_exception(strm.str()); throw default_exception(strm.str());
} }
old_rule = rls[i]; old_rule = rls[i];
@ -518,11 +503,11 @@ namespace datalog {
old_rule->display(*this, strm); old_rule->display(*this, strm);
strm << "does not subsume new rule "; strm << "does not subsume new rule ";
r->display(*this, strm); r->display(*this, strm);
m_rule_set.del_rule(r);
throw default_exception(strm.str()); throw default_exception(strm.str());
} }
m_rule_set.del_rule(old_rule); m_rule_set.del_rule(old_rule);
} }
m_rule_set.add_rule(r);
} }
bool context::check_subsumes(rule const& stronger_rule, rule const& weaker_rule) { bool context::check_subsumes(rule const& stronger_rule, rule const& weaker_rule) {
@ -623,20 +608,20 @@ namespace datalog {
} }
class context::contains_pred : public i_expr_pred { class context::contains_pred : public i_expr_pred {
rule_manager const& m; context const& ctx;
public: public:
contains_pred(rule_manager const& m): m(m) {} contains_pred(context& ctx): ctx(ctx) {}
virtual ~contains_pred() {} virtual ~contains_pred() {}
virtual bool operator()(expr* e) { virtual bool operator()(expr* e) {
return is_app(e) && m.is_predicate(to_app(e)); return ctx.is_predicate(e);
} }
}; };
void context::check_existential_tail(rule_ref& r) { void context::check_existential_tail(rule_ref& r) {
unsigned ut_size = r->get_uninterpreted_tail_size(); unsigned ut_size = r->get_uninterpreted_tail_size();
unsigned t_size = r->get_tail_size(); unsigned t_size = r->get_tail_size();
contains_pred contains_p(get_rule_manager()); contains_pred contains_p(*this);
check_pred check_pred(contains_p, get_manager()); check_pred check_pred(contains_p, get_manager());
TRACE("dl", r->display_smt2(get_manager(), tout); tout << "\n";); TRACE("dl", r->display_smt2(get_manager(), tout); tout << "\n";);
@ -663,7 +648,7 @@ namespace datalog {
} }
ast_manager& m = get_manager(); ast_manager& m = get_manager();
datalog::rule_manager& rm = get_rule_manager(); datalog::rule_manager& rm = get_rule_manager();
contains_pred contains_p(rm); contains_pred contains_p(*this);
check_pred check_pred(contains_p, get_manager()); check_pred check_pred(contains_p, get_manager());
for (unsigned i = ut_size; i < t_size; ++i) { for (unsigned i = ut_size; i < t_size; ++i) {
@ -676,7 +661,7 @@ namespace datalog {
continue; continue;
} }
visited.mark(e, true); visited.mark(e, true);
if (rm.is_predicate(e)) { if (is_predicate(e)) {
} }
else if (m.is_and(e) || m.is_or(e)) { else if (m.is_and(e) || m.is_or(e)) {
todo.append(to_app(e)->get_num_args(), to_app(e)->get_args()); todo.append(to_app(e)->get_num_args(), to_app(e)->get_args());
@ -749,14 +734,6 @@ namespace datalog {
m_rule_set.add_rule(r); m_rule_set.add_rule(r);
} }
void context::add_rules(rule_ref_vector& rules) {
for (unsigned i = 0; i < rules.size(); ++i) {
rule_ref rule(rules[i].get(), rules.get_manager());
add_rule(rule);
}
}
void context::add_fact(func_decl * pred, const relation_fact & fact) { void context::add_fact(func_decl * pred, const relation_fact & fact) {
if (get_engine() == DATALOG_ENGINE) { if (get_engine() == DATALOG_ENGINE) {
ensure_rel(); ensure_rel();
@ -771,10 +748,9 @@ namespace datalog {
void context::add_fact(app * head) { void context::add_fact(app * head) {
SASSERT(is_fact(head)); SASSERT(is_fact(head));
relation_fact fact(get_manager()); relation_fact fact(get_manager());
unsigned n=head->get_num_args(); unsigned n = head->get_num_args();
for (unsigned i=0; i<n; i++) { for (unsigned i = 0; i < n; i++) {
fact.push_back(to_app(head->get_arg(i))); fact.push_back(to_app(head->get_arg(i)));
} }
add_fact(head->get_decl(), fact); add_fact(head->get_decl(), fact);
@ -850,6 +826,12 @@ namespace datalog {
transform_rules(m_transf); transform_rules(m_transf);
} }
void context::transform_rules(rule_transformer::plugin* plugin) {
rule_transformer transformer(*this);
transformer.register_plugin(plugin);
transform_rules(transformer);
}
void context::transform_rules(rule_transformer& transf) { void context::transform_rules(rule_transformer& transf) {
SASSERT(m_closed); //we must finish adding rules before we start transforming them SASSERT(m_closed); //we must finish adding rules before we start transforming them
TRACE("dl", display_rules(tout);); TRACE("dl", display_rules(tout););
@ -862,15 +844,16 @@ namespace datalog {
} }
} }
void context::replace_rules(rule_set & rs) { void context::replace_rules(rule_set const & rs) {
SASSERT(!m_closed); SASSERT(!m_closed);
m_rule_set.reset(); m_rule_set.replace_rules(rs);
m_rule_set.add_rules(rs); if (m_rel) {
m_rel->restrict_predicates(get_predicates());
}
} }
void context::record_transformed_rules() { void context::record_transformed_rules() {
m_transformed_rule_set.reset(); m_transformed_rule_set.replace_rules(m_rule_set);
m_transformed_rule_set.add_rules(m_rule_set);
} }
void context::apply_default_transformation() { void context::apply_default_transformation() {
@ -921,16 +904,6 @@ namespace datalog {
if (m_pdr.get()) m_pdr->updt_params(); if (m_pdr.get()) m_pdr->updt_params();
} }
void context::collect_predicates(decl_set& res) {
ensure_rel();
m_rel->collect_predicates(res);
}
void context::restrict_predicates(decl_set const& res) {
ensure_rel();
m_rel->restrict_predicates(res);
}
expr_ref context::get_background_assertion() { expr_ref context::get_background_assertion() {
expr_ref result(m); expr_ref result(m);
switch (m_background.size()) { switch (m_background.size()) {
@ -1269,14 +1242,13 @@ namespace datalog {
void context::get_rules_as_formulas(expr_ref_vector& rules, svector<symbol>& names) { void context::get_rules_as_formulas(expr_ref_vector& rules, svector<symbol>& names) {
expr_ref fml(m); expr_ref fml(m);
datalog::rule_manager& rm = get_rule_manager(); datalog::rule_manager& rm = get_rule_manager();
datalog::rule_ref_vector rule_refs(rm);
// ensure that rules are all using bound variables. // ensure that rules are all using bound variables.
for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { for (unsigned i = 0; i < m_rule_fmls.size(); ++i) {
ptr_vector<sort> sorts; ptr_vector<sort> sorts;
get_free_vars(m_rule_fmls[i].get(), sorts); get_free_vars(m_rule_fmls[i].get(), sorts);
if (!sorts.empty()) { if (!sorts.empty()) {
rm.mk_rule(m_rule_fmls[i].get(), 0, rule_refs, m_rule_names[i]); rm.mk_rule(m_rule_fmls[i].get(), 0, m_rule_set, m_rule_names[i]);
m_rule_fmls[i] = m_rule_fmls.back(); m_rule_fmls[i] = m_rule_fmls.back();
m_rule_names[i] = m_rule_names.back(); m_rule_names[i] = m_rule_names.back();
m_rule_fmls.pop_back(); m_rule_fmls.pop_back();
@ -1284,7 +1256,6 @@ namespace datalog {
--i; --i;
} }
} }
add_rules(rule_refs);
rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end(); rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end();
for (; it != end; ++it) { for (; it != end; ++it) {
(*it)->to_formula(fml); (*it)->to_formula(fml);

View file

@ -185,7 +185,17 @@ namespace datalog {
*/ */
void register_predicate(func_decl * pred, bool named); void register_predicate(func_decl * pred, bool named);
bool is_predicate(func_decl * pred) const; /**
Restrict reltaions to set of predicates.
*/
void restrict_predicates(func_decl_set const& preds);
/**
\brief Retrieve predicates
*/
func_decl_set const& get_predicates() const { return m_preds; }
bool is_predicate(func_decl* pred) const { return m_preds.contains(pred); }
bool is_predicate(expr * e) const { return is_app(e) && is_predicate(to_app(e)->get_decl()); }
/** /**
\brief If a predicate name has a \c func_decl object assigned, return pointer to it; \brief If a predicate name has a \c func_decl object assigned, return pointer to it;
@ -238,11 +248,9 @@ namespace datalog {
void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt, void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt,
symbol const * relation_names); symbol const * relation_names);
void set_output_predicate(func_decl * pred); void set_output_predicate(func_decl * pred) { m_rule_set.set_output_predicate(pred); }
bool is_output_predicate(func_decl * pred);
const decl_set & get_output_predicates();
rule_set const & get_rules() { flush_add_rules(); return m_rule_set; } rule_set & get_rules() { flush_add_rules(); return m_rule_set; }
void get_rules_as_formulas(expr_ref_vector& fmls, svector<symbol>& names); void get_rules_as_formulas(expr_ref_vector& fmls, svector<symbol>& names);
@ -251,7 +259,6 @@ namespace datalog {
void add_rule(rule_ref& r); void add_rule(rule_ref& r);
void add_rules(rule_ref_vector& rs);
void assert_expr(expr* e); void assert_expr(expr* e);
expr_ref get_background_assertion(); expr_ref get_background_assertion();
@ -329,7 +336,8 @@ namespace datalog {
void transform_rules(); void transform_rules();
void transform_rules(rule_transformer& transf); void transform_rules(rule_transformer& transf);
void replace_rules(rule_set & rs); void transform_rules(rule_transformer::plugin* plugin);
void replace_rules(rule_set const& rs);
void record_transformed_rules(); void record_transformed_rules();
void apply_default_transformation(); void apply_default_transformation();
@ -338,14 +346,6 @@ namespace datalog {
void updt_params(params_ref const& p); void updt_params(params_ref const& p);
void collect_predicates(decl_set & res);
/**
\brief Restrict the set of used predicates to \c res.
The function deallocates unsused relations, it does not deal with rules.
*/
void restrict_predicates(const decl_set & res);
void display_rules(std::ostream & out) const { void display_rules(std::ostream & out) const {
m_rule_set.display(out); m_rule_set.display(out);
} }

View file

@ -129,7 +129,7 @@ namespace datalog {
for(unsigned i=0; i<n; i++) { for(unsigned i=0; i<n; i++) {
if(table_columns[i]) { if(table_columns[i]) {
table_sort t_sort; table_sort t_sort;
TRUSTME( rmgr.relation_sort_to_table(s[i], t_sort) ); VERIFY( rmgr.relation_sort_to_table(s[i], t_sort) );
table_sig.push_back(t_sort); table_sig.push_back(t_sort);
} }
else { else {
@ -1789,7 +1789,7 @@ namespace datalog {
m_sig2table[i]=m_table_sig.size(); m_sig2table[i]=m_table_sig.size();
table_sort srt; table_sort srt;
//the table columns must have table-friendly sorts //the table columns must have table-friendly sorts
TRUSTME( get_manager().relation_sort_to_table(rel_sig[i], srt) ); VERIFY( get_manager().relation_sort_to_table(rel_sig[i], srt) );
m_table_sig.push_back(srt); m_table_sig.push_back(srt);
m_table2sig.push_back(i); m_table2sig.push_back(i);
} }

View file

@ -182,7 +182,6 @@ namespace datalog {
} }
} }
rule_ref_vector new_rules(rm);
expr_ref fml1(m), fml2(m), body(m), head(m); expr_ref fml1(m), fml2(m), body(m), head(m);
r.to_formula(fml1); r.to_formula(fml1);
body = m.mk_and(new_conjs.size(), new_conjs.c_ptr()); body = m.mk_and(new_conjs.size(), new_conjs.c_ptr());
@ -199,12 +198,12 @@ namespace datalog {
fml2 = m.mk_implies(body, head); fml2 = m.mk_implies(body, head);
proof_ref p(m); proof_ref p(m);
rule_set new_rules(m_ctx);
rm.mk_rule(fml2, p, new_rules, r.name()); rm.mk_rule(fml2, p, new_rules, r.name());
SASSERT(new_rules.size() == 1);
TRACE("dl", new_rules[0]->display(m_ctx, tout << "new rule\n");); TRACE("dl", new_rules.last()->display(m_ctx, tout << "new rule\n"););
rule_ref new_rule(rm); rule_ref new_rule(rm);
if (m_simplifier.transform_rule(new_rules[0].get(), new_rule)) { if (m_simplifier.transform_rule(new_rules.last(), new_rule)) {
rules.add_rule(new_rule.get()); rules.add_rule(new_rule.get());
rm.mk_rule_rewrite_proof(r, *new_rule.get()); rm.mk_rule_rewrite_proof(r, *new_rule.get());
} }
@ -214,6 +213,7 @@ namespace datalog {
rule_set * mk_array_blast::operator()(rule_set const & source) { rule_set * mk_array_blast::operator()(rule_set const & source) {
rule_set* rules = alloc(rule_set, m_ctx); rule_set* rules = alloc(rule_set, m_ctx);
rules->inherit_predicates(source);
rule_set::iterator it = source.begin(), end = source.end(); rule_set::iterator it = source.begin(), end = source.end();
bool change = false; bool change = false;
for (; !m_ctx.canceled() && it != end; ++it) { for (; !m_ctx.canceled() && it != end; ++it) {

View file

@ -108,31 +108,35 @@ namespace datalog {
class expand_mkbv_cfg : public default_rewriter_cfg { class expand_mkbv_cfg : public default_rewriter_cfg {
context& m_context; context& m_context;
rule_ref_vector& m_rules;
ast_manager& m; ast_manager& m;
bv_util m_util; bv_util m_util;
expr_ref_vector m_args, m_f_vars, m_g_vars; expr_ref_vector m_args, m_f_vars, m_g_vars;
func_decl_ref_vector m_old_funcs; func_decl_ref_vector m_old_funcs;
func_decl_ref_vector m_new_funcs; func_decl_ref_vector m_new_funcs;
rule_set const* m_src;
rule_set* m_dst;
obj_map<func_decl,func_decl*> m_pred2blast; obj_map<func_decl,func_decl*> m_pred2blast;
public: public:
expand_mkbv_cfg(context& ctx, rule_ref_vector& rules): expand_mkbv_cfg(context& ctx):
m_context(ctx), m_context(ctx),
m_rules(rules),
m(ctx.get_manager()), m(ctx.get_manager()),
m_util(m), m_util(m),
m_args(m), m_args(m),
m_f_vars(m), m_f_vars(m),
m_g_vars(m), m_g_vars(m),
m_old_funcs(m), m_old_funcs(m),
m_new_funcs(m) m_new_funcs(m),
m_src(0),
m_dst(0)
{} {}
~expand_mkbv_cfg() {} ~expand_mkbv_cfg() {}
void set_src(rule_set const* src) { m_src = src; }
void set_dst(rule_set* dst) { m_dst = dst; }
func_decl_ref_vector const& old_funcs() const { return m_old_funcs; } func_decl_ref_vector const& old_funcs() const { return m_old_funcs; }
func_decl_ref_vector const& new_funcs() const { return m_new_funcs; } func_decl_ref_vector const& new_funcs() const { return m_new_funcs; }
@ -183,14 +187,7 @@ namespace datalog {
m_new_funcs.push_back(g); m_new_funcs.push_back(g);
m_pred2blast.insert(f, g); m_pred2blast.insert(f, g);
// Create rule f(mk_mkbv(args)) :- g(args) m_dst->inherit_predicate(*m_src, f, g);
fml = m.mk_implies(m.mk_app(g, m_g_vars.size(), m_g_vars.c_ptr()), m.mk_app(f, m_f_vars.size(), m_f_vars.c_ptr()));
proof_ref pr(m);
if (m_context.generate_proof_trace()) {
pr = m.mk_asserted(fml); // or a def?
}
rm.mk_rule(fml, pr, m_rules, g->get_name());
} }
result = m.mk_app(g, m_args.size(), m_args.c_ptr()); result = m.mk_app(g, m_args.size(), m_args.c_ptr());
result_pr = 0; result_pr = 0;
@ -200,9 +197,9 @@ namespace datalog {
struct expand_mkbv : public rewriter_tpl<expand_mkbv_cfg> { struct expand_mkbv : public rewriter_tpl<expand_mkbv_cfg> {
expand_mkbv_cfg m_cfg; expand_mkbv_cfg m_cfg;
expand_mkbv(ast_manager& m, context& ctx, rule_ref_vector& rules): expand_mkbv(ast_manager& m, context& ctx):
rewriter_tpl<expand_mkbv_cfg>(m, m.proofs_enabled(), m_cfg), rewriter_tpl<expand_mkbv_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(ctx, rules) { m_cfg(ctx) {
} }
}; };
@ -212,7 +209,6 @@ namespace datalog {
context & m_context; context & m_context;
ast_manager & m; ast_manager & m;
params_ref m_params; params_ref m_params;
rule_ref_vector m_rules;
mk_interp_tail_simplifier m_simplifier; mk_interp_tail_simplifier m_simplifier;
bit_blaster_rewriter m_blaster; bit_blaster_rewriter m_blaster;
expand_mkbv m_rewriter; expand_mkbv m_rewriter;
@ -239,19 +235,14 @@ namespace datalog {
} }
} }
void reset() {
m_rules.reset();
}
public: public:
impl(context& ctx): impl(context& ctx):
m_context(ctx), m_context(ctx),
m(ctx.get_manager()), m(ctx.get_manager()),
m_params(ctx.get_params().p), m_params(ctx.get_params().p),
m_rules(ctx.get_rule_manager()),
m_simplifier(ctx), m_simplifier(ctx),
m_blaster(ctx.get_manager(), m_params), m_blaster(ctx.get_manager(), m_params),
m_rewriter(ctx.get_manager(), ctx, m_rules) { m_rewriter(ctx.get_manager(), ctx) {
m_params.set_bool("blast_full", true); m_params.set_bool("blast_full", true);
m_params.set_bool("blast_quant", true); m_params.set_bool("blast_quant", true);
m_blaster.updt_params(m_params); m_blaster.updt_params(m_params);
@ -265,8 +256,9 @@ namespace datalog {
rule_manager& rm = m_context.get_rule_manager(); rule_manager& rm = m_context.get_rule_manager();
unsigned sz = source.get_num_rules(); unsigned sz = source.get_num_rules();
expr_ref fml(m); expr_ref fml(m);
reset();
rule_set * result = alloc(rule_set, m_context); rule_set * result = alloc(rule_set, m_context);
m_rewriter.m_cfg.set_src(&source);
m_rewriter.m_cfg.set_dst(result);
for (unsigned i = 0; !m_context.canceled() && i < sz; ++i) { for (unsigned i = 0; !m_context.canceled() && i < sz; ++i) {
rule * r = source.get_rule(i); rule * r = source.get_rule(i);
r->to_formula(fml); r->to_formula(fml);
@ -275,17 +267,16 @@ namespace datalog {
if (m_context.generate_proof_trace()) { if (m_context.generate_proof_trace()) {
pr = m.mk_asserted(fml); // loses original proof of r. pr = m.mk_asserted(fml); // loses original proof of r.
} }
rm.mk_rule(fml, pr, m_rules, r->name()); // TODO add logic for pc:
// 1. replace fresh predicates by non-bit-blasted predicates
// 2. replace pr by the proof of r.
rm.mk_rule(fml, pr, *result, r->name());
} }
else { else {
m_rules.push_back(r); result->add_rule(r);
} }
} }
for (unsigned i = 0; i < m_rules.size(); ++i) {
result->add_rule(m_rules.get(i));
}
if (m_context.get_model_converter()) { if (m_context.get_model_converter()) {
filter_model_converter* fmc = alloc(filter_model_converter, m); filter_model_converter* fmc = alloc(filter_model_converter, m);
bit_blast_model_converter* bvmc = alloc(bit_blast_model_converter, m); bit_blast_model_converter* bvmc = alloc(bit_blast_model_converter, m);

View file

@ -173,6 +173,7 @@ namespace datalog {
rule_set * mk_coalesce::operator()(rule_set const & source) { rule_set * mk_coalesce::operator()(rule_set const & source) {
rule_set* rules = alloc(rule_set, m_ctx); rule_set* rules = alloc(rule_set, m_ctx);
rules->inherit_predicates(source);
rule_set::decl2rules::iterator it = source.begin_grouped_rules(), end = source.end_grouped_rules(); rule_set::decl2rules::iterator it = source.begin_grouped_rules(), end = source.end_grouped_rules();
for (; it != end; ++it) { for (; it != end; ++it) {
rule_ref_vector d_rules(rm); rule_ref_vector d_rules(rm);

View file

@ -35,7 +35,7 @@ namespace datalog {
rule_set * mk_coi_filter::operator()(rule_set const & source) rule_set * mk_coi_filter::operator()(rule_set const & source)
{ {
if (source.get_num_rules()==0) { if (source.empty()) {
return 0; return 0;
} }
@ -43,7 +43,7 @@ namespace datalog {
decl_set pruned_preds; decl_set pruned_preds;
ptr_vector<func_decl> todo; ptr_vector<func_decl> todo;
{ {
const decl_set& output_preds = m_context.get_output_predicates(); const decl_set& output_preds = source.get_output_predicates();
decl_set::iterator oend = output_preds.end(); decl_set::iterator oend = output_preds.end();
for (decl_set::iterator it = output_preds.begin(); it!=oend; ++it) { for (decl_set::iterator it = output_preds.begin(); it!=oend; ++it) {
todo.push_back(*it); todo.push_back(*it);
@ -70,6 +70,7 @@ namespace datalog {
} }
scoped_ptr<rule_set> res = alloc(rule_set, m_context); scoped_ptr<rule_set> res = alloc(rule_set, m_context);
res->inherit_predicates(source);
rule_set::iterator rend = source.end(); rule_set::iterator rend = source.end();
for (rule_set::iterator rit = source.begin(); rit!=rend; ++rit) { for (rule_set::iterator rit = source.begin(); rit!=rend; ++rit) {

View file

@ -80,8 +80,8 @@ namespace datalog {
virtual bool can_handle_signature(const relation_signature & s) { virtual bool can_handle_signature(const relation_signature & s) {
unsigned n=s.size(); unsigned n=s.size();
for(unsigned i=0; i<n; i++) { for (unsigned i=0; i<n; i++) {
if(!get_context().get_decl_util().is_rule_sort(s[i])) { if (!get_context().get_decl_util().is_rule_sort(s[i])) {
return false; return false;
} }
} }
@ -142,7 +142,7 @@ namespace datalog {
DEBUG_CODE( DEBUG_CODE(
unsigned sz = s.size(); unsigned sz = s.size();
for(unsigned i=0;i<sz; i++) { for (unsigned i=0;i<sz; i++) {
SASSERT( p.get_context().get_decl_util().is_rule_sort(s[i]) ); SASSERT( p.get_context().get_decl_util().is_rule_sort(s[i]) );
} }
); );
@ -162,13 +162,13 @@ namespace datalog {
m_data.resize(get_signature().size()); m_data.resize(get_signature().size());
} }
void unite_with_data(const relation_fact & f) { void unite_with_data(const relation_fact & f) {
if(empty()) { if (empty()) {
assign_data(f); assign_data(f);
return; return;
} }
unsigned n=get_signature().size(); unsigned n=get_signature().size();
SASSERT(f.size()==n); SASSERT(f.size()==n);
for(unsigned i=0; i<n; i++) { for (unsigned i=0; i<n; i++) {
SASSERT(!is_undefined(i)); SASSERT(!is_undefined(i));
m_data[i] = get_plugin().mk_union(m_data[i], f[i]); m_data[i] = get_plugin().mk_union(m_data[i], f[i]);
} }
@ -193,12 +193,12 @@ namespace datalog {
return m_data[col_idx]==0; return m_data[col_idx]==0;
} }
bool no_undefined() const { bool no_undefined() const {
if(empty()) { if (empty()) {
return true; return true;
} }
unsigned n = get_signature().size(); unsigned n = get_signature().size();
for(unsigned i=0; i<n; i++) { for (unsigned i=0; i<n; i++) {
if(is_undefined(i)) { if (is_undefined(i)) {
return false; return false;
} }
} }
@ -231,14 +231,14 @@ namespace datalog {
virtual relation_base * complement(func_decl* pred) const { virtual relation_base * complement(func_decl* pred) const {
explanation_relation * res = static_cast<explanation_relation *>(get_plugin().mk_empty(get_signature())); explanation_relation * res = static_cast<explanation_relation *>(get_plugin().mk_empty(get_signature()));
if(empty()) { if (empty()) {
res->set_undefined(); res->set_undefined();
} }
return res; return res;
} }
void display_explanation(app * expl, std::ostream & out) const { void display_explanation(app * expl, std::ostream & out) const {
if(expl) { if (expl) {
//TODO: some nice explanation output //TODO: some nice explanation output
ast_smt_pp pp(get_plugin().get_ast_manager()); ast_smt_pp pp(get_plugin().get_ast_manager());
pp.display_expr_smt2(out, expl); pp.display_expr_smt2(out, expl);
@ -249,13 +249,13 @@ namespace datalog {
} }
virtual void display(std::ostream & out) const { virtual void display(std::ostream & out) const {
if(empty()) { if (empty()) {
out << "<empty explanation relation>\n"; out << "<empty explanation relation>\n";
return; return;
} }
unsigned sz = get_signature().size(); unsigned sz = get_signature().size();
for(unsigned i=0; i<sz; i++) { for (unsigned i=0; i<sz; i++) {
if(i!=0) { if (i!=0) {
out << ", "; out << ", ";
} }
display_explanation(m_data[0], out); display_explanation(m_data[0], out);
@ -305,7 +305,7 @@ namespace datalog {
explanation_relation_plugin & plugin = r1.get_plugin(); explanation_relation_plugin & plugin = r1.get_plugin();
explanation_relation * res = static_cast<explanation_relation *>(plugin.mk_empty(get_result_signature())); explanation_relation * res = static_cast<explanation_relation *>(plugin.mk_empty(get_result_signature()));
if(!r1.empty() && !r2.empty()) { if (!r1.empty() && !r2.empty()) {
res->m_empty = false; res->m_empty = false;
SASSERT(res->m_data.empty()); SASSERT(res->m_data.empty());
res->m_data.append(r1.m_data); res->m_data.append(r1.m_data);
@ -317,10 +317,10 @@ namespace datalog {
relation_join_fn * explanation_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2, relation_join_fn * explanation_relation_plugin::mk_join_fn(const relation_base & r1, const relation_base & r2,
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) { unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) {
if(&r1.get_plugin()!=this || &r2.get_plugin()!=this) { if (&r1.get_plugin()!=this || &r2.get_plugin()!=this) {
return 0; return 0;
} }
if(col_cnt!=0) { if (col_cnt!=0) {
return 0; return 0;
} }
return alloc(join_fn, r1.get_signature(), r2.get_signature()); return alloc(join_fn, r1.get_signature(), r2.get_signature());
@ -337,7 +337,7 @@ namespace datalog {
explanation_relation_plugin & plugin = r.get_plugin(); explanation_relation_plugin & plugin = r.get_plugin();
explanation_relation * res = static_cast<explanation_relation *>(plugin.mk_empty(get_result_signature())); explanation_relation * res = static_cast<explanation_relation *>(plugin.mk_empty(get_result_signature()));
if(!r.empty()) { if (!r.empty()) {
relation_fact proj_data = r.m_data; relation_fact proj_data = r.m_data;
project_out_vector_columns(proj_data, m_removed_cols); project_out_vector_columns(proj_data, m_removed_cols);
res->assign_data(proj_data); res->assign_data(proj_data);
@ -348,7 +348,7 @@ namespace datalog {
relation_transformer_fn * explanation_relation_plugin::mk_project_fn(const relation_base & r, unsigned col_cnt, relation_transformer_fn * explanation_relation_plugin::mk_project_fn(const relation_base & r, unsigned col_cnt,
const unsigned * removed_cols) { const unsigned * removed_cols) {
if(&r.get_plugin()!=this) { if (&r.get_plugin()!=this) {
return 0; return 0;
} }
return alloc(project_fn, r.get_signature(), col_cnt, removed_cols); return alloc(project_fn, r.get_signature(), col_cnt, removed_cols);
@ -365,7 +365,7 @@ namespace datalog {
explanation_relation_plugin & plugin = r.get_plugin(); explanation_relation_plugin & plugin = r.get_plugin();
explanation_relation * res = static_cast<explanation_relation *>(plugin.mk_empty(get_result_signature())); explanation_relation * res = static_cast<explanation_relation *>(plugin.mk_empty(get_result_signature()));
if(!r.empty()) { if (!r.empty()) {
relation_fact permutated_data = r.m_data; relation_fact permutated_data = r.m_data;
permutate_by_cycle(permutated_data, m_cycle); permutate_by_cycle(permutated_data, m_cycle);
res->assign_data(permutated_data); res->assign_data(permutated_data);
@ -389,16 +389,16 @@ namespace datalog {
explanation_relation * delta = delta0 ? static_cast<explanation_relation *>(delta0) : 0; explanation_relation * delta = delta0 ? static_cast<explanation_relation *>(delta0) : 0;
explanation_relation_plugin & plugin = tgt.get_plugin(); explanation_relation_plugin & plugin = tgt.get_plugin();
if(!src.no_undefined() || !tgt.no_undefined() || (delta && !delta->no_undefined())) { if (!src.no_undefined() || !tgt.no_undefined() || (delta && !delta->no_undefined())) {
UNREACHABLE(); UNREACHABLE();
} }
if(src.empty()) { if (src.empty()) {
return; return;
} }
if(plugin.m_relation_level_explanations) { if (plugin.m_relation_level_explanations) {
tgt.unite_with_data(src.m_data); tgt.unite_with_data(src.m_data);
if(delta) { if (delta) {
if(!m_delta_union_fun) { if (!m_delta_union_fun) {
m_delta_union_fun = plugin.get_manager().mk_union_fn(*delta, src); m_delta_union_fun = plugin.get_manager().mk_union_fn(*delta, src);
SASSERT(m_delta_union_fun); SASSERT(m_delta_union_fun);
} }
@ -406,9 +406,9 @@ namespace datalog {
} }
} }
else { else {
if(tgt.empty()) { if (tgt.empty()) {
tgt.assign_data(src.m_data); tgt.assign_data(src.m_data);
if(delta && delta->empty()) { if (delta && delta->empty()) {
delta->assign_data(src.m_data); delta->assign_data(src.m_data);
} }
} }
@ -423,11 +423,11 @@ namespace datalog {
explanation_relation & tgt = static_cast<explanation_relation &>(tgt0); explanation_relation & tgt = static_cast<explanation_relation &>(tgt0);
explanation_relation * delta = delta0 ? static_cast<explanation_relation *>(delta0) : 0; explanation_relation * delta = delta0 ? static_cast<explanation_relation *>(delta0) : 0;
if(src.empty()) { if (src.empty()) {
return; return;
} }
tgt.set_undefined(); tgt.set_undefined();
if(delta) { if (delta) {
delta->set_undefined(); delta->set_undefined();
} }
} }
@ -435,10 +435,10 @@ namespace datalog {
relation_union_fn * explanation_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src, relation_union_fn * explanation_relation_plugin::mk_union_fn(const relation_base & tgt, const relation_base & src,
const relation_base * delta) { const relation_base * delta) {
if(!check_kind(tgt) || (delta && !check_kind(*delta))) { if (!check_kind(tgt) || (delta && !check_kind(*delta))) {
return 0; return 0;
} }
if(!check_kind(src)) { if (!check_kind(src)) {
//this is to handle the product relation //this is to handle the product relation
return alloc(foreign_union_fn); return alloc(foreign_union_fn);
} }
@ -460,7 +460,7 @@ namespace datalog {
virtual void operator()(relation_base & r0) { virtual void operator()(relation_base & r0) {
explanation_relation & r = static_cast<explanation_relation &>(r0); explanation_relation & r = static_cast<explanation_relation &>(r0);
if(!r.is_undefined(m_col_idx)) { if (!r.is_undefined(m_col_idx)) {
UNREACHABLE(); UNREACHABLE();
} }
@ -468,7 +468,7 @@ namespace datalog {
ptr_vector<expr> subst_arg; ptr_vector<expr> subst_arg;
subst_arg.resize(sz, 0); subst_arg.resize(sz, 0);
unsigned ofs = sz-1; unsigned ofs = sz-1;
for(unsigned i=0; i<sz; i++) { for (unsigned i=0; i<sz; i++) {
SASSERT(!r.is_undefined(i) || !contains_var(m_new_rule, i)); SASSERT(!r.is_undefined(i) || !contains_var(m_new_rule, i));
subst_arg[ofs-i] = r.m_data.get(i); subst_arg[ofs-i] = r.m_data.get(i);
} }
@ -480,26 +480,26 @@ namespace datalog {
relation_mutator_fn * explanation_relation_plugin::mk_filter_interpreted_fn(const relation_base & r, relation_mutator_fn * explanation_relation_plugin::mk_filter_interpreted_fn(const relation_base & r,
app * cond) { app * cond) {
if(&r.get_plugin()!=this) { if (&r.get_plugin()!=this) {
return 0; return 0;
} }
ast_manager & m = get_ast_manager(); ast_manager & m = get_ast_manager();
if(!m.is_eq(cond)) { if (!m.is_eq(cond)) {
return 0; return 0;
} }
expr * arg1 = cond->get_arg(0); expr * arg1 = cond->get_arg(0);
expr * arg2 = cond->get_arg(1); expr * arg2 = cond->get_arg(1);
if(is_var(arg2)) { if (is_var(arg2)) {
std::swap(arg1, arg2); std::swap(arg1, arg2);
} }
if(!is_var(arg1) || !is_app(arg2)) { if (!is_var(arg1) || !is_app(arg2)) {
return 0; return 0;
} }
var * col_var = to_var(arg1); var * col_var = to_var(arg1);
app * new_rule = to_app(arg2); app * new_rule = to_app(arg2);
if(!get_context().get_decl_util().is_rule_sort(col_var->get_sort())) { if (!get_context().get_decl_util().is_rule_sort(col_var->get_sort())) {
return 0; return 0;
} }
unsigned col_idx = col_var->get_idx(); unsigned col_idx = col_var->get_idx();
@ -511,7 +511,7 @@ namespace datalog {
class explanation_relation_plugin::negation_filter_fn : public relation_intersection_filter_fn { class explanation_relation_plugin::negation_filter_fn : public relation_intersection_filter_fn {
public: public:
virtual void operator()(relation_base & r, const relation_base & neg) { virtual void operator()(relation_base & r, const relation_base & neg) {
if(!neg.empty()) { if (!neg.empty()) {
r.reset(); r.reset();
} }
} }
@ -520,7 +520,7 @@ namespace datalog {
relation_intersection_filter_fn * explanation_relation_plugin::mk_filter_by_negation_fn(const relation_base & r, relation_intersection_filter_fn * explanation_relation_plugin::mk_filter_by_negation_fn(const relation_base & r,
const relation_base & neg, unsigned joined_col_cnt, const unsigned * t_cols, const relation_base & neg, unsigned joined_col_cnt, const unsigned * t_cols,
const unsigned * negated_cols) { const unsigned * negated_cols) {
if(&r.get_plugin()!=this || &neg.get_plugin()!=this) { if (&r.get_plugin()!=this || &neg.get_plugin()!=this) {
return 0; return 0;
} }
return alloc(negation_filter_fn); return alloc(negation_filter_fn);
@ -537,26 +537,26 @@ namespace datalog {
explanation_relation & tgt = static_cast<explanation_relation &>(tgt0); explanation_relation & tgt = static_cast<explanation_relation &>(tgt0);
const explanation_relation & src = static_cast<const explanation_relation &>(src0); const explanation_relation & src = static_cast<const explanation_relation &>(src0);
if(src.empty()) { if (src.empty()) {
tgt.reset(); tgt.reset();
return; return;
} }
if(tgt.empty()) { if (tgt.empty()) {
return; return;
} }
unsigned sz = tgt.get_signature().size(); unsigned sz = tgt.get_signature().size();
for(unsigned i=0; i<sz; i++) { for (unsigned i=0; i<sz; i++) {
if(src.is_undefined(i)) { if (src.is_undefined(i)) {
continue; continue;
} }
app * curr_src = src.m_data.get(i); app * curr_src = src.m_data.get(i);
if(tgt.is_undefined(i)) { if (tgt.is_undefined(i)) {
tgt.m_data.set(i, curr_src); tgt.m_data.set(i, curr_src);
continue; continue;
} }
app * curr_tgt = tgt.m_data.get(i); app * curr_tgt = tgt.m_data.get(i);
if(curr_tgt->get_decl()==m_union_decl.get()) { if (curr_tgt->get_decl()==m_union_decl.get()) {
if(curr_tgt->get_arg(0)==curr_src || curr_tgt->get_arg(1)==curr_src) { if (curr_tgt->get_arg(0)==curr_src || curr_tgt->get_arg(1)==curr_src) {
tgt.m_data.set(i, curr_src); tgt.m_data.set(i, curr_src);
continue; continue;
} }
@ -570,18 +570,18 @@ namespace datalog {
relation_intersection_filter_fn * explanation_relation_plugin::mk_filter_by_intersection_fn( relation_intersection_filter_fn * explanation_relation_plugin::mk_filter_by_intersection_fn(
const relation_base & tgt, const relation_base & src, unsigned joined_col_cnt, const relation_base & tgt, const relation_base & src, unsigned joined_col_cnt,
const unsigned * tgt_cols, const unsigned * src_cols) { const unsigned * tgt_cols, const unsigned * src_cols) {
if(&tgt.get_plugin()!=this || &src.get_plugin()!=this) { if (&tgt.get_plugin()!=this || &src.get_plugin()!=this) {
return 0; return 0;
} }
//this checks the join is one to one on all columns //this checks the join is one to one on all columns
if(tgt.get_signature()!=src.get_signature() if (tgt.get_signature()!=src.get_signature()
|| joined_col_cnt!=tgt.get_signature().size() || joined_col_cnt!=tgt.get_signature().size()
|| !containers_equal(tgt_cols, tgt_cols+joined_col_cnt, src_cols, src_cols+joined_col_cnt)) { || !containers_equal(tgt_cols, tgt_cols+joined_col_cnt, src_cols, src_cols+joined_col_cnt)) {
return 0; return 0;
} }
counter ctr; counter ctr;
ctr.count(joined_col_cnt, tgt_cols); ctr.count(joined_col_cnt, tgt_cols);
if(ctr.get_max_counter_value()>1 || (joined_col_cnt && ctr.get_max_positive()!=joined_col_cnt-1)) { if (ctr.get_max_counter_value()>1 || (joined_col_cnt && ctr.get_max_positive()!=joined_col_cnt-1)) {
return 0; return 0;
} }
return alloc(intersection_filter_fn, *this); return alloc(intersection_filter_fn, *this);
@ -595,23 +595,23 @@ namespace datalog {
// ----------------------------------- // -----------------------------------
mk_explanations::mk_explanations(context & ctx, bool relation_level) mk_explanations::mk_explanations(context & ctx)
: plugin(50000), : plugin(50000),
m_manager(ctx.get_manager()), m_manager(ctx.get_manager()),
m_context(ctx), m_context(ctx),
m_decl_util(ctx.get_decl_util()), m_decl_util(ctx.get_decl_util()),
m_relation_level(relation_level), m_relation_level(ctx.explanations_on_relation_level()),
m_pinned(m_manager) { m_pinned(m_manager) {
m_e_sort = m_decl_util.mk_rule_sort(); m_e_sort = m_decl_util.mk_rule_sort();
m_pinned.push_back(m_e_sort); m_pinned.push_back(m_e_sort);
relation_manager & rmgr = ctx.get_rel_context().get_rmanager(); relation_manager & rmgr = ctx.get_rel_context().get_rmanager();
symbol er_symbol = explanation_relation_plugin::get_name(relation_level); symbol er_symbol = explanation_relation_plugin::get_name(m_relation_level);
m_er_plugin = static_cast<explanation_relation_plugin *>(rmgr.get_relation_plugin(er_symbol)); m_er_plugin = static_cast<explanation_relation_plugin *>(rmgr.get_relation_plugin(er_symbol));
if(!m_er_plugin) { if (!m_er_plugin) {
m_er_plugin = alloc(explanation_relation_plugin, relation_level, rmgr); m_er_plugin = alloc(explanation_relation_plugin, m_relation_level, rmgr);
rmgr.register_plugin(m_er_plugin); rmgr.register_plugin(m_er_plugin);
if(!m_relation_level) { if (!m_relation_level) {
DEBUG_CODE( DEBUG_CODE(
finite_product_relation_plugin * dummy; finite_product_relation_plugin * dummy;
SASSERT(!rmgr.try_get_finite_product_relation_plugin(*m_er_plugin, dummy)); SASSERT(!rmgr.try_get_finite_product_relation_plugin(*m_er_plugin, dummy));
@ -620,7 +620,7 @@ namespace datalog {
} }
} }
DEBUG_CODE( DEBUG_CODE(
if(!m_relation_level) { if (!m_relation_level) {
finite_product_relation_plugin * dummy; finite_product_relation_plugin * dummy;
SASSERT(rmgr.try_get_finite_product_relation_plugin(*m_er_plugin, dummy)); SASSERT(rmgr.try_get_finite_product_relation_plugin(*m_er_plugin, dummy));
} }
@ -668,7 +668,7 @@ namespace datalog {
func_decl * mk_explanations::get_e_decl(func_decl * orig_decl) { func_decl * mk_explanations::get_e_decl(func_decl * orig_decl) {
decl_map::obj_map_entry * e = m_e_decl_map.insert_if_not_there2(orig_decl, 0); decl_map::obj_map_entry * e = m_e_decl_map.insert_if_not_there2(orig_decl, 0);
if(e->get_data().m_value==0) { if (e->get_data().m_value==0) {
relation_signature e_domain; relation_signature e_domain;
e_domain.append(orig_decl->get_arity(), orig_decl->get_domain()); e_domain.append(orig_decl->get_arity(), orig_decl->get_domain());
e_domain.push_back(m_e_sort); e_domain.push_back(m_e_sort);
@ -677,7 +677,7 @@ namespace datalog {
m_pinned.push_back(new_decl); m_pinned.push_back(new_decl);
e->get_data().m_value = new_decl; e->get_data().m_value = new_decl;
if(m_relation_level) { if (m_relation_level) {
assign_rel_level_kind(new_decl, orig_decl); assign_rel_level_kind(new_decl, orig_decl);
} }
} }
@ -716,13 +716,13 @@ namespace datalog {
app_ref_vector e_tail(m_manager); app_ref_vector e_tail(m_manager);
svector<bool> neg_flags; svector<bool> neg_flags;
unsigned pos_tail_sz = r->get_positive_tail_size(); unsigned pos_tail_sz = r->get_positive_tail_size();
for(unsigned i=0; i<pos_tail_sz; i++) { for (unsigned i=0; i<pos_tail_sz; i++) {
unsigned e_var = next_var++; unsigned e_var = next_var++;
e_tail.push_back(get_e_lit(r->get_tail(i), e_var)); e_tail.push_back(get_e_lit(r->get_tail(i), e_var));
neg_flags.push_back(false); neg_flags.push_back(false);
} }
unsigned tail_sz = r->get_tail_size(); unsigned tail_sz = r->get_tail_size();
for(unsigned i=pos_tail_sz; i<tail_sz; i++) { for (unsigned i=pos_tail_sz; i<tail_sz; i++) {
e_tail.push_back(r->get_tail(i)); e_tail.push_back(r->get_tail(i));
neg_flags.push_back(r->is_neg_tail(i)); neg_flags.push_back(r->is_neg_tail(i));
} }
@ -730,9 +730,9 @@ namespace datalog {
symbol rule_repr = get_rule_symbol(r); symbol rule_repr = get_rule_symbol(r);
expr_ref_vector rule_expr_args(m_manager); expr_ref_vector rule_expr_args(m_manager);
for(unsigned tail_idx=0; tail_idx<pos_tail_sz; tail_idx++) { for (unsigned tail_idx=0; tail_idx<pos_tail_sz; tail_idx++) {
app * tail = e_tail.get(tail_idx); app * tail = e_tail.get(tail_idx);
if(true || m_relation_level) { if (true || m_relation_level) {
//this adds the explanation term of the tail //this adds the explanation term of the tail
rule_expr_args.push_back(tail->get_arg(tail->get_num_args()-1)); rule_expr_args.push_back(tail->get_arg(tail->get_num_args()-1));
} }
@ -754,37 +754,32 @@ namespace datalog {
return m_context.get_rule_manager().mk(e_head, e_tail.size(), e_tail.c_ptr(), neg_flags.c_ptr()); return m_context.get_rule_manager().mk(e_head, e_tail.size(), e_tail.c_ptr(), neg_flags.c_ptr());
} }
void mk_explanations::transform_rules(const rule_set & orig, rule_set & tgt) { void mk_explanations::transform_rules(const rule_set & src, rule_set & dst) {
rule_set::iterator rit = orig.begin(); rule_set::iterator rit = src.begin();
rule_set::iterator rend = orig.end(); rule_set::iterator rend = src.end();
for(; rit!=rend; ++rit) { for (; rit!=rend; ++rit) {
rule * e_rule = get_e_rule(*rit); rule * e_rule = get_e_rule(*rit);
tgt.add_rule(e_rule); dst.add_rule(e_rule);
} }
//add rules that will (for output predicates) copy facts from explained relations back to //add rules that will (for output predicates) copy facts from explained relations back to
//the original ones //the original ones
expr_ref_vector lit_args(m_manager); expr_ref_vector lit_args(m_manager);
decl_set::iterator pit = m_original_preds.begin(); decl_set::iterator pit = src.get_output_predicates().begin();
decl_set::iterator pend = m_original_preds.end(); decl_set::iterator pend = src.get_output_predicates().end();
for(; pit!=pend; ++pit) { for (; pit != pend; ++pit) {
func_decl * orig_decl = *pit; func_decl * orig_decl = *pit;
if(!m_context.is_output_predicate(orig_decl)) {
continue;
}
lit_args.reset(); lit_args.reset();
unsigned arity = orig_decl->get_arity(); unsigned arity = orig_decl->get_arity();
for(unsigned i=0; i<arity; i++) { for (unsigned i=0; i<arity; i++) {
lit_args.push_back(m_manager.mk_var(i, orig_decl->get_domain(i))); lit_args.push_back(m_manager.mk_var(i, orig_decl->get_domain(i)));
} }
app_ref orig_lit(m_manager.mk_app(orig_decl, lit_args.c_ptr()), m_manager); app_ref orig_lit(m_manager.mk_app(orig_decl, lit_args.c_ptr()), m_manager);
app_ref e_lit(get_e_lit(orig_lit, arity), m_manager); app_ref e_lit(get_e_lit(orig_lit, arity), m_manager);
app * tail[] = { e_lit.get() }; app * tail[] = { e_lit.get() };
tgt.add_rule(m_context.get_rule_manager().mk(orig_lit, 1, tail, 0)); dst.add_rule(m_context.get_rule_manager().mk(orig_lit, 1, tail, 0));
} }
} }
void mk_explanations::translate_rel_level_relation(relation_manager & rmgr, relation_base & orig, void mk_explanations::translate_rel_level_relation(relation_manager & rmgr, relation_base & orig,
@ -799,7 +794,7 @@ namespace datalog {
sieve_relation * srels[] = { sieve_relation * srels[] = {
static_cast<sieve_relation *>(&prod_rel[0]), static_cast<sieve_relation *>(&prod_rel[0]),
static_cast<sieve_relation *>(&prod_rel[1]) }; static_cast<sieve_relation *>(&prod_rel[1]) };
if(&srels[0]->get_inner().get_plugin()==m_er_plugin) { if (&srels[0]->get_inner().get_plugin()==m_er_plugin) {
std::swap(srels[0], srels[1]); std::swap(srels[0], srels[1]);
} }
SASSERT(&srels[0]->get_inner().get_plugin()==&orig.get_plugin()); SASSERT(&srels[0]->get_inner().get_plugin()==&orig.get_plugin());
@ -821,10 +816,9 @@ namespace datalog {
} }
} }
void mk_explanations::transform_facts(relation_manager & rmgr) { void mk_explanations::transform_facts(relation_manager & rmgr, rule_set const& src, rule_set& dst) {
if (!m_e_fact_relation) {
if(!m_e_fact_relation) {
relation_signature expl_singleton_sig; relation_signature expl_singleton_sig;
expl_singleton_sig.push_back(m_e_sort); expl_singleton_sig.push_back(m_e_sort);
@ -836,29 +830,26 @@ namespace datalog {
SASSERT(&expl_singleton->get_plugin()==m_er_plugin); SASSERT(&expl_singleton->get_plugin()==m_er_plugin);
m_e_fact_relation = static_cast<explanation_relation *>(expl_singleton); m_e_fact_relation = static_cast<explanation_relation *>(expl_singleton);
} }
func_decl_set const& predicates = m_context.get_predicates();
decl_set::iterator it = predicates.begin();
decl_set::iterator end = predicates.end();
decl_set::iterator it = m_original_preds.begin(); for (; it!=end; ++it) {
decl_set::iterator end = m_original_preds.end();
for(; it!=end; ++it) {
func_decl * orig_decl = *it; func_decl * orig_decl = *it;
func_decl * e_decl = get_e_decl(orig_decl); func_decl * e_decl = get_e_decl(orig_decl);
if(m_context.is_output_predicate(orig_decl)) { if (!rmgr.try_get_relation(orig_decl) &&
m_context.set_output_predicate(e_decl); !src.contains(orig_decl)) {
} // there are no facts or rules for this predicate
if(!rmgr.try_get_relation(orig_decl)) {
//there are no facts for this predicate
continue; continue;
} }
dst.inherit_predicate(src, orig_decl, e_decl);
relation_base & orig_rel = rmgr.get_relation(orig_decl); relation_base & orig_rel = rmgr.get_relation(orig_decl);
relation_base & e_rel = rmgr.get_relation(e_decl); relation_base & e_rel = rmgr.get_relation(e_decl);
SASSERT(e_rel.empty()); //the e_rel should be a new relation SASSERT(e_rel.empty()); //the e_rel should be a new relation
if(m_relation_level) { if (m_relation_level) {
translate_rel_level_relation(rmgr, orig_rel, e_rel); translate_rel_level_relation(rmgr, orig_rel, e_rel);
} }
else { else {
@ -869,18 +860,19 @@ namespace datalog {
SASSERT(union_fun); SASSERT(union_fun);
(*union_fun)(e_rel, *aux_extended_rel); (*union_fun)(e_rel, *aux_extended_rel);
} }
} }
} }
rule_set * mk_explanations::operator()(rule_set const & source) { rule_set * mk_explanations::operator()(rule_set const & source) {
if(source.get_num_rules()==0) { if (source.empty()) {
return 0;
}
if (!m_context.generate_explanations()) {
return 0; return 0;
} }
m_context.collect_predicates(m_original_preds);
rule_set * res = alloc(rule_set, m_context); rule_set * res = alloc(rule_set, m_context);
transform_facts(m_context.get_rel_context().get_rmanager()); transform_facts(m_context.get_rel_context().get_rmanager(), source, *res);
transform_rules(source, *res); transform_rules(source, *res);
return res; return res;
} }

View file

@ -32,19 +32,13 @@ namespace datalog {
typedef obj_map<func_decl, func_decl *> decl_map; typedef obj_map<func_decl, func_decl *> decl_map;
ast_manager & m_manager; ast_manager & m_manager;
context & m_context; context & m_context;
dl_decl_util & m_decl_util; dl_decl_util & m_decl_util;
bool m_relation_level;
bool m_relation_level;
decl_set m_original_preds;
ast_ref_vector m_pinned; ast_ref_vector m_pinned;
explanation_relation_plugin * m_er_plugin; explanation_relation_plugin * m_er_plugin;
sort * m_e_sort;
sort * m_e_sort;
scoped_rel<explanation_relation> m_e_fact_relation; scoped_rel<explanation_relation> m_e_fact_relation;
decl_map m_e_decl_map; decl_map m_e_decl_map;
@ -62,15 +56,15 @@ namespace datalog {
void assign_rel_level_kind(func_decl * e_decl, func_decl * orig); void assign_rel_level_kind(func_decl * e_decl, func_decl * orig);
void translate_rel_level_relation(relation_manager & rmgr, relation_base & orig, relation_base & e_rel); void translate_rel_level_relation(relation_manager & rmgr, relation_base & orig, relation_base & e_rel);
void transform_rules(const rule_set & orig, rule_set & tgt); void transform_rules(const rule_set & src, rule_set & dst);
void transform_facts(relation_manager & rmgr); void transform_facts(relation_manager & rmgr, rule_set const& src, rule_set& dst);
public: public:
/** /**
If relation_level is true, the explanation will not be stored for each fact, If relation_level is true, the explanation will not be stored for each fact,
but we will rather store history of the whole relation. but we will rather store history of the whole relation.
*/ */
mk_explanations(context & ctx, bool relation_level); mk_explanations(context & ctx);
/** /**
\brief Return explanation predicate that corresponds to \c orig_decl. \brief Return explanation predicate that corresponds to \c orig_decl.

View file

@ -1,379 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
dl_mk_extract_quantifiers.cpp
Abstract:
Remove universal quantifiers over interpreted predicates in the body.
Author:
Nikolaj Bjorner (nbjorner) 2012-11-21
Revision History:
--*/
#include"dl_mk_extract_quantifiers.h"
#include"ast_pp.h"
#include"dl_bmc_engine.h"
#include"smt_quantifier.h"
#include"smt_context.h"
#include"for_each_expr.h"
#include "expr_abstract.h"
namespace datalog {
mk_extract_quantifiers::mk_extract_quantifiers(context & ctx) :
rule_transformer::plugin(101, false),
m_ctx(ctx),
m(ctx.get_manager()),
rm(ctx.get_rule_manager()),
m_query_pred(m)
{}
mk_extract_quantifiers::~mk_extract_quantifiers() {
reset();
}
void mk_extract_quantifiers::set_query(func_decl* q) {
m_query_pred = q;
}
void mk_extract_quantifiers::ensure_predicate(expr* e, unsigned& max_var, app_ref_vector& tail) {
SASSERT(is_app(e));
SASSERT(to_app(e)->get_decl()->get_family_id() == null_family_id);
app* a = to_app(e);
expr_ref_vector args(m);
for (unsigned i = 0; i < a->get_num_args(); ++i) {
expr* arg = a->get_arg(i);
if (is_var(arg) || m.is_value(arg)) {
args.push_back(arg);
}
else {
expr_ref new_var(m);
new_var = m.mk_var(++max_var, m.get_sort(arg));
args.push_back(new_var);
tail.push_back(m.mk_eq(new_var, arg));
}
}
tail.push_back(m.mk_app(a->get_decl(), args.size(), args.c_ptr()));
}
class mk_extract_quantifiers::collect_insts {
ast_manager& m;
ptr_vector<expr> m_binding;
vector<expr_ref_vector> m_bindings;
ptr_vector<quantifier> m_quantifiers;
public:
collect_insts(ast_manager& m): m(m) { }
void operator()(expr* n) {
expr* not_q_or_i, *e1, *e2, *e3;
if (m.is_quant_inst(n, not_q_or_i, m_binding)) {
VERIFY(m.is_or(not_q_or_i, e1, e2));
VERIFY(m.is_not(e1, e3));
SASSERT(is_quantifier(e3));
m_quantifiers.push_back(to_quantifier(e3));
m_bindings.push_back(expr_ref_vector(m,m_binding.size(), m_binding.c_ptr()));
m_binding.reset();
}
else if ((m.is_rewrite(n, e1, e2) ||
(m.is_rewrite_star(n) &&
(e3 = to_app(n)->get_arg(to_app(n)->get_num_args()-1),
e1 = to_app(e3)->get_arg(0),
e2 = to_app(e3)->get_arg(1),
true))) &&
is_quantifier(e1) && m.is_false(e2)) {
quantifier* q = to_quantifier(e1);
m_quantifiers.push_back(q);
m_bindings.push_back(expr_ref_vector(m));
expr_ref_vector& b = m_bindings.back();
for (unsigned i = 0; i < q->get_num_decls(); ++i) {
b.push_back(m.mk_fresh_const("V", q->get_decl_sort(i)));
}
}
}
void reset() {
m_quantifiers.reset();
m_bindings.reset();
}
unsigned size() const { return m_quantifiers.size(); }
ptr_vector<quantifier> const& quantifiers() const { return m_quantifiers; }
vector<expr_ref_vector> const& bindings() const { return m_bindings; }
};
/*
* forall y . P1(x,y) &
* forall y . P2(x,y) &
* Body[x] &
* ~H[x]
* forall y . y != binding1 => ~ P1(x,y)
* forall y . y != binding2 => ~ P2(x,y)
*/
void mk_extract_quantifiers::extract(rule& r, rule_set& new_rules) {
unsigned utsz = r.get_uninterpreted_tail_size();
expr_ref_vector conjs(m);
quantifier_ref_vector qs(m);
for (unsigned i = utsz; i < r.get_tail_size(); ++i) {
conjs.push_back(r.get_tail(i));
}
datalog::flatten_and(conjs);
for (unsigned j = 0; j < conjs.size(); ++j) {
expr* e = conjs[j].get();
quantifier* q;
if (rule_manager::is_forall(m, e, q)) {
qs.push_back(q);
conjs[j] = conjs.back();
conjs.pop_back();
--j;
}
}
if (qs.empty()) {
new_rules.add_rule(&r);
}
else {
expr_ref fml(m);
expr_ref_vector bindings(m);
obj_map<quantifier, expr_ref_vector*> insts;
for (unsigned i = 0; i < qs.size(); ++i) {
insts.insert(qs[i].get(), alloc(expr_ref_vector, m));
}
unsigned max_inst = 10; // TODO configuration.
for (unsigned i = 0; i < max_inst; ++i) {
app_ref_vector sub(m);
rule2formula(r, insts, fml, sub);
bool new_binding = find_instantiations_proof_based(fml, sub, insts, bindings);
if (!new_binding) {
break;
}
}
expr_ref_vector fmls(m);
for (unsigned i = 0; i < utsz; ++i) {
fmls.push_back(r.get_tail(i));
}
fmls.append(bindings);
fmls.append(conjs);
fml = m.mk_implies(m.mk_and(fmls.size(), fmls.c_ptr()), r.get_head());
TRACE("dl", tout << "new rule\n" << mk_pp(fml, m) << "\n";);
rule_ref_vector rules(rm);
proof_ref pr(m);
if (m_ctx.generate_proof_trace()) {
scoped_proof _scp(m);
expr_ref fml1(m);
r.to_formula(fml1);
pr = m.mk_rewrite(fml1, fml);
pr = m.mk_modus_ponens(r.get_proof(), pr);
}
rm.mk_rule(fml, pr, rules, r.name());
for (unsigned i = 0; i < rules.size(); ++i) {
new_rules.add_rule(rules[i].get());
m_quantifiers.insert(rules[i].get(), alloc(quantifier_ref_vector, qs));
}
obj_map<quantifier, expr_ref_vector*>::iterator it = insts.begin(), end = insts.end();
for (; it != end; ++it) {
dealloc(it->m_value);
}
}
}
void mk_extract_quantifiers::rule2formula(
rule& r,
obj_map<quantifier, expr_ref_vector*> const& insts,
expr_ref& fml,
app_ref_vector& sub)
{
expr_ref body(m);
expr_ref_vector fmls(m);
ptr_vector<sort> sorts;
var_subst vs(m, false);
obj_map<quantifier, expr_ref_vector*>::iterator it = insts.begin(), end = insts.end();
for (; it != end; ++it) {
quantifier* q = it->m_key;
expr_ref_vector& eqs = *it->m_value;
expr_ref_vector disj(m);
disj.append(eqs);
disj.push_back(m.mk_not(q->get_expr()));
body = m.mk_or(disj.size(), disj.c_ptr());
fml = m.update_quantifier(q, body);
fmls.push_back(fml);
}
fml = m.mk_or(fmls.size(), fmls.c_ptr());
fmls.reset();
fmls.push_back(fml);
for (unsigned i = 0; i < r.get_tail_size(); ++i) {
SASSERT(!r.is_neg_tail(i));
fmls.push_back(r.get_tail(i));
}
fmls.push_back(m.mk_not(r.get_head()));
fml = m.mk_and(fmls.size(), fmls.c_ptr());
get_free_vars(fml, sorts);
for (unsigned i = 0; i < sorts.size(); ++i) {
if (!sorts[i]) {
sorts[i] = m.mk_bool_sort();
}
sub.push_back(m.mk_const(symbol(i), sorts[i]));
}
vs(fml, sub.size(), (expr*const*)sub.c_ptr(), fml);
}
bool mk_extract_quantifiers::find_instantiations_proof_based(
expr* fml,
app_ref_vector const& var_inst,
obj_map<quantifier, expr_ref_vector*>& insts,
expr_ref_vector& bindings)
{
datalog::scoped_proof _scp(m);
smt_params fparams;
fparams.m_mbqi = true; // false
fparams.m_soft_timeout = 1000;
smt::kernel solver(m, fparams);
solver.assert_expr(fml);
IF_VERBOSE(1, verbose_stream() << "check\n";);
lbool result = solver.check();
IF_VERBOSE(1, verbose_stream() << "checked\n";);
TRACE("dl", tout << result << "\n";);
if (result != l_false) {
return false;
}
map<symbol, quantifier*, symbol_hash_proc, symbol_eq_proc> qid_map;
quantifier* q;
obj_map<quantifier, expr_ref_vector*>::iterator it = insts.begin(), end = insts.end();
for (; it != end; ++it) {
q = it->m_key;
qid_map.insert(q->get_qid(), q);
}
proof* p = solver.get_proof();
TRACE("dl", tout << mk_pp(p, m) << "\n";);
collect_insts collector(m);
for_each_expr(collector, p);
ptr_vector<quantifier> const& quants = collector.quantifiers();
for (unsigned i = 0; i < collector.size(); ++i) {
symbol qid = quants[i]->get_qid();
if (!qid_map.find(qid, q)) {
TRACE("dl", tout << "Could not find quantifier " << mk_pp(quants[i], m) << "\n";);
continue;
}
expr_ref_vector const& binding = collector.bindings()[i];
TRACE("dl", tout << "Instantiating:\n" << mk_pp(quants[i], m) << "\n";
for (unsigned j = 0; j < binding.size(); ++j) {
tout << mk_pp(binding[j], m) << " ";
}
tout << "\n";);
expr_ref_vector instantiation(m);
for (unsigned j = 0; j < binding.size(); ++j) {
instantiation.push_back(binding[j]);
}
add_binding(var_inst, bindings, q, instantiation, insts);
}
return collector.size() > 0;
}
void mk_extract_quantifiers::add_binding(
app_ref_vector const& var_inst,
expr_ref_vector& bindings,
quantifier* q,
expr_ref_vector const& instantiation,
obj_map<quantifier, expr_ref_vector*>& insts)
{
if (instantiation.size() == q->get_num_decls()) {
// Full binding.
apply_binding(var_inst, bindings, q, instantiation, insts);
}
}
void mk_extract_quantifiers::apply_binding(
app_ref_vector const& var_inst,
expr_ref_vector& bindings,
quantifier* q,
expr_ref_vector const& instantiation,
obj_map<quantifier, expr_ref_vector*>& insts)
{
datalog::scoped_no_proof _scp(m);
expr_ref e(m);
expr_ref_vector eqs(m);
var_subst vs(m, false);
inv_var_shifter invsh(m);
vs(q->get_expr(), instantiation.size(), instantiation.c_ptr(), e);
invsh(e, q->get_num_decls(), e);
expr_ref_vector inst(m);
inst.append(var_inst.size(), (expr*const*)var_inst.c_ptr());
inst.reverse();
expr_abstract(m, 0, inst.size(), inst.c_ptr(), e, e);
bindings.push_back(e);
for (unsigned i = 0; i < instantiation.size(); ++i) {
e = instantiation[i];
e = m.mk_eq(m.mk_var(i, q->get_decl_sort(i)), e);
eqs.push_back(e);
}
e = m.mk_and(eqs.size(), eqs.c_ptr());
insts.find(q)->push_back(e);
TRACE("dl", tout << mk_pp(q, m) << "\n";
tout << "instantiation: ";
for (unsigned i = 0; i < instantiation.size(); ++i) {
tout << mk_pp(instantiation[i], m) << " ";
}
tout << "\n";
tout << "inst: ";
for (unsigned i = 0; i < var_inst.size(); ++i) {
tout << mk_pp(var_inst[i], m) << " ";
}
tout << "\n";
tout << mk_pp(bindings.back(), m) << "\n";
tout << "eqs: " << mk_pp(e, m) << "\n";
);
}
void mk_extract_quantifiers::reset() {
obj_map<rule const, quantifier_ref_vector*>::iterator it = m_quantifiers.begin(),
end = m_quantifiers.end();
for (; it != end; ++it) {
dealloc(it->m_value);
}
m_has_quantifiers = false;
m_quantifiers.reset();
}
rule_set * mk_extract_quantifiers::operator()(rule_set const & source) {
reset();
rule_set::iterator it = source.begin(), end = source.end();
for (; !m_has_quantifiers && it != end; ++it) {
m_has_quantifiers = (*it)->has_quantifiers();
}
if (!m_has_quantifiers) {
return 0;
}
rule_set* rules = alloc(rule_set, m_ctx);
it = source.begin();
for (; it != end; ++it) {
extract(**it, *rules);
}
return rules;
}
};

View file

@ -1,99 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
dl_mk_extract_quantifiers.h
Abstract:
Replace universal quantifiers over interpreted predicates in the body
by instantiations mined using bounded model checking search.
Author:
Nikolaj Bjorner (nbjorner) 2012-11-21
Revision History:
--*/
#ifndef _DL_MK_EXTRACT_QUANTIFIERS_H_
#define _DL_MK_EXTRACT_QUANTIFIERS_H_
#include"dl_context.h"
#include"dl_rule_set.h"
#include"dl_rule_transformer.h"
#include"obj_pair_hashtable.h"
namespace datalog {
/**
\brief Extract universal quantifiers from rules.
*/
class mk_extract_quantifiers : public rule_transformer::plugin {
class collect_insts;
context& m_ctx;
ast_manager& m;
rule_manager& rm;
func_decl_ref m_query_pred;
bool m_has_quantifiers;
obj_map<rule const, quantifier_ref_vector*> m_quantifiers;
void reset();
void extract(rule& r, rule_set& new_rules);
void rule2formula(
rule& r,
obj_map<quantifier, expr_ref_vector*> const& insts,
expr_ref& fml,
app_ref_vector& sub);
void add_binding(
app_ref_vector const& var_inst,
expr_ref_vector& bindings,
quantifier* q,
expr_ref_vector const& instantiation,
obj_map<quantifier, expr_ref_vector*>& insts);
void apply_binding(
app_ref_vector const& var_inst,
expr_ref_vector& bindings,
quantifier* q,
expr_ref_vector const& instantiation,
obj_map<quantifier, expr_ref_vector*>& insts);
public:
/**
\brief Create rule transformer that extracts universal quantifiers (over recursive predicates).
*/
mk_extract_quantifiers(context & ctx);
virtual ~mk_extract_quantifiers();
void set_query(func_decl* q);
rule_set * operator()(rule_set const & source);
bool has_quantifiers() { return m_has_quantifiers; }
obj_map<rule const, quantifier_ref_vector*>& quantifiers() { return m_quantifiers; }
void ensure_predicate(expr* e, unsigned& max_var, app_ref_vector& tail);
bool find_instantiations_proof_based(
expr* fml,
app_ref_vector const& var_inst,
obj_map<quantifier, expr_ref_vector*>& insts,
expr_ref_vector& bindings);
};
};
#endif /* _DL_MK_EXTRACT_QUANTIFIERS_H_ */

View file

@ -31,6 +31,7 @@ namespace datalog {
m_result(0), m_result(0),
m_pinned(m_manager) { m_pinned(m_manager) {
} }
mk_filter_rules::~mk_filter_rules() { mk_filter_rules::~mk_filter_rules() {
ptr_vector<filter_key> to_dealloc; ptr_vector<filter_key> to_dealloc;
filter_cache::iterator it = m_tail2filter.begin(); filter_cache::iterator it = m_tail2filter.begin();
@ -50,7 +51,7 @@ namespace datalog {
\brief Return true if \c pred is a cadidate for a "filter" rule. \brief Return true if \c pred is a cadidate for a "filter" rule.
*/ */
bool mk_filter_rules::is_candidate(app * pred) { bool mk_filter_rules::is_candidate(app * pred) {
if (!m_context.get_rule_manager().is_predicate(pred)) { if (!m_context.is_predicate(pred)) {
TRACE("mk_filter_rules", tout << mk_pp(pred, m_manager) << "\nis not a candidate because it is interpreted.\n";); TRACE("mk_filter_rules", tout << mk_pp(pred, m_manager) << "\nis not a candidate because it is interpreted.\n";);
return false; return false;
} }
@ -157,13 +158,13 @@ namespace datalog {
m_modified = false; m_modified = false;
unsigned num_rules = source.get_num_rules(); unsigned num_rules = source.get_num_rules();
for (unsigned i = 0; i < num_rules; i++) { for (unsigned i = 0; i < num_rules; i++) {
rule * r = source.get_rule(i); process(source.get_rule(i));
process(r);
} }
if(!m_modified) { if(!m_modified) {
dealloc(m_result); dealloc(m_result);
return static_cast<rule_set *>(0); return static_cast<rule_set *>(0);
} }
m_result->inherit_predicates(source);
return m_result; return m_result;
} }

View file

@ -587,6 +587,7 @@ namespace datalog {
dealloc(res); dealloc(res);
res = 0; res = 0;
} }
res->inherit_predicates(source);
return res; return res;
} }

View file

@ -199,15 +199,15 @@ namespace datalog {
return 0; return 0;
} }
} }
m_inner_ctx.reset();
rel_context& rctx = m_inner_ctx.get_rel_context(); rel_context& rctx = m_inner_ctx.get_rel_context();
ptr_vector<func_decl> heads; ptr_vector<func_decl> heads;
m_inner_ctx.ensure_opened(); func_decl_set const& predicates = m_ctx.get_predicates();
it = source.begin(); for (func_decl_set::iterator fit = predicates.begin(); fit != predicates.end(); ++fit) {
for (; it != end; ++it) { m_inner_ctx.register_predicate(*fit, false);
rule_ref r(*it, m_inner_ctx.get_rule_manager());
m_inner_ctx.add_rule(r);
m_inner_ctx.register_predicate(r->get_decl(), false);
} }
m_inner_ctx.ensure_opened();
m_inner_ctx.replace_rules(source);
m_inner_ctx.close(); m_inner_ctx.close();
rule_set::decl2rules::iterator dit = source.begin_grouped_rules(); rule_set::decl2rules::iterator dit = source.begin_grouped_rules();
rule_set::decl2rules::iterator dend = source.end_grouped_rules(); rule_set::decl2rules::iterator dend = source.end_grouped_rules();
@ -237,6 +237,7 @@ namespace datalog {
m_ctx.add_model_converter(kmc); m_ctx.add_model_converter(kmc);
} }
TRACE("dl", rules->display(tout);); TRACE("dl", rules->display(tout););
rules->inherit_predicates(source);
return rules; return rules;
} }

View file

@ -25,6 +25,7 @@ namespace datalog {
mk_loop_counter::mk_loop_counter(context & ctx, unsigned priority): mk_loop_counter::mk_loop_counter(context & ctx, unsigned priority):
plugin(priority), plugin(priority),
m(ctx.get_manager()), m(ctx.get_manager()),
m_ctx(ctx),
a(m), a(m),
m_refs(m) { m_refs(m) {
} }
@ -72,14 +73,14 @@ namespace datalog {
for (unsigned j = 0; j < utsz; ++j, ++cnt) { for (unsigned j = 0; j < utsz; ++j, ++cnt) {
tail.push_back(add_arg(r.get_tail(j), cnt)); tail.push_back(add_arg(r.get_tail(j), cnt));
neg.push_back(r.is_neg_tail(j)); neg.push_back(r.is_neg_tail(j));
ctx.register_predicate(tail.back()->get_decl(), false); m_ctx.register_predicate(tail.back()->get_decl(), false);
} }
for (unsigned j = utsz; j < tsz; ++j) { for (unsigned j = utsz; j < tsz; ++j) {
tail.push_back(r.get_tail(j)); tail.push_back(r.get_tail(j));
neg.push_back(false); neg.push_back(false);
} }
head = add_arg(r.get_head(), cnt); head = add_arg(r.get_head(), cnt);
ctx.register_predicate(head->get_decl(), false); m_ctx.register_predicate(head->get_decl(), false);
// set the loop counter to be an increment of the previous // set the loop counter to be an increment of the previous
bool found = false; bool found = false;
unsigned last = head->get_num_args()-1; unsigned last = head->get_num_args()-1;
@ -107,6 +108,8 @@ namespace datalog {
// model converter: remove references to extra argument. // model converter: remove references to extra argument.
// proof converter: remove references to extra argument as well. // proof converter: remove references to extra argument as well.
result->inherit_predicates(source);
return result; return result;
} }

View file

@ -26,6 +26,7 @@ namespace datalog {
class mk_loop_counter : public rule_transformer::plugin { class mk_loop_counter : public rule_transformer::plugin {
ast_manager& m; ast_manager& m;
context& m_ctx;
arith_util a; arith_util a;
func_decl_ref_vector m_refs; func_decl_ref_vector m_refs;
obj_map<func_decl, func_decl*> m_new2old; obj_map<func_decl, func_decl*> m_new2old;

View file

@ -24,13 +24,12 @@ Revision History:
namespace datalog { namespace datalog {
mk_magic_sets::mk_magic_sets(context & ctx, rule * goal_rule) : mk_magic_sets::mk_magic_sets(context & ctx, func_decl* goal) :
plugin(10000, true), plugin(10000, true),
m_context(ctx), m_context(ctx),
m_manager(ctx.get_manager()), m(ctx.get_manager()),
m_rules(ctx.get_rule_manager()), m_pinned(m),
m_pinned(m_manager), m_goal(goal, m) {
m_goal_rule(goal_rule, ctx.get_rule_manager()) {
} }
void mk_magic_sets::reset() { void mk_magic_sets::reset() {
@ -39,14 +38,13 @@ namespace datalog {
m_adorned_preds.reset(); m_adorned_preds.reset();
m_adornments.reset(); m_adornments.reset();
m_magic_preds.reset(); m_magic_preds.reset();
m_rules.reset();
m_pinned.reset(); m_pinned.reset();
} }
void mk_magic_sets::adornment::populate(app * lit, const var_idx_set & bound_vars) { void mk_magic_sets::adornment::populate(app * lit, const var_idx_set & bound_vars) {
SASSERT(empty()); SASSERT(empty());
unsigned arity = lit->get_num_args(); unsigned arity = lit->get_num_args();
for(unsigned i=0; i<arity; i++) { for (unsigned i = 0; i < arity; i++) {
const expr * arg = lit->get_arg(i); const expr * arg = lit->get_arg(i);
bool bound = !is_var(arg) || bound_vars.contains(to_var(arg)->get_idx()); bool bound = !is_var(arg) || bound_vars.contains(to_var(arg)->get_idx());
push_back(bound ? AD_BOUND : AD_FREE); push_back(bound ? AD_BOUND : AD_FREE);
@ -57,17 +55,8 @@ namespace datalog {
std::string res; std::string res;
const_iterator eit = begin(); const_iterator eit = begin();
const_iterator eend = end(); const_iterator eend = end();
for(; eit!=eend; ++eit) { for (; eit != eend; ++eit) {
switch(*eit) { res += (*eit == AD_BOUND)?'b':'f';
case AD_BOUND:
res+='b';
break;
case AD_FREE:
res+='f';
break;
default:
UNREACHABLE();
}
} }
return res; return res;
} }
@ -75,14 +64,13 @@ namespace datalog {
unsigned get_bound_arg_count(app * lit, const var_idx_set & bound_vars) { unsigned get_bound_arg_count(app * lit, const var_idx_set & bound_vars) {
unsigned res = 0; unsigned res = 0;
unsigned n = lit->get_num_args(); unsigned n = lit->get_num_args();
for(unsigned i=0; i<n; i++) { for (unsigned i = 0; i < n; i++) {
const expr * arg = lit->get_arg(i); const expr * arg = lit->get_arg(i);
if(is_var(arg) && !bound_vars.contains(to_var(arg)->get_idx())) { if (!is_var(arg) || bound_vars.contains(to_var(arg)->get_idx())) {
continue; SASSERT(is_var(arg) || is_app(arg));
SASSERT(!is_app(arg) || to_app(arg)->get_num_args()==0);
res++;
} }
SASSERT(is_var(arg) || is_app(arg));
SASSERT(!is_app(arg) || to_app(arg)->get_num_args()==0);
res++;
} }
return res; return res;
} }
@ -91,10 +79,10 @@ namespace datalog {
func_decl * pred = lit->get_decl(); func_decl * pred = lit->get_decl();
float res = 1; float res = 1;
unsigned n = lit->get_num_args(); unsigned n = lit->get_num_args();
for(unsigned i=0; i<n; i++) { for (unsigned i = 0; i < n; i++) {
const expr * arg = lit->get_arg(i); const expr * arg = lit->get_arg(i);
if(is_var(arg) && !bound_vars.contains(to_var(arg)->get_idx())) { if (is_var(arg) && !bound_vars.contains(to_var(arg)->get_idx())) {
res*=m_context.get_sort_size_estimate(pred->get_domain(i)); res *= m_context.get_sort_size_estimate(pred->get_domain(i));
} }
//res-=1; //res-=1;
} }
@ -111,22 +99,22 @@ namespace datalog {
float best_cost; float best_cost;
int candidate_index = -1; int candidate_index = -1;
unsigned n = cont.size(); unsigned n = cont.size();
for(unsigned i=0; i<n; i++) { for (unsigned i=0; i<n; i++) {
app * lit = r->get_tail(cont[i]); app * lit = r->get_tail(cont[i]);
unsigned bound_cnt = get_bound_arg_count(lit, bound_vars); unsigned bound_cnt = get_bound_arg_count(lit, bound_vars);
if(bound_cnt==0) { if (bound_cnt==0) {
continue; continue;
} }
float cost = get_unbound_cost(lit, bound_vars); float cost = get_unbound_cost(lit, bound_vars);
if(candidate_index==-1 || cost<best_cost) { if (candidate_index==-1 || cost<best_cost) {
best_cost = cost; best_cost = cost;
candidate_index = i; candidate_index = i;
} }
} }
if(candidate_index==-1) { if (candidate_index==-1) {
return -1; return -1;
} }
if(candidate_index != static_cast<int>(n-1)) { if (candidate_index != static_cast<int>(n-1)) {
std::swap(cont[candidate_index], cont[n-1]); std::swap(cont[candidate_index], cont[n-1]);
} }
unsigned res = cont.back(); unsigned res = cont.back();
@ -137,12 +125,12 @@ namespace datalog {
app * mk_magic_sets::adorn_literal(app * lit, const var_idx_set & bound_vars) { app * mk_magic_sets::adorn_literal(app * lit, const var_idx_set & bound_vars) {
SASSERT(!m_extentional.contains(lit->get_decl())); SASSERT(!m_extentional.contains(lit->get_decl()));
func_decl * old_pred = lit->get_decl(); func_decl * old_pred = lit->get_decl();
SASSERT(m_manager.is_bool(old_pred->get_range())); SASSERT(m.is_bool(old_pred->get_range()));
adornment_desc adn(old_pred); adornment_desc adn(old_pred);
adn.m_adornment.populate(lit, bound_vars); adn.m_adornment.populate(lit, bound_vars);
adornment_map::entry * e = m_adorned_preds.insert_if_not_there2(adn, 0); adornment_map::entry * e = m_adorned_preds.insert_if_not_there2(adn, 0);
func_decl * new_pred = e->get_data().m_value; func_decl * new_pred = e->get_data().m_value;
if(new_pred==0) { if (new_pred==0) {
std::string suffix = "ad_"+adn.m_adornment.to_string(); std::string suffix = "ad_"+adn.m_adornment.to_string();
new_pred = m_context.mk_fresh_head_predicate( new_pred = m_context.mk_fresh_head_predicate(
old_pred->get_name(), symbol(suffix.c_str()), old_pred->get_name(), symbol(suffix.c_str()),
@ -152,34 +140,34 @@ namespace datalog {
m_todo.push_back(adn); m_todo.push_back(adn);
m_adornments.insert(new_pred, adn.m_adornment); m_adornments.insert(new_pred, adn.m_adornment);
} }
app * res = m_manager.mk_app(new_pred, lit->get_args()); app * res = m.mk_app(new_pred, lit->get_args());
m_pinned.push_back(res); m_pinned.push_back(res);
return res; return res;
} }
app * mk_magic_sets::create_magic_literal(app * l) { app * mk_magic_sets::create_magic_literal(app * l) {
func_decl * l_pred = l->get_decl(); func_decl * l_pred = l->get_decl();
SASSERT(m_manager.is_bool(l_pred->get_range())); SASSERT(m.is_bool(l_pred->get_range()));
pred_adornment_map::obj_map_entry * ae = m_adornments.find_core(l_pred); pred_adornment_map::obj_map_entry * ae = m_adornments.find_core(l_pred);
SASSERT(ae); SASSERT(ae);
const adornment & adn = ae->get_data().m_value; const adornment & adn = ae->get_data().m_value;
unsigned l_arity = l->get_num_args(); unsigned l_arity = l->get_num_args();
ptr_vector<expr> bound_args; ptr_vector<expr> bound_args;
for(unsigned i=0; i<l_arity; i++) { for (unsigned i=0; i<l_arity; i++) {
if(adn[i]==AD_BOUND) { if (adn[i]==AD_BOUND) {
bound_args.push_back(l->get_arg(i)); bound_args.push_back(l->get_arg(i));
} }
} }
pred2pred::obj_map_entry * e = m_magic_preds.insert_if_not_there2(l_pred, 0); pred2pred::obj_map_entry * e = m_magic_preds.insert_if_not_there2(l_pred, 0);
func_decl * mag_pred = e->get_data().m_value; func_decl * mag_pred = e->get_data().m_value;
if(mag_pred==0) { if (mag_pred==0) {
unsigned mag_arity = bound_args.size(); unsigned mag_arity = bound_args.size();
ptr_vector<sort> mag_domain; ptr_vector<sort> mag_domain;
for(unsigned i=0; i<l_arity; i++) { for (unsigned i=0; i<l_arity; i++) {
if(adn[i]==AD_BOUND) { if (adn[i]==AD_BOUND) {
mag_domain.push_back(l_pred->get_domain(i)); mag_domain.push_back(l_pred->get_domain(i));
} }
} }
@ -190,12 +178,12 @@ namespace datalog {
e->get_data().m_value = mag_pred; e->get_data().m_value = mag_pred;
} }
app * res = m_manager.mk_app(mag_pred, bound_args.c_ptr()); app * res = m.mk_app(mag_pred, bound_args.c_ptr());
m_pinned.push_back(res); m_pinned.push_back(res);
return res; return res;
} }
void mk_magic_sets::create_magic_rules(app * head, unsigned tail_cnt, app * const * tail, bool const* negated) { void mk_magic_sets::create_magic_rules(app * head, unsigned tail_cnt, app * const * tail, bool const* negated, rule_set& result) {
//TODO: maybe include relevant interpreted predicates from the original rule //TODO: maybe include relevant interpreted predicates from the original rule
ptr_vector<app> new_tail; ptr_vector<app> new_tail;
svector<bool> negations; svector<bool> negations;
@ -204,26 +192,26 @@ namespace datalog {
negations.push_back(false); negations.push_back(false);
negations.append(tail_cnt, negated); negations.append(tail_cnt, negated);
for(unsigned i=0; i<tail_cnt; i++) { for (unsigned i=0; i<tail_cnt; i++) {
if(m_extentional.contains(tail[i]->get_decl())) { if (m_extentional.contains(tail[i]->get_decl())) {
continue; continue;
} }
app * mag_head = create_magic_literal(tail[i]); app * mag_head = create_magic_literal(tail[i]);
rule * r = m_context.get_rule_manager().mk(mag_head, i+1, new_tail.c_ptr(), negations.c_ptr()); rule * r = m_context.get_rule_manager().mk(mag_head, i+1, new_tail.c_ptr(), negations.c_ptr());
TRACE("dl", r->display(m_context,tout); ); TRACE("dl", r->display(m_context,tout); );
m_rules.push_back(r); result.add_rule(r);
} }
} }
void mk_magic_sets::transform_rule(const adornment & head_adornment, rule * r) { void mk_magic_sets::transform_rule(const adornment & head_adornment, rule * r, rule_set& result) {
app * head = r->get_head(); app * head = r->get_head();
unsigned head_len = head->get_num_args(); unsigned head_len = head->get_num_args();
SASSERT(head_len==head_adornment.size()); SASSERT(head_len==head_adornment.size());
var_idx_set bound_vars; var_idx_set bound_vars;
for(unsigned i=0; i<head_len; i++) { for (unsigned i=0; i<head_len; i++) {
expr * arg = head->get_arg(i); expr * arg = head->get_arg(i);
if(head_adornment[i]==AD_BOUND && is_var(arg)) { if (head_adornment[i]==AD_BOUND && is_var(arg)) {
bound_vars.insert(to_var(arg)->get_idx()); bound_vars.insert(to_var(arg)->get_idx());
} }
} }
@ -231,9 +219,9 @@ namespace datalog {
unsigned processed_tail_len = r->get_uninterpreted_tail_size(); unsigned processed_tail_len = r->get_uninterpreted_tail_size();
unsigned_vector exten_tails; unsigned_vector exten_tails;
unsigned_vector inten_tails; unsigned_vector inten_tails;
for(unsigned i=0; i<processed_tail_len; i++) { for (unsigned i=0; i<processed_tail_len; i++) {
app * t = r->get_tail(i); app * t = r->get_tail(i);
if(m_extentional.contains(t->get_decl())) { if (m_extentional.contains(t->get_decl())) {
exten_tails.push_back(i); exten_tails.push_back(i);
} }
else { else {
@ -243,17 +231,17 @@ namespace datalog {
ptr_vector<app> new_tail; ptr_vector<app> new_tail;
svector<bool> negations; svector<bool> negations;
while(new_tail.size()!=processed_tail_len) { while (new_tail.size()!=processed_tail_len) {
bool intentional = false; bool intentional = false;
int curr_index = pop_bound(exten_tails, r, bound_vars); int curr_index = pop_bound(exten_tails, r, bound_vars);
if(curr_index==-1) { if (curr_index==-1) {
curr_index = pop_bound(inten_tails, r,bound_vars); curr_index = pop_bound(inten_tails, r,bound_vars);
if(curr_index!=-1) { if (curr_index!=-1) {
intentional = true; intentional = true;
} }
} }
if(curr_index==-1) { if (curr_index==-1) {
if(!exten_tails.empty()) { if (!exten_tails.empty()) {
curr_index = exten_tails.back(); curr_index = exten_tails.back();
exten_tails.pop_back(); exten_tails.pop_back();
} }
@ -266,24 +254,24 @@ namespace datalog {
} }
SASSERT(curr_index!=-1); SASSERT(curr_index!=-1);
app * curr = r->get_tail(curr_index); app * curr = r->get_tail(curr_index);
if(intentional) { if (intentional) {
curr = adorn_literal(curr, bound_vars); curr = adorn_literal(curr, bound_vars);
} }
new_tail.push_back(curr); new_tail.push_back(curr);
negations.push_back(r->is_neg_tail(curr_index)); negations.push_back(r->is_neg_tail(curr_index));
collect_vars(m_manager, curr, bound_vars); collect_vars(m, curr, bound_vars);
} }
func_decl * new_head_pred; func_decl * new_head_pred;
VERIFY( m_adorned_preds.find(adornment_desc(head->get_decl(), head_adornment), new_head_pred) ); VERIFY( m_adorned_preds.find(adornment_desc(head->get_decl(), head_adornment), new_head_pred) );
app * new_head = m_manager.mk_app(new_head_pred, head->get_args()); app * new_head = m.mk_app(new_head_pred, head->get_args());
SASSERT(new_tail.size()==r->get_uninterpreted_tail_size()); SASSERT(new_tail.size()==r->get_uninterpreted_tail_size());
create_magic_rules(new_head, new_tail.size(), new_tail.c_ptr(), negations.c_ptr()); create_magic_rules(new_head, new_tail.size(), new_tail.c_ptr(), negations.c_ptr(), result);
unsigned tail_len = r->get_tail_size(); unsigned tail_len = r->get_tail_size();
for(unsigned i=processed_tail_len; i<tail_len; i++) { for (unsigned i=processed_tail_len; i<tail_len; i++) {
new_tail.push_back(r->get_tail(i)); new_tail.push_back(r->get_tail(i));
negations.push_back(r->is_neg_tail(i)); negations.push_back(r->is_neg_tail(i));
} }
@ -292,43 +280,49 @@ namespace datalog {
negations.push_back(false); negations.push_back(false);
rule * nr = m_context.get_rule_manager().mk(new_head, new_tail.size(), new_tail.c_ptr(), negations.c_ptr()); rule * nr = m_context.get_rule_manager().mk(new_head, new_tail.size(), new_tail.c_ptr(), negations.c_ptr());
m_rules.push_back(nr); result.add_rule(nr);
nr->set_accounting_parent_object(m_context, r); nr->set_accounting_parent_object(m_context, r);
} }
void mk_magic_sets::create_transfer_rule(const adornment_desc & d) { void mk_magic_sets::create_transfer_rule(const adornment_desc & d, rule_set& result) {
func_decl * adn_pred; func_decl * adn_pred = m_adorned_preds.find(d);
TRUSTME( m_adorned_preds.find(d, adn_pred) );
unsigned arity = adn_pred->get_arity(); unsigned arity = adn_pred->get_arity();
SASSERT(arity==d.m_pred->get_arity()); SASSERT(arity == d.m_pred->get_arity());
ptr_vector<expr> args; ptr_vector<expr> args;
for(unsigned i=0; i<arity; i++) { for (unsigned i=0; i<arity; i++) {
args.push_back(m_manager.mk_var(i, adn_pred->get_domain(i))); args.push_back(m.mk_var(i, adn_pred->get_domain(i)));
} }
app * lit = m_manager.mk_app(d.m_pred, args.c_ptr()); app * lit = m.mk_app(d.m_pred, args.c_ptr());
app * adn_lit = m_manager.mk_app(adn_pred, args.c_ptr()); app * adn_lit = m.mk_app(adn_pred, args.c_ptr());
app * mag_lit = create_magic_literal(adn_lit); app * mag_lit = create_magic_literal(adn_lit);
app * tail[] = {lit, mag_lit}; app * tail[] = {lit, mag_lit};
rule * r = m_context.get_rule_manager().mk(adn_lit, 2, tail, 0); rule * r = m_context.get_rule_manager().mk(adn_lit, 2, tail, 0);
m_rules.push_back(r); result.add_rule(r);
} }
rule_set * mk_magic_sets::operator()(rule_set const & source) { rule_set * mk_magic_sets::operator()(rule_set const & source) {
SASSERT(!m_context.get_model_converter());
if (!m_context.magic_sets_for_queries()) {
return 0;
}
app * goal_head = source.get_predicate_rules(m_goal)[0]->get_head();
unsigned init_rule_cnt = source.get_num_rules(); unsigned init_rule_cnt = source.get_num_rules();
{ {
func_decl_set intentional; func_decl_set intentional;
for(unsigned i=0; i<init_rule_cnt; i++) { for (unsigned i=0; i<init_rule_cnt; i++) {
intentional.insert(source.get_rule(i)->get_head()->get_decl()); func_decl* pred = source.get_rule(i)->get_decl();
intentional.insert(pred);
} }
//now we iterate through all predicates and collect the set of extentional ones //now we iterate through all predicates and collect the set of extentional ones
const rule_dependencies * deps; const rule_dependencies * deps;
rule_dependencies computed_deps(m_context); rule_dependencies computed_deps(m_context);
if(source.is_closed()) { if (source.is_closed()) {
deps = &source.get_dependencies(); deps = &source.get_dependencies();
} }
else { else {
@ -337,9 +331,9 @@ namespace datalog {
} }
rule_dependencies::iterator it = deps->begin(); rule_dependencies::iterator it = deps->begin();
rule_dependencies::iterator end = deps->end(); rule_dependencies::iterator end = deps->end();
for(; it!=end; ++it) { for (; it!=end; ++it) {
func_decl * pred = it->m_key; func_decl * pred = it->m_key;
if(intentional.contains(pred)) { if (intentional.contains(pred)) {
continue; continue;
} }
SASSERT(it->m_value->empty());//extentional predicates have no dependency SASSERT(it->m_value->empty());//extentional predicates have no dependency
@ -347,48 +341,39 @@ namespace datalog {
} }
} }
SASSERT(m_rules.empty());
app * goal_head = m_goal_rule->get_head();
//adornment goal_adn; //adornment goal_adn;
//goal_adn.populate(goal_head, ); //goal_adn.populate(goal_head, );
var_idx_set empty_var_idx_set; var_idx_set empty_var_idx_set;
adorn_literal(goal_head, empty_var_idx_set); adorn_literal(goal_head, empty_var_idx_set);
while(!m_todo.empty()) { rule_set * result = alloc(rule_set, m_context);
result->inherit_predicates(source);
while (!m_todo.empty()) {
adornment_desc task = m_todo.back(); adornment_desc task = m_todo.back();
m_todo.pop_back(); m_todo.pop_back();
const rule_vector & pred_rules = source.get_predicate_rules(task.m_pred); const rule_vector & pred_rules = source.get_predicate_rules(task.m_pred);
rule_vector::const_iterator it = pred_rules.begin(); rule_vector::const_iterator it = pred_rules.begin();
rule_vector::const_iterator end = pred_rules.end(); rule_vector::const_iterator end = pred_rules.end();
for(; it!=end; ++it) { for (; it != end; ++it) {
rule * r = *it; rule * r = *it;
transform_rule(task.m_adornment, r); transform_rule(task.m_adornment, r, *result);
} }
if(!m_context.get_rel_context().get_relation(task.m_pred).empty()) { if (!m_context.get_rel_context().get_relation(task.m_pred).empty()) {
//we need a rule to copy facts that are already in a relation into the adorned //we need a rule to copy facts that are already in a relation into the adorned
//relation (since out intentional predicates can have facts, not only rules) //relation (since out intentional predicates can have facts, not only rules)
create_transfer_rule(task); create_transfer_rule(task, *result);
} }
} }
app * adn_goal_head = adorn_literal(goal_head, empty_var_idx_set); app * adn_goal_head = adorn_literal(goal_head, empty_var_idx_set);
app * mag_goal_head = create_magic_literal(adn_goal_head); app * mag_goal_head = create_magic_literal(adn_goal_head);
SASSERT(mag_goal_head->is_ground()); SASSERT(mag_goal_head->is_ground());
//SASSERT(is_fact(m_manager, mag_goal_head));
//m_context.add_fact(mag_goal_head);
rule * mag_goal_rule = m_context.get_rule_manager().mk(mag_goal_head, 0, 0, 0); rule * mag_goal_rule = m_context.get_rule_manager().mk(mag_goal_head, 0, 0, 0);
m_rules.push_back(mag_goal_rule); result->add_rule(mag_goal_rule);
rule * back_to_goal_rule = m_context.get_rule_manager().mk(goal_head, 1, &adn_goal_head, 0); rule * back_to_goal_rule = m_context.get_rule_manager().mk(goal_head, 1, &adn_goal_head, 0);
m_rules.push_back(back_to_goal_rule); result->add_rule(back_to_goal_rule);
rule_set * result = static_cast<rule_set *>(0);
result = alloc(rule_set, m_context);
unsigned fin_rule_cnt = m_rules.size();
for(unsigned i=0; i<fin_rule_cnt; i++) {
result->add_rule(m_rules.get(i));
}
return result; return result;
} }
}; };

View file

@ -88,21 +88,20 @@ namespace datalog {
typedef obj_map<func_decl, adornment> pred_adornment_map; typedef obj_map<func_decl, adornment> pred_adornment_map;
typedef obj_map<func_decl, func_decl *> pred2pred; typedef obj_map<func_decl, func_decl *> pred2pred;
context & m_context; context & m_context;
ast_manager & m_manager; ast_manager & m;
rule_ref_vector m_rules; ast_ref_vector m_pinned;
ast_ref_vector m_pinned;
rule_ref m_goal_rule;
/** /**
\brief Predicates from the original set that appear in a head of a rule \brief Predicates from the original set that appear in a head of a rule
*/ */
func_decl_set m_extentional; func_decl_set m_extentional;
//adornment_set m_processed; //adornment_set m_processed;
vector<adornment_desc> m_todo; vector<adornment_desc> m_todo;
adornment_map m_adorned_preds; adornment_map m_adorned_preds;
pred_adornment_map m_adornments; pred_adornment_map m_adornments;
pred2pred m_magic_preds; pred2pred m_magic_preds;
func_decl_ref m_goal;
void reset(); void reset();
@ -110,16 +109,16 @@ namespace datalog {
int pop_bound(unsigned_vector & cont, rule * r, const var_idx_set & bound_vars); int pop_bound(unsigned_vector & cont, rule * r, const var_idx_set & bound_vars);
app * create_magic_literal(app * l); app * create_magic_literal(app * l);
void create_magic_rules(app * head, unsigned tail_cnt, app * const * tail, bool const* negated); void create_magic_rules(app * head, unsigned tail_cnt, app * const * tail, bool const* negated, rule_set& result);
app * adorn_literal(app * lit, const var_idx_set & bound_vars); app * adorn_literal(app * lit, const var_idx_set & bound_vars);
void transform_rule(const adornment & head_adornment, rule * r); void transform_rule(const adornment & head_adornment, rule * r, rule_set& result);
void create_transfer_rule(const adornment_desc & d); void create_transfer_rule(const adornment_desc & d, rule_set& result);
public: public:
/** /**
\brief Create magic sets rule transformer for \c goal_rule. When applying the transformer, \brief Create magic sets rule transformer for \c goal_rule. When applying the transformer,
the \c goal_rule must be present in the \c rule_set that is being transformed. the \c goal_rule must be present in the \c rule_set that is being transformed.
*/ */
mk_magic_sets(context & ctx, rule * goal_rule); mk_magic_sets(context & ctx, func_decl* goal);
rule_set * operator()(rule_set const & source); rule_set * operator()(rule_set const & source);
}; };

View file

@ -23,7 +23,7 @@ Revision History:
namespace datalog { namespace datalog {
bool mk_partial_equivalence_transformer::is_symmetry(rule const* r) { bool mk_partial_equivalence_transformer::is_symmetry(rule const* r) {
func_decl* p = r->get_head()->get_decl(); func_decl* p = r->get_decl();
return return
p->get_arity() == 2 && p->get_arity() == 2 &&
p->get_domain(0) == p->get_domain(1) && p->get_domain(0) == p->get_domain(1) &&
@ -38,7 +38,7 @@ namespace datalog {
bool mk_partial_equivalence_transformer::is_transitivity(rule const* r) { bool mk_partial_equivalence_transformer::is_transitivity(rule const* r) {
func_decl* p = r->get_head()->get_decl(); func_decl* p = r->get_decl();
if (p->get_arity() != 2 || if (p->get_arity() != 2 ||
p->get_domain(0) != p->get_domain(1) || p->get_domain(0) != p->get_domain(1) ||
r->get_tail_size() != 2 || r->get_tail_size() != 2 ||
@ -144,6 +144,7 @@ namespace datalog {
dealloc(res); dealloc(res);
return 0; return 0;
} }
res->inherit_predicates(source);
return res; return res;
} }

View file

@ -147,9 +147,10 @@ namespace datalog {
mk_quantifier_abstraction::~mk_quantifier_abstraction() { mk_quantifier_abstraction::~mk_quantifier_abstraction() {
} }
func_decl* mk_quantifier_abstraction::declare_pred(func_decl* old_p) { func_decl* mk_quantifier_abstraction::declare_pred(rule_set const& rules, rule_set& dst, func_decl* old_p) {
if (m_ctx.is_output_predicate(old_p)) { if (rules.is_output_predicate(old_p)) {
dst.inherit_predicate(rules, old_p, old_p);
return 0; return 0;
} }
@ -210,8 +211,8 @@ namespace datalog {
return new_p; return new_p;
} }
app_ref mk_quantifier_abstraction::mk_head(app* p, unsigned idx) { app_ref mk_quantifier_abstraction::mk_head(rule_set const& rules, rule_set& dst, app* p, unsigned idx) {
func_decl* new_p = declare_pred(p->get_decl()); func_decl* new_p = declare_pred(rules, dst, p->get_decl());
if (!new_p) { if (!new_p) {
return app_ref(p, m); return app_ref(p, m);
} }
@ -239,9 +240,9 @@ namespace datalog {
return app_ref(m.mk_app(new_p, args.size(), args.c_ptr()), m); return app_ref(m.mk_app(new_p, args.size(), args.c_ptr()), m);
} }
app_ref mk_quantifier_abstraction::mk_tail(app* p) { app_ref mk_quantifier_abstraction::mk_tail(rule_set const& rules, rule_set& dst, app* p) {
func_decl* old_p = p->get_decl(); func_decl* old_p = p->get_decl();
func_decl* new_p = declare_pred(old_p); func_decl* new_p = declare_pred(rules, dst, old_p);
if (!new_p) { if (!new_p) {
return app_ref(p, m); return app_ref(p, m);
} }
@ -332,18 +333,17 @@ namespace datalog {
unsigned utsz = r.get_uninterpreted_tail_size(); unsigned utsz = r.get_uninterpreted_tail_size();
unsigned tsz = r.get_tail_size(); unsigned tsz = r.get_tail_size();
for (unsigned j = 0; j < utsz; ++j) { for (unsigned j = 0; j < utsz; ++j) {
tail.push_back(mk_tail(r.get_tail(j))); tail.push_back(mk_tail(source, *result, r.get_tail(j)));
} }
for (unsigned j = utsz; j < tsz; ++j) { for (unsigned j = utsz; j < tsz; ++j) {
tail.push_back(r.get_tail(j)); tail.push_back(r.get_tail(j));
} }
head = mk_head(r.get_head(), cnt); head = mk_head(source, *result, r.get_head(), cnt);
fml = m.mk_implies(m.mk_and(tail.size(), tail.c_ptr()), head); fml = m.mk_implies(m.mk_and(tail.size(), tail.c_ptr()), head);
rule_ref_vector added_rules(rm); rule_ref_vector added_rules(rm);
proof_ref pr(m); proof_ref pr(m);
rm.mk_rule(fml, pr, added_rules); rm.mk_rule(fml, pr, *result);
result->add_rules(added_rules.size(), added_rules.c_ptr()); TRACE("dl", result->last()->display(m_ctx, tout););
TRACE("dl", added_rules.back()->display(m_ctx, tout););
} }
// proof converter: proofs are not necessarily preserved using this transformation. // proof converter: proofs are not necessarily preserved using this transformation.

View file

@ -43,9 +43,9 @@ namespace datalog {
obj_map<func_decl, func_decl*> m_old2new; obj_map<func_decl, func_decl*> m_old2new;
qa_model_converter* m_mc; qa_model_converter* m_mc;
func_decl* declare_pred(func_decl* old_p); func_decl* declare_pred(rule_set const& rules, rule_set& dst, func_decl* old_p);
app_ref mk_head(app* p, unsigned idx); app_ref mk_head(rule_set const& rules, rule_set& dst, app* p, unsigned idx);
app_ref mk_tail(app* p); app_ref mk_tail(rule_set const& rules, rule_set& dst, app* p);
expr* mk_select(expr* a, unsigned num_args, expr* const* args); expr* mk_select(expr* a, unsigned num_args, expr* const* args);
public: public:

View file

@ -232,20 +232,20 @@ namespace datalog {
fml = m.mk_implies(fml, r.get_head()); fml = m.mk_implies(fml, r.get_head());
TRACE("dl", r.display(m_ctx, tout); tout << mk_pp(fml, m) << "\n";); TRACE("dl", r.display(m_ctx, tout); tout << mk_pp(fml, m) << "\n";);
rule_ref_vector added_rules(rm); rule_set added_rules(m_ctx);
proof_ref pr(m); proof_ref pr(m);
rm.mk_rule(fml, pr, added_rules); rm.mk_rule(fml, pr, added_rules);
if (r.get_proof()) { if (r.get_proof()) {
// use def-axiom to encode that new rule is a weakening of the original. // use def-axiom to encode that new rule is a weakening of the original.
proof* p1 = r.get_proof(); proof* p1 = r.get_proof();
for (unsigned i = 0; i < added_rules.size(); ++i) { for (unsigned i = 0; i < added_rules.get_num_rules(); ++i) {
rule* r2 = added_rules[i].get(); rule* r2 = added_rules.get_rule(i);
r2->to_formula(fml); r2->to_formula(fml);
pr = m.mk_modus_ponens(m.mk_def_axiom(m.mk_implies(m.get_fact(p1), fml)), p1); pr = m.mk_modus_ponens(m.mk_def_axiom(m.mk_implies(m.get_fact(p1), fml)), p1);
r2->set_proof(m, pr); r2->set_proof(m, pr);
} }
} }
rules.add_rules(added_rules.size(), added_rules.c_ptr()); rules.add_rules(added_rules);
} }
rule_set * mk_quantifier_instantiation::operator()(rule_set const & source) { rule_set * mk_quantifier_instantiation::operator()(rule_set const & source) {
@ -286,7 +286,10 @@ namespace datalog {
// model convertion: identity function. // model convertion: identity function.
if (!instantiated) { if (instantiated) {
result->inherit_predicates(source);
}
else {
dealloc(result); dealloc(result);
result = 0; result = 0;
} }

View file

@ -230,10 +230,10 @@ namespace datalog {
} }
} }
bool mk_rule_inliner::inlining_allowed(func_decl * pred) bool mk_rule_inliner::inlining_allowed(rule_set const& source, func_decl * pred)
{ {
if (//these three conditions are important for soundness if (//these three conditions are important for soundness
m_context.is_output_predicate(pred) || source.is_output_predicate(pred) ||
m_preds_with_facts.contains(pred) || m_preds_with_facts.contains(pred) ||
m_preds_with_neg_occurrence.contains(pred) || m_preds_with_neg_occurrence.contains(pred) ||
//this condition is used for breaking of cycles among inlined rules //this condition is used for breaking of cycles among inlined rules
@ -260,7 +260,7 @@ namespace datalog {
unsigned rcnt = orig.get_num_rules(); unsigned rcnt = orig.get_num_rules();
for (unsigned i=0; i<rcnt; i++) { for (unsigned i=0; i<rcnt; i++) {
rule * r = orig.get_rule(i); rule * r = orig.get_rule(i);
if (inlining_allowed(r->get_decl())) { if (inlining_allowed(orig, r->get_decl())) {
res->add_rule(r); res->add_rule(r);
} }
} }
@ -324,7 +324,7 @@ namespace datalog {
unsigned pt_len = r->get_positive_tail_size(); unsigned pt_len = r->get_positive_tail_size();
for (unsigned ti = 0; ti<pt_len; ++ti) { for (unsigned ti = 0; ti<pt_len; ++ti) {
func_decl * tail_pred = r->get_decl(ti); func_decl * tail_pred = r->get_decl(ti);
if (!inlining_allowed(tail_pred)) { if (!inlining_allowed(orig, tail_pred)) {
continue; continue;
} }
unsigned tail_pred_head_cnt = m_head_pred_ctr.get(tail_pred); unsigned tail_pred_head_cnt = m_head_pred_ctr.get(tail_pred);
@ -359,7 +359,7 @@ namespace datalog {
func_decl * head_pred = r->get_decl(); func_decl * head_pred = r->get_decl();
if (inlining_allowed(head_pred)) { if (inlining_allowed(orig, head_pred)) {
//we have already processed inlined rules //we have already processed inlined rules
continue; continue;
} }
@ -368,7 +368,7 @@ namespace datalog {
unsigned pt_len = r->get_positive_tail_size(); unsigned pt_len = r->get_positive_tail_size();
for (unsigned ti = 0; ti<pt_len; ++ti) { for (unsigned ti = 0; ti<pt_len; ++ti) {
func_decl * pred = r->get_decl(ti); func_decl * pred = r->get_decl(ti);
if (!inlining_allowed(pred)) { if (!inlining_allowed(orig, pred)) {
continue; continue;
} }
if (m_head_pred_ctr.get(pred)<=1) { if (m_head_pred_ctr.get(pred)<=1) {
@ -417,14 +417,14 @@ namespace datalog {
const rule_vector& pred_rules = candidate_inlined_set->get_predicate_rules(pred); const rule_vector& pred_rules = candidate_inlined_set->get_predicate_rules(pred);
rule_vector::const_iterator iend = pred_rules.end(); rule_vector::const_iterator iend = pred_rules.end();
for (rule_vector::const_iterator iit = pred_rules.begin(); iit!=iend; ++iit) { for (rule_vector::const_iterator iit = pred_rules.begin(); iit!=iend; ++iit) {
transform_rule(*iit, m_inlined_rules); transform_rule(orig, *iit, m_inlined_rules);
} }
} }
TRACE("dl", tout << "inlined rules after mutual inlining:\n" << m_inlined_rules; ); TRACE("dl", tout << "inlined rules after mutual inlining:\n" << m_inlined_rules; );
} }
bool mk_rule_inliner::transform_rule(rule * r0, rule_set& tgt) { bool mk_rule_inliner::transform_rule(rule_set const& orig, rule * r0, rule_set& tgt) {
bool modified = false; bool modified = false;
rule_ref_vector todo(m_rm); rule_ref_vector todo(m_rm);
todo.push_back(r0); todo.push_back(r0);
@ -436,7 +436,7 @@ namespace datalog {
unsigned i = 0; unsigned i = 0;
for (; i < pt_len && !inlining_allowed(r->get_decl(i)); ++i) {}; for (; i < pt_len && !inlining_allowed(orig, r->get_decl(i)); ++i) {};
SASSERT(!has_quantifier(*r.get())); SASSERT(!has_quantifier(*r.get()));
@ -478,12 +478,12 @@ namespace datalog {
// this relation through inlining, // this relation through inlining,
// so we don't add its rules to the result // so we don't add its rules to the result
something_done |= !inlining_allowed(pred) && transform_rule(r, tgt); something_done |= !inlining_allowed(orig, pred) && transform_rule(orig, r, tgt);
} }
if (something_done && m_mc) { if (something_done && m_mc) {
for (rule_set::iterator rit = orig.begin(); rit!=rend; ++rit) { for (rule_set::iterator rit = orig.begin(); rit!=rend; ++rit) {
if (inlining_allowed((*rit)->get_decl())) { if (inlining_allowed(orig, (*rit)->get_decl())) {
datalog::del_rule(m_mc, **rit); datalog::del_rule(m_mc, **rit);
} }
} }
@ -676,7 +676,7 @@ namespace datalog {
m_head_index.insert(head); m_head_index.insert(head);
m_pinned.push_back(r); m_pinned.push_back(r);
if (m_context.is_output_predicate(headd) || if (m_context.get_rules().is_output_predicate(headd) ||
m_preds_with_facts.contains(headd)) { m_preds_with_facts.contains(headd)) {
can_remove.set(i, false); can_remove.set(i, false);
TRACE("dl", output_predicate(m_context, head, tout << "cannot remove: " << i << " "); tout << "\n";); TRACE("dl", output_predicate(m_context, head, tout << "cannot remove: " << i << " "); tout << "\n";);
@ -692,7 +692,7 @@ namespace datalog {
tl_sz == 1 tl_sz == 1
&& r->get_positive_tail_size() == 1 && r->get_positive_tail_size() == 1
&& !m_preds_with_facts.contains(r->get_decl(0)) && !m_preds_with_facts.contains(r->get_decl(0))
&& !m_context.is_output_predicate(r->get_decl(0)); && !m_context.get_rules().is_output_predicate(r->get_decl(0));
can_expand.set(i, can_exp); can_expand.set(i, can_exp);
} }
@ -883,6 +883,7 @@ namespace datalog {
res = 0; res = 0;
} }
else { else {
res->inherit_predicates(source);
m_context.add_model_converter(hsmc.get()); m_context.add_model_converter(hsmc.get());
} }

View file

@ -129,7 +129,7 @@ namespace datalog {
bool try_to_inline_rule(rule& tgt, rule& src, unsigned tail_index, rule_ref& res); bool try_to_inline_rule(rule& tgt, rule& src, unsigned tail_index, rule_ref& res);
bool inlining_allowed(func_decl * pred); bool inlining_allowed(rule_set const& orig, func_decl * pred);
void count_pred_occurrences(rule_set const & orig); void count_pred_occurrences(rule_set const & orig);
@ -143,7 +143,7 @@ namespace datalog {
bool forbid_multiple_multipliers(const rule_set & orig, rule_set const & proposed_inlined_rules); bool forbid_multiple_multipliers(const rule_set & orig, rule_set const & proposed_inlined_rules);
/** Return true if the rule was modified */ /** Return true if the rule was modified */
bool transform_rule(rule * r, rule_set& tgt); bool transform_rule(rule_set const& orig, rule * r, rule_set& tgt);
/** Return true if some transformation was performed */ /** Return true if some transformation was performed */
bool transform_rules(const rule_set & orig, rule_set & tgt); bool transform_rules(const rule_set & orig, rule_set & tgt);

View file

@ -24,12 +24,12 @@ Revision History:
namespace datalog { namespace datalog {
mk_similarity_compressor::mk_similarity_compressor(context & ctx, unsigned threshold_count) : mk_similarity_compressor::mk_similarity_compressor(context & ctx, unsigned threshold_count) :
plugin(5000), plugin(5000),
m_context(ctx), m_context(ctx),
m_manager(ctx.get_manager()), m_manager(ctx.get_manager()),
m_threshold_count(threshold_count), m_threshold_count(threshold_count),
m_result_rules(ctx.get_rule_manager()), m_result_rules(ctx.get_rule_manager()),
m_pinned(m_manager) { m_pinned(m_manager) {
SASSERT(threshold_count>1); SASSERT(threshold_count>1);
} }
@ -43,7 +43,7 @@ namespace datalog {
Allows to traverse head and positive tails in a single for loop starting from -1 Allows to traverse head and positive tails in a single for loop starting from -1
*/ */
app * get_by_tail_index(rule * r, int idx) { app * get_by_tail_index(rule * r, int idx) {
if(idx==-1) { if (idx == -1) {
return r->get_head(); return r->get_head();
} }
SASSERT(idx<static_cast<int>(r->get_positive_tail_size())); SASSERT(idx<static_cast<int>(r->get_positive_tail_size()));
@ -59,15 +59,18 @@ namespace datalog {
SASSERT(t1->get_num_args()==t2->get_num_args()); SASSERT(t1->get_num_args()==t2->get_num_args());
int res; int res;
unsigned n = t1->get_num_args(); unsigned n = t1->get_num_args();
for(unsigned i=0; i<n; i++) { for (unsigned i = 0; i < n; i++) {
expr * a1 = t1->get_arg(i); expr * a1 = t1->get_arg(i);
expr * a2 = t2->get_arg(i); expr * a2 = t2->get_arg(i);
res = aux_compare(is_var(a1), is_var(a2)); res = aux_compare(is_var(a1), is_var(a2));
if(res!=0) { return res; } if (res != 0) {
if(is_var(a1)) { return res;
}
if (is_var(a1)) {
res = aux_compare(to_var(a1)->get_idx(), to_var(a2)->get_idx()); res = aux_compare(to_var(a1)->get_idx(), to_var(a2)->get_idx());
if(res!=0) { return res; } if (res != 0) {
return res;
}
} }
} }
return 0; return 0;
@ -77,16 +80,16 @@ namespace datalog {
SASSERT(t1->get_num_args()==t2->get_num_args()); SASSERT(t1->get_num_args()==t2->get_num_args());
int res; int res;
unsigned n = t1->get_num_args(); unsigned n = t1->get_num_args();
for(unsigned i=0; i<n; i++) { for (unsigned i=0; i<n; i++) {
if(is_var(t1->get_arg(i))) { if (is_var(t1->get_arg(i))) {
SASSERT(t1->get_arg(i)==t2->get_arg(i)); SASSERT(t1->get_arg(i) == t2->get_arg(i));
continue; continue;
} }
if((skip_countdown--)==0) { if ((skip_countdown--) == 0) {
continue; continue;
} }
res = aux_compare(t1->get_arg(i), t2->get_arg(i)); res = aux_compare(t1->get_arg(i), t2->get_arg(i));
if(res!=0) { return res; } if (res!=0) { return res; }
} }
return 0; return 0;
} }
@ -100,26 +103,26 @@ namespace datalog {
*/ */
int rough_compare(rule * r1, rule * r2) { int rough_compare(rule * r1, rule * r2) {
int res = aux_compare(r1->get_tail_size(), r2->get_tail_size()); int res = aux_compare(r1->get_tail_size(), r2->get_tail_size());
if(res!=0) { return res; } if (res!=0) { return res; }
res = aux_compare(r1->get_uninterpreted_tail_size(), r2->get_uninterpreted_tail_size()); res = aux_compare(r1->get_uninterpreted_tail_size(), r2->get_uninterpreted_tail_size());
if(res!=0) { return res; } if (res!=0) { return res; }
res = aux_compare(r1->get_positive_tail_size(), r2->get_positive_tail_size()); res = aux_compare(r1->get_positive_tail_size(), r2->get_positive_tail_size());
if(res!=0) { return res; } if (res!=0) { return res; }
int pos_tail_sz = r1->get_positive_tail_size(); int pos_tail_sz = r1->get_positive_tail_size();
for(int i=-1; i<pos_tail_sz; i++) { for (int i=-1; i<pos_tail_sz; i++) {
app * t1 = get_by_tail_index(r1, i); app * t1 = get_by_tail_index(r1, i);
app * t2 = get_by_tail_index(r2, i); app * t2 = get_by_tail_index(r2, i);
res = aux_compare(t1->get_decl(), t2->get_decl()); res = aux_compare(t1->get_decl(), t2->get_decl());
if(res!=0) { return res; } if (res!=0) { return res; }
res = compare_var_args(t1, t2); res = compare_var_args(t1, t2);
if(res!=0) { return res; } if (res!=0) { return res; }
} }
unsigned tail_sz = r1->get_tail_size(); unsigned tail_sz = r1->get_tail_size();
for(unsigned i=pos_tail_sz; i<tail_sz; i++) { for (unsigned i=pos_tail_sz; i<tail_sz; i++) {
res = aux_compare(r1->get_tail(i), r2->get_tail(i)); res = aux_compare(r1->get_tail(i), r2->get_tail(i));
if(res!=0) { return res; } if (res!=0) { return res; }
} }
return 0; return 0;
@ -132,9 +135,9 @@ namespace datalog {
int total_compare(rule * r1, rule * r2, int skipped_arg_index = INT_MAX) { int total_compare(rule * r1, rule * r2, int skipped_arg_index = INT_MAX) {
SASSERT(rough_compare(r1, r2)==0); SASSERT(rough_compare(r1, r2)==0);
int pos_tail_sz = r1->get_positive_tail_size(); int pos_tail_sz = r1->get_positive_tail_size();
for(int i=-1; i<pos_tail_sz; i++) { for (int i=-1; i<pos_tail_sz; i++) {
int res = compare_args(get_by_tail_index(r1, i), get_by_tail_index(r2, i), skipped_arg_index); int res = compare_args(get_by_tail_index(r1, i), get_by_tail_index(r2, i), skipped_arg_index);
if(res!=0) { return res; } if (res!=0) { return res; }
} }
return 0; return 0;
} }
@ -167,8 +170,8 @@ namespace datalog {
void collect_const_indexes(app * t, int tail_index, info_vector & res) { void collect_const_indexes(app * t, int tail_index, info_vector & res) {
unsigned n = t->get_num_args(); unsigned n = t->get_num_args();
for(unsigned i=0; i<n; i++) { for (unsigned i=0; i<n; i++) {
if(is_var(t->get_arg(i))) { if (is_var(t->get_arg(i))) {
continue; continue;
} }
res.push_back(const_info(tail_index, i)); res.push_back(const_info(tail_index, i));
@ -178,7 +181,7 @@ namespace datalog {
void collect_const_indexes(rule * r, info_vector & res) { void collect_const_indexes(rule * r, info_vector & res) {
collect_const_indexes(r->get_head(), -1, res); collect_const_indexes(r->get_head(), -1, res);
unsigned pos_tail_sz = r->get_positive_tail_size(); unsigned pos_tail_sz = r->get_positive_tail_size();
for(unsigned i=0; i<pos_tail_sz; i++) { for (unsigned i=0; i<pos_tail_sz; i++) {
collect_const_indexes(r->get_tail(i), i, res); collect_const_indexes(r->get_tail(i), i, res);
} }
} }
@ -187,9 +190,9 @@ namespace datalog {
void collect_orphan_consts(rule * r, const info_vector & const_infos, T & tgt) { void collect_orphan_consts(rule * r, const info_vector & const_infos, T & tgt) {
unsigned const_cnt = const_infos.size(); unsigned const_cnt = const_infos.size();
tgt.reset(); tgt.reset();
for(unsigned i=0; i<const_cnt; i++) { for (unsigned i=0; i<const_cnt; i++) {
const_info inf = const_infos[i]; const_info inf = const_infos[i];
if(inf.has_parent()) { if (inf.has_parent()) {
continue; continue;
} }
app * pred = get_by_tail_index(r, inf.tail_index()); app * pred = get_by_tail_index(r, inf.tail_index());
@ -201,9 +204,9 @@ namespace datalog {
void collect_orphan_sorts(rule * r, const info_vector & const_infos, T & tgt) { void collect_orphan_sorts(rule * r, const info_vector & const_infos, T & tgt) {
unsigned const_cnt = const_infos.size(); unsigned const_cnt = const_infos.size();
tgt.reset(); tgt.reset();
for(unsigned i=0; i<const_cnt; i++) { for (unsigned i=0; i<const_cnt; i++) {
const_info inf = const_infos[i]; const_info inf = const_infos[i];
if(inf.has_parent()) { if (inf.has_parent()) {
continue; continue;
} }
app * pred = get_by_tail_index(r, inf.tail_index()); app * pred = get_by_tail_index(r, inf.tail_index());
@ -224,25 +227,25 @@ namespace datalog {
collect_orphan_consts(r, const_infos, vals); collect_orphan_consts(r, const_infos, vals);
SASSERT(vals.size()==const_cnt); SASSERT(vals.size()==const_cnt);
rule_vector::iterator it = first; rule_vector::iterator it = first;
for(; it!=after_last; ++it) { for (; it!=after_last; ++it) {
for(unsigned i=0; i<const_cnt; i++) { for (unsigned i=0; i<const_cnt; i++) {
app * pred = get_by_tail_index(*it, const_infos[i].tail_index()); app * pred = get_by_tail_index(*it, const_infos[i].tail_index());
app * val = to_app(pred->get_arg(const_infos[i].arg_index())); app * val = to_app(pred->get_arg(const_infos[i].arg_index()));
if(vals[i]!=val) { if (vals[i]!=val) {
vals[i] = 0; vals[i] = 0;
} }
} }
} }
unsigned removed_cnt = 0; unsigned removed_cnt = 0;
for(unsigned i=0; i<const_cnt; i++) { for (unsigned i=0; i<const_cnt; i++) {
if(vals[i]!=0) { if (vals[i]!=0) {
removed_cnt++; removed_cnt++;
} }
else if(removed_cnt!=0) { else if (removed_cnt!=0) {
const_infos[i-removed_cnt] = const_infos[i]; const_infos[i-removed_cnt] = const_infos[i];
} }
} }
if(removed_cnt!=0) { if (removed_cnt!=0) {
const_infos.shrink(const_cnt-removed_cnt); const_infos.shrink(const_cnt-removed_cnt);
} }
} }
@ -263,21 +266,21 @@ namespace datalog {
collect_orphan_sorts(r, const_infos, sorts); collect_orphan_sorts(r, const_infos, sorts);
SASSERT(vals.size()==const_cnt); SASSERT(vals.size()==const_cnt);
vector<unsigned_vector> possible_parents(const_cnt); vector<unsigned_vector> possible_parents(const_cnt);
for(unsigned i=1; i<const_cnt; i++) { for (unsigned i=1; i<const_cnt; i++) {
for(unsigned j=0; j<i; j++) { for (unsigned j=0; j<i; j++) {
if(vals[i]==vals[j] && sorts[i]==sorts[j]) { if (vals[i]==vals[j] && sorts[i]==sorts[j]) {
possible_parents[i].push_back(j); possible_parents[i].push_back(j);
} }
} }
} }
rule_vector::iterator it = first; rule_vector::iterator it = first;
for(; it!=after_last; ++it) { for (; it!=after_last; ++it) {
collect_orphan_consts(*it, const_infos, vals); collect_orphan_consts(*it, const_infos, vals);
for(unsigned i=1; i<const_cnt; i++) { for (unsigned i=1; i<const_cnt; i++) {
unsigned_vector & ppars = possible_parents[i]; unsigned_vector & ppars = possible_parents[i];
unsigned j=0; unsigned j=0;
while(j<ppars.size()) { while(j<ppars.size()) {
if(vals[i]!=vals[ppars[j]]) { if (vals[i]!=vals[ppars[j]]) {
ppars[j] = ppars.back(); ppars[j] = ppars.back();
ppars.pop_back(); ppars.pop_back();
} }
@ -287,16 +290,16 @@ namespace datalog {
} }
} }
} }
for(unsigned i=0; i<const_cnt; i++) { for (unsigned i=0; i<const_cnt; i++) {
unsigned parent = i; unsigned parent = i;
unsigned_vector & ppars = possible_parents[i]; unsigned_vector & ppars = possible_parents[i];
unsigned ppars_sz = ppars.size(); unsigned ppars_sz = ppars.size();
for(unsigned j=0; j<ppars_sz; j++) { for (unsigned j=0; j<ppars_sz; j++) {
if(ppars[j]<parent) { if (ppars[j]<parent) {
parent = ppars[j]; parent = ppars[j];
} }
} }
if(parent!=i) { if (parent!=i) {
const_infos[i].set_parent_index(parent); const_infos[i].set_parent_index(parent);
} }
} }
@ -305,7 +308,7 @@ namespace datalog {
unsigned get_constant_count(rule * r) { unsigned get_constant_count(rule * r) {
unsigned res = r->get_head()->get_num_args() - count_variable_arguments(r->get_head()); unsigned res = r->get_head()->get_num_args() - count_variable_arguments(r->get_head());
unsigned pos_tail_sz = r->get_positive_tail_size(); unsigned pos_tail_sz = r->get_positive_tail_size();
for(unsigned i=0; i<pos_tail_sz; i++) { for (unsigned i=0; i<pos_tail_sz; i++) {
res+= r->get_tail(i)->get_num_args() - count_variable_arguments(r->get_tail(i)); res+= r->get_tail(i)->get_num_args() - count_variable_arguments(r->get_tail(i));
} }
return res; return res;
@ -313,7 +316,7 @@ namespace datalog {
bool initial_comparator(rule * r1, rule * r2) { bool initial_comparator(rule * r1, rule * r2) {
int res = rough_compare(r1, r2); int res = rough_compare(r1, r2);
if(res!=0) { return res>0; } if (res!=0) { return res>0; }
return total_compare(r1, r2)>0; return total_compare(r1, r2)>0;
} }
@ -348,7 +351,7 @@ namespace datalog {
ptr_vector<sort> aux_domain; ptr_vector<sort> aux_domain;
collect_orphan_sorts(r, const_infos, aux_domain); collect_orphan_sorts(r, const_infos, aux_domain);
func_decl* head_pred = r->get_head()->get_decl(); func_decl* head_pred = r->get_decl();
symbol const& name_prefix = head_pred->get_name(); symbol const& name_prefix = head_pred->get_name();
std::string name_suffix = "sc_" + to_string(const_cnt); std::string name_suffix = "sc_" + to_string(const_cnt);
func_decl * aux_pred = m_context.mk_fresh_head_predicate(name_prefix, symbol(name_suffix.c_str()), func_decl * aux_pred = m_context.mk_fresh_head_predicate(name_prefix, symbol(name_suffix.c_str()),
@ -357,7 +360,7 @@ namespace datalog {
relation_fact val_fact(m_manager, const_cnt); relation_fact val_fact(m_manager, const_cnt);
rule_vector::iterator it = first; rule_vector::iterator it = first;
for(; it!=after_last; ++it) { for (; it!=after_last; ++it) {
collect_orphan_consts(*it, const_infos, val_fact); collect_orphan_consts(*it, const_infos, val_fact);
m_context.add_fact(aux_pred, val_fact); m_context.add_fact(aux_pred, val_fact);
} }
@ -367,7 +370,7 @@ namespace datalog {
ptr_vector<app> new_tail; ptr_vector<app> new_tail;
svector<bool> new_negs; svector<bool> new_negs;
unsigned tail_sz = r->get_tail_size(); unsigned tail_sz = r->get_tail_size();
for(unsigned i=0; i<tail_sz; i++) { for (unsigned i=0; i<tail_sz; i++) {
new_tail.push_back(r->get_tail(i)); new_tail.push_back(r->get_tail(i));
new_negs.push_back(r->is_neg_tail(i)); new_negs.push_back(r->is_neg_tail(i));
} }
@ -375,7 +378,7 @@ namespace datalog {
rule_counter ctr; rule_counter ctr;
ctr.count_rule_vars(m_manager, r); ctr.count_rule_vars(m_manager, r);
unsigned max_var_idx, new_var_idx_base; unsigned max_var_idx, new_var_idx_base;
if(ctr.get_max_positive(max_var_idx)) { if (ctr.get_max_positive(max_var_idx)) {
new_var_idx_base = max_var_idx+1; new_var_idx_base = max_var_idx+1;
} }
else { else {
@ -387,15 +390,15 @@ namespace datalog {
unsigned aux_column_index = 0; unsigned aux_column_index = 0;
for(unsigned i=0; i<const_cnt; ) { for (unsigned i=0; i<const_cnt; ) {
int tail_idx = const_infos[i].tail_index(); int tail_idx = const_infos[i].tail_index();
app * & mod_tail = (tail_idx==-1) ? new_head : new_tail[tail_idx]; app * & mod_tail = (tail_idx==-1) ? new_head : new_tail[tail_idx];
ptr_vector<expr> mod_args(mod_tail->get_num_args(), mod_tail->get_args()); ptr_vector<expr> mod_args(mod_tail->get_num_args(), mod_tail->get_args());
for(; i<const_cnt && const_infos[i].tail_index()==tail_idx; i++) { //here the outer loop counter is modified for (; i<const_cnt && const_infos[i].tail_index()==tail_idx; i++) { //here the outer loop counter is modified
const_info & inf = const_infos[i]; const_info & inf = const_infos[i];
var * mod_var; var * mod_var;
if(!inf.has_parent()) { if (!inf.has_parent()) {
mod_var = m_manager.mk_var(new_var_idx_base+aux_column_index, mod_var = m_manager.mk_var(new_var_idx_base+aux_column_index,
aux_domain[aux_column_index]); aux_domain[aux_column_index]);
aux_column_index++; aux_column_index++;
@ -435,7 +438,7 @@ namespace datalog {
rule_vector::iterator prev = it; rule_vector::iterator prev = it;
++it; ++it;
while(it!=after_last) { while(it!=after_last) {
if(it!=after_last && total_compare(*prev, *it)==0) { if (it!=after_last && total_compare(*prev, *it)==0) {
--after_last; --after_last;
std::swap(*it, *after_last); std::swap(*it, *after_last);
m_modified = true; m_modified = true;
@ -450,7 +453,7 @@ namespace datalog {
unsigned const_cnt = get_constant_count(*first); unsigned const_cnt = get_constant_count(*first);
#if 0 #if 0
for(unsigned ignored_index=0; ignored_index<const_cnt; ignored_index++) { for (unsigned ignored_index=0; ignored_index<const_cnt; ignored_index++) {
arg_ignoring_comparator comparator(ignored_index); arg_ignoring_comparator comparator(ignored_index);
std::sort(first, after_last, comparator); std::sort(first, after_last, comparator);
@ -461,11 +464,11 @@ namespace datalog {
rule_vector::iterator prev = it; rule_vector::iterator prev = it;
++it; ++it;
grp_size++; grp_size++;
if(it==after_last || !comparator.eq(*prev, *it)) { if (it==after_last || !comparator.eq(*prev, *it)) {
if(grp_size>m_threshold_count) { if (grp_size>m_threshold_count) {
merge_class(grp_begin, it); merge_class(grp_begin, it);
//group was processed, so we remove it from the class //group was processed, so we remove it from the class
if(it==after_last) { if (it==after_last) {
after_last=grp_begin; after_last=grp_begin;
it=after_last; it=after_last;
} }
@ -484,9 +487,9 @@ namespace datalog {
//TODO: compress also rules with pairs (or tuples) of equal constants //TODO: compress also rules with pairs (or tuples) of equal constants
#if 1 #if 1
if(const_cnt>0) { if (const_cnt>0) {
unsigned rule_cnt = static_cast<unsigned>(after_last-first); unsigned rule_cnt = static_cast<unsigned>(after_last-first);
if(rule_cnt>m_threshold_count) { if (rule_cnt>m_threshold_count) {
merge_class(first, after_last); merge_class(first, after_last);
return; return;
} }
@ -495,7 +498,7 @@ namespace datalog {
//put rules which weren't merged into result //put rules which weren't merged into result
rule_vector::iterator it = first; rule_vector::iterator it = first;
for(; it!=after_last; ++it) { for (; it!=after_last; ++it) {
m_result_rules.push_back(*it); m_result_rules.push_back(*it);
} }
} }
@ -505,7 +508,7 @@ namespace datalog {
m_modified = false; m_modified = false;
unsigned init_rule_cnt = source.get_num_rules(); unsigned init_rule_cnt = source.get_num_rules();
SASSERT(m_rules.empty()); SASSERT(m_rules.empty());
for(unsigned i=0; i<init_rule_cnt; i++) { for (unsigned i=0; i<init_rule_cnt; i++) {
m_rules.push_back(source.get_rule(i)); m_rules.push_back(source.get_rule(i));
} }
@ -517,19 +520,20 @@ namespace datalog {
while(it!=end) { while(it!=end) {
rule_vector::iterator prev = it; rule_vector::iterator prev = it;
++it; ++it;
if(it==end || rough_compare(*prev, *it)!=0) { if (it==end || rough_compare(*prev, *it)!=0) {
process_class(cl_begin, it); process_class(cl_begin, it);
cl_begin = it; cl_begin = it;
} }
} }
rule_set * result = static_cast<rule_set *>(0); rule_set * result = static_cast<rule_set *>(0);
if(m_modified) { if (m_modified) {
result = alloc(rule_set, m_context); result = alloc(rule_set, m_context);
unsigned fin_rule_cnt = m_result_rules.size(); unsigned fin_rule_cnt = m_result_rules.size();
for(unsigned i=0; i<fin_rule_cnt; i++) { for (unsigned i=0; i<fin_rule_cnt; i++) {
result->add_rule(m_result_rules.get(i)); result->add_rule(m_result_rules.get(i));
} }
result->inherit_predicates(source);
} }
reset(); reset();
return result; return result;

View file

@ -89,7 +89,7 @@ namespace datalog {
m_consumers++; m_consumers++;
} }
if(m_stratified) { if(m_stratified) {
unsigned head_stratum = pl.get_stratum(r->get_head()->get_decl()); unsigned head_stratum = pl.get_stratum(r->get_decl());
SASSERT(head_stratum>=m_src_stratum); SASSERT(head_stratum>=m_src_stratum);
if(head_stratum==m_src_stratum) { if(head_stratum==m_src_stratum) {
m_stratified = false; m_stratified = false;
@ -383,7 +383,7 @@ namespace datalog {
rule * one_parent = inf.m_rules.back(); rule * one_parent = inf.m_rules.back();
func_decl* parent_head = one_parent->get_head()->get_decl(); func_decl* parent_head = one_parent->get_decl();
const char * one_parent_name = parent_head->get_name().bare_str(); const char * one_parent_name = parent_head->get_name().bare_str();
std::string parent_name; std::string parent_name;
if(inf.m_rules.size()>1) { if(inf.m_rules.size()>1) {
@ -714,13 +714,14 @@ namespace datalog {
m_context.get_rule_manager().mk_rule_asserted_proof(*m_introduced_rules.back()); m_context.get_rule_manager().mk_rule_asserted_proof(*m_introduced_rules.back());
m_introduced_rules.pop_back(); m_introduced_rules.pop_back();
} }
result->inherit_predicates(source);
return result; return result;
} }
}; };
rule_set * mk_simple_joins::operator()(rule_set const & source) { rule_set * mk_simple_joins::operator()(rule_set const & source) {
rule_set rs_aux_copy(m_context); rule_set rs_aux_copy(m_context);
rs_aux_copy.add_rules(source); rs_aux_copy.replace_rules(source);
if(!rs_aux_copy.is_closed()) { if(!rs_aux_copy.is_closed()) {
rs_aux_copy.close(); rs_aux_copy.close();
} }

View file

@ -703,7 +703,7 @@ namespace datalog {
m_pinned.reset(); m_pinned.reset();
} }
void mk_slice::declare_predicates() { void mk_slice::declare_predicates(rule_set const& src, rule_set& dst) {
obj_map<func_decl, bit_vector>::iterator it = m_sliceable.begin(), end = m_sliceable.end(); obj_map<func_decl, bit_vector>::iterator it = m_sliceable.begin(), end = m_sliceable.end();
ptr_vector<sort> domain; ptr_vector<sort> domain;
func_decl* f; func_decl* f;
@ -720,6 +720,7 @@ namespace datalog {
f = m_ctx.mk_fresh_head_predicate(p->get_name(), symbol("slice"), domain.size(), domain.c_ptr(), p); f = m_ctx.mk_fresh_head_predicate(p->get_name(), symbol("slice"), domain.size(), domain.c_ptr(), p);
m_pinned.push_back(f); m_pinned.push_back(f);
m_predicates.insert(p, f); m_predicates.insert(p, f);
dst.inherit_predicate(src, p, f);
if (m_mc) { if (m_mc) {
m_mc->add_predicate(p, f); m_mc->add_predicate(p, f);
} }
@ -820,13 +821,14 @@ namespace datalog {
m_mc = smc.get(); m_mc = smc.get();
reset(); reset();
saturate(src); saturate(src);
declare_predicates(); rule_set* result = alloc(rule_set, m_ctx);
declare_predicates(src, *result);
if (m_predicates.empty()) { if (m_predicates.empty()) {
// nothing could be sliced. // nothing could be sliced.
dealloc(result);
return 0; return 0;
} }
TRACE("dl", display(tout);); TRACE("dl", display(tout););
rule_set* result = alloc(rule_set, m_ctx);
update_rules(src, *result); update_rules(src, *result);
TRACE("dl", result->display(tout);); TRACE("dl", result->display(tout););
if (m_mc) { if (m_mc) {

View file

@ -83,7 +83,7 @@ namespace datalog {
expr_ref_vector get_tail_conjs(rule const& r); expr_ref_vector get_tail_conjs(rule const& r);
void declare_predicates(); void declare_predicates(rule_set const& src, rule_set& dst);
bool rule_updated(rule const& r); bool rule_updated(rule const& r);

View file

@ -21,11 +21,8 @@ Revision History:
#include <sstream> #include <sstream>
#include"ast_pp.h" #include"ast_pp.h"
#include "rewriter.h" #include "rewriter.h"
#include "rewriter_def.h" #include "rewriter_def.h"
#include"dl_mk_subsumption_checker.h" #include"dl_mk_subsumption_checker.h"
#include"dl_table_relation.h" #include"dl_table_relation.h"
@ -82,7 +79,7 @@ namespace datalog {
void mk_subsumption_checker::on_discovered_total_relation(func_decl * pred, rule * r) { void mk_subsumption_checker::on_discovered_total_relation(func_decl * pred, rule * r) {
//this should be rule marking a new relation as total //this should be rule marking a new relation as total
SASSERT(!m_total_relations.contains(pred)); SASSERT(!m_total_relations.contains(pred));
SASSERT(!r || pred==r->get_head()->get_decl()); SASSERT(!r || pred==r->get_decl());
SASSERT(!r || is_total_rule(r)); SASSERT(!r || is_total_rule(r));
m_total_relations.insert(pred); m_total_relations.insert(pred);
@ -102,7 +99,7 @@ namespace datalog {
rule_set::iterator rend = rules.end(); rule_set::iterator rend = rules.end();
for(rule_set::iterator rit = rules.begin(); rit!=rend; ++rit) { for(rule_set::iterator rit = rules.begin(); rit!=rend; ++rit) {
rule * r = *rit; rule * r = *rit;
func_decl * head_pred = r->get_head()->get_decl(); func_decl * head_pred = r->get_decl();
if(is_total_rule(r) && !m_total_relations.contains(head_pred)) { if(is_total_rule(r) && !m_total_relations.contains(head_pred)) {
on_discovered_total_relation(head_pred, r); on_discovered_total_relation(head_pred, r);
new_discovered = true; new_discovered = true;
@ -196,10 +193,10 @@ namespace datalog {
for(rule_set::iterator rit = rbegin; rit!=rend; ++rit) { for(rule_set::iterator rit = rbegin; rit!=rend; ++rit) {
rule * r = *rit; rule * r = *rit;
func_decl * head_pred = r->get_head()->get_decl(); func_decl * head_pred = r->get_decl();
if(m_total_relations.contains(head_pred)) { if(m_total_relations.contains(head_pred)) {
if(!m_context.is_output_predicate(head_pred) || if(!orig.is_output_predicate(head_pred) ||
total_relations_with_included_rules.contains(head_pred)) { total_relations_with_included_rules.contains(head_pred)) {
//We just skip definitions of total non-output relations as //We just skip definitions of total non-output relations as
//we'll eliminate them from the problem. //we'll eliminate them from the problem.
@ -217,7 +214,7 @@ namespace datalog {
modified = true; modified = true;
} }
tgt.add_rule(totality_rule); tgt.add_rule(totality_rule);
SASSERT(totality_rule->get_head()->get_decl()==head_pred); SASSERT(totality_rule->get_decl()==head_pred);
} }
else { else {
modified = true; modified = true;
@ -250,24 +247,23 @@ namespace datalog {
return modified; return modified;
} }
void mk_subsumption_checker::scan_for_relations_total_due_to_facts() { void mk_subsumption_checker::scan_for_relations_total_due_to_facts(rule_set const& source) {
relation_manager& rm = m_context.get_rel_context().get_rmanager(); relation_manager& rm = m_context.get_rel_context().get_rmanager();
decl_set candidate_preds; decl_set const& candidate_preds = m_context.get_predicates();
m_context.collect_predicates(candidate_preds);
decl_set::iterator end = candidate_preds.end(); decl_set::iterator end = candidate_preds.end();
for(decl_set::iterator it = candidate_preds.begin(); it!=end; ++it) { for(decl_set::iterator it = candidate_preds.begin(); it!=end; ++it) {
func_decl * pred = *it; func_decl * pred = *it;
if(m_total_relations.contains(pred)) { continue; } //already total if (m_total_relations.contains(pred)) { continue; } //already total
relation_base * rel = rm.try_get_relation(pred); relation_base * rel = rm.try_get_relation(pred);
if(!rel || !rel->knows_exact_size()) { continue; } if (!rel || !rel->knows_exact_size()) { continue; }
unsigned arity = pred->get_arity(); unsigned arity = pred->get_arity();
if(arity>30) { continue; } if (arity > 30) { continue; }
//for now we only check booleans domains //for now we only check booleans domains
for(unsigned i=0; i<arity; i++) { for(unsigned i=0; i<arity; i++) {
@ -307,7 +303,7 @@ namespace datalog {
rule_set::iterator rend = rules.end(); rule_set::iterator rend = rules.end();
for(rule_set::iterator rit = rules.begin(); rit!=rend; ++rit) { for(rule_set::iterator rit = rules.begin(); rit!=rend; ++rit) {
rule * r = *rit; rule * r = *rit;
func_decl * pred = r->get_head()->get_decl(); func_decl * pred = r->get_decl();
if(r->get_tail_size()!=0) { continue; } if(r->get_tail_size()!=0) { continue; }
@ -337,7 +333,7 @@ namespace datalog {
m_have_new_total_rule = false; m_have_new_total_rule = false;
collect_ground_unconditional_rule_heads(source); collect_ground_unconditional_rule_heads(source);
scan_for_relations_total_due_to_facts(); scan_for_relations_total_due_to_facts(source);
scan_for_total_rules(source); scan_for_total_rules(source);
m_have_new_total_rule = false; m_have_new_total_rule = false;
@ -361,6 +357,7 @@ namespace datalog {
transform_rules(*old, *res); transform_rules(*old, *res);
dealloc(old); dealloc(old);
} }
res->inherit_predicates(source);
return res; return res;
} }

View file

@ -64,8 +64,8 @@ namespace datalog {
/** Function to be called when a new total relation is discovered */ /** Function to be called when a new total relation is discovered */
void on_discovered_total_relation(func_decl * pred, rule * r); void on_discovered_total_relation(func_decl * pred, rule * r);
void scan_for_total_rules(const rule_set & rules); void scan_for_total_rules(rule_set const& rules);
void scan_for_relations_total_due_to_facts(); void scan_for_relations_total_due_to_facts(rule_set const& rules);
void collect_ground_unconditional_rule_heads(const rule_set & rules); void collect_ground_unconditional_rule_heads(const rule_set & rules);

View file

@ -26,9 +26,9 @@ namespace datalog {
mk_unbound_compressor::mk_unbound_compressor(context & ctx) : mk_unbound_compressor::mk_unbound_compressor(context & ctx) :
plugin(500), plugin(500),
m_context(ctx), m_context(ctx),
m_manager(ctx.get_manager()), m(ctx.get_manager()),
m_rules(ctx.get_rule_manager()), m_rules(ctx.get_rule_manager()),
m_pinned(m_manager) { m_pinned(m) {
} }
void mk_unbound_compressor::reset() { void mk_unbound_compressor::reset() {
@ -48,7 +48,7 @@ namespace datalog {
unsigned var_idx = to_var(head_arg)->get_idx(); unsigned var_idx = to_var(head_arg)->get_idx();
var_idx_set tail_vars; var_idx_set tail_vars;
collect_tail_vars(m_manager, r, tail_vars); collect_tail_vars(m, r, tail_vars);
return tail_vars.contains(var_idx); return tail_vars.contains(var_idx);
} }
@ -81,14 +81,14 @@ namespace datalog {
m_map.insert(ci, cpred); m_map.insert(ci, cpred);
} }
void mk_unbound_compressor::detect_tasks(unsigned rule_index) { void mk_unbound_compressor::detect_tasks(rule_set const& source, unsigned rule_index) {
rule * r = m_rules.get(rule_index); rule * r = m_rules.get(rule_index);
var_idx_set tail_vars; var_idx_set tail_vars;
collect_tail_vars(m_manager, r, tail_vars); collect_tail_vars(m, r, tail_vars);
app * head = r->get_head(); app * head = r->get_head();
func_decl * head_pred = head->get_decl(); func_decl * head_pred = head->get_decl();
if (m_context.is_output_predicate(head_pred)) { if (source.is_output_predicate(head_pred)) {
//we don't compress output predicates //we don't compress output predicates
return; return;
} }
@ -96,7 +96,7 @@ namespace datalog {
unsigned n = head_pred->get_arity(); unsigned n = head_pred->get_arity();
var_counter head_var_counter; var_counter head_var_counter;
head_var_counter.count_vars(m_manager, head, 1); head_var_counter.count_vars(m, head, 1);
for (unsigned i=0; i<n; i++) { for (unsigned i=0; i<n; i++) {
expr * arg = head->get_arg(i); expr * arg = head->get_arg(i);
@ -118,18 +118,18 @@ namespace datalog {
} }
} }
void mk_unbound_compressor::try_compress(unsigned rule_index) { void mk_unbound_compressor::try_compress(rule_set const& source, unsigned rule_index) {
start: start:
rule * r = m_rules.get(rule_index); rule * r = m_rules.get(rule_index);
var_idx_set tail_vars; var_idx_set tail_vars;
collect_tail_vars(m_manager, r, tail_vars); collect_tail_vars(m, r, tail_vars);
app * head = r->get_head(); app * head = r->get_head();
func_decl * head_pred = head->get_decl(); func_decl * head_pred = head->get_decl();
unsigned head_arity = head_pred->get_arity(); unsigned head_arity = head_pred->get_arity();
var_counter head_var_counter; var_counter head_var_counter;
head_var_counter.count_vars(m_manager, head); head_var_counter.count_vars(m, head);
unsigned arg_index; unsigned arg_index;
for (arg_index = 0; arg_index < head_arity; arg_index++) { for (arg_index = 0; arg_index < head_arity; arg_index++) {
@ -163,13 +163,13 @@ namespace datalog {
} }
} }
app_ref chead(m_manager.mk_app(cpred, head_arity-1, cargs.c_ptr()), m_manager); app_ref chead(m.mk_app(cpred, head_arity-1, cargs.c_ptr()), m);
if (r->get_tail_size()==0 && m_context.get_rule_manager().is_fact(chead)) { if (r->get_tail_size()==0 && m_context.get_rule_manager().is_fact(chead)) {
m_non_empty_rels.insert(cpred); m_non_empty_rels.insert(cpred);
m_context.add_fact(chead); m_context.add_fact(chead);
//remove the rule that became fact by placing the last rule on its place //remove the rule that became fact by placing the last rule on its place
m_head_occurrence_ctr.dec(m_rules.get(rule_index)->get_head()->get_decl()); m_head_occurrence_ctr.dec(m_rules.get(rule_index)->get_decl());
m_rules.set(rule_index, m_rules.get(m_rules.size()-1)); m_rules.set(rule_index, m_rules.get(m_rules.size()-1));
m_rules.shrink(m_rules.size()-1); m_rules.shrink(m_rules.size()-1);
//since we moved the last rule to rule_index, we have to try to compress it as well //since we moved the last rule to rule_index, we have to try to compress it as well
@ -181,10 +181,10 @@ namespace datalog {
rule_ref new_rule(m_context.get_rule_manager().mk(r, chead), m_context.get_rule_manager()); rule_ref new_rule(m_context.get_rule_manager().mk(r, chead), m_context.get_rule_manager());
new_rule->set_accounting_parent_object(m_context, r); new_rule->set_accounting_parent_object(m_context, r);
m_head_occurrence_ctr.dec(m_rules.get(rule_index)->get_head()->get_decl()); m_head_occurrence_ctr.dec(m_rules.get(rule_index)->get_decl());
m_rules.set(rule_index, new_rule); m_rules.set(rule_index, new_rule);
m_head_occurrence_ctr.inc(m_rules.get(rule_index)->get_head()->get_decl()); m_head_occurrence_ctr.inc(m_rules.get(rule_index)->get_decl());
detect_tasks(rule_index); detect_tasks(source, rule_index);
} }
m_modified = true; m_modified = true;
@ -205,10 +205,10 @@ namespace datalog {
} }
} }
SASSERT(dtail_args.size()==dtail_pred->get_arity()); SASSERT(dtail_args.size()==dtail_pred->get_arity());
app_ref dtail(m_manager.mk_app(dtail_pred, dtail_args.size(), dtail_args.c_ptr()), m_manager); app_ref dtail(m.mk_app(dtail_pred, dtail_args.size(), dtail_args.c_ptr()), m);
svector<bool> tails_negated; svector<bool> tails_negated;
app_ref_vector tails(m_manager); app_ref_vector tails(m);
unsigned tail_len = r->get_tail_size(); unsigned tail_len = r->get_tail_size();
for (unsigned i=0; i<tail_len; i++) { for (unsigned i=0; i<tail_len; i++) {
tails_negated.push_back(r->is_neg_tail(i)); tails_negated.push_back(r->is_neg_tail(i));
@ -232,17 +232,17 @@ namespace datalog {
m_context.get_rule_manager().fix_unbound_vars(res, true); m_context.get_rule_manager().fix_unbound_vars(res, true);
} }
void mk_unbound_compressor::add_decompression_rule(rule * r, unsigned tail_index, unsigned arg_index) { void mk_unbound_compressor::add_decompression_rule(rule_set const& source, rule * r, unsigned tail_index, unsigned arg_index) {
rule_ref new_rule(m_context.get_rule_manager()); rule_ref new_rule(m_context.get_rule_manager());
mk_decompression_rule(r, tail_index, arg_index, new_rule); mk_decompression_rule(r, tail_index, arg_index, new_rule);
unsigned new_rule_index = m_rules.size(); unsigned new_rule_index = m_rules.size();
m_rules.push_back(new_rule); m_rules.push_back(new_rule);
m_context.get_rule_manager().mk_rule_rewrite_proof(*r, *new_rule.get()); m_context.get_rule_manager().mk_rule_rewrite_proof(*r, *new_rule.get());
m_head_occurrence_ctr.inc(new_rule->get_head()->get_decl()); m_head_occurrence_ctr.inc(new_rule->get_decl());
detect_tasks(new_rule_index); detect_tasks(source, new_rule_index);
m_modified = true; m_modified = true;
@ -258,7 +258,7 @@ namespace datalog {
//P:- R1(x), S1(x) //P:- R1(x), S1(x)
} }
void mk_unbound_compressor::replace_by_decompression_rule(unsigned rule_index, unsigned tail_index, unsigned arg_index) void mk_unbound_compressor::replace_by_decompression_rule(rule_set const& source, unsigned rule_index, unsigned tail_index, unsigned arg_index)
{ {
rule * r = m_rules.get(rule_index); rule * r = m_rules.get(rule_index);
@ -269,12 +269,12 @@ namespace datalog {
//we don't update the m_head_occurrence_ctr because the head predicate doesn't change //we don't update the m_head_occurrence_ctr because the head predicate doesn't change
detect_tasks(rule_index); detect_tasks(source, rule_index);
m_modified = true; m_modified = true;
} }
void mk_unbound_compressor::add_decompression_rules(unsigned rule_index) { void mk_unbound_compressor::add_decompression_rules(rule_set const& source, unsigned rule_index) {
unsigned_vector compressed_tail_pred_arg_indexes; unsigned_vector compressed_tail_pred_arg_indexes;
@ -306,11 +306,11 @@ namespace datalog {
m_head_occurrence_ctr.get(t_pred)==0; m_head_occurrence_ctr.get(t_pred)==0;
if (can_remove_orig_rule || is_negated_predicate) { if (can_remove_orig_rule || is_negated_predicate) {
replace_by_decompression_rule(rule_index, tail_index, arg_index); replace_by_decompression_rule(source, rule_index, tail_index, arg_index);
orig_rule_replaced = true; orig_rule_replaced = true;
} }
else { else {
add_decompression_rule(r, tail_index, arg_index); add_decompression_rule(source, r, tail_index, arg_index);
} }
} }
if (orig_rule_replaced) { if (orig_rule_replaced) {
@ -345,11 +345,11 @@ namespace datalog {
for (unsigned i=0; i<init_rule_cnt; i++) { for (unsigned i=0; i<init_rule_cnt; i++) {
rule * r = source.get_rule(i); rule * r = source.get_rule(i);
m_rules.push_back(r); m_rules.push_back(r);
m_head_occurrence_ctr.inc(r->get_head()->get_decl()); m_head_occurrence_ctr.inc(r->get_decl());
} }
for (unsigned i=0; i<init_rule_cnt; i++) { for (unsigned i=0; i<init_rule_cnt; i++) {
detect_tasks(i); detect_tasks(source, i);
} }
while (!m_todo.empty()) { while (!m_todo.empty()) {
@ -360,9 +360,9 @@ namespace datalog {
} }
unsigned rule_index = 0; unsigned rule_index = 0;
while (rule_index<m_rules.size()) { while (rule_index<m_rules.size()) {
try_compress(rule_index); //m_rules.size() can change here try_compress(source, rule_index); //m_rules.size() can change here
if (rule_index<m_rules.size()) { if (rule_index<m_rules.size()) {
add_decompression_rules(rule_index); //m_rules.size() can change here add_decompression_rules(source, rule_index); //m_rules.size() can change here
} }
rule_index++; rule_index++;
} }
@ -375,6 +375,7 @@ namespace datalog {
for (unsigned i=0; i<fin_rule_cnt; i++) { for (unsigned i=0; i<fin_rule_cnt; i++) {
result->add_rule(m_rules.get(i)); result->add_rule(m_rules.get(i));
} }
result->inherit_predicates(source);
} }
reset(); reset();
return result; return result;

View file

@ -50,8 +50,8 @@ namespace datalog {
typedef hashtable<c_info, c_info_hash, default_eq<c_info> > in_progress_table; typedef hashtable<c_info, c_info_hash, default_eq<c_info> > in_progress_table;
typedef svector<c_info> todo_stack; typedef svector<c_info> todo_stack;
context & m_context; context & m_context;
ast_manager & m_manager; ast_manager & m;
rule_ref_vector m_rules; rule_ref_vector m_rules;
bool m_modified; bool m_modified;
todo_stack m_todo; todo_stack m_todo;
@ -71,13 +71,13 @@ namespace datalog {
bool is_unbound_argument(rule * r, unsigned head_index); bool is_unbound_argument(rule * r, unsigned head_index);
bool has_unbound_head_var(rule * r); bool has_unbound_head_var(rule * r);
void detect_tasks(unsigned rule_index); void detect_tasks(rule_set const& source, unsigned rule_index);
void add_task(func_decl * pred, unsigned arg_index); void add_task(func_decl * pred, unsigned arg_index);
void try_compress(unsigned rule_index); void try_compress(rule_set const& source, unsigned rule_index);
void add_decompression_rules(unsigned rule_index); void add_decompression_rules(rule_set const& source, unsigned rule_index);
void mk_decompression_rule(rule * r, unsigned tail_index, unsigned arg_index, rule_ref& res); void mk_decompression_rule(rule * r, unsigned tail_index, unsigned arg_index, rule_ref& res);
void add_decompression_rule(rule * r, unsigned tail_index, unsigned arg_index); void add_decompression_rule(rule_set const& source, rule * r, unsigned tail_index, unsigned arg_index);
void replace_by_decompression_rule(unsigned rule_index, unsigned tail_index, unsigned arg_index); void replace_by_decompression_rule(rule_set const& source, unsigned rule_index, unsigned tail_index, unsigned arg_index);
void reset(); void reset();
public: public:
mk_unbound_compressor(context & ctx); mk_unbound_compressor(context & ctx);

View file

@ -56,6 +56,7 @@ namespace datalog {
for (; it != end; ++it) { for (; it != end; ++it) {
expand_tail(**it, 0, source, *rules); expand_tail(**it, 0, source, *rules);
} }
rules->inherit_predicates(source);
return rules; return rules;
} }

View file

@ -124,14 +124,6 @@ namespace datalog {
e->get_data().m_value = rel; e->get_data().m_value = rel;
} }
void relation_manager::collect_predicates(decl_set & res) const {
relation_map::iterator it = m_relations.begin();
relation_map::iterator end = m_relations.end();
for(; it!=end; ++it) {
res.insert(it->m_key);
}
}
void relation_manager::collect_non_empty_predicates(decl_set & res) const { void relation_manager::collect_non_empty_predicates(decl_set & res) const {
relation_map::iterator it = m_relations.begin(); relation_map::iterator it = m_relations.begin();
relation_map::iterator end = m_relations.end(); relation_map::iterator end = m_relations.end();
@ -539,8 +531,8 @@ namespace datalog {
} }
} }
void relation_manager::display_output_tables(std::ostream & out) const { void relation_manager::display_output_tables(rule_set const& rules, std::ostream & out) const {
const decl_set & output_preds = get_context().get_output_predicates(); const decl_set & output_preds = rules.get_output_predicates();
decl_set::iterator it=output_preds.begin(); decl_set::iterator it=output_preds.begin();
decl_set::iterator end=output_preds.end(); decl_set::iterator end=output_preds.end();
for(; it!=end; ++it) { for(; it!=end; ++it) {

View file

@ -22,7 +22,6 @@ Revision History:
#include"map.h" #include"map.h"
#include"vector.h" #include"vector.h"
#include"dl_base.h" #include"dl_base.h"
namespace datalog { namespace datalog {
@ -35,8 +34,8 @@ namespace datalog {
class finite_product_relation_plugin; class finite_product_relation_plugin;
class sieve_relation; class sieve_relation;
class sieve_relation_plugin; class sieve_relation_plugin;
class rule_set;
typedef hashtable<func_decl * , ptr_hash<func_decl>, ptr_eq<func_decl> > decl_set;
class relation_manager { class relation_manager {
class empty_signature_relation_join_fn; class empty_signature_relation_join_fn;
@ -153,7 +152,6 @@ namespace datalog {
} }
} }
void collect_predicates(decl_set & res) const;
void collect_non_empty_predicates(decl_set & res) const; void collect_non_empty_predicates(decl_set & res) const;
void restrict_predicates(const decl_set & preds); void restrict_predicates(const decl_set & preds);
@ -595,7 +593,7 @@ namespace datalog {
void display(std::ostream & out) const; void display(std::ostream & out) const;
void display_relation_sizes(std::ostream & out) const; void display_relation_sizes(std::ostream & out) const;
void display_output_tables(std::ostream & out) const; void display_output_tables(rule_set const& rules, std::ostream & out) const;
private: private:
relation_intersection_filter_fn * try_mk_default_filter_by_intersection_fn(const relation_base & t, relation_intersection_filter_fn * try_mk_default_filter_by_intersection_fn(const relation_base & t,

View file

@ -50,10 +50,6 @@ namespace datalog {
: m(ctx.get_manager()), : m(ctx.get_manager()),
m_ctx(ctx) {} m_ctx(ctx) {}
bool rule_manager::is_predicate(func_decl * f) const {
return m_ctx.is_predicate(f);
}
void rule_manager::inc_ref(rule * r) { void rule_manager::inc_ref(rule * r) {
if (r) { if (r) {
SASSERT(r->m_ref_cnt != UINT_MAX); SASSERT(r->m_ref_cnt != UINT_MAX);
@ -102,7 +98,7 @@ namespace datalog {
} }
void rule_manager::mk_rule(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name) { void rule_manager::mk_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) {
scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED); scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED);
proof_ref pr(p, m); proof_ref pr(p, m);
expr_ref fml1(m); expr_ref fml1(m);
@ -111,13 +107,13 @@ namespace datalog {
pr = m.mk_asserted(fml1); pr = m.mk_asserted(fml1);
} }
remove_labels(fml1, pr); remove_labels(fml1, pr);
mk_rule_core_new(fml1, pr, rules, name); mk_rule_core(fml1, pr, rules, name);
} }
void rule_manager::mk_negations(app_ref_vector& body, svector<bool>& is_negated) { void rule_manager::mk_negations(app_ref_vector& body, svector<bool>& is_negated) {
for (unsigned i = 0; i < body.size(); ++i) { for (unsigned i = 0; i < body.size(); ++i) {
expr* e = body[i].get(), *e1; expr* e = body[i].get(), *e1;
if (m.is_not(e, e1) && is_predicate(e1)) { if (m.is_not(e, e1) && m_ctx.is_predicate(e1)) {
check_app(e1); check_app(e1);
body[i] = to_app(e1); body[i] = to_app(e1);
is_negated.push_back(true); is_negated.push_back(true);
@ -128,7 +124,7 @@ namespace datalog {
} }
} }
void rule_manager::mk_rule_core_new(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name) { void rule_manager::mk_rule_core(expr* fml, proof* p, rule_set& rules, symbol const& name) {
hnf h(m); hnf h(m);
expr_ref_vector fmls(m); expr_ref_vector fmls(m);
proof_ref_vector prs(m); proof_ref_vector prs(m);
@ -138,11 +134,11 @@ namespace datalog {
m_ctx.register_predicate(h.get_fresh_predicates()[i], false); m_ctx.register_predicate(h.get_fresh_predicates()[i], false);
} }
for (unsigned i = 0; i < fmls.size(); ++i) { for (unsigned i = 0; i < fmls.size(); ++i) {
mk_rule_core2(fmls[i].get(), prs[i].get(), rules, name); mk_horn_rule(fmls[i].get(), prs[i].get(), rules, name);
} }
} }
void rule_manager::mk_rule_core2(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name) { void rule_manager::mk_horn_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) {
app_ref_vector body(m); app_ref_vector body(m);
app_ref head(m); app_ref head(m);
@ -189,7 +185,7 @@ namespace datalog {
} }
r->set_proof(m, p); r->set_proof(m, p);
} }
rules.push_back(r); rules.add_rule(r);
} }
unsigned rule_manager::extract_horn(expr* fml, app_ref_vector& body, app_ref& head) { unsigned rule_manager::extract_horn(expr* fml, app_ref_vector& body, app_ref& head) {
@ -224,7 +220,7 @@ namespace datalog {
} }
void rule_manager::mk_query(expr* query, func_decl_ref& qpred, rule_ref_vector& query_rules, rule_ref& query_rule) { func_decl* rule_manager::mk_query(expr* query, rule_set& rules) {
ptr_vector<sort> vars; ptr_vector<sort> vars;
svector<symbol> names; svector<symbol> names;
app_ref_vector body(m); app_ref_vector body(m);
@ -279,7 +275,9 @@ namespace datalog {
} }
vars.reverse(); vars.reverse();
names.reverse(); names.reverse();
qpred = m_ctx.mk_fresh_head_predicate(symbol("query"), symbol(), vars.size(), vars.c_ptr(), body_pred); func_decl* qpred = m_ctx.mk_fresh_head_predicate(symbol("query"), symbol(), vars.size(), vars.c_ptr(), body_pred);
m_ctx.register_predicate(qpred, false);
rules.set_output_predicate(qpred);
expr_ref_vector qhead_args(m); expr_ref_vector qhead_args(m);
for (unsigned i = 0; i < vars.size(); i++) { for (unsigned i = 0; i < vars.size(); i++) {
@ -297,9 +295,8 @@ namespace datalog {
if (m_ctx.generate_proof_trace()) { if (m_ctx.generate_proof_trace()) {
pr = m.mk_asserted(rule_expr); pr = m.mk_asserted(rule_expr);
} }
mk_rule(rule_expr, pr, query_rules); mk_rule(rule_expr, pr, rules);
SASSERT(query_rules.size() >= 1); return qpred;
query_rule = query_rules.back();
} }
void rule_manager::bind_variables(expr* fml, bool is_forall, expr_ref& result) { void rule_manager::bind_variables(expr* fml, bool is_forall, expr_ref& result) {
@ -330,7 +327,7 @@ namespace datalog {
return; return;
} }
expr_ref_vector args(m); expr_ref_vector args(m);
if (!is_predicate(fml)) { if (!m_ctx.is_predicate(fml)) {
return; return;
} }
for (unsigned i = 0; i < fml->get_num_args(); ++i) { for (unsigned i = 0; i < fml->get_num_args(); ++i) {
@ -355,19 +352,19 @@ namespace datalog {
} }
class contains_predicate_proc { class contains_predicate_proc {
rule_manager const& m; context const& ctx;
public: public:
struct found {}; struct found {};
contains_predicate_proc(rule_manager const& m): m(m) {} contains_predicate_proc(context const& ctx): ctx(ctx) {}
void operator()(var * n) {} void operator()(var * n) {}
void operator()(quantifier * n) {} void operator()(quantifier * n) {}
void operator()(app* n) { void operator()(app* n) {
if (m.is_predicate(n)) throw found(); if (ctx.is_predicate(n)) throw found();
} }
}; };
bool rule_manager::contains_predicate(expr* fml) const { bool rule_manager::contains_predicate(expr* fml) const {
contains_predicate_proc proc(*this); contains_predicate_proc proc(m_ctx);
try { try {
quick_for_each_expr(proc, fml); quick_for_each_expr(proc, fml);
} }
@ -434,7 +431,7 @@ namespace datalog {
bool is_neg = (is_negated != 0 && is_negated[i]); bool is_neg = (is_negated != 0 && is_negated[i]);
app * curr = tail[i]; app * curr = tail[i];
if (is_neg && !is_predicate(curr)) { if (is_neg && !m_ctx.is_predicate(curr)) {
curr = m.mk_not(curr); curr = m.mk_not(curr);
is_neg = false; is_neg = false;
} }
@ -442,7 +439,7 @@ namespace datalog {
has_neg = true; has_neg = true;
} }
app * tail_entry = TAG(app *, curr, is_neg); app * tail_entry = TAG(app *, curr, is_neg);
if (is_predicate(curr)) { if (m_ctx.is_predicate(curr)) {
*uninterp_tail=tail_entry; *uninterp_tail=tail_entry;
uninterp_tail++; uninterp_tail++;
} }
@ -755,7 +752,7 @@ namespace datalog {
void rule_manager::check_valid_head(expr * head) const { void rule_manager::check_valid_head(expr * head) const {
SASSERT(head); SASSERT(head);
if (!is_predicate(head)) { if (!m_ctx.is_predicate(head)) {
std::ostringstream out; std::ostringstream out;
out << "Illegal head. The head predicate needs to be uninterpreted and registered (as recursive) " << mk_pp(head, m); out << "Illegal head. The head predicate needs to be uninterpreted and registered (as recursive) " << mk_pp(head, m);
throw default_exception(out.str()); throw default_exception(out.str());
@ -966,7 +963,7 @@ namespace datalog {
if (is_neg_tail(i)) if (is_neg_tail(i))
out << "not "; out << "not ";
app * t = get_tail(i); app * t = get_tail(i);
if (ctx.get_rule_manager().is_predicate(t)) { if (ctx.is_predicate(t)) {
output_predicate(ctx, t, out); output_predicate(ctx, t, out);
} }
else { else {

View file

@ -32,6 +32,7 @@ namespace datalog {
class rule; class rule;
class rule_manager; class rule_manager;
class rule_set;
class table; class table;
class context; class context;
@ -74,13 +75,11 @@ namespace datalog {
void bind_variables(expr* fml, bool is_forall, expr_ref& result); void bind_variables(expr* fml, bool is_forall, expr_ref& result);
void mk_rule_core(expr* fml, rule_ref_vector& rules, symbol const& name);
void mk_negations(app_ref_vector& body, svector<bool>& is_negated); void mk_negations(app_ref_vector& body, svector<bool>& is_negated);
void mk_rule_core_new(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name); void mk_rule_core(expr* fml, proof* p, rule_set& rules, symbol const& name);
void mk_rule_core2(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name); void mk_horn_rule(expr* fml, proof* p, rule_set& rules, symbol const& name);
static expr_ref mk_implies(app_ref_vector const& body, expr* head); static expr_ref mk_implies(app_ref_vector const& body, expr* head);
@ -104,13 +103,13 @@ namespace datalog {
The formula is of the form (forall (...) (forall (...) (=> (and ...) head))) The formula is of the form (forall (...) (forall (...) (=> (and ...) head)))
*/ */
void mk_rule(expr* fml, proof* p, rule_ref_vector& rules, symbol const& name = symbol::null); void mk_rule(expr* fml, proof* p, rule_set& rules, symbol const& name = symbol::null);
/** /**
\brief Create a Datalog query from an expression. \brief Create a Datalog query from an expression.
The formula is of the form (exists (...) (exists (...) (and ...)) The formula is of the form (exists (...) (exists (...) (and ...))
*/ */
void mk_query(expr* query, func_decl_ref& query_pred, rule_ref_vector& query_rules, rule_ref& query_rule); func_decl* mk_query(expr* query, rule_set& rules);
/** /**
\brief Create a Datalog rule head :- tail[0], ..., tail[n-1]. \brief Create a Datalog rule head :- tail[0], ..., tail[n-1].
@ -166,11 +165,6 @@ namespace datalog {
bool is_fact(app * head) const; bool is_fact(app * head) const;
bool is_predicate(func_decl * f) const;
bool is_predicate(expr * e) const {
return is_app(e) && is_predicate(to_app(e)->get_decl());
}
static bool is_forall(ast_manager& m, expr* e, quantifier*& q); static bool is_forall(ast_manager& m, expr* e, quantifier*& q);
rule_counter& get_counter() { return m_counter; } rule_counter& get_counter() { return m_counter; }

View file

@ -64,8 +64,7 @@ namespace datalog {
reset_dealloc_values(m_data); reset_dealloc_values(m_data);
} }
void rule_dependencies::remove_m_data_entry(func_decl * key) void rule_dependencies::remove_m_data_entry(func_decl * key) {
{
item_set * itm_set = m_data.find(key); item_set * itm_set = m_data.find(key);
dealloc(itm_set); dealloc(itm_set);
m_data.remove(key); m_data.remove(key);
@ -109,7 +108,7 @@ namespace datalog {
void rule_dependencies::populate(rule const* r) { void rule_dependencies::populate(rule const* r) {
TRACE("dl_verbose", tout << r->get_decl()->get_name() << "\n";); TRACE("dl_verbose", tout << r->get_decl()->get_name() << "\n";);
m_visited.reset(); m_visited.reset();
func_decl * d = r->get_head()->get_decl(); func_decl * d = r->get_decl();
func_decl_set & s = ensure_key(d); func_decl_set & s = ensure_key(d);
for (unsigned i = 0; i < r->get_tail_size(); ++i) { for (unsigned i = 0; i < r->get_tail_size(); ++i) {
@ -164,7 +163,7 @@ namespace datalog {
} }
ptr_vector<func_decl>::iterator rit = to_remove.begin(); ptr_vector<func_decl>::iterator rit = to_remove.begin();
ptr_vector<func_decl>::iterator rend = to_remove.end(); ptr_vector<func_decl>::iterator rend = to_remove.end();
for (; rit!=rend; ++rit) { for (; rit != rend; ++rit) {
remove_m_data_entry(*rit); remove_m_data_entry(*rit);
} }
} }
@ -173,7 +172,7 @@ namespace datalog {
remove_m_data_entry(itm); remove_m_data_entry(itm);
iterator pit = begin(); iterator pit = begin();
iterator pend = end(); iterator pend = end();
for (; pit!=pend; ++pit) { for (; pit != pend; ++pit) {
item_set & itms = *pit->get_value(); item_set & itms = *pit->get_value();
itms.remove(itm); itms.remove(itm);
} }
@ -244,7 +243,7 @@ namespace datalog {
} }
curr_index++; curr_index++;
} }
if (res.size()<init_len+m_data.size()) { if (res.size() < init_len + m_data.size()) {
res.shrink(init_len); res.shrink(init_len);
return false; return false;
} }
@ -283,17 +282,19 @@ namespace datalog {
m_rule_manager(ctx.get_rule_manager()), m_rule_manager(ctx.get_rule_manager()),
m_rules(m_rule_manager), m_rules(m_rule_manager),
m_deps(ctx), m_deps(ctx),
m_stratifier(0) { m_stratifier(0),
m_refs(ctx.get_manager()) {
} }
rule_set::rule_set(const rule_set & rs) rule_set::rule_set(const rule_set & other)
: m_context(rs.m_context), : m_context(other.m_context),
m_rule_manager(rs.m_rule_manager), m_rule_manager(other.m_rule_manager),
m_rules(m_rule_manager), m_rules(m_rule_manager),
m_deps(rs.m_context), m_deps(other.m_context),
m_stratifier(0) { m_stratifier(0),
add_rules(rs); m_refs(m_context.get_manager()) {
if (rs.m_stratifier) { add_rules(other);
if (other.m_stratifier) {
VERIFY(close()); VERIFY(close());
} }
} }
@ -303,18 +304,67 @@ namespace datalog {
} }
void rule_set::reset() { void rule_set::reset() {
if (m_stratifier) { m_rules.reset();
m_stratifier = 0;
}
reset_dealloc_values(m_head2rules); reset_dealloc_values(m_head2rules);
m_deps.reset(); m_deps.reset();
m_rules.reset(); m_stratifier = 0;
m_output_preds.reset();
m_orig2pred.reset();
m_pred2orig.reset();
m_refs.reset();
} }
ast_manager & rule_set::get_manager() const { ast_manager & rule_set::get_manager() const {
return m_context.get_manager(); return m_context.get_manager();
} }
func_decl* rule_set::get_orig(func_decl* pred) const {
func_decl* orig = pred;
m_pred2orig.find(pred, orig);
return orig;
}
func_decl* rule_set::get_pred(func_decl* orig) const {
func_decl* pred = orig;
m_orig2pred.find(orig, pred);
return pred;
}
void rule_set::inherit_predicates(rule_set const& other) {
m_refs.append(other.m_refs);
SASSERT(m_refs.size() < 1000);
set_union(m_output_preds, other.m_output_preds);
{
obj_map<func_decl, func_decl*>::iterator it = other.m_orig2pred.begin();
obj_map<func_decl, func_decl*>::iterator end = other.m_orig2pred.end();
for (; it != end; ++it) {
m_orig2pred.insert(it->m_key, it->m_value);
m_refs.push_back(it->m_key);
m_refs.push_back(it->m_value);
}
}
{
obj_map<func_decl, func_decl*>::iterator it = other.m_pred2orig.begin();
obj_map<func_decl, func_decl*>::iterator end = other.m_pred2orig.end();
for (; it != end; ++it) {
m_pred2orig.insert(it->m_key, it->m_value);
m_refs.push_back(it->m_key);
m_refs.push_back(it->m_value);
}
}
}
void rule_set::inherit_predicate(rule_set const& other, func_decl* orig, func_decl* pred) {
if (other.is_output_predicate(orig)) {
set_output_predicate(pred);
}
orig = other.get_orig(orig);
m_refs.push_back(pred);
m_refs.push_back(orig);
m_orig2pred.insert(orig, pred);
m_pred2orig.insert(pred, orig);
}
void rule_set::add_rule(rule * r) { void rule_set::add_rule(rule * r) {
TRACE("dl_verbose", r->display(m_context, tout << "add:");); TRACE("dl_verbose", r->display(m_context, tout << "add:"););
SASSERT(!is_closed()); SASSERT(!is_closed());
@ -329,7 +379,7 @@ namespace datalog {
void rule_set::del_rule(rule * r) { void rule_set::del_rule(rule * r) {
TRACE("dl", r->display(m_context, tout << "del:");); TRACE("dl", r->display(m_context, tout << "del:"););
func_decl* d = r->get_head()->get_decl(); func_decl* d = r->get_decl();
rule_vector* rules = m_head2rules.find(d); rule_vector* rules = m_head2rules.find(d);
#define DEL_VECTOR(_v) \ #define DEL_VECTOR(_v) \
for (unsigned i = (_v).size(); i > 0; ) { \ for (unsigned i = (_v).size(); i > 0; ) { \
@ -345,8 +395,7 @@ namespace datalog {
DEL_VECTOR(m_rules); DEL_VECTOR(m_rules);
} }
void rule_set::ensure_closed() void rule_set::ensure_closed() {
{
if (!is_closed()) { if (!is_closed()) {
VERIFY(close()); VERIFY(close());
} }
@ -354,23 +403,18 @@ namespace datalog {
bool rule_set::close() { bool rule_set::close() {
SASSERT(!is_closed()); //the rule_set is not already closed SASSERT(!is_closed()); //the rule_set is not already closed
m_deps.populate(*this); m_deps.populate(*this);
m_stratifier = alloc(rule_stratifier, m_deps); m_stratifier = alloc(rule_stratifier, m_deps);
if (!stratified_negation()) { if (!stratified_negation()) {
m_stratifier = 0; m_stratifier = 0;
m_deps.reset(); m_deps.reset();
return false; return false;
} }
return true; return true;
} }
void rule_set::reopen() { void rule_set::reopen() {
SASSERT(is_closed()); SASSERT(is_closed());
m_stratifier = 0; m_stratifier = 0;
m_deps.reset(); m_deps.reset();
} }
@ -401,18 +445,20 @@ namespace datalog {
return true; return true;
} }
void rule_set::add_rules(const rule_set & src) { void rule_set::replace_rules(const rule_set & src) {
SASSERT(!is_closed()); if (this != &src) {
unsigned n = src.get_num_rules(); reset();
for (unsigned i=0; i<n; i++) { add_rules(src);
add_rule(src.get_rule(i));
} }
} }
void rule_set::add_rules(unsigned sz, rule * const * rules) { void rule_set::add_rules(const rule_set & src) {
for (unsigned i=0; i<sz; i++) { SASSERT(!is_closed());
add_rule(rules[i]); unsigned n = src.get_num_rules();
for (unsigned i = 0; i < n; i++) {
add_rule(src.get_rule(i));
} }
inherit_predicates(src);
} }
const rule_vector & rule_set::get_predicate_rules(func_decl * pred) const { const rule_vector & rule_set::get_predicate_rules(func_decl * pred) const {
@ -433,6 +479,38 @@ namespace datalog {
return m_stratifier->get_predicate_strat(pred); return m_stratifier->get_predicate_strat(pred);
} }
void rule_set::split_founded_rules(func_decl_set& founded, func_decl_set& non_founded) {
founded.reset();
non_founded.reset();
{
decl2rules::iterator it = begin_grouped_rules(), end = end_grouped_rules();
for (; it != end; ++it) {
non_founded.insert(it->m_key);
}
}
bool change = true;
while (change) {
change = false;
func_decl_set::iterator it = non_founded.begin(), end = non_founded.end();
for (; it != end; ++it) {
rule_vector const& rv = get_predicate_rules(*it);
bool found = false;
for (unsigned i = 0; !found && i < rv.size(); ++i) {
rule const& r = *rv[i];
bool is_founded = true;
for (unsigned j = 0; is_founded && j < r.get_uninterpreted_tail_size(); ++j) {
is_founded = founded.contains(r.get_decl(j));
}
if (is_founded) {
founded.insert(*it);
non_founded.remove(*it);
change = true;
found = true;
}
}
}
}
}
void rule_set::display(std::ostream & out) const { void rule_set::display(std::ostream & out) const {
out << "; rule count: " << get_num_rules() << "\n"; out << "; rule count: " << get_num_rules() << "\n";
@ -451,17 +529,6 @@ namespace datalog {
r->display(m_context, out); r->display(m_context, out);
} }
} }
#if 0 //print dependencies
out<<"##\n";
out<<m_deps.size()<<"\n";
#endif
#if 0 //print strats
out<<"##\n";
stratifier strat(m_deps);
#endif
} }

View file

@ -162,10 +162,14 @@ namespace datalog {
context & m_context; context & m_context;
rule_manager & m_rule_manager; rule_manager & m_rule_manager;
rule_ref_vector m_rules; //!< all rules rule_ref_vector m_rules; //!< all rules
decl2rules m_head2rules; //!< mapping from head symbol to rules. decl2rules m_head2rules; //!< mapping from head symbol to rules.
rule_dependencies m_deps; //!< dependencies rule_dependencies m_deps; //!< dependencies
scoped_ptr<rule_stratifier> m_stratifier; //!< contains stratifier object iff the rule_set is closed scoped_ptr<rule_stratifier> m_stratifier; //!< contains stratifier object iff the rule_set is closed
func_decl_set m_output_preds; //!< output predicates
obj_map<func_decl,func_decl*> m_orig2pred;
obj_map<func_decl,func_decl*> m_pred2orig;
func_decl_ref_vector m_refs;
//sometimes we need to return reference to an empty rule_vector, //sometimes we need to return reference to an empty rule_vector,
@ -184,6 +188,12 @@ namespace datalog {
rule_manager & get_rule_manager() const { return const_cast<rule_manager&>(m_rule_manager); } rule_manager & get_rule_manager() const { return const_cast<rule_manager&>(m_rule_manager); }
context& get_context() const { return m_context; } context& get_context() const { return m_context; }
void inherit_predicates(rule_set const& other);
void inherit_predicate(rule_set const& other, func_decl* orig, func_decl* pred);
func_decl* get_orig(func_decl* pred) const;
func_decl* get_pred(func_decl* orig) const;
/** /**
\brief Add rule \c r to the rule set. \brief Add rule \c r to the rule set.
*/ */
@ -198,7 +208,7 @@ namespace datalog {
\brief Add all rules from a different rule_set. \brief Add all rules from a different rule_set.
*/ */
void add_rules(const rule_set& src); void add_rules(const rule_set& src);
void add_rules(unsigned sz, rule * const * rules); void replace_rules(const rule_set& other);
/** /**
\brief This method should be invoked after all rules are added to the rule set. \brief This method should be invoked after all rules are added to the rule set.
@ -216,11 +226,14 @@ namespace datalog {
bool is_closed() const { return m_stratifier != 0; } bool is_closed() const { return m_stratifier != 0; }
unsigned get_num_rules() const { return m_rules.size(); } unsigned get_num_rules() const { return m_rules.size(); }
bool empty() const { return m_rules.size() == 0; }
rule * get_rule(unsigned i) const { return m_rules[i]; } rule * get_rule(unsigned i) const { return m_rules[i]; }
rule * last() const { return m_rules[m_rules.size()-1]; }
rule_ref_vector const& get_rules() const { return m_rules; } rule_ref_vector const& get_rules() const { return m_rules; }
const rule_vector & get_predicate_rules(func_decl * pred) const; const rule_vector & get_predicate_rules(func_decl * pred) const;
bool contains(func_decl* pred) const { return m_head2rules.contains(pred); }
const rule_stratifier & get_stratifier() const { const rule_stratifier & get_stratifier() const {
SASSERT(m_stratifier); SASSERT(m_stratifier);
@ -230,9 +243,17 @@ namespace datalog {
unsigned get_predicate_strat(func_decl * pred) const; unsigned get_predicate_strat(func_decl * pred) const;
const rule_dependencies & get_dependencies() const { SASSERT(is_closed()); return m_deps; } const rule_dependencies & get_dependencies() const { SASSERT(is_closed()); return m_deps; }
// split predicats into founded and non-founded.
void split_founded_rules(func_decl_set& founded, func_decl_set& non_founded);
void reset(); void reset();
void set_output_predicate(func_decl * pred) { m_refs.push_back(pred); m_output_preds.insert(pred); }
bool is_output_predicate(func_decl * pred) const { return m_output_preds.contains(pred); }
const func_decl_set & get_output_predicates() const { return m_output_preds; }
func_decl* get_output_predicate() const { SASSERT(m_output_preds.size() == 1); return *m_output_preds.begin(); }
void display(std::ostream & out) const; void display(std::ostream & out) const;
/** /**

View file

@ -80,36 +80,38 @@ namespace datalog {
tout<<"init:\n"; tout<<"init:\n";
rules.display(tout); rules.display(tout);
); );
rule_set* new_rules = alloc(rule_set, rules);
plugin_vector::iterator it = m_plugins.begin(); plugin_vector::iterator it = m_plugins.begin();
plugin_vector::iterator end = m_plugins.end(); plugin_vector::iterator end = m_plugins.end();
for(; it!=end && !m_context.canceled(); ++it) { for(; it!=end && !m_context.canceled(); ++it) {
plugin & p = **it; plugin & p = **it;
rule_set * new_rules = p(rules); rule_set * new_rules1 = p(*new_rules);
if (!new_rules) { if (!new_rules1) {
continue; continue;
} }
if (p.can_destratify_negation()) { if (p.can_destratify_negation() &&
if (!new_rules->is_closed()) { !new_rules1->is_closed() &&
if (!new_rules->close()) { !new_rules1->close()) {
warning_msg("a rule transformation skipped because it destratified negation"); warning_msg("a rule transformation skipped "
dealloc(new_rules); "because it destratified negation");
continue; dealloc(new_rules1);
} continue;
}
} }
modified = true; modified = true;
rules.reset();
rules.add_rules(*new_rules);
dealloc(new_rules); dealloc(new_rules);
rules.ensure_closed(); new_rules = new_rules1;
new_rules->ensure_closed();
TRACE("dl_rule_transf", TRACE("dl_rule_transf",
tout << typeid(p).name()<<":\n"; tout << typeid(p).name()<<":\n";
rules.display(tout); new_rules->display(tout);
); );
} }
if (modified) {
rules.replace_rules(*new_rules);
}
dealloc(new_rules);
return modified; return modified;
} }

View file

@ -1,622 +0,0 @@
/*++
Copyright (c) 2010 Microsoft Corporation
Module Name:
dl_skip_table.h
Abstract:
<abstract>
Author:
Nikolaj Bjorner (nbjorner)
Leonardo de Moura (leonardo) 2010-10-14
Revision History:
--*/
#ifndef _EXTERNAL_RELEASE
#include "dl_skip_table.h"
#include "dl_table.h"
#include "dl_context.h"
namespace datalog {
skip_table & skip_table_plugin::get(table_base& r) {
return static_cast<skip_table&>(r);
}
skip_table const & skip_table_plugin::get(table_base const& r) {
return static_cast<skip_table const &>(r);
}
table_base * skip_table_plugin::mk_empty(const table_signature & s) {
return alloc(skip_table, *this, s);
}
skip_table* skip_table_plugin::mk_join(
table_base const& t1, table_base const& t2, table_signature const& result_sig,
unsigned_vector const& cols1, unsigned_vector const& cols2) {
skip_table const& s1 = get(t1);
skip_table const& s2 = get(t2);
imdd_manager& m = s1.get_imdd_manager();
imdd_ref pr(m);
m.mk_join(s1.get_imdd(), s2.get_imdd(), pr, cols1, cols2);
return alloc(skip_table, s1.get_plugin(), result_sig, pr);
}
skip_table* skip_table_plugin::mk_join_project(
table_base const& t1, table_base const& t2, table_signature const& result_sig,
unsigned_vector const& cols1, unsigned_vector const& cols2,
unsigned_vector const& proj_cols) {
skip_table const& s1 = get(t1);
skip_table const& s2 = get(t2);
imdd_manager& m = s1.get_imdd_manager();
imdd_ref pr(m);
m.mk_join_project(s1.get_imdd(), s2.get_imdd(), pr, cols1, cols2, proj_cols);
return alloc(skip_table, s1.get_plugin(), result_sig, pr);
}
class skip_table_plugin::join_fn : public convenient_table_join_fn {
public:
join_fn(const table_base & t1, const table_base & t2,
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2):
convenient_table_join_fn(t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2) {
}
virtual table_base* operator()(const table_base & t1, const table_base & t2) {
return skip_table_plugin::mk_join(t1, t2, get_result_signature(), m_cols1, m_cols2);
}
};
table_join_fn * skip_table_plugin::mk_join_fn(const table_base & t1, const table_base & t2,
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) {
if (check_kind(t1) && check_kind(t2)) {
return alloc(join_fn, t1, t2, col_cnt, cols1, cols2);
}
TRACE("dl", tout << "could not handle operation\n";);
return 0;
}
class skip_table_plugin::join_project_fn : public convenient_table_join_project_fn {
public:
join_project_fn(const table_base & t1, const table_base & t2,
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2,
unsigned removed_col_cnt, const unsigned * removed_cols):
convenient_table_join_project_fn(t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2,
removed_col_cnt, removed_cols) {
}
virtual table_base* operator()(const table_base & t1, const table_base & t2) {
return skip_table_plugin::mk_join_project(t1, t2, get_result_signature(), m_cols1, m_cols2, m_removed_cols);
}
};
table_join_fn * skip_table_plugin::mk_join_project_fn(
const table_base & t1, const table_base & t2,
unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2,
unsigned removed_col_cnt, const unsigned * removed_cols) {
if (check_kind(t1) && check_kind(t2)) {
return alloc(join_project_fn, t1, t2, joined_col_cnt, cols1, cols2, removed_col_cnt, removed_cols);
}
TRACE("dl", tout << "could not handle operation\n";);
return 0;
}
class skip_table_plugin::union_fn : public table_union_fn {
public:
virtual void operator()(table_base& tgt, const table_base& src, table_base* delta) {
skip_table& s1 = get(tgt);
skip_table const& s2 = get(src);
imdd_manager& m = s1.get_imdd_manager();
imdd_ref r(m);
m.mk_union(s1.get_imdd(), s2.get_imdd(), r);
if (delta) {
skip_table& d = get(*delta);
if (m.is_subset(r, s1.get_imdd())) {
d.update(m.mk_empty(s1.get_signature().size()));
}
else {
d.update(r);
}
}
s1.update(r);
}
};
table_union_fn * skip_table_plugin::mk_union_fn(const table_base & tgt, const table_base & src, const table_base * delta) {
if (check_kind(tgt) && check_kind(src) && (!delta || check_kind(*delta))) {
return alloc(union_fn);
}
TRACE("dl", tout << "could not handle operation\n";);
return 0;
}
skip_table* skip_table_plugin::mk_project(table_base const& src, table_signature const& result_sig, unsigned_vector const& cols) {
skip_table const& s = get(src);
imdd_manager& m = s.get_imdd_manager();
imdd_ref pr(m);
m.mk_project(s.get_imdd(), pr, cols.size(), cols.c_ptr());
return alloc(skip_table, s.get_plugin(), result_sig, pr);
}
class skip_table_plugin::project_fn : public convenient_table_project_fn {
public:
project_fn(table_signature const& orig_sig, unsigned col_cnt, unsigned const* removed_cols):
convenient_table_project_fn(orig_sig, col_cnt, removed_cols) {}
table_base* operator()(table_base const& src) {
return mk_project(src, get_result_signature(), m_removed_cols);
}
};
table_transformer_fn * skip_table_plugin::mk_project_fn(const table_base & t, unsigned col_cnt, const unsigned * removed_cols) {
if (check_kind(t)) {
return alloc(project_fn, t.get_signature(), col_cnt, removed_cols);
}
TRACE("dl", tout << "could not handle operation\n";);
return 0;
}
class skip_table_plugin::rename_fn : public convenient_table_rename_fn {
void swap2(imdd_ref& n, unsigned col1, unsigned col2) {
imdd_manager& m = n.get_manager();
imdd_ref tmp(m);
if (col1 == col2) {
return;
}
if (col1 > col2) {
std::swap(col1, col2);
}
for (unsigned i = col1; i < col2; ++i) {
m.mk_swap(n, tmp, i);
n = tmp;
}
for (unsigned i = col2 - 1; i > col1; ) {
--i;
m.mk_swap(n, tmp, i);
n = tmp;
}
}
public:
rename_fn(table_signature const& sig, unsigned cycle_len, unsigned const* cycle):
convenient_rename_fn(sig, cycle_len, cycle) {}
table_base* operator()(table_base const& src) {
TRACE("skip",
for (unsigned i = 0; i < m_cycle.size(); ++i) {
tout << m_cycle[i] << " ";
}
tout << "\n";
src.display(tout););
skip_table const& s = get(src);
imdd_ref n(s.m_imdd, s.get_imdd_manager());
unsigned cycle_len = m_cycle.size();
unsigned col1, col2;
// TBD: review this for proper direction
for (unsigned i = 0; i + 1 < cycle_len; ++i) {
col1 = m_cycle[i];
col2 = m_cycle[i+1];
swap2(n, col1, col2);
}
if (cycle_len > 2) {
col1 = m_cycle[cycle_len-1];
col2 = m_cycle[0];
swap2(n, col1, col2);
}
skip_table* res = alloc(skip_table, s.get_plugin(), get_result_signature(), n);
TRACE("skip",res->display(tout););
return res;
}
};
table_transformer_fn * skip_table_plugin::mk_rename_fn(const table_base & t, unsigned len, const unsigned * cycle) {
if (check_kind(t)) {
return alloc(rename_fn, t.get_signature(), len, cycle);
}
TRACE("dl", tout << "could not handle operation\n";);
return 0;
}
class skip_table_plugin::filter_identical_fn : public table_mutator_fn {
unsigned_vector m_cols;
public:
filter_identical_fn(unsigned cnt, unsigned const* cols):
m_cols(cnt, cols)
{}
void operator()(table_base & t) {
skip_table& s = get(t);
imdd_manager& m = s.get_imdd_manager();
m.mk_filter_identical(s.get_imdd(), s.m_imdd, m_cols.size(), m_cols.c_ptr(), true);
}
};
table_mutator_fn * skip_table_plugin::mk_filter_identical_fn(const table_base & t, unsigned col_cnt,
const unsigned * identical_cols) {
if (check_kind(t)) {
return alloc(filter_identical_fn, col_cnt, identical_cols);
}
TRACE("dl", tout << "could not handle operation\n";);
return 0;
}
class skip_table_plugin::filter_equal_fn : public table_mutator_fn {
unsigned m_col;
unsigned m_value;
public:
filter_equal_fn(const table_base & t, const table_element & v, unsigned col):
m_col(col),
m_value(static_cast<unsigned>(v))
{
SASSERT(v <= UINT_MAX);
}
virtual void operator()(table_base& src) {
skip_table& s = get(src);
imdd_manager& m = s.get_imdd_manager();
m.mk_filter_equal(s.get_imdd(), s.m_imdd, m_col, m_value);
}
};
table_mutator_fn * skip_table_plugin::mk_filter_equal_fn(const table_base & t, const table_element & value,
unsigned col) {
if (check_kind(t)) {
return alloc(filter_equal_fn, t, value, col);
}
TRACE("dl", tout << "could not handle operation\n";);
return 0;
}
class skip_table_plugin::filter_not_equal_fn : public table_mutator_fn {
unsigned m_col;
unsigned m_value;
public:
filter_not_equal_fn(const table_base & t, const table_element & v, unsigned col):
m_col(col),
m_value(static_cast<unsigned>(v))
{
SASSERT(v <= UINT_MAX);
}
virtual void operator()(table_base& src) {
skip_table& s = get(src);
imdd_manager& m = s.get_imdd_manager();
m.mk_filter_disequal(s.get_imdd(), s.m_imdd, m_col, m_value);
}
};
table_mutator_fn * skip_table_plugin::mk_filter_not_equal_fn(const table_base & t, const table_element & value,
unsigned col) {
if (check_kind(t)) {
return alloc(filter_not_equal_fn, t, value, col);
}
TRACE("dl", tout << "could not handle operation\n";);
return 0;
}
class skip_table_plugin::filter_distinct_fn : public table_mutator_fn {
unsigned m_col1;
unsigned m_col2;
public:
filter_distinct_fn(const table_base & t, unsigned col1, unsigned col2):
m_col1(col1),
m_col2(col2) {
}
virtual void operator()(table_base& src) {
skip_table& s = get(src);
imdd_manager& m = s.get_imdd_manager();
m.mk_filter_distinct(s.get_imdd(), s.m_imdd, m_col1, m_col2);
}
};
table_mutator_fn * skip_table_plugin::mk_filter_distinct_fn(const table_base & t, unsigned col1, unsigned col2) {
if (check_kind(t)) {
return alloc(filter_distinct_fn, t, col1, col2);
}
TRACE("dl", tout << "could not handle operation\n";);
return 0;
}
//
// The default implementation uses an iterator
// if the condition is a comparison <, <=, then interval table native will be an advantage.
//
table_mutator_fn * skip_table_plugin::mk_filter_interpreted_fn(const table_base & t, app * condition) {
ast_manager& m = get_ast_manager();
dl_decl_util& util = get_context().get_decl_util();
uint64 value;
if (m.is_eq(condition)) {
expr* x = condition->get_arg(0);
expr* y = condition->get_arg(1);
if (is_var(y)) {
std::swap(x,y);
}
if (is_var(x) && is_var(y)) {
unsigned cols[2] = { to_var(x)->get_idx(), to_var(y)->get_idx() };
return mk_filter_identical_fn(t, 2, cols);
}
if (is_var(x) && util.is_numeral_ext(y, value)) {
return mk_filter_equal_fn(t, value, to_var(x)->get_idx());
}
}
if (m.is_not(condition) && is_app(condition->get_arg(0))) {
condition = to_app(condition->get_arg(0));
if (m.is_eq(condition)) {
expr* x = condition->get_arg(0);
expr* y = condition->get_arg(1);
if (is_var(y)) {
std::swap(x,y);
}
if (is_var(x) && is_var(y)) {
return mk_filter_distinct_fn(t, to_var(x)->get_idx(), to_var(y)->get_idx());
}
if (is_var(x) && util.is_numeral_ext(y, value)) {
return mk_filter_not_equal_fn(t, value, to_var(x)->get_idx());
}
}
}
TRACE("dl", tout << "could not handle operation\n";);
return 0;
}
class skip_table_plugin::filter_by_negation_fn : public convenient_table_negation_filter_fn {
public:
filter_by_negation_fn(
const table_base & tgt, const table_base & neg,
unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * negated_cols)
: convenient_table_negation_filter_fn(tgt, neg, joined_col_cnt, t_cols, negated_cols) {
}
//
// Compute
// { (x,y) | t(x,y) & ! exists z . negated_obj(x,z) }
//
// 1. Project z
// 2. Join with result.
//
virtual void operator()(table_base & tgt0, const table_base & neg0) {
skip_table & tgt = get(tgt0);
const skip_table & neg = get(neg0);
unsigned_vector cols2(m_cols2);
unsigned_vector proj_cols;
table_base* t1 = 0;
if (!m_all_neg_bound) {
unsigned_vector proj_cols, remap;
table_signature sig2;
table_signature const& neg_sig = neg.get_signature();
for (unsigned i = 0, j = 0; i < m_bound.size(); ++i) {
if (m_bound[i]) {
remap.push_back(j++);
sig2.push_back(neg_sig[i]);
}
else {
proj_cols.push_back(i);
remap.push_back(0);
}
}
for (unsigned i = 0; i < cols2.size(); ++i) {
cols2[i] = remap[cols2[i]];
}
skip_table* t0 = skip_table_plugin::mk_project(neg, sig2, proj_cols);
t1 = t0->complement();
t0->deallocate();
proj_cols.reset();
}
else {
t1 = neg.complement();
}
for (unsigned i = 0; i < t1->get_signature().size(); ++i) {
proj_cols.push_back(tgt0.get_signature().size()+i);
}
skip_table* t2 = skip_table_plugin::mk_join_project(tgt0, *t1, tgt0.get_signature(), m_cols1, cols2, proj_cols);
t1->deallocate();
tgt.update(*t2);
t2->deallocate();
}
};
table_intersection_filter_fn * skip_table_plugin::mk_filter_by_negation_fn(
const table_base & t,
const table_base & negated_obj, unsigned joined_col_cnt,
const unsigned * t_cols, const unsigned * negated_cols) {
if (check_kind(t) && check_kind(negated_obj)) {
return alloc(filter_by_negation_fn, t, negated_obj, joined_col_cnt, t_cols, negated_cols);
}
TRACE("dl", tout << "could not handle operation\n";);
return 0;
}
bool skip_table_plugin::can_handle_signature(table_signature const& sig) {
for (unsigned i = 0; i < sig.size(); ++i) {
if (sig[i] >= UINT_MAX) {
return false;
}
}
return true;
}
// ------------------
// skip_table
skip_table::skip_table(skip_table_plugin & p, const table_signature & sig):
table_base(p, sig),
m_imdd(p.get_imdd_manager().mk_empty(sig.size()), p.get_imdd_manager()) {
SASSERT(well_formed());
}
skip_table::skip_table(skip_table_plugin & p, const table_signature & sig, imdd* m):
table_base(p, sig),
m_imdd(m, p.get_imdd_manager()) {
SASSERT(well_formed());
}
skip_table::~skip_table() {
}
bool skip_table::well_formed() const {
table_signature const& sig = get_signature();
return
get_plugin().can_handle_signature(sig) &&
(get_imdd()->get_arity() == sig.size());
}
bool skip_table::empty() const {
return get_imdd()->empty();
}
void skip_table::update(imdd* n) {
m_imdd = n;
SASSERT(well_formed());
}
void skip_table::add_fact(const table_fact & f) {
imdd_manager& m = get_plugin().get_imdd_manager();
unsigned const* fact = get_fact(f.c_ptr());
m.add_fact(get_imdd(), m_imdd, f.size(), fact);
SASSERT(well_formed());
}
void skip_table::remove_fact(const table_element* f) {
imdd_manager& m = get_imdd_manager();
unsigned const* fact = get_fact(f);
m.remove_facts(get_imdd(), m_imdd, get_signature().size(), fact, fact);
}
bool skip_table::contains_fact(const table_fact & f) const {
imdd_manager& m = get_imdd_manager();
unsigned const* fact = get_fact(f.c_ptr());
return m.contains(get_imdd(), f.size(), fact);
}
table_base * skip_table::clone() const {
return alloc(skip_table, get_plugin(), get_signature(), get_imdd());
}
table_base * skip_table::complement() const {
imdd_manager& m = get_plugin().get_imdd_manager();
table_signature const& sig = get_signature();
unsigned_vector mins, maxs;
for (unsigned i = 0; i < sig.size(); ++i) {
SASSERT(sig[i] < UINT_MAX);
mins.push_back(0);
maxs.push_back(static_cast<unsigned>(sig[i]));
}
imdd_ref cmpl(m);
m.mk_complement(get_imdd(), cmpl, sig.size(), mins.c_ptr(), maxs.c_ptr());
return alloc(skip_table, get_plugin(), get_signature(), cmpl);
}
unsigned const* skip_table::get_fact(table_element const* f) const {
table_signature const& sig = get_signature();
const_cast<unsigned_vector&>(m_fact).reset();
for (unsigned i = 0; i < sig.size(); ++i) {
const_cast<unsigned_vector&>(m_fact).push_back(static_cast<unsigned>(f[i]));
SASSERT(f[i] < UINT_MAX);
}
return m_fact.c_ptr();
}
class skip_table::our_iterator_core : public table_base::iterator_core {
skip_table const& m_table;
imdd_manager::iterator m_iterator;
class our_row : public row_interface {
const our_iterator_core & m_parent;
public:
our_row(const our_iterator_core & parent) : row_interface(parent.m_table), m_parent(parent) {}
virtual void get_fact(table_fact & result) const {
result.reset();
unsigned arity = m_parent.m_iterator.get_arity();
unsigned const* values = *(m_parent.m_iterator);
for (unsigned i = 0; i < arity; ++i) {
result.push_back(values[i]);
}
}
virtual table_element operator[](unsigned col) const {
SASSERT(col < m_parent.m_iterator.get_arity());
unsigned const* values = *(m_parent.m_iterator);
return values[col];
}
};
our_row m_row_obj;
public:
struct b {};
struct e {};
our_iterator_core(skip_table const& t, b):
m_table(t),
m_iterator(t.m_imdd.get_manager(), t.get_imdd()),
m_row_obj(*this) {}
our_iterator_core(skip_table const& t, e):
m_table(t),
m_iterator(),
m_row_obj(*this) {}
virtual bool is_finished() const {
return m_iterator == imdd_manager::iterator();
}
virtual row_interface & operator*() {
SASSERT(!is_finished());
return m_row_obj;
}
virtual void operator++() {
SASSERT(!is_finished());
++m_iterator;
}
};
table_base::iterator skip_table::begin() const {
return mk_iterator(alloc(our_iterator_core, *this, our_iterator_core::b()));
}
table_base::iterator skip_table::end() const {
return mk_iterator(alloc(our_iterator_core, *this, our_iterator_core::e()));
}
unsigned skip_table::get_size_estimate_rows() const {
imdd_manager& m = get_plugin().get_imdd_manager();
size_t sz = m.get_num_rows(get_imdd());
unsigned sz0 = static_cast<unsigned>(sz);
SASSERT (sz == sz0 && "we need to use size_t or big-ints for row count");
return sz0;
}
unsigned skip_table::get_size_estimate_bytes() const {
imdd_manager& m = get_plugin().get_imdd_manager();
return m.memory(get_imdd());
}
};
#endif

View file

@ -1,161 +0,0 @@
/*++
Copyright (c) 2010 Microsoft Corporation
Module Name:
dl_skip_table.h
Abstract:
<abstract>
Author:
Nikolaj Bjorner (nbjorner)
Leonardo de Moura (leonardo) 2010-10-14
Revision History:
--*/
#ifndef _DL_SKIP_TABLE_H_
#define _DL_SKIP_TABLE_H_
#include "dl_base.h"
#include "imdd.h"
namespace datalog {
class skip_table;
class skip_table_plugin : public table_plugin {
friend class skip_table;
imdd_manager m_manager;
protected:
class join_fn;
class join_project_fn;
class union_fn;
class transformer_fn;
class rename_fn;
class project_fn;
class filter_equal_fn;
class filter_not_equal_fn;
class filter_identical_fn;
class filter_distinct_fn;
class filter_by_negation_fn;
imdd_manager& get_imdd_manager() const { return const_cast<imdd_manager&>(m_manager); }
public:
typedef skip_table table;
skip_table_plugin(relation_manager & manager)
: table_plugin(symbol("skip"), manager) {}
virtual table_base * mk_empty(const table_signature & s);
virtual table_join_fn * mk_join_fn(const table_base & t1, const table_base & t2,
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2);
virtual table_join_fn * mk_join_project_fn(
const table_base & t1, const table_base & t2,
unsigned joined_col_cnt, const unsigned * cols1, const unsigned * cols2,
unsigned removed_col_cnt, const unsigned * removed_cols);
virtual table_union_fn * mk_union_fn(const table_base & tgt, const table_base & src,
const table_base * delta);
virtual table_transformer_fn * mk_project_fn(const table_base & t, unsigned col_cnt,
const unsigned * removed_cols);
virtual table_transformer_fn * mk_rename_fn(const table_base & t, unsigned permutation_cycle_len,
const unsigned * permutation_cycle);
virtual table_mutator_fn * mk_filter_identical_fn(const table_base & t, unsigned col_cnt,
const unsigned * identical_cols);
virtual table_mutator_fn * mk_filter_equal_fn(const table_base & t, const table_element & value,
unsigned col);
virtual table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition);
virtual table_intersection_filter_fn * mk_filter_by_negation_fn(
const table_base & t,
const table_base & negated_obj, unsigned joined_col_cnt,
const unsigned * t_cols, const unsigned * negated_cols);
virtual bool can_handle_signature(table_signature const& s);
private:
static skip_table& get(table_base& r);
static skip_table const & get(table_base const& r);
static skip_table* mk_join(table_base const& t1, table_base const& t2, table_signature const& s,
unsigned_vector const& cols_t1, unsigned_vector const& cols_t2);
static skip_table* mk_join_project(table_base const& t1, table_base const& t2, table_signature const& s,
unsigned_vector const& cols_t1, unsigned_vector const& cols_t2, unsigned_vector const& proj_cols);
static skip_table* mk_project(table_base const& src, table_signature const& result_sig,
unsigned_vector const& cols);
virtual table_mutator_fn * mk_filter_distinct_fn(const table_base & t, unsigned col1, unsigned col2);
virtual table_mutator_fn * mk_filter_not_equal_fn(const table_base & t, const table_element & value,
unsigned col);
};
class skip_table : public table_base {
friend class skip_table_plugin;
friend class skip_table_plugin::join_fn;
friend class skip_table_plugin::union_fn;
friend class skip_table_plugin::transformer_fn;
friend class skip_table_plugin::rename_fn;
friend class skip_table_plugin::project_fn;
friend class skip_table_plugin::filter_equal_fn;
friend class skip_table_plugin::filter_not_equal_fn;
friend class skip_table_plugin::filter_identical_fn;
friend class skip_table_plugin::filter_distinct_fn;
class our_iterator_core;
imdd_ref m_imdd;
unsigned_vector m_fact;
imdd* get_imdd() const { return m_imdd.get(); }
imdd_manager& get_imdd_manager() const { return get_plugin().get_imdd_manager(); }
unsigned const* get_fact(table_element const* f) const;
bool well_formed() const;
void update(imdd* n);
void update(skip_table& t) { update(t.m_imdd); }
skip_table(skip_table_plugin & p, const table_signature & sig);
skip_table(skip_table_plugin & p, const table_signature & sig, imdd*);
skip_table(const skip_table & t);
virtual ~skip_table();
public:
skip_table_plugin & get_plugin() const {
return static_cast<skip_table_plugin &>(table_base::get_plugin());
}
virtual bool empty() const;
virtual void add_fact(const table_fact & f);
virtual void remove_fact(const table_element * fact);
virtual bool contains_fact(const table_fact & f) const;
virtual table_base * complement() const;
virtual table_base * clone() const;
virtual iterator begin() const;
virtual iterator end() const;
virtual unsigned get_size_estimate_rows() const;
virtual unsigned get_size_estimate_bytes() const;
};
};
#endif /* _DL_SKIP_TABLE_H_ */

View file

@ -500,6 +500,9 @@ namespace datalog {
char * reserve = m_data.get_reserve_ptr(); char * reserve = m_data.get_reserve_ptr();
unsigned col_cnt = m_column_layout.size(); unsigned col_cnt = m_column_layout.size();
for(unsigned i=0; i<col_cnt; i++) { for(unsigned i=0; i<col_cnt; i++) {
if (f[i] >= get_signature()[i]) {
std::cout << f[i] << " " << get_signature()[i] << "\n";
}
SASSERT(f[i]<get_signature()[i]); //the value fits into the table signature SASSERT(f[i]<get_signature()[i]); //the value fits into the table signature
m_column_layout.set(reserve, i, f[i]); m_column_layout.set(reserve, i, f[i]);
} }

File diff suppressed because it is too large Load diff

View file

@ -1,849 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
imdd.h
Abstract:
Interval based Multiple-valued Decision Diagrams.
Author:
Leonardo de Moura (leonardo) 2010-10-13.
Revision History:
--*/
#ifndef _IMDD_H_
#define _IMDD_H_
#include"id_gen.h"
#include"hashtable.h"
#include"map.h"
#include"obj_hashtable.h"
#include"obj_pair_hashtable.h"
#include"buffer.h"
#include"interval_skip_list.h"
#include"region.h"
#include"obj_ref.h"
class imdd;
class imdd_manager;
/**
\brief Manager for skip-lists used to implement IMDD nodes.
*/
class sl_imdd_manager : public random_level_manager {
imdd_manager * m_manager; // real manager
small_object_allocator & m_alloc;
friend class imdd_manager;
public:
sl_imdd_manager(small_object_allocator & alloc):m_alloc(alloc) {}
void * allocate(size_t size) { return m_alloc.allocate(size); }
void deallocate(size_t size, void* p) { m_alloc.deallocate(size, p); }
void inc_ref_eh(imdd * v);
void dec_ref_eh(imdd * v);
};
#define IMDD_BUCKET_CAPACITY 128
#define IMDD_MAX_LEVEL 32
typedef interval_skip_list<unsigned_interval_skip_list_traits<imdd*,
default_eq<imdd*>,
IMDD_BUCKET_CAPACITY,
IMDD_MAX_LEVEL,
true, /* support ref-counting */
sl_imdd_manager> > imdd_children;
typedef interval_skip_list<unsigned_interval_skip_list_traits<unsigned,
default_eq<unsigned>,
IMDD_BUCKET_CAPACITY,
IMDD_MAX_LEVEL,
false,
sl_manager_base<unsigned> > > sl_interval_set;
/*
Notes:
- We use reference counting for garbage collecting IMDDs nodes.
- Each IMDD node has a "memoized" flag. If the flag is true, the we use hash-consing for this node.
- The children of a memoized node must be memoized.
- The children of a non-memoized node may be memoized.
- The "memoized" flag cannot be reset after it was set.
- The result of some operations may be cached. We only use caching for
operations processing memoized nodes.
- For non-memoized nodes, if m_ref_count <= 1, destructive updates may be performed by some operations.
- IMPORTANT: "memoized" flag == false doesn't imply m_ref_count <= 1.
*/
/**
\brief IMDDs
*/
class imdd {
protected:
friend class imdd_manager;
unsigned m_id; //!< Unique ID
unsigned m_ref_count;
unsigned m_arity:30;
unsigned m_memoized:1;
unsigned m_dead:1;
imdd_children m_children;
void inc_ref() {
m_ref_count ++;
}
void dec_ref() {
SASSERT(m_ref_count > 0);
m_ref_count --;
}
void mark_as_memoized(bool flag = true) {
SASSERT(is_memoized() != flag);
m_memoized = flag;
}
void mark_as_dead() { SASSERT(!m_dead); m_dead = true; }
void replace_children(sl_imdd_manager & m, sbuffer<imdd_children::entry> & new_children);
public:
imdd(sl_imdd_manager & m, unsigned id, unsigned arity):m_id(id), m_ref_count(0), m_arity(arity), m_memoized(false), m_dead(false), m_children(m) {}
unsigned get_id() const { return m_id; }
unsigned get_ref_count() const { return m_ref_count; }
bool is_memoized() const { return m_memoized; }
bool is_shared() const { return m_ref_count > 1; }
bool is_dead() const { return m_dead; }
unsigned get_arity() const { return m_arity; }
imdd_children::iterator begin_children() const { return m_children.begin(); }
imdd_children::iterator end_children() const { return m_children.end(); }
unsigned hc_hash() const; // hash code for hash-consing.
bool hc_equal(imdd const * other) const; // eq function for hash-consing
bool empty() const { return m_children.empty(); }
unsigned hash() const { return m_id; }
unsigned memory() const { return sizeof(imdd) + m_children.memory() - sizeof(imdd_children); }
};
// -----------------------------------
//
// IMDD hash-consing
//
// -----------------------------------
// this is the internal hashing functor for hash-consing IMDDs.
struct imdd_hash_proc {
unsigned operator()(imdd const * d) const { return d->hc_hash(); }
};
// This is the internal comparison functor for hash-consing IMDDs.
struct imdd_eq_proc {
bool operator()(imdd const * d1, imdd const * d2) const { return d1->hc_equal(d2); }
};
typedef ptr_hashtable<imdd, imdd_hash_proc, imdd_eq_proc> imdd_table;
typedef obj_hashtable<imdd> imdd_cache;
typedef obj_map<imdd, imdd*> imdd2imdd_cache;
typedef obj_pair_map<imdd, imdd, imdd*> imdd_pair2imdd_cache;
typedef obj_pair_map<imdd, imdd, bool> imdd_pair2bool_cache;
typedef obj_map<imdd, sl_interval_set*> imdd2intervals;
typedef std::pair<imdd*, unsigned> imdd_value_pair;
struct fi_cache_entry {
imdd * m_d;
unsigned m_lower;
unsigned m_upper;
unsigned m_hash;
unsigned m_num_result;
imdd_value_pair m_result[0];
void mk_hash() {
m_hash = hash_u_u(m_d->get_id(), hash_u_u(m_lower, m_upper));
}
fi_cache_entry(imdd * d, unsigned l, unsigned u):
m_d(d),
m_lower(l),
m_upper(u) {
mk_hash();
}
fi_cache_entry(imdd * d, unsigned l, unsigned u, unsigned num, imdd_value_pair result[]):
m_d(d),
m_lower(l),
m_upper(u),
m_num_result(num) {
mk_hash();
memcpy(m_result, result, sizeof(imdd_value_pair)*num);
}
unsigned hash() const {
return m_hash;
}
bool operator==(fi_cache_entry const & other) const {
return
m_d == other.m_d &&
m_lower == other.m_lower &&
m_upper == other.m_upper;
}
};
typedef obj_hashtable<fi_cache_entry> imdd_fi_cache;
typedef union {
imdd * m_d;
fi_cache_entry * m_entry;
} mk_fi_result;
struct filter_cache_entry {
imdd * m_d;
imdd * m_r;
unsigned m_hash;
unsigned m_ctx_size;
unsigned m_ctx[0]; // lower and upper bounds that are part of the context.
static unsigned get_obj_size(unsigned ctx_size) {
return sizeof(filter_cache_entry) + ctx_size * sizeof(unsigned);
}
void mk_hash() {
if (m_ctx_size > 0)
m_hash = string_hash(reinterpret_cast<char *>(m_ctx), m_ctx_size * sizeof(unsigned), m_d->get_id());
else
m_hash = m_d->get_id();
}
filter_cache_entry(imdd * d, imdd * r, unsigned ctx_size, unsigned * ctx):
m_d(d),
m_r(r),
m_ctx_size(ctx_size) {
memcpy(m_ctx, ctx, sizeof(unsigned)*m_ctx_size);
mk_hash();
}
unsigned hash() const {
return m_hash;
}
bool operator==(filter_cache_entry const & other) const {
if (m_d != other.m_d)
return false;
if (m_ctx_size != other.m_ctx_size)
return false;
for (unsigned i = 0; i < m_ctx_size; i++)
if (m_ctx[i] != other.m_ctx[i])
return false;
return true;
}
};
typedef obj_hashtable<filter_cache_entry> imdd_mk_filter_cache;
typedef obj_ref<imdd, imdd_manager> imdd_ref;
class imdd_manager {
typedef imdd_children::entry entry;
small_object_allocator m_alloc;
id_gen m_id_gen;
vector<imdd_table> m_tables; // we keep a table for each height.
sl_imdd_manager m_sl_manager;
unsigned m_simple_max_entries; //!< maximum number of entries in a "simple" node.
bool m_delay_dealloc;
ptr_vector<imdd> m_to_delete; //!< list of IMDDs marked as dead. These IMDDs may still be in cache tables.
// generic cache and todo-lists
ptr_vector<imdd> m_worklist;
imdd_cache m_visited;
void mark_as_dead(imdd * d);
void deallocate_imdd(imdd * d);
void delete_imdd(imdd * d);
class delay_dealloc;
friend class delay_dealloc;
class delay_dealloc {
imdd_manager & m_manager;
bool m_delay_dealloc_value;
unsigned m_to_delete_size;
public:
delay_dealloc(imdd_manager & m):
m_manager(m),
m_delay_dealloc_value(m_manager.m_delay_dealloc),
m_to_delete_size(m_manager.m_to_delete.size()) {
m_manager.m_delay_dealloc = true;
}
~delay_dealloc();
};
bool is_simple_node(imdd * d) const;
void add_child(imdd * d, unsigned lower, unsigned upper, imdd * child) {
d->m_children.insert(m_sl_manager, lower, upper, child);
}
void add_child(imdd * d, unsigned value, imdd * child) {
add_child(d, value, value, child);
}
void remove_child(imdd * d, unsigned lower, unsigned upper) {
d->m_children.remove(m_sl_manager, lower, upper);
}
imdd * copy_main(imdd * d);
imdd * insert_main(imdd * d, unsigned b, unsigned e, bool destructive, bool memoize_res);
imdd * remove_main(imdd * d, unsigned b, unsigned e, bool destructive, bool memoize_res);
imdd2imdd_cache m_mk_product_cache;
struct null2imdd_proc;
struct mk_product_proc;
friend struct mk_product_proc;
imdd * mk_product_core(imdd * d1, imdd * d2, bool destructive, bool memoize);
imdd * mk_product_main(imdd * d1, imdd * d2, bool destructive, bool memoize_res);
imdd2imdd_cache m_add_facts_cache;
ptr_vector<imdd> m_add_facts_new_children;
void init_add_facts_new_children(unsigned num, unsigned const * lowers, unsigned const * uppers, bool memoize_res);
imdd * add_facts_core(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res);
imdd * add_facts_main(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res);
imdd2imdd_cache m_remove_facts_cache;
imdd * remove_facts_core(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res);
imdd * remove_facts_main(imdd * d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool destructive, bool memoize_res);
imdd2imdd_cache m_defrag_cache;
imdd * defrag_core(imdd * d);
imdd_pair2imdd_cache m_union_cache;
void push_back_entries(unsigned head, imdd_children::iterator & it, imdd_children::iterator & end,
imdd_children::push_back_proc & push_back, bool & children_memoized);
void push_back_upto(unsigned & head, imdd_children::iterator & it, imdd_children::iterator & end, unsigned limit,
imdd_children::push_back_proc & push_back, bool & children_memoized);
void move_head(unsigned & head, imdd_children::iterator & it, imdd_children::iterator & end, unsigned new_head);
void copy_upto(unsigned & head, imdd_children::iterator & it, imdd_children::iterator & end, unsigned limit, sbuffer<entry> & result);
void reset_union_cache();
imdd * mk_union_core(imdd * d1, imdd * d2, bool destructive, bool memoize_res);
imdd * mk_union_main(imdd * d1, imdd * d2, bool destructive, bool memoize_res);
void mk_union_core_dupdt(imdd_ref & d1, imdd * d2, bool memoize_res);
void mk_union_core(imdd * d1, imdd * d2, imdd_ref & r, bool memoize_res);
imdd_pair2bool_cache m_is_equal_cache;
bool is_equal_core(imdd * d1, imdd * d2);
imdd_pair2bool_cache m_subsumes_cache;
bool subsumes_core(imdd * d1, imdd * d2);
imdd2imdd_cache m_complement_cache;
imdd * mk_complement_core(imdd * d, unsigned num, unsigned const * mins, unsigned const * maxs, bool destructive, bool memoize_res);
imdd * mk_complement_main(imdd * d, unsigned num, unsigned const * mins, unsigned const * maxs, bool destructive, bool memoize_res);
imdd2imdd_cache m_filter_equal_cache;
imdd * mk_filter_equal_core(imdd * d, unsigned vidx, unsigned value, bool destructive, bool memoize_res);
imdd * mk_filter_equal_main(imdd * d, unsigned vidx, unsigned value, bool destructive, bool memoize_res);
// original
imdd2intervals m_imdd2interval_set;
ptr_vector<sl_interval_set> m_alloc_is;
typedef sl_manager_base<unsigned> sl_imanager;
void reset_fi_intervals(sl_imanager& m);
sl_interval_set const* init_fi_intervals(sl_imanager& m, imdd* d, unsigned var, unsigned num_found);
imdd2imdd_cache m_fi_top_cache;
imdd_fi_cache m_fi_bottom_cache;
unsigned m_fi_num_vars;
unsigned * m_fi_begin_vars;
unsigned * m_fi_end_vars;
region m_fi_entries;
bool is_fi_var(unsigned v) const { return std::find(m_fi_begin_vars, m_fi_end_vars, v) != m_fi_end_vars; }
fi_cache_entry * mk_fi_cache_entry(imdd * d, unsigned lower, unsigned upper, unsigned num_pairs, imdd_value_pair pairs[]);
mk_fi_result mk_filter_identical_core(imdd * d, unsigned offset, unsigned num_found, unsigned lower, unsigned upper,
bool destructive, bool memoize_res);
imdd * mk_filter_identical_main(imdd * d, unsigned num_vars, unsigned * vars, bool destructive, bool memoize_res);
// v2
obj_map<imdd, imdd*> m_filter_identical_cache;
void filter_identical_core2(imdd* d, unsigned num_vars, unsigned b, unsigned e, ptr_vector<imdd>& ch);
imdd* filter_identical_core2(imdd* d, unsigned var, unsigned num_vars, bool memoize_res);
void filter_identical_main2(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars, bool destructive, bool memoize_res);
void swap_in(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars);
void swap_out(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars);
// v3
struct interval {
unsigned m_lo;
unsigned m_hi;
interval(unsigned lo, unsigned hi): m_lo(lo), m_hi(hi) {}
};
struct interval_dd : public interval {
imdd* m_dd;
interval_dd(unsigned lo, unsigned hi, imdd* d): interval(lo, hi), m_dd(d) {}
};
template<typename I>
class id_map {
unsigned m_T;
unsigned_vector m_Ts;
svector<svector<I>*> m_vecs;
unsigned_vector m_alloc;
unsigned m_first_free;
void hard_reset() {
std::for_each(m_vecs.begin(), m_vecs.end(), delete_proc<svector<I> >());
m_alloc.reset();
m_first_free = 0;
m_vecs.reset();
m_Ts.reset();
m_T = 0;
}
void allocate_entry(unsigned id) {
if (m_vecs[id]) {
return;
}
while (m_first_free < m_alloc.size()) {
if (m_vecs[m_first_free] && m_Ts[m_first_free] < m_T) {
svector<I>* v = m_vecs[m_first_free];
m_vecs[m_first_free] = 0;
m_vecs[id] = v;
++m_first_free;
return;
}
++m_first_free;
}
m_vecs[id] = alloc(svector<I>);
m_alloc.push_back(id);
}
public:
id_map():m_T(0) {}
~id_map() { hard_reset(); }
void reset() { ++m_T; m_first_free = 0; if (m_T == UINT_MAX) hard_reset(); }
svector<I>& init(imdd* d) {
unsigned id = d->get_id();
if (id >= m_vecs.size()) {
m_vecs.resize(id+1);
m_Ts.resize(id+1);
}
if (m_Ts[id] < m_T) {
allocate_entry(id);
m_vecs[id]->reset();
m_Ts[id] = m_T;
}
return *m_vecs[id];
}
typedef svector<I> data;
struct iterator {
unsigned m_offset;
id_map const& m;
iterator(unsigned o, id_map const& m):m_offset(o),m(m) {}
data const & operator*() const { return *m.m_vecs[m_offset]; }
data const * operator->() const { return &(operator*()); }
data * operator->() { return &(operator*()); }
iterator & operator++() { ++m_offset; return move_to_used(); }
iterator operator++(int) { iterator tmp = *this; ++*this; return tmp; }
bool operator==(iterator const & it) const { return m_offset == it.m_offset; }
bool operator!=(iterator const & it) const { return m_offset != it.m_offset; }
iterator & move_to_used() {
while (m_offset < m.m_vecs.size() &&
m.m_Ts[m_offset] < m.m_T) {
++m_offset;
}
return *this;
}
};
iterator begin() const { return iterator(0, *this).move_to_used(); }
iterator end() const { return iterator(m_vecs.size(), *this); }
};
typedef id_map<interval > filter_id_map;
typedef id_map<interval_dd > filter_idd_map;
filter_id_map m_nodes;
filter_idd_map m_nodes_dd;
svector<interval_dd> m_i_nodes_dd, m_i_nodes_dd_tmp;
svector<interval> m_i_nodes, m_i_nodes_tmp;
unsigned_vector m_offsets;
void filter_identical_main3(imdd * d, imdd_ref& r, unsigned num_vars, unsigned * vars, bool destructive, bool memoize_res);
void filter_identical_main3(imdd * d, imdd_ref& r, unsigned v1, bool del1, unsigned v2, bool del2, bool memoize_res);
imdd* filter_identical_loop3(imdd * d, unsigned v1, bool del1, unsigned v2, bool del2, bool memoize_res);
void refine_intervals(svector<interval>& i_nodes, svector<interval_dd> const& i_nodes_dd);
void merge_intervals(svector<interval>& dst, svector<interval> const& src);
imdd* filter_identical_mk_nodes(imdd* d, unsigned v, bool del1, bool del2, bool memoize_res);
void print_filter_idd(std::ostream& out, filter_idd_map const& m);
void print_interval_dd(std::ostream& out, svector<interval_dd> const& m);
unsigned m_proj_num_vars;
unsigned * m_proj_begin_vars;
unsigned * m_proj_end_vars;
imdd2imdd_cache m_proj_cache;
bool is_proj_var(unsigned v) const { return std::find(m_proj_begin_vars, m_proj_end_vars, v) != m_proj_end_vars; }
void mk_project_init(unsigned num_vars, unsigned * vars);
void mk_project_core(imdd * d, imdd_ref & r, unsigned var, unsigned num_found, bool memoize_res);
void mk_project_dupdt_core(imdd_ref & d, unsigned var, unsigned num_found, bool memoize_res);
imdd2imdd_cache m_swap_cache;
imdd * m_swap_new_child;
bool m_swap_granchildren_memoized;
imdd * mk_swap_new_child(unsigned lower, unsigned upper, imdd * child);
void mk_swap_acc1_dupdt(imdd_ref & d, unsigned lower, unsigned upper, imdd * grandchild, bool memoize_res);
void mk_swap_acc1(imdd * d, imdd_ref & r, unsigned lower, unsigned upper, imdd * grandchild, bool memoize_res);
void mk_swap_acc2(imdd_ref & r, unsigned lower1, unsigned upper1, unsigned lower2, unsigned upper2, imdd * grandchild, bool memoize_res);
void mk_swap_top_vars(imdd * d, imdd_ref & r, bool memoize_res);
imdd * mk_swap_memoize(imdd * d);
void mk_swap_core(imdd * d, imdd_ref & r, unsigned vidx, bool memoize_res);
void mk_swap_dupdt_core(imdd_ref & d, unsigned vidx, bool memoize_res);
imdd2imdd_cache m_add_bounded_var_cache;
imdd * add_bounded_var_core(imdd * d, unsigned before_vidx, unsigned lower, unsigned upper, bool destructive, bool memoize_res);
imdd * add_bounded_var_main(imdd * d, unsigned before_vidx, unsigned lower, unsigned upper, bool destructive, bool memoize_res);
friend struct distinct_proc;
imdd * mk_distinct_imdd(unsigned l1, unsigned u1, unsigned l2, unsigned u2, imdd * d, bool memoize_res = true);
imdd_mk_filter_cache m_filter_cache;
region m_filter_entries;
unsigned m_filter_num_vars;
unsigned * m_filter_begin_vars;
unsigned * m_filter_end_vars;
unsigned_vector m_filter_context;
bool is_filter_var(unsigned v) const { return std::find(m_filter_begin_vars, m_filter_end_vars, v) != m_filter_end_vars; }
filter_cache_entry * mk_filter_cache_entry(imdd * d, unsigned ctx_sz, unsigned * ctx, imdd * r);
imdd * is_mk_filter_cached(imdd * d, unsigned ctx_sz, unsigned * ctx);
void cache_mk_filter(imdd * d, unsigned ctx_sz, unsigned * ctx, imdd * r);
void init_mk_filter(unsigned arity, unsigned num_vars, unsigned * vars);
template<typename FilterProc>
void mk_filter_dupdt_core(imdd_ref & d, unsigned vidx, unsigned num_found, FilterProc & proc, bool memoize_res);
template<typename FilterProc>
void mk_filter_core(imdd * d, imdd_ref & r, unsigned vidx, unsigned num_found, FilterProc & proc, bool memoize_res);
/**
\brief Filter the elements of the given IMDD using the given filter.
The FilterProc template parameter is a filter for computing subsets of sets of the form:
[L_1, U_1] X [L_2, U_2] X ... X [L_n, U_n] X d (where d is an IMDD)
where n == num_vars
The subset of elements is returned as an IMDD.
FilterProc must have a method of the form:
void operator()(unsigned * lowers_uppers, imdd * d, imdd_ref & r, bool memoize_res);
The size of the array lowers_uppers is 2*num_vars
The arity of the resultant IMDD must be num_vars + d->get_arity().
*/
template<typename FilterProc>
void mk_filter_dupdt(imdd_ref & d, unsigned num_vars, unsigned * vars, FilterProc & proc, bool memoize_res = true);
template<typename FilterProc>
void mk_filter(imdd * d, imdd_ref & r, unsigned num_vars, unsigned * vars, FilterProc & proc, bool memoize_res = true);
imdd * mk_disequal_imdd(unsigned l1, unsigned u1, unsigned value, imdd * d, bool memoize_res);
friend struct disequal_proc;
public:
imdd_manager();
void inc_ref(imdd * d) {
if (d)
d->inc_ref();
}
void dec_ref(imdd * d) {
if (d) {
d->dec_ref();
if (d->get_ref_count() == 0)
delete_imdd(d);
}
}
unsigned get_num_nodes(imdd const * d) const;
// count number of keys (rows) in table as if table is uncompressed.
size_t get_num_rows(imdd const* d) const;
unsigned memory(imdd const * d) const;
private:
imdd * _mk_empty(unsigned arity);
public:
imdd * mk_empty(unsigned arity) {
imdd * r = _mk_empty(arity);
STRACE("imdd_trace", tout << "mk_empty(" << arity << ", 0x" << r << ");\n";);
return r;
}
private:
imdd * memoize(imdd * d);
public:
void memoize(imdd_ref const & d, imdd_ref & r) { r = memoize(d.get()); }
void memoize(imdd_ref & d) { d = memoize(d.get()); }
imdd * memoize_new_imdd_if(bool cond, imdd * r) {
if (cond && is_simple_node(r)) {
SASSERT(!r->is_shared());
imdd * can_r = memoize(r);
if (can_r != r) {
SASSERT(r->get_ref_count() == 0);
delete_imdd(r);
}
return can_r;
}
return r;
}
public:
void defrag(imdd_ref & d);
void unmemoize(imdd * d);
void unmemoize_rec(imdd * d);
void copy(imdd * d, imdd_ref & r) { r = copy_main(d); }
void insert_dupdt(imdd_ref & d, unsigned b, unsigned e, bool memoize_res = true) {
d = insert_main(d, b, e, true, memoize_res);
}
void insert(imdd * d, imdd_ref & r, unsigned b, unsigned e, bool memoize_res = true) {
r = insert_main(d, b, e, false, memoize_res);
}
void mk_product_dupdt(imdd_ref & d1, imdd * d2, bool memoize_res = true) {
d1 = mk_product_main(d1.get(), d2, true, memoize_res);
}
void mk_product(imdd * d1, imdd * d2, imdd_ref & r, bool memoize_res = true) {
r = mk_product_main(d1, d2, false, memoize_res);
STRACE("imdd_trace", tout << "mk_product(0x" << d1 << ", 0x" << d2 << ", 0x" << r.get() << ", " << memoize_res << ");\n";);
}
void mk_union_dupdt(imdd_ref & d1, imdd * d2, bool memoize_res = true) {
d1 = mk_union_main(d1.get(), d2, true, memoize_res);
}
void mk_union(imdd * d1, imdd * d2, imdd_ref & r, bool memoize_res = true) {
r = mk_union_main(d1, d2, false, memoize_res);
STRACE("imdd_trace", tout << "mk_union(0x" << d1 << ", 0x" << d2 << ", 0x" << r.get() << ", " << memoize_res << ");\n";);
}
void mk_complement_dupdt(imdd_ref & d, unsigned num, unsigned const * mins, unsigned const * maxs, bool memoize_res = true) {
d = mk_complement_main(d, num, mins, maxs, true, memoize_res);
}
void mk_complement(imdd * d, imdd_ref & r, unsigned num, unsigned const * mins, unsigned const * maxs, bool memoize_res = true) {
r = mk_complement_main(d, num, mins, maxs, false, memoize_res);
STRACE("imdd_trace", tout << "mk_complement(0x" << d << ", 0x" << r.get() << ", ";
for (unsigned i = 0; i < num; i++) tout << mins[i] << ", " << maxs[i] << ", ";
tout << memoize_res << ");\n";);
}
void mk_filter_equal_dupdt(imdd_ref & d, unsigned vidx, unsigned value, bool memoize_res = true) {
d = mk_filter_equal_main(d, vidx, value, true, memoize_res);
}
void mk_filter_equal(imdd * d, imdd_ref & r, unsigned vidx, unsigned value, bool memoize_res = true) {
r = mk_filter_equal_main(d, vidx, value, false, memoize_res);
STRACE("imdd_trace", tout << "mk_filter_equal(0x" << d << ", 0x" << r.get() << ", " << vidx << ", " << value << ", " << memoize_res << ");\n";);
}
void mk_filter_identical_dupdt(imdd_ref & d, unsigned num_vars, unsigned * vars, bool memoize_res = true) {
// d = mk_filter_identical_main(d, num_vars, vars, true, memoize_res);
filter_identical_main3(d, d, num_vars, vars, true, memoize_res);
}
void mk_filter_identical(imdd * d, imdd_ref & r, unsigned num_vars, unsigned * vars, bool memoize_res = true) {
filter_identical_main3(d, r, num_vars, vars, false, memoize_res);
STRACE("imdd_trace", tout << "mk_filter_identical(0x" << d << ", 0x" << r.get() << ", ";
for (unsigned i = 0; i < num_vars; i++) tout << vars[i] << ", ";
tout << memoize_res << ");\n";);
}
void mk_project_dupdt(imdd_ref & d, unsigned num_vars, unsigned * vars, bool memoize_res = true);
void mk_project(imdd * d, imdd_ref & r, unsigned num_vars, unsigned * vars, bool memoize_res = true);
// swap vidx and vidx+1
void mk_swap_dupdt(imdd_ref & d, unsigned vidx, bool memoize_res = true);
// swap vidx and vidx+1
void mk_swap(imdd * d, imdd_ref & r, unsigned vidx, bool memoize_res = true);
void add_facts_dupdt(imdd_ref & d, unsigned num, unsigned const * lowers, unsigned const * uppers, bool memoize_res = true) {
d = add_facts_main(d, num, lowers, uppers, true, memoize_res);
}
void add_facts(imdd * d, imdd_ref & r, unsigned num, unsigned const * lowers, unsigned const * uppers, bool memoize_res = true) {
r = add_facts_main(d, num, lowers, uppers, false, memoize_res);
STRACE("imdd_trace", tout << "add_facts(0x" << d << ", 0x" << r.get() << ", ";
for (unsigned i = 0; i < num; i++) tout << lowers[i] << ", " << uppers[i] << ", ";
tout << memoize_res << ");\n";);
}
void add_fact_dupdt(imdd_ref & d, unsigned num, unsigned const * values, bool memoize_res = true) {
add_facts_dupdt(d, num, values, values, memoize_res);
}
void add_fact(imdd * d, imdd_ref & r, unsigned num, unsigned const * values, bool memoize_res = true) {
add_facts(d, r, num, values, values, memoize_res);
}
void add_bounded_var_dupdt(imdd_ref & d, unsigned before_vidx, unsigned lower, unsigned upper, bool memoize_res = true) {
d = add_bounded_var_main(d, before_vidx, lower, upper, true, memoize_res);
}
void add_bounded_var(imdd * d, imdd_ref & r, unsigned before_vidx, unsigned lower, unsigned upper, bool memoize_res = true) {
r = add_bounded_var_main(d, before_vidx, lower, upper, false, memoize_res);
}
void mk_filter_distinct_dupdt(imdd_ref & d, unsigned v1, unsigned v2, bool memoize_res = true);
void mk_filter_distinct(imdd * d, imdd_ref & r, unsigned v1, unsigned v2, bool memoize_res = true);
void mk_filter_disequal_dupdt(imdd_ref & d, unsigned var, unsigned value, bool memoize_res = true);
void mk_filter_disequal(imdd * d, imdd_ref & r, unsigned var, unsigned value, bool memoize_res = true);
void mk_join(imdd * d1, imdd * d2, imdd_ref & r, unsigned_vector const& vars1, unsigned_vector const& vars2, bool memoize_res = true);
void mk_join_project(imdd * d1, imdd * d2, imdd_ref & r,
unsigned_vector const& vars1, unsigned_vector const& vars2,
unsigned_vector const& proj_vars, bool memoize_res = true);
void mk_join_dupdt(imdd_ref & d1, imdd * d2, unsigned num_vars, unsigned const * vars1, unsigned const * vars2, bool memoize_res = true);
void remove_facts_dupdt(imdd_ref & d, unsigned num, unsigned const * lowers, unsigned const * uppers);
void remove_facts(imdd * d, imdd_ref & r, unsigned num, unsigned const * lowers, unsigned const * uppers);
bool is_equal(imdd * d1, imdd * d2);
bool contains(imdd * d, unsigned num, unsigned const * values) const;
bool contains(imdd * d, unsigned v) const { return contains(d, 1, &v); }
bool contains(imdd * d, unsigned v1, unsigned v2) const { unsigned vs[2] = {v1, v2}; return contains(d, 2, vs); }
bool contains(imdd * d, unsigned v1, unsigned v2, unsigned v3) const { unsigned vs[3] = {v1,v2,v3}; return contains(d, 3, vs); }
bool subsumes(imdd * d1, imdd * d2);
bool is_subset(imdd * d1, imdd * d2) { return subsumes(d2, d1); }
private:
void display(std::ostream & out, imdd const * d, unsigned_vector & intervals, bool & first) const;
public:
void display(std::ostream & out, imdd const * d) const;
void display_ll(std::ostream & out, imdd const * d) const;
/**
\brief Execute proc (once) in each node in the IMDD rooted by d.
*/
template<typename Proc>
void for_each(imdd * d, Proc & proc) const {
// for_each is a generic procedure, we don't know what proc will actually do.
// So, it is not safe to reuse m_worklist and m_visited.
ptr_buffer<imdd,128> worklist;
imdd_cache visited;
worklist.push_back(d);
while (!worklist.empty()) {
d = worklist.back();
worklist.pop_back();
if (d->is_shared() && visited.contains(d))
continue;
if (d->is_shared())
visited.insert(d);
proc(d);
if (d->get_arity() > 1) {
imdd_children::iterator it = d->begin_children();
imdd_children::iterator end = d->end_children();
for (; it != end; ++it)
worklist.push_back(it->val());
}
}
}
class iterator {
bool m_done;
svector<imdd_children::iterator> m_iterators;
svector<unsigned> m_element;
void begin_iterators(imdd const * curr, unsigned start_idx);
public:
iterator():m_done(true) {}
iterator(imdd_manager const & m, imdd const * d);
unsigned get_arity() const { return m_element.size(); }
unsigned * operator*() const { return m_element.c_ptr(); }
iterator & operator++();
bool operator==(iterator const & it) const;
bool operator!=(iterator const & it) const { return !operator==(it); }
};
friend class iterator;
iterator begin(imdd const * d) const { return iterator(*this, d); }
iterator end(imdd const * d) const { return iterator(); }
};
inline std::ostream & operator<<(std::ostream & out, imdd_ref const & r) {
r.get_manager().display(out, r.get());
return out;
}
struct mk_imdd_pp {
imdd * m_d;
imdd_manager & m_manager;
mk_imdd_pp(imdd * d, imdd_manager & m):m_d(d), m_manager(m) {}
};
inline mk_imdd_pp mk_pp(imdd * d, imdd_manager & m) {
return mk_imdd_pp(d, m);
}
inline std::ostream & operator<<(std::ostream & out, mk_imdd_pp const & pp) {
pp.m_manager.display(out, pp.m_d);
return out;
}
struct mk_imdd_ll_pp : public mk_imdd_pp {
mk_imdd_ll_pp(imdd * d, imdd_manager & m):mk_imdd_pp(d, m) {}
};
inline mk_imdd_ll_pp mk_ll_pp(imdd * d, imdd_manager & m) {
return mk_imdd_ll_pp(d, m);
}
inline std::ostream & operator<<(std::ostream & out, mk_imdd_ll_pp const & pp) {
pp.m_manager.display_ll(out, pp.m_d);
return out;
}
#endif /* _IMDD_H_ */

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,6 @@ Revision History:
#include "dl_mk_rule_inliner.h" #include "dl_mk_rule_inliner.h"
#include "dl_rule.h" #include "dl_rule.h"
#include "dl_rule_transformer.h" #include "dl_rule_transformer.h"
#include "dl_mk_extract_quantifiers.h"
#include "smt2parser.h" #include "smt2parser.h"
#include "pdr_context.h" #include "pdr_context.h"
#include "pdr_dl_interface.h" #include "pdr_dl_interface.h"
@ -33,7 +32,6 @@ Revision History:
#include "dl_mk_slice.h" #include "dl_mk_slice.h"
#include "dl_mk_unfold.h" #include "dl_mk_unfold.h"
#include "dl_mk_coalesce.h" #include "dl_mk_coalesce.h"
#include "pdr_quantifiers.h"
using namespace pdr; using namespace pdr;
@ -57,41 +55,36 @@ dl_interface::~dl_interface() {
// re-use existing context. // re-use existing context.
// //
void dl_interface::check_reset() { void dl_interface::check_reset() {
datalog::rule_ref_vector const& new_rules = m_ctx.get_rules().get_rules(); datalog::rule_set const& new_rules = m_ctx.get_rules();
datalog::rule_ref_vector const& old_rules = m_old_rules.get_rules(); datalog::rule_ref_vector const& old_rules = m_old_rules.get_rules();
bool is_subsumed = !old_rules.empty(); bool is_subsumed = !old_rules.empty();
for (unsigned i = 0; is_subsumed && i < new_rules.size(); ++i) { for (unsigned i = 0; is_subsumed && i < new_rules.get_num_rules(); ++i) {
is_subsumed = false; is_subsumed = false;
for (unsigned j = 0; !is_subsumed && j < old_rules.size(); ++j) { for (unsigned j = 0; !is_subsumed && j < old_rules.size(); ++j) {
if (m_ctx.check_subsumes(*old_rules[j], *new_rules[i])) { if (m_ctx.check_subsumes(*old_rules[j], *new_rules.get_rule(i))) {
is_subsumed = true; is_subsumed = true;
} }
} }
if (!is_subsumed) { if (!is_subsumed) {
TRACE("pdr", new_rules[i]->display(m_ctx, tout << "Fresh rule ");); TRACE("pdr", new_rules.get_rule(i)->display(m_ctx, tout << "Fresh rule "););
m_context->reset(); m_context->reset();
} }
} }
m_old_rules.reset(); m_old_rules.replace_rules(new_rules);
m_old_rules.add_rules(new_rules.size(), new_rules.c_ptr());
} }
lbool dl_interface::query(expr * query) { lbool dl_interface::query(expr * query) {
//we restore the initial state in the datalog context //we restore the initial state in the datalog context
m_ctx.ensure_opened(); m_ctx.ensure_opened();
m_pdr_rules.reset();
m_refs.reset(); m_refs.reset();
m_pred2slice.reset(); m_pred2slice.reset();
ast_manager& m = m_ctx.get_manager(); ast_manager& m = m_ctx.get_manager();
datalog::rule_manager& rule_manager = m_ctx.get_rule_manager(); datalog::rule_manager& rm = m_ctx.get_rule_manager();
datalog::rule_set old_rules(m_ctx.get_rules()); datalog::rule_set old_rules(m_ctx.get_rules());
func_decl_ref query_pred(m); func_decl_ref query_pred(m);
datalog::rule_ref_vector query_rules(rule_manager); rm.mk_query(query, m_ctx.get_rules());
datalog::rule_ref query_rule(rule_manager);
rule_manager.mk_query(query, query_pred, query_rules, query_rule);
m_ctx.add_rules(query_rules);
expr_ref bg_assertion = m_ctx.get_background_assertion(); expr_ref bg_assertion = m_ctx.get_background_assertion();
check_reset(); check_reset();
@ -107,7 +100,6 @@ lbool dl_interface::query(expr * query) {
); );
m_ctx.set_output_predicate(query_pred);
m_ctx.apply_default_transformation(); m_ctx.apply_default_transformation();
if (m_ctx.get_params().slice()) { if (m_ctx.get_params().slice()) {
@ -115,8 +107,6 @@ lbool dl_interface::query(expr * query) {
datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx); datalog::mk_slice* slice = alloc(datalog::mk_slice, m_ctx);
transformer.register_plugin(slice); transformer.register_plugin(slice);
m_ctx.transform_rules(transformer); m_ctx.transform_rules(transformer);
query_pred = slice->get_predicate(query_pred.get());
m_ctx.set_output_predicate(query_pred);
// track sliced predicates. // track sliced predicates.
obj_map<func_decl, func_decl*> const& preds = slice->get_predicates(); obj_map<func_decl, func_decl*> const& preds = slice->get_predicates();
@ -142,24 +132,15 @@ lbool dl_interface::query(expr * query) {
--num_unfolds; --num_unfolds;
} }
} }
// remove universal quantifiers from body. query_pred = m_ctx.get_rules().get_output_predicate();
datalog::mk_extract_quantifiers* extract_quantifiers = alloc(datalog::mk_extract_quantifiers, m_ctx);
datalog::rule_transformer extract_q_tr(m_ctx);
extract_q_tr.register_plugin(extract_quantifiers);
m_ctx.transform_rules(extract_q_tr);
IF_VERBOSE(2, m_ctx.display_rules(verbose_stream());); IF_VERBOSE(2, m_ctx.display_rules(verbose_stream()););
m_pdr_rules.add_rules(m_ctx.get_rules()); m_pdr_rules.replace_rules(m_ctx.get_rules());
m_pdr_rules.close(); m_pdr_rules.close();
m_ctx.reopen(); m_ctx.reopen();
m_ctx.replace_rules(old_rules); m_ctx.replace_rules(old_rules);
quantifier_model_checker quantifier_mc(*m_context, m, extract_quantifiers->quantifiers(), m_pdr_rules);
datalog::scoped_restore_proof _sc(m); // update_rules may overwrite the proof mode. datalog::scoped_restore_proof _sc(m); // update_rules may overwrite the proof mode.
m_context->set_proof_converter(m_ctx.get_proof_converter()); m_context->set_proof_converter(m_ctx.get_proof_converter());
@ -173,20 +154,7 @@ lbool dl_interface::query(expr * query) {
return l_false; return l_false;
} }
lbool result; return m_context->solve();
while (true) {
result = m_context->solve();
if (result == l_true && extract_quantifiers->has_quantifiers()) {
result = quantifier_mc.check();
if (result != l_false) {
return result;
}
// else continue
}
else {
return result;
}
}
} }

View file

@ -132,7 +132,7 @@ namespace pdr {
for_each_expr(collect_decls, m_relation_info[i].m_body); for_each_expr(collect_decls, m_relation_info[i].m_body);
} }
for (unsigned i = 0; i < rules.size(); ++i) { for (unsigned i = 0; i < rules.size(); ++i) {
bound_decls.insert(rules[i]->get_head()->get_decl()); bound_decls.insert(rules[i]->get_decl());
} }
for (unsigned i = 0; i < rules.size(); ++i) { for (unsigned i = 0; i < rules.size(); ++i) {
unsigned u_sz = rules[i]->get_uninterpreted_tail_size(); unsigned u_sz = rules[i]->get_uninterpreted_tail_size();

View file

@ -1,660 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
pdr_quantifiers.cpp
Abstract:
Module for handling quantifiers in rule bodies.
Author:
Nikolaj Bjorner (nbjorner) 2012-05-19.
Revision History:
--*/
#include "pdr_quantifiers.h"
#include "pdr_context.h"
#include "qe.h"
#include "var_subst.h"
#include "dl_rule_set.h"
#include "ast_smt2_pp.h"
#include "model_smt2_pp.h"
#include "ast_smt_pp.h"
#include "expr_abstract.h"
#include "dl_mk_extract_quantifiers.h"
#include "qe_lite.h"
#include "well_sorted.h"
#include "expr_safe_replace.h"
namespace pdr {
/**
\brief model check a potential model against quantifiers in bodies of rules.
\return true if the model rooted in 'root' is checks with the quantifiers, otherwise
'false' and a set of instantiations that contradict the current model.
*/
static void get_nodes(model_node& root, ptr_vector<model_node>& nodes) {
ptr_vector<model_node> todo;
todo.push_back(&root);
while (!todo.empty()) {
model_node* n = todo.back();
todo.pop_back();
nodes.push_back(n);
todo.append(n->children().size(), n->children().c_ptr());
}
}
quantifier_model_checker::~quantifier_model_checker() {
obj_map<func_decl,expr*>::iterator it = m_reachable.begin(), end = m_reachable.end();
for (; it != end; ++it) {
m.dec_ref(it->m_value);
}
}
void quantifier_model_checker::generalize_binding(expr_ref_vector const& binding, vector<expr_ref_vector>& bindings) {
expr_ref_vector new_binding(m);
generalize_binding(binding, 0, new_binding, bindings);
}
void quantifier_model_checker::generalize_binding(
expr_ref_vector const& binding, unsigned idx,
expr_ref_vector& new_binding, vector<expr_ref_vector>& bindings) {
if (idx == binding.size()) {
bool non_zero = false;
for (unsigned i = 0; i < binding.size(); ++i) {
if (new_binding[i].get()) {
non_zero = true;
}
else {
new_binding[i] = binding[i];
}
}
if (non_zero) {
TRACE("pdr",
for (unsigned i = 0; i < new_binding.size(); ++i) {
tout << mk_pp(new_binding[i].get(), m) << " ";
}
tout << "\n";);
bindings.push_back(new_binding);
}
return;
}
model_node& node = *m_current_node;
expr_ref_vector ands(m);
expr* e1, *e2;
datalog::flatten_and(node.state(), ands);
new_binding.push_back(0);
generalize_binding(binding, idx + 1, new_binding, bindings);
for (unsigned i = 0; i < ands.size(); ++i) {
if (m.is_eq(ands[i].get(), e1, e2)) {
if (e2 == binding[idx]) {
new_binding[new_binding.size()-1] = e1;
generalize_binding(binding, idx + 1, new_binding, bindings);
}
}
}
new_binding.pop_back();
}
void quantifier_model_checker::add_binding(quantifier* q, expr_ref_vector& binding) {
if (binding.size() != q->get_num_decls()) {
// not a full binding. It may happen that the quantifier got simplified.
return;
}
apply_binding(q, binding);
vector<expr_ref_vector> bindings;
generalize_binding(binding, bindings);
for (unsigned i = 0; i < bindings.size(); ++i) {
apply_binding(q, bindings[i]);
}
}
void quantifier_model_checker::apply_binding(quantifier* q, expr_ref_vector& binding) {
datalog::scoped_no_proof _scp(m);
app_ref_vector& var_inst = m_current_pt->get_inst(m_current_rule);
expr_ref e(m);
var_subst vs(m, false);
inv_var_shifter invsh(m);
vs(q->get_expr(), binding.size(), binding.c_ptr(), e);
invsh(e, q->get_num_decls(), e);
expr_ref_vector inst(m);
inst.append(var_inst.size(), (expr*const*)var_inst.c_ptr());
inst.reverse();
expr_abstract(m, 0, inst.size(), inst.c_ptr(), e, e);
if (m_instantiations.contains(to_app(e))) {
return;
}
m_instantiated_rules.push_back(m_current_rule);
m_instantiations.push_back(to_app(e));
TRACE("pdr", tout << mk_pp(q, m) << "\n";
tout << "binding: ";
for (unsigned i = 0; i < binding.size(); ++i) {
tout << mk_pp(binding[i].get(), m) << " ";
}
tout << "\n";
tout << "inst: ";
for (unsigned i = 0; i < var_inst.size(); ++i) {
tout << mk_pp(var_inst[i].get(), m) << " ";
}
tout << "\n";
tout << mk_pp(e, m) << "\n";
);
}
// As & not Body_i is satisfiable
// then instantiate with model for parameters to Body_i
void quantifier_model_checker::find_instantiations(quantifier_ref_vector const& qs, unsigned level) {
find_instantiations_proof_based(qs, level);
}
class collect_insts {
ast_manager& m;
ptr_vector<expr> m_binding;
vector<expr_ref_vector> m_bindings;
ptr_vector<quantifier> m_quantifiers;
public:
collect_insts(ast_manager& m): m(m) { }
void operator()(expr* n) {
expr* not_q_or_i, *e1, *e2, *e3;
if (m.is_quant_inst(n, not_q_or_i, m_binding)) {
VERIFY(m.is_or(not_q_or_i, e1, e2));
VERIFY(m.is_not(e1, e3));
SASSERT(is_quantifier(e3));
m_quantifiers.push_back(to_quantifier(e3));
m_bindings.push_back(expr_ref_vector(m,m_binding.size(), m_binding.c_ptr()));
m_binding.reset();
}
else if ((m.is_rewrite(n, e1, e2) ||
(m.is_rewrite_star(n) &&
(e3 = to_app(n)->get_arg(to_app(n)->get_num_args()-1),
e1 = to_app(e3)->get_arg(0),
e2 = to_app(e3)->get_arg(1),
true))) &&
is_quantifier(e1) && m.is_false(e2)) {
quantifier* q = to_quantifier(e1);
m_quantifiers.push_back(q);
m_bindings.push_back(expr_ref_vector(m));
expr_ref_vector& b = m_bindings.back();
for (unsigned i = 0; i < q->get_num_decls(); ++i) {
b.push_back(m.mk_fresh_const("V", q->get_decl_sort(i)));
}
}
}
void reset() {
m_quantifiers.reset();
m_bindings.reset();
}
unsigned size() const { return m_quantifiers.size(); }
ptr_vector<quantifier> const& quantifiers() const { return m_quantifiers; }
vector<expr_ref_vector> const& bindings() const { return m_bindings; }
};
void quantifier_model_checker::find_instantiations_proof_based(quantifier_ref_vector const& qs, unsigned level) {
bool found_instance = false;
datalog::scoped_proof _scp(m);
expr_ref_vector fmls(m);
smt_params fparams;
SASSERT(m.proofs_enabled());
fparams.m_mbqi = true;
fmls.push_back(m_A.get());
fmls.append(m_Bs);
TRACE("pdr",
tout << "assert\n";
for (unsigned i = 0; i < fmls.size(); ++i) {
tout << mk_pp(fmls[i].get(), m) << "\n";
});
smt::kernel solver(m, fparams);
for (unsigned i = 0; i < fmls.size(); ++i) {
solver.assert_expr(fmls[i].get());
}
lbool result = solver.check();
TRACE("pdr", tout << result << "\n";);
if (m_rules_model_check != l_false) {
m_rules_model_check = result;
}
if (result != l_false) {
return;
}
map<symbol, quantifier*, symbol_hash_proc, symbol_eq_proc> qid_map;
quantifier* q;
for (unsigned i = 0; i < qs.size(); ++i) {
q = qs[i];
qid_map.insert(q->get_qid(), q);
}
proof* p = solver.get_proof();
TRACE("pdr", tout << mk_ismt2_pp(p, m) << "\n";);
collect_insts collector(m);
for_each_expr(collector, p);
ptr_vector<quantifier> const& quants = collector.quantifiers();
for (unsigned i = 0; i < collector.size(); ++i) {
symbol qid = quants[i]->get_qid();
if (!qid_map.find(qid, q)) {
TRACE("pdr", tout << "Could not find quantifier " << mk_pp(quants[i], m) << "\n";);
continue;
}
expr_ref_vector const& binding = collector.bindings()[i];
TRACE("pdr", tout << "Instantiating:\n" << mk_pp(quants[i], m) << "\n";
for (unsigned j = 0; j < binding.size(); ++j) {
tout << mk_pp(binding[j], m) << " ";
}
tout << "\n";);
expr_ref_vector new_binding(m);
for (unsigned j = 0; j < binding.size(); ++j) {
new_binding.push_back(binding[j]);
}
add_binding(q, new_binding);
found_instance = true;
}
if (found_instance) {
m_rules_model_check = l_false;
}
else if (m_rules_model_check != l_false) {
m_rules_model_check = l_undef;
}
}
/**
For under-approximations:
m_reachable: set of reachable states, per predicate
rules: P(x) :- B[x,y] & Fa z . Q(y,z)
Q(y,z) :- C[y,z,u] & Fa w . R(u,w)
qis: Fa z . Q(y,z)
M: model satisfying P(x) & B[x,y]
B'[x,y]: body with reachable states substituted for predicates.
Q'[y,z]: reachable states substituted for Q.
S'[x]: Ex y . B'[x,y] & Fa z . Q'[y, z]
Method:
1. M |= Fa z . Q'[y, z] => done
Weaker variant:
Check B[x,y] & Fa z . Q'[y, z] for consistency.
2. Otherwise, extract instantiations.
3. Update reachable (for next round):
Q'[y,z] := Q'[y,z] \/ C'[y,z,u] & Fa w . R'(u,w)
*/
/**
For over-approximations:
- pt - predicate transformer for rule:
P(x) :- Body1(x,y) || Body2(x,z) & (Fa u . Q(u,x,z)).
- rule - P(x) :- Body2(x,z)
- qis - Fa u . Q(u,x,z)
- A := node.state(x) && Body2(x,y)
- Bs := array of Bs of the form:
. Fa u . Q(u, P_x, P_y) - instantiate quantifier to P variables.
. B := inv(Q_0,Q_1,Q_2)
. B := inv(u, P_x, P_y) := B[u/Q_0, P_x/Q_1, P_y/Q_2]
. B := Fa u . inv(u, P_x, P_y)
*/
void quantifier_model_checker::update_reachable(func_decl* f, expr* e) {
expr* e_old;
m.inc_ref(e);
if (m_reachable.find(f, e_old)) {
m.dec_ref(e_old);
}
m_reachable.insert(f, e);
}
expr_ref quantifier_model_checker::get_reachable(func_decl* p) {
expr* e = 0;
if (!m_reachable.find(p, e)) {
e = m_ctx.get_pred_transformer(p).initial_state();
update_reachable(p, e);
}
return expr_ref(e, m);
}
void quantifier_model_checker::add_over_approximations(quantifier_ref_vector& qis, model_node& n) {
add_approximations(qis, n, true);
}
void quantifier_model_checker::add_under_approximations(quantifier_ref_vector& qis, model_node& n) {
add_approximations(qis, n, false);
}
void quantifier_model_checker::add_approximations(quantifier_ref_vector& qis, model_node& n, bool is_over) {
pred_transformer& pt = n.pt();
manager& pm = pt.get_pdr_manager();
unsigned level = n.level();
expr_ref_vector Bs(m);
expr_ref B(m), v(m);
quantifier_ref q(m);
datalog::scoped_no_proof _no_proof(m);
scoped_ptr<expr_replacer> rep = mk_default_expr_replacer(m);
for (unsigned j = 0; j < qis.size(); ++j) {
q = qis[j].get();
SASSERT(is_forall(q));
app_ref_vector& inst = pt.get_inst(m_current_rule);
TRACE("pdr",
tout << "q:\n" << mk_pp(q, m) << "\n";
tout << "level: " << level << "\n";
model_smt2_pp(tout, m, n.get_model(), 0);
m_current_rule->display(m_ctx.get_context(), tout << "rule:\n");
);
var_subst vs(m, false);
vs(q, inst.size(), (expr*const*)inst.c_ptr(), B);
q = to_quantifier(B);
TRACE("pdr", tout << "q instantiated:\n" << mk_pp(q, m) << "\n";);
app* a = to_app(q->get_expr());
func_decl* f = a->get_decl();
pred_transformer& pt2 = m_ctx.get_pred_transformer(f);
if (is_over) {
B = pt2.get_formulas(level - 1, false);
}
else {
B = get_reachable(f);
SASSERT(is_well_sorted(m, B));
}
TRACE("pdr", tout << "B:\n" << mk_pp(B, m) << "\n";);
expr_safe_replace sub(m);
for (unsigned i = 0; i < a->get_num_args(); ++i) {
v = m.mk_const(pm.o2n(pt2.sig(i),0));
sub.insert(v, a->get_arg(i));
}
sub(B);
TRACE("pdr", tout << "B substituted:\n" << mk_pp(B, m) << "\n";);
datalog::flatten_and(B, Bs);
for (unsigned i = 0; i < Bs.size(); ++i) {
m_Bs.push_back(m.update_quantifier(q, Bs[i].get()));
}
}
}
/**
\brief compute strongest post-conditions for each predicate transformer.
(or at least something sufficient to change the set of current counter-examples)
*/
void quantifier_model_checker::weaken_under_approximation() {
datalog::rule_set::decl2rules::iterator it = m_rules.begin_grouped_rules(), end = m_rules.end_grouped_rules();
for (; it != end; ++it) {
func_decl* p = it->m_key;
datalog::rule_vector& rules = *it->m_value;
expr_ref_vector bodies(m);
for (unsigned i = 0; i < rules.size(); ++i) {
bodies.push_back(strongest_post_condition(*rules[i]));
}
update_reachable(p, m.mk_or(bodies.size(), bodies.c_ptr()));
}
}
expr_ref quantifier_model_checker::strongest_post_condition(datalog::rule& r) {
pred_transformer& pt = m_ctx.get_pred_transformer(r.get_decl());
manager& pm = pt.get_pdr_manager();
quantifier_ref_vector* qis = 0;
m_quantifiers.find(&r, qis);
expr_ref_vector body(m), inst(m);
expr_ref fml(m), v(m);
app* a;
func_decl* p;
svector<symbol> names;
unsigned ut_size = r.get_uninterpreted_tail_size();
unsigned t_size = r.get_tail_size();
var_subst vs(m, false);
ptr_vector<sort> vars;
uint_set empty_index_set;
qe_lite qe(m);
r.get_vars(vars);
if (qis) {
quantifier_ref_vector const& qi = *qis;
for (unsigned i = 0; i < qi.size(); ++i) {
quantifier* q = qi[i];
fml = q->get_expr();
a = to_app(fml);
p = a->get_decl();
expr* p_reach = get_reachable(p);
pred_transformer& pt2 = m_ctx.get_pred_transformer(p);
expr_safe_replace sub(m);
for (unsigned j = 0; j < a->get_num_args(); ++j) {
v = m.mk_const(pm.o2n(pt2.sig(j),0));
sub.insert(v, a->get_arg(j));
}
sub(p_reach, fml);
uint_set is;
for (unsigned j = 0; j < q->get_num_decls(); ++j) {
is.insert(j);
}
fml = m.mk_not(fml);
qe(is, true, fml);
fml = m.mk_not(fml);
body.push_back(m.update_quantifier(q, fml));
}
}
a = r.get_head();
for (unsigned i = 0; i < a->get_num_args(); ++i) {
v = m.mk_var(vars.size()+i, m.get_sort(a->get_arg(i)));
body.push_back(m.mk_eq(v, a->get_arg(i)));
}
for (unsigned i = 0; i < ut_size; ++i) {
a = r.get_tail(i);
p = a->get_decl();
pred_transformer& pt2 = m_ctx.get_pred_transformer(p);
expr* p_reach = get_reachable(p);
expr_safe_replace sub(m);
for (unsigned i = 0; i < a->get_num_args(); ++i) {
v = m.mk_const(pm.o2n(pt2.sig(i),0));
sub.insert(v, a->get_arg(i));
}
sub(p_reach, fml);
body.push_back(fml);
}
for (unsigned i = ut_size; i < t_size; ++i) {
body.push_back(r.get_tail(i));
}
fml = m.mk_and(body.size(), body.c_ptr());
vars.reverse();
for (unsigned i = 0; i < vars.size(); ++i) {
names.push_back(symbol(i));
}
if (!vars.empty()) {
fml = m.mk_exists(vars.size(), vars.c_ptr(), names.c_ptr(), fml);
SASSERT(is_well_sorted(m, fml));
}
for (unsigned i = 0; i < r.get_head()->get_num_args(); ++i) {
inst.push_back(m.mk_const(pm.o2n(pt.sig(i),0)));
}
vs(fml, inst.size(), inst.c_ptr(), fml);
SASSERT(is_well_sorted(m, fml));
if (!vars.empty()) {
fml = to_quantifier(fml)->get_expr();
qe(empty_index_set, false, fml);
fml = m.mk_exists(vars.size(), vars.c_ptr(), names.c_ptr(), fml);
SASSERT(is_well_sorted(m, fml));
m_ctx.get_context().get_rewriter()(fml);
}
SASSERT(is_well_sorted(m, fml));
IF_VERBOSE(0, verbose_stream() << "instantiate to:\n" << mk_pp(fml, m) << "\n";);
return fml;
}
void quantifier_model_checker::model_check_node(model_node& node) {
TRACE("pdr", node.display(tout, 0););
pred_transformer& pt = node.pt();
manager& pm = pt.get_pdr_manager();
expr_ref A(m), C(m);
expr_ref_vector As(m);
m_Bs.reset();
//
// nodes from leaves that are repeated
// inside the search tree don't have models.
//
if (!node.get_model_ptr()) {
return;
}
m_current_rule = node.get_rule();
m_current_pt = &pt;
m_current_node = &node;
if (!m_current_rule) {
return;
}
quantifier_ref_vector* qis = 0;
m_quantifiers.find(m_current_rule, qis);
if (!qis) {
return;
}
unsigned level = node.level();
if (level == 0) {
return;
}
As.push_back(pt.get_propagation_formula(m_ctx.get_pred_transformers(), level));
As.push_back(node.state());
As.push_back(pt.rule2tag(m_current_rule));
m_A = pm.mk_and(As);
// Add quantifiers:
// add_over_approximations(*qis, node);
add_under_approximations(*qis, node);
TRACE("pdr",
tout << "A:\n" << mk_pp(m_A, m) << "\n";
tout << "quantifier:\n";
for (unsigned i = 0; i < qis->size(); ++i) {
tout << mk_pp((*qis)[i].get(), m) << " ";
}
tout << "\n";
tout << "B:\n";
for (unsigned i = 0; i < m_Bs.size(); ++i) {
tout << mk_pp(m_Bs[i].get(), m) << "\n";
}
ast_smt_pp pp(m);
pp.add_assumption(m_A);
for (unsigned i = 0; i < m_Bs.size(); ++i) {
pp.add_assumption(m_Bs[i].get());
}
pp.display_smt2(tout, m.mk_true());
);
find_instantiations(*qis, level);
}
lbool quantifier_model_checker::model_check(model_node& root) {
m_instantiations.reset();
m_instantiated_rules.reset();
m_rules_model_check = l_true;
ptr_vector<model_node> nodes;
get_nodes(root, nodes);
for (unsigned i = nodes.size(); i > 0; ) {
--i;
model_check_node(*nodes[i]);
}
if (m_rules_model_check == l_false) {
weaken_under_approximation();
}
return m_rules_model_check;
}
void quantifier_model_checker::refine() {
datalog::mk_extract_quantifiers eq(m_ctx.get_context());
datalog::rule_manager& rm = m_rules.get_rule_manager();
datalog::rule_set new_rules(m_rules.get_context());
datalog::rule_set::iterator it = m_rules.begin(), end = m_rules.end();
for (; it != end; ++it) {
datalog::rule* r = *it;
datalog::rule_counter vc(true);
unsigned max_var = vc.get_max_rule_var(*r);
app_ref_vector body(m);
for (unsigned i = 0; i < m_instantiations.size(); ++i) {
if (r == m_instantiated_rules[i]) {
eq.ensure_predicate(m_instantiations[i].get(), max_var, body);
}
}
if (body.empty()) {
new_rules.add_rule(r);
}
else {
for (unsigned i = 0; i < r->get_tail_size(); ++i) {
body.push_back(r->get_tail(i));
}
quantifier_ref_vector* qs = 0;
m_quantifiers.find(r, qs);
m_quantifiers.remove(r);
datalog::rule_ref new_rule(rm);
new_rule = rm.mk(r->get_head(), body.size(), body.c_ptr(), 0, r->name(), false);
new_rules.add_rule(new_rule);
m_quantifiers.insert(new_rule, qs);
IF_VERBOSE(1,
verbose_stream() << "instantiating quantifiers\n";
r->display(m_ctx.get_context(), verbose_stream());
verbose_stream() << "replaced by\n";
new_rule->display(m_ctx.get_context(), verbose_stream()););
}
}
new_rules.close();
m_rules.reset();
m_rules.add_rules(new_rules);
m_rules.close();
m_ctx.update_rules(m_rules);
TRACE("pdr", m_rules.display(tout););
}
lbool quantifier_model_checker::check() {
lbool result = model_check(m_ctx.get_root());
if (result == l_false) {
refine();
}
return result;
}
};

View file

@ -1,117 +0,0 @@
/*++
Copyright (c) 2012 Microsoft Corporation
Module Name:
pdr_quantifiers.h
Abstract:
Module for handling quantifiers in rule bodies.
Author:
Nikolaj Bjorner (nbjorner) 2012-05-19.
Revision History:
--*/
#ifndef _PDR_QUANTIFIERS_H_
#define _PDR_QUANTIFIERS_H_
#include "ast.h"
#include "lbool.h"
#include "dl_rule.h"
#include "obj_pair_hashtable.h"
namespace datalog {
class rule_set;
};
namespace pdr {
class model_node;
class pred_transformer;
class context;
class quantifier_model_checker {
context& m_ctx;
ast_manager& m;
obj_map<datalog::rule const, quantifier_ref_vector*>& m_quantifiers;
datalog::rule_set& m_rules;
obj_map<func_decl, expr*> m_reachable; // set of reachable states
expr_ref m_A;
expr_ref_vector m_Bs;
pred_transformer* m_current_pt;
datalog::rule const* m_current_rule;
model_node* m_current_node;
lbool m_rules_model_check;
app_ref_vector m_instantiations;
ptr_vector<datalog::rule const> m_instantiated_rules;
void model_check_node(model_node& node);
void weaken_under_approximation();
void find_instantiations(quantifier_ref_vector const& qs, unsigned level);
void find_instantiations_proof_based(quantifier_ref_vector const& qs, unsigned level);
void add_binding(quantifier* q, expr_ref_vector& binding);
void apply_binding(quantifier* q, expr_ref_vector& binding);
void generalize_binding(expr_ref_vector const& binding, vector<expr_ref_vector>& bindings);
void generalize_binding(expr_ref_vector const& binding, unsigned idx, expr_ref_vector& new_binding, vector<expr_ref_vector>& bindings);
void refine();
/**
\brief model check a potential model against quantifiers in bodies of rules.
\return true if the model rooted in 'root' is checks with the quantifiers, otherwise
'false' and a set of instantiations that contradict the current model.
*/
lbool model_check(model_node& root);
void add_over_approximations(quantifier_ref_vector& qis, model_node& n);
void add_under_approximations(quantifier_ref_vector& qis, model_node& n);
void add_approximations(quantifier_ref_vector& qis, model_node& n, bool is_over);
expr_ref get_reachable(func_decl* f);
void update_reachable(func_decl* f, expr* e);
expr_ref strongest_post_condition(datalog::rule& r);
public:
quantifier_model_checker(
context& ctx,
ast_manager& m,
obj_map<datalog::rule const, quantifier_ref_vector*>& quantifiers,
datalog::rule_set& rules) :
m_ctx(ctx),
m(m),
m_quantifiers(quantifiers),
m_rules(rules),
m_A(m),
m_Bs(m),
m_current_pt(0),
m_current_rule(0),
m_current_node(0),
m_instantiations(m) {}
~quantifier_model_checker();
lbool check();
};
};
#endif

View file

@ -35,6 +35,39 @@ Revision History:
namespace datalog { namespace datalog {
class rel_context::scoped_query {
context& m_ctx;
rule_set m_rules;
decl_set m_preds;
bool m_was_closed;
public:
scoped_query(context& ctx):
m_ctx(ctx),
m_rules(ctx.get_rules()),
m_preds(ctx.get_predicates()),
m_was_closed(ctx.is_closed())
{
if (m_was_closed) {
ctx.reopen();
}
}
~scoped_query() {
m_ctx.reopen();
m_ctx.restrict_predicates(m_preds);
m_ctx.replace_rules(m_rules);
if (m_was_closed) {
m_ctx.close();
}
}
void reset() {
m_ctx.reopen();
m_ctx.restrict_predicates(m_preds);
m_ctx.replace_rules(m_rules);
m_ctx.close();
}
};
rel_context::rel_context(context& ctx) rel_context::rel_context(context& ctx)
: m_context(ctx), : m_context(ctx),
m(ctx.get_manager()), m(ctx.get_manager()),
@ -56,9 +89,7 @@ namespace datalog {
get_rmanager().register_plugin(alloc(bound_relation_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(bound_relation_plugin, get_rmanager()));
get_rmanager().register_plugin(alloc(interval_relation_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(interval_relation_plugin, get_rmanager()));
get_rmanager().register_plugin(alloc(karr_relation_plugin, get_rmanager())); get_rmanager().register_plugin(alloc(karr_relation_plugin, get_rmanager()));
}
}
rel_context::~rel_context() { rel_context::~rel_context() {
if (m_last_result_relation) { if (m_last_result_relation) {
@ -67,25 +98,6 @@ namespace datalog {
} }
} }
void rel_context::collect_predicates(decl_set & res) {
unsigned rule_cnt = m_context.get_rules().get_num_rules();
for (unsigned rindex=0; rindex<rule_cnt; rindex++) {
rule * r = m_context.get_rules().get_rule(rindex);
res.insert(r->get_head()->get_decl());
unsigned tail_len = r->get_uninterpreted_tail_size();
for (unsigned tindex=0; tindex<tail_len; tindex++) {
res.insert(r->get_tail(tindex)->get_decl());
}
}
decl_set::iterator oit = m_output_preds.begin();
decl_set::iterator oend = m_output_preds.end();
for (; oit!=oend; ++oit) {
res.insert(*oit);
}
get_rmanager().collect_predicates(res);
}
lbool rel_context::saturate() { lbool rel_context::saturate() {
m_context.ensure_closed(); m_context.ensure_closed();
@ -93,9 +105,7 @@ namespace datalog {
unsigned remaining_time_limit = m_context.soft_timeout(); unsigned remaining_time_limit = m_context.soft_timeout();
unsigned restart_time = m_context.initial_restart_timeout(); unsigned restart_time = m_context.initial_restart_timeout();
rule_set original_rules(m_context.get_rules()); scoped_query scoped_query(m_context);
decl_set original_predicates;
m_context.collect_predicates(original_predicates);
m_code.reset(); m_code.reset();
instruction_block termination_code; instruction_block termination_code;
@ -106,6 +116,7 @@ namespace datalog {
TRACE("dl", m_context.display(tout);); TRACE("dl", m_context.display(tout););
while (true) { while (true) {
m_context.ensure_closed();
m_context.transform_rules(); m_context.transform_rules();
if (m_context.canceled()) { if (m_context.canceled()) {
result = l_undef; result = l_undef;
@ -165,45 +176,20 @@ namespace datalog {
} }
termination_code.reset(); termination_code.reset();
m_context.reopen(); scoped_query.reset();
restrict_predicates(original_predicates);
m_context.replace_rules(original_rules);
m_context.close();
} }
m_context.reopen();
restrict_predicates(original_predicates);
m_context.record_transformed_rules(); m_context.record_transformed_rules();
m_context.replace_rules(original_rules);
m_context.close();
TRACE("dl", m_ectx.report_big_relations(100, tout);); TRACE("dl", m_ectx.report_big_relations(100, tout););
m_code.process_all_costs(); m_code.process_all_costs();
m_code.make_annotations(m_ectx); m_code.make_annotations(m_ectx);
return result; return result;
} }
#define BEGIN_QUERY() \
rule_set original_rules(m_context.get_rules()); \
decl_set original_preds; \
m_context.collect_predicates(original_preds); \
bool was_closed = m_context.is_closed(); \
if (was_closed) { \
m_context.reopen(); \
} \
#define END_QUERY() \
m_context.reopen(); \
m_context.replace_rules(original_rules); \
restrict_predicates(original_preds); \
\
if (was_closed) { \
m_context.close(); \
} \
lbool rel_context::query(unsigned num_rels, func_decl * const* rels) { lbool rel_context::query(unsigned num_rels, func_decl * const* rels) {
get_rmanager().reset_saturated_marks(); get_rmanager().reset_saturated_marks();
BEGIN_QUERY(); scoped_query _scoped_query(m_context);
for (unsigned i = 0; i < num_rels; ++i) { for (unsigned i = 0; i < num_rels; ++i) {
set_output_predicate(rels[i]); m_context.set_output_predicate(rels[i]);
} }
m_context.close(); m_context.close();
reset_negated_tables(); reset_negated_tables();
@ -238,27 +224,16 @@ namespace datalog {
case l_undef: case l_undef:
break; break;
} }
END_QUERY();
return res; return res;
} }
lbool rel_context::query(expr* query) { lbool rel_context::query(expr* query) {
get_rmanager().reset_saturated_marks(); get_rmanager().reset_saturated_marks();
BEGIN_QUERY(); scoped_query _scoped_query(m_context);
rule_manager& rm = m_context.get_rule_manager(); rule_manager& rm = m_context.get_rule_manager();
rule_ref qrule(rm);
rule_ref_vector qrules(rm);
func_decl_ref query_pred(m); func_decl_ref query_pred(m);
try { try {
rm.mk_query(query, query_pred, qrules, qrule); query_pred = rm.mk_query(query, m_context.get_rules());
}
catch(default_exception& exn) {
m_context.close();
m_context.set_status(INPUT_ERROR);
throw exn;
}
try {
m_context.add_rules(qrules);
} }
catch (default_exception& exn) { catch (default_exception& exn) {
m_context.close(); m_context.close();
@ -266,29 +241,17 @@ namespace datalog {
throw exn; throw exn;
} }
set_output_predicate(qrule->get_head()->get_decl());
m_context.close(); m_context.close();
reset_negated_tables(); reset_negated_tables();
if (m_context.generate_explanations()) { if (m_context.generate_explanations()) {
rule_transformer transformer(m_context); m_context.transform_rules(alloc(mk_explanations, m_context));
//expl_plugin is deallocated when transformer goes out of scope
mk_explanations * expl_plugin =
alloc(mk_explanations, m_context, m_context.explanations_on_relation_level());
transformer.register_plugin(expl_plugin);
m_context.transform_rules(transformer);
//we will retrieve the predicate with explanations instead of the original query predicate
query_pred = expl_plugin->get_e_decl(query_pred);
const rule_vector & query_rules = m_context.get_rules().get_predicate_rules(query_pred);
SASSERT(query_rules.size()==1);
qrule = query_rules.back();
} }
query_pred = m_context.get_rules().get_pred(query_pred);
if (m_context.magic_sets_for_queries()) { if (m_context.magic_sets_for_queries()) {
rule_transformer transformer(m_context); m_context.transform_rules(alloc(mk_magic_sets, m_context, query_pred));
transformer.register_plugin(alloc(mk_magic_sets, m_context, qrule.get()));
m_context.transform_rules(transformer);
} }
lbool res = saturate(); lbool res = saturate();
@ -304,7 +267,6 @@ namespace datalog {
} }
} }
END_QUERY();
return res; return res;
} }
@ -372,15 +334,8 @@ namespace datalog {
} }
} }
void rel_context::set_output_predicate(func_decl * pred) { void rel_context::restrict_predicates(func_decl_set const& predicates) {
if (!m_output_preds.contains(pred)) { get_rmanager().restrict_predicates(predicates);
m_output_preds.insert(pred);
}
}
void rel_context::restrict_predicates( const decl_set & res ) {
set_intersection(m_output_preds, res);
get_rmanager().restrict_predicates(res);
} }
relation_base & rel_context::get_relation(func_decl * pred) { return get_rmanager().get_relation(pred); } relation_base & rel_context::get_relation(func_decl * pred) { return get_rmanager().get_relation(pred); }
@ -510,8 +465,8 @@ namespace datalog {
} }
} }
void rel_context::display_output_facts(std::ostream & out) const { void rel_context::display_output_facts(rule_set const& rules, std::ostream & out) const {
get_rmanager().display_output_tables(out); get_rmanager().display_output_tables(rules, out);
} }
void rel_context::display_facts(std::ostream& out) const { void rel_context::display_facts(std::ostream& out) const {

View file

@ -37,11 +37,12 @@ namespace datalog {
relation_manager m_rmanager; relation_manager m_rmanager;
expr_ref m_answer; expr_ref m_answer;
relation_base * m_last_result_relation; relation_base * m_last_result_relation;
decl_set m_output_preds;
fact_vector m_table_facts; fact_vector m_table_facts;
execution_context m_ectx; execution_context m_ectx;
instruction_block m_code; instruction_block m_code;
class scoped_query;
void reset_negated_tables(); void reset_negated_tables();
relation_plugin & get_ordinary_relation_plugin(symbol relation_name); relation_plugin & get_ordinary_relation_plugin(symbol relation_name);
@ -78,13 +79,7 @@ namespace datalog {
The function deallocates unsused relations, it does not deal with rules. The function deallocates unsused relations, it does not deal with rules.
*/ */
void restrict_predicates(const decl_set & res); void restrict_predicates(func_decl_set const& predicates);
void collect_predicates(decl_set & res);
void set_output_predicate(func_decl * pred);
bool is_output_predicate(func_decl * pred) { return m_output_preds.contains(pred); }
const decl_set & get_output_predicates() const { return m_output_preds; }
/** /**
@ -102,7 +97,7 @@ namespace datalog {
*/ */
void store_relation(func_decl * pred, relation_base * rel); void store_relation(func_decl * pred, relation_base * rel);
void display_output_facts(std::ostream & out) const; void display_output_facts(rule_set const& rules, std::ostream & out) const;
void display_facts(std::ostream & out) const; void display_facts(std::ostream & out) const;
void display_profile(std::ostream& out) const; void display_profile(std::ostream& out) const;

View file

@ -191,6 +191,7 @@ namespace tb {
unsigned get_index() const { return m_index; } unsigned get_index() const { return m_index; }
void set_index(unsigned index) { m_index = index; } void set_index(unsigned index) { m_index = index; }
app* get_head() const { return m_head; } app* get_head() const { return m_head; }
func_decl* get_decl() const { return m_head->get_decl(); }
void set_head(app* h) { m_head = h; } void set_head(app* h) { m_head = h; }
unsigned get_parent_index() const { return m_parent_index; } unsigned get_parent_index() const { return m_parent_index; }
unsigned get_parent_rule() const { return m_parent_rule; } unsigned get_parent_rule() const { return m_parent_rule; }
@ -447,7 +448,7 @@ namespace tb {
void insert(ref<clause>& g) { void insert(ref<clause>& g) {
unsigned idx = m_rules.size(); unsigned idx = m_rules.size();
m_rules.push_back(g); m_rules.push_back(g);
func_decl* f = g->get_head()->get_decl(); func_decl* f = g->get_decl();
map::obj_map_entry* e = m_index.insert_if_not_there2(f, unsigned_vector()); map::obj_map_entry* e = m_index.insert_if_not_there2(f, unsigned_vector());
SASSERT(e); SASSERT(e);
e->get_data().m_value.push_back(idx); e->get_data().m_value.push_back(idx);
@ -613,7 +614,7 @@ namespace tb {
bool match_head(clause const& g) { bool match_head(clause const& g) {
return return
m_head->get_decl() == g.get_head()->get_decl() && m_head->get_decl() == g.get_decl() &&
m_matcher(m_head, g.get_head(), m_subst, m_sideconds) && m_matcher(m_head, g.get_head(), m_subst, m_sideconds) &&
match_predicates(0, g); match_predicates(0, g);
} }
@ -1080,7 +1081,7 @@ namespace tb {
bool unify(clause const& tgt, unsigned idx, clause const& src, bool compute_subst, ref<clause>& result) { bool unify(clause const& tgt, unsigned idx, clause const& src, bool compute_subst, ref<clause>& result) {
qe_lite qe(m); qe_lite qe(m);
reset(); reset();
SASSERT(tgt.get_predicate(idx)->get_decl() == src.get_head()->get_decl()); SASSERT(tgt.get_predicate(idx)->get_decl() == src.get_decl());
unsigned var_cnt = std::max(tgt.get_num_vars(), src.get_num_vars()); unsigned var_cnt = std::max(tgt.get_num_vars(), src.get_num_vars());
m_S1.reserve(2, var_cnt); m_S1.reserve(2, var_cnt);
if (!m_unifier(tgt.get_predicate(idx), src.get_head(), m_S1)) { if (!m_unifier(tgt.get_predicate(idx), src.get_head(), m_S1)) {
@ -1380,11 +1381,10 @@ namespace datalog {
m_displayed_rules.reset(); m_displayed_rules.reset();
m_rules.init(m_ctx.get_rules()); m_rules.init(m_ctx.get_rules());
m_selection.init(m_rules); m_selection.init(m_rules);
rule_ref_vector query_rules(rm); rule_set query_rules(m_ctx);
rule_ref clause(rm); rule_ref clause(rm);
func_decl_ref query_pred(m); rm.mk_query(query, query_rules);
rm.mk_query(query, query_pred, query_rules, clause); clause = query_rules.last();
ref<tb::clause> g = alloc(tb::clause, m); ref<tb::clause> g = alloc(tb::clause, m);
g->init(clause); g->init(clause);
g->set_head(m.mk_false()); g->set_head(m.mk_false());

View file

@ -175,8 +175,6 @@ unsigned read_datalog(char const * file) {
TRACE("dl_compiler", ctx.display(tout);); TRACE("dl_compiler", ctx.display(tout););
datalog::rule_set original_rules(ctx.get_rules()); datalog::rule_set original_rules(ctx.get_rules());
datalog::decl_set original_predicates;
ctx.collect_predicates(original_predicates);
datalog::instruction_block rules_code; datalog::instruction_block rules_code;
datalog::instruction_block termination_code; datalog::instruction_block termination_code;
@ -237,7 +235,6 @@ unsigned read_datalog(char const * file) {
termination_code.reset(); termination_code.reset();
ex_ctx.reset(); ex_ctx.reset();
ctx.reopen(); ctx.reopen();
ctx.restrict_predicates(original_predicates);
ctx.replace_rules(original_rules); ctx.replace_rules(original_rules);
ctx.close(); ctx.close();
} }
@ -248,7 +245,7 @@ unsigned read_datalog(char const * file) {
rules_code.display(ctx.get_rel_context(), tout);); rules_code.display(ctx.get_rel_context(), tout););
if (ctx.get_params().output_tuples()) { if (ctx.get_params().output_tuples()) {
ctx.get_rel_context().display_output_facts(std::cout); ctx.get_rel_context().display_output_facts(ctx.get_rules(), std::cout);
} }
display_statistics( display_statistics(

View file

@ -59,7 +59,7 @@ void dl_query_test(ast_manager & m, smt_params & fparams, params_ref& params,
} }
relation_manager & rel_mgr_q = ctx_b.get_rel_context().get_rmanager(); relation_manager & rel_mgr_q = ctx_b.get_rel_context().get_rmanager();
decl_set out_preds = ctx_b.get_output_predicates(); decl_set out_preds = ctx_b.get_rules().get_output_predicates();
decl_set::iterator it = out_preds.begin(); decl_set::iterator it = out_preds.begin();
decl_set::iterator end = out_preds.end(); decl_set::iterator end = out_preds.end();
for(; it!=end; ++it) { for(; it!=end; ++it) {

View file

@ -1,7 +1,6 @@
#ifdef _WINDOWS #ifdef _WINDOWS
#include "dl_context.h" #include "dl_context.h"
#include "dl_table.h" #include "dl_table.h"
#include "dl_skip_table.h"
typedef datalog::table_base* (*mk_table_fn)(datalog::relation_manager& m, datalog::table_signature& sig); typedef datalog::table_base* (*mk_table_fn)(datalog::relation_manager& m, datalog::table_signature& sig);
@ -11,13 +10,6 @@ static datalog::table_base* mk_bv_table(datalog::relation_manager& m, datalog::t
return p->mk_empty(sig); return p->mk_empty(sig);
} }
static datalog::table_base* mk_skip_table(datalog::relation_manager& m, datalog::table_signature& sig) {
datalog::table_plugin * p = m.get_table_plugin(symbol("skip"));
SASSERT(p);
return p->mk_empty(sig);
}
static void test_table(mk_table_fn mk_table) { static void test_table(mk_table_fn mk_table) {
datalog::table_signature sig; datalog::table_signature sig;
sig.push_back(2); sig.push_back(2);
@ -96,13 +88,9 @@ void test_dl_bitvector_table() {
test_table(mk_bv_table); test_table(mk_bv_table);
} }
void test_dl_skip_table() {
test_table(mk_skip_table);
}
void tst_dl_table() { void tst_dl_table() {
test_dl_bitvector_table(); test_dl_bitvector_table();
test_dl_skip_table();
} }
#else #else
void tst_dl_table() { void tst_dl_table() {

View file

@ -1,617 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
imdd.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2010-10-14.
Revision History:
--*/
#include"imdd.h"
#if !defined(_AMD64_) && defined(Z3DEBUG)
static void tst0() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m), d2(m), d3(m), d4(m);
d1 = m.mk_empty(1);
d2 = m.mk_empty(1);
m.insert_dupdt(d1, 10, 20);
m.insert_dupdt(d1, 31, 50);
m.insert_dupdt(d2, 1, 5);
m.insert_dupdt(d2, 11, 13);
m.mk_product(d1, d2, d4);
m.mk_product(d4, d2, d4);
m.mk_product_dupdt(d1, d2);
std::cout << "d1:\n" << mk_ll_pp(d1, m) << "\n-------\n";
m.mk_product_dupdt(d1, d2);
std::cout << "d4:\n" << mk_ll_pp(d4, m) << "\nd1:\n" << mk_ll_pp(d1, m) << "\nd2:\n" << mk_ll_pp(d2, m) << "\n";
std::cout << d1 << "\n" << d2 << "\n";
m.mk_product_dupdt(d1, d1);
std::cout << "d1 X d1:\n" << mk_ll_pp(d1, m) << "\n";
}
static void add_triple(imdd_manager & m, imdd_ref & d, unsigned l1, unsigned u1, unsigned l2, unsigned u2, unsigned l3, unsigned u3,
bool destructive = false, bool memoize = true) {
unsigned lowers[3] = {l1, l2, l3};
unsigned uppers[3] = {u1, u2, u3};
if (destructive)
m.add_facts_dupdt(d, 3, lowers, uppers, memoize);
else
m.add_facts(d, d, 3, lowers, uppers, memoize);
// std::cout << mk_ll_pp(d, m) << "\n";
}
static void add_pair(imdd_manager & m, imdd_ref & d, unsigned l1, unsigned u1, unsigned l2, unsigned u2, bool destructive = false, bool memoize = true) {
unsigned lowers[2] = {l1, l2};
unsigned uppers[2] = {u1, u2};
if (destructive)
m.add_facts_dupdt(d, 2, lowers, uppers, memoize);
else
m.add_facts(d, d, 2, lowers, uppers, memoize);
// std::cout << mk_ll_pp(d, m) << "\n";
}
static void add_some_facts(imdd_manager & m, imdd_ref & d, bool destructive = false, bool memoize = true) {
std::cout << "destructive: " << destructive << ", memoize: " << memoize << std::endl;
add_triple(m, d, 1, 10, 3, 3, 0, 100, destructive, memoize);
std::cout << mk_ll_pp(d, m) << std::endl;
SASSERT(m.contains(d, 2, 3, 20));
SASSERT(!m.contains(d, 2, 4, 20));
SASSERT(!m.contains(d, 2, 3, 200));
SASSERT(!m.contains(d, 0, 3, 200));
SASSERT(m.contains(d,1,3,0));
add_triple(m, d, 3, 6, 3, 4, 7, 101, destructive, memoize);
std::cout << mk_ll_pp(d, m) << std::endl;
add_triple(m, d, 3, 6, 2, 2, 7, 101, destructive, memoize);
std::cout << mk_ll_pp(d, m) << std::endl;
add_triple(m, d, 3, 6, 5, 6, 7, 101, destructive, memoize);
SASSERT(m.contains(d, 2, 3, 20));
std::cout << mk_ll_pp(d, m) << std::endl;
SASSERT(!m.contains(d, 2, 4, 20));
SASSERT(m.contains(d, 3, 4, 20));
SASSERT(!m.contains(d, 2, 3, 200));
SASSERT(!m.contains(d, 0, 3, 200));
SASSERT(m.contains(d,1,3,0));
}
static void tst1() {
std::cout << "--------------------------------\n";
imdd_manager m;
{
imdd_ref d(m);
d = m.mk_empty(3);
add_some_facts(m, d);
}
{
imdd_ref d(m);
d = m.mk_empty(3);
add_some_facts(m, d, true, false);
m.defrag(d);
std::cout << mk_ll_pp(d, m) << "\n";
}
}
static void tst2() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m), d2(m), d3(m);
d1 = m.mk_empty(3);
add_triple(m, d1, 10, 20, 11, 21, 12, 22);
add_triple(m, d1, 30, 40, 31, 41, 32, 42);
d2 = m.mk_empty(3);
add_triple(m, d2, 15, 22, 15, 23, 7, 18);
add_triple(m, d2, 28, 42, 29, 39, 34, 46);
add_triple(m, d2, 28, 42, 29, 39, 100, 200);
add_triple(m, d2, 28, 42, 50, 60, 100, 200);
std::cout << mk_ll_pp(d1, m) << "\n";
std::cout << mk_ll_pp(d2, m) << "\n";
m.mk_union(d1, d2, d3);
SASSERT(m.subsumes(d3, d1));
SASSERT(m.subsumes(d3, d2));
SASSERT(!m.subsumes(d1, d3));
SASSERT(!m.subsumes(d2, d3));
std::cout << "d3: " << d3.get() << "\n" << mk_ll_pp(d3, m) << "\n";
m.mk_union_dupdt(d1, d2, false);
std::cout << "d1: " << d1.get() << "\n" << mk_ll_pp(d1, m) << "\n";
SASSERT(m.is_equal(d1, d3));
SASSERT(!m.is_equal(d2, d3));
SASSERT(!m.is_equal(d2, d1));
std::cout << "memory(d1): " << m.memory(d1) << "\n";
}
static void tst3() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m);
d1 = m.mk_empty(3);
unsigned mins[3] = {0,0,0};
unsigned maxs[3] = {127, 511, 255};
m.mk_complement(d1, d1, 3, mins, maxs);
std::cout << d1 << "\n";
m.mk_complement(d1, d1, 3, mins, maxs);
std::cout << d1 << "\n";
SASSERT(d1->empty());
d1 = m.mk_empty(3);
add_triple(m, d1, 10, 20, 11, 21, 12, 22);
add_triple(m, d1, 30, 40, 31, 41, 32, 42);
std::cout << d1 << "\n";
m.mk_complement(d1, d1, 3, mins, maxs);
std::cout << mk_ll_pp(d1,m) << "\n";
m.mk_filter_equal(d1, d1, 1, 15);
std::cout << "after selecting second column = 15\n" << mk_ll_pp(d1,m) << "\n";
}
static void tst4() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m);
d1 = m.mk_empty(3);
add_triple(m, d1, 1, 2, 2, 5, 4, 4);
add_triple(m, d1, 3, 4, 3, 4, 2, 5);
std::cout << "testing iterator:\n";
imdd_manager::iterator it = m.begin(d1);
imdd_manager::iterator end = m.end(d1);
for (; it != end; ++it) {
unsigned * tuple = *it;
std::cout << "[";
for (unsigned i = 0; i < d1->get_arity(); i++) {
if (i > 0)
std::cout << ", ";
std::cout << tuple[i];
}
std::cout << "]\n";
}
}
static void tst5() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m), d2(m), d3(m);
std::cout.flush();
d1 = m.mk_empty(3);
add_triple(m, d1, 5, 100, 10, 20, 3, 10);
std::cout << mk_ll_pp(d1,m) << std::endl;
add_triple(m, d1, 5, 100, 34, 50, 98, 110);
std::cout << mk_ll_pp(d1,m) << std::endl;
unsigned vals[3] = {6, 8, 3};
SASSERT(!m.contains(d1, 3, vals));
add_triple(m, d1, 6, 25, 8, 30, 14, 50);
std::cout << mk_ll_pp(d1,m) << std::endl;
SASSERT(!m.contains(d1, 3, vals));
unsigned vars[2] = {0, 2};
d2 = d1;
d3 = d1;
m.mk_filter_identical(d1, d1, 2, vars);
vars[1] = 1;
std::cout << "d1:\n" << mk_ll_pp(d1,m) << "\n";
m.mk_filter_identical(d2, d2, 2, vars);
std::cout << "d2:\n" << mk_ll_pp(d2,m) << "\n";
vars[0] = 1;
vars[1] = 2;
m.mk_filter_identical(d3, d3, 2, vars);
std::cout << "d3:\n" << mk_ll_pp(d3,m) << "\n";
}
static void add_5tuple(imdd_manager & m, imdd_ref & d, unsigned l1, unsigned u1, unsigned l2, unsigned u2, unsigned l3, unsigned u3,
unsigned l4, unsigned u4, unsigned l5, unsigned u5, bool destructive = false, bool memoize = true) {
unsigned lowers[5] = {l1, l2, l3, l4, l5};
unsigned uppers[5] = {u1, u2, u3, u4, u5};
if (destructive)
m.add_facts_dupdt(d, 5, lowers, uppers, memoize);
else
m.add_facts(d, d, 5, lowers, uppers, memoize);
// std::cout << mk_ll_pp(d, m) << "\n";
}
static void tst6() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m);
std::cout.flush();
d1 = m.mk_empty(5);
// TODO: make a more complicated mk_filter_identical example
}
static void tst7() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d2(m), d3(m);
d2 = m.mk_empty(3);
add_triple(m, d2, 15, 22, 15, 23, 7, 18);
add_triple(m, d2, 28, 42, 29, 39, 34, 46);
add_triple(m, d2, 28, 42, 29, 39, 100, 200);
add_triple(m, d2, 28, 42, 50, 60, 100, 200);
std::cout << "mk_project\n";
std::cout << mk_ll_pp(d2, m) << "\n";
unsigned vars[1] = {1};
m.mk_project(d2, d3, 1, vars);
std::cout << mk_ll_pp(d3, m) << "\n";
}
static void tst8() {
std::cout << "--------------------------------\n";
// enable_trace("mk_swap_bug");
imdd_manager m;
imdd_ref d2(m), d3(m);
d2 = m.mk_empty(3);
add_triple(m, d2, 15, 22, 15, 23, 7, 18);
add_triple(m, d2, 28, 42, 29, 39, 34, 46);
add_triple(m, d2, 28, 42, 29, 39, 100, 200);
add_triple(m, d2, 28, 42, 50, 60, 100, 200);
std::cout << mk_ll_pp(d2, m) << "\n";
m.mk_swap(d2, d3, 0);
std::cout << "after swap 0<->1\n";
std::cout << mk_ll_pp(d3, m) << "\n";
m.mk_swap(d2, d3, 1);
std::cout << "after swap 1<->2\n";
std::cout << mk_ll_pp(d3, m) << "\n";
}
static void tst9() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d2(m), d3(m);
d2 = m.mk_empty(5);
add_5tuple(m, d2, 2,2, 3,3, 1, 1, 5, 10, 100, 200);
std::cout << mk_ll_pp(d2, m) << "\n";
add_5tuple(m, d2, 2,2, 3,3, 1, 1, 15, 20, 100, 200);
std::cout << mk_ll_pp(d2, m) << "\n";
add_5tuple(m, d2, 4,4, 5,5, 1, 1, 5, 10, 100, 200);
std::cout << mk_ll_pp(d2, m) << "\n";
add_5tuple(m, d2, 4,4, 5,5, 1, 1, 15, 20, 100, 200);
std::cout << mk_ll_pp(d2, m) << "\n";
m.mk_swap(d2, d3, 2);
std::cout << "after swap 2<->3\n";
std::cout << mk_ll_pp(d3, m) << "\n";
}
static void tst10() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m), d2(m), d3(m);
d1 = m.mk_empty(3);
add_triple(m, d1, 5, 100, 10, 20, 3, 10);
add_triple(m, d1, 5, 100, 34, 50, 98, 110);
m.add_bounded_var(d1, d2, 0, 66, 72);
std::cout << mk_ll_pp(d1, m) << "\n";
std::cout << mk_ll_pp(d2, m) << "\n";
m.add_bounded_var(d1, d3, 1, 64, 73);
std::cout << mk_ll_pp(d3, m) << "\n";
}
static void tst11() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m), d2(m), d3(m);
d1 = m.mk_empty(3);
add_triple(m, d1, 5, 100, 10, 20, 3, 10);
add_triple(m, d1, 5, 100, 34, 50, 98, 110);
add_triple(m, d1, 20, 30, 5, 25, 11, 13);
m.mk_filter_distinct(d1, d2, 1, 2);
std::cout << mk_ll_pp(d1, m) << "\n";
std::cout << "filter_distinct(1,2):\n";
std::cout << mk_ll_pp(d2, m) << "\n";
}
static void tst12() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m), d2(m), d3(m);
d1 = m.mk_empty(3);
add_triple(m, d1, 1, 10, 5, 25, 10, 13);
m.mk_filter_distinct(d1, d2, 1, 2);
std::cout << mk_ll_pp(d1, m) << "\n";
std::cout << "filter_distinct(1,2):\n";
std::cout << mk_ll_pp(d2, m) << "\n";
}
static void tst13() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m), d2(m), d3(m);
d1 = m.mk_empty(3);
add_triple(m, d1, 5, 25, 1, 10, 10, 13);
add_triple(m, d1, 5, 25, 20, 30, 10, 13);
m.mk_filter_distinct(d1, d2, 0, 2);
std::cout << mk_ll_pp(d1, m) << "\n";
std::cout << "filter_distinct(0,2):\n";
std::cout << mk_ll_pp(d2, m) << "\n";
}
static void tst14() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m), d2(m), d3(m);
d1 = m.mk_empty(3);
add_triple(m, d1, 5, 25, 1, 10, 10, 13);
add_triple(m, d1, 5, 25, 20, 30, 15, 18);
std::cout << "destructive version\n";
std::cout << mk_ll_pp(d1, m) << "\n";
m.mk_filter_distinct_dupdt(d1, 0, 2);
std::cout << "filter_distinct(0,2):\n";
std::cout << mk_ll_pp(d1, m) << "\n";
}
static void tst15() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m), d2(m), d3(m);
d1 = m.mk_empty(3);
add_triple(m, d1, 5, 5, 1, 10, 5, 5);
std::cout << mk_ll_pp(d1, m) << "\n";
m.mk_filter_distinct(d1, d2, 0, 2);
std::cout << "filter_distinct(0,2):\n";
std::cout << mk_ll_pp(d2, m) << "\n";
}
static void tst16() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m), d2(m), d3(m);
d1 = m.mk_empty(3);
add_triple(m, d1, 5, 15, 1, 10, 50, 500);
std::cout << mk_ll_pp(d1, m) << "\n";
m.mk_filter_disequal(d1, d2, 1, 4);
std::cout << "filter_disequal(var1,4):\n";
std::cout << mk_ll_pp(d2, m) << "\n";
}
static void tst17() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m), d2(m), d3(m);
d1 = m.mk_empty(3);
add_triple(m, d1, 5, 15, 10, 10, 50, 500);
std::cout << mk_ll_pp(d1, m) << "\n";
m.mk_filter_disequal(d1, d2, 1, 10);
std::cout << "filter_disequal(var1,10):\n";
std::cout << mk_ll_pp(d2, m) << "\n";
}
static void tst18() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d1(m), d2(m), d3(m);
d1 = m.mk_empty(2);
add_pair(m, d1, 1112, 1290, 1302, 1302);
std::cout << mk_ll_pp(d1, m) << "\n";
m.mk_swap(d1, d2, 0);
std::cout << "mk_swap 0:\n";
std::cout << mk_ll_pp(d2, m) << "\n";
}
static void tst19() {
std::cout << "--------------------------------\n";
imdd_manager m;
imdd_ref d2(m), d3(m);
d2 = m.mk_empty(3);
add_triple(m, d2, 15, 22, 15, 23, 7, 18);
add_triple(m, d2, 28, 42, 29, 39, 34, 46);
add_triple(m, d2, 28, 42, 29, 39, 100, 200);
add_triple(m, d2, 28, 42, 50, 60, 100, 200);
std::cout << "mk_project_dupdt\n";
std::cout << mk_ll_pp(d2, m) << "\n";
unsigned vars[1] = {1};
m.mk_project_dupdt(d2, 1, vars);
std::cout << "new table\n";
std::cout << mk_ll_pp(d2, m) << "\n";
}
static void init(unsigned* v, unsigned a, unsigned b, unsigned c) {
v[0] = a;
v[1] = b;
v[2] = c;
}
static void tst20() {
std::cout << "--------------------------------\n";
std::cout << "remove_facts\n";
imdd_manager m;
imdd_ref d2(m), d3(m);
d2 = m.mk_empty(3);
add_triple(m, d2, 15, 22, 15, 23, 7, 18);
add_triple(m, d2, 28, 42, 29, 39, 34, 46);
add_triple(m, d2, 28, 42, 29, 39, 100, 200);
add_triple(m, d2, 28, 42, 50, 60, 100, 200);
std::cout << mk_ll_pp(d2, m) << "\n";
//
// [15, 22] -> #1:{
// [15, 23] -> {[7, 18]}*$80}*$80
// [28, 42] -> #2:{
// [29, 39] -> {[34, 46], [100, 200]}*$160
// [50, 60] -> {[100, 200]}*$80}*$80}$80
//
unsigned lowers[3] = {23,1,1};
unsigned uppers[3] = {24,1,1};
m.remove_facts(d2, d3, 3, lowers, uppers);
std::cout << "new table (no change)\n";
std::cout << mk_ll_pp(d3, m) << "\n";
lowers[0] = 22;
m.remove_facts(d2, d3, 3, lowers, uppers);
std::cout << "new table (no change)\n";
std::cout << mk_ll_pp(d3, m) << "\n";
init(lowers, 22, 15, 0);
init(uppers, 24, 23, 0);
m.remove_facts(d2, d3, 3, lowers, uppers);
std::cout << "new table (no change)\n";
std::cout << mk_ll_pp(d3, m) << "\n";
init(lowers, 22, 15, 7);
init(uppers, 24, 23, 18);
m.remove_facts(d2, d3, 3, lowers, uppers);
std::cout << "new table (narrow first interval)\n";
std::cout << mk_ll_pp(d3, m) << "\n";
init(lowers, 22, 15, 8);
init(uppers, 24, 23, 18);
m.remove_facts(d2, d3, 3, lowers, uppers);
std::cout << "new table (split first interval)\n";
std::cout << mk_ll_pp(d3, m) << "\n";
init(lowers, 22, 15, 8);
init(uppers, 24, 23, 17);
m.remove_facts(d2, d3, 3, lowers, uppers);
std::cout << "new table (split first interval)\n";
std::cout << mk_ll_pp(d3, m) << "\n";
init(lowers, 22, 15, 8);
init(uppers, 24, 23, 19);
m.remove_facts(d2, d3, 3, lowers, uppers);
std::cout << "new table (split first interval)\n";
std::cout << mk_ll_pp(d3, m) << "\n";
init(lowers, 30, 20, 120);
init(uppers, 40, 60, 140);
m.remove_facts(d2, d3, 3, lowers, uppers);
std::cout << "new table (split second interval)\n";
std::cout << mk_ll_pp(d3, m) << "\n";
}
static void tst21() {
std::cout << "--------------------------------\n";
std::cout << "remove_facts\n";
imdd_manager m;
imdd_ref d2(m), d3(m);
d2 = m.mk_empty(3);
add_triple(m, d2, 15, 22, 15, 23, 7, 18);
add_triple(m, d2, 28, 42, 29, 39, 34, 46);
add_triple(m, d2, 28, 42, 29, 39, 100, 200);
add_triple(m, d2, 28, 42, 50, 60, 100, 200);
std::cout << mk_ll_pp(d2, m) << "\n";
//
// [15, 22] -> #1:{
// [15, 23] -> {[7, 18]}*$80}*$80
// [28, 42] -> #2:{
// [29, 39] -> {[34, 46], [100, 200]}*$160
// [50, 60] -> {[100, 200]}*$80}*$80}$80
//
unsigned lowers[3] = {23,1,1};
unsigned uppers[3] = {24,1,1};
d3 = d2;
m.remove_facts_dupdt(d2, 3, lowers, uppers);
std::cout << "new table (no change)\n";
std::cout << mk_ll_pp(d2, m) << "\n";
d2 = d3;
lowers[0] = 22;
m.remove_facts_dupdt(d2, 3, lowers, uppers);
std::cout << "new table (no change)\n";
std::cout << mk_ll_pp(d2, m) << "\n";
init(lowers, 22, 15, 0);
init(uppers, 24, 23, 0);
m.remove_facts_dupdt(d2, 3, lowers, uppers);
std::cout << "new table (no change)\n";
std::cout << mk_ll_pp(d2, m) << "\n";
init(lowers, 22, 15, 7);
init(uppers, 24, 23, 18);
m.remove_facts_dupdt(d2, 3, lowers, uppers);
std::cout << "new table (narrow first interval)\n";
std::cout << mk_ll_pp(d2, m) << "\n";
init(lowers, 22, 15, 8);
init(uppers, 24, 23, 18);
m.remove_facts_dupdt(d2, 3, lowers, uppers);
std::cout << "new table (split first interval)\n";
std::cout << mk_ll_pp(d2, m) << "\n";
init(lowers, 22, 15, 8);
init(uppers, 24, 23, 17);
m.remove_facts_dupdt(d2, 3, lowers, uppers);
std::cout << "new table (split first interval)\n";
std::cout << mk_ll_pp(d2, m) << "\n";
init(lowers, 22, 15, 8);
init(uppers, 24, 23, 19);
m.remove_facts_dupdt(d2, 3, lowers, uppers);
std::cout << "new table (split first interval)\n";
std::cout << mk_ll_pp(d2, m) << "\n";
init(lowers, 30, 20, 120);
init(uppers, 40, 60, 140);
m.remove_facts_dupdt(d2, 3, lowers, uppers);
std::cout << "new table (split second interval)\n";
std::cout << mk_ll_pp(d2, m) << "\n";
}
static void tst22() {
std::cout << "--------------------------------\n";
std::cout << "swap\n";
imdd_manager m;
imdd_ref d2(m), d3(m), d4(m);
d2 = m.mk_empty(3);
random_gen rand;
for (unsigned i = 0; i < 130; ++i) {
unsigned a = rand(20);
unsigned b = rand(20);
unsigned c = rand(20);
add_triple(m, d2, a, a, b, b, c, c);
}
std::cout << mk_ll_pp(d2, m) << "\n";
m.mk_swap(d2, d3, 0, true);
std::cout << mk_ll_pp(d3, m) << "\n";
m.mk_swap(d3, d4, 0, true);
std::cout << mk_ll_pp(d4, m) << "\n";
SASSERT(m.is_subset(d2, d4));
SASSERT(m.is_subset(d4, d2));
}
void tst_imdd() {
// enable_trace("imdd_add_bug");
// enable_trace("add_facts_bug");
enable_trace("mk_distinct_imdd");
enable_trace("mk_union_core");
tst22();
tst0();
tst1();
tst2();
tst3();
tst4();
tst5();
tst6();
tst7();
tst19();
tst8();
tst9();
tst10();
tst11();
tst12();
tst13();
tst14();
tst15();
tst16();
tst17();
tst18();
tst20();
tst21();
}
#else
void tst_imdd() {
}
#endif

View file

@ -1,716 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
interval_skip_list.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2010-10-05.
Revision History:
--*/
#include"interval_skip_list.h"
#include"map.h"
#include"vector.h"
typedef sl_manager_base<unsigned> slist_manager;
template class interval_skip_list<unsigned_interval_skip_list_traits<unsigned, default_eq<unsigned>, 4, 4, false, slist_manager> >;
typedef interval_skip_list<unsigned_interval_skip_list_traits<unsigned, default_eq<unsigned>, 4, 4, false, slist_manager> > slist;
typedef u_map<unsigned> u2u_map;
typedef unsigned_isp_set<4, 4, slist_manager> uset;
static void tst1() {
slist_manager m;
slist l(m);
SASSERT(l.check_invariant());
SASSERT(l.empty());
// l.display_physical(std::cout);
l.insert(m, 20, 30, 5);
l.insert(m, 31, 32, 5);
l.insert(m, 18, 19, 5);
// l.display_physical(std::cout);
SASSERT(l.check_invariant());
l.insert(m, 10, 15, 8);
SASSERT(l.check_invariant());
// l.display_physical(std::cout);
l.insert(m, 5, 25, 7);
SASSERT(l.check_invariant());
// l.display_physical(std::cout);
l.insert(m, 23, 27, 5);
// l.display_physical(std::cout);
SASSERT(l.check_invariant());
l.deallocate(m);
}
static void tst2() {
slist_manager(m);
slist l(m);
for(unsigned i = 0; i < 50; i++) {
l.insert(m,i,i,i*10);
}
// l.display_physical(std::cout);
SASSERT(l.check_invariant());
for (unsigned i = 0; i < 25; i++) {
l.insert(m,i*2,i*2+1,i*20+1);
}
// l.display_physical(std::cout);
SASSERT(l.check_invariant());
for (unsigned i = 0; i < 15; i++) {
l.insert(m,i*3,i*3+2,i*30+1);
}
SASSERT(l.check_invariant());
// l.display_physical(std::cout);
// l.compress(4);
// l.display_physical(std::cout);
SASSERT(l.check_invariant());
l.deallocate(m);
}
static bool check_interval(slist & l, unsigned k1, unsigned k2, unsigned val) {
for (unsigned i = k1; i <= k2; i++) {
DEBUG_CODE({
unsigned _val;
SASSERT(l.contains(i, _val) && _val == val);
});
}
return true;
}
static bool check_no_interval(slist & l, unsigned k1, unsigned k2) {
for (unsigned i = k1; i <= k2; i++) {
DEBUG_CODE({
unsigned _val;
SASSERT(!l.contains(i, _val));
});
}
return true;
}
static void tst4() {
slist_manager m;
slist l(m);
l.insert(m, 1, 10, 0);
l.insert(m, 2, 5, 1);
SASSERT(check_no_interval(l,0,0));
SASSERT(check_interval(l,1,1,0));
SASSERT(check_interval(l,2,5,1));
SASSERT(check_interval(l,6,10,0));
SASSERT(check_no_interval(l,11,20));
SASSERT(l.check_invariant());
l.deallocate(m);
}
static void tst5() {
slist_manager m;
slist l(m);
l.insert(m, 1, 5, 0);
l.insert(m, 8, 100, 1);
l.insert(m, 8, 20, 1);
SASSERT(check_no_interval(l,0,0));
SASSERT(check_interval(l,1,5,0));
SASSERT(check_no_interval(l,6,7));
SASSERT(check_interval(l,8,100,1));
SASSERT(check_no_interval(l,101,200));
SASSERT(l.check_invariant());
l.deallocate(m);
}
static void tst6() {
slist_manager m;
slist l(m);
l.insert(m, 1, 5, 0);
l.insert(m, 8, 100, 1);
l.insert(m, 3, 20, 1);
SASSERT(check_no_interval(l,0,0));
SASSERT(check_interval(l,1,2,0));
SASSERT(check_interval(l,3,100,1));
SASSERT(check_no_interval(l,101,200));
SASSERT(l.check_invariant());
l.deallocate(m);
}
static void tst7() {
slist_manager m;
slist l(m);
l.insert(m, 1, 5, 0);
l.insert(m, 8, 100, 1);
l.insert(m, 2, 12, 0);
SASSERT(check_no_interval(l,0,0));
SASSERT(check_interval(l,1,12,0));
SASSERT(check_interval(l,13,100,1));
SASSERT(check_no_interval(l,101,200));
SASSERT(l.check_invariant());
l.deallocate(m);
}
static void tst8() {
slist_manager m;
slist l(m);
for (unsigned i = 0; i < 100; i++) {
l.insert(m, 10*i, 10*i+5, i);
}
SASSERT(!l.empty());
l.insert(m, 0, 10000, 0);
SASSERT(!l.has_more_than_k_entries(1));
// l.display_physical(std::cout);
l.deallocate(m);
}
struct for_each_contains {
slist const & m_other;
for_each_contains(slist const & other):m_other(other) {}
bool operator()(unsigned b, unsigned e, unsigned v) {
for (unsigned i = b; i <= e; i++) {
DEBUG_CODE({
unsigned _v;
SASSERT(m_other.contains(i, _v));
SASSERT(v == _v);
});
}
return true;
}
};
static void random_tsts(unsigned num_ops, unsigned max_key, unsigned max_val, unsigned max_interval_size) {
slist_manager m;
slist m1(m);
u2u_map m2;
for (unsigned i = 0; i < num_ops; i++) {
SASSERT(m1.check_invariant());
TRACE("interval_skip_list", tout << "i: " << i << "\n"; m1.display_physical(tout););
// std::cout << i << std::endl;
int op = rand()%8;
if (op < 3) {
unsigned bg = rand() % max_key;
unsigned sz = rand() % max_interval_size;
if (sz == 0) sz = 1;
unsigned val = rand() % max_val;
m1.insert(m, bg, bg+sz, val);
for (unsigned j = bg; j <= bg+sz; j++) {
DEBUG_CODE({
unsigned _val;
SASSERT(m1.contains(j, _val));
CTRACE("interval_skip_list", val != _val, tout << "i: " << i << ", j: " << j << ", val: " << val << ", _val: " << _val << "\n"; m1.display_physical(tout););
SASSERT(val == _val);
TRACE("interval_skip_list", tout << "[insert]: " << j << " -> " << val << "\n";);
});
m2.insert(j, val);
}
}
else if (op < 4) {
unsigned bg = rand() % max_key;
unsigned sz = rand() % max_interval_size;
if (sz == 0) sz = 1;
m1.erase(m, bg, bg+sz);
for (unsigned i = bg; i <= bg+sz; i++) {
m2.erase(i);
}
}
else if (op < 5) {
slist m1_copy(m);
m1_copy.copy(m, m1);
for_each_contains proc1(m1);
for_each_contains proc2(m1_copy);
m1.for_each(proc2);
m1_copy.for_each(proc1);
// m1.display_physical(std::cout);
// std::cout << "COPY===>\n";
// m1_copy->display_physical(std::cout);
m1_copy.deallocate(m);
}
else if (op < 6) {
m1.compress(m, 3);
}
else {
SASSERT(m1.check_invariant());
u2u_map::iterator it = m2.begin();
u2u_map::iterator end = m2.end();
for (; it != end; ++it) {
DEBUG_CODE({
unsigned _val;
CTRACE("interval_skip_list", !m1.contains(it->m_key, _val),
tout << it->m_key << " -> " << it->m_value << "\n";
m1.display_physical(tout););
SASSERT(m1.contains(it->m_key, _val));
SASSERT(it->m_value == _val);
});
}
}
}
// m1.display_physical(std::cout);
// m1.compress(4);
// m1.display_physical(std::cout);
m1.deallocate(m);
}
static void tst9() {
slist_manager m;
slist l(m);
l.insert(m,10,10,1);
l.insert(m,9,9,0);
l.insert(m,8,8,2);
l.insert(m,7,7,3);
l.insert(m,6,8,3);
SASSERT(!l.has_more_than_k_buckets(1));
SASSERT(check_no_interval(l,0,5));
SASSERT(check_interval(l,6,8,3));
SASSERT(check_interval(l,9,9,0));
SASSERT(check_interval(l,10,10,1));
SASSERT(check_no_interval(l,11,20));
l.deallocate(m);
}
static void tst10() {
slist_manager m;
slist l(m);
l.insert(m,10,10,1);
l.insert(m,13,16,2);
l.insert(m,17,28,3);
l.remove(m,12,19);
SASSERT(l.check_invariant());
SASSERT(check_no_interval(l,0,9));
SASSERT(check_interval(l,10,10,1));
SASSERT(check_no_interval(l,12,19));
SASSERT(check_interval(l,20,28,3));
SASSERT(check_no_interval(l,29,100));
l.remove(m,10,11);
SASSERT(l.check_invariant());
SASSERT(check_no_interval(l,0,19));
SASSERT(check_interval(l,20,28,3));
SASSERT(check_no_interval(l,29,100));
l.remove(m,0,1000);
SASSERT(l.empty());
SASSERT(l.check_invariant());
l.deallocate(m);
}
static void tst11() {
slist_manager m;
slist l(m);
l.insert(m,11,20,1);
l.insert(m,21,30,2);
l.insert(m,31,40,3);
l.insert(m,41,50,4);
l.insert(m,51,60,5);
l.compress(m,4);
SASSERT(check_no_interval(l,0,10));
SASSERT(check_interval(l,11,20,1));
SASSERT(check_interval(l,21,30,2));
SASSERT(check_interval(l,31,40,3));
SASSERT(check_interval(l,41,50,4));
SASSERT(check_interval(l,51,60,5));
SASSERT(check_no_interval(l,61,100));
SASSERT(l.check_invariant());
l.remove(m, 25, 26);
SASSERT(check_no_interval(l,0,10));
SASSERT(check_interval(l,11,20,1));
SASSERT(check_interval(l,21,24,2));
SASSERT(check_no_interval(l,25,26));
SASSERT(check_interval(l,27,30,2));
SASSERT(check_interval(l,31,40,3));
SASSERT(check_interval(l,41,50,4));
SASSERT(check_interval(l,51,60,5));
SASSERT(check_no_interval(l,61,100));
SASSERT(l.check_invariant());
l.remove(m, 44,48);
SASSERT(check_no_interval(l,0,10));
SASSERT(check_interval(l,11,20,1));
SASSERT(check_interval(l,21,24,2));
SASSERT(check_no_interval(l,25,26));
SASSERT(check_interval(l,27,30,2));
SASSERT(check_interval(l,31,40,3));
SASSERT(check_interval(l,41,43,4));
SASSERT(check_no_interval(l,44,48));
SASSERT(check_interval(l,49,50,4));
SASSERT(check_interval(l,51,60,5));
SASSERT(check_no_interval(l,61,100));
SASSERT(l.check_invariant());
l.remove(m, 22,24);
SASSERT(check_no_interval(l,0,10));
SASSERT(check_interval(l,11,20,1));
SASSERT(check_interval(l,21,21,2));
SASSERT(check_no_interval(l,22,26));
SASSERT(check_interval(l,27,30,2));
SASSERT(check_interval(l,31,40,3));
SASSERT(check_interval(l,41,43,4));
SASSERT(check_no_interval(l,44,48));
SASSERT(check_interval(l,49,50,4));
SASSERT(check_interval(l,51,60,5));
SASSERT(check_no_interval(l,61,100));
SASSERT(l.check_invariant());
l.remove(m, 42,49);
SASSERT(check_no_interval(l,0,10));
SASSERT(check_interval(l,11,20,1));
SASSERT(check_interval(l,21,21,2));
SASSERT(check_no_interval(l,22,26));
SASSERT(check_interval(l,27,30,2));
SASSERT(check_interval(l,31,40,3));
SASSERT(check_interval(l,41,41,4));
SASSERT(check_no_interval(l,42,49));
SASSERT(check_interval(l,50,50,4));
SASSERT(check_interval(l,51,60,5));
SASSERT(check_no_interval(l,61,100));
SASSERT(l.check_invariant());
// l.display_physical(std::cout);
l.deallocate(m);
}
static void tst12() {
slist_manager m;
slist l(m);
l.insert(m,10,10,0);
l.insert(m,9,9,0);
SASSERT(l.check_invariant());
l.insert(m,8,9,1);
SASSERT(l.check_invariant());
l.insert(m,7,7,2);
SASSERT(l.check_invariant());
l.insert(m,6,6,3);
SASSERT(l.check_invariant());
l.insert(m,4,5,2);
SASSERT(l.check_invariant());
l.insert(m,3,9,0);
// l.display_physical(std::cout);
l.deallocate(m);
}
static void tst13() {
slist_manager m;
uset s(m);
s.insert(m, 10, 30);
s.insert(m, 32, 40);
s.display(std::cout);
std::cout << ", mem: " << s.memory() << "\n";
s.deallocate(m);
}
struct obj {
unsigned m_val;
unsigned m_ref_count;
void inc_ref() {
m_ref_count++;
}
void dec_ref() {
SASSERT(m_ref_count > 0);
m_ref_count--;
if (m_ref_count == 0)
dealloc(this);
}
obj(unsigned v):m_val(v), m_ref_count(0) {
}
};
std::ostream & operator<<(std::ostream & out, obj * o) {
out << o->m_val << "{" << o->m_ref_count << "}";
return out;
}
struct obj_slist_manager : public sl_manager_base<obj*> {
void inc_ref_eh(obj * v) {
v->inc_ref();
}
void dec_ref_eh(obj * v) {
v->dec_ref();
}
};
struct inc_ref_functor {
unsigned_vector & refs;
inc_ref_functor(unsigned_vector & r):refs(r) {}
bool operator()(unsigned b, unsigned e, obj * val) {
refs[val->m_val]++;
return true;
}
};
template class interval_skip_list<unsigned_interval_skip_list_traits<obj*, default_eq<obj*>, 16, 16, true, obj_slist_manager> >;
typedef interval_skip_list<unsigned_interval_skip_list_traits<obj*, default_eq<obj*>, 16, 16, true, obj_slist_manager> > obj_slist;
void random_tsts_ref(unsigned num_ops, unsigned num_objs, unsigned max_key, unsigned max_interval_size) {
obj_slist_manager m;
obj_slist l(m);
ptr_vector<obj> objs;
unsigned_vector refs;
for (unsigned i = 0; i < num_objs; i++) {
objs.push_back(alloc(obj, i));
objs.back()->inc_ref();
refs.push_back(1);
}
for (unsigned i = 0; i < num_ops; i++) {
SASSERT(l.check_invariant());
TRACE("interval_skip_list", tout << "i: " << i << "\n"; l.display_physical(tout); tout << "\n";);
int op = rand()%5;
if (op < 3) {
unsigned bg = rand() % max_key;
unsigned sz = rand() % max_interval_size;
if (sz == 0) sz = 1;
unsigned val = rand() % num_objs;
TRACE("interval_skip_list", tout << "[inserting]: [" << bg << ", " << (bg+sz) << "] -> " << objs[val] << "\n";);
l.insert(m, bg, bg+sz, objs[val]);
SASSERT(objs[val]->m_ref_count > 1);
}
else if (op < 4) {
unsigned bg = rand() % max_key;
unsigned sz = rand() % max_interval_size;
if (sz == 0) sz = 1;
TRACE("interval_skip_list", tout << "[erasing]: [" << bg << ", " << (bg+sz) << "]\n";);
l.erase(m, bg, bg+sz);
}
else if (op < 5) {
obj_slist l_copy(m);
l_copy.copy(m, l);
TRACE("interval_skip_list", tout << "[copying]\n";);
l_copy.deallocate(m);
TRACE("interval_skip_list", tout << "[deleting copy]\n";);
}
else {
TRACE("interval_skip_list", tout << "[compressing]\n";);
l.compress(m, 3);
}
// check ref-counts
inc_ref_functor proc(refs);
l.for_each(proc);
for (unsigned i = 0; i < num_objs; i++) {
CTRACE("interval_skip_list", refs[i] != objs[i]->m_ref_count,
tout << "i: " << i << ", objs[i]: " << objs[i] << ", refs[i]: " << refs[i] << "\n\n";
l.display_physical(tout););
SASSERT(refs[i] == objs[i]->m_ref_count);
refs[i] = 1;
}
}
l.deallocate(m);
for (unsigned i = 0; i < num_objs; i++) {
SASSERT(objs[i]->m_ref_count == 1);
objs[i]->dec_ref();
}
}
void tst_ref() {
obj_slist_manager m;
obj_slist l(m);
for (unsigned i = 0; i < 30; i++) {
obj * n = alloc(obj, i);
l.insert(m, i*10, i*10+3, n);
// l.display_physical(std::cout);
// std::cout << "memory: " << l.memory() << "\n";
}
l.deallocate(m);
}
void tst_push_back_aux(slist::push_back_proc & push_back, unsigned num_ops, unsigned max_int, unsigned max_sep, unsigned max_val) {
unsigned prev_key;
if (push_back.empty())
prev_key = 0;
else
prev_key = push_back.last_key();
for (unsigned i = 0; i < num_ops; i++) {
unsigned next_key = prev_key + 1;
next_key += (rand() % max_sep);
unsigned sz = rand() % max_int;
if (sz == 0) sz = 1;
unsigned val = rand() % max_val;
push_back(next_key, next_key+sz, val);
SASSERT(!push_back.empty());
prev_key = push_back.last_key();
}
}
void tst_push_back1(unsigned num_ops, unsigned max_int, unsigned max_sep, unsigned max_val) {
slist_manager m;
slist l(m);
slist::push_back_proc push_back(m, l);
tst_push_back_aux(push_back, num_ops, max_int, max_sep, max_val);
// l.display_physical(std::cout);
SASSERT(l.check_invariant());
l.deallocate(m);
}
void tst_push_back2(unsigned num_ops, unsigned max_int, unsigned max_sep, unsigned max_val) {
slist_manager m;
slist l(m);
// insert some random values before creating push_back functor
for (unsigned i = 0; i < num_ops; i++) {
unsigned next_key = rand() % (num_ops * max_int/2);
unsigned sz = rand() % max_int;
if (sz == 0) sz = 1;
unsigned val = rand() % max_val;
l.insert(m, next_key, next_key+sz, val);
}
slist::push_back_proc push_back(m, l);
tst_push_back_aux(push_back, num_ops, max_int, max_sep, max_val);
// l.display_physical(std::cout);
SASSERT(l.check_invariant());
l.deallocate(m);
}
void tst_find_geq1() {
slist_manager m;
slist l(m);
l.insert(m, 10, 20, 4);
l.insert(m, 23, 30, 3);
l.insert(m, 40, 45, 10);
l.insert(m, 50, 66, 1);
l.insert(m, 100, 120, 21);
l.insert(m, 140, 200, 2);
slist::iterator it = l.find_geq(22);
SASSERT(it->begin_key() == 23);
it = l.find_geq(42);
SASSERT(it->begin_key() == 40);
it.move_to(130);
SASSERT(it->begin_key() == 140);
it.move_to(400);
SASSERT(it == l.end());
it = l.find_geq(300);
SASSERT(it == l.end());
it = l.find_geq(9);
SASSERT(it->begin_key() == 10);
it.move_to(105);
SASSERT(it->begin_key() == 100);
it = l.find_geq(15);
SASSERT(it->begin_key() == 10);
it.move_to(31);
SASSERT(it->begin_key() == 40);
it = l.find_geq(22);
SASSERT(it->begin_key() == 23);
it = l.find_geq(124);
SASSERT(it->begin_key() == 140);
it = l.find_geq(102);
SASSERT(it->begin_key() == 100);
// l.display_physical(std::cout);
l.deallocate(m);
}
struct add42 {
unsigned operator()(unsigned v) { return v + 42; }
};
void tst_move_to() {
slist_manager m;
slist l(m);
for (unsigned i = 0; i < 500; i++)
l.insert(m, i*10, i*10 + 5, i);
l.compress(m, 4);
slist::iterator it = l.find_geq(137);
SASSERT(it->begin_key() == 140);
it.move_to(947);
SASSERT(it->begin_key() == 950);
it.move_to(4955);
SASSERT(it->begin_key() == 4950);
it.move_to(4955);
SASSERT(it->begin_key() == 4950);
it.move_to(4956);
SASSERT(it->begin_key() == 4960);
it.move_to(4982);
SASSERT(it->begin_key() == 4980);
it.move_to(4987);
SASSERT(it->begin_key() == 4990);
it.move_to(4990);
SASSERT(it->begin_key() == 4990);
it.move_to(4995);
SASSERT(it->begin_key() == 4990);
it.move_to(4996);
SASSERT(it.at_end());
// l.display_physical(std::cout);
add42 f;
// l.display(std::cout); std::cout << "\n";
l.update_values(m, f);
// l.display(std::cout); std::cout << "\n";
l.deallocate(m);
}
static void tst_ext_iterator() {
slist_manager m;
slist l(m);
for (unsigned i = 0; i < 20; i++)
l.insert(m, i*10, i*10 + 5, i);
l.compress(m, 4);
l.display_physical(std::cout); std::cout << "\n";
slist::ext_iterator it;
slist::ext_iterator end;
SASSERT(end.at_end());
l.move_geq(it, 92);
SASSERT(!it.at_end());
SASSERT(it->begin_key() == 90);
it++;
SASSERT(it->begin_key() == 100);
it.erase(m);
SASSERT(it->begin_key() == 110);
it.erase(m);
SASSERT(it->begin_key() == 120);
it.erase(m);
it.erase(m);
it.erase(m);
it.erase(m);
SASSERT(it->begin_key() == 160);
SASSERT(l.check_invariant());
l.display_physical(std::cout); std::cout << "\n";
l.move_geq(it, 0);
SASSERT(it->begin_key() == 0);
it.erase(m);
SASSERT(it->begin_key() == 10);
it.erase(m);
SASSERT(it->begin_key() == 20);
it.erase(m);
SASSERT(it->begin_key() == 30);
it.erase(m);
SASSERT(it->begin_key() == 40);
it.erase(m);
SASSERT(it->begin_key() == 50);
l.display_physical(std::cout); std::cout << "\n";
l.deallocate(m);
}
void tst_interval_skip_list() {
std::cout << "unsigned map stats:\n";
slist::display_size_info(std::cout);
std::cout << "\nunsigned set stats:\n";
uset::display_size_info(std::cout);
std::cout << "\n";
tst1();
// enable_trace("interval_skip_list_insert_bug");
// enable_trace("interval_skip_list_bug");
// enable_trace("del_entries_upto_bug");
// enable_trace("insert_inside_bug");
// enable_trace("insert_at_bug");
tst2();
tst4();
tst5();
tst6();
tst7();
tst8();
tst9();
tst10();
tst11();
tst12();
tst13();
tst_find_geq1();
tst_move_to();
tst_push_back1(300, 4, 2, 10);
tst_push_back2(300, 4, 2, 10);
random_tsts(1000, 20, 20, 5);
random_tsts_ref(1000, 20, 20, 5);
tst_ref();
tst_ext_iterator();
}

View file

@ -22,7 +22,7 @@
if (do_display_usage) \ if (do_display_usage) \
std::cout << #MODULE << "\n"; \ std::cout << #MODULE << "\n"; \
for (int i = 0; i < argc; i++) \ for (int i = 0; i < argc; i++) \
if (strcmp(argv[i], #MODULE) == 0) { \ if (test_all || strcmp(argv[i], #MODULE) == 0) { \
enable_trace(#MODULE); \ enable_trace(#MODULE); \
enable_debug(#MODULE); \ enable_debug(#MODULE); \
timeit timeit(true, s.c_str()); \ timeit timeit(true, s.c_str()); \
@ -60,6 +60,7 @@ void display_usage() {
std::cout << " /h prints this message.\n"; std::cout << " /h prints this message.\n";
std::cout << " /v:level be verbose, where <level> is the verbosity level.\n"; std::cout << " /v:level be verbose, where <level> is the verbosity level.\n";
std::cout << " /w enable warning messages.\n"; std::cout << " /w enable warning messages.\n";
std::cout << " /a run all unit tests that don't require arguments.\n";
#if defined(Z3DEBUG) || defined(_TRACE) #if defined(Z3DEBUG) || defined(_TRACE)
std::cout << "\nDebugging support:\n"; std::cout << "\nDebugging support:\n";
#endif #endif
@ -71,7 +72,7 @@ void display_usage() {
#endif #endif
} }
void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage) { void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage, bool& test_all) {
int i = 1; int i = 1;
while (i < argc) { while (i < argc) {
char * arg = argv[i]; char * arg = argv[i];
@ -99,6 +100,9 @@ void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage) {
else if (strcmp(opt_name, "w") == 0) { else if (strcmp(opt_name, "w") == 0) {
enable_warning_messages(true); enable_warning_messages(true);
} }
else if (strcmp(opt_name, "a") == 0) {
test_all = true;
}
#ifdef _TRACE #ifdef _TRACE
else if (strcmp(opt_name, "tr") == 0) { else if (strcmp(opt_name, "tr") == 0) {
if (!opt_arg) if (!opt_arg)
@ -122,7 +126,8 @@ void parse_cmd_line_args(int argc, char ** argv, bool& do_display_usage) {
int main(int argc, char ** argv) { int main(int argc, char ** argv) {
memory::initialize(0); memory::initialize(0);
bool do_display_usage = false; bool do_display_usage = false;
parse_cmd_line_args(argc, argv, do_display_usage); bool test_all = false;
parse_cmd_line_args(argc, argv, do_display_usage, test_all);
TST(random); TST(random);
TST(vector); TST(vector);
TST(symbol_table); TST(symbol_table);
@ -151,7 +156,6 @@ int main(int argc, char ** argv) {
TST(simple_parser); TST(simple_parser);
TST(api); TST(api);
TST(old_interval); TST(old_interval);
TST(interval_skip_list);
TST(no_overflow); TST(no_overflow);
TST(memory); TST(memory);
TST(get_implied_equalities); TST(get_implied_equalities);
@ -170,7 +174,6 @@ int main(int argc, char ** argv) {
TST(dl_util); TST(dl_util);
TST(dl_product_relation); TST(dl_product_relation);
TST(dl_relation); TST(dl_relation);
TST(imdd);
TST(parray); TST(parray);
TST(stack); TST(stack);
TST(escaped); TST(escaped);

View file

@ -1299,9 +1299,10 @@ bool mpz_manager<SYNCH>::is_int64(mpz const & a) const {
if (is_small(a)) if (is_small(a))
return true; return true;
#ifndef _MP_GMP #ifndef _MP_GMP
if (!is_uint64(a)) if (!is_uint64(a)) {
return false; return false;
uint64 num = get_uint64(a); }
uint64 num get_uint64(a);
uint64 msb = static_cast<uint64>(1) << 63; uint64 msb = static_cast<uint64>(1) << 63;
uint64 msb_val = msb & num; uint64 msb_val = msb & num;
if (a.m_val >= 0) { if (a.m_val >= 0) {