mirror of
https://github.com/Z3Prover/z3
synced 2025-10-18 05:20:26 +00:00
re-organize muz_qe into separate units
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
4597872be8
commit
0d56499e2d
131 changed files with 994 additions and 20069 deletions
328
src/muz/rel/aig_exporter.cpp
Normal file
328
src/muz/rel/aig_exporter.cpp
Normal file
|
@ -0,0 +1,328 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
aig_exporter.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Export AIG files from horn clauses
|
||||
|
||||
--*/
|
||||
|
||||
#include "aig_exporter.h"
|
||||
#include "dl_context.h"
|
||||
#include <set>
|
||||
|
||||
namespace datalog {
|
||||
|
||||
aig_exporter::aig_exporter(const rule_set& rules, context& ctx, const fact_vector *facts) :
|
||||
m_rules(rules), m_facts(facts), m(ctx.get_manager()), m_rm(ctx.get_rule_manager()),
|
||||
m_aigm(m), m_next_decl_id(1), m_next_aig_expr_id(2), m_num_and_gates(0),
|
||||
m_latch_vars(m), m_latch_varsp(m), m_ruleid_var_set(m), m_ruleid_varp_set(m)
|
||||
{
|
||||
std::set<func_decl*> predicates;
|
||||
for (rule_set::decl2rules::iterator I = m_rules.begin_grouped_rules(),
|
||||
E = m_rules.end_grouped_rules(); I != E; ++I) {
|
||||
predicates.insert(I->m_key);
|
||||
}
|
||||
|
||||
for (fact_vector::const_iterator I = facts->begin(), E = facts->end(); I != E; ++I) {
|
||||
predicates.insert(I->first);
|
||||
}
|
||||
|
||||
// reserve pred id = 0 for initalization purposes
|
||||
unsigned num_preds = (unsigned)predicates.size() + 1;
|
||||
|
||||
// poor's man round-up log2
|
||||
unsigned preds_bitsize = log2(num_preds);
|
||||
if ((1U << preds_bitsize) < num_preds)
|
||||
++preds_bitsize;
|
||||
SASSERT((1U << preds_bitsize) >= num_preds);
|
||||
|
||||
for (unsigned i = 0; i < preds_bitsize; ++i) {
|
||||
m_ruleid_var_set.push_back(m.mk_fresh_const("rule_id", m.mk_bool_sort()));
|
||||
m_ruleid_varp_set.push_back(m.mk_fresh_const("rule_id_p", m.mk_bool_sort()));
|
||||
}
|
||||
}
|
||||
|
||||
void aig_exporter::mk_latch_vars(unsigned n) {
|
||||
for (unsigned i = m_latch_vars.size(); i <= n; ++i) {
|
||||
m_latch_vars.push_back(m.mk_fresh_const("latch_var", m.mk_bool_sort()));
|
||||
m_latch_varsp.push_back(m.mk_fresh_const("latch_varp", m.mk_bool_sort()));
|
||||
}
|
||||
SASSERT(m_latch_vars.size() > n);
|
||||
}
|
||||
|
||||
expr* aig_exporter::get_latch_var(unsigned i, const expr_ref_vector& vars) {
|
||||
mk_latch_vars(i);
|
||||
return vars.get(i);
|
||||
}
|
||||
|
||||
void aig_exporter::assert_pred_id(func_decl *decl, const expr_ref_vector& vars, expr_ref_vector& exprs) {
|
||||
unsigned id = 0;
|
||||
if (decl && !m_decl_id_map.find(decl, id)) {
|
||||
id = m_next_decl_id++;
|
||||
SASSERT(id < (1U << vars.size()));
|
||||
m_decl_id_map.insert(decl, id);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < vars.size(); ++i) {
|
||||
exprs.push_back((id & (1U << i)) ? vars[i] : m.mk_not(vars[i]));
|
||||
}
|
||||
}
|
||||
|
||||
void aig_exporter::collect_var_substs(substitution& subst, const app *h,
|
||||
const expr_ref_vector& vars, expr_ref_vector& eqs) {
|
||||
for (unsigned i = 0; i < h->get_num_args(); ++i) {
|
||||
expr *arg = h->get_arg(i);
|
||||
expr *latchvar = get_latch_var(i, vars);
|
||||
|
||||
if (is_var(arg)) {
|
||||
var *v = to_var(arg);
|
||||
expr_offset othervar;
|
||||
if (subst.find(v, 0, othervar)) {
|
||||
eqs.push_back(m.mk_eq(latchvar, othervar.get_expr()));
|
||||
} else {
|
||||
subst.insert(v, 0, expr_offset(latchvar, 0));
|
||||
}
|
||||
} else {
|
||||
eqs.push_back(m.mk_eq(latchvar, arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void aig_exporter::operator()(std::ostream& out) {
|
||||
expr_ref_vector transition_function(m), output_preds(m);
|
||||
var_ref_vector input_vars(m);
|
||||
|
||||
rule_counter& vc = m_rm.get_counter();
|
||||
expr_ref_vector exprs(m);
|
||||
substitution subst(m);
|
||||
|
||||
for (rule_set::decl2rules::iterator I = m_rules.begin_grouped_rules(),
|
||||
E = m_rules.end_grouped_rules(); I != E; ++I) {
|
||||
for (rule_vector::iterator II = I->get_value()->begin(),
|
||||
EE = I->get_value()->end(); II != EE; ++II) {
|
||||
rule *r = *II;
|
||||
unsigned numqs = r->get_positive_tail_size();
|
||||
if (numqs > 1) {
|
||||
std::cerr << "non-linear clauses not supported\n";
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (numqs != r->get_uninterpreted_tail_size()) {
|
||||
std::cerr << "negation of queries not supported\n";
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
exprs.reset();
|
||||
assert_pred_id(numqs ? r->get_tail(0)->get_decl() : 0, m_ruleid_var_set, exprs);
|
||||
assert_pred_id(r->get_head()->get_decl(), m_ruleid_varp_set, exprs);
|
||||
|
||||
subst.reset();
|
||||
subst.reserve(1, vc.get_max_rule_var(*r)+1);
|
||||
if (numqs)
|
||||
collect_var_substs(subst, r->get_tail(0), m_latch_vars, exprs);
|
||||
collect_var_substs(subst, r->get_head(), m_latch_varsp, exprs);
|
||||
|
||||
for (unsigned i = numqs; i < r->get_tail_size(); ++i) {
|
||||
expr_ref e(m);
|
||||
subst.apply(r->get_tail(i), e);
|
||||
exprs.push_back(e);
|
||||
}
|
||||
|
||||
transition_function.push_back(m.mk_and(exprs.size(), exprs.c_ptr()));
|
||||
}
|
||||
}
|
||||
|
||||
// collect table facts
|
||||
if (m_facts) {
|
||||
for (fact_vector::const_iterator I = m_facts->begin(), E = m_facts->end(); I != E; ++I) {
|
||||
exprs.reset();
|
||||
assert_pred_id(0, m_ruleid_var_set, exprs);
|
||||
assert_pred_id(I->first, m_ruleid_varp_set, exprs);
|
||||
|
||||
for (unsigned i = 0; i < I->second.size(); ++i) {
|
||||
exprs.push_back(m.mk_eq(get_latch_var(i, m_latch_varsp), I->second[i]));
|
||||
}
|
||||
|
||||
transition_function.push_back(m.mk_and(exprs.size(), exprs.c_ptr()));
|
||||
}
|
||||
}
|
||||
|
||||
expr *tr = m.mk_or(transition_function.size(), transition_function.c_ptr());
|
||||
aig_ref aig = m_aigm.mk_aig(tr);
|
||||
expr_ref aig_expr(m);
|
||||
m_aigm.to_formula(aig, aig_expr);
|
||||
|
||||
#if 0
|
||||
std::cout << mk_pp(tr, m) << "\n\n";
|
||||
std::cout << mk_pp(aig_expr, m) << "\n\n";
|
||||
#endif
|
||||
|
||||
// make rule_id vars latches
|
||||
for (unsigned i = 0; i < m_ruleid_var_set.size(); ++i) {
|
||||
m_latch_vars.push_back(m_ruleid_var_set.get(i));
|
||||
m_latch_varsp.push_back(m_ruleid_varp_set.get(i));
|
||||
}
|
||||
|
||||
// create vars for latches
|
||||
for (unsigned i = 0; i < m_latch_vars.size(); ++i) {
|
||||
mk_var(m_latch_vars.get(i));
|
||||
mk_input_var(m_latch_varsp.get(i));
|
||||
}
|
||||
|
||||
unsigned tr_id = expr_to_aig(aig_expr);
|
||||
|
||||
// create latch next state variables: (ite tr varp var)
|
||||
unsigned_vector latch_varp_ids;
|
||||
for (unsigned i = 0; i < m_latch_vars.size(); ++i) {
|
||||
unsigned in_val = mk_and(tr_id, get_var(m_latch_varsp.get(i)));
|
||||
unsigned latch_val = mk_and(neg(tr_id), get_var(m_latch_vars.get(i)));
|
||||
latch_varp_ids.push_back(mk_or(in_val, latch_val));
|
||||
}
|
||||
m_latch_varsp.reset();
|
||||
|
||||
// create output variable (true iff an output predicate is derivable)
|
||||
unsigned output_id = 0;
|
||||
{
|
||||
expr_ref_vector output(m);
|
||||
const func_decl_set& preds = m_rules.get_output_predicates();
|
||||
|
||||
for (func_decl_set::iterator I = preds.begin(), E = preds.end(); I != E; ++I) {
|
||||
exprs.reset();
|
||||
assert_pred_id(*I, m_ruleid_var_set, exprs);
|
||||
output.push_back(m.mk_and(exprs.size(), exprs.c_ptr()));
|
||||
}
|
||||
|
||||
expr *out = m.mk_or(output.size(), output.c_ptr());
|
||||
aig = m_aigm.mk_aig(out);
|
||||
m_aigm.to_formula(aig, aig_expr);
|
||||
output_id = expr_to_aig(aig_expr);
|
||||
|
||||
#if 0
|
||||
std::cout << "output formula\n";
|
||||
std::cout << mk_pp(out, m) << "\n\n";
|
||||
std::cout << mk_pp(aig_expr, m) << "\n\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
// 1) print header
|
||||
// aag var_index inputs latches outputs andgates
|
||||
out << "aag " << (m_next_aig_expr_id-1)/2 << ' ' << m_input_vars.size()
|
||||
<< ' ' << m_latch_vars.size() << " 1 " << m_num_and_gates << '\n';
|
||||
|
||||
// 2) print inputs
|
||||
for (unsigned i = 0; i < m_input_vars.size(); ++i) {
|
||||
out << m_input_vars[i] << '\n';
|
||||
}
|
||||
|
||||
// 3) print latches
|
||||
for (unsigned i = 0; i < m_latch_vars.size(); ++i) {
|
||||
out << get_var(m_latch_vars.get(i)) << ' ' << latch_varp_ids[i] << '\n';
|
||||
}
|
||||
|
||||
// 4) print outputs (just one for now)
|
||||
out << output_id << '\n';
|
||||
|
||||
// 5) print formula
|
||||
out << m_buffer.str();
|
||||
}
|
||||
|
||||
unsigned aig_exporter::expr_to_aig(const expr *e) {
|
||||
unsigned id;
|
||||
if (m_aig_expr_id_map.find(e, id))
|
||||
return id;
|
||||
|
||||
if (is_uninterp_const(e))
|
||||
return get_var(e);
|
||||
|
||||
switch (e->get_kind()) {
|
||||
case AST_APP: {
|
||||
const app *a = to_app(e);
|
||||
switch (a->get_decl_kind()) {
|
||||
case OP_OR:
|
||||
SASSERT(a->get_num_args() > 0);
|
||||
id = expr_to_aig(a->get_arg(0));
|
||||
for (unsigned i = 1; i < a->get_num_args(); ++i) {
|
||||
id = mk_or(id, expr_to_aig(a->get_arg(i)));
|
||||
}
|
||||
m_aig_expr_id_map.insert(e, id);
|
||||
return id;
|
||||
|
||||
case OP_NOT:
|
||||
return neg(expr_to_aig(a->get_arg(0)));
|
||||
|
||||
case OP_FALSE:
|
||||
return 0;
|
||||
|
||||
case OP_TRUE:
|
||||
return 1;
|
||||
}
|
||||
break;}
|
||||
|
||||
case AST_VAR:
|
||||
return get_var(e);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned aig_exporter::neg(unsigned id) const {
|
||||
return (id % 2) ? (id-1) : (id+1);
|
||||
}
|
||||
|
||||
unsigned aig_exporter::mk_and(unsigned id1, unsigned id2) {
|
||||
if (id1 > id2)
|
||||
std::swap(id1, id2);
|
||||
|
||||
std::pair<unsigned,unsigned> key(id1, id2);
|
||||
and_gates_map::const_iterator I = m_and_gates_map.find(key);
|
||||
if (I != m_and_gates_map.end())
|
||||
return I->second;
|
||||
|
||||
unsigned id = mk_expr_id();
|
||||
m_buffer << id << ' ' << id1 << ' ' << id2 << '\n';
|
||||
m_and_gates_map[key] = id;
|
||||
++m_num_and_gates;
|
||||
return id;
|
||||
}
|
||||
|
||||
unsigned aig_exporter::mk_or(unsigned id1, unsigned id2) {
|
||||
return neg(mk_and(neg(id1), neg(id2)));
|
||||
}
|
||||
|
||||
unsigned aig_exporter::get_var(const expr *e) {
|
||||
unsigned id;
|
||||
if (m_aig_expr_id_map.find(e, id))
|
||||
return id;
|
||||
return mk_input_var(e);
|
||||
}
|
||||
|
||||
unsigned aig_exporter::mk_var(const expr *e) {
|
||||
SASSERT(!m_aig_expr_id_map.contains(e));
|
||||
unsigned id = mk_expr_id();
|
||||
m_aig_expr_id_map.insert(e, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
unsigned aig_exporter::mk_input_var(const expr *e) {
|
||||
SASSERT(!m_aig_expr_id_map.contains(e));
|
||||
unsigned id = mk_expr_id();
|
||||
m_input_vars.push_back(id);
|
||||
if (e)
|
||||
m_aig_expr_id_map.insert(e, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
unsigned aig_exporter::mk_expr_id() {
|
||||
unsigned id = m_next_aig_expr_id;
|
||||
m_next_aig_expr_id += 2;
|
||||
return id;
|
||||
}
|
||||
}
|
68
src/muz/rel/aig_exporter.h
Normal file
68
src/muz/rel/aig_exporter.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
aig_exporter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Export AIG files from horn clauses
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef _AIG_EXPORTER_H_
|
||||
#define _AIG_EXPORTER_H_
|
||||
|
||||
#include "aig.h"
|
||||
#include "dl_rule_set.h"
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include "rel_context.h"
|
||||
|
||||
namespace datalog {
|
||||
class aig_exporter {
|
||||
public:
|
||||
aig_exporter(const rule_set& rules, context& ctx, const fact_vector *facts = 0);
|
||||
void operator()(std::ostream& out);
|
||||
|
||||
private:
|
||||
typedef obj_map<func_decl, unsigned> decl_id_map;
|
||||
typedef obj_map<const expr, unsigned> aig_expr_id_map;
|
||||
typedef std::map<std::pair<unsigned,unsigned>, unsigned> and_gates_map;
|
||||
|
||||
const rule_set& m_rules;
|
||||
const fact_vector *m_facts;
|
||||
ast_manager& m;
|
||||
rule_manager& m_rm;
|
||||
aig_manager m_aigm;
|
||||
decl_id_map m_decl_id_map;
|
||||
unsigned m_next_decl_id;
|
||||
aig_expr_id_map m_aig_expr_id_map;
|
||||
unsigned m_next_aig_expr_id;
|
||||
and_gates_map m_and_gates_map;
|
||||
unsigned m_num_and_gates;
|
||||
|
||||
expr_ref_vector m_latch_vars, m_latch_varsp;
|
||||
expr_ref_vector m_ruleid_var_set, m_ruleid_varp_set;
|
||||
unsigned_vector m_input_vars;
|
||||
|
||||
std::stringstream m_buffer;
|
||||
|
||||
void mk_latch_vars(unsigned n);
|
||||
expr* get_latch_var(unsigned i, const expr_ref_vector& vars);
|
||||
void assert_pred_id(func_decl *decl, const expr_ref_vector& vars, expr_ref_vector& exprs);
|
||||
void collect_var_substs(substitution& subst, const app *h,
|
||||
const expr_ref_vector& vars, expr_ref_vector& eqs);
|
||||
unsigned expr_to_aig(const expr *e);
|
||||
unsigned neg(unsigned id) const;
|
||||
unsigned mk_and(unsigned id1, unsigned id2);
|
||||
unsigned mk_or(unsigned id1, unsigned id2);
|
||||
unsigned get_var(const expr *e);
|
||||
unsigned mk_var(const expr *e);
|
||||
unsigned mk_input_var(const expr *e = 0);
|
||||
unsigned mk_expr_id();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
1345
src/muz/rel/dl_compiler.cpp
Normal file
1345
src/muz/rel/dl_compiler.cpp
Normal file
File diff suppressed because it is too large
Load diff
282
src/muz/rel/dl_compiler.h
Normal file
282
src/muz/rel/dl_compiler.h
Normal file
|
@ -0,0 +1,282 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_compiler.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Krystof Hoder (t-khoder) 2010-09-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _DL_COMPILER_H_
|
||||
#define _DL_COMPILER_H_
|
||||
|
||||
#include<iostream>
|
||||
#include<list>
|
||||
#include<utility>
|
||||
|
||||
#include "ast.h"
|
||||
#include "hashtable.h"
|
||||
#include "map.h"
|
||||
#include "obj_pair_hashtable.h"
|
||||
#include "ref_vector.h"
|
||||
#include "vector.h"
|
||||
|
||||
#include "dl_base.h"
|
||||
#include "dl_context.h"
|
||||
#include "dl_instruction.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
class compiler {
|
||||
typedef instruction::reg_idx reg_idx;
|
||||
typedef hashtable<unsigned, u_hash, u_eq> int_set;
|
||||
typedef u_map<unsigned> int2int;
|
||||
typedef u_map<unsigned_vector> int2ints;
|
||||
typedef obj_map<func_decl, reg_idx> pred2idx;
|
||||
typedef unsigned_vector var_vector;
|
||||
typedef ptr_vector<func_decl> func_decl_vector;
|
||||
|
||||
enum assembling_column_kind {
|
||||
ACK_BOUND_VAR,
|
||||
ACK_UNBOUND_VAR,
|
||||
ACK_CONSTANT
|
||||
};
|
||||
|
||||
/**
|
||||
\brief instruction for assembling head relation from a joint relation built
|
||||
from rule evaluation.
|
||||
|
||||
ACK_BOUND_VAR(source_column) - encodes that the column contains a variable
|
||||
bound in the body.
|
||||
|
||||
ACK_UNBOUND_VAR(var_index) - encodes that the column contains a variable that
|
||||
is unbound (by the corresponding rule body),
|
||||
var_index is the de-Brujin index (var->get_idx())
|
||||
of the variable associated with the column.
|
||||
|
||||
ACK_CONSTANT(constant) - encodes that the column contains the constant.
|
||||
|
||||
Examples:
|
||||
|
||||
P(x) :- Q(x,y), Q(y,z)
|
||||
The variables in the body relation are [x, y, y, z] indexed as 0, 1, 2, 3.
|
||||
The variable x gets the instruction ACK_BOUND_VAR(0)
|
||||
|
||||
P(u,x) :- Q(x,y), Q(y,z)
|
||||
The variable u gets the instruction ACK_UNBOUND_VAR(#0)
|
||||
|
||||
P(1, x) :- Q(x,y), Q(y,z)
|
||||
The instruction for column 0 is ACK_CONSTANT(1)
|
||||
|
||||
*/
|
||||
struct assembling_column_info {
|
||||
|
||||
relation_sort domain; // domain of the column
|
||||
assembling_column_kind kind; // "instruction" tag
|
||||
unsigned source_column; // for ACK_BOUND_VAR
|
||||
unsigned var_index; // for ACK_UNBOUND_VAR
|
||||
relation_element constant; // for ACK_CONSTANT
|
||||
};
|
||||
|
||||
class instruction_observer : public instruction_block::instruction_observer {
|
||||
compiler & m_parent;
|
||||
rule * m_current;
|
||||
public:
|
||||
instruction_observer(compiler & parent) : m_parent(parent), m_current(0) {}
|
||||
|
||||
void start_rule(rule * r) { SASSERT(!m_current); m_current=r; }
|
||||
void finish_rule() { m_current = 0; }
|
||||
virtual void notify(instruction * i) {
|
||||
if(m_current) {
|
||||
i->set_accounting_parent_object(m_parent.m_context, m_current);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
context & m_context;
|
||||
rule_set const & m_rule_set;
|
||||
/**
|
||||
Invariant: the \c m_top_level_code never contains the loop that is being constructed,
|
||||
so instruction that need to be executed before the loop can be pushed into it.
|
||||
*/
|
||||
instruction_block & m_top_level_code;
|
||||
pred2idx m_pred_regs;
|
||||
reg_idx m_new_reg;
|
||||
vector<relation_signature> m_reg_signatures;
|
||||
obj_pair_map<sort, app, reg_idx> m_constant_registers;
|
||||
obj_pair_map<sort, decl, reg_idx> m_total_registers;
|
||||
obj_map<decl, reg_idx> m_empty_tables_registers;
|
||||
instruction_observer m_instruction_observer;
|
||||
|
||||
/**
|
||||
If true, the union operation on the underlying structure only provides the information
|
||||
whether the updated relation has changed or not. In this case we do not get anything
|
||||
from using delta relations at position of input relations in the saturation loop, so we
|
||||
would not do it.
|
||||
*/
|
||||
bool all_or_nothing_deltas() const { return m_context.all_or_nothing_deltas(); }
|
||||
|
||||
/**
|
||||
If true, we compile the saturation loops in a way that allows us to use widening.
|
||||
*/
|
||||
bool compile_with_widening() const { return m_context.compile_with_widening(); }
|
||||
|
||||
reg_idx get_fresh_register(const relation_signature & sig);
|
||||
reg_idx get_single_column_register(const relation_sort & s);
|
||||
|
||||
/**
|
||||
\brief Allocate registers for predicates in \c pred and add them into the \c regs map.
|
||||
|
||||
\c regs must not already contain any predicate from \c preds.
|
||||
*/
|
||||
void get_fresh_registers(const func_decl_set & preds, pred2idx & regs);
|
||||
|
||||
void make_join(reg_idx t1, reg_idx t2, const variable_intersection & vars, reg_idx & result,
|
||||
instruction_block & acc);
|
||||
void make_join_project(reg_idx t1, reg_idx t2, const variable_intersection & vars,
|
||||
const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc);
|
||||
void make_filter_interpreted_and_project(reg_idx src, app_ref & cond,
|
||||
const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc);
|
||||
void make_select_equal_and_project(reg_idx src, const relation_element & val, unsigned col,
|
||||
reg_idx & result, instruction_block & acc);
|
||||
/**
|
||||
\brief Create add an union or widen operation and put it into \c acc.
|
||||
*/
|
||||
void make_union(reg_idx src, reg_idx tgt, reg_idx delta, bool widening, instruction_block & acc);
|
||||
void make_projection(reg_idx src, unsigned col_cnt, const unsigned * removed_cols,
|
||||
reg_idx & result, instruction_block & acc);
|
||||
void make_rename(reg_idx src, unsigned cycle_len, const unsigned * permutation_cycle,
|
||||
reg_idx & result, instruction_block & acc);
|
||||
void make_clone(reg_idx src, reg_idx & result, instruction_block & acc);
|
||||
|
||||
/**
|
||||
\brief Into \c acc add code that will assemble columns of a relation according to description
|
||||
in \c acis0. The source for bound variables is the table in register \c src.
|
||||
|
||||
If \c src is \c execution_context::void_register, it is assumed to be a full relation
|
||||
with empty signature.
|
||||
*/
|
||||
void make_assembling_code(rule* compiled_rule, func_decl* head_pred, reg_idx src, const svector<assembling_column_info> & acis0,
|
||||
reg_idx & result, bool & dealloc, instruction_block & acc);
|
||||
|
||||
void make_dealloc_non_void(reg_idx r, instruction_block & acc);
|
||||
|
||||
void make_add_constant_column(func_decl* pred, reg_idx src, const relation_sort & s, const relation_element & val,
|
||||
reg_idx & result, bool & dealloc, instruction_block & acc);
|
||||
|
||||
void make_add_unbound_column(rule* compiled_rule, unsigned col_idx, func_decl* pred, reg_idx src, const relation_sort & s, reg_idx & result,
|
||||
bool & dealloc, instruction_block & acc);
|
||||
void make_full_relation(func_decl* pred, const relation_signature & sig, reg_idx & result,
|
||||
instruction_block & acc);
|
||||
|
||||
void add_unbound_columns_for_negation(rule* compiled_rule, func_decl* pred, reg_idx& single_res, expr_ref_vector& single_res_expr,
|
||||
bool & dealloc, instruction_block& acc);
|
||||
|
||||
void make_duplicate_column(reg_idx src, unsigned col, reg_idx & result, instruction_block & acc);
|
||||
|
||||
void ensure_predicate_loaded(func_decl * pred, instruction_block & acc);
|
||||
|
||||
/**
|
||||
\brief For rule \c r with two positive uninterpreted predicates put into \c res indexes of
|
||||
local variables in a table that results from join of the two positive predicates.
|
||||
|
||||
Used to get input for the "project" part of join-project.
|
||||
*/
|
||||
void get_local_indexes_for_projection(rule * r, unsigned_vector & res);
|
||||
void get_local_indexes_for_projection(app * t, var_counter & globals, unsigned ofs,
|
||||
unsigned_vector & res);
|
||||
|
||||
/**
|
||||
\brief Into \c acc add instructions that will add new facts following from the rule into
|
||||
\c head_reg, and add the facts that were not in \c head_reg before into \c delta_reg.
|
||||
*/
|
||||
void compile_rule_evaluation_run(rule * r, reg_idx head_reg, const reg_idx * tail_regs,
|
||||
reg_idx delta_reg, bool use_widening, instruction_block & acc);
|
||||
|
||||
void compile_rule_evaluation(rule * r, const pred2idx * input_deltas, reg_idx output_delta,
|
||||
bool use_widening, instruction_block & acc);
|
||||
|
||||
/**
|
||||
\brief Generate code to evaluate rules corresponding to predicates in \c head_preds.
|
||||
The rules are evaluated in the order their heads appear in the \c head_preds vector.
|
||||
*/
|
||||
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,
|
||||
const pred2idx & global_head_deltas, const pred2idx & global_tail_deltas,
|
||||
const pred2idx & local_deltas, instruction_block & acc);
|
||||
void compile_dependent_rules(const func_decl_set & head_preds,
|
||||
const pred2idx * input_deltas, const pred2idx & output_deltas,
|
||||
bool add_saturation_marks, instruction_block & acc);
|
||||
|
||||
void detect_chains(const func_decl_set & preds, func_decl_vector & ordered_preds,
|
||||
func_decl_set & global_deltas);
|
||||
/**
|
||||
Return true if there is no dependency inside the \c rules stratum.
|
||||
|
||||
The head predicates in stratum must be strongly connected by dependency.
|
||||
*/
|
||||
bool is_nonrecursive_stratum(const func_decl_set & preds) const;
|
||||
/**
|
||||
input_deltas==0 --> we use the actual content of relations instead of deltas
|
||||
*/
|
||||
void compile_nonrecursive_stratum(const func_decl_set & preds,
|
||||
const pred2idx * input_deltas, const pred2idx & output_deltas,
|
||||
bool add_saturation_marks, instruction_block & acc);
|
||||
|
||||
void compile_strats(const rule_stratifier & stratifier,
|
||||
const pred2idx * input_deltas, const pred2idx & output_deltas,
|
||||
bool add_saturation_marks, instruction_block & acc);
|
||||
|
||||
bool all_saturated(const func_decl_set & preds) const;
|
||||
|
||||
void reset();
|
||||
|
||||
explicit compiler(context & ctx, rule_set const & rules, instruction_block & top_level_code)
|
||||
: m_context(ctx),
|
||||
m_rule_set(rules),
|
||||
m_top_level_code(top_level_code),
|
||||
m_instruction_observer(*this) {}
|
||||
|
||||
/**
|
||||
\brief Compile \c rules in to pseudocode.
|
||||
|
||||
Instructions to load data and perform computations put into \c execution_code
|
||||
*/
|
||||
void do_compilation(instruction_block & execution_code,
|
||||
instruction_block & termination_code);
|
||||
|
||||
public:
|
||||
|
||||
static void compile(context & ctx, rule_set const & rules, instruction_block & execution_code,
|
||||
instruction_block & termination_code) {
|
||||
compiler(ctx, rules, execution_code)
|
||||
.do_compilation(execution_code, termination_code);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* _DL_COMPILER_H_ */
|
||||
|
1119
src/muz/rel/dl_instruction.cpp
Normal file
1119
src/muz/rel/dl_instruction.cpp
Normal file
File diff suppressed because it is too large
Load diff
349
src/muz/rel/dl_instruction.h
Normal file
349
src/muz/rel/dl_instruction.h
Normal file
|
@ -0,0 +1,349 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
dl_instruction.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Krystof Hoder (t-khoder) 2010-09-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _DL_INSTRUCTION_H_
|
||||
#define _DL_INSTRUCTION_H_
|
||||
|
||||
#include<iostream>
|
||||
#include<string>
|
||||
#include<utility>
|
||||
#include "ast.h"
|
||||
#include "vector.h"
|
||||
#include "dl_base.h"
|
||||
#include "dl_costs.h"
|
||||
#include "dl_context.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
class execution_context;
|
||||
class instruction_block;
|
||||
class rel_context;
|
||||
|
||||
inline void check_overflow(unsigned i) {
|
||||
if (i == UINT_MAX) {
|
||||
throw out_of_memory_error();
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
// execution_context
|
||||
//
|
||||
// -----------------------------------
|
||||
|
||||
class execution_context {
|
||||
public:
|
||||
typedef relation_base * reg_type;
|
||||
typedef vector<reg_type> reg_vector;
|
||||
typedef unsigned reg_idx;
|
||||
|
||||
/**
|
||||
\brief A register number that should never be referenced to. Can stand e.g. for a tail
|
||||
table in a rule with no tail.
|
||||
*/
|
||||
static const reg_idx void_register = UINT_MAX;
|
||||
private:
|
||||
typedef u_map<std::string> reg_annotations;
|
||||
|
||||
context & m_context;
|
||||
reg_vector m_registers;
|
||||
|
||||
reg_annotations m_reg_annotation;
|
||||
stopwatch * m_stopwatch;
|
||||
unsigned m_timelimit_ms; //zero means no limit
|
||||
/**
|
||||
\brief If true, after every operation that may result in an empty relation, a check
|
||||
for emptiness will be performed, and if a relation is empty, it will be deleted
|
||||
and replaced by zero. This allows us to avoid performing operations that would have
|
||||
no effect due to relation emptiness, but if the check for emptiness is expensive, its
|
||||
cost may overcome the gains.
|
||||
*/
|
||||
bool m_eager_emptiness_checking;
|
||||
public:
|
||||
execution_context(context & context);
|
||||
~execution_context();
|
||||
|
||||
void reset();
|
||||
|
||||
rel_context & get_rel_context();
|
||||
|
||||
void set_timelimit(unsigned time_in_ms);
|
||||
void reset_timelimit();
|
||||
bool should_terminate();
|
||||
|
||||
bool eager_emptiness_checking() const { return m_eager_emptiness_checking; }
|
||||
|
||||
/**
|
||||
\brief Return reference to \c i -th register that contains pointer to a relation.
|
||||
|
||||
If register contains zero, it should be treated as if it contains an empty relation.
|
||||
*/
|
||||
reg_type reg(reg_idx i) const {
|
||||
if (i >= m_registers.size()) {
|
||||
return 0;
|
||||
}
|
||||
return m_registers[i];
|
||||
}
|
||||
/**
|
||||
\brief Return value of the register and assign zero into it place.
|
||||
*/
|
||||
reg_type release_reg(reg_idx i) {
|
||||
SASSERT(i < m_registers.size());
|
||||
SASSERT(m_registers[i]);
|
||||
reg_type res = m_registers[i];
|
||||
m_registers[i] = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Assign value to a register. If it was non-empty, deallocate its content first.
|
||||
*/
|
||||
void set_reg(reg_idx i, reg_type val) {
|
||||
if (i >= m_registers.size()) {
|
||||
check_overflow(i);
|
||||
m_registers.resize(i+1,0);
|
||||
}
|
||||
if (m_registers[i]) {
|
||||
m_registers[i]->deallocate();
|
||||
}
|
||||
m_registers[i] = val;
|
||||
}
|
||||
|
||||
void make_empty(reg_idx i) {
|
||||
if (reg(i)) {
|
||||
set_reg(i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned register_count() const {
|
||||
return m_registers.size();
|
||||
}
|
||||
|
||||
bool get_register_annotation(reg_idx reg, std::string & res) const {
|
||||
return m_reg_annotation.find(reg, res);
|
||||
}
|
||||
|
||||
void set_register_annotation(reg_idx reg, std::string str) {
|
||||
m_reg_annotation.insert(reg, str);
|
||||
}
|
||||
|
||||
void report_big_relations(unsigned threshold, std::ostream & out) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
// instruction
|
||||
//
|
||||
// -----------------------------------
|
||||
|
||||
|
||||
/**
|
||||
\brief Base class for instructions used in datalog saturation.
|
||||
|
||||
A relation in a register is owned by that register and is not referenced from anywhere else.
|
||||
|
||||
Instructions that move context of one register to another leave the source register empty
|
||||
and deallocate the previous content of the target register.
|
||||
*/
|
||||
class instruction : public accounted_object {
|
||||
typedef u_map<base_relation_fn *> fn_cache;
|
||||
|
||||
fn_cache m_fn_cache;
|
||||
|
||||
|
||||
static const int rk_encode_base = 1024;
|
||||
|
||||
inline static unsigned encode_kind(family_id k)
|
||||
{ SASSERT(k<rk_encode_base); return k; }
|
||||
inline static unsigned encode_kinds(family_id k1, family_id k2)
|
||||
{ SASSERT(k1<rk_encode_base && k2<rk_encode_base); return (k1+1)*rk_encode_base + k2; }
|
||||
inline static unsigned encode_kinds(family_id k1, family_id k2, family_id k3) {
|
||||
SASSERT(k1<rk_encode_base && k2<rk_encode_base && k3<rk_encode_base);
|
||||
return ((k1+1)*rk_encode_base + k2)*rk_encode_base + k3;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend class instruction_block;
|
||||
|
||||
template<typename T>
|
||||
bool find_fn(const relation_base & r, T* & result) const
|
||||
{ return m_fn_cache.find(encode_kind(r.get_kind()), reinterpret_cast<base_relation_fn*&>(result)); }
|
||||
|
||||
template<typename T>
|
||||
bool find_fn(const relation_base & r1, const relation_base & r2, T*& result) const
|
||||
{ return m_fn_cache.find(encode_kinds(r1.get_kind(), r2.get_kind()), reinterpret_cast<base_relation_fn*&>(result)); }
|
||||
|
||||
template<typename T>
|
||||
bool find_fn(const relation_base & r1, const relation_base & r2, const relation_base & r3, T * & result) const
|
||||
{ return m_fn_cache.find(encode_kinds(r1.get_kind(), r2.get_kind(), r3.get_kind()), reinterpret_cast<base_relation_fn*&>(result)); }
|
||||
|
||||
void store_fn(const relation_base & r, base_relation_fn * fn)
|
||||
{ m_fn_cache.insert(encode_kind(r.get_kind()), fn); }
|
||||
void store_fn(const relation_base & r1, const relation_base & r2, base_relation_fn * fn)
|
||||
{ m_fn_cache.insert(encode_kinds(r1.get_kind(), r2.get_kind()), fn); }
|
||||
void store_fn(const relation_base & r1, const relation_base & r2, const relation_base & r3,
|
||||
base_relation_fn * fn)
|
||||
{ m_fn_cache.insert(encode_kinds(r1.get_kind(), r2.get_kind(), r3.get_kind()), fn); }
|
||||
|
||||
/**
|
||||
Process not only costs associated with the current instruction, but in case of
|
||||
block instructions, process also costs associated with its child instructions.
|
||||
*/
|
||||
virtual void process_all_costs();
|
||||
|
||||
/**
|
||||
\brief Output one line header of the current instruction.
|
||||
|
||||
The newline character at the end should not be printed.
|
||||
*/
|
||||
virtual void display_head_impl(rel_context const & ctx, std::ostream & out) const {
|
||||
out << "<instruction>";
|
||||
}
|
||||
/**
|
||||
\brief If relevant, output the body of the current instruction.
|
||||
|
||||
Each line must be prepended by \c indentation and ended by a newline character.
|
||||
*/
|
||||
virtual void display_body_impl(rel_context const & ctx, std::ostream & out, std::string indentation) const {}
|
||||
public:
|
||||
typedef execution_context::reg_type reg_type;
|
||||
typedef execution_context::reg_idx reg_idx;
|
||||
|
||||
virtual ~instruction();
|
||||
|
||||
virtual bool perform(execution_context & ctx) = 0;
|
||||
|
||||
virtual void make_annotations(execution_context & ctx) = 0;
|
||||
|
||||
void display(rel_context_base const& ctx, std::ostream & out) const {
|
||||
display_indented(ctx, out, "");
|
||||
}
|
||||
void display_indented(rel_context_base const & ctx, std::ostream & out, std::string indentation) const;
|
||||
|
||||
static instruction * mk_load(ast_manager & m, func_decl * pred, reg_idx tgt);
|
||||
/**
|
||||
\brief The store operation moves the relation from a register into the context. The register
|
||||
is set to zero after the operation.
|
||||
*/
|
||||
static instruction * mk_store(ast_manager & m, func_decl * pred, reg_idx src);
|
||||
static instruction * mk_dealloc(reg_idx reg); //maybe not necessary
|
||||
static instruction * mk_clone(reg_idx from, reg_idx to);
|
||||
static instruction * mk_move(reg_idx from, reg_idx to);
|
||||
|
||||
/**
|
||||
\brief Return instruction that performs \c body as long as at least one register
|
||||
in \c control_regs contains non-empty relation.
|
||||
|
||||
The instruction object takes over the ownership of the \c body object.
|
||||
*/
|
||||
static instruction * mk_while_loop(unsigned control_reg_cnt, const reg_idx * control_regs,
|
||||
instruction_block * body);
|
||||
|
||||
static instruction * mk_join(reg_idx rel1, reg_idx rel2, unsigned col_cnt,
|
||||
const unsigned * cols1, const unsigned * cols2, reg_idx result);
|
||||
static instruction * mk_filter_equal(ast_manager & m, reg_idx reg, const relation_element & value, unsigned col);
|
||||
static instruction * mk_filter_identical(reg_idx reg, unsigned col_cnt, const unsigned * identical_cols);
|
||||
static instruction * mk_filter_interpreted(reg_idx reg, app_ref & condition);
|
||||
static instruction * mk_filter_interpreted_and_project(reg_idx src, app_ref & condition,
|
||||
unsigned col_cnt, const unsigned * removed_cols, reg_idx result);
|
||||
static instruction * mk_union(reg_idx src, reg_idx tgt, reg_idx delta);
|
||||
static instruction * mk_widen(reg_idx src, reg_idx tgt, reg_idx delta);
|
||||
static instruction * mk_projection(reg_idx src, unsigned col_cnt, const unsigned * removed_cols,
|
||||
reg_idx tgt);
|
||||
static instruction * mk_join_project(reg_idx rel1, reg_idx rel2, unsigned joined_col_cnt,
|
||||
const unsigned * cols1, const unsigned * cols2, unsigned removed_col_cnt,
|
||||
const unsigned * removed_cols, reg_idx result);
|
||||
static instruction * mk_rename(reg_idx src, unsigned cycle_len, const unsigned * permutation_cycle,
|
||||
reg_idx tgt);
|
||||
static instruction * mk_filter_by_negation(reg_idx tgt, reg_idx neg_rel, unsigned col_cnt,
|
||||
const unsigned * cols1, const unsigned * cols2);
|
||||
static instruction * mk_select_equal_and_project(ast_manager & m, reg_idx src,
|
||||
const relation_element & value, unsigned col, reg_idx result);
|
||||
|
||||
static instruction * mk_unary_singleton(ast_manager & m, func_decl* pred, const relation_sort & s, const relation_element & val, reg_idx tgt);
|
||||
static instruction * mk_total(const relation_signature & sig, func_decl* pred, reg_idx tgt);
|
||||
|
||||
/**
|
||||
\brief The mark_saturated instruction marks a relation as saturated, so that after
|
||||
next restart it does not have to be part of the saturation again.
|
||||
*/
|
||||
static instruction * mk_mark_saturated(ast_manager & m, func_decl * pred);
|
||||
|
||||
static instruction * mk_assert_signature(const relation_signature & s, reg_idx tgt);
|
||||
|
||||
};
|
||||
|
||||
|
||||
// -----------------------------------
|
||||
//
|
||||
// instruction_block
|
||||
//
|
||||
// -----------------------------------
|
||||
|
||||
class instruction_block {
|
||||
public:
|
||||
struct instruction_observer {
|
||||
virtual ~instruction_observer() {}
|
||||
virtual void notify(instruction * i) {}
|
||||
};
|
||||
private:
|
||||
typedef ptr_vector<instruction> instr_seq_type;
|
||||
instr_seq_type m_data;
|
||||
instruction_observer* m_observer;
|
||||
public:
|
||||
instruction_block() : m_observer(0) {}
|
||||
~instruction_block();
|
||||
void reset();
|
||||
|
||||
void push_back(instruction * i) {
|
||||
m_data.push_back(i);
|
||||
if(m_observer) {
|
||||
m_observer->notify(i);
|
||||
}
|
||||
}
|
||||
void set_observer(instruction_observer * o) {
|
||||
SASSERT(o==0 || m_observer==0);
|
||||
m_observer = o;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Perform instructions in the block. If the run was interrupted before completion,
|
||||
return false; otherwise return true.
|
||||
|
||||
The execution can terminate before completion if the function
|
||||
\c execution_context::should_terminate() returns true.
|
||||
*/
|
||||
bool perform(execution_context & ctx) const;
|
||||
|
||||
void process_all_costs();
|
||||
|
||||
void make_annotations(execution_context & ctx);
|
||||
|
||||
void display(rel_context_base const & ctx, std::ostream & out) const {
|
||||
display_indented(ctx, out, "");
|
||||
}
|
||||
void display_indented(rel_context_base const & ctx, std::ostream & out, std::string indentation) const;
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* _DL_INSTRUCTION_H_ */
|
||||
|
593
src/muz/rel/rel_context.cpp
Normal file
593
src/muz/rel/rel_context.cpp
Normal file
|
@ -0,0 +1,593 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
rel_context.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
context for relational datalog engine.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-12-3.
|
||||
|
||||
Revision History:
|
||||
|
||||
Extracted from dl_context
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include"rel_context.h"
|
||||
#include"dl_context.h"
|
||||
#include"dl_compiler.h"
|
||||
#include"dl_instruction.h"
|
||||
#include"dl_mk_explanations.h"
|
||||
#include"dl_mk_magic_sets.h"
|
||||
#include"dl_product_relation.h"
|
||||
#include"dl_bound_relation.h"
|
||||
#include"dl_interval_relation.h"
|
||||
#include"karr_relation.h"
|
||||
#include"dl_finite_product_relation.h"
|
||||
#include"dl_sparse_table.h"
|
||||
#include"dl_table.h"
|
||||
#include"dl_table_relation.h"
|
||||
#include"aig_exporter.h"
|
||||
#include"dl_mk_simple_joins.h"
|
||||
#include"dl_mk_similarity_compressor.h"
|
||||
#include"dl_mk_unbound_compressor.h"
|
||||
#include"dl_mk_subsumption_checker.h"
|
||||
#include"dl_mk_partial_equiv.h"
|
||||
#include"dl_mk_coi_filter.h"
|
||||
#include"dl_mk_filter_rules.h"
|
||||
#include"dl_mk_rule_inliner.h"
|
||||
#include"dl_mk_interp_tail_simplifier.h"
|
||||
#include"dl_mk_bit_blast.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)
|
||||
: rel_context_base(ctx.get_manager(), "datalog"),
|
||||
m_context(ctx),
|
||||
m(ctx.get_manager()),
|
||||
m_rmanager(ctx),
|
||||
m_answer(m),
|
||||
m_last_result_relation(0),
|
||||
m_ectx(ctx) {
|
||||
|
||||
// register plugins for builtin tables
|
||||
|
||||
get_rmanager().register_plugin(alloc(sparse_table_plugin, get_rmanager()));
|
||||
get_rmanager().register_plugin(alloc(hashtable_table_plugin, get_rmanager()));
|
||||
get_rmanager().register_plugin(alloc(bitvector_table_plugin, get_rmanager()));
|
||||
get_rmanager().register_plugin(alloc(equivalence_table_plugin, get_rmanager()));
|
||||
|
||||
|
||||
// register plugins for builtin relations
|
||||
|
||||
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) {
|
||||
m_last_result_relation->deallocate();
|
||||
m_last_result_relation = 0;
|
||||
}
|
||||
}
|
||||
|
||||
lbool rel_context::saturate() {
|
||||
scoped_query sq(m_context);
|
||||
return saturate(sq);
|
||||
}
|
||||
|
||||
lbool rel_context::saturate(scoped_query& sq) {
|
||||
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();
|
||||
|
||||
instruction_block termination_code;
|
||||
|
||||
lbool result;
|
||||
|
||||
TRACE("dl", m_context.display(tout););
|
||||
|
||||
while (true) {
|
||||
m_ectx.reset();
|
||||
m_code.reset();
|
||||
termination_code.reset();
|
||||
m_context.ensure_closed();
|
||||
transform_rules();
|
||||
if (m_context.canceled()) {
|
||||
result = l_undef;
|
||||
break;
|
||||
}
|
||||
TRACE("dl", m_context.display(tout););
|
||||
|
||||
if (m_context.get_params().dump_aig().size()) {
|
||||
const char *filename = static_cast<const char*>(m_context.get_params().dump_aig().c_ptr());
|
||||
aig_exporter aig(m_context.get_rules(), get_context(), &m_table_facts);
|
||||
std::ofstream strm(filename, std::ios_base::binary);
|
||||
aig(strm);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
compiler::compile(m_context, m_context.get_rules(), m_code, termination_code);
|
||||
|
||||
TRACE("dl", m_code.display(*this, tout); );
|
||||
|
||||
bool timeout_after_this_round = time_limit && (restart_time==0 || remaining_time_limit<=restart_time);
|
||||
|
||||
if (time_limit || restart_time!=0) {
|
||||
unsigned timeout = time_limit ? (restart_time!=0) ?
|
||||
std::min(remaining_time_limit, restart_time)
|
||||
: remaining_time_limit : restart_time;
|
||||
m_ectx.set_timelimit(timeout);
|
||||
}
|
||||
|
||||
bool early_termination = !m_code.perform(m_ectx);
|
||||
m_ectx.reset_timelimit();
|
||||
VERIFY( termination_code.perform(m_ectx) || m_context.canceled());
|
||||
|
||||
m_code.process_all_costs();
|
||||
|
||||
IF_VERBOSE(10, m_ectx.report_big_relations(1000, verbose_stream()););
|
||||
|
||||
if (m_context.canceled()) {
|
||||
result = l_undef;
|
||||
break;
|
||||
}
|
||||
if (!early_termination) {
|
||||
m_context.set_status(OK);
|
||||
result = l_true;
|
||||
break;
|
||||
}
|
||||
if (memory::above_high_watermark()) {
|
||||
m_context.set_status(MEMOUT);
|
||||
result = l_undef;
|
||||
break;
|
||||
}
|
||||
if (timeout_after_this_round) {
|
||||
m_context.set_status(TIMEOUT);
|
||||
result = l_undef;
|
||||
break;
|
||||
}
|
||||
SASSERT(restart_time != 0);
|
||||
if (time_limit) {
|
||||
SASSERT(remaining_time_limit>restart_time);
|
||||
remaining_time_limit -= restart_time;
|
||||
}
|
||||
uint64 new_restart_time = static_cast<uint64>(restart_time)*m_context.initial_restart_timeout();
|
||||
if (new_restart_time > UINT_MAX) {
|
||||
restart_time = UINT_MAX;
|
||||
}
|
||||
else {
|
||||
restart_time = static_cast<unsigned>(new_restart_time);
|
||||
}
|
||||
sq.reset();
|
||||
}
|
||||
m_context.record_transformed_rules();
|
||||
TRACE("dl", display_profile(tout););
|
||||
return result;
|
||||
}
|
||||
|
||||
lbool rel_context::query(unsigned num_rels, func_decl * const* rels) {
|
||||
get_rmanager().reset_saturated_marks();
|
||||
scoped_query _scoped_query(m_context);
|
||||
for (unsigned i = 0; i < num_rels; ++i) {
|
||||
m_context.set_output_predicate(rels[i]);
|
||||
}
|
||||
m_context.close();
|
||||
reset_negated_tables();
|
||||
lbool res = saturate(_scoped_query);
|
||||
|
||||
switch(res) {
|
||||
case l_true: {
|
||||
expr_ref_vector ans(m);
|
||||
expr_ref e(m);
|
||||
bool some_non_empty = num_rels == 0;
|
||||
bool is_approx = false;
|
||||
for (unsigned i = 0; i < num_rels; ++i) {
|
||||
func_decl* q = m_context.get_rules().get_pred(rels[i]);
|
||||
relation_base& rel = get_relation(q);
|
||||
if (!rel.empty()) {
|
||||
some_non_empty = true;
|
||||
}
|
||||
if (!rel.is_precise()) {
|
||||
is_approx = true;
|
||||
}
|
||||
rel.to_formula(e);
|
||||
ans.push_back(e);
|
||||
}
|
||||
SASSERT(!m_last_result_relation);
|
||||
if (some_non_empty) {
|
||||
m_answer = m.mk_and(ans.size(), ans.c_ptr());
|
||||
if (is_approx) {
|
||||
res = l_undef;
|
||||
m_context.set_status(APPROX);
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_answer = m.mk_false();
|
||||
res = l_false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case l_false:
|
||||
m_answer = m.mk_false();
|
||||
break;
|
||||
case l_undef:
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void rel_context::transform_rules() {
|
||||
rule_transformer transf(m_context);
|
||||
transf.register_plugin(alloc(mk_coi_filter, m_context));
|
||||
transf.register_plugin(alloc(mk_filter_rules, m_context));
|
||||
transf.register_plugin(alloc(mk_simple_joins, m_context));
|
||||
if (m_context.unbound_compressor()) {
|
||||
transf.register_plugin(alloc(mk_unbound_compressor, m_context));
|
||||
}
|
||||
if (m_context.similarity_compressor()) {
|
||||
transf.register_plugin(alloc(mk_similarity_compressor, m_context));
|
||||
}
|
||||
transf.register_plugin(alloc(mk_partial_equivalence_transformer, m_context));
|
||||
transf.register_plugin(alloc(mk_rule_inliner, m_context));
|
||||
transf.register_plugin(alloc(mk_interp_tail_simplifier, m_context));
|
||||
|
||||
if (m_context.get_params().bit_blast()) {
|
||||
transf.register_plugin(alloc(mk_bit_blast, m_context, 22000));
|
||||
transf.register_plugin(alloc(mk_interp_tail_simplifier, m_context, 21000));
|
||||
}
|
||||
m_context.transform_rules(transf);
|
||||
}
|
||||
|
||||
bool rel_context::try_get_size(func_decl* p, unsigned& rel_size) const {
|
||||
relation_base* rb = try_get_relation(p);
|
||||
if (rb && rb->knows_exact_size()) {
|
||||
rel_size = rb->get_size_estimate_rows();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
lbool rel_context::query(expr* query) {
|
||||
get_rmanager().reset_saturated_marks();
|
||||
scoped_query _scoped_query(m_context);
|
||||
rule_manager& rm = m_context.get_rule_manager();
|
||||
func_decl_ref query_pred(m);
|
||||
try {
|
||||
query_pred = rm.mk_query(query, m_context.get_rules());
|
||||
}
|
||||
catch (default_exception& exn) {
|
||||
m_context.set_status(INPUT_ERROR);
|
||||
throw exn;
|
||||
}
|
||||
|
||||
m_context.close();
|
||||
reset_negated_tables();
|
||||
|
||||
if (m_context.generate_explanations()) {
|
||||
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()) {
|
||||
m_context.transform_rules(alloc(mk_magic_sets, m_context, query_pred));
|
||||
query_pred = m_context.get_rules().get_pred(query_pred);
|
||||
}
|
||||
|
||||
lbool res = saturate(_scoped_query);
|
||||
|
||||
query_pred = m_context.get_rules().get_pred(query_pred);
|
||||
|
||||
if (res != l_undef) {
|
||||
m_last_result_relation = get_relation(query_pred).clone();
|
||||
if (m_last_result_relation->empty()) {
|
||||
res = l_false;
|
||||
m_answer = m.mk_false();
|
||||
}
|
||||
else {
|
||||
m_last_result_relation->to_formula(m_answer);
|
||||
if (!m_last_result_relation->is_precise()) {
|
||||
m_context.set_status(APPROX);
|
||||
res = l_undef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void rel_context::reset_negated_tables() {
|
||||
rule_set::pred_set_vector const & pred_sets = m_context.get_rules().get_strats();
|
||||
bool non_empty = false;
|
||||
for (unsigned i = 1; i < pred_sets.size(); ++i) {
|
||||
func_decl_set::iterator it = pred_sets[i]->begin(), end = pred_sets[i]->end();
|
||||
for (; it != end; ++it) {
|
||||
func_decl* pred = *it;
|
||||
relation_base & rel = get_relation(pred);
|
||||
if (!rel.empty()) {
|
||||
non_empty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!non_empty) {
|
||||
return;
|
||||
}
|
||||
// collect predicates that depend on negation.
|
||||
func_decl_set depends_on_negation;
|
||||
for (unsigned i = 1; i < pred_sets.size(); ++i) {
|
||||
bool change = true;
|
||||
while (change) {
|
||||
change = false;
|
||||
func_decl_set::iterator it = pred_sets[i]->begin(), end = pred_sets[i]->end();
|
||||
for (; it != end; ++it) {
|
||||
func_decl* pred = *it;
|
||||
if (depends_on_negation.contains(pred)) {
|
||||
continue;
|
||||
}
|
||||
rule_vector const& rules = m_context.get_rules().get_predicate_rules(pred);
|
||||
bool inserted = false;
|
||||
for (unsigned j = 0; !inserted && j < rules.size(); ++j) {
|
||||
rule* r = rules[j];
|
||||
unsigned psz = r->get_positive_tail_size();
|
||||
unsigned tsz = r->get_uninterpreted_tail_size();
|
||||
if (psz < tsz) {
|
||||
depends_on_negation.insert(pred);
|
||||
change = true;
|
||||
inserted = true;
|
||||
}
|
||||
for (unsigned k = 0; !inserted && k < tsz; ++k) {
|
||||
func_decl* tail_decl = r->get_tail(k)->get_decl();
|
||||
if (depends_on_negation.contains(tail_decl)) {
|
||||
depends_on_negation.insert(pred);
|
||||
change = true;
|
||||
inserted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func_decl_set::iterator it = depends_on_negation.begin(), end = depends_on_negation.end();
|
||||
for (; it != end; ++it) {
|
||||
func_decl* pred = *it;
|
||||
relation_base & rel = get_relation(pred);
|
||||
|
||||
if (!rel.empty()) {
|
||||
TRACE("dl", tout << "Resetting: " << mk_ismt2_pp(pred, m) << "\n";);
|
||||
rel.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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); }
|
||||
relation_base * rel_context::try_get_relation(func_decl * pred) const { return get_rmanager().try_get_relation(pred); }
|
||||
|
||||
expr_ref rel_context::try_get_formula(func_decl* p) const {
|
||||
expr_ref result(m);
|
||||
relation_base* rb = try_get_relation(p);
|
||||
if (rb) {
|
||||
rb->to_formula(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool rel_context::is_empty_relation(func_decl* pred) const {
|
||||
relation_base* rb = try_get_relation(pred);
|
||||
return !rb || rb->empty();
|
||||
}
|
||||
|
||||
relation_manager & rel_context::get_rmanager() { return m_rmanager; }
|
||||
|
||||
const relation_manager & rel_context::get_rmanager() const { return m_rmanager; }
|
||||
|
||||
bool rel_context::output_profile() const { return m_context.output_profile(); }
|
||||
|
||||
|
||||
void rel_context::set_predicate_representation(func_decl * pred, unsigned relation_name_cnt,
|
||||
symbol const * relation_names) {
|
||||
|
||||
TRACE("dl",
|
||||
tout << pred->get_name() << ": ";
|
||||
for (unsigned i = 0; i < relation_name_cnt; ++i) {
|
||||
tout << relation_names[i] << " ";
|
||||
}
|
||||
tout << "\n";
|
||||
);
|
||||
|
||||
relation_manager & rmgr = get_rmanager();
|
||||
family_id target_kind = null_family_id;
|
||||
switch (relation_name_cnt) {
|
||||
case 0:
|
||||
return;
|
||||
case 1:
|
||||
target_kind = get_ordinary_relation_plugin(relation_names[0]).get_kind();
|
||||
break;
|
||||
default: {
|
||||
svector<family_id> rel_kinds; // kinds of plugins that are not table plugins
|
||||
family_id rel_kind; // the aggregate kind of non-table plugins
|
||||
for (unsigned i = 0; i < relation_name_cnt; i++) {
|
||||
relation_plugin & p = get_ordinary_relation_plugin(relation_names[i]);
|
||||
rel_kinds.push_back(p.get_kind());
|
||||
}
|
||||
if (rel_kinds.size() == 1) {
|
||||
rel_kind = rel_kinds[0];
|
||||
}
|
||||
else {
|
||||
relation_signature rel_sig;
|
||||
rmgr.from_predicate(pred, rel_sig);
|
||||
product_relation_plugin & prod_plugin = product_relation_plugin::get_plugin(rmgr);
|
||||
rel_kind = prod_plugin.get_relation_kind(rel_sig, rel_kinds);
|
||||
}
|
||||
target_kind = rel_kind;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SASSERT(target_kind != null_family_id);
|
||||
get_rmanager().set_predicate_kind(pred, target_kind);
|
||||
}
|
||||
|
||||
void rel_context::set_cancel(bool f) {
|
||||
get_rmanager().set_cancel(f);
|
||||
}
|
||||
|
||||
relation_plugin & rel_context::get_ordinary_relation_plugin(symbol relation_name) {
|
||||
relation_plugin * plugin = get_rmanager().get_relation_plugin(relation_name);
|
||||
if (!plugin) {
|
||||
std::stringstream sstm;
|
||||
sstm << "relation plugin " << relation_name << " does not exist";
|
||||
throw default_exception(sstm.str());
|
||||
}
|
||||
if (plugin->is_product_relation()) {
|
||||
throw default_exception("cannot request product relation directly");
|
||||
}
|
||||
if (plugin->is_sieve_relation()) {
|
||||
throw default_exception("cannot request sieve relation directly");
|
||||
}
|
||||
if (plugin->is_finite_product_relation()) {
|
||||
throw default_exception("cannot request finite product relation directly");
|
||||
}
|
||||
return *plugin;
|
||||
}
|
||||
|
||||
bool rel_context::result_contains_fact(relation_fact const& f) {
|
||||
SASSERT(m_last_result_relation);
|
||||
return m_last_result_relation->contains_fact(f);
|
||||
}
|
||||
|
||||
void rel_context::reset_tables() {
|
||||
get_rmanager().reset_saturated_marks();
|
||||
rule_set::decl2rules::iterator it = m_context.get_rules().begin_grouped_rules();
|
||||
rule_set::decl2rules::iterator end = m_context.get_rules().end_grouped_rules();
|
||||
for (; it != end; ++it) {
|
||||
func_decl* p = it->m_key;
|
||||
relation_base & rel = get_relation(p);
|
||||
rel.reset();
|
||||
}
|
||||
for (unsigned i = 0; i < m_table_facts.size(); ++i) {
|
||||
func_decl* pred = m_table_facts[i].first;
|
||||
relation_fact const& fact = m_table_facts[i].second;
|
||||
get_relation(pred).add_fact(fact);
|
||||
}
|
||||
}
|
||||
|
||||
void rel_context::add_fact(func_decl* pred, relation_fact const& fact) {
|
||||
get_rmanager().reset_saturated_marks();
|
||||
get_relation(pred).add_fact(fact);
|
||||
m_table_facts.push_back(std::make_pair(pred, fact));
|
||||
}
|
||||
|
||||
void rel_context::add_fact(func_decl* pred, table_fact const& fact) {
|
||||
get_rmanager().reset_saturated_marks();
|
||||
relation_base & rel0 = get_relation(pred);
|
||||
if (rel0.from_table()) {
|
||||
table_relation & rel = static_cast<table_relation &>(rel0);
|
||||
rel.add_table_fact(fact);
|
||||
// TODO: table facts?
|
||||
}
|
||||
else {
|
||||
relation_fact rfact(m);
|
||||
for (unsigned i = 0; i < fact.size(); ++i) {
|
||||
rfact.push_back(m_context.get_decl_util().mk_numeral(fact[i], pred->get_domain()[i]));
|
||||
}
|
||||
add_fact(pred, rfact);
|
||||
}
|
||||
}
|
||||
|
||||
bool rel_context::has_facts(func_decl * pred) const {
|
||||
relation_base* r = try_get_relation(pred);
|
||||
return r && !r->empty();
|
||||
}
|
||||
|
||||
void rel_context::store_relation(func_decl * pred, relation_base * rel) {
|
||||
get_rmanager().store_relation(pred, rel);
|
||||
}
|
||||
|
||||
void rel_context::inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred) {
|
||||
if (orig_pred) {
|
||||
family_id target_kind = get_rmanager().get_requested_predicate_kind(orig_pred);
|
||||
if (target_kind != null_family_id) {
|
||||
get_rmanager().set_predicate_kind(new_pred, target_kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
get_rmanager().display(out);
|
||||
}
|
||||
|
||||
void rel_context::display_profile(std::ostream& out) {
|
||||
m_code.make_annotations(m_ectx);
|
||||
m_code.process_all_costs();
|
||||
|
||||
out << "\n--------------\n";
|
||||
out << "Instructions\n";
|
||||
m_code.display(*this, out);
|
||||
|
||||
out << "\n--------------\n";
|
||||
out << "Big relations\n";
|
||||
m_ectx.report_big_relations(1000, out);
|
||||
|
||||
get_rmanager().display_relation_sizes(out);
|
||||
}
|
||||
|
||||
|
||||
};
|
130
src/muz/rel/rel_context.h
Normal file
130
src/muz/rel/rel_context.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
rel_context.h
|
||||
|
||||
Abstract:
|
||||
|
||||
context for relational datalog engine.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2012-12-3.
|
||||
|
||||
Revision History:
|
||||
|
||||
Extracted from dl_context
|
||||
|
||||
--*/
|
||||
#ifndef _REL_CONTEXT_H_
|
||||
#define _REL_CONTEXT_H_
|
||||
#include "ast.h"
|
||||
#include "dl_relation_manager.h"
|
||||
#include "dl_instruction.h"
|
||||
#include "dl_engine_base.h"
|
||||
#include "dl_context.h"
|
||||
#include "lbool.h"
|
||||
|
||||
namespace datalog {
|
||||
|
||||
class context;
|
||||
typedef vector<std::pair<func_decl*,relation_fact> > fact_vector;
|
||||
|
||||
class rel_context : public rel_context_base {
|
||||
context& m_context;
|
||||
ast_manager& m;
|
||||
relation_manager m_rmanager;
|
||||
expr_ref m_answer;
|
||||
relation_base * m_last_result_relation;
|
||||
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);
|
||||
|
||||
void reset_tables();
|
||||
|
||||
lbool saturate(scoped_query& sq);
|
||||
|
||||
void set_cancel(bool f);
|
||||
|
||||
public:
|
||||
rel_context(context& ctx);
|
||||
|
||||
virtual ~rel_context();
|
||||
|
||||
virtual relation_manager & get_rmanager();
|
||||
virtual const relation_manager & get_rmanager() const;
|
||||
ast_manager& get_manager() const { return m; }
|
||||
context& get_context() const { return m_context; }
|
||||
virtual relation_base & get_relation(func_decl * pred);
|
||||
virtual relation_base * try_get_relation(func_decl * pred) const;
|
||||
virtual bool is_empty_relation(func_decl* pred) const;
|
||||
virtual expr_ref try_get_formula(func_decl * pred) const;
|
||||
virtual expr_ref get_answer() { return m_answer; }
|
||||
|
||||
virtual bool output_profile() const;
|
||||
|
||||
virtual lbool query(expr* q);
|
||||
virtual lbool query(unsigned num_rels, func_decl * const* rels);
|
||||
|
||||
virtual void set_predicate_representation(func_decl * pred, unsigned relation_name_cnt,
|
||||
symbol const * relation_names);
|
||||
|
||||
virtual void inherit_predicate_kind(func_decl* new_pred, func_decl* orig_pred);
|
||||
|
||||
|
||||
virtual void cancel() { set_cancel(true); }
|
||||
virtual void cleanup() { set_cancel(false);}
|
||||
|
||||
/**
|
||||
\brief Restrict the set of used predicates to \c res.
|
||||
|
||||
The function deallocates unsused relations, it does not deal with rules.
|
||||
*/
|
||||
virtual void restrict_predicates(func_decl_set const& predicates);
|
||||
|
||||
virtual void transform_rules();
|
||||
|
||||
virtual bool try_get_size(func_decl* pred, unsigned& rel_size) const;
|
||||
/**
|
||||
\brief query result if it contains fact.
|
||||
*/
|
||||
virtual bool result_contains_fact(relation_fact const& f);
|
||||
|
||||
virtual void collect_non_empty_predicates(func_decl_set& ps) {
|
||||
return get_rmanager().collect_non_empty_predicates(ps);
|
||||
}
|
||||
|
||||
/** \brief add facts to relation
|
||||
*/
|
||||
virtual void add_fact(func_decl* pred, relation_fact const& fact);
|
||||
virtual void add_fact(func_decl* pred, table_fact const& fact);
|
||||
|
||||
/** \brief check if facts were added to relation
|
||||
*/
|
||||
virtual bool has_facts(func_decl * pred) const;
|
||||
|
||||
/**
|
||||
\brief Store the relation \c rel under the predicate \c pred. The \c context object
|
||||
takes over the ownership of the relation object.
|
||||
*/
|
||||
virtual void store_relation(func_decl * pred, relation_base * rel);
|
||||
|
||||
virtual void display_output_facts(rule_set const& rules, std::ostream & out) const;
|
||||
virtual void display_facts(std::ostream & out) const;
|
||||
|
||||
virtual void display_profile(std::ostream& out);
|
||||
|
||||
virtual lbool saturate();
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _REL_CONTEXT_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue