3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-22 16:45:31 +00:00

compiler optimization and fixes to unit tests

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2013-04-11 13:44:23 -07:00
commit 18ea547cea
85 changed files with 1156 additions and 11585 deletions

View file

@ -636,9 +636,13 @@ namespace datalog {
app* dl_decl_util::mk_numeral(uint64 value, 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) };
return m.mk_const(m.mk_func_decl(m_fid, OP_DL_CONSTANT, 2, params, 0, (sort*const*)0));
}
}
if (m_arith.is_int(s) || m_arith.is_real(s)) {
return m_arith.mk_numeral(rational(value, rational::ui64()), s);
}

View file

@ -568,7 +568,7 @@ public:
ctx.regular_stream() << "(:authors \"Leonardo de Moura and Nikolaj Bjorner\")" << std::endl;
}
else if (opt == m_version) {
ctx.regular_stream() << "(:version \"" << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "\")" << std::endl;
ctx.regular_stream() << "(:version \"" << Z3_MAJOR_VERSION << "." << Z3_MINOR_VERSION << "." << Z3_BUILD_NUMBER << "\")" << std::endl;
}
else if (opt == m_status) {
ctx.regular_stream() << "(:status " << ctx.get_status() << ")" << std::endl;

View file

@ -37,6 +37,8 @@ namespace datalog {
ast_manager & get_ast_manager_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
void leak_guard_check(const symbol & s);
#endif

View file

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

View file

@ -445,40 +445,8 @@ public:
ctx.insert(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) {
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_declare_rel_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) {

View file

@ -708,6 +708,7 @@ namespace datalog {
//update the head relation
make_union(new_head_reg, head_reg, delta_reg, use_widening, acc);
make_dealloc_non_void(new_head_reg, acc);
}
finish:
@ -761,7 +762,7 @@ namespace datalog {
typedef svector<tail_delta_info> tail_delta_infos;
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;
tail_delta_infos tail_deltas;
@ -798,6 +799,8 @@ namespace datalog {
typedef rule_dependencies::item_set item_set; //set of T
rule_dependencies & m_deps;
rule_set const& m_rules;
context& m_context;
item_set & m_removed;
svector<T> m_stack;
ast_mark m_stack_content;
@ -820,7 +823,7 @@ namespace datalog {
T d = *it;
if(m_stack_content.is_marked(d)) {
//TODO: find the best vertex to remove in the cycle
m_removed.insert(v);
remove_from_stack();
break;
}
traverse(d);
@ -830,9 +833,36 @@ namespace datalog {
m_stack.pop_back();
m_stack_content.mark(v, false);
}
void remove_from_stack() {
for (unsigned i = 0; i < m_stack.size(); ++i) {
func_decl* p = m_stack[i];
rule_vector const& rules = m_rules.get_predicate_rules(p);
unsigned stratum = m_rules.get_predicate_strat(p);
if (m_context.has_facts(p)) {
m_removed.insert(p);
return;
}
for (unsigned j = 0; j < rules.size(); ++j) {
rule const& r = *rules[j];
bool ok = true;
for (unsigned k = 0; ok && k < r.get_uninterpreted_tail_size(); ++k) {
ok &= m_rules.get_predicate_strat(r.get_decl(k)) < stratum;
}
if (ok) {
m_removed.insert(p);
return;
}
}
}
// nothing was found.
m_removed.insert(m_stack.back());
}
public:
cycle_breaker(rule_dependencies & deps, item_set & removed)
: m_deps(deps), m_removed(removed) { SASSERT(removed.empty()); }
cycle_breaker(rule_dependencies & deps, rule_set const& rules, context& ctx, item_set & removed)
: m_deps(deps), m_rules(rules), m_context(ctx), m_removed(removed) { SASSERT(removed.empty()); }
void operator()() {
rule_dependencies::iterator it = m_deps.begin();
@ -854,7 +884,7 @@ namespace datalog {
rule_dependencies deps(m_rule_set.get_dependencies());
deps.restrict(preds);
cycle_breaker(deps, global_deltas)();
cycle_breaker(deps, m_rule_set, m_context, global_deltas)();
VERIFY( deps.sort_deps(ordered_preds) );
//the predicates that were removed to get acyclic induced subgraph are put last
@ -885,13 +915,47 @@ namespace datalog {
rule_vector::const_iterator rend = pred_rules.end();
for(; rit!=rend; ++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);
}
}
}
void compiler::compile_preds_init(const func_decl_vector & head_preds, const func_decl_set & widened_preds,
const pred2idx * input_deltas, const pred2idx & output_deltas, instruction_block & acc) {
func_decl_vector::const_iterator hpit = head_preds.begin();
func_decl_vector::const_iterator hpend = head_preds.end();
reg_idx void_reg = execution_context::void_register;
for(; hpit!=hpend; ++hpit) {
func_decl * head_pred = *hpit;
const rule_vector & pred_rules = m_rule_set.get_predicate_rules(head_pred);
rule_vector::const_iterator rit = pred_rules.begin();
rule_vector::const_iterator rend = pred_rules.end();
unsigned stratum = m_rule_set.get_predicate_strat(head_pred);
for(; rit != rend; ++rit) {
rule * r = *rit;
SASSERT(head_pred==r->get_decl());
for (unsigned i = 0; i < r->get_uninterpreted_tail_size(); ++i) {
unsigned stratum1 = m_rule_set.get_predicate_strat(r->get_decl(i));
if (stratum1 >= stratum) {
goto next_loop;
}
}
compile_rule_evaluation(r, input_deltas, void_reg, false, acc);
next_loop:
;
}
reg_idx d_head_reg;
if (output_deltas.find(head_pred, d_head_reg)) {
acc.push_back(instruction::mk_clone(m_pred_regs.find(head_pred), d_head_reg));
}
}
}
void compiler::make_inloop_delta_transition(const pred2idx & global_head_deltas,
const pred2idx & global_tail_deltas, const pred2idx & local_deltas, instruction_block & acc) {
//move global head deltas into tail ones
@ -942,7 +1006,7 @@ namespace datalog {
const pred2idx * input_deltas, const pred2idx & output_deltas,
bool add_saturation_marks, instruction_block & acc) {
if(!output_deltas.empty()) {
if (!output_deltas.empty()) {
func_decl_set::iterator hpit = head_preds.begin();
func_decl_set::iterator hpend = head_preds.end();
for(; hpit!=hpend; ++hpit) {
@ -979,7 +1043,8 @@ namespace datalog {
func_decl_set empty_func_decl_set;
//generate code for the initial run
compile_preds(preds_vector, empty_func_decl_set, input_deltas, d_global_src, acc);
// compile_preds(preds_vector, empty_func_decl_set, input_deltas, d_global_src, acc);
compile_preds_init(preds_vector, empty_func_decl_set, input_deltas, d_global_src, acc);
if (compile_with_widening()) {
compile_loop(preds_vector, global_deltas, d_global_tgt, d_global_src, d_local, acc);
@ -1040,7 +1105,7 @@ namespace datalog {
rule_vector::const_iterator end = rules.end();
for (; it != end; ++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);
}
@ -1113,7 +1178,7 @@ namespace datalog {
//load predicate data
for(unsigned i=0;i<rule_cnt;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();
for(unsigned j=0;j<rule_len;j++) {

View file

@ -209,6 +209,12 @@ namespace datalog {
void compile_preds(const func_decl_vector & head_preds, const func_decl_set & widened_preds,
const pred2idx * input_deltas, const pred2idx & output_deltas, instruction_block & acc);
/**
\brief Generate code to evaluate predicates in a stratum based on their non-recursive rules.
*/
void compile_preds_init(const func_decl_vector & head_preds, const func_decl_set & widened_preds,
const pred2idx * input_deltas, const pred2idx & output_deltas, instruction_block & acc);
void make_inloop_delta_transition(const pred2idx & global_head_deltas,
const pred2idx & global_tail_deltas, const pred2idx & local_deltas, instruction_block & acc);
void compile_loop(const func_decl_vector & head_preds, const func_decl_set & widened_preds,

View file

@ -270,15 +270,11 @@ namespace datalog {
}
context::sort_domain & context::get_sort_domain(relation_sort s) {
sort_domain * dom;
TRUSTME( m_sorts.find(s, dom) );
return *dom;
return *m_sorts.find(s);
}
const context::sort_domain & context::get_sort_domain(relation_sort s) const {
sort_domain * dom;
TRUSTME( m_sorts.find(s, dom) );
return *dom;
return *m_sorts.find(s);
}
void context::register_finite_sort(sort * s, sort_kind k) {
@ -298,10 +294,6 @@ namespace datalog {
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) {
m_vars.push_back(m.mk_const(var));
}
@ -347,13 +339,20 @@ namespace datalog {
}
void context::register_predicate(func_decl * decl, bool named) {
if (m_preds.contains(decl)) {
return;
if (!is_predicate(decl)) {
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) {
m_preds_by_name.insert(decl->get_name(), decl);
}
void context::restrict_predicates(func_decl_set const& preds) {
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;
}
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) {
m_rule_fmls.push_back(rl);
m_rule_names.push_back(name);
@ -469,14 +453,12 @@ namespace datalog {
void context::flush_add_rules() {
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);
for (unsigned i = 0; i < m_rule_fmls.size(); ++i) {
expr* fml = m_rule_fmls[i].get();
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_names.reset();
}
@ -487,25 +469,28 @@ namespace datalog {
//
void context::update_rule(expr* rl, symbol const& name) {
datalog::rule_manager& rm = get_rule_manager();
datalog::rule_ref_vector rules(rm);
proof* p = 0;
if (generate_proof_trace()) {
p = m.mk_asserted(rl);
}
rm.mk_rule(rl, p, rules, name);
if (rules.size() != 1) {
unsigned size_before = m_rule_set.get_num_rules();
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;
strm << "Rule " << name << " has a non-trivial body. It cannot be modified";
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* 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 (old_rule) {
std::stringstream strm;
strm << "Rule " << name << " occurs twice. It cannot be modified";
m_rule_set.del_rule(r);
throw default_exception(strm.str());
}
old_rule = rls[i];
@ -518,11 +503,11 @@ namespace datalog {
old_rule->display(*this, strm);
strm << "does not subsume new rule ";
r->display(*this, strm);
m_rule_set.del_rule(r);
throw default_exception(strm.str());
}
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) {
@ -623,20 +608,20 @@ namespace datalog {
}
class context::contains_pred : public i_expr_pred {
rule_manager const& m;
context const& ctx;
public:
contains_pred(rule_manager const& m): m(m) {}
contains_pred(context& ctx): ctx(ctx) {}
virtual ~contains_pred() {}
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) {
unsigned ut_size = r->get_uninterpreted_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());
TRACE("dl", r->display_smt2(get_manager(), tout); tout << "\n";);
@ -663,7 +648,7 @@ namespace datalog {
}
ast_manager& m = get_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());
for (unsigned i = ut_size; i < t_size; ++i) {
@ -676,7 +661,7 @@ namespace datalog {
continue;
}
visited.mark(e, true);
if (rm.is_predicate(e)) {
if (is_predicate(e)) {
}
else if (m.is_and(e) || m.is_or(e)) {
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);
}
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) {
if (get_engine() == DATALOG_ENGINE) {
ensure_rel();
@ -771,10 +748,9 @@ namespace datalog {
void context::add_fact(app * head) {
SASSERT(is_fact(head));
relation_fact fact(get_manager());
unsigned n=head->get_num_args();
for (unsigned i=0; i<n; i++) {
unsigned n = head->get_num_args();
for (unsigned i = 0; i < n; i++) {
fact.push_back(to_app(head->get_arg(i)));
}
add_fact(head->get_decl(), fact);
@ -838,21 +814,26 @@ namespace datalog {
void context::transform_rules() {
m_transf.reset();
m_transf.register_plugin(alloc(mk_filter_rules,*this));
m_transf.register_plugin(alloc(mk_simple_joins,*this));
if (unbound_compressor()) {
m_transf.register_plugin(alloc(mk_unbound_compressor,*this));
if (get_params().filter_rules()) {
m_transf.register_plugin(alloc(mk_filter_rules, *this));
}
m_transf.register_plugin(alloc(mk_simple_joins, *this));
if (unbound_compressor()) {
m_transf.register_plugin(alloc(mk_unbound_compressor, *this));
}
if (similarity_compressor()) {
m_transf.register_plugin(alloc(mk_similarity_compressor, *this,
similarity_compressor_threshold()));
m_transf.register_plugin(alloc(mk_similarity_compressor, *this));
}
m_transf.register_plugin(alloc(datalog::mk_partial_equivalence_transformer, *this));
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) {
SASSERT(m_closed); //we must finish adding rules before we start transforming them
@ -866,15 +847,16 @@ namespace datalog {
}
}
void context::replace_rules(rule_set & rs) {
void context::replace_rules(rule_set const & rs) {
SASSERT(!m_closed);
m_rule_set.reset();
m_rule_set.add_rules(rs);
m_rule_set.replace_rules(rs);
if (m_rel) {
m_rel->restrict_predicates(get_predicates());
}
}
void context::record_transformed_rules() {
m_transformed_rule_set.reset();
m_transformed_rule_set.add_rules(m_rule_set);
m_transformed_rule_set.replace_rules(m_rule_set);
}
void context::apply_default_transformation() {
@ -925,16 +907,6 @@ namespace datalog {
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 result(m);
switch (m_background.size()) {
@ -1273,14 +1245,13 @@ namespace datalog {
void context::get_rules_as_formulas(expr_ref_vector& rules, svector<symbol>& names) {
expr_ref fml(m);
datalog::rule_manager& rm = get_rule_manager();
datalog::rule_ref_vector rule_refs(rm);
// ensure that rules are all using bound variables.
for (unsigned i = 0; i < m_rule_fmls.size(); ++i) {
ptr_vector<sort> sorts;
get_free_vars(m_rule_fmls[i].get(), sorts);
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_names[i] = m_rule_names.back();
m_rule_fmls.pop_back();
@ -1288,7 +1259,6 @@ namespace datalog {
--i;
}
}
add_rules(rule_refs);
rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end();
for (; it != end; ++it) {
(*it)->to_formula(fml);

View file

@ -185,7 +185,17 @@ namespace datalog {
*/
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;
@ -238,11 +248,9 @@ namespace datalog {
void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt,
symbol const * relation_names);
void set_output_predicate(func_decl * pred);
bool is_output_predicate(func_decl * pred);
const decl_set & get_output_predicates();
void set_output_predicate(func_decl * pred) { m_rule_set.set_output_predicate(pred); }
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);
@ -252,7 +260,6 @@ namespace datalog {
bool has_facts(func_decl * pred) const;
void add_rule(rule_ref& r);
void add_rules(rule_ref_vector& rs);
void assert_expr(expr* e);
expr_ref get_background_assertion();
@ -330,7 +337,8 @@ namespace datalog {
void transform_rules();
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 apply_default_transformation();
@ -339,14 +347,6 @@ namespace datalog {
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 {
m_rule_set.display(out);
}

View file

@ -129,7 +129,7 @@ namespace datalog {
for(unsigned i=0; i<n; i++) {
if(table_columns[i]) {
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);
}
else {
@ -1789,7 +1789,7 @@ namespace datalog {
m_sig2table[i]=m_table_sig.size();
table_sort srt;
//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_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);
r.to_formula(fml1);
body = m.mk_and(new_conjs.size(), new_conjs.c_ptr());
@ -199,12 +198,12 @@ namespace datalog {
fml2 = m.mk_implies(body, head);
proof_ref p(m);
rule_set new_rules(m_ctx);
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);
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());
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* rules = alloc(rule_set, m_ctx);
rules->inherit_predicates(source);
rule_set::iterator it = source.begin(), end = source.end();
bool change = false;
for (; !m_ctx.canceled() && it != end; ++it) {

View file

@ -108,31 +108,35 @@ namespace datalog {
class expand_mkbv_cfg : public default_rewriter_cfg {
context& m_context;
rule_ref_vector& m_rules;
ast_manager& m;
bv_util m_util;
expr_ref_vector m_args, m_f_vars, m_g_vars;
func_decl_ref_vector m_old_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;
public:
expand_mkbv_cfg(context& ctx, rule_ref_vector& rules):
expand_mkbv_cfg(context& ctx):
m_context(ctx),
m_rules(rules),
m(ctx.get_manager()),
m_util(m),
m_args(m),
m_f_vars(m),
m_g_vars(m),
m_old_funcs(m),
m_new_funcs(m)
m_new_funcs(m),
m_src(0),
m_dst(0)
{}
~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& new_funcs() const { return m_new_funcs; }
@ -183,14 +187,7 @@ namespace datalog {
m_new_funcs.push_back(g);
m_pred2blast.insert(f, g);
// Create rule f(mk_mkbv(args)) :- g(args)
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());
m_dst->inherit_predicate(*m_src, f, g);
}
result = m.mk_app(g, m_args.size(), m_args.c_ptr());
result_pr = 0;
@ -200,9 +197,9 @@ namespace datalog {
struct expand_mkbv : public rewriter_tpl<expand_mkbv_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),
m_cfg(ctx, rules) {
m_cfg(ctx) {
}
};
@ -212,7 +209,6 @@ namespace datalog {
context & m_context;
ast_manager & m;
params_ref m_params;
rule_ref_vector m_rules;
mk_interp_tail_simplifier m_simplifier;
bit_blaster_rewriter m_blaster;
expand_mkbv m_rewriter;
@ -239,19 +235,14 @@ namespace datalog {
}
}
void reset() {
m_rules.reset();
}
public:
impl(context& ctx):
m_context(ctx),
m(ctx.get_manager()),
m_params(ctx.get_params().p),
m_rules(ctx.get_rule_manager()),
m_simplifier(ctx),
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_quant", true);
m_blaster.updt_params(m_params);
@ -265,8 +256,9 @@ namespace datalog {
rule_manager& rm = m_context.get_rule_manager();
unsigned sz = source.get_num_rules();
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) {
rule * r = source.get_rule(i);
r->to_formula(fml);
@ -275,17 +267,16 @@ namespace datalog {
if (m_context.generate_proof_trace()) {
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 {
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()) {
filter_model_converter* fmc = alloc(filter_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* rules = alloc(rule_set, m_ctx);
rules->inherit_predicates(source);
rule_set::decl2rules::iterator it = source.begin_grouped_rules(), end = source.end_grouped_rules();
for (; it != end; ++it) {
rule_ref_vector d_rules(rm);

View file

@ -35,7 +35,7 @@ namespace datalog {
rule_set * mk_coi_filter::operator()(rule_set const & source)
{
if (source.get_num_rules()==0) {
if (source.empty()) {
return 0;
}
@ -43,7 +43,7 @@ namespace datalog {
decl_set pruned_preds;
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();
for (decl_set::iterator it = output_preds.begin(); it!=oend; ++it) {
todo.push_back(*it);
@ -70,6 +70,7 @@ namespace datalog {
}
scoped_ptr<rule_set> res = alloc(rule_set, m_context);
res->inherit_predicates(source);
rule_set::iterator rend = source.end();
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) {
unsigned n=s.size();
for(unsigned i=0; i<n; i++) {
if(!get_context().get_decl_util().is_rule_sort(s[i])) {
for (unsigned i=0; i<n; i++) {
if (!get_context().get_decl_util().is_rule_sort(s[i])) {
return false;
}
}
@ -142,7 +142,7 @@ namespace datalog {
DEBUG_CODE(
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]) );
}
);
@ -162,13 +162,13 @@ namespace datalog {
m_data.resize(get_signature().size());
}
void unite_with_data(const relation_fact & f) {
if(empty()) {
if (empty()) {
assign_data(f);
return;
}
unsigned n=get_signature().size();
SASSERT(f.size()==n);
for(unsigned i=0; i<n; i++) {
for (unsigned i=0; i<n; i++) {
SASSERT(!is_undefined(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;
}
bool no_undefined() const {
if(empty()) {
if (empty()) {
return true;
}
unsigned n = get_signature().size();
for(unsigned i=0; i<n; i++) {
if(is_undefined(i)) {
for (unsigned i=0; i<n; i++) {
if (is_undefined(i)) {
return false;
}
}
@ -231,14 +231,14 @@ namespace datalog {
virtual relation_base * complement(func_decl* pred) const {
explanation_relation * res = static_cast<explanation_relation *>(get_plugin().mk_empty(get_signature()));
if(empty()) {
if (empty()) {
res->set_undefined();
}
return res;
}
void display_explanation(app * expl, std::ostream & out) const {
if(expl) {
if (expl) {
//TODO: some nice explanation output
ast_smt_pp pp(get_plugin().get_ast_manager());
pp.display_expr_smt2(out, expl);
@ -249,13 +249,13 @@ namespace datalog {
}
virtual void display(std::ostream & out) const {
if(empty()) {
if (empty()) {
out << "<empty explanation relation>\n";
return;
}
unsigned sz = get_signature().size();
for(unsigned i=0; i<sz; i++) {
if(i!=0) {
for (unsigned i=0; i<sz; i++) {
if (i!=0) {
out << ", ";
}
display_explanation(m_data[0], out);
@ -305,7 +305,7 @@ namespace datalog {
explanation_relation_plugin & plugin = r1.get_plugin();
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;
SASSERT(res->m_data.empty());
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,
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;
}
if(col_cnt!=0) {
if (col_cnt!=0) {
return 0;
}
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 * res = static_cast<explanation_relation *>(plugin.mk_empty(get_result_signature()));
if(!r.empty()) {
if (!r.empty()) {
relation_fact proj_data = r.m_data;
project_out_vector_columns(proj_data, m_removed_cols);
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,
const unsigned * removed_cols) {
if(&r.get_plugin()!=this) {
if (&r.get_plugin()!=this) {
return 0;
}
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 * res = static_cast<explanation_relation *>(plugin.mk_empty(get_result_signature()));
if(!r.empty()) {
if (!r.empty()) {
relation_fact permutated_data = r.m_data;
permutate_by_cycle(permutated_data, m_cycle);
res->assign_data(permutated_data);
@ -389,16 +389,16 @@ namespace datalog {
explanation_relation * delta = delta0 ? static_cast<explanation_relation *>(delta0) : 0;
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();
}
if(src.empty()) {
if (src.empty()) {
return;
}
if(plugin.m_relation_level_explanations) {
if (plugin.m_relation_level_explanations) {
tgt.unite_with_data(src.m_data);
if(delta) {
if(!m_delta_union_fun) {
if (delta) {
if (!m_delta_union_fun) {
m_delta_union_fun = plugin.get_manager().mk_union_fn(*delta, src);
SASSERT(m_delta_union_fun);
}
@ -406,9 +406,9 @@ namespace datalog {
}
}
else {
if(tgt.empty()) {
if (tgt.empty()) {
tgt.assign_data(src.m_data);
if(delta && delta->empty()) {
if (delta && delta->empty()) {
delta->assign_data(src.m_data);
}
}
@ -423,11 +423,11 @@ namespace datalog {
explanation_relation & tgt = static_cast<explanation_relation &>(tgt0);
explanation_relation * delta = delta0 ? static_cast<explanation_relation *>(delta0) : 0;
if(src.empty()) {
if (src.empty()) {
return;
}
tgt.set_undefined();
if(delta) {
if (delta) {
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,
const relation_base * delta) {
if(!check_kind(tgt) || (delta && !check_kind(*delta))) {
if (!check_kind(tgt) || (delta && !check_kind(*delta))) {
return 0;
}
if(!check_kind(src)) {
if (!check_kind(src)) {
//this is to handle the product relation
return alloc(foreign_union_fn);
}
@ -460,7 +460,7 @@ namespace datalog {
virtual void operator()(relation_base & r0) {
explanation_relation & r = static_cast<explanation_relation &>(r0);
if(!r.is_undefined(m_col_idx)) {
if (!r.is_undefined(m_col_idx)) {
UNREACHABLE();
}
@ -468,7 +468,7 @@ namespace datalog {
ptr_vector<expr> subst_arg;
subst_arg.resize(sz, 0);
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));
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,
app * cond) {
if(&r.get_plugin()!=this) {
if (&r.get_plugin()!=this) {
return 0;
}
ast_manager & m = get_ast_manager();
if(!m.is_eq(cond)) {
if (!m.is_eq(cond)) {
return 0;
}
expr * arg1 = cond->get_arg(0);
expr * arg2 = cond->get_arg(1);
if(is_var(arg2)) {
if (is_var(arg2)) {
std::swap(arg1, arg2);
}
if(!is_var(arg1) || !is_app(arg2)) {
if (!is_var(arg1) || !is_app(arg2)) {
return 0;
}
var * col_var = to_var(arg1);
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;
}
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 {
public:
virtual void operator()(relation_base & r, const relation_base & neg) {
if(!neg.empty()) {
if (!neg.empty()) {
r.reset();
}
}
@ -520,7 +520,7 @@ namespace datalog {
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 unsigned * negated_cols) {
if(&r.get_plugin()!=this || &neg.get_plugin()!=this) {
if (&r.get_plugin()!=this || &neg.get_plugin()!=this) {
return 0;
}
return alloc(negation_filter_fn);
@ -537,26 +537,26 @@ namespace datalog {
explanation_relation & tgt = static_cast<explanation_relation &>(tgt0);
const explanation_relation & src = static_cast<const explanation_relation &>(src0);
if(src.empty()) {
if (src.empty()) {
tgt.reset();
return;
}
if(tgt.empty()) {
if (tgt.empty()) {
return;
}
unsigned sz = tgt.get_signature().size();
for(unsigned i=0; i<sz; i++) {
if(src.is_undefined(i)) {
for (unsigned i=0; i<sz; i++) {
if (src.is_undefined(i)) {
continue;
}
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);
continue;
}
app * curr_tgt = tgt.m_data.get(i);
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_decl()==m_union_decl.get()) {
if (curr_tgt->get_arg(0)==curr_src || curr_tgt->get_arg(1)==curr_src) {
tgt.m_data.set(i, curr_src);
continue;
}
@ -570,18 +570,18 @@ namespace datalog {
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 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;
}
//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()
|| !containers_equal(tgt_cols, tgt_cols+joined_col_cnt, src_cols, src_cols+joined_col_cnt)) {
return 0;
}
counter ctr;
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 alloc(intersection_filter_fn, *this);
@ -595,23 +595,23 @@ namespace datalog {
// -----------------------------------
mk_explanations::mk_explanations(context & ctx, bool relation_level)
: plugin(50000),
m_manager(ctx.get_manager()),
m_context(ctx),
m_decl_util(ctx.get_decl_util()),
m_relation_level(relation_level),
m_pinned(m_manager) {
mk_explanations::mk_explanations(context & ctx)
: plugin(50000),
m_manager(ctx.get_manager()),
m_context(ctx),
m_decl_util(ctx.get_decl_util()),
m_relation_level(ctx.explanations_on_relation_level()),
m_pinned(m_manager) {
m_e_sort = m_decl_util.mk_rule_sort();
m_pinned.push_back(m_e_sort);
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));
if(!m_er_plugin) {
m_er_plugin = alloc(explanation_relation_plugin, relation_level, rmgr);
if (!m_er_plugin) {
m_er_plugin = alloc(explanation_relation_plugin, m_relation_level, rmgr);
rmgr.register_plugin(m_er_plugin);
if(!m_relation_level) {
if (!m_relation_level) {
DEBUG_CODE(
finite_product_relation_plugin * dummy;
SASSERT(!rmgr.try_get_finite_product_relation_plugin(*m_er_plugin, dummy));
@ -620,7 +620,7 @@ namespace datalog {
}
}
DEBUG_CODE(
if(!m_relation_level) {
if (!m_relation_level) {
finite_product_relation_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) {
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;
e_domain.append(orig_decl->get_arity(), orig_decl->get_domain());
e_domain.push_back(m_e_sort);
@ -677,7 +677,7 @@ namespace datalog {
m_pinned.push_back(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);
}
}
@ -716,13 +716,13 @@ namespace datalog {
app_ref_vector e_tail(m_manager);
svector<bool> neg_flags;
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++;
e_tail.push_back(get_e_lit(r->get_tail(i), e_var));
neg_flags.push_back(false);
}
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));
neg_flags.push_back(r->is_neg_tail(i));
}
@ -730,9 +730,9 @@ namespace datalog {
symbol rule_repr = get_rule_symbol(r);
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);
if(true || m_relation_level) {
if (true || m_relation_level) {
//this adds the explanation term of the tail
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());
}
void mk_explanations::transform_rules(const rule_set & orig, rule_set & tgt) {
rule_set::iterator rit = orig.begin();
rule_set::iterator rend = orig.end();
for(; rit!=rend; ++rit) {
void mk_explanations::transform_rules(const rule_set & src, rule_set & dst) {
rule_set::iterator rit = src.begin();
rule_set::iterator rend = src.end();
for (; rit!=rend; ++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
//the original ones
expr_ref_vector lit_args(m_manager);
decl_set::iterator pit = m_original_preds.begin();
decl_set::iterator pend = m_original_preds.end();
for(; pit!=pend; ++pit) {
decl_set::iterator pit = src.get_output_predicates().begin();
decl_set::iterator pend = src.get_output_predicates().end();
for (; pit != pend; ++pit) {
func_decl * orig_decl = *pit;
if(!m_context.is_output_predicate(orig_decl)) {
continue;
}
lit_args.reset();
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)));
}
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 * 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,
@ -799,7 +794,7 @@ namespace datalog {
sieve_relation * srels[] = {
static_cast<sieve_relation *>(&prod_rel[0]),
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]);
}
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;
expl_singleton_sig.push_back(m_e_sort);
@ -836,29 +830,26 @@ namespace datalog {
SASSERT(&expl_singleton->get_plugin()==m_er_plugin);
m_e_fact_relation = static_cast<explanation_relation *>(expl_singleton);
}
decl_set::iterator it = m_original_preds.begin();
decl_set::iterator end = m_original_preds.end();
for(; it!=end; ++it) {
func_decl_set const& predicates = m_context.get_predicates();
decl_set::iterator it = predicates.begin();
decl_set::iterator end = predicates.end();
for (; it!=end; ++it) {
func_decl * orig_decl = *it;
func_decl * e_decl = get_e_decl(orig_decl);
if(m_context.is_output_predicate(orig_decl)) {
m_context.set_output_predicate(e_decl);
}
if(!rmgr.try_get_relation(orig_decl)) {
//there are no facts for this predicate
if (!rmgr.try_get_relation(orig_decl) &&
!src.contains(orig_decl)) {
// there are no facts or rules for this predicate
continue;
}
dst.inherit_predicate(src, orig_decl, e_decl);
relation_base & orig_rel = rmgr.get_relation(orig_decl);
relation_base & e_rel = rmgr.get_relation(e_decl);
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);
}
else {
@ -869,18 +860,19 @@ namespace datalog {
SASSERT(union_fun);
(*union_fun)(e_rel, *aux_extended_rel);
}
}
}
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;
}
m_context.collect_predicates(m_original_preds);
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);
return res;
}

View file

@ -32,19 +32,13 @@ namespace datalog {
typedef obj_map<func_decl, func_decl *> decl_map;
ast_manager & m_manager;
context & m_context;
ast_manager & m_manager;
context & m_context;
dl_decl_util & m_decl_util;
bool m_relation_level;
decl_set m_original_preds;
bool m_relation_level;
ast_ref_vector m_pinned;
explanation_relation_plugin * m_er_plugin;
sort * m_e_sort;
sort * m_e_sort;
scoped_rel<explanation_relation> m_e_fact_relation;
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 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:
/**
If relation_level is true, the explanation will not be stored for each fact,
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.

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_pinned(m_manager) {
}
mk_filter_rules::~mk_filter_rules() {
ptr_vector<filter_key> to_dealloc;
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.
*/
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";);
return false;
}
@ -151,19 +152,21 @@ namespace datalog {
}
rule_set * mk_filter_rules::operator()(rule_set const & source) {
// TODO mc, pc
if (!m_context.get_params().filter_rules()) {
return 0;
}
m_tail2filter.reset();
m_result = alloc(rule_set, m_context);
m_modified = false;
unsigned num_rules = source.get_num_rules();
for (unsigned i = 0; i < num_rules; i++) {
rule * r = source.get_rule(i);
process(r);
process(source.get_rule(i));
}
if(!m_modified) {
dealloc(m_result);
return static_cast<rule_set *>(0);
}
m_result->inherit_predicates(source);
return m_result;
}

View file

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

View file

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

View file

@ -25,6 +25,7 @@ namespace datalog {
mk_loop_counter::mk_loop_counter(context & ctx, unsigned priority):
plugin(priority),
m(ctx.get_manager()),
m_ctx(ctx),
a(m),
m_refs(m) {
}
@ -72,14 +73,14 @@ namespace datalog {
for (unsigned j = 0; j < utsz; ++j, ++cnt) {
tail.push_back(add_arg(r.get_tail(j), cnt));
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) {
tail.push_back(r.get_tail(j));
neg.push_back(false);
}
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
bool found = false;
unsigned last = head->get_num_args()-1;
@ -107,6 +108,8 @@ namespace datalog {
// model converter: remove references to extra argument.
// proof converter: remove references to extra argument as well.
result->inherit_predicates(source);
return result;
}

View file

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

View file

@ -24,13 +24,12 @@ Revision History:
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),
m_context(ctx),
m_manager(ctx.get_manager()),
m_rules(ctx.get_rule_manager()),
m_pinned(m_manager),
m_goal_rule(goal_rule, ctx.get_rule_manager()) {
m(ctx.get_manager()),
m_pinned(m),
m_goal(goal, m) {
}
void mk_magic_sets::reset() {
@ -39,14 +38,13 @@ namespace datalog {
m_adorned_preds.reset();
m_adornments.reset();
m_magic_preds.reset();
m_rules.reset();
m_pinned.reset();
}
void mk_magic_sets::adornment::populate(app * lit, const var_idx_set & bound_vars) {
SASSERT(empty());
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);
bool bound = !is_var(arg) || bound_vars.contains(to_var(arg)->get_idx());
push_back(bound ? AD_BOUND : AD_FREE);
@ -57,17 +55,8 @@ namespace datalog {
std::string res;
const_iterator eit = begin();
const_iterator eend = end();
for(; eit!=eend; ++eit) {
switch(*eit) {
case AD_BOUND:
res+='b';
break;
case AD_FREE:
res+='f';
break;
default:
UNREACHABLE();
}
for (; eit != eend; ++eit) {
res += (*eit == AD_BOUND)?'b':'f';
}
return res;
}
@ -75,14 +64,13 @@ namespace datalog {
unsigned get_bound_arg_count(app * lit, const var_idx_set & bound_vars) {
unsigned res = 0;
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);
if(is_var(arg) && !bound_vars.contains(to_var(arg)->get_idx())) {
continue;
if (!is_var(arg) || bound_vars.contains(to_var(arg)->get_idx())) {
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;
}
@ -91,10 +79,10 @@ namespace datalog {
func_decl * pred = lit->get_decl();
float res = 1;
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);
if(is_var(arg) && !bound_vars.contains(to_var(arg)->get_idx())) {
res*=m_context.get_sort_size_estimate(pred->get_domain(i));
if (is_var(arg) && !bound_vars.contains(to_var(arg)->get_idx())) {
res *= m_context.get_sort_size_estimate(pred->get_domain(i));
}
//res-=1;
}
@ -111,22 +99,22 @@ namespace datalog {
float best_cost;
int candidate_index = -1;
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]);
unsigned bound_cnt = get_bound_arg_count(lit, bound_vars);
if(bound_cnt==0) {
if (bound_cnt==0) {
continue;
}
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;
candidate_index = i;
}
}
if(candidate_index==-1) {
if (candidate_index==-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]);
}
unsigned res = cont.back();
@ -137,12 +125,12 @@ namespace datalog {
app * mk_magic_sets::adorn_literal(app * lit, const var_idx_set & bound_vars) {
SASSERT(!m_extentional.contains(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);
adn.m_adornment.populate(lit, bound_vars);
adornment_map::entry * e = m_adorned_preds.insert_if_not_there2(adn, 0);
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();
new_pred = m_context.mk_fresh_head_predicate(
old_pred->get_name(), symbol(suffix.c_str()),
@ -152,34 +140,34 @@ namespace datalog {
m_todo.push_back(adn);
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);
return res;
}
app * mk_magic_sets::create_magic_literal(app * l) {
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);
SASSERT(ae);
const adornment & adn = ae->get_data().m_value;
unsigned l_arity = l->get_num_args();
ptr_vector<expr> bound_args;
for(unsigned i=0; i<l_arity; i++) {
if(adn[i]==AD_BOUND) {
for (unsigned i=0; i<l_arity; i++) {
if (adn[i]==AD_BOUND) {
bound_args.push_back(l->get_arg(i));
}
}
pred2pred::obj_map_entry * e = m_magic_preds.insert_if_not_there2(l_pred, 0);
func_decl * mag_pred = e->get_data().m_value;
if(mag_pred==0) {
if (mag_pred==0) {
unsigned mag_arity = bound_args.size();
ptr_vector<sort> mag_domain;
for(unsigned i=0; i<l_arity; i++) {
if(adn[i]==AD_BOUND) {
for (unsigned i=0; i<l_arity; i++) {
if (adn[i]==AD_BOUND) {
mag_domain.push_back(l_pred->get_domain(i));
}
}
@ -190,12 +178,12 @@ namespace datalog {
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);
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
ptr_vector<app> new_tail;
svector<bool> negations;
@ -204,26 +192,26 @@ namespace datalog {
negations.push_back(false);
negations.append(tail_cnt, negated);
for(unsigned i=0; i<tail_cnt; i++) {
if(m_extentional.contains(tail[i]->get_decl())) {
for (unsigned i=0; i<tail_cnt; i++) {
if (m_extentional.contains(tail[i]->get_decl())) {
continue;
}
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());
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();
unsigned head_len = head->get_num_args();
SASSERT(head_len==head_adornment.size());
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);
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());
}
}
@ -231,9 +219,9 @@ namespace datalog {
unsigned processed_tail_len = r->get_uninterpreted_tail_size();
unsigned_vector exten_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);
if(m_extentional.contains(t->get_decl())) {
if (m_extentional.contains(t->get_decl())) {
exten_tails.push_back(i);
}
else {
@ -243,17 +231,17 @@ namespace datalog {
ptr_vector<app> new_tail;
svector<bool> negations;
while(new_tail.size()!=processed_tail_len) {
while (new_tail.size()!=processed_tail_len) {
bool intentional = false;
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);
if(curr_index!=-1) {
if (curr_index!=-1) {
intentional = true;
}
}
if(curr_index==-1) {
if(!exten_tails.empty()) {
if (curr_index==-1) {
if (!exten_tails.empty()) {
curr_index = exten_tails.back();
exten_tails.pop_back();
}
@ -266,24 +254,24 @@ namespace datalog {
}
SASSERT(curr_index!=-1);
app * curr = r->get_tail(curr_index);
if(intentional) {
if (intentional) {
curr = adorn_literal(curr, bound_vars);
}
new_tail.push_back(curr);
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;
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());
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();
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));
negations.push_back(r->is_neg_tail(i));
}
@ -292,42 +280,51 @@ namespace datalog {
negations.push_back(false);
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);
}
void mk_magic_sets::create_transfer_rule(const adornment_desc & d) {
func_decl * adn_pred;
TRUSTME( m_adorned_preds.find(d, adn_pred) );
void mk_magic_sets::create_transfer_rule(const adornment_desc & d, rule_set& result) {
func_decl * adn_pred = m_adorned_preds.find(d);
unsigned arity = adn_pred->get_arity();
SASSERT(arity==d.m_pred->get_arity());
SASSERT(arity == d.m_pred->get_arity());
ptr_vector<expr> args;
for(unsigned i=0; i<arity; i++) {
args.push_back(m_manager.mk_var(i, adn_pred->get_domain(i)));
for (unsigned i=0; i<arity; 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 * adn_lit = m_manager.mk_app(adn_pred, args.c_ptr());
app * lit = m.mk_app(d.m_pred, args.c_ptr());
app * adn_lit = m.mk_app(adn_pred, args.c_ptr());
app * mag_lit = create_magic_literal(adn_lit);
app * tail[] = {lit, mag_lit};
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) {
if (!m_context.magic_sets_for_queries()) {
return 0;
}
SASSERT(source.contains(m_goal));
SASSERT(source.get_predicate_rules(m_goal).size() == 1);
app * goal_head = source.get_predicate_rules(m_goal)[0]->get_head();
unsigned init_rule_cnt = source.get_num_rules();
{
func_decl_set intentional;
for(unsigned i=0; i<init_rule_cnt; i++) {
intentional.insert(source.get_rule(i)->get_head()->get_decl());
for (unsigned i=0; i<init_rule_cnt; i++) {
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
const rule_dependencies * deps;
rule_dependencies computed_deps(m_context);
if(source.is_closed()) {
if (source.is_closed()) {
deps = &source.get_dependencies();
}
else {
@ -336,9 +333,9 @@ namespace datalog {
}
rule_dependencies::iterator it = deps->begin();
rule_dependencies::iterator end = deps->end();
for(; it!=end; ++it) {
for (; it!=end; ++it) {
func_decl * pred = it->m_key;
if(intentional.contains(pred)) {
if (intentional.contains(pred)) {
continue;
}
SASSERT(it->m_value->empty());//extentional predicates have no dependency
@ -346,48 +343,39 @@ namespace datalog {
}
}
SASSERT(m_rules.empty());
app * goal_head = m_goal_rule->get_head();
//adornment goal_adn;
//goal_adn.populate(goal_head, );
var_idx_set 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();
m_todo.pop_back();
const rule_vector & pred_rules = source.get_predicate_rules(task.m_pred);
rule_vector::const_iterator it = pred_rules.begin();
rule_vector::const_iterator end = pred_rules.end();
for(; it!=end; ++it) {
for (; it != end; ++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
//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 * mag_goal_head = create_magic_literal(adn_goal_head);
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);
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);
m_rules.push_back(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));
}
result->add_rule(back_to_goal_rule);
return result;
}
};

View file

@ -88,21 +88,20 @@ namespace datalog {
typedef obj_map<func_decl, adornment> pred_adornment_map;
typedef obj_map<func_decl, func_decl *> pred2pred;
context & m_context;
ast_manager & m_manager;
rule_ref_vector m_rules;
ast_ref_vector m_pinned;
rule_ref m_goal_rule;
context & m_context;
ast_manager & m;
ast_ref_vector m_pinned;
/**
\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;
vector<adornment_desc> m_todo;
adornment_map m_adorned_preds;
pred_adornment_map m_adornments;
pred2pred m_magic_preds;
adornment_map m_adorned_preds;
pred_adornment_map m_adornments;
pred2pred m_magic_preds;
func_decl_ref m_goal;
void reset();
@ -110,16 +109,16 @@ namespace datalog {
int pop_bound(unsigned_vector & cont, rule * r, const var_idx_set & bound_vars);
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);
void transform_rule(const adornment & head_adornment, rule * r);
void create_transfer_rule(const adornment_desc & d);
void transform_rule(const adornment & head_adornment, rule * r, rule_set& result);
void create_transfer_rule(const adornment_desc & d, rule_set& result);
public:
/**
\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.
*/
mk_magic_sets(context & ctx, rule * goal_rule);
mk_magic_sets(context & ctx, func_decl* goal);
rule_set * operator()(rule_set const & source);
};

View file

@ -23,7 +23,7 @@ Revision History:
namespace datalog {
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
p->get_arity() == 2 &&
p->get_domain(0) == p->get_domain(1) &&
@ -38,7 +38,7 @@ namespace datalog {
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 ||
p->get_domain(0) != p->get_domain(1) ||
r->get_tail_size() != 2 ||
@ -144,6 +144,7 @@ namespace datalog {
dealloc(res);
return 0;
}
res->inherit_predicates(source);
return res;
}

View file

@ -147,9 +147,10 @@ namespace datalog {
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;
}
@ -210,8 +211,8 @@ namespace datalog {
return new_p;
}
app_ref mk_quantifier_abstraction::mk_head(app* p, unsigned idx) {
func_decl* new_p = declare_pred(p->get_decl());
app_ref mk_quantifier_abstraction::mk_head(rule_set const& rules, rule_set& dst, app* p, unsigned idx) {
func_decl* new_p = declare_pred(rules, dst, p->get_decl());
if (!new_p) {
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);
}
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* new_p = declare_pred(old_p);
func_decl* new_p = declare_pred(rules, dst, old_p);
if (!new_p) {
return app_ref(p, m);
}
@ -332,18 +333,17 @@ namespace datalog {
unsigned utsz = r.get_uninterpreted_tail_size();
unsigned tsz = r.get_tail_size();
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) {
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);
rule_ref_vector added_rules(rm);
proof_ref pr(m);
rm.mk_rule(fml, pr, added_rules);
result->add_rules(added_rules.size(), added_rules.c_ptr());
TRACE("dl", added_rules.back()->display(m_ctx, tout););
rm.mk_rule(fml, pr, *result);
TRACE("dl", result->last()->display(m_ctx, tout););
}
// 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;
qa_model_converter* m_mc;
func_decl* declare_pred(func_decl* old_p);
app_ref mk_head(app* p, unsigned idx);
app_ref mk_tail(app* p);
func_decl* declare_pred(rule_set const& rules, rule_set& dst, func_decl* old_p);
app_ref mk_head(rule_set const& rules, rule_set& dst, app* p, unsigned idx);
app_ref mk_tail(rule_set const& rules, rule_set& dst, app* p);
expr* mk_select(expr* a, unsigned num_args, expr* const* args);
public:

View file

@ -232,20 +232,20 @@ namespace datalog {
fml = m.mk_implies(fml, r.get_head());
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);
rm.mk_rule(fml, pr, added_rules);
if (r.get_proof()) {
// use def-axiom to encode that new rule is a weakening of the original.
proof* p1 = r.get_proof();
for (unsigned i = 0; i < added_rules.size(); ++i) {
rule* r2 = added_rules[i].get();
for (unsigned i = 0; i < added_rules.get_num_rules(); ++i) {
rule* r2 = added_rules.get_rule(i);
r2->to_formula(fml);
pr = m.mk_modus_ponens(m.mk_def_axiom(m.mk_implies(m.get_fact(p1), fml)), p1);
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) {
@ -286,7 +286,10 @@ namespace datalog {
// model convertion: identity function.
if (!instantiated) {
if (instantiated) {
result->inherit_predicates(source);
}
else {
dealloc(result);
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
m_context.is_output_predicate(pred) ||
source.is_output_predicate(pred) ||
m_preds_with_facts.contains(pred) ||
m_preds_with_neg_occurrence.contains(pred) ||
//this condition is used for breaking of cycles among inlined rules
@ -260,7 +260,7 @@ namespace datalog {
unsigned rcnt = orig.get_num_rules();
for (unsigned i=0; i<rcnt; i++) {
rule * r = orig.get_rule(i);
if (inlining_allowed(r->get_decl())) {
if (inlining_allowed(orig, r->get_decl())) {
res->add_rule(r);
}
}
@ -324,7 +324,7 @@ namespace datalog {
unsigned pt_len = r->get_positive_tail_size();
for (unsigned ti = 0; ti<pt_len; ++ti) {
func_decl * tail_pred = r->get_decl(ti);
if (!inlining_allowed(tail_pred)) {
if (!inlining_allowed(orig, tail_pred)) {
continue;
}
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();
if (inlining_allowed(head_pred)) {
if (inlining_allowed(orig, head_pred)) {
//we have already processed inlined rules
continue;
}
@ -368,7 +368,7 @@ namespace datalog {
unsigned pt_len = r->get_positive_tail_size();
for (unsigned ti = 0; ti<pt_len; ++ti) {
func_decl * pred = r->get_decl(ti);
if (!inlining_allowed(pred)) {
if (!inlining_allowed(orig, pred)) {
continue;
}
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);
rule_vector::const_iterator iend = pred_rules.end();
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; );
}
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;
rule_ref_vector todo(m_rm);
todo.push_back(r0);
@ -436,7 +436,7 @@ namespace datalog {
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()));
@ -478,12 +478,12 @@ namespace datalog {
// this relation through inlining,
// 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) {
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);
}
}
@ -676,7 +676,7 @@ namespace datalog {
m_head_index.insert(head);
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)) {
can_remove.set(i, false);
TRACE("dl", output_predicate(m_context, head, tout << "cannot remove: " << i << " "); tout << "\n";);
@ -692,7 +692,7 @@ namespace datalog {
tl_sz == 1
&& r->get_positive_tail_size() == 1
&& !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);
}
@ -883,6 +883,7 @@ namespace datalog {
res = 0;
}
else {
res->inherit_predicates(source);
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 inlining_allowed(func_decl * pred);
bool inlining_allowed(rule_set const& orig, func_decl * pred);
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);
/** 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 */
bool transform_rules(const rule_set & orig, rule_set & tgt);

View file

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

View file

@ -67,7 +67,7 @@ namespace datalog {
void reset();
public:
mk_similarity_compressor(context & ctx, unsigned threshold_count);
mk_similarity_compressor(context & ctx);
rule_set * operator()(rule_set const & source);
};

View file

@ -89,7 +89,7 @@ namespace datalog {
m_consumers++;
}
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);
if(head_stratum==m_src_stratum) {
m_stratified = false;
@ -383,7 +383,7 @@ namespace datalog {
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();
std::string parent_name;
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_introduced_rules.pop_back();
}
result->inherit_predicates(source);
return result;
}
};
rule_set * mk_simple_joins::operator()(rule_set const & source) {
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()) {
rs_aux_copy.close();
}

View file

@ -703,7 +703,7 @@ namespace datalog {
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();
ptr_vector<sort> domain;
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);
m_pinned.push_back(f);
m_predicates.insert(p, f);
dst.inherit_predicate(src, p, f);
if (m_mc) {
m_mc->add_predicate(p, f);
}
@ -820,13 +821,14 @@ namespace datalog {
m_mc = smc.get();
reset();
saturate(src);
declare_predicates();
rule_set* result = alloc(rule_set, m_ctx);
declare_predicates(src, *result);
if (m_predicates.empty()) {
// nothing could be sliced.
dealloc(result);
return 0;
}
TRACE("dl", display(tout););
rule_set* result = alloc(rule_set, m_ctx);
update_rules(src, *result);
TRACE("dl", result->display(tout););
if (m_mc) {

View file

@ -83,7 +83,7 @@ namespace datalog {
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);

View file

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

View file

@ -64,8 +64,8 @@ namespace datalog {
/** Function to be called when a new total relation is discovered */
void on_discovered_total_relation(func_decl * pred, rule * r);
void scan_for_total_rules(const rule_set & rules);
void scan_for_relations_total_due_to_facts();
void scan_for_total_rules(rule_set const& rules);
void scan_for_relations_total_due_to_facts(rule_set const& 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) :
plugin(500),
m_context(ctx),
m_manager(ctx.get_manager()),
m(ctx.get_manager()),
m_rules(ctx.get_rule_manager()),
m_pinned(m_manager) {
m_pinned(m) {
}
void mk_unbound_compressor::reset() {
@ -48,7 +48,7 @@ namespace datalog {
unsigned var_idx = to_var(head_arg)->get_idx();
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);
}
@ -81,14 +81,14 @@ namespace datalog {
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);
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();
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
return;
}
@ -96,7 +96,7 @@ namespace datalog {
unsigned n = head_pred->get_arity();
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++) {
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:
rule * r = m_rules.get(rule_index);
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();
func_decl * head_pred = head->get_decl();
unsigned head_arity = head_pred->get_arity();
var_counter head_var_counter;
head_var_counter.count_vars(m_manager, head);
head_var_counter.count_vars(m, head);
unsigned 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)) {
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_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.shrink(m_rules.size()-1);
//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());
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_head_occurrence_ctr.inc(m_rules.get(rule_index)->get_head()->get_decl());
detect_tasks(rule_index);
m_head_occurrence_ctr.inc(m_rules.get(rule_index)->get_decl());
detect_tasks(source, rule_index);
}
m_modified = true;
@ -205,10 +205,10 @@ namespace datalog {
}
}
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;
app_ref_vector tails(m_manager);
app_ref_vector tails(m);
unsigned tail_len = r->get_tail_size();
for (unsigned i=0; i<tail_len; 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);
}
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());
mk_decompression_rule(r, tail_index, arg_index, new_rule);
unsigned new_rule_index = m_rules.size();
m_rules.push_back(new_rule);
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;
@ -258,7 +258,7 @@ namespace datalog {
//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);
@ -269,12 +269,12 @@ namespace datalog {
//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;
}
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;
@ -306,11 +306,11 @@ namespace datalog {
m_head_occurrence_ctr.get(t_pred)==0;
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;
}
else {
add_decompression_rule(r, tail_index, arg_index);
add_decompression_rule(source, r, tail_index, arg_index);
}
}
if (orig_rule_replaced) {
@ -345,11 +345,11 @@ namespace datalog {
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_head()->get_decl());
m_head_occurrence_ctr.inc(r->get_decl());
}
for (unsigned i=0; i<init_rule_cnt; i++) {
detect_tasks(i);
detect_tasks(source, i);
}
while (!m_todo.empty()) {
@ -360,9 +360,9 @@ namespace datalog {
}
unsigned rule_index = 0;
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()) {
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++;
}
@ -375,6 +375,7 @@ namespace datalog {
for (unsigned i=0; i<fin_rule_cnt; i++) {
result->add_rule(m_rules.get(i));
}
result->inherit_predicates(source);
}
reset();
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 svector<c_info> todo_stack;
context & m_context;
ast_manager & m_manager;
context & m_context;
ast_manager & m;
rule_ref_vector m_rules;
bool m_modified;
todo_stack m_todo;
@ -71,13 +71,13 @@ namespace datalog {
bool is_unbound_argument(rule * r, unsigned head_index);
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 try_compress(unsigned rule_index);
void add_decompression_rules(unsigned rule_index);
void 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);
void add_decompression_rule(rule * r, unsigned tail_index, unsigned arg_index);
void replace_by_decompression_rule(unsigned rule_index, 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 reset();
public:
mk_unbound_compressor(context & ctx);

View file

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

View file

@ -124,14 +124,6 @@ namespace datalog {
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 {
relation_map::iterator it = m_relations.begin();
relation_map::iterator end = m_relations.end();
@ -539,8 +531,8 @@ namespace datalog {
}
}
void relation_manager::display_output_tables(std::ostream & out) const {
const decl_set & output_preds = get_context().get_output_predicates();
void relation_manager::display_output_tables(rule_set const& rules, std::ostream & out) const {
const decl_set & output_preds = rules.get_output_predicates();
decl_set::iterator it=output_preds.begin();
decl_set::iterator end=output_preds.end();
for(; it!=end; ++it) {

View file

@ -22,7 +22,6 @@ Revision History:
#include"map.h"
#include"vector.h"
#include"dl_base.h"
namespace datalog {
@ -35,8 +34,8 @@ namespace datalog {
class finite_product_relation_plugin;
class sieve_relation;
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 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 restrict_predicates(const decl_set & preds);
@ -595,7 +593,7 @@ namespace datalog {
void display(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:
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(ctx) {}
bool rule_manager::is_predicate(func_decl * f) const {
return m_ctx.is_predicate(f);
}
void rule_manager::inc_ref(rule * r) {
if (r) {
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);
proof_ref pr(p, m);
expr_ref fml1(m);
@ -111,13 +107,13 @@ namespace datalog {
pr = m.mk_asserted(fml1);
}
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) {
for (unsigned i = 0; i < body.size(); ++i) {
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);
body[i] = to_app(e1);
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);
expr_ref_vector fmls(m);
proof_ref_vector prs(m);
@ -138,11 +134,11 @@ namespace datalog {
m_ctx.register_predicate(h.get_fresh_predicates()[i], false);
}
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 head(m);
@ -189,7 +185,7 @@ namespace datalog {
}
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) {
@ -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;
svector<symbol> names;
app_ref_vector body(m);
@ -279,7 +275,9 @@ namespace datalog {
}
vars.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);
for (unsigned i = 0; i < vars.size(); i++) {
@ -297,9 +295,8 @@ namespace datalog {
if (m_ctx.generate_proof_trace()) {
pr = m.mk_asserted(rule_expr);
}
mk_rule(rule_expr, pr, query_rules);
SASSERT(query_rules.size() >= 1);
query_rule = query_rules.back();
mk_rule(rule_expr, pr, rules);
return qpred;
}
void rule_manager::bind_variables(expr* fml, bool is_forall, expr_ref& result) {
@ -330,7 +327,7 @@ namespace datalog {
return;
}
expr_ref_vector args(m);
if (!is_predicate(fml)) {
if (!m_ctx.is_predicate(fml)) {
return;
}
for (unsigned i = 0; i < fml->get_num_args(); ++i) {
@ -355,19 +352,19 @@ namespace datalog {
}
class contains_predicate_proc {
rule_manager const& m;
context const& ctx;
public:
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()(quantifier * 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 {
contains_predicate_proc proc(*this);
contains_predicate_proc proc(m_ctx);
try {
quick_for_each_expr(proc, fml);
}
@ -434,7 +431,7 @@ namespace datalog {
bool is_neg = (is_negated != 0 && is_negated[i]);
app * curr = tail[i];
if (is_neg && !is_predicate(curr)) {
if (is_neg && !m_ctx.is_predicate(curr)) {
curr = m.mk_not(curr);
is_neg = false;
}
@ -442,7 +439,7 @@ namespace datalog {
has_neg = true;
}
app * tail_entry = TAG(app *, curr, is_neg);
if (is_predicate(curr)) {
if (m_ctx.is_predicate(curr)) {
*uninterp_tail=tail_entry;
uninterp_tail++;
}
@ -755,7 +752,7 @@ namespace datalog {
void rule_manager::check_valid_head(expr * head) const {
SASSERT(head);
if (!is_predicate(head)) {
if (!m_ctx.is_predicate(head)) {
std::ostringstream out;
out << "Illegal head. The head predicate needs to be uninterpreted and registered (as recursive) " << mk_pp(head, m);
throw default_exception(out.str());
@ -966,7 +963,7 @@ namespace datalog {
if (is_neg_tail(i))
out << "not ";
app * t = get_tail(i);
if (ctx.get_rule_manager().is_predicate(t)) {
if (ctx.is_predicate(t)) {
output_predicate(ctx, t, out);
}
else {

View file

@ -32,6 +32,7 @@ namespace datalog {
class rule;
class rule_manager;
class rule_set;
class table;
class context;
@ -74,13 +75,11 @@ namespace datalog {
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_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);
@ -104,13 +103,13 @@ namespace datalog {
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.
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].
@ -166,11 +165,6 @@ namespace datalog {
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);
rule_counter& get_counter() { return m_counter; }

View file

@ -64,8 +64,7 @@ namespace datalog {
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);
dealloc(itm_set);
m_data.remove(key);
@ -109,7 +108,7 @@ namespace datalog {
void rule_dependencies::populate(rule const* r) {
TRACE("dl_verbose", tout << r->get_decl()->get_name() << "\n";);
m_visited.reset();
func_decl * d = r->get_head()->get_decl();
func_decl * d = r->get_decl();
func_decl_set & s = ensure_key(d);
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 rend = to_remove.end();
for (; rit!=rend; ++rit) {
for (; rit != rend; ++rit) {
remove_m_data_entry(*rit);
}
}
@ -173,7 +172,7 @@ namespace datalog {
remove_m_data_entry(itm);
iterator pit = begin();
iterator pend = end();
for (; pit!=pend; ++pit) {
for (; pit != pend; ++pit) {
item_set & itms = *pit->get_value();
itms.remove(itm);
}
@ -244,7 +243,7 @@ namespace datalog {
}
curr_index++;
}
if (res.size()<init_len+m_data.size()) {
if (res.size() < init_len + m_data.size()) {
res.shrink(init_len);
return false;
}
@ -283,17 +282,19 @@ namespace datalog {
m_rule_manager(ctx.get_rule_manager()),
m_rules(m_rule_manager),
m_deps(ctx),
m_stratifier(0) {
m_stratifier(0),
m_refs(ctx.get_manager()) {
}
rule_set::rule_set(const rule_set & rs)
: m_context(rs.m_context),
m_rule_manager(rs.m_rule_manager),
m_rules(m_rule_manager),
m_deps(rs.m_context),
m_stratifier(0) {
add_rules(rs);
if (rs.m_stratifier) {
rule_set::rule_set(const rule_set & other)
: m_context(other.m_context),
m_rule_manager(other.m_rule_manager),
m_rules(m_rule_manager),
m_deps(other.m_context),
m_stratifier(0),
m_refs(m_context.get_manager()) {
add_rules(other);
if (other.m_stratifier) {
VERIFY(close());
}
}
@ -303,18 +304,67 @@ namespace datalog {
}
void rule_set::reset() {
if (m_stratifier) {
m_stratifier = 0;
}
m_rules.reset();
reset_dealloc_values(m_head2rules);
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 {
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) {
TRACE("dl_verbose", r->display(m_context, tout << "add:"););
SASSERT(!is_closed());
@ -329,7 +379,7 @@ namespace datalog {
void rule_set::del_rule(rule * r) {
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);
#define DEL_VECTOR(_v) \
for (unsigned i = (_v).size(); i > 0; ) { \
@ -345,32 +395,26 @@ namespace datalog {
DEL_VECTOR(m_rules);
}
void rule_set::ensure_closed()
{
void rule_set::ensure_closed() {
if (!is_closed()) {
VERIFY(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_stratifier = alloc(rule_stratifier, m_deps);
if (!stratified_negation()) {
m_stratifier = 0;
m_deps.reset();
return false;
}
return true;
}
void rule_set::reopen() {
SASSERT(is_closed());
m_stratifier = 0;
m_deps.reset();
}
@ -401,18 +445,20 @@ namespace datalog {
return true;
}
void rule_set::add_rules(const rule_set & src) {
SASSERT(!is_closed());
unsigned n = src.get_num_rules();
for (unsigned i=0; i<n; i++) {
add_rule(src.get_rule(i));
void rule_set::replace_rules(const rule_set & src) {
if (this != &src) {
reset();
add_rules(src);
}
}
void rule_set::add_rules(unsigned sz, rule * const * rules) {
for (unsigned i=0; i<sz; i++) {
add_rule(rules[i]);
void rule_set::add_rules(const rule_set & src) {
SASSERT(!is_closed());
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 {
@ -433,6 +479,38 @@ namespace datalog {
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 {
out << "; rule count: " << get_num_rules() << "\n";
@ -451,17 +529,6 @@ namespace datalog {
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;
rule_manager & m_rule_manager;
rule_ref_vector m_rules; //!< all rules
decl2rules m_head2rules; //!< mapping from head symbol to rules.
rule_dependencies m_deps; //!< dependencies
scoped_ptr<rule_stratifier> m_stratifier; //!< contains stratifier object iff the rule_set is closed
rule_ref_vector m_rules; //!< all rules
decl2rules m_head2rules; //!< mapping from head symbol to rules.
rule_dependencies m_deps; //!< dependencies
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,
@ -184,6 +188,12 @@ namespace datalog {
rule_manager & get_rule_manager() const { return const_cast<rule_manager&>(m_rule_manager); }
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.
*/
@ -198,7 +208,7 @@ namespace datalog {
\brief Add all rules from a different rule_set.
*/
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.
@ -216,11 +226,14 @@ namespace datalog {
bool is_closed() const { return m_stratifier != 0; }
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 * last() const { return m_rules[m_rules.size()-1]; }
rule_ref_vector const& get_rules() const { return m_rules; }
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 {
SASSERT(m_stratifier);
@ -230,9 +243,17 @@ namespace datalog {
unsigned get_predicate_strat(func_decl * pred) const;
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 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;
/**

View file

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

@ -33,7 +33,7 @@ namespace datalog {
entry_storage::store_offset entry_storage::insert_or_get_reserve_content() {
SASSERT(has_reserve());
store_offset entry_ofs = m_data_indexer.insert_if_not_there(m_reserve);
if(m_reserve==entry_ofs) {
if (m_reserve == entry_ofs) {
//entry inserted, so reserve is no longer a reserve
m_reserve = NO_RESERVE;
}
@ -42,7 +42,7 @@ namespace datalog {
bool entry_storage::insert_reserve_content() {
SASSERT(has_reserve());
store_offset entry_ofs = m_data_indexer.insert_if_not_there(m_reserve);
if(m_reserve==entry_ofs) {
if (m_reserve == entry_ofs) {
//entry inserted, so reserve is no longer a reserve
m_reserve = NO_RESERVE;
return true;
@ -53,7 +53,7 @@ namespace datalog {
bool entry_storage::remove_reserve_content() {
SASSERT(has_reserve());
store_offset entry_ofs;
if(!find_reserve_content(entry_ofs)) {
if (!find_reserve_content(entry_ofs)) {
//the fact was not in the table
return false;
}
@ -64,8 +64,8 @@ namespace datalog {
void entry_storage::remove_offset(store_offset ofs) {
m_data_indexer.remove(ofs);
store_offset last_ofs = after_last_offset() - m_entry_size;
if(ofs!=last_ofs) {
SASSERT(ofs+m_entry_size<=last_ofs);
if (ofs!=last_ofs) {
SASSERT(ofs + m_entry_size <= last_ofs);
//we don't want any holes, so we put the last element at the place
//of the removed one
m_data_indexer.remove(last_ofs);
@ -73,7 +73,7 @@ namespace datalog {
memcpy(base+ofs, base+last_ofs, m_entry_size);
m_data_indexer.insert(ofs);
}
if(has_reserve()) {
if (has_reserve()) {
//we already have a reserve, so we need to shrink a little to keep having just one
resize_data(m_data_size-m_entry_size);
}
@ -98,20 +98,20 @@ namespace datalog {
unsigned length = 0;
unsigned dom_size_sm;
if(dom_size>UINT_MAX) {
if (dom_size>UINT_MAX) {
dom_size_sm = static_cast<unsigned>(dom_size>>32);
length += 32;
if( (dom_size&UINT_MAX)!=0 && dom_size_sm!=UINT_MAX ) {
if ( (dom_size&UINT_MAX)!=0 && dom_size_sm!=UINT_MAX ) {
dom_size_sm++;
}
}
else {
dom_size_sm=static_cast<unsigned>(dom_size);
}
if(dom_size_sm==1) {
if (dom_size_sm == 1) {
length += 1; //unary domains
}
else if(dom_size_sm>0x80000000u) {
else if (dom_size_sm > 0x80000000u) {
length += 32;
}
else {
@ -122,30 +122,30 @@ namespace datalog {
sparse_table::column_layout::column_layout(const table_signature & sig)
: m_functional_col_cnt(sig.functional_columns()) {
SASSERT(sig.size()>0);
SASSERT(sig.size() > 0);
unsigned ofs = 0;
unsigned sig_sz = sig.size();
unsigned first_functional = sig_sz-m_functional_col_cnt;
for(unsigned i=0; i<sig_sz; i++) {
for (unsigned i=0; i<sig_sz; i++) {
uint64 dom_size = sig[i];
unsigned length = get_domain_length(dom_size);
SASSERT(length>0);
SASSERT(length<=64);
if(size()>0 && (length>54 || i==first_functional)) {
if (size() > 0 && (length > 54 || i == first_functional)) {
//large domains must start byte-aligned, as well as functional columns
make_byte_aligned_end(size()-1);
ofs = back().next_ofs();
}
push_back(column_info(ofs, length));
ofs+=length;
ofs += length;
}
make_byte_aligned_end(size()-1);
SASSERT(back().next_ofs()%8==0);//the entries must be aligned to whole bytes
SASSERT(back().next_ofs()%8 == 0);//the entries must be aligned to whole bytes
m_entry_size = back().next_ofs()/8;
if(m_functional_col_cnt) {
SASSERT((*this)[first_functional].m_offset%8==0);
if (m_functional_col_cnt) {
SASSERT((*this)[first_functional].m_offset%8 == 0);
m_functional_part_size = m_entry_size - (*this)[first_functional].m_offset/8;
}
else {
@ -156,9 +156,9 @@ namespace datalog {
void sparse_table::column_layout::make_byte_aligned_end(unsigned col_index0) {
unsigned ofs = (*this)[col_index0].next_ofs();
unsigned ofs_bit_part = ofs%8;
unsigned rounded_ofs = (ofs_bit_part==0) ? ofs : (ofs+8-ofs_bit_part);
unsigned rounded_ofs = (ofs_bit_part == 0) ? ofs : (ofs+8-ofs_bit_part);
if(rounded_ofs!=ofs) {
if (rounded_ofs!=ofs) {
SASSERT(rounded_ofs>ofs);
int diff = rounded_ofs-ofs;
unsigned col_idx = col_index0+1;
@ -168,18 +168,18 @@ namespace datalog {
col_idx--;
column_info & ci = (*this)[col_idx];
unsigned new_length = ci.m_length;
if(ci.m_length<64) {
if (ci.m_length < 64) {
unsigned swallowed = std::min(64-static_cast<int>(ci.m_length), diff);
diff-=swallowed;
new_length+=swallowed;
diff -= swallowed;
new_length += swallowed;
}
unsigned new_ofs = ci.m_offset+diff;
ci = column_info(new_ofs, new_length);
}
}
SASSERT(rounded_ofs%8==0);
SASSERT((*this)[col_index0].next_ofs()%8==0);
SASSERT(rounded_ofs%8 == 0);
SASSERT((*this)[col_index0].next_ofs()%8 == 0);
}
// -----------------------------------
@ -218,7 +218,7 @@ namespace datalog {
m_layout(t.m_column_layout) {}
virtual bool is_finished() const {
return m_ptr==m_end;
return m_ptr == m_end;
}
virtual row_interface & operator*() {
@ -267,7 +267,7 @@ namespace datalog {
offset_iterator begin() const { return m_singleton ? &m_single_result : m_many.begin; }
offset_iterator end() const { return m_singleton ? (&m_single_result+1) : m_many.end; }
bool empty() const { return begin()==end(); }
bool empty() const { return begin() == end(); }
};
key_indexer(unsigned key_len, const unsigned * key_cols)
@ -299,7 +299,7 @@ namespace datalog {
key_to_reserve(key);
store_offset ofs = m_keys.insert_or_get_reserve_content();
index_map::entry * e = m_map.find_core(ofs);
if(!e) {
if (!e) {
TRACE("dl_table_relation", tout << "inserting\n";);
e = m_map.insert_if_not_there2(ofs, offset_vector());
}
@ -312,7 +312,7 @@ namespace datalog {
m_first_nonindexed(0) {}
virtual void update(const sparse_table & t) {
if(m_first_nonindexed==t.m_data.after_last_offset()) {
if (m_first_nonindexed == t.m_data.after_last_offset()) {
return;
}
SASSERT(m_first_nonindexed<t.m_data.after_last_offset());
@ -330,16 +330,16 @@ namespace datalog {
DEBUG_CODE( index_entry = 0; );
bool key_modified = true;
for(; ofs!=after_last; ofs+=t.m_fact_size) {
for(unsigned i=0; i<key_len; i++) {
for (; ofs!=after_last; ofs+=t.m_fact_size) {
for (unsigned i=0; i<key_len; i++) {
table_element col_val = t.get_cell(ofs, m_key_cols[i]);
if(key[i]!=col_val) {
if (key[i]!=col_val) {
key[i] = col_val;
key_modified = true;
}
}
if(key_modified) {
if (key_modified) {
index_entry = &get_matching_offset_vector(key);
key_modified = false;
}
@ -354,11 +354,11 @@ namespace datalog {
virtual query_result get_matching_offsets(const key_value & key) const {
key_to_reserve(key);
store_offset ofs;
if(!m_keys.find_reserve_content(ofs)) {
if (!m_keys.find_reserve_content(ofs)) {
return query_result();
}
index_map::entry * e = m_map.find_core(ofs);
if(!e) {
if (!e) {
return query_result();
}
const offset_vector & res = e->get_data().m_value;
@ -381,15 +381,15 @@ namespace datalog {
static bool can_handle(unsigned key_len, const unsigned * key_cols, const sparse_table & t) {
unsigned non_func_cols = t.get_signature().first_functional();
if(key_len!=non_func_cols) {
if (key_len!=non_func_cols) {
return false;
}
counter ctr;
ctr.count(key_len, key_cols);
if(ctr.get_max_counter_value()!=1 || ctr.get_max_positive()!=non_func_cols-1) {
if (ctr.get_max_counter_value()!=1 || ctr.get_max_positive()!=non_func_cols-1) {
return false;
}
SASSERT(ctr.get_positive_count()==non_func_cols);
SASSERT(ctr.get_positive_count() == non_func_cols);
return true;
}
@ -399,7 +399,7 @@ namespace datalog {
SASSERT(can_handle(key_len, key_cols, t));
m_permutation.resize(key_len);
for(unsigned i=0; i<key_len; i++) {
for (unsigned i=0; i<key_len; i++) {
//m_permutation[m_key_cols[i]] = i;
m_permutation[i] = m_key_cols[i];
}
@ -410,7 +410,7 @@ namespace datalog {
virtual query_result get_matching_offsets(const key_value & key) const {
unsigned key_len = m_key_cols.size();
for(unsigned i=0; i<key_len; i++) {
for (unsigned i=0; i<key_len; i++) {
m_key_fact[m_permutation[i]] = key[i];
}
//We will change the content of the reserve; which does not change the 'high-level'
@ -419,7 +419,7 @@ namespace datalog {
t.write_into_reserve(m_key_fact.c_ptr());
store_offset res;
if(!t.m_data.find_reserve_content(res)) {
if (!t.m_data.find_reserve_content(res)) {
return query_result();
}
return query_result(res);
@ -466,14 +466,14 @@ namespace datalog {
//without having to worry about updating indexes.
//Maybe we might keep a list of indexes that contain functional columns and on an update reset
//only those.
SASSERT(key_len==0 ||
SASSERT(key_len == 0 ||
counter().count(key_len, key_cols).get_max_positive()<get_signature().first_functional());
#endif
key_spec kspec;
kspec.append(key_len, key_cols);
key_index_map::entry * key_map_entry = m_key_indexes.insert_if_not_there2(kspec, 0);
if(!key_map_entry->get_data().m_value) {
if(full_signature_key_indexer::can_handle(key_len, key_cols, *this)) {
if (!key_map_entry->get_data().m_value) {
if (full_signature_key_indexer::can_handle(key_len, key_cols, *this)) {
key_map_entry->get_data().m_value = alloc(full_signature_key_indexer, key_len, key_cols, *this);
}
else {
@ -488,7 +488,7 @@ namespace datalog {
void sparse_table::reset_indexes() {
key_index_map::iterator kmit = m_key_indexes.begin();
key_index_map::iterator kmend = m_key_indexes.end();
for(; kmit!=kmend; ++kmit) {
for (; kmit!=kmend; ++kmit) {
dealloc((*kmit).m_value);
}
m_key_indexes.reset();
@ -499,13 +499,8 @@ namespace datalog {
m_data.ensure_reserve();
char * reserve = m_data.get_reserve_ptr();
unsigned col_cnt = m_column_layout.size();
for(unsigned i=0; i<col_cnt; i++) {
if (f[i] >= get_signature()[i]) {
std::cout << "***************************\n";
std::cout << f[i] << " " << get_signature()[i] << "\n";
} //the value fits into the table signature
SASSERT(f[i]<get_signature()[i]); //the value fits into the table signature
for (unsigned i = 0; i < col_cnt; ++i) {
SASSERT(f[i] < get_signature()[i]); //the value fits into the table signature
m_column_layout.set(reserve, i, f[i]);
}
}
@ -528,17 +523,17 @@ namespace datalog {
sparse_table & t = const_cast<sparse_table &>(*this);
t.write_into_reserve(f.c_ptr());
unsigned func_col_cnt = get_signature().functional_columns();
if(func_col_cnt==0) {
if (func_col_cnt == 0) {
return t.m_data.reserve_content_already_present();
}
else {
store_offset ofs;
if(!t.m_data.find_reserve_content(ofs)) {
if (!t.m_data.find_reserve_content(ofs)) {
return false;
}
unsigned sz = get_signature().size();
for(unsigned i=func_col_cnt; i<sz; i++) {
if(t.get_cell(ofs, i)!=f[i]) {
for (unsigned i=func_col_cnt; i<sz; i++) {
if (t.get_cell(ofs, i)!=f[i]) {
return false;
}
}
@ -548,19 +543,19 @@ namespace datalog {
bool sparse_table::fetch_fact(table_fact & f) const {
const table_signature & sig = get_signature();
SASSERT(f.size()==sig.size());
if(sig.functional_columns()==0) {
SASSERT(f.size() == sig.size());
if (sig.functional_columns() == 0) {
return contains_fact(f);
}
else {
sparse_table & t = const_cast<sparse_table &>(*this);
t.write_into_reserve(f.c_ptr());
store_offset ofs;
if(!t.m_data.find_reserve_content(ofs)) {
if (!t.m_data.find_reserve_content(ofs)) {
return false;
}
unsigned sz = sig.size();
for(unsigned i=sig.first_functional(); i<sz; i++) {
for (unsigned i=sig.first_functional(); i<sz; i++) {
f[i] = t.get_cell(ofs, i);
}
return true;
@ -573,18 +568,18 @@ namespace datalog {
*/
void sparse_table::ensure_fact(const table_fact & f) {
const table_signature & sig = get_signature();
if(sig.functional_columns()==0) {
if (sig.functional_columns() == 0) {
add_fact(f);
}
else {
write_into_reserve(f.c_ptr());
store_offset ofs;
if(!m_data.find_reserve_content(ofs)) {
if (!m_data.find_reserve_content(ofs)) {
add_fact(f);
return;
}
unsigned sz = sig.size();
for(unsigned i=sig.first_functional(); i<sz; i++) {
for (unsigned i=sig.first_functional(); i<sz; i++) {
set_cell(ofs, i, f[i]);
}
}
@ -593,7 +588,7 @@ namespace datalog {
void sparse_table::remove_fact(const table_element* f) {
//first insert the fact so that we find it's original location and remove it
write_into_reserve(f);
if(!m_data.remove_reserve_content()) {
if (!m_data.remove_reserve_content()) {
//the fact was not in the table
return;
}
@ -603,8 +598,8 @@ namespace datalog {
void sparse_table::copy_columns(const column_layout & src_layout, const column_layout & dest_layout,
unsigned start_index, unsigned after_last, const char * src, char * dest,
unsigned & dest_idx, unsigned & pre_projection_idx, const unsigned * & next_removed) {
for(unsigned i=start_index; i<after_last; i++, pre_projection_idx++) {
if(*next_removed==pre_projection_idx) {
for (unsigned i=start_index; i<after_last; i++, pre_projection_idx++) {
if (*next_removed == pre_projection_idx) {
next_removed++;
continue;
}
@ -658,18 +653,18 @@ namespace datalog {
tout << (&t1) << " " << (&t2) << " " << (&result) << "\n";
);
if(joined_col_cnt==0) {
if (joined_col_cnt == 0) {
unsigned t2idx = 0;
unsigned t2end = t2.m_data.after_last_offset();
for(; t1idx!=t1end; t1idx+=t1_entry_size) {
for(t2idx = 0; t2idx != t2end; t2idx += t2_entry_size) {
for (; t1idx!=t1end; t1idx+=t1_entry_size) {
for (t2idx = 0; t2idx != t2end; t2idx += t2_entry_size) {
result.m_data.ensure_reserve();
result.garbage_collect();
char * res_reserve = result.m_data.get_reserve_ptr();
char const* t1ptr = t1.get_at_offset(t1idx);
char const* t2ptr = t2.get_at_offset(t2idx);
if(tables_swapped) {
if (tables_swapped) {
concatenate_rows(t2.m_column_layout, t1.m_column_layout, result.m_column_layout,
t2ptr, t1ptr, res_reserve, removed_cols);
} else {
@ -689,34 +684,34 @@ namespace datalog {
bool key_modified = true;
key_indexer::query_result t2_offsets;
for(; t1idx != t1end; t1idx += t1_entry_size) {
for(unsigned i = 0; i < joined_col_cnt; i++) {
for (; t1idx != t1end; t1idx += t1_entry_size) {
for (unsigned i = 0; i < joined_col_cnt; i++) {
table_element val = t1.m_column_layout.get(t1.get_at_offset(t1idx), t1_joined_cols[i]);
TRACE("dl_table_relation", tout << "val: " << val << " " << t1idx << " " << t1_joined_cols[i] << "\n";);
if(t1_key[i] != val) {
if (t1_key[i] != val) {
t1_key[i] = val;
key_modified = true;
}
}
if(key_modified) {
if (key_modified) {
t2_offsets = t2_indexer.get_matching_offsets(t1_key);
key_modified = false;
}
if(t2_offsets.empty()) {
if (t2_offsets.empty()) {
continue;
}
key_indexer::offset_iterator t2ofs_it = t2_offsets.begin();
key_indexer::offset_iterator t2ofs_end = t2_offsets.end();
for(; t2ofs_it != t2ofs_end; ++t2ofs_it) {
for (; t2ofs_it != t2ofs_end; ++t2ofs_it) {
store_offset t2ofs = *t2ofs_it;
result.m_data.ensure_reserve();
result.garbage_collect();
char * res_reserve = result.m_data.get_reserve_ptr();
char const * t1ptr = t1.get_at_offset(t1idx);
char const * t2ptr = t2.get_at_offset(t2ofs);
if(tables_swapped) {
if (tables_swapped) {
concatenate_rows(t2.m_column_layout, t1.m_column_layout, result.m_column_layout,
t2ptr, t1ptr, res_reserve, removed_cols);
} else {
@ -745,11 +740,11 @@ namespace datalog {
void sparse_table_plugin::reset() {
table_pool::iterator it = m_pool.begin();
table_pool::iterator end = m_pool.end();
for(; it!=end; ++it) {
for (; it!=end; ++it) {
sp_table_vector * vect = it->m_value;
sp_table_vector::iterator it = vect->begin();
sp_table_vector::iterator end = vect->end();
for(; it!=end; ++it) {
for (; it!=end; ++it) {
(*it)->destroy(); //calling deallocate() would only put the table back into the pool
}
dealloc(vect);
@ -769,7 +764,7 @@ namespace datalog {
table_pool::entry * e = m_pool.insert_if_not_there2(sig, 0);
sp_table_vector * & vect = e->get_data().m_value;
if(vect==0) {
if (vect == 0) {
vect = alloc(sp_table_vector);
}
IF_VERBOSE(12, verbose_stream() << "Recycle: " << t->get_size_estimate_bytes() << "\n";);
@ -781,7 +776,7 @@ namespace datalog {
SASSERT(can_handle_signature(s));
sp_table_vector * vect;
if(!m_pool.find(s, vect) || vect->empty()) {
if (!m_pool.find(s, vect) || vect->empty()) {
return alloc(sparse_table, *this, s);
}
sparse_table * res = vect->back();
@ -798,7 +793,7 @@ namespace datalog {
bool sparse_table_plugin::join_involves_functional(const table_signature & s1, const table_signature & s2,
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) {
if(col_cnt==0) {
if (col_cnt == 0) {
return false;
}
return counter().count(col_cnt, cols1).get_max_positive()>=s1.first_functional()
@ -829,7 +824,7 @@ namespace datalog {
//do indexing into the bigger one. If we simply do a product, we want the bigger
//one to be at the outer iteration (then the small one will hopefully fit into
//the cache)
if( (t1.row_count() > t2.row_count()) == (!m_cols1.empty()) ) {
if ( (t1.row_count() > t2.row_count()) == (!m_cols1.empty()) ) {
sparse_table::self_agnostic_join_project(t2, t1, m_cols1.size(), m_cols2.c_ptr(),
m_cols1.c_ptr(), m_removed_cols.c_ptr(), true, *res);
}
@ -846,7 +841,7 @@ namespace datalog {
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) {
const table_signature & sig1 = t1.get_signature();
const table_signature & sig2 = t2.get_signature();
if(t1.get_kind()!=get_kind() || t2.get_kind()!=get_kind()
if (t1.get_kind()!=get_kind() || t2.get_kind()!=get_kind()
|| join_involves_functional(sig1, sig2, col_cnt, cols1, cols2)) {
//We also don't allow indexes on functional columns (and they are needed for joins)
return 0;
@ -859,8 +854,8 @@ namespace datalog {
const unsigned * removed_cols) {
const table_signature & sig1 = t1.get_signature();
const table_signature & sig2 = t2.get_signature();
if(t1.get_kind()!=get_kind() || t2.get_kind()!=get_kind()
|| removed_col_cnt==t1.get_signature().size()+t2.get_signature().size()
if (t1.get_kind()!=get_kind() || t2.get_kind()!=get_kind()
|| removed_col_cnt == t1.get_signature().size()+t2.get_signature().size()
|| join_involves_functional(sig1, sig2, col_cnt, cols1, cols2)) {
//We don't allow sparse tables with zero signatures (and project on all columns leads to such)
//We also don't allow indexes on functional columns.
@ -881,8 +876,8 @@ namespace datalog {
unsigned fact_size = tgt.m_fact_size;
const char* ptr = src.m_data.begin();
const char* after_last=src.m_data.after_last();
for(; ptr<after_last; ptr+=fact_size) {
if(tgt.add_fact(ptr) && delta) {
for (; ptr<after_last; ptr+=fact_size) {
if (tgt.add_fact(ptr) && delta) {
delta->add_fact(ptr);
}
}
@ -891,7 +886,7 @@ namespace datalog {
table_union_fn * sparse_table_plugin::mk_union_fn(const table_base & tgt, const table_base & src,
const table_base * delta) {
if(tgt.get_kind()!=get_kind() || src.get_kind()!=get_kind()
if (tgt.get_kind()!=get_kind() || src.get_kind()!=get_kind()
|| (delta && delta->get_kind()!=get_kind())
|| tgt.get_signature()!=src.get_signature()
|| (delta && delta->get_signature()!=tgt.get_signature())) {
@ -918,8 +913,8 @@ namespace datalog {
const sparse_table::column_layout & tgt_layout) {
unsigned r_idx=0;
unsigned tgt_i=0;
for(unsigned i=0; i<m_inp_col_cnt; i++) {
if(r_idx!=m_removed_col_cnt && i==m_removed_cols[r_idx]) {
for (unsigned i=0; i<m_inp_col_cnt; i++) {
if (r_idx!=m_removed_col_cnt && i == m_removed_cols[r_idx]) {
SASSERT(r_idx<m_removed_col_cnt);
r_idx++;
continue;
@ -927,8 +922,8 @@ namespace datalog {
tgt_layout.set(tgt, tgt_i, src_layout.get(src, i));
tgt_i++;
}
SASSERT(tgt_i==m_result_col_cnt);
SASSERT(r_idx==m_removed_col_cnt);
SASSERT(tgt_i == m_result_col_cnt);
SASSERT(r_idx == m_removed_col_cnt);
}
virtual table_base * operator()(const table_base & tb) {
@ -944,7 +939,7 @@ namespace datalog {
const char* t_ptr = t.m_data.begin();
const char* t_end = t.m_data.after_last();
for(; t_ptr!=t_end; t_ptr+=t_fact_size) {
for (; t_ptr!=t_end; t_ptr+=t_fact_size) {
SASSERT(t_ptr<t_end);
res->m_data.ensure_reserve();
char * res_ptr = res->m_data.get_reserve_ptr();
@ -957,7 +952,7 @@ namespace datalog {
table_transformer_fn * sparse_table_plugin::mk_project_fn(const table_base & t, unsigned col_cnt,
const unsigned * removed_cols) {
if(col_cnt==t.get_signature().size()) {
if (col_cnt == t.get_signature().size()) {
return 0;
}
return alloc(project_fn, t.get_signature(), col_cnt, removed_cols);
@ -986,14 +981,14 @@ namespace datalog {
sparse_table::key_indexer & indexer = t.get_key_indexer(1, &m_col);
sparse_table::key_indexer::query_result t_offsets = indexer.get_matching_offsets(m_key);
if(t_offsets.empty()) {
if (t_offsets.empty()) {
//no matches
return res;
}
sparse_table::key_indexer::offset_iterator ofs_it=t_offsets.begin();
sparse_table::key_indexer::offset_iterator ofs_end=t_offsets.end();
for(; ofs_it!=ofs_end; ++ofs_it) {
for (; ofs_it!=ofs_end; ++ofs_it) {
sparse_table::store_offset t_ofs = *ofs_it;
const char * t_ptr = t.get_at_offset(t_ofs);
@ -1001,8 +996,8 @@ namespace datalog {
char * res_reserve = res->m_data.get_reserve_ptr();
unsigned res_i = 0;
for(unsigned i=0; i<t_cols; i++) {
if(i==m_col) {
for (unsigned i=0; i<t_cols; i++) {
if (i == m_col) {
continue;
}
res_layout.set(res_reserve, res_i++, t_layout.get(t_ptr, i));
@ -1015,7 +1010,7 @@ namespace datalog {
table_transformer_fn * sparse_table_plugin::mk_select_equal_and_project_fn(const table_base & t,
const table_element & value, unsigned col) {
if(t.get_kind()!=get_kind() || t.get_signature().size()==1 || col>=t.get_signature().first_functional()) {
if (t.get_kind()!=get_kind() || t.get_signature().size() == 1 || col>=t.get_signature().first_functional()) {
//We don't allow sparse tables with zero signatures (and project on a single
//column table produces one).
//We also don't allow indexes on functional columns. And our implementation of
@ -1036,11 +1031,11 @@ namespace datalog {
m_cycle_len(permutation_cycle_len), m_col_cnt(orig_sig.size()) {
SASSERT(permutation_cycle_len>=2);
idx_set cycle_cols;
for(unsigned i=0; i<m_cycle_len; i++) {
for (unsigned i=0; i<m_cycle_len; i++) {
cycle_cols.insert(permutation_cycle[i]);
}
for(unsigned i=0; i<m_col_cnt; i++) {
if(!cycle_cols.contains(i)) {
for (unsigned i=0; i<m_col_cnt; i++) {
if (!cycle_cols.contains(i)) {
m_out_of_cycle.push_back(i);
}
}
@ -1050,14 +1045,14 @@ namespace datalog {
const sparse_table::column_layout & src_layout,
const sparse_table::column_layout & tgt_layout) {
for(unsigned i=1; i<m_cycle_len; i++) {
for (unsigned i=1; i<m_cycle_len; i++) {
tgt_layout.set(tgt, m_cycle[i-1], src_layout.get(src, m_cycle[i]));
}
tgt_layout.set(tgt, m_cycle[m_cycle_len-1], src_layout.get(src, m_cycle[0]));
unsigned_vector::const_iterator it = m_out_of_cycle.begin();
unsigned_vector::const_iterator end = m_out_of_cycle.end();
for(; it!=end; ++it) {
for (; it!=end; ++it) {
unsigned col = *it;
tgt_layout.set(tgt, col, src_layout.get(src, col));
}
@ -1084,12 +1079,12 @@ namespace datalog {
const char* t_ptr = t.m_data.begin();
char* res_ptr = res->m_data.begin();
char* res_end = res_ptr+res_data_size;
for(; res_ptr!=res_end; t_ptr+=t_fact_size, res_ptr+=res_fact_size) {
for (; res_ptr!=res_end; t_ptr+=t_fact_size, res_ptr+=res_fact_size) {
transform_row(t_ptr, res_ptr, t.m_column_layout, res->m_column_layout);
}
//and insert them into the hash-map
for(unsigned i=0; i!=res_data_size; i+=res_fact_size) {
for (unsigned i=0; i!=res_data_size; i+=res_fact_size) {
TRUSTME(res->m_data.insert_offset(i));
}
@ -1099,7 +1094,7 @@ namespace datalog {
table_transformer_fn * sparse_table_plugin::mk_rename_fn(const table_base & t, unsigned permutation_cycle_len,
const unsigned * permutation_cycle) {
if(t.get_kind()!=get_kind()) {
if (t.get_kind()!=get_kind()) {
return 0;
}
return alloc(rename_fn, t.get_signature(), permutation_cycle_len, permutation_cycle);
@ -1125,9 +1120,9 @@ namespace datalog {
unsigned neg_fisrt_func = neg.get_signature().first_functional();
counter ctr;
ctr.count(m_cols2);
m_joining_neg_non_functional = ctr.get_max_counter_value()==1
&& ctr.get_positive_count()==neg_fisrt_func
&& (neg_fisrt_func==0 || ctr.get_max_positive()==neg_fisrt_func-1);
m_joining_neg_non_functional = ctr.get_max_counter_value() == 1
&& ctr.get_positive_count() == neg_fisrt_func
&& (neg_fisrt_func == 0 || ctr.get_max_positive() == neg_fisrt_func-1);
}
/**
@ -1138,7 +1133,7 @@ namespace datalog {
bool tgt_is_first, svector<store_offset> & res) {
SASSERT(res.empty());
if(!tgt_is_first) {
if (!tgt_is_first) {
m_intersection_content.reset();
}
@ -1155,32 +1150,32 @@ namespace datalog {
bool key_modified=true;
key_indexer::query_result t2_offsets;
store_offset t1_after_last = t1.m_data.after_last_offset();
for(store_offset t1_ofs=0; t1_ofs<t1_after_last; t1_ofs+=t1_entry_size) {
for (store_offset t1_ofs=0; t1_ofs<t1_after_last; t1_ofs+=t1_entry_size) {
for(unsigned i=0; i<joined_col_cnt; i++) {
for (unsigned i=0; i<joined_col_cnt; i++) {
table_element val = t1.get_cell(t1_ofs, cols1[i]);
if(t1_key[i]!=val) {
if (t1_key[i]!=val) {
t1_key[i]=val;
key_modified=true;
}
}
if(key_modified) {
if (key_modified) {
t2_offsets = t2_indexer.get_matching_offsets(t1_key);
key_modified=false;
}
if(t2_offsets.empty()) {
if (t2_offsets.empty()) {
continue;
}
if(tgt_is_first) {
if (tgt_is_first) {
res.push_back(t1_ofs);
}
else {
key_indexer::offset_iterator it = t2_offsets.begin();
key_indexer::offset_iterator end = t2_offsets.end();
for(; it!=end; ++it) {
for (; it!=end; ++it) {
store_offset ofs = *it;
if(!m_intersection_content.contains(ofs)) {
if (!m_intersection_content.contains(ofs)) {
m_intersection_content.insert(ofs);
res.push_back(ofs);
}
@ -1188,7 +1183,7 @@ namespace datalog {
}
}
if(!tgt_is_first) {
if (!tgt_is_first) {
//in this case \c res now may be in arbitrary order
std::sort(res.begin(), res.end());
}
@ -1198,8 +1193,8 @@ namespace datalog {
sparse_table & tgt = static_cast<sparse_table &>(tgt0);
const sparse_table & neg = static_cast<const sparse_table &>(neg0);
if(m_cols1.size()==0) {
if(!neg.empty()) {
if (m_cols1.size() == 0) {
if (!neg.empty()) {
tgt.reset();
}
return;
@ -1209,14 +1204,14 @@ namespace datalog {
//We don't do just the simple tgt.row_count()>neg.row_count() because the swapped case is
//more expensive. The constant 4 is, however, just my guess what the ratio might be.
if(tgt.row_count()/4>neg.row_count()) {
if (tgt.row_count()/4>neg.row_count()) {
collect_intersection_offsets(neg, tgt, false, to_remove);
}
else {
collect_intersection_offsets(tgt, neg, true, to_remove);
}
if(to_remove.empty()) {
if (to_remove.empty()) {
return;
}
@ -1234,7 +1229,7 @@ namespace datalog {
table_intersection_filter_fn * sparse_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)
if (!check_kind(t) || !check_kind(negated_obj)
|| join_involves_functional(t.get_signature(), negated_obj.get_signature(), joined_col_cnt,
t_cols, negated_cols) ) {
return 0;

View file

@ -1,311 +0,0 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
fdd.cpp
Abstract:
Finite decision diagram trie.
Author:
Nikolaj Bjorner (nbjorner) 2013-07-03.
Revision History:
--*/
#include "fdd.h"
#include "hash.h"
#include "bit_vector.h"
#include "trace.h"
#define OFFSET_OF(th, ty, field) (unsigned char*)(&((ty*)(th))->field) - (unsigned char*)(ty*)(th)
using namespace fdd;
unsigned node::get_hash() const {
return string_hash((char*)this, static_cast<unsigned>(OFFSET_OF(this, node, m_ref_count)), 11);
}
bool node::operator==(node const& other) const {
return
m_var == other.m_var &&
m_lo == other.m_lo &&
m_hi == other.m_hi;
}
// ------------------------------------------
// manager
manager::manager() :
m_alloc_node(2),
m_false(0),
m_true(1),
m_root(m_false)
{
m_nodes.push_back(node()); // false
m_nodes.push_back(node()); // true
inc_ref(m_false);
inc_ref(m_true);
alloc_node(); // pre-allocate a node.
}
manager::~manager() {
}
void manager::alloc_node() {
unsigned index;
while (!m_free.empty()) {
index = m_free.back();
node& n = m_nodes[index];
m_free.pop_back();
if (n.get_ref_count() == 0) {
if (!is_leaf(n.lo())) {
m_free.push_back(n.lo());
}
if (!is_leaf(n.hi())) {
m_free.push_back(n.hi());
}
m_alloc_node = index;
m_table.erase(n);
return;
}
}
index = m_nodes.size();
m_nodes.push_back(node());
m_alloc_node = index;
}
node_id manager::mk_node(unsigned var, node_id lo, node_id hi) {
if (lo == hi) {
return lo;
}
node n(var, lo, hi);
unsigned index = m_alloc_node;
node_id result = m_table.insert_if_not_there(n, index).m_value;
if (result == index) {
alloc_node();
m_nodes[result] = n;
inc_ref(lo);
inc_ref(hi);
}
TRACE("fdd", tout << "mk_node: " << var << " " << lo << " " << hi << " -> " << result << "\n";);
return result;
}
void manager::inc_ref(node_id n) {
TRACE("fdd", tout << "incref: " << n << "\n";);
if (!is_leaf(n)) {
m_nodes[n].inc_ref();
}
}
void manager::dec_ref(node_id n) {
if (!is_leaf(n) && 0 == m_nodes[n].dec_ref()) {
m_free.push_back(n);
}
}
void manager::setup_keys(Key const* keys) {
for (unsigned i = 0; i < m_num_keys; ++i) {
m_keys[i] = (uint64)keys[i];
m_sign[i] = keys[i] < 0;
}
}
void manager::insert(Key const* keys) {
setup_keys(keys);
m_insert_cache.reset();
node_id result = insert_sign(m_num_idx + m_num_keys, m_root);
inc_ref(result);
dec_ref(m_root);
m_root = result;
}
node_id manager::insert_sign(unsigned idx, node_id n) {
if (idx > m_num_idx) {
--idx;
bool s = idx2sign(idx);
node nd = m_nodes[n];
if (!is_leaf(n) && nd.var() == idx) {
if (s) {
return mk_node(idx, insert_sign(idx, nd.lo()), nd.hi());
}
else {
return mk_node(idx, nd.lo(), insert_sign(idx, nd.hi()));
}
}
else {
if (s) {
return mk_node(idx, insert_sign(idx, n), n);
}
else {
return mk_node(idx, n, insert_sign(idx, n));
}
}
}
SASSERT(m_num_idx == idx);
return insert(idx, n);
}
node_id manager::insert(unsigned idx, node_id n) {
node_id result;
SASSERT(0 <= idx && idx <= m_num_idx);
TRACE("fdd", tout << "insert: " << idx << " " << n << "\n";);
if (is_leaf(n)) {
while (idx > 0) {
--idx;
if (idx2bit(idx) && !is_dont_care(idx2key(idx))) {
return mk_node(idx, n, insert(idx, n));
}
}
return m_true;
}
SASSERT(0 < idx);
--idx;
config c(m_dont_cares, idx, n);
if (m_insert_cache.find(c, result)) {
return result;
}
node nd = m_nodes[n];
SASSERT(idx >= nd.var());
while (idx > nd.var()) {
if (idx2bit(idx) && !is_dont_care(idx2key(idx))) {
return mk_node(idx, n, insert(idx, n));
}
--idx;
}
SASSERT(nd.var() == idx);
unsigned key = idx2key(idx);
if (is_dont_care(key)) {
result = mk_node(idx, insert(idx, nd.lo()), insert(idx, nd.hi()));
}
else {
bool bit = idx2bit(idx);
node_id lo, hi;
if (bit) {
hi = insert(idx, nd.hi());
lo = nd.lo();
}
else {
lo = insert(idx, nd.lo());
scoped_dont_cares _set(*this, key);
hi = insert(idx, nd.hi());
}
result = mk_node(idx, lo, hi);
}
m_insert_cache.insert(c, result);
return result;
}
void manager::set_dont_care(unsigned key) {
SASSERT(!is_dont_care(key));
m_dont_cares |= (1ull << key);
}
void manager::unset_dont_care(unsigned key) {
m_dont_cares &= ~(1ull << key);
}
bool manager::is_dont_care(unsigned key) const {
return 0 != (m_dont_cares & (1ull << key));
}
void manager::collect_statistics(statistics& st) const {
st.update("fdd.num_nodes", m_nodes.size());
}
void manager::reset(unsigned num_keys) {
m_num_keys = num_keys;
m_num_idx = m_num_keys * m_num_bits;
m_dont_cares = 0;
m_sign.resize(num_keys);
m_keys.resize(num_keys);
SASSERT(num_keys <= 8*sizeof(m_dont_cares));
}
bool manager::find_le(Key const* keys) {
setup_keys(keys);
unsigned idx = m_num_idx + m_num_keys;
node_id n = m_root;
node nc = m_nodes[n];
while (n > 1 && idx > m_num_idx) {
--idx;
if (nc.var() == idx) {
if (idx2sign(idx)) {
n = nc.lo();
}
else {
n = nc.hi();
}
nc = m_nodes[n];
}
}
while (n > 1) {
SASSERT(idx > 0);
--idx;
while (nc.var() < idx) {
if (idx2bit(idx) && is_dont_care(idx2key(idx))) {
set_dont_care(idx2key(idx));
}
--idx;
}
SASSERT(nc.var() == idx);
if (is_dont_care(idx2key(idx)) || idx2bit(idx)) {
n = nc.hi();
}
else {
n = nc.lo();
}
nc = m_nodes[n];
}
m_dont_cares = 0;
return n == 1;
}
std::ostream& manager::display(std::ostream& out, node_id n) const{
svector<bool> mark;
svector<node_id> nodes;
nodes.push_back(n);
while (!nodes.empty()) {
n = nodes.back();
nodes.pop_back();
if (mark.size() <= n) {
mark.resize(n+1, false);
}
node const& nc = m_nodes[n];
if (is_leaf(n) || mark[n]) {
continue;
}
nodes.push_back(nc.lo());
nodes.push_back(nc.hi());
mark[n] = true;
if (nc.var() >= m_num_idx) {
out << n << " if " << idx2key(nc.var()) << " then " << nc.hi() << " else " << nc.lo() << "\n";
}
else {
out << n << " if " << idx2key(nc.var()) << ":" << idx2bitnum(nc.var()) << " then " << nc.hi() << " else " << nc.lo() << "\n";
}
}
return out;
}

View file

@ -1,173 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
fdd.h
Abstract:
Finite decision diagram.
Author:
Nikolaj Bjorner (nbjorner) 2013-07-03.
Revision History:
--*/
#ifndef __FDD_H__
#define __FDD_H__
#include "hashtable.h"
#include "hash.h"
#include "map.h"
#include "vector.h"
#include "statistics.h"
namespace fdd {
typedef unsigned node_id;
class node {
unsigned m_var;
node_id m_lo;
node_id m_hi;
unsigned m_ref_count;
void reset();
public:
node() : m_var(0), m_lo(0), m_hi(0), m_ref_count(0) {}
node(unsigned var, node_id l, node_id h): m_var(var), m_lo(l), m_hi(h), m_ref_count(0) {}
unsigned get_hash() const;
bool operator==(node const& other) const;
void inc_ref() { ++m_ref_count; }
unsigned dec_ref() { return --m_ref_count; }
unsigned get_ref_count() const { return m_ref_count; }
node_id lo() const { return m_lo; }
node_id hi() const { return m_hi; }
unsigned var() const { return m_var; }
struct hash { unsigned operator()(node const& n) const { return n.get_hash(); } };
struct eq { bool operator()(node const& l, node const& r) const { return l == r; } };
std::ostream& display(std::ostream& out) const { return out << m_var << " " << m_lo << " " << m_hi << ""; }
};
inline std::ostream& operator<<(std::ostream& out, node const& n) { return n.display(out); }
class config {
uint64 m_dont_cares;
unsigned m_idx;
node_id m_node;
public:
config(): m_dont_cares(0), m_idx(0), m_node(0) {}
config(uint64 dont_cares, unsigned idx, node_id n):
m_dont_cares(dont_cares),
m_idx(idx),
m_node(n)
{}
struct hash {
unsigned operator()(config const& c) const {
return string_hash((char*)&c, sizeof(c), 12);
};
};
struct eq {
bool operator()(config const& a, config const& b) const {
return
a.m_dont_cares == b.m_dont_cares &&
a.m_idx == b.m_idx &&
a.m_node == b.m_node;
}
};
};
class manager {
public:
typedef int64 Key;
typedef node::hash node_hash;
typedef node::eq node_eq;
typedef config::hash config_hash;
typedef config::eq config_eq;
private:
typedef map<node, unsigned, node_hash, node_eq> node_table;
typedef map<config, node_id, config_hash, config_eq> insert_cache;
node_table m_table;
insert_cache m_insert_cache;
svector<node> m_nodes;
unsigned_vector m_free;
unsigned m_alloc_node;
node_id m_false;
node_id m_true;
node_id m_root;
static const unsigned m_num_bits = 64;
unsigned m_num_keys;
unsigned m_num_idx; // = m_num_keys * m_num_bits
// state associated with insert.
svector<uint64> m_keys;
svector<bool> m_sign;
uint64 m_dont_cares;
public:
manager();
~manager();
void reset(unsigned num_keys);
void insert(Key const* keys);
bool find_le(Key const* keys);
void collect_statistics(statistics& st) const;
void reset_statistics() {}
unsigned size() const { return m_nodes.size(); }
void display(std::ostream& out) const { display(out, m_root); }
private:
void dec_ref(node_id n);
void inc_ref(node_id n);
node_id mk_node(unsigned var, node_id lo, node_id hi);
inline unsigned get_ref_count(node_id n) { return m_nodes[n].get_ref_count(); }
std::ostream& display(std::ostream& out, node_id n) const;
void setup_keys(Key const* keys);
node_id insert(unsigned idx, node_id n);
node_id insert_sign(unsigned idx, node_id n);
bool is_dont_care(unsigned idx) const;
void set_dont_care(unsigned key);
void unset_dont_care(unsigned key);
struct scoped_dont_cares {
manager& m;
unsigned m_key;
scoped_dont_cares(manager& m, unsigned key):m(m), m_key(key) { m.set_dont_care(key); }
~scoped_dont_cares() { m.unset_dont_care(m_key); }
};
void alloc_node();
unsigned idx2key(unsigned i) const { return i % m_num_keys; }
unsigned idx2bitnum(unsigned i) const { SASSERT(i < m_num_idx); return (i / m_num_keys); }
bool idx2bit(unsigned i) const { return 0 != (m_keys[idx2key(i)] & (1LL << idx2bitnum(i))); }
bool idx2sign(unsigned i) const { return m_sign[idx2key(i)]; }
bool is_leaf(node_id n) const { return n <= 1; }
};
};
#endif

View file

@ -13,6 +13,7 @@ def_module_params('fixedpoint',
('unbound_compressor', BOOL, True, "auxiliary relations will be introduced to avoid unbound variables in rule heads"),
('similarity_compressor', BOOL, True, "(DATALOG) rules that differ only in values of constants will be merged into a single rule"),
('similarity_compressor_threshold', UINT, 11, "(DATALOG) if similarity_compressor is on, this value determines how many similar rules there must be in order for them to be merged"),
('filter_rules', BOOL, True, "(DATALOG) apply filter compression on rules"),
('all_or_nothing_deltas', BOOL, False, "(DATALOG) compile rules so that it is enough for the delta relation in union and widening operations to determine only whether the updated relation was modified or not"),
('compile_with_widening', BOOL, False, "(DATALOG) widening will be used to compile recursive rules"),
('eager_emptiness_checking', BOOL, True, "(DATALOG) emptiness of affected relations will be checked after each instruction, so that we may ommit unnecessary instructions"),

View file

@ -21,7 +21,6 @@ Revision History:
#include "heap.h"
#include "map.h"
#include "heap_trie.h"
#include "fdd.h"
#include "stopwatch.h"
@ -237,64 +236,8 @@ public:
void display(std::ostream& out) const {
// m_trie.display(out);
}
};
class hilbert_basis::value_index3 {
hilbert_basis& hb;
fdd::manager m_fdd;
unsigned m_offset;
svector<int64> m_keys;
int64 const* get_keys(values const& vs) {
numeral const* nums = vs()-m_offset;
for (unsigned i = 0; i < m_keys.size(); ++i) {
m_keys[i] = nums[i].get_int64();
}
return m_keys.c_ptr();
}
public:
value_index3(hilbert_basis & hb): hb(hb), m_offset(1) {}
void insert(offset_t, values const& vs) {
m_fdd.insert(get_keys(vs));
}
bool find(offset_t, values const& vs) {
return m_fdd.find_le(get_keys(vs));
}
void reset(unsigned offset) {
m_offset = offset;
m_fdd.reset(hb.get_num_vars()+m_offset);
m_keys.resize(hb.get_num_vars()+m_offset);
}
void collect_statistics(statistics& st) const {
m_fdd.collect_statistics(st);
}
void reset_statistics() {
m_fdd.reset_statistics();
}
unsigned size() const {
return m_fdd.size();
}
void remove(offset_t idx, values const& vs) {
UNREACHABLE();
}
void display(std::ostream& out) const {
m_fdd.display(out);
}
};
class hilbert_basis::index {

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_rule.h"
#include "dl_rule_transformer.h"
#include "dl_mk_extract_quantifiers.h"
#include "smt2parser.h"
#include "pdr_context.h"
#include "pdr_dl_interface.h"
@ -33,7 +32,6 @@ Revision History:
#include "dl_mk_slice.h"
#include "dl_mk_unfold.h"
#include "dl_mk_coalesce.h"
#include "pdr_quantifiers.h"
using namespace pdr;
@ -57,41 +55,36 @@ dl_interface::~dl_interface() {
// re-use existing context.
//
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();
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;
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;
}
}
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_old_rules.reset();
m_old_rules.add_rules(new_rules.size(), new_rules.c_ptr());
m_old_rules.replace_rules(new_rules);
}
lbool dl_interface::query(expr * query) {
//we restore the initial state in the datalog context
m_ctx.ensure_opened();
m_pdr_rules.reset();
m_refs.reset();
m_pred2slice.reset();
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());
func_decl_ref query_pred(m);
datalog::rule_ref_vector query_rules(rule_manager);
datalog::rule_ref query_rule(rule_manager);
rule_manager.mk_query(query, query_pred, query_rules, query_rule);
m_ctx.add_rules(query_rules);
rm.mk_query(query, m_ctx.get_rules());
expr_ref bg_assertion = m_ctx.get_background_assertion();
check_reset();
@ -107,7 +100,6 @@ lbool dl_interface::query(expr * query) {
);
m_ctx.set_output_predicate(query_pred);
m_ctx.apply_default_transformation();
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);
transformer.register_plugin(slice);
m_ctx.transform_rules(transformer);
query_pred = slice->get_predicate(query_pred.get());
m_ctx.set_output_predicate(query_pred);
// track sliced predicates.
obj_map<func_decl, func_decl*> const& preds = slice->get_predicates();
@ -142,23 +132,14 @@ lbool dl_interface::query(expr * query) {
--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()););
m_pdr_rules.add_rules(m_ctx.get_rules());
m_pdr_rules.replace_rules(m_ctx.get_rules());
m_pdr_rules.close();
m_ctx.reopen();
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.
@ -173,20 +154,7 @@ lbool dl_interface::query(expr * query) {
return l_false;
}
lbool result;
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;
}
}
return m_context->solve();
}

View file

@ -132,7 +132,7 @@ namespace pdr {
for_each_expr(collect_decls, m_relation_info[i].m_body);
}
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) {
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

@ -34,7 +34,40 @@ Revision History:
#include"dl_table_relation.h"
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)
: m_context(ctx),
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(interval_relation_plugin, get_rmanager()));
get_rmanager().register_plugin(alloc(karr_relation_plugin, get_rmanager()));
}
}
rel_context::~rel_context() {
if (m_last_result_relation) {
@ -67,42 +98,25 @@ 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() {
m_context.ensure_closed();
bool time_limit = m_context.soft_timeout()!=0;
unsigned remaining_time_limit = m_context.soft_timeout();
unsigned restart_time = m_context.initial_restart_timeout();
rule_set original_rules(m_context.get_rules());
decl_set original_predicates;
m_context.collect_predicates(original_predicates);
unsigned restart_time = m_context.initial_restart_timeout();
scoped_query scoped_query(m_context);
instruction_block termination_code;
lbool result;
TRACE("dl", m_context.display(tout););
while (true) {
m_code.reset();
m_ectx.reset();
m_code.reset();
termination_code.reset();
m_context.ensure_closed();
m_context.transform_rules();
if (m_context.canceled()) {
result = l_undef;
@ -162,47 +176,20 @@ namespace datalog {
else {
restart_time = static_cast<unsigned>(new_restart_time);
}
termination_code.reset();
m_context.reopen();
restrict_predicates(original_predicates);
m_context.replace_rules(original_rules);
m_context.close();
scoped_query.reset();
}
m_context.reopen();
restrict_predicates(original_predicates);
m_context.record_transformed_rules();
m_context.replace_rules(original_rules);
m_context.close();
TRACE("dl", m_ectx.report_big_relations(100, tout););
m_code.process_all_costs();
m_code.make_annotations(m_ectx);
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) {
get_rmanager().reset_saturated_marks();
BEGIN_QUERY();
scoped_query _scoped_query(m_context);
for (unsigned i = 0; i < num_rels; ++i) {
set_output_predicate(rels[i]);
m_context.set_output_predicate(rels[i]);
}
m_context.close();
reset_negated_tables();
@ -237,27 +224,16 @@ namespace datalog {
case l_undef:
break;
}
END_QUERY();
return res;
}
lbool rel_context::query(expr* query) {
get_rmanager().reset_saturated_marks();
BEGIN_QUERY();
scoped_query _scoped_query(m_context);
rule_manager& rm = m_context.get_rule_manager();
rule_ref qrule(rm);
rule_ref_vector qrules(rm);
func_decl_ref query_pred(m);
try {
rm.mk_query(query, query_pred, qrules, qrule);
}
catch(default_exception& exn) {
m_context.close();
m_context.set_status(INPUT_ERROR);
throw exn;
}
try {
m_context.add_rules(qrules);
query_pred = rm.mk_query(query, m_context.get_rules());
}
catch (default_exception& exn) {
m_context.close();
@ -265,29 +241,17 @@ namespace datalog {
throw exn;
}
set_output_predicate(qrule->get_head()->get_decl());
m_context.close();
reset_negated_tables();
if (m_context.generate_explanations()) {
rule_transformer transformer(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();
m_context.transform_rules(alloc(mk_explanations, m_context));
}
query_pred = m_context.get_rules().get_pred(query_pred);
if (m_context.magic_sets_for_queries()) {
rule_transformer transformer(m_context);
transformer.register_plugin(alloc(mk_magic_sets, m_context, qrule.get()));
m_context.transform_rules(transformer);
m_context.transform_rules(alloc(mk_magic_sets, m_context, query_pred));
}
lbool res = saturate();
@ -303,7 +267,6 @@ namespace datalog {
}
}
END_QUERY();
return res;
}
@ -371,15 +334,8 @@ namespace datalog {
}
}
void rel_context::set_output_predicate(func_decl * pred) {
if (!m_output_preds.contains(pred)) {
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);
void rel_context::restrict_predicates(func_decl_set const& predicates) {
get_rmanager().restrict_predicates(predicates);
}
relation_base & rel_context::get_relation(func_decl * pred) { return get_rmanager().get_relation(pred); }
@ -514,8 +470,8 @@ namespace datalog {
}
}
void rel_context::display_output_facts(std::ostream & out) const {
get_rmanager().display_output_tables(out);
void rel_context::display_output_facts(rule_set const& rules, std::ostream & out) const {
get_rmanager().display_output_tables(rules, out);
}
void rel_context::display_facts(std::ostream& out) const {

View file

@ -37,11 +37,12 @@ namespace datalog {
relation_manager m_rmanager;
expr_ref m_answer;
relation_base * m_last_result_relation;
decl_set m_output_preds;
fact_vector m_table_facts;
execution_context m_ectx;
instruction_block m_code;
class scoped_query;
void reset_negated_tables();
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.
*/
void restrict_predicates(const decl_set & res);
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; }
void restrict_predicates(func_decl_set const& predicates);
/**
@ -107,7 +102,7 @@ namespace datalog {
*/
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_profile(std::ostream& out) const;

View file

@ -191,6 +191,7 @@ namespace tb {
unsigned get_index() const { return m_index; }
void set_index(unsigned index) { m_index = index; }
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; }
unsigned get_parent_index() const { return m_parent_index; }
unsigned get_parent_rule() const { return m_parent_rule; }
@ -447,7 +448,7 @@ namespace tb {
void insert(ref<clause>& g) {
unsigned idx = m_rules.size();
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());
SASSERT(e);
e->get_data().m_value.push_back(idx);
@ -613,7 +614,7 @@ namespace tb {
bool match_head(clause const& g) {
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) &&
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) {
qe_lite qe(m);
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());
m_S1.reserve(2, var_cnt);
if (!m_unifier(tgt.get_predicate(idx), src.get_head(), m_S1)) {
@ -1380,11 +1381,10 @@ namespace datalog {
m_displayed_rules.reset();
m_rules.init(m_ctx.get_rules());
m_selection.init(m_rules);
rule_ref_vector query_rules(rm);
rule_set query_rules(m_ctx);
rule_ref clause(rm);
func_decl_ref query_pred(m);
rm.mk_query(query, query_pred, query_rules, clause);
rm.mk_query(query, query_rules);
clause = query_rules.last();
ref<tb::clause> g = alloc(tb::clause, m);
g->init(clause);
g->set_head(m.mk_false());

View file

@ -1745,6 +1745,12 @@ namespace sat {
mark_lit(m_lemma[i]);
}
literal l0 = m_lemma[0];
// l0 is the FUIP, and we never remove the FUIP.
//
// In the following loop, we use unmark_lit(l) to remove a
// literal from m_lemma.
for (unsigned i = 0; i < sz; i++) {
literal l = m_lemma[i];
if (!is_marked_lit(l))
@ -1754,9 +1760,15 @@ namespace sat {
watch_list::const_iterator it = wlist.begin();
watch_list::const_iterator end = wlist.end();
for (; it != end; ++it) {
// In this for-loop, the conditions l0 != ~l2 and l0 != ~l3
// are not really needed if the solver does not miss unit propagations.
// However, we add them anyway because we don't want to rely on this
// property of the propagator.
// For example, if this property is relaxed in the future, then the code
// without the conditions l0 != ~l2 and l0 != ~l3 may remove the FUIP
if (it->is_binary_clause()) {
literal l2 = it->get_literal();
if (is_marked_lit(~l2)) {
if (is_marked_lit(~l2) && l0 != ~l2) {
// eliminate ~l2 from lemma because we have the clause l \/ l2
unmark_lit(~l2);
}
@ -1764,11 +1776,11 @@ namespace sat {
else if (it->is_ternary_clause()) {
literal l2 = it->get_literal1();
literal l3 = it->get_literal2();
if (is_marked_lit(l2) && is_marked_lit(~l3)) {
if (is_marked_lit(l2) && is_marked_lit(~l3) && l0 != ~l3) {
// eliminate ~l3 from lemma because we have the clause l \/ l2 \/ l3
unmark_lit(~l3);
}
else if (is_marked_lit(~l2) && is_marked_lit(l3)) {
else if (is_marked_lit(~l2) && is_marked_lit(l3) && l0 != ~l2) {
// eliminate ~l2 from lemma because we have the clause l \/ l2 \/ l3
unmark_lit(~l2);
}
@ -1786,7 +1798,41 @@ namespace sat {
literal_vector::iterator end = implied_lits->end();
for (; it != end; ++it) {
literal l2 = *it;
if (is_marked_lit(~l2)) {
// Here, we must check l0 != ~l2.
// l \/ l2 is an implied binary clause.
// However, it may have been deduced using a lemma that has been deleted.
// For example, consider the following sequence of events:
//
// 1. Initial clause database:
//
// l \/ ~p1
// p1 \/ ~p2
// p2 \/ ~p3
// p3 \/ ~p4
// q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
// q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
// ~q1 \/ q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
// ~q1 \/ ~q2 \/ p1 \/ p2 \/ p3 \/ p4 \/ l2
// ...
//
// 2. Now suppose we learned the lemma
//
// p1 \/ p2 \/ p3 \/ p4 \/ l2 (*)
//
// 3. Probing is executed and we notice hat (~l => l2) when we assign l to false.
// That is, l \/ l2 is an implied clause. Note that probing does not add
// this clause to the clause database (there are too many).
//
// 4. Lemma (*) is deleted (garbage collected).
//
// 5. l is decided to be false, p1, p2, p3 and p4 are propagated using BCP,
// but l2 is not since the lemma (*) was deleted.
//
// Probing module still "knows" that l \/ l2 is valid binary clause
//
// 6. A new lemma is created where ~l2 is the FUIP and the lemma also contains l.
// If we remove l0 != ~l2 may try to delete the FUIP.
if (is_marked_lit(~l2) && l0 != ~l2) {
// eliminate ~l2 from lemma because we have the clause l \/ l2
unmark_lit(~l2);
}

View file

@ -175,8 +175,6 @@ unsigned read_datalog(char const * file) {
TRACE("dl_compiler", ctx.display(tout););
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 termination_code;
@ -237,7 +235,6 @@ unsigned read_datalog(char const * file) {
termination_code.reset();
ex_ctx.reset();
ctx.reopen();
ctx.restrict_predicates(original_predicates);
ctx.replace_rules(original_rules);
ctx.close();
}
@ -248,7 +245,7 @@ unsigned read_datalog(char const * file) {
rules_code.display(ctx.get_rel_context(), tout););
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(

View file

@ -29,6 +29,7 @@ Revision History:
#include"th_rewriter.h"
#include"filter_model_converter.h"
#include"ast_smt2_pp.h"
#include"expr_replacer.h"
/*
----
@ -131,18 +132,16 @@ struct purify_arith_proc {
proof_ref_vector m_new_cnstr_prs;
expr_ref m_subst;
proof_ref m_subst_pr;
bool m_in_q;
unsigned m_var_idx;
expr_ref_vector m_new_vars;
rw_cfg(purify_arith_proc & o, bool in_q):
rw_cfg(purify_arith_proc & o):
m_owner(o),
m_pinned(o.m()),
m_new_cnstrs(o.m()),
m_new_cnstr_prs(o.m()),
m_subst(o.m()),
m_subst_pr(o.m()),
m_in_q(in_q),
m_var_idx(0) {
m_new_vars(o.m()) {
}
ast_manager & m() { return m_owner.m(); }
@ -155,14 +154,9 @@ struct purify_arith_proc {
bool elim_inverses() const { return m_owner.m_elim_inverses; }
expr * mk_fresh_var(bool is_int) {
if (m_in_q) {
unsigned idx = m_var_idx;
m_var_idx++;
return m().mk_var(idx, is_int ? u().mk_int() : u().mk_real());
}
else {
return m().mk_fresh_const(0, is_int ? u().mk_int() : u().mk_real());
}
expr * r = m().mk_fresh_const(0, is_int ? u().mk_int() : u().mk_real());
m_new_vars.push_back(r);
return r;
}
expr * mk_fresh_real_var() { return mk_fresh_var(false); }
@ -596,105 +590,51 @@ struct purify_arith_proc {
struct rw : public rewriter_tpl<rw_cfg> {
rw_cfg m_cfg;
rw(purify_arith_proc & o, bool in_q):
rw(purify_arith_proc & o):
rewriter_tpl<rw_cfg>(o.m(), o.m_produce_proofs, m_cfg),
m_cfg(o, in_q) {
}
};
/**
\brief Return the number of (auxiliary) variables needed for converting an expression.
*/
struct num_vars_proc {
arith_util & m_util;
expr_fast_mark1 m_visited;
ptr_vector<expr> m_todo;
unsigned m_num_vars;
bool m_elim_root_objs;
num_vars_proc(arith_util & u, bool elim_root_objs):
m_util(u),
m_elim_root_objs(elim_root_objs) {
}
void visit(expr * t) {
if (m_visited.is_marked(t))
return;
m_visited.mark(t);
m_todo.push_back(t);
}
void process(app * t) {
if (t->get_family_id() == m_util.get_family_id()) {
if (m_util.is_power(t)) {
rational k;
if (m_util.is_numeral(t->get_arg(1), k) && (k.is_zero() || !k.is_int())) {
m_num_vars++;
}
}
else if (m_util.is_div(t) ||
m_util.is_idiv(t) ||
m_util.is_mod(t) ||
m_util.is_to_int(t) ||
(m_util.is_irrational_algebraic_numeral(t) && m_elim_root_objs)) {
m_num_vars++;
}
}
unsigned num_args = t->get_num_args();
for (unsigned i = 0; i < num_args; i++)
visit(t->get_arg(i));
}
unsigned operator()(expr * t) {
m_num_vars = 0;
visit(t);
while (!m_todo.empty()) {
expr * t = m_todo.back();
m_todo.pop_back();
if (is_app(t))
process(to_app(t));
}
m_visited.reset();
return m_num_vars;
m_cfg(o) {
}
};
void process_quantifier(quantifier * q, expr_ref & result, proof_ref & result_pr) {
result_pr = 0;
num_vars_proc p(u(), m_elim_root_objs);
expr_ref body(m());
unsigned num_vars = p(q->get_expr());
if (num_vars > 0) {
// open space for aux vars
var_shifter shifter(m());
shifter(q->get_expr(), num_vars, body);
}
else {
body = q->get_expr();
}
rw r(*this, true);
rw r(*this);
expr_ref new_body(m());
proof_ref new_body_pr(m());
r(body, new_body, new_body_pr);
r(q->get_expr(), new_body, new_body_pr);
unsigned num_vars = r.cfg().m_new_vars.size();
TRACE("purify_arith",
tout << "num_vars: " << num_vars << "\n";
tout << "body: " << mk_ismt2_pp(body, m()) << "\nnew_body: " << mk_ismt2_pp(new_body, m()) << "\n";);
tout << "body: " << mk_ismt2_pp(q->get_expr(), m()) << "\nnew_body: " << mk_ismt2_pp(new_body, m()) << "\n";);
if (num_vars == 0) {
SASSERT(r.cfg().m_new_cnstrs.empty());
result = m().update_quantifier(q, new_body);
if (m_produce_proofs)
result_pr = m().mk_quant_intro(q, to_quantifier(result.get()), result_pr);
}
else {
// Add new constraints
expr_ref_vector & cnstrs = r.cfg().m_new_cnstrs;
cnstrs.push_back(new_body);
new_body = m().mk_and(cnstrs.size(), cnstrs.c_ptr());
// Open space for new variables
var_shifter shifter(m());
shifter(new_body, num_vars, new_body);
// Rename fresh constants in r.cfg().m_new_vars to variables
ptr_buffer<sort> sorts;
buffer<symbol> names;
expr_substitution subst(m(), false, false);
for (unsigned i = 0; i < num_vars; i++) {
sorts.push_back(u().mk_real());
expr * c = r.cfg().m_new_vars.get(i);
sort * s = get_sort(c);
sorts.push_back(s);
names.push_back(m().mk_fresh_var_name("x"));
unsigned idx = num_vars - i - 1;
subst.insert(c, m().mk_var(idx, s));
}
scoped_ptr<expr_replacer> replacer = mk_default_expr_replacer(m());
replacer->set_substitution(&subst);
(*replacer)(new_body, new_body);
new_body = m().mk_exists(num_vars, sorts.c_ptr(), names.c_ptr(), new_body);
result = m().update_quantifier(q, new_body);
if (m_produce_proofs) {
@ -708,7 +648,7 @@ struct purify_arith_proc {
}
void operator()(goal & g, model_converter_ref & mc, bool produce_models) {
rw r(*this, false);
rw r(*this);
// purify
expr_ref new_curr(m());
proof_ref new_pr(m());

View file

@ -450,7 +450,7 @@ void test_bvneg() {
void tst_api() {
test_apps();
test_bvneg();
bv_invariant();
// bv_invariant();
}
#else
void tst_api() {

View file

@ -4,7 +4,14 @@
#include "reg_decl_plugins.h"
class tst_bv_simplifier_plugin_cls {
class mgr {
public:
mgr(ast_manager& m) {
reg_decl_plugins(m);
}
};
ast_manager m_manager;
mgr m_mgr;
bv_simplifier_params m_bv_params;
basic_simplifier_plugin m_bsimp;
arith_util m_arith;
@ -75,12 +82,13 @@ class tst_bv_simplifier_plugin_cls {
public:
tst_bv_simplifier_plugin_cls() :
m_mgr(m_manager),
m_bsimp(m_manager),
m_arith(m_manager),
m_simp(m_manager, m_bsimp, m_bv_params),
m_bv_util(m_manager),
m_fid(m_manager.mk_family_id("bv")) {
reg_decl_plugins(m_manager);
m_fid(0) {
m_fid = m_manager.mk_family_id("bv");
}
~tst_bv_simplifier_plugin_cls() {}
@ -249,7 +257,9 @@ public:
ar = m_manager.mk_app(m_fid, OP_BASHR, 2, e1e2);
m_simp.reduce(ar->get_decl(), ar->get_num_args(), ar->get_args(), e);
SASSERT((sa >> b) == i32(e.get()));
std::cout << "compare: " << sa << " >> " << b << " = " << (sa >> b) << " with " << i32(e.get()) << "\n";
SASSERT(b >= 32 || ((sa >> b) == i32(e.get())));
if (b != 0) {
ar = m_manager.mk_app(m_fid, OP_BSDIV, 2, e1e2);

View file

@ -164,9 +164,9 @@ static void tst3() {
}
void tst_diff_logic() {
tst1();
tst2();
tst3();
//tst1();
//tst2();
//tst3();
}
#else
void tst_diff_logic() {

View file

@ -60,7 +60,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();
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 end = out_preds.end();
for(; it!=end; ++it) {

View file

@ -1,7 +1,6 @@
#ifdef _WINDOWS
#include "dl_context.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);
@ -11,13 +10,6 @@ static datalog::table_base* mk_bv_table(datalog::relation_manager& m, datalog::t
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) {
datalog::table_signature sig;
sig.push_back(2);
@ -96,13 +88,9 @@ void test_dl_bitvector_table() {
test_table(mk_bv_table);
}
void test_dl_skip_table() {
test_table(mk_skip_table);
}
void tst_dl_table() {
test_dl_bitvector_table();
test_dl_skip_table();
}
#else
void tst_dl_table() {

View file

@ -381,7 +381,7 @@ static void tst3() {
{
std::ostringstream buffer;
display(buffer, m, a, EN_PLUS_INFINITY);
SASSERT(buffer.str() == "oo");
SASSERT(buffer.str() == "+oo");
}
{
std::ostringstream buffer;

View file

@ -1,87 +0,0 @@
#include "fdd.h"
static void test1() {
fdd::manager m;
m.reset(2);
int64 keys1[2] = { 1, 2 };
m.insert(keys1);
m.display(std::cout << "test1\n");
}
static void test2() {
fdd::manager m;
m.reset(2);
int64 keys2[2] = { 2, 1 };
m.insert(keys2);
m.display(std::cout << "test2\n");
}
static void test3() {
fdd::manager m;
m.reset(2);
int64 keys1[2] = { 1, 2 };
int64 keys2[2] = { 2, 1 };
m.insert(keys1);
m.insert(keys2);
m.display(std::cout << "test3\n");
}
static void test4() {
fdd::manager m;
std::cout << "test4\n";
m.reset(2);
int64 keys1[2] = { 1, 2 };
int64 keys2[2] = { 2, 1 };
int64 keys3[2] = { 1, 1 };
int64 keys4[2] = { 2, 2 };
int64 keys5[2] = { 2, 3 };
int64 keys6[2] = { 3, 1 };
int64 keys7[2] = { 3, 4 };
m.insert(keys1);
m.insert(keys2);
std::cout << m.find_le(keys1) << "\n";
std::cout << m.find_le(keys2) << "\n";
std::cout << m.find_le(keys3) << "\n";
std::cout << m.find_le(keys4) << "\n";
std::cout << m.find_le(keys5) << "\n";
std::cout << m.find_le(keys6) << "\n";
std::cout << m.find_le(keys7) << "\n";
SASSERT(m.find_le(keys1));
SASSERT(m.find_le(keys2));
SASSERT(!m.find_le(keys3));
SASSERT(m.find_le(keys4));
SASSERT(m.find_le(keys5));
SASSERT(m.find_le(keys6));
SASSERT(m.find_le(keys7));
}
static void test5() {
fdd::manager m;
std::cout << "test5\n";
m.reset(2);
int64 keys1[2] = { 1, 2 };
int64 keys2[2] = { 2, 1 };
m.insert(keys1);
m.insert(keys2);
m.insert(keys2);
m.display(std::cout);
}
void tst_fdd() {
test1();
test2();
test3();
test4();
test5();
}

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) \
std::cout << #MODULE << "\n"; \
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_debug(#MODULE); \
timeit timeit(true, s.c_str()); \
@ -60,6 +60,7 @@ void display_usage() {
std::cout << " /h prints this message.\n";
std::cout << " /v:level be verbose, where <level> is the verbosity level.\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)
std::cout << "\nDebugging support:\n";
#endif
@ -71,7 +72,7 @@ void display_usage() {
#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;
while (i < argc) {
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) {
enable_warning_messages(true);
}
else if (strcmp(opt_name, "a") == 0) {
test_all = true;
}
#ifdef _TRACE
else if (strcmp(opt_name, "tr") == 0) {
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) {
memory::initialize(0);
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(vector);
TST(symbol_table);
@ -151,14 +156,9 @@ int main(int argc, char ** argv) {
TST(simple_parser);
TST(api);
TST(old_interval);
TST(interval_skip_list);
TST(no_overflow);
TST(memory);
TST(get_implied_equalities);
TST(arith_simplifier_plugin);
TST(matcher);
TST(datalog_parser);
TST_ARGV(datalog_parser_file);
TST(object_allocator);
TST(mpz);
TST(mpq);
@ -166,11 +166,9 @@ int main(int argc, char ** argv) {
TST(total_order);
TST(dl_table);
TST(dl_context);
TST(dl_query);
TST(dl_util);
TST(dl_product_relation);
TST(dl_relation);
TST(imdd);
TST(parray);
TST(stack);
TST(escaped);
@ -196,7 +194,6 @@ int main(int argc, char ** argv) {
TST(nlsat);
TST(ext_numeral);
TST(interval);
TST(quant_solve);
TST(f2n);
TST(hwf);
TST(trigo);
@ -206,11 +203,16 @@ int main(int argc, char ** argv) {
TST(mpff);
TST(horn_subsume_model_converter);
TST(model2expr);
TST(rcf);
TST(hilbert_basis);
TST(heap_trie);
TST(karr);
TST(fdd);
TST(no_overflow);
TST(memory);
TST(datalog_parser);
TST_ARGV(datalog_parser_file);
TST(dl_query);
TST(quant_solve);
TST(rcf);
}
void initialize_mam() {}

View file

@ -20,30 +20,36 @@ static void hit_me(char const* wm) {
oom = false;
cfg = Z3_mk_config();
Z3_set_param_value(cfg, "MEMORY_MAX_SIZE", wm);
ctx = Z3_mk_context(cfg);
Z3_set_error_handler(ctx, &err_handler);
unsigned i;
for (i = 1; !oom ; ++i) {
try {
Z3_mk_bv_sort(ctx,i);
}
catch (std::bad_alloc) {
std::cout << "caught\n";
}
if (!cfg) {
return;
}
std::cout << "oom " << i << "\n";
Z3_global_param_set("MEMORY_MAX_SIZE", wm);
ctx = Z3_mk_context(cfg);
if (ctx) {
Z3_set_error_handler(ctx, &err_handler);
unsigned i;
for (i = 1; !oom ; ++i) {
try {
Z3_mk_bv_sort(ctx,i);
}
catch (std::bad_alloc) {
std::cout << "caught\n";
}
}
std::cout << "oom " << i << "\n";
Z3_del_context(ctx);
}
Z3_del_config(cfg);
}
void tst_memory() {
hit_me("1");
hit_me("10");
Z3_reset_memory();
hit_me("2");
hit_me("20");
Z3_reset_memory();
hit_me("3");
hit_me("30");
Z3_reset_memory();
}

View file

@ -659,7 +659,7 @@ void test_equiv(Equivalence_params params, unsigned bvsize, bool is_signed) {
typedef void (*TESTFUN)(unsigned bvsize, bool is_signed);
void tst_no_overflow() {
disable_debug("heap");
unsigned bvsizes[BVSIZES] = { 1, 16, 32, 42 };
TESTFUN tests[TESTNUM] = { test_add, test_sub, test_mul };

View file

@ -76,6 +76,7 @@ static void test_formula(lbool expected_outcome, char const* fml) {
}
void tst_quant_elim() {
disable_debug("heap");
test_formula(l_undef, "(exists ((p1 Bool) (q1 Bool) (r1 Bool))\
(and (or (not p1) (not q1) r1)\

View file

@ -28,6 +28,7 @@ static void validate_quant_solution(ast_manager& m, expr* fml, expr* guard, qe::
(*rep)(fml1);
expr_ref tmp(m);
tmp = m.mk_not(m.mk_implies(guard, fml1));
std::cout << "validating: " << mk_pp(tmp, m) << "\n";
smt_params fp;
smt::kernel solver(m, fp);
solver.assert_expr(tmp);
@ -174,11 +175,11 @@ static void test_quant_solve1() {
app* xy[2] = { x, y };
test_quant_solver(m, x, "(and (<= (* 2 x) y) (>= x z) (= (mod x 2) 0))");
test_quant_solver(m, x, "(and (<= x y) (= (mod x 2) 0))");
test_quant_solver(m, x, "(and (<= (* 2 x) y) (= (mod x 2) 0))");
test_quant_solver(m, x, "(and (>= x y) (= (mod x 2) 0))");
test_quant_solver(m, x, "(and (>= (* 2 x) y) (= (mod x 2) 0))");
test_quant_solver(m, x, "(and (<= (* 2 x) y) (>= x z) (= (mod x 2) 0))");
test_quant_solver(m, x, "(and (<= (* 2 x) y) (>= (* 3 x) z) (= (mod x 2) 0))");
test_quant_solver(m, x, "(>= (* 2 x) a)");
test_quant_solver(m, x, "(<= (* 2 x) a)");
@ -242,6 +243,7 @@ static void test_quant_solve1() {
void tst_quant_solve() {
disable_debug("heap");
test_quant_solve1();

View file

@ -5,7 +5,8 @@
#include "util.h"
#include "trace.h"
void ev_const(Z3_context ctx, Z3_ast e) {
static void ev_const(Z3_context ctx, Z3_ast e) {
Z3_ast r = Z3_simplify(ctx, e);
TRACE("simplifier",
tout << Z3_ast_to_string(ctx, e) << " -> ";
@ -17,7 +18,7 @@ void ev_const(Z3_context ctx, Z3_ast e) {
Z3_OP_FALSE == Z3_get_decl_kind(ctx,Z3_get_app_decl(ctx, Z3_to_app(ctx, r))))));
}
void test_bv() {
static void test_bv() {
Z3_config cfg = Z3_mk_config();
Z3_context ctx = Z3_mk_context(cfg);
Z3_sort bv1 = Z3_mk_bv_sort(ctx,1);
@ -75,7 +76,7 @@ void test_bv() {
Z3_del_context(ctx);
}
void test_datatypes() {
static void test_datatypes() {
Z3_config cfg = Z3_mk_config();
Z3_context ctx = Z3_mk_context(cfg);
Z3_sort int_ty, int_list;
@ -108,17 +109,15 @@ void test_datatypes() {
}
void test_skolemize_bug() {
static void test_skolemize_bug() {
Z3_config cfg = Z3_mk_config();
Z3_set_param_value(cfg, "MODEL", "true");
Z3_set_param_value(cfg, "QUANT_FM","true");
Z3_set_param_value(cfg, "FM","true");
Z3_context ctx = Z3_mk_context(cfg);
Z3_del_config(cfg);
Z3_sort Real = Z3_mk_real_sort(ctx);
Z3_ast x = Z3_mk_bound(ctx, 0, Real);
Z3_symbol x_name = Z3_mk_string_symbol(ctx, "x");
Z3_symbol x_name = Z3_mk_string_symbol(ctx, "x");
Z3_ast y = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "y"), Real);
Z3_ast xp = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "xp"), Real);
Z3_ast n0 = Z3_mk_numeral(ctx, "0", Real);
@ -136,7 +135,7 @@ void test_skolemize_bug() {
}
void test_bool() {
static void test_bool() {
Z3_config cfg = Z3_mk_config();
Z3_context ctx = Z3_mk_context(cfg);
@ -151,7 +150,7 @@ void test_bool() {
Z3_del_context(ctx);
}
void test_array() {
static void test_array() {
Z3_config cfg = Z3_mk_config();
Z3_context ctx = Z3_mk_context(cfg);
@ -172,8 +171,10 @@ void test_array() {
Z3_ast exy = Z3_mk_eq(ctx, x2, x1);
Z3_ast rxy = Z3_simplify(ctx, exy);
SASSERT(rxy == Z3_mk_true(ctx));
SASSERT(Z3_simplify(ctx, Z3_mk_eq(ctx, x2, x3)) == Z3_mk_false(ctx));
TRACE("simplifier", tout << Z3_ast_to_string(ctx, rxy) << "\n";);
TRACE("simplifier", tout << Z3_ast_to_string(ctx, Z3_simplify(ctx, Z3_mk_eq(ctx, x2, x3))) << "\n";);
// SASSERT(rxy == Z3_mk_true(ctx));
// SASSERT(Z3_simplify(ctx, Z3_mk_eq(ctx, x2, x3)) == Z3_mk_false(ctx));
for (unsigned i = 0; i < 4; ++i) {
for (unsigned j = 0; j < 4; ++j) {

View file

@ -113,6 +113,7 @@ public:
heap(int s, const LT & lt = LT()):LT(lt) {
m_values.push_back(-1);
set_bounds(s);
CASSERT("heap", check_invariant());
}
bool empty() const {
@ -124,12 +125,14 @@ public:
}
void reset() {
CASSERT("heap", check_invariant());
if (empty()) {
return;
}
memset(m_value2indices.begin(), 0, sizeof(int) * m_value2indices.size());
m_values.reset();
m_values.push_back(-1);
CASSERT("heap", check_invariant());
}
void clear() {
@ -138,6 +141,7 @@ public:
void set_bounds(int s) {
m_value2indices.resize(s, 0);
CASSERT("heap", check_invariant());
}
unsigned get_bounds() const {
@ -145,8 +149,10 @@ public:
}
void reserve(int s) {
CASSERT("heap", check_invariant());
if (s > static_cast<int>(m_value2indices.size()))
set_bounds(s);
CASSERT("heap", check_invariant());
}
int min_value() const {
@ -155,6 +161,7 @@ public:
}
int erase_min() {
CASSERT("heap", check_invariant());
SASSERT(!empty());
SASSERT(m_values.size() >= 2);
int result = m_values[1];
@ -176,6 +183,7 @@ public:
}
void erase(int val) {
CASSERT("heap", check_invariant());
SASSERT(contains(val));
int idx = m_value2indices[val];
if (idx == static_cast<int>(m_values.size()) - 1) {
@ -210,12 +218,14 @@ public:
}
void insert(int val) {
CASSERT("heap", check_invariant());
SASSERT(is_valid_value(val));
int idx = static_cast<int>(m_values.size());
m_value2indices[val] = idx;
m_values.push_back(val);
SASSERT(idx == static_cast<int>(m_values.size()) - 1);
move_up(idx);
CASSERT("heap", check_invariant());
}
iterator begin() {
@ -235,8 +245,14 @@ public:
}
void swap(heap & other) {
m_values.swap(other.m_values);
m_value2indices.swap(other.m_value2indices);
if (this != &other) {
CASSERT("heap", other.check_invariant());
CASSERT("heap", check_invariant());
m_values.swap(other.m_values);
m_value2indices.swap(other.m_value2indices);
CASSERT("heap", other.check_invariant());
CASSERT("heap", check_invariant());
}
}
/**

View file

@ -96,7 +96,7 @@ void * small_object_allocator::allocate(size_t size) {
return memory::allocate(size);
#endif
m_alloc_size += size;
if (size > SMALL_OBJ_SIZE - (1 << PTR_ALIGNMENT))
if (size > SMALL_OBJ_SIZE - (1 << PTR_ALIGNMENT))
return memory::allocate(size);
#ifdef Z3DEBUG
size_t osize = size;