3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 09:05:31 +00:00
This commit is contained in:
Nikolaj Bjorner 2016-06-03 10:13:27 -07:00
commit 19db0c5f2c
37 changed files with 965 additions and 524 deletions

View file

@ -26,7 +26,8 @@ Revision History:
#include"dl_util.h"
#include"dl_compiler.h"
#include"ast_pp.h"
#include"ast_smt2_pp.h"
// include"ast_smt2_pp.h"
#include"ast_util.h"
namespace datalog {
@ -185,10 +186,11 @@ namespace datalog {
}
}
void compiler::make_add_unbound_column(rule* compiled_rule, unsigned col_idx, func_decl* pred, reg_idx src, const relation_sort s, reg_idx & result,
void compiler::make_add_unbound_column(rule* compiled_rule, unsigned col_idx, func_decl* pred, reg_idx src, const relation_sort& s, reg_idx & result,
bool & dealloc, instruction_block & acc) {
TRACE("dl", tout << "Adding unbound column " << mk_pp(pred, m_context.get_manager()) << "\n";);
TRACE("dl", tout << "Adding unbound column " << mk_pp(pred, m_context.get_manager())
<< " " << m_context.get_rel_context()->get_rmanager().to_nice_string(s) << "\n";);
IF_VERBOSE(3, {
expr_ref e(m_context.get_manager());
m_context.get_rule_manager().to_formula(*compiled_rule, e);
@ -328,13 +330,15 @@ namespace datalog {
continue;
}
unsigned bound_column_index;
if(acis[i].kind!=ACK_UNBOUND_VAR || !handled_unbound.find(acis[i].var_index,bound_column_index)) {
if(acis[i].kind != ACK_UNBOUND_VAR || !handled_unbound.find(acis[i].var_index,bound_column_index)) {
bound_column_index=curr_sig->size();
if(acis[i].kind==ACK_CONSTANT) {
make_add_constant_column(head_pred, curr, acis[i].domain, acis[i].constant, curr, dealloc, acc);
}
else {
SASSERT(acis[i].kind==ACK_UNBOUND_VAR);
TRACE("dl", tout << head_pred->get_name() << " index: " << i
<< " " << m_context.get_rel_context()->get_rmanager().to_nice_string(acis[i].domain) << "\n";);
make_add_unbound_column(compiled_rule, i, head_pred, curr, acis[i].domain, curr, dealloc, acc);
handled_unbound.insert(acis[i].var_index,bound_column_index);
}
@ -598,14 +602,15 @@ namespace datalog {
// add unbounded columns for interpreted filter
unsigned ut_len = r->get_uninterpreted_tail_size();
unsigned ft_len = r->get_tail_size(); // full tail
ptr_vector<expr> tail;
expr_ref_vector tail(m);
for (unsigned tail_index = ut_len; tail_index < ft_len; ++tail_index) {
tail.push_back(r->get_tail(tail_index));
}
expr_ref_vector binding(m);
if (!tail.empty()) {
app_ref filter_cond(tail.size() == 1 ? to_app(tail.back()) : m.mk_and(tail.size(), tail.c_ptr()), m);
expr_ref filter_cond = mk_and(tail);
m_free_vars.reset();
m_free_vars(filter_cond);
// create binding
binding.resize(m_free_vars.size()+1);
@ -620,6 +625,7 @@ namespace datalog {
} else {
// we have an unbound variable, so we add an unbound column for it
relation_sort unbound_sort = m_free_vars[v];
TRACE("dl", tout << "unbound: " << v << "\n" << filter_cond << " " << mk_pp(unbound_sort, m) << "\n";);
make_add_unbound_column(r, 0, head_pred, filtered_res, unbound_sort, filtered_res, dealloc, acc);
src_col = single_res_expr.size();

View file

@ -180,7 +180,7 @@ namespace datalog {
void make_add_constant_column(func_decl* pred, reg_idx src, const relation_sort s, const relation_element val,
reg_idx & result, bool & dealloc, instruction_block & acc);
void make_add_unbound_column(rule* compiled_rule, unsigned col_idx, func_decl* pred, reg_idx src, const relation_sort s, reg_idx & result,
void make_add_unbound_column(rule* compiled_rule, unsigned col_idx, func_decl* pred, reg_idx src, const relation_sort& s, reg_idx & result,
bool & dealloc, instruction_block & acc);
void make_full_relation(func_decl* pred, const relation_signature & sig, reg_idx & result,
instruction_block & acc);

View file

@ -1052,7 +1052,8 @@ namespace datalog {
}
virtual void display_head_impl(execution_context const& ctx, std::ostream & out) const {
out << "mk_total into " << m_tgt << " sort:"
<< ctx.get_rel_context().get_rmanager().to_nice_string(m_sig);
<< ctx.get_rel_context().get_rmanager().to_nice_string(m_sig)
<< " " << m_pred->get_name();
}
virtual void make_annotations(execution_context & ctx) {
std::string s;

View file

@ -102,7 +102,7 @@ namespace datalog {
in the pair, and so it should be removed.
*/
bool remove_rule(rule * r, unsigned original_length) {
TRUSTME( remove_from_vector(m_rules, r) );
VERIFY( remove_from_vector(m_rules, r) );
if (original_length>2) {
SASSERT(m_consumers>0);
m_consumers--;
@ -114,22 +114,23 @@ namespace datalog {
pair_info & operator=(const pair_info &); //to avoid the implicit one
};
typedef std::pair<app*, app*> app_pair;
typedef map<app_pair, pair_info *,
pair_hash<obj_ptr_hash<app>, obj_ptr_hash<app> >, default_eq<app_pair> > cost_map;
typedef pair_hash<obj_ptr_hash<app>, obj_ptr_hash<app> > app_pair_hash;
typedef map<app_pair, pair_info *, app_pair_hash, default_eq<app_pair> > cost_map;
typedef map<rule *, ptr_vector<app>, ptr_hash<rule>, ptr_eq<rule> > rule_pred_map;
typedef ptr_hashtable<rule, rule_hash_proc, default_eq<rule *> > rule_hashtable;
context & m_context;
ast_manager & m;
rule_manager & rm;
var_subst & m_var_subst;
rule_set & m_rs_aux_copy; //reference to a rule_set that will allow to ask for stratum levels
cost_map m_costs;
ptr_vector<app> m_interpreted;
rule_pred_map m_rules_content;
rule_ref_vector m_introduced_rules;
ptr_hashtable<rule, ptr_hash<rule>, ptr_eq<rule> > m_modified_rules;
context & m_context;
ast_manager & m;
rule_manager & rm;
var_subst & m_var_subst;
rule_set & m_rs_aux_copy; //reference to a rule_set that will allow to ask for stratum levels
cost_map m_costs;
ptr_vector<app> m_interpreted;
rule_pred_map m_rules_content;
rule_ref_vector m_introduced_rules;
bool m_modified_rules;
ast_ref_vector m_pinned;
mutable ptr_vector<sort> m_vars;
@ -140,6 +141,7 @@ namespace datalog {
m_var_subst(ctx.get_var_subst()),
m_rs_aux_copy(rs_aux_copy),
m_introduced_rules(ctx.get_rule_manager()),
m_modified_rules(false),
m_pinned(ctx.get_manager())
{
}
@ -248,20 +250,13 @@ namespace datalog {
m_var_subst(t2, norm_subst.size(), norm_subst.c_ptr(), t2n_ref);
app * t1n = to_app(t1n_ref);
app * t2n = to_app(t2n_ref);
if (t1n>t2n) {
if (t1n->get_id() > t2n->get_id()) {
std::swap(t1n, t2n);
}
m_pinned.push_back(t1n);
m_pinned.push_back(t2n);
/*
IF_VERBOSE(0,
print_renaming(norm_subst, verbose_stream());
display_predicate(m_context, t1, verbose_stream());
display_predicate(m_context, t2, verbose_stream());
display_predicate(m_context, t1n, verbose_stream());
display_predicate(m_context, t2n, verbose_stream()););
*/
return app_pair(t1n, t2n);
}
@ -392,7 +387,7 @@ namespace datalog {
func_decl* parent_head = one_parent->get_decl();
const char * one_parent_name = parent_head->get_name().bare_str();
std::string parent_name;
if (inf.m_rules.size()>1) {
if (inf.m_rules.size() > 1) {
parent_name = one_parent_name + std::string("_and_") + to_string(inf.m_rules.size()-1);
}
else {
@ -417,15 +412,16 @@ namespace datalog {
//here we copy the inf.m_rules vector because inf.m_rules will get changed
//in the iteration. Also we use hashtable instead of vector because we do
//not want to process one rule twice.
typedef ptr_hashtable<rule, ptr_hash<rule>, default_eq<rule *> > rule_hashtable;
rule_hashtable relevant_rules;
insert_into_set(relevant_rules, inf.m_rules);
rule_hashtable::iterator rit = relevant_rules.begin();
rule_hashtable::iterator rend = relevant_rules.end();
for(; rit!=rend; ++rit) {
apply_binary_rule(*rit, pair_key, head);
}
rule_hashtable processed_rules;
rule_vector rules(inf.m_rules);
for (unsigned i = 0; i < rules.size(); ++i) {
rule* r = rules[i];
if (!processed_rules.contains(r)) {
apply_binary_rule(r, pair_key, head);
processed_rules.insert(r);
}
}
// SASSERT(!m_costs.contains(pair_key));
}
@ -553,7 +549,7 @@ namespace datalog {
}
SASSERT(!removed_tails.empty());
SASSERT(!added_tails.empty());
m_modified_rules.insert(r);
m_modified_rules = true;
replace_edges(r, removed_tails, added_tails, rule_content);
}
@ -705,7 +701,7 @@ namespace datalog {
join_pair(selected);
}
if (m_modified_rules.empty()) {
if (!m_modified_rules) {
return 0;
}
rule_set * result = alloc(rule_set, m_context);

View file

@ -488,7 +488,9 @@ namespace datalog {
}
std::string relation_manager::to_nice_string(const relation_sort & s) const {
return std::string(s->get_name().bare_str());
std::ostringstream strm;
strm << mk_pp(s, get_context().get_manager());
return strm.str();
}
std::string relation_manager::to_nice_string(const relation_signature & s) const {

View file

@ -97,7 +97,7 @@ namespace datalog {
TRACE("dl", tout << mk_pp(body, m) << "\n";);
// 2. replace bound variables by constants.
expr_ref_vector consts(m), bound(m), free(m);
expr_ref_vector consts(m), bound(m), _free(m);
svector<symbol> names;
ptr_vector<sort> bound_sorts;
for (unsigned i = 0; i < sorts.size(); ++i) {
@ -110,7 +110,7 @@ namespace datalog {
bound_sorts.push_back(s);
}
else {
free.push_back(consts.back());
_free.push_back(consts.back());
}
}
rep(body);
@ -123,8 +123,8 @@ namespace datalog {
TRACE("dl", tout << mk_pp(body, m) << "\n";);
// 4. replace remaining constants by variables.
for (unsigned i = 0; i < free.size(); ++i) {
rep.insert(free[i].get(), m.mk_var(i, m.get_sort(free[i].get())));
for (unsigned i = 0; i < _free.size(); ++i) {
rep.insert(_free[i].get(), m.mk_var(i, m.get_sort(_free[i].get())));
}
rep(body);
g->set_else(body);

View file

@ -43,16 +43,16 @@ namespace datalog {
bool mk_unbound_compressor::is_unbound_argument(rule * r, unsigned head_index) {
app * head = r->get_head();
expr * head_arg = head->get_arg(head_index);
if (!is_var(head_arg)) {
return false;
}
unsigned var_idx = to_var(head_arg)->get_idx();
return rm.collect_tail_vars(r).contains(var_idx);
unsigned var_idx;
return
is_var(head_arg, var_idx) &&
rm.collect_tail_vars(r).contains(var_idx);
}
void mk_unbound_compressor::add_task(func_decl * pred, unsigned arg_index) {
c_info ci = c_info(pred, arg_index);
SASSERT(pred->get_arity() > 0);
c_info ci(pred, arg_index);
if (m_map.contains(ci)) {
return; //this task was already added
}
@ -74,9 +74,11 @@ namespace datalog {
func_decl * cpred = m_context.mk_fresh_head_predicate(parent_name, symbol(name_suffix.str().c_str()),
arity, domain.c_ptr(), pred);
m_pinned.push_back(cpred);
m_pinned.push_back(pred);
m_todo.push_back(ci);
m_map.insert(ci, cpred);
TRACE("dl", tout << "inserting: " << pred->get_name() << " " << arg_index << " for " << cpred->get_name() << "\n";);
}
void mk_unbound_compressor::detect_tasks(rule_set const& source, unsigned rule_index) {
@ -95,28 +97,26 @@ namespace datalog {
rm.get_counter().reset();
rm.get_counter().count_vars(head, 1);
for (unsigned i=0; i<n; i++) {
for (unsigned i = 0; i < n; i++) {
expr * arg = head->get_arg(i);
if (!is_var(arg)) {
continue;
}
unsigned var_idx = to_var(arg)->get_idx();
if (!tail_vars.contains(var_idx)) {
//unbound
unsigned occurence_cnt = rm.get_counter().get(var_idx);
SASSERT(occurence_cnt>0);
if (occurence_cnt == 1) {
TRACE("dl", r->display(m_context, tout << "Compress: "););
add_task(head_pred, i);
return; //we compress out the unbound arguments one by one
}
unsigned var_idx;
if (is_var(arg, var_idx) &&
!tail_vars.contains(var_idx) &&
(1 == rm.get_counter().get(var_idx))) {
TRACE("dl", r->display(m_context, tout << "Compress: "););
add_task(head_pred, i);
break;
//we compress out the unbound arguments one by one
}
}
}
void mk_unbound_compressor::try_compress(rule_set const& source, unsigned rule_index) {
start:
//
// l_undef if nothing to compress.
// l_true if compressed.
// l_false if removed.
//
lbool mk_unbound_compressor::try_compress(rule_set const& source, unsigned rule_index) {
rule * r = m_rules.get(rule_index);
var_idx_set& tail_vars = rm.collect_tail_vars(r);
@ -130,30 +130,25 @@ namespace datalog {
unsigned arg_index;
for (arg_index = 0; arg_index < head_arity; arg_index++) {
expr * arg = head->get_arg(arg_index);
if (!is_var(arg)) {
continue;
}
unsigned var_idx = to_var(arg)->get_idx();
if (!tail_vars.contains(var_idx)) {
//unbound
unsigned occurence_cnt = rm.get_counter().get(var_idx);
SASSERT(occurence_cnt>0);
if ( occurence_cnt==1 && m_in_progress.contains(c_info(head_pred, arg_index)) ) {
//we have found what to compress
break;
}
unsigned var_idx;
if (is_var(arg, var_idx) &&
!tail_vars.contains(var_idx) &&
(rm.get_counter().get(var_idx) == 1) &&
m_in_progress.contains(c_info(head_pred, arg_index))) {
break;
}
}
if (arg_index == head_arity) {
//we didn't find anything to compress
return;
return l_undef;
}
SASSERT(arg_index<head_arity);
c_info ci(head_pred, arg_index);
func_decl * cpred;
TRUSTME( m_map.find(ci, cpred) );
SASSERT(arg_index < head_arity);
SASSERT(m_in_progress.contains(ci));
func_decl * cpred = m_map.find(ci);
ptr_vector<expr> cargs;
for (unsigned i=0; i<head_arity; i++) {
for (unsigned i=0; i < head_arity; i++) {
if (i != arg_index) {
cargs.push_back(head->get_arg(i));
}
@ -161,41 +156,48 @@ namespace datalog {
app_ref chead(m.mk_app(cpred, head_arity-1, cargs.c_ptr()), m);
m_modified = true;
if (r->get_tail_size()==0 && m_context.get_rule_manager().is_fact(chead)) {
m_non_empty_rels.insert(cpred);
m_context.add_fact(chead);
//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_decl());
m_rules.set(rule_index, m_rules.get(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
if (rule_index<m_rules.size()) {
goto start;
unsigned new_size = m_rules.size() - 1;
rule* last_rule = m_rules.get(new_size);
TRACE("dl", tout << "remove\n"; r->display(m_context, tout);
tout << "shift\n"; last_rule->display(m_context, tout););
if (rule_index < new_size) {
m_rules.set(rule_index, last_rule);
}
m_rules.shrink(new_size);
return l_false;
}
else {
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);
m_head_occurrence_ctr.dec(m_rules.get(rule_index)->get_decl());
TRACE("dl", tout << "remove\n"; r->display(m_context, tout);
tout << "set\n"; new_rule->display(m_context, tout););
m_rules.set(rule_index, new_rule);
m_head_occurrence_ctr.inc(m_rules.get(rule_index)->get_decl());
detect_tasks(source, rule_index);
return l_true;
}
m_modified = true;
}
void mk_unbound_compressor::mk_decompression_rule(rule * r, unsigned tail_index, unsigned arg_index,
rule_ref& res)
{
rule_ref mk_unbound_compressor::mk_decompression_rule(rule * r, unsigned tail_index, unsigned arg_index) {
rule_ref res(m_context.get_rule_manager());
app * orig_dtail = r->get_tail(tail_index); //dtail ~ decompressed tail
c_info ci(orig_dtail->get_decl(), arg_index);
func_decl * dtail_pred;
TRUSTME( m_map.find(ci, dtail_pred) );
TRACE("dl", tout << "retrieving: " << ci.first->get_name() << " " << ci.second << "\n";);
func_decl * dtail_pred = m_map.find(ci);
ptr_vector<expr> dtail_args;
unsigned orig_dtail_arity = orig_dtail->get_num_args();
for (unsigned i=0;i<orig_dtail_arity;i++) {
for (unsigned i = 0; i < orig_dtail_arity; i++) {
if (i != arg_index) {
dtail_args.push_back(orig_dtail->get_arg(i));
}
@ -206,9 +208,9 @@ namespace datalog {
svector<bool> tails_negated;
app_ref_vector tails(m);
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));
if (i==tail_index && !r->is_neg_tail(i)) {
if (i == tail_index && !r->is_neg_tail(i)) {
tails.push_back(dtail);
}
else {
@ -226,97 +228,108 @@ namespace datalog {
res = m_context.get_rule_manager().mk( r->get_head(), tails.size(), tails.c_ptr(), tails_negated.c_ptr());
res->set_accounting_parent_object(m_context, r);
m_context.get_rule_manager().fix_unbound_vars(res, true);
return res;
}
//TODO: avoid rule duplicity
//If two predicates are compressed in a rule, applying decompression
//to the results can cause a rule being added multiple times:
//P:- R(x,y), S(x,y)
//is decompressed into rules
//P:- R1(x), S(x,y)
//P:- R(x,y), S1(x)
//and each of these rules is again decompressed giving the same rule
//P:- R1(x), S1(x)
//P:- R1(x), S1(x)
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());
mk_decompression_rule(r, tail_index, arg_index, new_rule);
rule_ref new_rule = mk_decompression_rule(r, tail_index, arg_index);
unsigned new_rule_index = m_rules.size();
m_rules.push_back(new_rule);
TRACE("dl", r->display(m_context, tout); new_rule->display(m_context, tout); );
m_context.get_rule_manager().mk_rule_rewrite_proof(*r, *new_rule.get());
m_head_occurrence_ctr.inc(new_rule->get_decl());
detect_tasks(source, new_rule_index);
m_modified = true;
//TODO: avoid rule duplicity
//If two predicates are compressed in a rule, applying decompression
//to the results can cause a rule being added multiple times:
//P:- R(x,y), S(x,y)
//is decompressed into rules
//P:- R1(x), S(x,y)
//P:- R(x,y), S1(x)
//and each of these rules is again decompressed giving the same rule
//P:- R1(x), S1(x)
//P:- R1(x), S1(x)
}
void mk_unbound_compressor::replace_by_decompression_rule(rule_set const& source, 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_ref new_rule(m_context.get_rule_manager());
mk_decompression_rule(r, tail_index, arg_index, new_rule);
rule_ref new_rule = mk_decompression_rule(r, tail_index, arg_index);
TRACE("dl", tout << "remove\n"; r->display(m_context, tout); tout << "set\n"; new_rule->display(m_context, tout););
m_rules.set(rule_index, new_rule);
//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(source, rule_index);
m_modified = true;
}
void mk_unbound_compressor::add_in_progress_indices(unsigned_vector& arg_indices, app* p) {
arg_indices.reset();
for (unsigned i = 0; i < p->get_num_args(); ++i) {
if (m_in_progress.contains(c_info(p->get_decl(), i))) {
SASSERT(m_map.contains(c_info(p->get_decl(), i)));
arg_indices.push_back(i);
}
}
}
bool mk_unbound_compressor::decompress_rule(rule_set const& source, rule* r, unsigned_vector const& arg_indices, unsigned rule_index, unsigned tail_index) {
app * t = r->get_tail(tail_index);
func_decl * t_pred = t->get_decl();
bool is_negated_predicate = r->is_neg_tail(tail_index);
bool replace_original_rule = false;
for (unsigned i = 0; i < arg_indices.size(); ++i) {
unsigned arg_index = arg_indices[i];
SASSERT(m_in_progress.contains(c_info(t_pred, arg_index)));
SASSERT(m_map.contains(c_info(t_pred, arg_index)));
bool can_remove_orig_rule =
arg_indices.empty() &&
!m_non_empty_rels.contains(t_pred) &&
m_head_occurrence_ctr.get(t_pred) == 0;
if (can_remove_orig_rule || is_negated_predicate) {
replace_original_rule = true;
replace_by_decompression_rule(source, rule_index, tail_index, arg_index);
// NB. arg_indices becomes stale after original rule is replaced.
if (is_negated_predicate && !can_remove_orig_rule) {
break;
}
}
else {
add_decompression_rule(source, r, tail_index, arg_index);
}
}
return replace_original_rule;
}
void mk_unbound_compressor::add_decompression_rules(rule_set const& source, unsigned rule_index) {
unsigned_vector compressed_tail_pred_arg_indexes;
//this value is updated inside the loop if replace_by_decompression_rule is called
unsigned_vector arg_indices;
// this value is updated inside the loop if replace_by_decompression_rule is called
rule_ref r(m_rules.get(rule_index), m_context.get_rule_manager());
unsigned utail_len = r->get_uninterpreted_tail_size();
unsigned tail_index=0;
while (tail_index<utail_len) {
unsigned tail_index = 0;
while (tail_index < utail_len) {
app * t = r->get_tail(tail_index);
func_decl * t_pred = t->get_decl();
unsigned t_arity = t_pred->get_arity();
bool is_negated_predicate = r->is_neg_tail(tail_index);
compressed_tail_pred_arg_indexes.reset();
for (unsigned arg_index=0; arg_index<t_arity; arg_index++) {
c_info ci(t_pred, arg_index);
if (m_in_progress.contains(ci)) {
compressed_tail_pred_arg_indexes.push_back(arg_index);
}
}
bool orig_rule_replaced = false;
while (!compressed_tail_pred_arg_indexes.empty()) {
unsigned arg_index = compressed_tail_pred_arg_indexes.back();
compressed_tail_pred_arg_indexes.pop_back();
bool can_remove_orig_rule =
compressed_tail_pred_arg_indexes.empty() &&
!m_non_empty_rels.contains(t_pred) &&
m_head_occurrence_ctr.get(t_pred)==0;
add_in_progress_indices(arg_indices, t);
if (can_remove_orig_rule || is_negated_predicate) {
replace_by_decompression_rule(source, rule_index, tail_index, arg_index);
orig_rule_replaced = true;
}
else {
add_decompression_rule(source, r, tail_index, arg_index);
}
}
if (orig_rule_replaced) {
//update r with the new rule
bool replace_original_rule = decompress_rule(source, r, arg_indices, rule_index, tail_index);
if (replace_original_rule) {
// update r with the new rule
rule * new_rule = m_rules.get(rule_index);
SASSERT(new_rule->get_uninterpreted_tail_size() >= utail_len);
//here we check that the rule replacement didn't affect other uninterpreted literals
//in the tail (aside of variable renaming)
SASSERT(tail_index==0 ||
new_rule->get_tail(tail_index-1)->get_decl()==r->get_tail(tail_index-1)->get_decl());
// here we check that the rule replacement didn't affect other uninterpreted literals
// in the tail (aside of variable renaming)
SASSERT(tail_index==0 || new_rule->get_decl(tail_index-1) == r->get_decl(tail_index-1));
r = new_rule;
@ -334,19 +347,20 @@ namespace datalog {
// TODO mc
m_modified = false;
SASSERT(m_rules.empty());
rel_context_base* rel = m_context.get_rel_context();
if (rel) {
rel->collect_non_empty_predicates(m_non_empty_rels);
}
unsigned init_rule_cnt = source.get_num_rules();
SASSERT(m_rules.empty());
for (unsigned i=0; i<init_rule_cnt; i++) {
for (unsigned i = 0; i < init_rule_cnt; i++) {
rule * r = source.get_rule(i);
m_rules.push_back(r);
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(source, i);
}
@ -356,13 +370,16 @@ namespace datalog {
m_in_progress.insert(m_todo.back());
m_todo.pop_back();
}
unsigned rule_index = 0;
while (rule_index<m_rules.size()) {
try_compress(source, rule_index); //m_rules.size() can change here
if (rule_index<m_rules.size()) {
add_decompression_rules(source, rule_index); //m_rules.size() can change here
for (unsigned rule_index = 0; rule_index < m_rules.size(); ) {
switch (try_compress(source, rule_index)) {
case l_true:
case l_undef:
add_decompression_rules(source, rule_index); //m_rules.size() can be increased here
++rule_index;
break;
case l_false:
break;
}
rule_index++;
}
}

View file

@ -74,11 +74,14 @@ namespace datalog {
void detect_tasks(rule_set const& source, unsigned rule_index);
void add_task(func_decl * pred, unsigned arg_index);
void try_compress(rule_set const& source, unsigned rule_index);
lbool try_compress(rule_set const& source, 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);
rule_ref mk_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(rule_set const& source, unsigned rule_index, unsigned tail_index, unsigned arg_index);
void add_in_progress_indices(unsigned_vector& arg_indices, app* p);
bool decompress_rule(rule_set const& source, rule* r, unsigned_vector const& cmpressed_tail_pred_arg_indexes, unsigned rule_index, unsigned tail_index);
void reset();
public:
mk_unbound_compressor(context & ctx);