3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-12 09:03:26 +00:00

Merge branch 'unstable' into contrib

This commit is contained in:
Leonardo de Moura 2013-06-05 14:00:59 -07:00
commit d2a2dbb4b6
230 changed files with 9263 additions and 13830 deletions

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
src/api/dotnet/Properties/AssemblyInfo.cs text eol=crlf

View file

@ -906,6 +906,72 @@ void enum_sort_example() {
std::cout << "2: " << result_goal.as_expr() << std::endl;
}
void expr_vector_example() {
std::cout << "expr_vector example\n";
context c;
const unsigned N = 10;
expr_vector x(c);
for (unsigned i = 0; i < N; i++) {
std::stringstream x_name;
x_name << "x_" << i;
x.push_back(c.int_const(x_name.str().c_str()));
}
solver s(c);
for (unsigned i = 0; i < N; i++) {
s.add(x[i] >= 1);
}
std::cout << s << "\n" << "solving...\n" << s.check() << "\n";
model m = s.get_model();
std::cout << "solution\n" << m;
}
void exists_expr_vector_example() {
std::cout << "exists expr_vector example\n";
context c;
const unsigned N = 10;
expr_vector xs(c);
expr x(c);
expr b(c);
b = c.bool_val(true);
for (unsigned i = 0; i < N; i++) {
std::stringstream x_name;
x_name << "x_" << i;
x = c.int_const(x_name.str().c_str());
xs.push_back(x);
b = b && x >= 0;
}
expr ex(c);
ex = exists(xs, b);
std::cout << ex << std::endl;
}
void substitute_example() {
std::cout << "substitute example\n";
context c;
expr x(c);
x = c.int_const("x");
expr f(c);
f = (x == 2) || (x == 1);
std::cout << f << std::endl;
expr two(c), three(c);
two = c.int_val(2);
three = c.int_val(3);
Z3_ast from[] = { two };
Z3_ast to[] = { three };
expr new_f(c);
new_f = to_expr(c, Z3_substitute(c, f, 1, from, to));
std::cout << new_f << std::endl;
}
int main() {
try {
demorgan(); std::cout << "\n";
@ -937,10 +1003,13 @@ int main() {
tactic_example9(); std::cout << "\n";
tactic_qe(); std::cout << "\n";
tst_visit(); std::cout << "\n";
incremental_example1(); std::cout << "\n";
incremental_example2(); std::cout << "\n";
incremental_example3(); std::cout << "\n";
incremental_example1(); std::cout << "\n";
incremental_example2(); std::cout << "\n";
incremental_example3(); std::cout << "\n";
enum_sort_example(); std::cout << "\n";
expr_vector_example(); std::cout << "\n";
exists_expr_vector_example(); std::cout << "\n";
substitute_example(); std::cout << "\n";
std::cout << "done\n";
}
catch (exception & ex) {

View file

@ -54,7 +54,7 @@ def init_project_def():
add_lib('smt_tactic', ['smt'], 'smt/tactic')
add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls')
# TODO: split muz_qe into muz, qe. Perhaps, we should also consider breaking muz into muz and pdr.
add_lib('muz_qe', ['smt', 'sat', 'smt2parser'])
add_lib('muz_qe', ['smt', 'sat', 'smt2parser', 'aig_tactic'])
add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'muz_qe'], 'tactic/smtlogics')
add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv')
add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'muz_qe', 'sls_tactic', 'subpaving_tactic'], 'tactic/portfolio')

View file

@ -46,7 +46,7 @@ extern "C" {
Z3_TRY;
LOG_Z3_mk_int_symbol(c, i);
RESET_ERROR_CODE();
if (i < 0 || (unsigned)i >= (SIZE_MAX >> PTR_ALIGNMENT)) {
if (i < 0 || (size_t)i >= (SIZE_MAX >> PTR_ALIGNMENT)) {
SET_ERROR_CODE(Z3_IOB);
return 0;
}
@ -1070,6 +1070,10 @@ extern "C" {
case OP_BV2INT: return Z3_OP_BV2INT;
case OP_CARRY: return Z3_OP_CARRY;
case OP_XOR3: return Z3_OP_XOR3;
case OP_BSMUL_NO_OVFL:
case OP_BUMUL_NO_OVFL:
case OP_BSMUL_NO_UDFL:
return Z3_OP_UNINTERPRETED;
default:
UNREACHABLE();
return Z3_OP_UNINTERPRETED;

View file

@ -121,10 +121,20 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \
unsigned sz = Z3_get_bv_sort_size(c, s);
rational max_bound = power(rational(2), sz);
Z3_ast bound = Z3_mk_numeral(c, max_bound.to_string().c_str(), int_s);
Z3_ast pred = Z3_mk_bvslt(c, n, Z3_mk_int(c, 0, s));
Z3_inc_ref(c, bound);
Z3_ast zero = Z3_mk_int(c, 0, s);
Z3_inc_ref(c, zero);
Z3_ast pred = Z3_mk_bvslt(c, n, zero);
Z3_inc_ref(c, pred);
// if n <_sigend 0 then r - s^sz else r
Z3_ast args[2] = { r, bound };
Z3_ast res = Z3_mk_ite(c, pred, Z3_mk_sub(c, 2, args), r);
Z3_ast sub = Z3_mk_sub(c, 2, args);
Z3_inc_ref(c, sub);
Z3_ast res = Z3_mk_ite(c, pred, sub, r);
Z3_dec_ref(c, bound);
Z3_dec_ref(c, pred);
Z3_dec_ref(c, sub);
Z3_dec_ref(c, zero);
RETURN_Z3(res);
}
else {
@ -156,7 +166,14 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \
SET_ERROR_CODE(Z3_INVALID_ARG);
return 0;
}
return Z3_mk_bvshl(c, Z3_mk_int64(c, 1, s), Z3_mk_int64(c, sz - 1, s));
Z3_ast x = Z3_mk_int64(c, 1, s);
Z3_inc_ref(c, x);
Z3_ast y = Z3_mk_int64(c, sz - 1, s);
Z3_inc_ref(c, y);
Z3_ast result = Z3_mk_bvshl(c, x, y);
Z3_dec_ref(c, x);
Z3_dec_ref(c, y);
return result;
Z3_CATCH_RETURN(0);
}
@ -177,17 +194,40 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \
RESET_ERROR_CODE();
if (is_signed) {
Z3_ast zero = Z3_mk_int(c, 0, Z3_get_sort(c, t1));
Z3_inc_ref(c, zero);
Z3_ast r = Z3_mk_bvadd(c, t1, t2);
Z3_ast args[2] = { Z3_mk_bvslt(c, zero, t1), Z3_mk_bvslt(c, zero, t2) };
Z3_inc_ref(c, r);
Z3_ast l1 = Z3_mk_bvslt(c, zero, t1);
Z3_inc_ref(c, l1);
Z3_ast l2 = Z3_mk_bvslt(c, zero, t2);
Z3_inc_ref(c, l2);
Z3_ast args[2] = { l1, l2 };
Z3_ast args_pos = Z3_mk_and(c, 2, args);
return Z3_mk_implies(c, args_pos, Z3_mk_bvslt(c, zero, r));
Z3_inc_ref(c, args_pos);
Z3_ast result = Z3_mk_implies(c, args_pos, Z3_mk_bvslt(c, zero, r));
Z3_dec_ref(c, r);
Z3_dec_ref(c, l1);
Z3_dec_ref(c, l2);
Z3_dec_ref(c, args_pos);
Z3_dec_ref(c, zero);
return result;
}
else {
unsigned sz = Z3_get_bv_sort_size(c, Z3_get_sort(c, t1));
t1 = Z3_mk_zero_ext(c, 1, t1);
Z3_inc_ref(c, t1);
t2 = Z3_mk_zero_ext(c, 1, t2);
Z3_inc_ref(c, t2);
Z3_ast r = Z3_mk_bvadd(c, t1, t2);
return Z3_mk_eq(c, Z3_mk_extract(c, sz, sz, r), Z3_mk_int(c, 0, Z3_mk_bv_sort(c, 1)));
Z3_inc_ref(c, r);
Z3_ast ex = Z3_mk_extract(c, sz, sz, r);
Z3_inc_ref(c, ex);
Z3_ast result = Z3_mk_eq(c, ex, Z3_mk_int(c, 0, Z3_mk_bv_sort(c, 1)));
Z3_dec_ref(c, t1);
Z3_dec_ref(c, t2);
Z3_dec_ref(c, ex);
Z3_dec_ref(c, r);
return result;
}
Z3_CATCH_RETURN(0);
}
@ -197,10 +237,26 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \
Z3_TRY;
RESET_ERROR_CODE();
Z3_ast zero = Z3_mk_int(c, 0, Z3_get_sort(c, t1));
Z3_inc_ref(c, zero);
Z3_ast r = Z3_mk_bvadd(c, t1, t2);
Z3_ast args[2] = { Z3_mk_bvslt(c, t1, zero), Z3_mk_bvslt(c, t2, zero) };
Z3_inc_ref(c, r);
Z3_ast l1 = Z3_mk_bvslt(c, t1, zero);
Z3_inc_ref(c, l1);
Z3_ast l2 = Z3_mk_bvslt(c, t2, zero);
Z3_inc_ref(c, l2);
Z3_ast args[2] = { l1, l2 };
Z3_ast args_neg = Z3_mk_and(c, 2, args);
return Z3_mk_implies(c, args_neg, Z3_mk_bvslt(c, r, zero));
Z3_inc_ref(c, args_neg);
Z3_ast lt = Z3_mk_bvslt(c, r, zero);
Z3_inc_ref(c, lt);
Z3_ast result = Z3_mk_implies(c, args_neg, lt);
Z3_dec_ref(c, lt);
Z3_dec_ref(c, l1);
Z3_dec_ref(c, l2);
Z3_dec_ref(c, r);
Z3_dec_ref(c, args_neg);
Z3_dec_ref(c, zero);
return result;
Z3_CATCH_RETURN(0);
}
@ -208,12 +264,28 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \
Z3_ast Z3_API Z3_mk_bvsub_no_overflow(__in Z3_context c, __in Z3_ast t1, __in Z3_ast t2) {
Z3_TRY;
RESET_ERROR_CODE();
Z3_sort s = Z3_get_sort(c, t2);
Z3_ast minus_t2 = Z3_mk_bvneg(c, t2);
Z3_inc_ref(c, minus_t2);
Z3_sort s = Z3_get_sort(c, t2);
Z3_ast min = Z3_mk_bvsmin(c, s);
return Z3_mk_ite(c, Z3_mk_eq(c, t2, min),
Z3_mk_bvslt(c, t1, Z3_mk_int(c, 0, s)),
Z3_mk_bvadd_no_overflow(c, t1, minus_t2, true));
Z3_inc_ref(c, min);
Z3_ast x = Z3_mk_eq(c, t2, min);
Z3_inc_ref(c, x);
Z3_ast zero = Z3_mk_int(c, 0, s);
Z3_inc_ref(c, zero);
Z3_ast y = Z3_mk_bvslt(c, t1, zero);
Z3_inc_ref(c, y);
Z3_ast z = Z3_mk_bvadd_no_overflow(c, t1, minus_t2, true);
Z3_inc_ref(c, z);
Z3_ast result = Z3_mk_ite(c, x, y, z);
mk_c(c)->save_ast_trail(to_app(result));
Z3_dec_ref(c, minus_t2);
Z3_dec_ref(c, min);
Z3_dec_ref(c, x);
Z3_dec_ref(c, y);
Z3_dec_ref(c, z);
Z3_dec_ref(c, zero);
return result;
Z3_CATCH_RETURN(0);
}
@ -222,10 +294,19 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \
RESET_ERROR_CODE();
if (is_signed) {
Z3_ast zero = Z3_mk_int(c, 0, Z3_get_sort(c, t1));
if (Z3_get_error_code(c) != Z3_OK) return 0;
Z3_inc_ref(c, zero);
Z3_ast minus_t2 = Z3_mk_bvneg(c, t2);
if (Z3_get_error_code(c) != Z3_OK) return 0;
return Z3_mk_implies(c, Z3_mk_bvslt(c, zero, t2), Z3_mk_bvadd_no_underflow(c, t1, minus_t2));
Z3_inc_ref(c, minus_t2);
Z3_ast x = Z3_mk_bvslt(c, zero, t2);
Z3_inc_ref(c, x);
Z3_ast y = Z3_mk_bvadd_no_underflow(c, t1, minus_t2);
Z3_inc_ref(c, y);
Z3_ast result = Z3_mk_implies(c, x, y);
Z3_dec_ref(c, zero);
Z3_dec_ref(c, minus_t2);
Z3_dec_ref(c, x);
Z3_dec_ref(c, y);
return result;
}
else {
return Z3_mk_bvule(c, t2, t1);
@ -267,12 +348,24 @@ Z3_ast Z3_API NAME(Z3_context c, unsigned i, Z3_ast n) { \
Z3_TRY;
RESET_ERROR_CODE();
Z3_sort s = Z3_get_sort(c, t1);
if (Z3_get_error_code(c) != Z3_OK) return 0;
Z3_ast min = Z3_mk_bvmsb(c, s);
if (Z3_get_error_code(c) != Z3_OK) return 0;
Z3_ast args[2] = { Z3_mk_eq(c, t1, min),
Z3_mk_eq(c, t2, Z3_mk_int(c, -1, s)) };
return Z3_mk_not(c, Z3_mk_and(c, 2, args));
Z3_inc_ref(c, min);
Z3_ast x = Z3_mk_eq(c, t1, min);
Z3_inc_ref(c, x);
Z3_ast y = Z3_mk_int(c, -1, s);
Z3_inc_ref(c, y);
Z3_ast z = Z3_mk_eq(c, t2, y);
Z3_inc_ref(c, z);
Z3_ast args[2] = { x, z };
Z3_ast u = Z3_mk_and(c, 2, args);
Z3_inc_ref(c, u);
Z3_ast result = Z3_mk_not(c, u);
Z3_dec_ref(c, min);
Z3_dec_ref(c, x);
Z3_dec_ref(c, y);
Z3_dec_ref(c, z);
Z3_dec_ref(c, u);
return result;
Z3_CATCH_RETURN(0);
}

View file

@ -29,7 +29,6 @@ Revision History:
#define Z3_CATCH_RETURN_NO_HANDLE(VAL) } catch (z3_exception &) { return VAL; }
#define CHECK_REF_COUNT(a) (reinterpret_cast<ast const*>(a)->get_ref_count() > 0)
#define VALIDATE(a) SASSERT(!a || CHECK_REF_COUNT(a))
namespace api {
// Generic wrapper for ref-count objects exposed by the API
@ -44,30 +43,30 @@ namespace api {
};
};
inline ast * to_ast(Z3_ast a) { VALIDATE(a); return reinterpret_cast<ast *>(a); }
inline ast * to_ast(Z3_ast a) { return reinterpret_cast<ast *>(a); }
inline Z3_ast of_ast(ast* a) { return reinterpret_cast<Z3_ast>(a); }
inline expr * to_expr(Z3_ast a) { VALIDATE(a); return reinterpret_cast<expr*>(a); }
inline expr * to_expr(Z3_ast a) { return reinterpret_cast<expr*>(a); }
inline Z3_ast of_expr(expr* e) { return reinterpret_cast<Z3_ast>(e); }
inline expr * const * to_exprs(Z3_ast const* a) { return reinterpret_cast<expr* const*>(a); }
inline Z3_ast * const * of_exprs(expr* const* e) { return reinterpret_cast<Z3_ast* const*>(e); }
inline app * to_app(Z3_app a) { VALIDATE(a); return reinterpret_cast<app*>(a); }
inline app * to_app(Z3_ast a) { VALIDATE(a); return reinterpret_cast<app*>(a); }
inline app * to_app(Z3_app a) { return reinterpret_cast<app*>(a); }
inline app * to_app(Z3_ast a) { return reinterpret_cast<app*>(a); }
inline Z3_app of_app(app* a) { return reinterpret_cast<Z3_app>(a); }
inline app * const* to_apps(Z3_ast const* a) { VALIDATE(a); return reinterpret_cast<app * const*>(a); }
inline app * const* to_apps(Z3_ast const* a) { return reinterpret_cast<app * const*>(a); }
inline ast * const * to_asts(Z3_ast const* a) { return reinterpret_cast<ast* const*>(a); }
inline sort * to_sort(Z3_sort a) { VALIDATE(a); return reinterpret_cast<sort*>(a); }
inline sort * to_sort(Z3_sort a) { return reinterpret_cast<sort*>(a); }
inline Z3_sort of_sort(sort* s) { return reinterpret_cast<Z3_sort>(s); }
inline sort * const * to_sorts(Z3_sort const* a) { return reinterpret_cast<sort* const*>(a); }
inline Z3_sort const * of_sorts(sort* const* s) { return reinterpret_cast<Z3_sort const*>(s); }
inline func_decl * to_func_decl(Z3_func_decl a) { VALIDATE(a); return reinterpret_cast<func_decl*>(a); }
inline func_decl * to_func_decl(Z3_func_decl a) { return reinterpret_cast<func_decl*>(a); }
inline Z3_func_decl of_func_decl(func_decl* f) { return reinterpret_cast<Z3_func_decl>(f); }
inline func_decl * const * to_func_decls(Z3_func_decl const* f) { return reinterpret_cast<func_decl*const*>(f); }
@ -75,7 +74,7 @@ inline func_decl * const * to_func_decls(Z3_func_decl const* f) { return reinter
inline symbol to_symbol(Z3_symbol s) { return symbol::mk_symbol_from_c_ptr(reinterpret_cast<void*>(s)); }
inline Z3_symbol of_symbol(symbol s) { return reinterpret_cast<Z3_symbol>(const_cast<void*>(s.c_ptr())); }
inline Z3_pattern of_pattern(ast* a) { VALIDATE(a); return reinterpret_cast<Z3_pattern>(a); }
inline Z3_pattern of_pattern(ast* a) { return reinterpret_cast<Z3_pattern>(a); }
inline app* to_pattern(Z3_pattern p) { return reinterpret_cast<app*>(p); }
inline Z3_lbool of_lbool(lbool b) { return static_cast<Z3_lbool>(b); }

View file

@ -249,6 +249,8 @@ namespace z3 {
array & operator=(array const & s);
public:
array(unsigned sz):m_size(sz) { m_array = new T[sz]; }
template<typename T2>
array(ast_vector_tpl<T2> const & v);
~array() { delete[] m_array; }
unsigned size() const { return m_size; }
T & operator[](int i) { assert(0 <= i); assert(static_cast<unsigned>(i) < m_size); return m_array[i]; }
@ -872,7 +874,18 @@ namespace z3 {
\brief Return a simplified version of this expression. The parameter \c p is a set of parameters for the Z3 simplifier.
*/
expr simplify(params const & p) const { Z3_ast r = Z3_simplify_ex(ctx(), m_ast, p); check_error(); return expr(ctx(), r); }
};
/**
\brief Apply substitution. Replace src expressions by dst.
*/
expr substitute(expr_vector const& src, expr_vector const& dst);
/**
\brief Apply substitution. Replace bound variables by expressions.
*/
expr substitute(expr_vector const& dst);
};
/**
\brief Wraps a Z3_ast as an expr object. It also checks for errors.
@ -928,49 +941,6 @@ namespace z3 {
inline expr udiv(expr const & a, int b) { return udiv(a, a.ctx().num_val(b, a.get_sort())); }
inline expr udiv(int a, expr const & b) { return udiv(b.ctx().num_val(a, b.get_sort()), b); }
// Basic functions for creating quantified formulas.
// The C API should be used for creating quantifiers with patterns, weights, many variables, etc.
inline expr forall(expr const & x, expr const & b) {
check_context(x, b);
Z3_app vars[] = {(Z3_app) x};
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr forall(expr const & x1, expr const & x2, expr const & b) {
check_context(x1, b); check_context(x2, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2};
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & b) {
check_context(x1, b); check_context(x2, b); check_context(x3, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 };
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) {
check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 };
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr exists(expr const & x, expr const & b) {
check_context(x, b);
Z3_app vars[] = {(Z3_app) x};
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr exists(expr const & x1, expr const & x2, expr const & b) {
check_context(x1, b); check_context(x2, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2};
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & b) {
check_context(x1, b); check_context(x2, b); check_context(x3, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 };
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) {
check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 };
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
template<typename T> class cast_ast;
template<> class cast_ast<ast> {
@ -1032,6 +1002,67 @@ namespace z3 {
friend std::ostream & operator<<(std::ostream & out, ast_vector_tpl const & v) { out << Z3_ast_vector_to_string(v.ctx(), v); return out; }
};
template<typename T>
template<typename T2>
array<T>::array(ast_vector_tpl<T2> const & v) {
m_array = new T[v.size()];
m_size = v.size();
for (unsigned i = 0; i < m_size; i++) {
m_array[i] = v[i];
}
}
// Basic functions for creating quantified formulas.
// The C API should be used for creating quantifiers with patterns, weights, many variables, etc.
inline expr forall(expr const & x, expr const & b) {
check_context(x, b);
Z3_app vars[] = {(Z3_app) x};
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr forall(expr const & x1, expr const & x2, expr const & b) {
check_context(x1, b); check_context(x2, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2};
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & b) {
check_context(x1, b); check_context(x2, b); check_context(x3, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 };
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr forall(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) {
check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 };
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr forall(expr_vector const & xs, expr const & b) {
array<Z3_app> vars(xs);
Z3_ast r = Z3_mk_forall_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr exists(expr const & x, expr const & b) {
check_context(x, b);
Z3_app vars[] = {(Z3_app) x};
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 1, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr exists(expr const & x1, expr const & x2, expr const & b) {
check_context(x1, b); check_context(x2, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2};
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 2, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & b) {
check_context(x1, b); check_context(x2, b); check_context(x3, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3 };
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 3, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr exists(expr const & x1, expr const & x2, expr const & x3, expr const & x4, expr const & b) {
check_context(x1, b); check_context(x2, b); check_context(x3, b); check_context(x4, b);
Z3_app vars[] = {(Z3_app) x1, (Z3_app) x2, (Z3_app) x3, (Z3_app) x4 };
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, 4, vars, 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
inline expr exists(expr_vector const & xs, expr const & b) {
array<Z3_app> vars(xs);
Z3_ast r = Z3_mk_exists_const(b.ctx(), 0, vars.size(), vars.ptr(), 0, 0, b); b.check_error(); return expr(b.ctx(), r);
}
class func_entry : public object {
Z3_func_entry m_entry;
void init(Z3_func_entry e) {
@ -1681,6 +1712,30 @@ namespace z3 {
return expr(d.ctx(), r);
}
inline expr expr::substitute(expr_vector const& src, expr_vector const& dst) {
assert(src.size() == dst.size());
array<Z3_ast> _src(src.size());
array<Z3_ast> _dst(dst.size());
for (unsigned i = 0; i < src.size(); ++i) {
_src[i] = src[i];
_dst[i] = dst[i];
}
Z3_ast r = Z3_substitute(ctx(), m_ast, src.size(), _src.ptr(), _dst.ptr());
check_error();
return expr(ctx(), r);
}
inline expr expr::substitute(expr_vector const& dst) {
array<Z3_ast> _dst(dst.size());
for (unsigned i = 0; i < dst.size(); ++i) {
_dst[i] = dst[i];
}
Z3_ast r = Z3_substitute_vars(ctx(), m_ast, dst.size(), _dst.ptr());
check_error();
return expr(ctx(), r);
}
};

View file

@ -44,6 +44,21 @@ namespace Microsoft.Z3
/// <summary>
/// Constructor.
/// </summary>
/// <remarks>
/// The following parameters can be set:
/// - proof (Boolean) Enable proof generation
/// - debug_ref_count (Boolean) Enable debug support for Z3_ast reference counting
/// - trace (Boolean) Tracing support for VCC
/// - trace_file_name (String) Trace out file for VCC traces
/// - timeout (unsigned) default timeout (in milliseconds) used for solvers
/// - well_sorted_check type checker
/// - auto_config use heuristics to automatically select solver and configure it
/// - model model generation for solvers, this parameter can be overwritten when creating a solver
/// - model_validate validate models produced by solvers
/// - unsat_core unsat-core generation for solvers, this parameter can be overwritten when creating a solver
/// Note that in previous versions of Z3, this constructor was also used to set global and module parameters.
/// For this purpose we should now use <see cref="Global.SetParameter"/>
/// </remarks>
public Context(Dictionary<string, string> settings)
: base()
{

View file

@ -27,6 +27,21 @@ public class Context extends IDisposable
/**
* Constructor.
* <remarks>
* The following parameters can be set:
* - proof (Boolean) Enable proof generation
* - debug_ref_count (Boolean) Enable debug support for Z3_ast reference counting
* - trace (Boolean) Tracing support for VCC
* - trace_file_name (String) Trace out file for VCC traces
* - timeout (unsigned) default timeout (in milliseconds) used for solvers
* - well_sorted_check type checker
* - auto_config use heuristics to automatically select solver and configure it
* - model model generation for solvers, this parameter can be overwritten when creating a solver
* - model_validate validate models produced by solvers
* - unsat_core unsat-core generation for solvers, this parameter can be overwritten when creating a solver
* Note that in previous versions of Z3, this constructor was also used to set global and
* module parameters. For this purpose we should now use <see cref="Global.setParameter"/>
* </remarks>
**/
public Context(Map<String, String> settings) throws Z3Exception
{

View file

@ -585,6 +585,9 @@ class FuncDeclRef(AstRef):
def as_ast(self):
return Z3_func_decl_to_ast(self.ctx_ref(), self.ast)
def as_func_decl(self):
return self.ast
def name(self):
"""Return the name of the function declaration `self`.

View file

@ -268,6 +268,8 @@ public:
bool is_int_real(expr const * n) const { return is_int_real(get_sort(n)); }
MATCH_UNARY(is_uminus);
MATCH_UNARY(is_to_real);
MATCH_UNARY(is_to_int);
MATCH_BINARY(is_sub);
MATCH_BINARY(is_add);
MATCH_BINARY(is_mul);

View file

@ -300,7 +300,7 @@ std::ostream & operator<<(std::ostream & out, func_decl_info const & info) {
//
// -----------------------------------
char const * g_ast_kind_names[] = {"application", "variable", "quantifier", "sort", "function declaration" };
static char const * g_ast_kind_names[] = {"application", "variable", "quantifier", "sort", "function declaration" };
char const * get_ast_kind_name(ast_kind k) {
return g_ast_kind_names[k];
@ -2755,7 +2755,7 @@ proof * ast_manager::mk_unit_resolution(unsigned num_proofs, proof * const * pro
app const * cls = to_app(f1);
unsigned num_args = cls->get_num_args();
#ifdef Z3DEBUG
vector<bool> found;
svector<bool> found;
#endif
for (unsigned i = 0; i < num_args; i++) {
expr * lit = cls->get_arg(i);

View file

@ -1193,7 +1193,6 @@ enum pattern_op_kind {
heurisitic quantifier instantiation.
*/
class pattern_decl_plugin : public decl_plugin {
sort * m_list;
public:
virtual decl_plugin * mk_fresh() { return alloc(pattern_decl_plugin); }

View file

@ -260,6 +260,7 @@ class smt_printer {
else {
m_out << sym << "[";
}
for (unsigned i = 0; i < num_params; ++i) {
parameter const& p = params[i];
if (p.is_ast()) {
@ -642,9 +643,7 @@ class smt_printer {
m_out << m_var_names[m_num_var_names - idx - 1];
}
else {
if (!m_is_smt2) {
m_out << "?" << idx;
}
m_out << "?" << idx;
}
}

View file

@ -326,6 +326,7 @@ namespace datalog {
}
unsigned index0;
sort* last_sort = 0;
SASSERT(num_params > 0);
for (unsigned i = 0; i < num_params; ++i) {
parameter const& p = params[i];
if (!p.is_int()) {
@ -636,6 +637,10 @@ 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));
}
@ -656,9 +661,9 @@ namespace datalog {
return 0;
}
bool dl_decl_util::is_numeral(expr* e, uint64& v) const {
bool dl_decl_util::is_numeral(const expr* e, uint64& v) const {
if (is_numeral(e)) {
app* c = to_app(e);
const app* c = to_app(e);
SASSERT(c->get_decl()->get_num_parameters() == 2);
parameter const& p = c->get_decl()->get_parameter(0);
SASSERT(p.is_rational());

View file

@ -169,11 +169,11 @@ namespace datalog {
app* mk_le(expr* a, expr* b);
bool is_lt(expr* a) { return is_app_of(a, m_fid, OP_DL_LT); }
bool is_lt(const expr* a) const { return is_app_of(a, m_fid, OP_DL_LT); }
bool is_numeral(expr* c) const { return is_app_of(c, m_fid, OP_DL_CONSTANT); }
bool is_numeral(const expr* c) const { return is_app_of(c, m_fid, OP_DL_CONSTANT); }
bool is_numeral(expr* e, uint64& v) const;
bool is_numeral(const expr* e, uint64& v) const;
//
// Utilities for extracting constants

View file

@ -20,52 +20,50 @@ Notes:
#include "expr_abstract.h"
#include "map.h"
void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) {
ast_ref_vector pinned(m);
ptr_vector<expr> stack;
obj_map<expr, expr*> map;
void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) {
expr * curr = 0, *b = 0;
SASSERT(n->get_ref_count() > 0);
stack.push_back(n);
m_stack.push_back(n);
for (unsigned i = 0; i < num_bound; ++i) {
b = bound[i];
expr* v = m.mk_var(base + num_bound - i - 1, m.get_sort(b));
pinned.push_back(v);
map.insert(b, v);
m_pinned.push_back(v);
m_map.insert(b, v);
}
while(!stack.empty()) {
curr = stack.back();
if (map.contains(curr)) {
stack.pop_back();
while(!m_stack.empty()) {
curr = m_stack.back();
if (m_map.contains(curr)) {
m_stack.pop_back();
continue;
}
switch(curr->get_kind()) {
case AST_VAR: {
map.insert(curr, curr);
stack.pop_back();
m_map.insert(curr, curr);
m_stack.pop_back();
break;
}
case AST_APP: {
app* a = to_app(curr);
bool all_visited = true;
ptr_vector<expr> args;
m_args.reset();
for (unsigned i = 0; i < a->get_num_args(); ++i) {
if (!map.find(a->get_arg(i), b)) {
stack.push_back(a->get_arg(i));
if (!m_map.find(a->get_arg(i), b)) {
m_stack.push_back(a->get_arg(i));
all_visited = false;
}
else {
args.push_back(b);
m_args.push_back(b);
}
}
if (all_visited) {
b = m.mk_app(a->get_decl(), args.size(), args.c_ptr());
pinned.push_back(b);
map.insert(curr, b);
stack.pop_back();
b = m.mk_app(a->get_decl(), m_args.size(), m_args.c_ptr());
m_pinned.push_back(b);
m_map.insert(curr, b);
m_stack.pop_back();
}
break;
}
@ -81,17 +79,24 @@ void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* cons
}
expr_abstract(m, new_base, num_bound, bound, q->get_expr(), result1);
b = m.update_quantifier(q, patterns.size(), patterns.c_ptr(), result1.get());
pinned.push_back(b);
map.insert(curr, b);
stack.pop_back();
m_pinned.push_back(b);
m_map.insert(curr, b);
m_stack.pop_back();
break;
}
default:
UNREACHABLE();
}
}
if (!map.find(n, b)) {
UNREACHABLE();
}
VERIFY (m_map.find(n, b));
result = b;
m_pinned.reset();
m_map.reset();
m_stack.reset();
m_args.reset();
}
void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) {
expr_abstractor abs(m);
abs(base, num_bound, bound, n, result);
}

View file

@ -21,6 +21,17 @@ Notes:
#include"ast.h"
class expr_abstractor {
ast_manager& m;
expr_ref_vector m_pinned;
ptr_vector<expr> m_stack, m_args;
obj_map<expr, expr*> m_map;
public:
expr_abstractor(ast_manager& m): m(m), m_pinned(m) {}
void operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result);
};
void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result);
#endif

View file

@ -200,6 +200,7 @@ func_decl * float_decl_plugin::mk_float_const_decl(decl_kind k, unsigned num_par
}
else {
m_manager->raise_exception("sort of floating point constant was not specified");
UNREACHABLE();
}
SASSERT(is_sort_of(s, m_family_id, FLOAT_SORT));

View file

@ -79,7 +79,6 @@ void func_decl_dependencies::collect_ng_func_decls(expr * n, func_decl_set * s)
*/
class func_decl_dependencies::top_sort {
enum color { OPEN, IN_PROGRESS, CLOSED };
ast_manager & m_manager;
dependency_graph & m_deps;
typedef obj_map<func_decl, color> color_map;
@ -177,7 +176,7 @@ class func_decl_dependencies::top_sort {
}
public:
top_sort(ast_manager & m, dependency_graph & deps):m_manager(m), m_deps(deps) {}
top_sort(dependency_graph & deps) : m_deps(deps) {}
bool operator()(func_decl * new_decl) {
@ -198,7 +197,7 @@ bool func_decl_dependencies::insert(func_decl * f, func_decl_set * s) {
m_deps.insert(f, s);
top_sort cycle_detector(m_manager, m_deps);
top_sort cycle_detector(m_deps);
if (cycle_detector(f)) {
m_deps.erase(f);
dealloc(s);

View file

@ -22,10 +22,9 @@ Revision History:
#include"uint_set.h"
#include"var_subst.h"
quasi_macros::quasi_macros(ast_manager & m, macro_manager & mm, basic_simplifier_plugin & p, simplifier & s) :
quasi_macros::quasi_macros(ast_manager & m, macro_manager & mm, simplifier & s) :
m_manager(m),
m_macro_manager(mm),
m_bsimp(p),
m_simplifier(s),
m_new_vars(m),
m_new_eqs(m),

View file

@ -32,7 +32,6 @@ class quasi_macros {
ast_manager & m_manager;
macro_manager & m_macro_manager;
basic_simplifier_plugin & m_bsimp;
simplifier & m_simplifier;
occurrences_map m_occurrences;
ptr_vector<expr> m_todo;
@ -57,7 +56,7 @@ class quasi_macros {
void apply_macros(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs);
public:
quasi_macros(ast_manager & m, macro_manager & mm, basic_simplifier_plugin & p, simplifier & s);
quasi_macros(ast_manager & m, macro_manager & mm, simplifier & s);
~quasi_macros();
/**

View file

@ -119,13 +119,13 @@
:pattern (?select (?select (?asElems e) a) i))))
(assert (forall ((x Int) (f Int) (a0 Int))
(!
(or (<= (+ a0 (* -1 (?fClosedTime f))) 0)
(or (<= (+ a0 (* (- 1) (?fClosedTime f))) 0)
(not (= (?isAllocated x a0) 1))
(= (?isAllocated (?select f x) a0) 1))
:pattern (?isAllocated (?select f x) a0))))
(assert (forall ((a Int) (e Int) (i Int) (a0 Int))
(!
(or (<= (+ a0 (* -1 (?eClosedTime e))) 0)
(or (<= (+ a0 (* (- 1) (?eClosedTime e))) 0)
(not (= (?isAllocated a a0) 1))
(= (?isAllocated (?select (?select e a) i) a0) 1))
:pattern (?isAllocated (?select (?select e a) i) a0))))
@ -281,13 +281,13 @@
:pattern (IntsAllocated h (?StructGet_ s f)))))
(assert (forall ((x Int) (f Int) (a0 Int))
(!
(or (<= (+ a0 (* -1 (?fClosedTime f))) 0)
(or (<= (+ a0 (* (- 1) (?fClosedTime f))) 0)
(not (?isAllocated_ x a0))
(?isAllocated_ (?select f x) a0))
:pattern (?isAllocated_ (?select f x) a0))))
(assert (forall ((a Int) (e Int) (i Int) (a0 Int))
(!
(or (<= (+ a0 (* -1 (?eClosedTime e))) 0)
(or (<= (+ a0 (* (- 1) (?eClosedTime e))) 0)
(not (?isAllocated_ a a0))
(?isAllocated_ (?select (?select e a) i) a0))
:pattern (?isAllocated_ (?select (?select e a) i) a0))))

View file

@ -30,7 +30,7 @@ class recurse_expr : public Visitor {
vector<T, CallDestructors> m_results2;
bool is_cached(expr * n) const { T c; return m_cache.find(n, c); }
T get_cached(expr * n) const { T c; m_cache.find(n, c); return c; }
T get_cached(expr * n) const { return m_cache.find(n); }
void cache_result(expr * n, T c) { m_cache.insert(n, c); }
void visit(expr * n, bool & visited);

View file

@ -25,6 +25,7 @@ void array_rewriter::updt_params(params_ref const & _p) {
array_rewriter_params p(_p);
m_sort_store = p.sort_store();
m_expand_select_store = p.expand_select_store();
m_expand_store_eq = p.expand_store_eq();
}
void array_rewriter::get_param_descrs(param_descrs & r) {
@ -365,3 +366,40 @@ br_status array_rewriter::mk_set_subset(expr * arg1, expr * arg2, expr_ref & res
return BR_REWRITE3;
}
br_status array_rewriter::mk_eq_core(expr * lhs, expr * rhs, expr_ref & result) {
if (!m_expand_store_eq) {
return BR_FAILED;
}
expr* lhs1 = lhs;
while (m_util.is_store(lhs1)) {
lhs1 = to_app(lhs1)->get_arg(0);
}
expr* rhs1 = rhs;
while (m_util.is_store(rhs1)) {
rhs1 = to_app(rhs1)->get_arg(0);
}
if (lhs1 != rhs1) {
return BR_FAILED;
}
ptr_buffer<expr> fmls, args;
expr* e;
expr_ref tmp1(m()), tmp2(m());
#define MK_EQ() \
while (m_util.is_store(e)) { \
args.push_back(lhs); \
args.append(to_app(e)->get_num_args()-2,to_app(e)->get_args()+1); \
mk_select(args.size(), args.c_ptr(), tmp1); \
args[0] = rhs; \
mk_select(args.size(), args.c_ptr(), tmp2); \
fmls.push_back(m().mk_eq(tmp1, tmp2)); \
e = to_app(e)->get_arg(0); \
args.reset(); \
} \
e = lhs;
MK_EQ();
e = rhs;
MK_EQ();
result = m().mk_and(fmls.size(), fmls.c_ptr());
return BR_REWRITE_FULL;
}

View file

@ -31,12 +31,14 @@ class array_rewriter {
array_util m_util;
bool m_sort_store;
bool m_expand_select_store;
bool m_expand_store_eq;
template<bool CHECK_DISEQ>
lbool compare_args(unsigned num_args, expr * const * args1, expr * const * args2);
public:
array_rewriter(ast_manager & m, params_ref const & p = params_ref()):
m_util(m) {
updt_params(p);
}
ast_manager & m() const { return m_util.get_manager(); }
family_id get_fid() const { return m_util.get_family_id(); }
@ -60,6 +62,7 @@ public:
br_status mk_set_complement(expr * arg, expr_ref & result);
br_status mk_set_difference(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_set_subset(expr * arg1, expr * arg2, expr_ref & result);
br_status mk_eq_core(expr * lhs, expr * rhs, expr_ref & result);
};
#endif

View file

@ -2,4 +2,5 @@ def_module_params(module_name='rewriter',
class_name='array_rewriter_params',
export=True,
params=(("expand_select_store", BOOL, False, "replace a (select (store ...) ...) term by an if-then-else term"),
("expand_store_eq", BOOL, False, "reduce (store ...) = (store ...) with a common base into selects"),
("sort_store", BOOL, False, "sort nested stores when the indices are known to be different")))

View file

@ -93,7 +93,9 @@ void var_counter::count_vars(ast_manager & m, const app * pred, int coef) {
unsigned n = pred->get_num_args();
for (unsigned i = 0; i < n; i++) {
m_sorts.reset();
::get_free_vars(pred->get_arg(i), m_sorts);
m_todo.reset();
m_mark.reset();
::get_free_vars(m_mark, m_todo, pred->get_arg(i), m_sorts);
for (unsigned j = 0; j < m_sorts.size(); ++j) {
if (m_sorts[j]) {
update(j, coef);
@ -108,24 +110,27 @@ unsigned var_counter::get_max_var(bool& has_var) {
unsigned max_var = 0;
while (!m_todo.empty()) {
expr* e = m_todo.back();
unsigned scope = m_scopes.back();
m_todo.pop_back();
m_scopes.pop_back();
if (m_visited.is_marked(e)) {
continue;
}
m_visited.mark(e, true);
switch(e->get_kind()) {
case AST_QUANTIFIER: {
var_counter aux_counter;
quantifier* q = to_quantifier(e);
m_todo.push_back(q->get_expr());
m_scopes.push_back(scope + q->get_num_decls());
bool has_var1 = false;
unsigned max_v = aux_counter.get_max_var(has_var1);
if (max_v > max_var + q->get_num_decls()) {
max_var = max_v - q->get_num_decls();
has_var = true;
}
break;
}
case AST_VAR: {
if (to_var(e)->get_idx() >= scope + max_var) {
if (to_var(e)->get_idx() >= max_var) {
has_var = true;
max_var = to_var(e)->get_idx() - scope;
max_var = to_var(e)->get_idx();
}
break;
}
@ -133,7 +138,6 @@ unsigned var_counter::get_max_var(bool& has_var) {
app* a = to_app(e);
for (unsigned i = 0; i < a->get_num_args(); ++i) {
m_todo.push_back(a->get_arg(i));
m_scopes.push_back(scope);
}
break;
}
@ -150,14 +154,12 @@ unsigned var_counter::get_max_var(bool& has_var) {
unsigned var_counter::get_max_var(expr* e) {
bool has_var = false;
m_todo.push_back(e);
m_scopes.push_back(0);
return get_max_var(has_var);
}
unsigned var_counter::get_next_var(expr* e) {
bool has_var = false;
m_todo.push_back(e);
m_scopes.push_back(0);
unsigned mv = get_max_var(has_var);
if (has_var) mv++;
return mv;

View file

@ -38,6 +38,7 @@ public:
counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {}
void reset() { m_data.reset(); }
iterator begin() const { return m_data.begin(); }
iterator end() const { return m_data.end(); }
void update(unsigned el, int delta);
@ -71,6 +72,7 @@ protected:
ptr_vector<sort> m_sorts;
expr_fast_mark1 m_visited;
ptr_vector<expr> m_todo;
ast_mark m_mark;
unsigned_vector m_scopes;
unsigned get_max_var(bool & has_var);
public:

View file

@ -242,13 +242,13 @@ br_status float_rewriter::mk_min(expr * arg1, expr * arg2, expr_ref & result) {
return BR_DONE;
}
// expand as using ite's
result = m().mk_ite(mk_eq_nan(arg1),
result = m().mk_ite(m().mk_or(mk_eq_nan(arg1), m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2))),
arg2,
m().mk_ite(mk_eq_nan(arg2),
arg1,
m().mk_ite(m_util.mk_lt(arg1, arg2),
arg1,
arg2)));
arg1,
arg2)));
return BR_REWRITE_FULL;
}
@ -262,7 +262,7 @@ br_status float_rewriter::mk_max(expr * arg1, expr * arg2, expr_ref & result) {
return BR_DONE;
}
// expand as using ite's
result = m().mk_ite(mk_eq_nan(arg1),
result = m().mk_ite(m().mk_or(mk_eq_nan(arg1), m().mk_and(m_util.mk_is_zero(arg1), m_util.mk_is_zero(arg2))),
arg2,
m().mk_ite(mk_eq_nan(arg2),
arg1,

View file

@ -62,6 +62,8 @@ struct mk_simplified_app::imp {
st = m_dt_rw.mk_eq_core(args[0], args[1], result);
else if (s_fid == m_f_rw.get_fid())
st = m_f_rw.mk_eq_core(args[0], args[1], result);
else if (s_fid == m_ar_rw.get_fid())
st = m_ar_rw.mk_eq_core(args[0], args[1], result);
if (st != BR_FAILED)
return st;

View file

@ -169,6 +169,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
st = m_dt_rw.mk_eq_core(args[0], args[1], result);
else if (s_fid == m_f_rw.get_fid())
st = m_f_rw.mk_eq_core(args[0], args[1], result);
else if (s_fid == m_ar_rw.get_fid())
st = m_ar_rw.mk_eq_core(args[0], args[1], result);
if (st != BR_FAILED)
return st;

View file

@ -17,7 +17,6 @@ Notes:
--*/
#include"var_subst.h"
#include"used_vars.h"
#include"ast_ll_pp.h"
#include"ast_pp.h"
#include"ast_smt2_pp.h"
@ -40,7 +39,7 @@ void var_subst::operator()(expr * n, unsigned num_args, expr * const * args, exp
tout << mk_ismt2_pp(result, m_reducer.m()) << "\n";);
}
void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
SASSERT(is_well_sorted(m, q));
if (is_ground(q->get_expr())) {
// ignore patterns if the body is a ground formula.
@ -51,17 +50,17 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
result = q;
return;
}
used_vars used;
used.process(q->get_expr());
m_used.reset();
m_used.process(q->get_expr());
unsigned num_patterns = q->get_num_patterns();
for (unsigned i = 0; i < num_patterns; i++)
used.process(q->get_pattern(i));
m_used.process(q->get_pattern(i));
unsigned num_no_patterns = q->get_num_no_patterns();
for (unsigned i = 0; i < num_no_patterns; i++)
used.process(q->get_no_pattern(i));
m_used.process(q->get_no_pattern(i));
unsigned num_decls = q->get_num_decls();
if (used.uses_all_vars(num_decls)) {
if (m_used.uses_all_vars(num_decls)) {
q->set_no_unused_vars();
result = q;
return;
@ -70,7 +69,7 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
ptr_buffer<sort> used_decl_sorts;
buffer<symbol> used_decl_names;
for (unsigned i = 0; i < num_decls; ++i) {
if (used.contains(num_decls - i - 1)) {
if (m_used.contains(num_decls - i - 1)) {
used_decl_sorts.push_back(q->get_decl_sort(i));
used_decl_names.push_back(q->get_decl_name(i));
}
@ -79,10 +78,10 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
unsigned num_removed = 0;
expr_ref_buffer var_mapping(m);
int next_idx = 0;
unsigned sz = used.get_max_found_var_idx_plus_1();
unsigned sz = m_used.get_max_found_var_idx_plus_1();
for (unsigned i = 0; i < num_decls; ++i) {
sort * s = used.contains(i);
sort * s = m_used.contains(i);
if (s) {
var_mapping.push_back(m.mk_var(next_idx, s));
next_idx++;
@ -95,7 +94,7 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
// (VAR 0) is in the first position of var_mapping.
for (unsigned i = num_decls; i < sz; i++) {
sort * s = used.contains(i);
sort * s = m_used.contains(i);
if (s)
var_mapping.push_back(m.mk_var(i - num_removed, s));
else
@ -110,9 +109,8 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
std::reverse(var_mapping.c_ptr(), var_mapping.c_ptr() + var_mapping.size());
expr_ref new_expr(m);
var_subst subst(m);
subst(q->get_expr(), var_mapping.size(), var_mapping.c_ptr(), new_expr);
m_subst(q->get_expr(), var_mapping.size(), var_mapping.c_ptr(), new_expr);
if (num_removed == num_decls) {
result = new_expr;
@ -124,11 +122,11 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
expr_ref_buffer new_no_patterns(m);
for (unsigned i = 0; i < num_patterns; i++) {
subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
new_patterns.push_back(tmp);
}
for (unsigned i = 0; i < num_no_patterns; i++) {
subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
new_no_patterns.push_back(tmp);
}
@ -148,6 +146,11 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
SASSERT(is_well_sorted(m, result));
}
void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
unused_vars_eliminator el(m);
el(q, result);
}
void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref & result) {
var_subst subst(m);
expr_ref new_expr(m);
@ -161,9 +164,7 @@ void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref
tout << "\n----->\n" << mk_ismt2_pp(result, m) << "\n";);
}
static void get_free_vars_offset(expr* e, unsigned offset, ptr_vector<sort>& sorts) {
ast_mark mark;
ptr_vector<expr> todo;
static void get_free_vars_offset(ast_mark& mark, ptr_vector<expr>& todo, unsigned offset, expr* e, ptr_vector<sort>& sorts) {
todo.push_back(e);
while (!todo.empty()) {
e = todo.back();
@ -175,7 +176,9 @@ static void get_free_vars_offset(expr* e, unsigned offset, ptr_vector<sort>& sor
switch(e->get_kind()) {
case AST_QUANTIFIER: {
quantifier* q = to_quantifier(e);
get_free_vars_offset(q->get_expr(), offset+q->get_num_decls(), sorts);
ast_mark mark1;
ptr_vector<expr> todo1;
get_free_vars_offset(mark1, todo1, offset+q->get_num_decls(), q->get_expr(), sorts);
break;
}
case AST_VAR: {
@ -207,5 +210,11 @@ static void get_free_vars_offset(expr* e, unsigned offset, ptr_vector<sort>& sor
void get_free_vars(expr* e, ptr_vector<sort>& sorts) {
get_free_vars_offset(e, 0, sorts);
ast_mark mark;
ptr_vector<expr> todo;
get_free_vars_offset(mark, todo, 0, e, sorts);
}
void get_free_vars(ast_mark& mark, ptr_vector<expr>& todo, expr* e, ptr_vector<sort>& sorts) {
get_free_vars_offset(mark, todo, 0, e, sorts);
}

View file

@ -20,6 +20,7 @@ Notes:
#define _VAR_SUBST_H_
#include"rewriter.h"
#include"used_vars.h"
/**
\brief Alias for var_shifter class.
@ -53,6 +54,15 @@ public:
/**
\brief Eliminate the unused variables from \c q. Store the result in \c r.
*/
class unused_vars_eliminator {
ast_manager& m;
var_subst m_subst;
used_vars m_used;
public:
unused_vars_eliminator(ast_manager& m): m(m), m_subst(m) {}
void operator()(quantifier* q, expr_ref& r);
};
void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & r);
/**
@ -73,6 +83,8 @@ void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref
*/
void get_free_vars(expr* e, ptr_vector<sort>& sorts);
void get_free_vars(ast_mark& mark, ptr_vector<expr>& todo, expr* e, ptr_vector<sort>& sorts);
#endif

View file

@ -636,7 +636,31 @@ bool bv_simplifier_plugin::try_mk_extract(unsigned high, unsigned low, expr * ar
if (!all_found) {
return false;
}
result = m_manager.mk_app(m_fid, a->get_decl_kind(), new_args.size(), new_args.c_ptr());
// We should not use mk_app because it does not guarantee that the result would be in simplified form.
// result = m_manager.mk_app(m_fid, a->get_decl_kind(), new_args.size(), new_args.c_ptr());
if (is_app_of(a, m_fid, OP_BAND))
mk_bv_and(new_args.size(), new_args.c_ptr(), result);
else if (is_app_of(a, m_fid, OP_BOR))
mk_bv_or(new_args.size(), new_args.c_ptr(), result);
else if (is_app_of(a, m_fid, OP_BXOR))
mk_bv_xor(new_args.size(), new_args.c_ptr(), result);
else if (is_app_of(a, m_fid, OP_BNOR))
mk_bv_nor(new_args.size(), new_args.c_ptr(), result);
else if (is_app_of(a, m_fid, OP_BNAND))
mk_bv_nand(new_args.size(), new_args.c_ptr(), result);
else if (is_app_of(a, m_fid, OP_BNOT)) {
SASSERT(new_args.size() == 1);
mk_bv_not(new_args[0], result);
}
else if (is_app_of(a, m_fid, OP_BADD))
mk_add(new_args.size(), new_args.c_ptr(), result);
else if (is_app_of(a, m_fid, OP_BMUL))
mk_mul(new_args.size(), new_args.c_ptr(), result);
else if (is_app_of(a, m_fid, OP_BSUB))
mk_sub(new_args.size(), new_args.c_ptr(), result);
else {
UNREACHABLE();
}
return true;
}
else if (m_manager.is_ite(a)) {
@ -747,16 +771,16 @@ void bv_simplifier_plugin::mk_bv_eq(expr* a1, expr* a2, expr_ref& result) {
expr * arg1 = *it1;
expr * arg2 = *it2;
TRACE("expr_bv_util", tout << "low1: " << low1 << " low2: " << low2 << "\n";
ast_ll_pp(tout, m_manager, arg1);
ast_ll_pp(tout, m_manager, arg2););
tout << mk_pp(arg1, m_manager) << "\n";
tout << mk_pp(arg2, m_manager) << "\n";);
unsigned sz1 = get_bv_size(arg1);
unsigned sz2 = get_bv_size(arg2);
SASSERT(low1 < sz1 && low2 < sz2);
unsigned rsz1 = sz1 - low1;
unsigned rsz2 = sz2 - low2;
TRACE("expr_bv_util", tout << "rsz1: " << rsz1 << " rsz2: " << rsz2 << "\n";
ast_ll_pp(tout, m_manager, arg1); ast_ll_pp(tout, m_manager, arg2););
tout << mk_pp(arg1, m_manager) << "\n";
tout << mk_pp(arg2, m_manager) << "\n";);
if (rsz1 == rsz2) {
mk_extract(sz1 - 1, low1, arg1, lhs);
@ -826,9 +850,9 @@ void bv_simplifier_plugin::mk_eq_core(expr * arg1, expr * arg2, expr_ref & resul
}
m_bsimp.mk_and(tmps.size(), tmps.c_ptr(), result);
TRACE("mk_eq_bb",
ast_ll_pp(tout, m_manager, arg1);
ast_ll_pp(tout, m_manager, arg2);
ast_ll_pp(tout, m_manager, result););
tout << mk_pp(arg1, m_manager) << "\n";
tout << mk_pp(arg2, m_manager) << "\n";
tout << mk_pp(result, m_manager) << "\n";);
return;
}
#endif

View file

@ -285,6 +285,7 @@ bool poly_simplifier_plugin::merge_monomials(bool inv, expr * n1, expr * n2, exp
else
result = m_manager.mk_app(m_fid, m_MUL, mk_numeral(k1), b);
}
TRACE("merge_monomials", tout << mk_pp(n1, m_manager) << "\n" << mk_pp(n2, m_manager) << "\n" << mk_pp(result, m_manager) << "\n";);
return true;
}

View file

@ -18,10 +18,6 @@ Revision History:
--*/
#include"matcher.h"
matcher::matcher(ast_manager & m):
m_manager(m) {
}
bool matcher::operator()(expr * e1, expr * e2, substitution & s) {
reset();
m_subst = &s;

View file

@ -30,7 +30,6 @@ class matcher {
typedef pair_hash<obj_ptr_hash<expr>, obj_ptr_hash<expr> > expr_pair_hash;
typedef hashtable<expr_pair, expr_pair_hash, default_eq<expr_pair> > cache;
ast_manager & m_manager;
substitution * m_subst;
// cache m_cache;
svector<expr_pair> m_todo;
@ -38,7 +37,7 @@ class matcher {
void reset();
public:
matcher(ast_manager & m);
matcher() {}
/**
\brief Return true if e2 is an instance of e1.

View file

@ -148,7 +148,7 @@ void substitution::apply(unsigned num_actual_offsets, unsigned const * deltas, e
expr * arg = to_app(e)->get_arg(i);
expr * new_arg;
m_apply_cache.find(expr_offset(arg, off), new_arg);
VERIFY(m_apply_cache.find(expr_offset(arg, off), new_arg));
new_args.push_back(new_arg);
if (arg != new_arg)
has_new_args = true;

View file

@ -660,8 +660,7 @@ namespace realclosure {
return; // interval was already saved.
to_restore.push_back(v);
inc_ref(v);
void * mem = allocator().allocate(sizeof(mpbqi));
v->m_old_interval = new (mem) mpbqi();
v->m_old_interval = new (allocator()) mpbqi();
set_interval(*(v->m_old_interval), v->m_interval);
}
void save_interval(value * v) {
@ -1237,8 +1236,7 @@ namespace realclosure {
}
sign_condition * mk_sign_condition(unsigned qidx, int sign, sign_condition * prev_sc) {
void * mem = allocator().allocate(sizeof(sign_condition));
return new (mem) sign_condition(qidx, sign, prev_sc);
return new (allocator()) sign_condition(qidx, sign, prev_sc);
}
/**
@ -1246,7 +1244,7 @@ namespace realclosure {
This method does not set the interval. It remains (-oo, oo)
*/
rational_function_value * mk_rational_function_value_core(extension * ext, unsigned num_sz, value * const * num, unsigned den_sz, value * const * den) {
rational_function_value * r = alloc(rational_function_value, ext);
rational_function_value * r = new (allocator()) rational_function_value(ext);
inc_ref(ext);
set_p(r->num(), num_sz, num);
if (ext->is_algebraic()) {
@ -1283,7 +1281,7 @@ namespace realclosure {
*/
void mk_infinitesimal(symbol const & n, symbol const & pp_n, numeral & r) {
unsigned idx = next_infinitesimal_idx();
infinitesimal * eps = alloc(infinitesimal, idx, n, pp_n);
infinitesimal * eps = new (allocator()) infinitesimal(idx, n, pp_n);
m_extensions[extension::INFINITESIMAL].push_back(eps);
set_lower(eps->interval(), mpbq(0));
@ -1335,7 +1333,7 @@ namespace realclosure {
void mk_transcendental(symbol const & n, symbol const & pp_n, mk_interval & proc, numeral & r) {
unsigned idx = next_transcendental_idx();
transcendental * t = alloc(transcendental, idx, n, pp_n, proc);
transcendental * t = new (allocator()) transcendental(idx, n, pp_n, proc);
m_extensions[extension::TRANSCENDENTAL].push_back(t);
while (contains_zero(t->interval())) {
@ -1798,8 +1796,7 @@ namespace realclosure {
M and scs will be empty after this operation.
*/
sign_det * mk_sign_det(mpz_matrix & M_s, scoped_polynomial_seq const & prs, int_buffer const & taqrs, scoped_polynomial_seq const & qs, scoped_sign_conditions & scs) {
void * mem = allocator().allocate(sizeof(sign_det));
sign_det * r = new (mem) sign_det();
sign_det * r = new (allocator()) sign_det();
r->M_s.swap(M_s);
set_array_p(r->m_prs, prs);
r->m_taqrs.set(allocator(), taqrs.size(), taqrs.c_ptr());
@ -1814,8 +1811,7 @@ namespace realclosure {
*/
algebraic * mk_algebraic(unsigned p_sz, value * const * p, mpbqi const & interval, mpbqi const & iso_interval, sign_det * sd, unsigned sc_idx) {
unsigned idx = next_algebraic_idx();
void * mem = allocator().allocate(sizeof(algebraic));
algebraic * r = new (mem) algebraic(idx);
algebraic * r = new (allocator()) algebraic(idx);
m_extensions[extension::ALGEBRAIC].push_back(r);
set_p(r->m_p, p_sz, p);
@ -2561,8 +2557,7 @@ namespace realclosure {
}
rational_value * mk_rational() {
void * mem = allocator().allocate(sizeof(rational_value));
return new (mem) rational_value();
return new (allocator()) rational_value();
}
/**

View file

@ -85,7 +85,6 @@ namespace subpaving {
};
class context_mpf_wrapper : public context_wrapper<context_mpf> {
f2n<mpf_manager> & m_fm;
unsynch_mpq_manager & m_qm;
scoped_mpf m_c;
scoped_mpf_vector m_as;
@ -103,7 +102,6 @@ namespace subpaving {
public:
context_mpf_wrapper(f2n<mpf_manager> & fm, params_ref const & p, small_object_allocator * a):
context_wrapper<context_mpf>(fm, p, a),
m_fm(fm),
m_qm(fm.m().mpq_manager()),
m_c(fm.m()),
m_as(fm.m()),
@ -145,7 +143,6 @@ namespace subpaving {
};
class context_hwf_wrapper : public context_wrapper<context_hwf> {
f2n<hwf_manager> & m_fm;
unsynch_mpq_manager & m_qm;
hwf m_c;
svector<hwf> m_as;
@ -166,7 +163,6 @@ namespace subpaving {
public:
context_hwf_wrapper(f2n<hwf_manager> & fm, unsynch_mpq_manager & qm, params_ref const & p, small_object_allocator * a):
context_wrapper<context_hwf>(fm, p, a),
m_fm(fm),
m_qm(qm) {
}

328
src/muz_qe/aig_exporter.cpp Executable file
View 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_qe/aig_exporter.h Executable file
View 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 "rel_context.h"
#include <map>
#include <sstream>
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

235
src/muz_qe/clp_context.cpp Normal file
View file

@ -0,0 +1,235 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
clp_context.cpp
Abstract:
Bounded CLP (symbolic simulation using Z3) context.
Author:
Nikolaj Bjorner (nbjorner) 2013-04-26
Revision History:
--*/
#include "clp_context.h"
#include "dl_context.h"
#include "unifier.h"
#include "var_subst.h"
#include "substitution.h"
namespace datalog {
class clp::imp {
struct stats {
stats() { reset(); }
void reset() { memset(this, 0, sizeof(*this)); }
unsigned m_num_unfold;
unsigned m_num_no_unfold;
unsigned m_num_subsumed;
};
context& m_ctx;
ast_manager& m;
rule_manager& rm;
smt_params m_fparams;
smt::kernel m_solver;
var_subst m_var_subst;
expr_ref_vector m_ground;
app_ref_vector m_goals;
volatile bool m_cancel;
stats m_stats;
public:
imp(context& ctx):
m_ctx(ctx),
m(ctx.get_manager()),
rm(ctx.get_rule_manager()),
m_solver(m, m_fparams), // TBD: can be replaced by efficient BV solver.
m_var_subst(m, false),
m_ground(m),
m_goals(m),
m_cancel(false)
{
// m_fparams.m_relevancy_lvl = 0;
m_fparams.m_mbqi = false;
m_fparams.m_soft_timeout = 1000;
}
~imp() {}
lbool query(expr* query) {
m_ctx.ensure_opened();
m_solver.reset();
m_goals.reset();
rm.mk_query(query, m_ctx.get_rules());
m_ctx.apply_default_transformation();
func_decl *head_decl = m_ctx.get_rules().get_output_predicate();
expr_ref head(m_ctx.get_rules().get_predicate_rules(head_decl)[0]->get_head(), m);
ground(head);
m_goals.push_back(to_app(head));
return search(20, 0);
}
void cancel() {
m_cancel = true;
m_solver.cancel();
}
void cleanup() {
m_cancel = false;
m_goals.reset();
m_solver.reset_cancel();
}
void reset_statistics() {
m_stats.reset();
}
void collect_statistics(statistics& st) const {
//st.update("tab.num_unfold", m_stats.m_num_unfold);
//st.update("tab.num_unfold_fail", m_stats.m_num_no_unfold);
//st.update("tab.num_subsumed", m_stats.m_num_subsumed);
}
void display_certificate(std::ostream& out) const {
expr_ref ans = get_answer();
out << mk_pp(ans, m) << "\n";
}
expr_ref get_answer() const {
return expr_ref(m.mk_true(), m);
}
private:
void reset_ground() {
m_ground.reset();
}
void ground(expr_ref& e) {
ptr_vector<sort> sorts;
get_free_vars(e, sorts);
if (m_ground.size() < sorts.size()) {
m_ground.resize(sorts.size());
}
for (unsigned i = 0; i < sorts.size(); ++i) {
if (sorts[i] && !m_ground[i].get()) {
m_ground[i] = m.mk_fresh_const("c",sorts[i]);
}
}
m_var_subst(e, m_ground.size(), m_ground.c_ptr(), e);
}
static bool rule_sort_fn(const rule *r1, const rule *r2) {
return r1->get_uninterpreted_tail_size() < r2->get_uninterpreted_tail_size();
}
lbool search(unsigned depth, unsigned index) {
if (index == m_goals.size()) {
return l_true;
}
if (depth == 0) {
return l_undef;
}
IF_VERBOSE(1, verbose_stream() << "search " << depth << " " << index << "\n";);
unsigned num_goals = m_goals.size();
app* head = m_goals[index].get();
rule_vector rules(m_ctx.get_rules().get_predicate_rules(head->get_decl()));
std::stable_sort(rules.begin(), rules.end(), rule_sort_fn);
lbool status = l_false;
for (unsigned i = 0; i < rules.size(); ++i) {
rule* r = rules[i];
m_solver.push();
reset_ground();
expr_ref tmp(m);
tmp = r->get_head();
IF_VERBOSE(2, verbose_stream() << index << " " << mk_pp(tmp, m) << "\n";);
ground(tmp);
for (unsigned j = 0; j < head->get_num_args(); ++j) {
expr_ref eq(m);
eq = m.mk_eq(head->get_arg(j), to_app(tmp)->get_arg(j));
m_solver.assert_expr(eq);
}
for (unsigned j = r->get_uninterpreted_tail_size(); j < r->get_tail_size(); ++j) {
tmp = r->get_tail(j);
ground(tmp);
m_solver.assert_expr(tmp);
}
lbool is_sat = m_solver.check();
switch (is_sat) {
case l_false:
break;
case l_true:
if (depth == 1 && (index+1 > m_goals.size() || r->get_uninterpreted_tail_size() > 0)) {
status = l_undef;
break;
}
for (unsigned j = 0; j < r->get_uninterpreted_tail_size(); ++j) {
tmp = r->get_tail(j);
ground(tmp);
m_goals.push_back(to_app(tmp));
}
switch(search(depth-1, index+1)) {
case l_undef:
status = l_undef;
// fallthrough
case l_false:
m_goals.resize(num_goals);
break;
case l_true:
return l_true;
}
break;
case l_undef:
status = l_undef;
throw default_exception("undef");
}
m_solver.pop(1);
}
return status;
}
proof_ref get_proof() const {
return proof_ref(0, m);
}
};
clp::clp(context& ctx):
m_imp(alloc(imp, ctx)) {
}
clp::~clp() {
dealloc(m_imp);
}
lbool clp::query(expr* query) {
return m_imp->query(query);
}
void clp::cancel() {
m_imp->cancel();
}
void clp::cleanup() {
m_imp->cleanup();
}
void clp::reset_statistics() {
m_imp->reset_statistics();
}
void clp::collect_statistics(statistics& st) const {
m_imp->collect_statistics(st);
}
void clp::display_certificate(std::ostream& out) const {
m_imp->display_certificate(out);
}
expr_ref clp::get_answer() {
return m_imp->get_answer();
}
};

45
src/muz_qe/clp_context.h Normal file
View file

@ -0,0 +1,45 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
clp_context.h
Abstract:
Bounded CLP (symbolic simulation using Z3) context.
Author:
Nikolaj Bjorner (nbjorner) 2013-04-26
Revision History:
--*/
#ifndef _CLP_CONTEXT_H_
#define _CLP_CONTEXT_H_
#include "ast.h"
#include "lbool.h"
#include "statistics.h"
namespace datalog {
class context;
class clp {
class imp;
imp* m_imp;
public:
clp(context& ctx);
~clp();
lbool query(expr* query);
void cancel();
void cleanup();
void reset_statistics();
void collect_statistics(statistics& st) const;
void display_certificate(std::ostream& out) const;
expr_ref get_answer();
};
};
#endif

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
@ -329,6 +331,10 @@ namespace datalog {
virtual mutator_fn * mk_filter_interpreted_fn(const base_object & t, app * condition)
{ return 0; }
virtual transformer_fn * mk_filter_interpreted_and_project_fn(const base_object & t,
app * condition, unsigned removed_col_cnt, const unsigned * removed_cols)
{ return 0; }
virtual transformer_fn * mk_select_equal_and_project_fn(const base_object & t,
const element & value, unsigned col) { return 0; }
@ -452,8 +458,8 @@ namespace datalog {
class convenient_join_fn : public join_fn {
signature m_result_sig;
protected:
const unsigned_vector m_cols1;
const unsigned_vector m_cols2;
unsigned_vector m_cols1;
unsigned_vector m_cols2;
convenient_join_fn(const signature & o1_sig, const signature & o2_sig, unsigned col_cnt,
const unsigned * cols1, const unsigned * cols2)
@ -468,8 +474,8 @@ namespace datalog {
class convenient_join_project_fn : public join_fn {
signature m_result_sig;
protected:
const unsigned_vector m_cols1;
const unsigned_vector m_cols2;
unsigned_vector m_cols1;
unsigned_vector m_cols2;
//it is non-const because it needs to be modified in sparse_table version of the join_project operator
unsigned_vector m_removed_cols;
@ -496,7 +502,7 @@ namespace datalog {
class convenient_project_fn : public convenient_transformer_fn {
protected:
const unsigned_vector m_removed_cols;
unsigned_vector m_removed_cols;
convenient_project_fn(const signature & orig_sig, unsigned col_cnt, const unsigned * removed_cols)
: m_removed_cols(col_cnt, removed_cols) {
@ -654,6 +660,7 @@ namespace datalog {
typedef sort * relation_sort;
typedef ptr_vector<sort> relation_signature_base0;
typedef ptr_hash<sort> relation_sort_hash;
typedef app * relation_element;
typedef app_ref relation_element_ref;
@ -737,8 +744,8 @@ namespace datalog {
struct hash {
unsigned operator()(relation_signature const& s) const {
relation_sort const* sorts = s.c_ptr();
return string_hash(reinterpret_cast<char const*>(sorts), sizeof(*sorts)*s.size(), 12); }
return obj_vector_hash<relation_signature>(s);
}
};
struct eq {
@ -814,9 +821,11 @@ namespace datalog {
typedef uint64 table_sort;
typedef svector<table_sort> table_signature_base0;
typedef uint64_hash table_sort_hash;
typedef uint64 table_element;
typedef svector<table_element> table_fact;
typedef uint64_hash table_element_hash;
struct table_traits {
typedef table_plugin plugin;
@ -879,8 +888,8 @@ namespace datalog {
public:
struct hash {
unsigned operator()(table_signature const& s) const {
table_sort const* sorts = s.c_ptr();
return string_hash(reinterpret_cast<char const*>(sorts), sizeof(*sorts)*s.size(), 12); }
return svector_hash<table_sort_hash>()(s);
}
};
struct eq {

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;
@ -298,6 +297,7 @@ namespace datalog {
r->to_formula(fml);
r2 = r;
rm.substitute(r2, sub.size(), sub.c_ptr());
proof_ref p(m);
if (r0) {
VERIFY(unifier.unify_rules(*r0.get(), 0, *r2.get()));
expr_ref_vector sub1 = unifier.get_rule_subst(*r0.get(), true);
@ -307,7 +307,10 @@ namespace datalog {
r1->to_formula(concl);
scoped_proof _sp(m);
proof* p = r->get_proof();
p = r->get_proof();
if (!p) {
p = m.mk_asserted(fml);
}
proof* premises[2] = { pr, p };
positions.push_back(std::make_pair(0, 1));
@ -320,13 +323,17 @@ namespace datalog {
else {
r2->to_formula(concl);
scoped_proof _sp(m);
proof* p = r->get_proof();
p = r->get_proof();
if (!p) {
p = m.mk_asserted(fml);
}
if (sub.empty()) {
pr = p;
}
else {
substs.push_back(sub);
pr = m.mk_hyper_resolve(1, &p, concl, positions, substs);
proof* ps[1] = { p };
pr = m.mk_hyper_resolve(1, ps, concl, positions, substs);
}
r0 = r2;
}
@ -1005,7 +1012,6 @@ namespace datalog {
symbol is_name(_name.str().c_str());
std::stringstream _name2;
_name2 << "get_succ#" << i;
symbol acc_name(_name2.str().c_str());
ptr_vector<accessor_decl> accs;
type_ref tr(0);
accs.push_back(mk_accessor_decl(name, tr));
@ -1213,6 +1219,15 @@ namespace datalog {
r->to_formula(fml);
r2 = r;
rm.substitute(r2, sub.size(), sub.c_ptr());
proof_ref p(m);
{
scoped_proof _sp(m);
p = r->get_proof();
if (!p) {
p = m.mk_asserted(fml);
}
}
if (r0) {
VERIFY(unifier.unify_rules(*r0.get(), 0, *r2.get()));
expr_ref_vector sub1 = unifier.get_rule_subst(*r0.get(), true);
@ -1220,9 +1235,8 @@ namespace datalog {
apply_subst(sub, sub2);
unifier.apply(*r0.get(), 0, *r2.get(), r1);
r1->to_formula(concl);
scoped_proof _sp(m);
proof* p = r->get_proof();
scoped_proof _sp(m);
proof* premises[2] = { pr, p };
positions.push_back(std::make_pair(0, 1));
@ -1235,13 +1249,13 @@ namespace datalog {
else {
r2->to_formula(concl);
scoped_proof _sp(m);
proof* p = r->get_proof();
if (sub.empty()) {
pr = p;
}
else {
substs.push_back(sub);
pr = m.mk_hyper_resolve(1, &p, concl, positions, substs);
proof * ps[1] = { p };
pr = m.mk_hyper_resolve(1, ps, concl, positions, substs);
}
r0 = r2;
}
@ -1416,19 +1430,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);
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.set_output_predicate(m_query_pred);
m_ctx.apply_default_transformation();
if (m_ctx.get_params().slice()) {
@ -1436,10 +1443,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

@ -82,6 +82,34 @@ namespace datalog {
return alloc(join_fn, *this, t1, t2, col_cnt, cols1, cols2);
}
class check_table_plugin::join_project_fn : public table_join_fn {
scoped_ptr<table_join_fn> m_tocheck;
scoped_ptr<table_join_fn> m_checker;
public:
join_project_fn(check_table_plugin& p, 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) {
m_tocheck = p.get_manager().mk_join_project_fn(tocheck(t1), tocheck(t2), col_cnt, cols1, cols2, removed_col_cnt, removed_cols);
m_checker = p.get_manager().mk_join_project_fn(checker(t1), checker(t2), col_cnt, cols1, cols2, removed_col_cnt, removed_cols);
}
virtual table_base* operator()(const table_base & t1, const table_base & t2) {
table_base* ttocheck = (*m_tocheck)(tocheck(t1), tocheck(t2));
table_base* tchecker = (*m_checker)(checker(t1), checker(t2));
check_table* result = alloc(check_table, get(t1).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker);
return result;
}
};
table_join_fn * check_table_plugin::mk_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) {
if (!check_kind(t1) || !check_kind(t2)) {
return 0;
}
return alloc(join_project_fn, *this, t1, t2, col_cnt, cols1, cols2, removed_col_cnt, removed_cols);
}
class check_table_plugin::union_fn : public table_union_fn {
scoped_ptr<table_union_fn> m_tocheck;
scoped_ptr<table_union_fn> m_checker;
@ -120,7 +148,6 @@ namespace datalog {
}
table_base* operator()(table_base const& src) {
IF_VERBOSE(1, verbose_stream() << __FUNCTION__ << "\n";);
table_base* tchecker = (*m_checker)(checker(src));
table_base* ttocheck = (*m_tocheck)(tocheck(src));
check_table* result = alloc(check_table, get(src).get_plugin(), tchecker->get_signature(), ttocheck, tchecker);
@ -135,6 +162,31 @@ namespace datalog {
return alloc(project_fn, *this, t, col_cnt, removed_cols);
}
class check_table_plugin::select_equal_and_project_fn : public table_transformer_fn {
scoped_ptr<table_transformer_fn> m_checker;
scoped_ptr<table_transformer_fn> m_tocheck;
public:
select_equal_and_project_fn(check_table_plugin& p, const table_base & t, const table_element & value, unsigned col) {
m_checker = p.get_manager().mk_select_equal_and_project_fn(checker(t), value, col);
m_tocheck = p.get_manager().mk_select_equal_and_project_fn(tocheck(t), value, col);
}
table_base* operator()(table_base const& src) {
table_base* tchecker = (*m_checker)(checker(src));
table_base* ttocheck = (*m_tocheck)(tocheck(src));
check_table* result = alloc(check_table, get(src).get_plugin(), tchecker->get_signature(), ttocheck, tchecker);
return result;
}
};
table_transformer_fn * check_table_plugin::mk_select_equal_and_project_fn(const table_base & t,
const table_element & value, unsigned col) {
if (!check_kind(t)) {
return 0;
}
return alloc(select_equal_and_project_fn, *this, t, value, col);
}
class check_table_plugin::rename_fn : public table_transformer_fn {
scoped_ptr<table_transformer_fn> m_checker;
scoped_ptr<table_transformer_fn> m_tocheck;
@ -233,6 +285,33 @@ namespace datalog {
return 0;
}
class check_table_plugin::filter_interpreted_and_project_fn : public table_transformer_fn {
scoped_ptr<table_transformer_fn> m_checker;
scoped_ptr<table_transformer_fn> m_tocheck;
public:
filter_interpreted_and_project_fn(check_table_plugin& p, const table_base & t, app * condition,
unsigned removed_col_cnt, const unsigned * removed_cols)
{
m_checker = p.get_manager().mk_filter_interpreted_and_project_fn(checker(t), condition, removed_col_cnt, removed_cols);
m_tocheck = p.get_manager().mk_filter_interpreted_and_project_fn(tocheck(t), condition, removed_col_cnt, removed_cols);
}
table_base* operator()(table_base const& src) {
table_base* tchecker = (*m_checker)(checker(src));
table_base* ttocheck = (*m_tocheck)(tocheck(src));
check_table* result = alloc(check_table, get(src).get_plugin(), ttocheck->get_signature(), ttocheck, tchecker);
return result;
}
};
table_transformer_fn * check_table_plugin::mk_filter_interpreted_and_project_fn(const table_base & t,
app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) {
if (check_kind(t)) {
return alloc(filter_interpreted_and_project_fn, *this, t, condition, removed_col_cnt, removed_cols);
}
return 0;
}
class check_table_plugin::filter_by_negation_fn : public table_intersection_filter_fn {
scoped_ptr<table_intersection_filter_fn> m_checker;
scoped_ptr<table_intersection_filter_fn> m_tocheck;

View file

@ -35,13 +35,16 @@ namespace datalog {
unsigned m_count;
protected:
class join_fn;
class join_project_fn;
class union_fn;
class transformer_fn;
class rename_fn;
class project_fn;
class select_equal_and_project_fn;
class filter_equal_fn;
class filter_identical_fn;
class filter_interpreted_fn;
class filter_interpreted_and_project_fn;
class filter_by_negation_fn;
public:
@ -54,10 +57,15 @@ namespace datalog {
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 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_select_equal_and_project_fn(const table_base & t,
const table_element & value, unsigned col);
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,
@ -65,6 +73,8 @@ namespace datalog {
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_transformer_fn * mk_filter_interpreted_and_project_fn(const table_base & t,
app * condition, unsigned removed_col_cnt, const unsigned * removed_cols);
virtual table_intersection_filter_fn * mk_filter_by_negation_fn(
const table_base & t,
const table_base & negated_obj, unsigned joined_col_cnt,
@ -89,15 +99,6 @@ namespace datalog {
class check_table : public table_base {
friend class check_table_plugin;
friend class check_table_plugin::join_fn;
friend class check_table_plugin::union_fn;
friend class check_table_plugin::transformer_fn;
friend class check_table_plugin::rename_fn;
friend class check_table_plugin::project_fn;
friend class check_table_plugin::filter_equal_fn;
friend class check_table_plugin::filter_identical_fn;
friend class check_table_plugin::filter_interpreted_fn;
friend class check_table_plugin::filter_by_negation_fn;
table_base* m_checker;
table_base* m_tocheck;

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

@ -36,7 +36,7 @@ namespace datalog {
}
void compiler::ensure_predicate_loaded(func_decl * pred, instruction_block & acc) {
pred2idx::entry * e = m_pred_regs.insert_if_not_there2(pred, UINT_MAX);
pred2idx::obj_map_entry * e = m_pred_regs.insert_if_not_there2(pred, UINT_MAX);
if(e->get_data().m_value!=UINT_MAX) {
//predicate is already loaded
return;
@ -61,17 +61,30 @@ namespace datalog {
void compiler::make_join_project(reg_idx t1, reg_idx t2, const variable_intersection & vars,
const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc) {
relation_signature aux_sig;
relation_signature::from_join(m_reg_signatures[t1], m_reg_signatures[t2], vars.size(),
vars.get_cols1(), vars.get_cols2(), aux_sig);
relation_signature sig1 = m_reg_signatures[t1];
relation_signature sig2 = m_reg_signatures[t2];
relation_signature::from_join(sig1, sig2, vars.size(), vars.get_cols1(), vars.get_cols2(), aux_sig);
relation_signature res_sig;
relation_signature::from_project(aux_sig, removed_cols.size(), removed_cols.c_ptr(),
res_sig);
result = get_fresh_register(res_sig);
acc.push_back(instruction::mk_join_project(t1, t2, vars.size(), vars.get_cols1(),
vars.get_cols2(), removed_cols.size(), removed_cols.c_ptr(), result));
}
void compiler::make_filter_interpreted_and_project(reg_idx src, app_ref & cond,
const unsigned_vector & removed_cols, reg_idx & result, instruction_block & acc) {
SASSERT(!removed_cols.empty());
relation_signature res_sig;
relation_signature::from_project(m_reg_signatures[src], removed_cols.size(),
removed_cols.c_ptr(), res_sig);
result = get_fresh_register(res_sig);
acc.push_back(instruction::mk_filter_interpreted_and_project(src, cond,
removed_cols.size(), removed_cols.c_ptr(), result));
}
void compiler::make_select_equal_and_project(reg_idx src, const relation_element & val, unsigned col,
reg_idx & result, instruction_block & acc) {
relation_signature res_sig;
@ -145,7 +158,7 @@ namespace datalog {
}
void compiler::make_add_constant_column(func_decl* head_pred, reg_idx src, const relation_sort & s, const relation_element & val,
reg_idx & result, instruction_block & acc) {
reg_idx & result, bool & dealloc, instruction_block & acc) {
reg_idx singleton_table;
if(!m_constant_registers.find(s, val, singleton_table)) {
singleton_table = get_single_column_register(s);
@ -154,16 +167,18 @@ namespace datalog {
m_constant_registers.insert(s, val, singleton_table);
}
if(src==execution_context::void_register) {
make_clone(singleton_table, result, acc);
result = singleton_table;
dealloc = false;
}
else {
variable_intersection empty_vars(m_context.get_manager());
make_join(src, singleton_table, empty_vars, result, acc);
dealloc = true;
}
}
void compiler::make_add_unbound_column(rule* compiled_rule, unsigned col_idx, func_decl* pred, reg_idx src, const relation_sort & s, reg_idx & result,
instruction_block & acc) {
bool & dealloc, instruction_block & acc) {
TRACE("dl", tout << "Adding unbound column " << mk_pp(pred, m_context.get_manager()) << "\n";);
IF_VERBOSE(3, {
@ -172,25 +187,35 @@ namespace datalog {
verbose_stream() << "Compiling unsafe rule column " << col_idx << "\n"
<< mk_ismt2_pp(e, m_context.get_manager()) << "\n";
});
reg_idx total_table = get_single_column_register(s);
relation_signature sig;
sig.push_back(s);
acc.push_back(instruction::mk_total(sig, pred, total_table));
reg_idx total_table;
if (!m_total_registers.find(s, pred, total_table)) {
total_table = get_single_column_register(s);
relation_signature sig;
sig.push_back(s);
m_top_level_code.push_back(instruction::mk_total(sig, pred, total_table));
m_total_registers.insert(s, pred, total_table);
}
if(src == execution_context::void_register) {
result = total_table;
dealloc = false;
}
else {
variable_intersection empty_vars(m_context.get_manager());
make_join(src, total_table, empty_vars, result, acc);
make_dealloc_non_void(total_table, acc);
dealloc = true;
}
}
void compiler::make_full_relation(func_decl* pred, const relation_signature & sig, reg_idx & result,
instruction_block & acc) {
SASSERT(sig.empty());
TRACE("dl", tout << "Adding unbound column " << mk_pp(pred, m_context.get_manager()) << "\n";);
if (m_empty_tables_registers.find(pred, result))
return;
result = get_fresh_register(sig);
acc.push_back(instruction::mk_total(sig, pred, result));
m_top_level_code.push_back(instruction::mk_total(sig, pred, result));
m_empty_tables_registers.insert(pred, result);
}
@ -232,6 +257,7 @@ namespace datalog {
reg_idx src,
const svector<assembling_column_info> & acis0,
reg_idx & result,
bool & dealloc,
instruction_block & acc) {
TRACE("dl", tout << mk_pp(head_pred, m_context.get_manager()) << "\n";);
@ -276,7 +302,9 @@ namespace datalog {
if(!src_cols_to_remove.empty()) {
reg_idx new_curr;
make_projection(curr, src_cols_to_remove.size(), src_cols_to_remove.c_ptr(), new_curr, acc);
make_dealloc_non_void(curr, acc);
if (dealloc)
make_dealloc_non_void(curr, acc);
dealloc = true;
curr=new_curr;
curr_sig = & m_reg_signatures[curr];
@ -297,16 +325,19 @@ namespace datalog {
unsigned bound_column_index;
if(acis[i].kind!=ACK_UNBOUND_VAR || !handled_unbound.find(acis[i].var_index,bound_column_index)) {
reg_idx new_curr;
bool new_dealloc;
bound_column_index=curr_sig->size();
if(acis[i].kind==ACK_CONSTANT) {
make_add_constant_column(head_pred, curr, acis[i].domain, acis[i].constant, new_curr, acc);
make_add_constant_column(head_pred, curr, acis[i].domain, acis[i].constant, new_curr, new_dealloc, acc);
}
else {
SASSERT(acis[i].kind==ACK_UNBOUND_VAR);
make_add_unbound_column(compiled_rule, i, head_pred, curr, acis[i].domain, new_curr, acc);
make_add_unbound_column(compiled_rule, i, head_pred, curr, acis[i].domain, new_curr, new_dealloc, acc);
handled_unbound.insert(acis[i].var_index,bound_column_index);
}
make_dealloc_non_void(curr, acc);
if (dealloc)
make_dealloc_non_void(curr, acc);
dealloc = new_dealloc;
curr=new_curr;
curr_sig = & m_reg_signatures[curr];
SASSERT(bound_column_index==curr_sig->size()-1);
@ -327,7 +358,9 @@ namespace datalog {
}
reg_idx new_curr;
make_duplicate_column(curr, col, new_curr, acc);
make_dealloc_non_void(curr, acc);
if (dealloc)
make_dealloc_non_void(curr, acc);
dealloc = true;
curr=new_curr;
curr_sig = & m_reg_signatures[curr];
unsigned bound_column_index=curr_sig->size()-1;
@ -355,7 +388,9 @@ namespace datalog {
reg_idx new_curr;
make_rename(curr, permutation.size(), permutation.c_ptr(), new_curr, acc);
make_dealloc_non_void(curr, acc);
if (dealloc)
make_dealloc_non_void(curr, acc);
dealloc = true;
curr=new_curr;
curr_sig = & m_reg_signatures[curr];
}
@ -364,6 +399,7 @@ namespace datalog {
SASSERT(src==execution_context::void_register);
SASSERT(acis0.size()==0);
make_full_relation(head_pred, empty_signature, curr, acc);
dealloc = false;
}
result=curr;
@ -397,6 +433,7 @@ namespace datalog {
void compiler::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) {
ast_manager & m = m_context.get_manager();
m_instruction_observer.start_rule(r);
const app * h = r->get_head();
@ -409,12 +446,15 @@ namespace datalog {
SASSERT(pt_len<=2); //we require rules to be processed by the mk_simple_joins rule transformer plugin
reg_idx single_res;
ptr_vector<expr> single_res_expr;
expr_ref_vector single_res_expr(m);
//used to save on filter_identical instructions where the check is already done
//by the join operation
unsigned second_tail_arg_ofs;
// whether to dealloc the previous result
bool dealloc = true;
if(pt_len == 2) {
reg_idx t1_reg=tail_regs[0];
reg_idx t2_reg=tail_regs[1];
@ -471,8 +511,7 @@ namespace datalog {
expr * arg = a->get_arg(i);
if(is_app(arg)) {
app * c = to_app(arg); //argument is a constant
SASSERT(c->get_num_args()==0);
SASSERT(m_context.get_decl_util().is_numeral_ext(arg));
SASSERT(m.is_value(c));
reg_idx new_reg;
make_select_equal_and_project(single_res, c, single_res_expr.size(), new_reg, acc);
if(single_res!=t_reg) {
@ -487,8 +526,7 @@ namespace datalog {
}
}
if(single_res==t_reg) {
//we may be modifying the register later, so we need a local copy
make_clone(t_reg, single_res, acc);
dealloc = false;
}
}
@ -499,7 +537,7 @@ namespace datalog {
single_res=execution_context::void_register;
}
add_unbound_columns_for_negation(r, head_pred, single_res, single_res_expr, acc);
add_unbound_columns_for_negation(r, head_pred, single_res, single_res_expr, dealloc, acc);
int2ints var_indexes;
@ -510,11 +548,14 @@ namespace datalog {
unsigned srlen=single_res_expr.size();
SASSERT((single_res==execution_context::void_register) ? (srlen==0) : (srlen==m_reg_signatures[single_res].size()));
for(unsigned i=0; i<srlen; i++) {
expr * exp = single_res_expr[i];
expr * exp = single_res_expr[i].get();
if(is_app(exp)) {
SASSERT(m_context.get_decl_util().is_numeral_ext(exp));
relation_element value = to_app(exp);
if (!dealloc)
make_clone(filtered_res, filtered_res, acc);
acc.push_back(instruction::mk_filter_equal(m_context.get_manager(), filtered_res, value, i));
dealloc = true;
}
else {
SASSERT(is_var(exp));
@ -541,7 +582,10 @@ namespace datalog {
//condition!)
continue;
}
if (!dealloc)
make_clone(filtered_res, filtered_res, acc);
acc.push_back(instruction::mk_filter_identical(filtered_res, indexes.size(), indexes.c_ptr()));
dealloc = true;
}
//enforce negative predicates
@ -564,9 +608,12 @@ namespace datalog {
relation_sort arg_sort;
m_context.get_rel_context().get_rmanager().from_predicate(neg_pred, i, arg_sort);
reg_idx new_reg;
make_add_constant_column(head_pred, filtered_res, arg_sort, to_app(e), new_reg, acc);
bool new_dealloc;
make_add_constant_column(head_pred, filtered_res, arg_sort, to_app(e), new_reg, new_dealloc, acc);
make_dealloc_non_void(filtered_res, acc);
if (dealloc)
make_dealloc_non_void(filtered_res, acc);
dealloc = new_dealloc;
filtered_res = new_reg; // here filtered_res value gets changed !!
t_cols.push_back(single_res_expr.size());
@ -576,17 +623,129 @@ namespace datalog {
SASSERT(t_cols.size()==neg_cols.size());
reg_idx neg_reg = m_pred_regs.find(neg_pred);
if (!dealloc)
make_clone(filtered_res, filtered_res, acc);
acc.push_back(instruction::mk_filter_by_negation(filtered_res, neg_reg, t_cols.size(),
t_cols.c_ptr(), neg_cols.c_ptr()));
dealloc = true;
}
//enforce interpreted tail predicates
// enforce interpreted tail predicates
unsigned ft_len = r->get_tail_size(); // full tail
ptr_vector<expr> tail;
for (unsigned tail_index = ut_len; tail_index < ft_len; ++tail_index) {
tail.push_back(r->get_tail(tail_index));
}
if (!tail.empty()) {
app_ref filter_cond(tail.size() == 1 ? to_app(tail.back()) : m.mk_and(tail.size(), tail.c_ptr()), m);
ptr_vector<sort> filter_vars;
get_free_vars(filter_cond, filter_vars);
// create binding
expr_ref_vector binding(m);
binding.resize(filter_vars.size()+1);
for (unsigned v = 0; v < filter_vars.size(); ++v) {
if (!filter_vars[v])
continue;
int2ints::entry * entry = var_indexes.find_core(v);
unsigned src_col;
if (entry) {
src_col = entry->get_data().m_value.back();
} else {
// we have an unbound variable, so we add an unbound column for it
relation_sort unbound_sort = filter_vars[v];
reg_idx new_reg;
bool new_dealloc;
make_add_unbound_column(r, 0, head_pred, filtered_res, unbound_sort, new_reg, new_dealloc, acc);
if (dealloc)
make_dealloc_non_void(filtered_res, acc);
dealloc = new_dealloc;
filtered_res = new_reg;
src_col = single_res_expr.size();
single_res_expr.push_back(m.mk_var(v, unbound_sort));
entry = var_indexes.insert_if_not_there2(v, unsigned_vector());
entry->get_data().m_value.push_back(src_col);
}
relation_sort var_sort = m_reg_signatures[filtered_res][src_col];
binding[filter_vars.size()-v] = m.mk_var(src_col, var_sort);
}
// check if there are any columns to remove
unsigned_vector remove_columns;
{
unsigned_vector var_idx_to_remove;
ptr_vector<sort> vars;
get_free_vars(r->get_head(), vars);
for (int2ints::iterator I = var_indexes.begin(), E = var_indexes.end();
I != E; ++I) {
unsigned var_idx = I->m_key;
if (!vars.get(var_idx, 0)) {
unsigned_vector & cols = I->m_value;
for (unsigned i = 0; i < cols.size(); ++i) {
remove_columns.push_back(cols[i]);
}
var_idx_to_remove.push_back(var_idx);
}
}
for (unsigned i = 0; i < var_idx_to_remove.size(); ++i) {
var_indexes.remove(var_idx_to_remove[i]);
}
// update column idx for after projection state
if (!remove_columns.empty()) {
unsigned_vector offsets;
offsets.resize(single_res_expr.size(), 0);
for (unsigned i = 0; i < remove_columns.size(); ++i) {
for (unsigned col = remove_columns[i]; col < offsets.size(); ++col) {
++offsets[col];
}
}
for (int2ints::iterator I = var_indexes.begin(), E = var_indexes.end();
I != E; ++I) {
unsigned_vector & cols = I->m_value;
for (unsigned i = 0; i < cols.size(); ++i) {
cols[i] -= offsets[cols[i]];
}
}
}
}
expr_ref renamed(m);
m_context.get_var_subst()(filter_cond, binding.size(), binding.c_ptr(), renamed);
app_ref app_renamed(to_app(renamed), m);
if (remove_columns.empty()) {
if (!dealloc)
make_clone(filtered_res, filtered_res, acc);
acc.push_back(instruction::mk_filter_interpreted(filtered_res, app_renamed));
} else {
reg_idx new_reg;
std::sort(remove_columns.begin(), remove_columns.end());
make_filter_interpreted_and_project(filtered_res, app_renamed, remove_columns, new_reg, acc);
if (dealloc)
make_dealloc_non_void(filtered_res, acc);
filtered_res = new_reg;
}
dealloc = true;
}
#if 0
// this version is potentially better for non-symbolic tables,
// since it constraints each unbound column at a time (reducing the
// size of intermediate results).
unsigned ft_len=r->get_tail_size(); //full tail
for(unsigned tail_index=ut_len; tail_index<ft_len; tail_index++) {
app * t = r->get_tail(tail_index);
var_idx_set t_vars;
ast_manager & m = m_context.get_manager();
collect_vars(m, t, t_vars);
ptr_vector<sort> t_vars;
::get_free_vars(t, t_vars);
if(t_vars.empty()) {
expr_ref simplified(m);
@ -601,46 +760,32 @@ namespace datalog {
}
//determine binding size
unsigned max_var=0;
var_idx_set::iterator vit = t_vars.begin();
var_idx_set::iterator vend = t_vars.end();
for(; vit!=vend; ++vit) {
unsigned v = *vit;
if(v>max_var) { max_var = v; }
while (!t_vars.back()) {
t_vars.pop_back();
}
unsigned max_var = t_vars.size();
//create binding
expr_ref_vector binding(m);
binding.resize(max_var+1);
vit = t_vars.begin();
for(; vit!=vend; ++vit) {
unsigned v = *vit;
for(unsigned v = 0; v < t_vars.size(); ++v) {
if (!t_vars[v]) {
continue;
}
int2ints::entry * e = var_indexes.find_core(v);
if(!e) {
//we have an unbound variable, so we add an unbound column for it
relation_sort unbound_sort = 0;
for(unsigned hindex = 0; hindex<head_len; hindex++) {
expr * harg = h->get_arg(hindex);
if(!is_var(harg) || to_var(harg)->get_idx()!=v) {
continue;
}
unbound_sort = to_var(harg)->get_sort();
}
if(!unbound_sort) {
// the variable in the interpreted tail is neither bound in the
// uninterpreted tail nor present in the head
std::stringstream sstm;
sstm << "rule with unbound variable #" << v << " in interpreted tail: ";
r->display(m_context, sstm);
throw default_exception(sstm.str());
}
relation_sort unbound_sort = t_vars[v];
reg_idx new_reg;
TRACE("dl", tout << mk_pp(head_pred, m_context.get_manager()) << "\n";);
make_add_unbound_column(r, 0, head_pred, filtered_res, unbound_sort, new_reg, acc);
bool new_dealloc;
make_add_unbound_column(r, 0, head_pred, filtered_res, unbound_sort, new_reg, new_dealloc, acc);
make_dealloc_non_void(filtered_res, acc);
if (dealloc)
make_dealloc_non_void(filtered_res, acc);
dealloc = new_dealloc;
filtered_res = new_reg; // here filtered_res value gets changed !!
unsigned unbound_column_index = single_res_expr.size();
@ -658,8 +803,12 @@ namespace datalog {
expr_ref renamed(m);
m_context.get_var_subst()(t, binding.size(), binding.c_ptr(), renamed);
app_ref app_renamed(to_app(renamed), m);
if (!dealloc)
make_clone(filtered_res, filtered_res, acc);
acc.push_back(instruction::mk_filter_interpreted(filtered_res, app_renamed));
dealloc = true;
}
#endif
{
//put together the columns of head relation
@ -703,19 +852,20 @@ namespace datalog {
SASSERT(head_acis.size()==head_len);
reg_idx new_head_reg;
make_assembling_code(r, head_pred, filtered_res, head_acis, new_head_reg, acc);
make_assembling_code(r, head_pred, filtered_res, head_acis, new_head_reg, dealloc, acc);
//update the head relation
make_union(new_head_reg, head_reg, delta_reg, use_widening, acc);
make_dealloc_non_void(new_head_reg, acc);
if (dealloc)
make_dealloc_non_void(new_head_reg, acc);
}
finish:
// finish:
m_instruction_observer.finish_rule();
}
void compiler::add_unbound_columns_for_negation(rule* r, func_decl* pred, reg_idx& single_res, ptr_vector<expr>& single_res_expr,
instruction_block & acc) {
void compiler::add_unbound_columns_for_negation(rule* r, func_decl* pred, reg_idx& single_res, expr_ref_vector& single_res_expr,
bool & dealloc, instruction_block & acc) {
uint_set pos_vars;
u_map<expr*> neg_vars;
ast_manager& m = m_context.get_manager();
@ -737,7 +887,7 @@ namespace datalog {
}
// populate positive variables:
for (unsigned i = 0; i < single_res_expr.size(); ++i) {
expr* e = single_res_expr[i];
expr* e = single_res_expr[i].get();
if (is_var(e)) {
pos_vars.insert(to_var(e)->get_idx());
}
@ -749,7 +899,13 @@ namespace datalog {
expr* e = it->m_value;
if (!pos_vars.contains(v)) {
single_res_expr.push_back(e);
make_add_unbound_column(r, v, pred, single_res, m.get_sort(e), single_res, acc);
reg_idx new_single_res;
bool new_dealloc;
make_add_unbound_column(r, v, pred, single_res, m.get_sort(e), new_single_res, new_dealloc, acc);
if (dealloc)
make_dealloc_non_void(single_res, acc);
dealloc = new_dealloc;
single_res = new_single_res;
TRACE("dl", tout << "Adding unbound column: " << mk_pp(e, m) << "\n";);
}
}
@ -761,7 +917,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;
@ -830,6 +986,7 @@ namespace datalog {
m_stack.pop_back();
m_stack_content.mark(v, false);
}
public:
cycle_breaker(rule_dependencies & deps, item_set & removed)
: m_deps(deps), m_removed(removed) { SASSERT(removed.empty()); }
@ -885,13 +1042,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 +1133,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) {
@ -956,12 +1147,17 @@ namespace datalog {
}
func_decl_vector preds_vector;
func_decl_set global_deltas;
func_decl_set global_deltas_dummy;
detect_chains(head_preds, preds_vector, global_deltas);
detect_chains(head_preds, preds_vector, global_deltas_dummy);
/*
FIXME: right now we use all preds as global deltas for correctness purposes
func_decl_set local_deltas(head_preds);
set_difference(local_deltas, global_deltas);
*/
func_decl_set local_deltas;
func_decl_set global_deltas(head_preds);
pred2idx d_global_src; //these deltas serve as sources of tuples for rule evaluation inside the loop
get_fresh_registers(global_deltas, d_global_src);
@ -979,7 +1175,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 +1237,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 +1310,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

@ -41,7 +41,7 @@ namespace datalog {
typedef hashtable<unsigned, u_hash, u_eq> int_set;
typedef u_map<unsigned> int2int;
typedef u_map<unsigned_vector> int2ints;
typedef map<func_decl *, reg_idx, ptr_hash<func_decl>,ptr_eq<func_decl> > pred2idx;
typedef obj_map<func_decl, reg_idx> pred2idx;
typedef unsigned_vector var_vector;
typedef ptr_vector<func_decl> func_decl_vector;
@ -114,6 +114,8 @@ namespace datalog {
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;
/**
@ -143,6 +145,8 @@ namespace datalog {
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);
/**
@ -163,20 +167,20 @@ namespace datalog {
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, instruction_block & acc);
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, instruction_block & acc);
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,
instruction_block & acc);
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, ptr_vector<expr>& single_res_expr,
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);
@ -209,6 +213,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

@ -41,7 +41,6 @@ Revision History:
#include"for_each_expr.h"
#include"ast_smt_pp.h"
#include"ast_smt2_pp.h"
#include"expr_functors.h"
#include"dl_mk_partial_equiv.h"
#include"dl_mk_bit_blast.h"
#include"dl_mk_array_blast.h"
@ -49,7 +48,6 @@ Revision History:
#include"dl_mk_quantifier_abstraction.h"
#include"dl_mk_quantifier_instantiation.h"
#include"datatype_decl_plugin.h"
#include"expr_abstract.h"
namespace datalog {
@ -226,12 +224,17 @@ namespace datalog {
m_rewriter(m),
m_var_subst(m),
m_rule_manager(*this),
m_elim_unused_vars(m),
m_abstractor(m),
m_contains_p(*this),
m_check_pred(m_contains_p, m),
m_transf(*this),
m_trail(*this),
m_pinned(m),
m_vars(m),
m_rule_set(*this),
m_transformed_rule_set(*this),
m_rule_fmls_head(0),
m_rule_fmls(m),
m_background(m),
m_mc(0),
@ -241,8 +244,6 @@ namespace datalog {
m_last_answer(m),
m_engine(LAST_ENGINE),
m_cancel(false) {
//register plugins for builtin tables
}
context::~context() {
@ -252,6 +253,9 @@ namespace datalog {
void context::reset() {
m_trail.reset();
m_rule_set.reset();
m_rule_fmls_head = 0;
m_rule_fmls.reset();
m_rule_names.reset();
m_argument_var_names.reset();
m_preds.reset();
m_preds_by_name.reset();
@ -270,15 +274,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 +298,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));
}
@ -309,18 +305,19 @@ namespace datalog {
expr_ref context::bind_variables(expr* fml, bool is_forall) {
expr_ref result(m);
app_ref_vector const & vars = m_vars;
rule_manager& rm = get_rule_manager();
if (vars.empty()) {
result = fml;
}
else {
ptr_vector<sort> sorts;
expr_abstract(m, 0, vars.size(), reinterpret_cast<expr*const*>(vars.c_ptr()), fml, result);
get_free_vars(result, sorts);
m_names.reset();
m_abstractor(0, vars.size(), reinterpret_cast<expr*const*>(vars.c_ptr()), fml, result);
rm.collect_vars(result);
ptr_vector<sort>& sorts = rm.get_var_sorts();
if (sorts.empty()) {
result = fml;
}
else {
svector<symbol> names;
for (unsigned i = 0; i < sorts.size(); ++i) {
if (!sorts[i]) {
if (i < vars.size()) {
@ -331,29 +328,36 @@ namespace datalog {
}
}
if (i < vars.size()) {
names.push_back(vars[i]->get_decl()->get_name());
m_names.push_back(vars[i]->get_decl()->get_name());
}
else {
names.push_back(symbol(i));
m_names.push_back(symbol(i));
}
}
quantifier_ref q(m);
sorts.reverse();
q = m.mk_quantifier(is_forall, sorts.size(), sorts.c_ptr(), names.c_ptr(), result);
elim_unused_vars(m, q, result);
q = m.mk_quantifier(is_forall, sorts.size(), sorts.c_ptr(), m_names.c_ptr(), result);
m_elim_unused_vars(q, result);
}
}
return result;
}
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 +451,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,16 +458,19 @@ 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();
while (m_rule_fmls_head < m_rule_fmls.size()) {
expr* fml = m_rule_fmls[m_rule_fmls_head].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[m_rule_fmls_head]);
++m_rule_fmls_head;
}
rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end();
rule_ref r(m_rule_manager);
for (; it != end; ++it) {
r = *it;
check_rule(r);
}
add_rules(rules);
m_rule_fmls.reset();
m_rule_names.reset();
}
//
@ -487,25 +479,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 +513,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) {
@ -559,6 +554,8 @@ namespace datalog {
throw default_exception("get_num_levels is not supported for bmc");
case TAB_ENGINE:
throw default_exception("get_num_levels is not supported for tab");
case CLP_ENGINE:
throw default_exception("get_num_levels is not supported for clp");
default:
throw default_exception("unknown engine");
}
@ -577,6 +574,8 @@ namespace datalog {
throw default_exception("operation is not supported for BMC engine");
case TAB_ENGINE:
throw default_exception("operation is not supported for TAB engine");
case CLP_ENGINE:
throw default_exception("operation is not supported for CLP engine");
default:
throw default_exception("unknown engine");
}
@ -596,6 +595,8 @@ namespace datalog {
throw default_exception("operation is not supported for BMC engine");
case TAB_ENGINE:
throw default_exception("operation is not supported for TAB engine");
case CLP_ENGINE:
throw default_exception("operation is not supported for CLP engine");
default:
throw default_exception("unknown engine");
}
@ -622,28 +623,16 @@ namespace datalog {
}
}
class context::contains_pred : public i_expr_pred {
rule_manager const& m;
public:
contains_pred(rule_manager const& m): m(m) {}
virtual ~contains_pred() {}
virtual bool operator()(expr* e) {
return is_app(e) && m.is_predicate(to_app(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());
check_pred check_pred(contains_p, get_manager());
TRACE("dl", r->display_smt2(get_manager(), tout); tout << "\n";);
for (unsigned i = ut_size; i < t_size; ++i) {
app* t = r->get_tail(i);
TRACE("dl", tout << "checking: " << mk_ismt2_pp(t, get_manager()) << "\n";);
if (check_pred(t)) {
if (m_check_pred(t)) {
std::ostringstream out;
out << "interpreted body " << mk_ismt2_pp(t, get_manager()) << " contains recursive predicate";
throw default_exception(out.str());
@ -662,8 +651,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 +664,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());
@ -736,6 +724,10 @@ namespace datalog {
check_existential_tail(r);
check_positive_predicates(r);
break;
case CLP_ENGINE:
check_existential_tail(r);
check_positive_predicates(r);
break;
default:
UNREACHABLE();
break;
@ -749,14 +741,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 +755,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,22 +821,33 @@ 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));
m_transf.register_plugin(alloc(mk_coi_filter, *this));
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));
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(mk_partial_equivalence_transformer, *this));
m_transf.register_plugin(alloc(mk_rule_inliner, *this));
m_transf.register_plugin(alloc(mk_interp_tail_simplifier, *this));
if (get_params().bit_blast()) {
m_transf.register_plugin(alloc(mk_bit_blast, *this, 22000));
m_transf.register_plugin(alloc(mk_interp_tail_simplifier, *this, 21000));
}
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
TRACE("dl", display_rules(tout););
@ -866,15 +860,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 +920,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()) {
@ -980,18 +965,21 @@ namespace datalog {
engine_type_proc(ast_manager& m): m(m), a(m), dt(m), m_engine(DATALOG_ENGINE) {}
DL_ENGINE get_engine() const { return m_engine; }
void operator()(expr* e) {
if (is_quantifier(e)) {
m_engine = QPDR_ENGINE;
}
else if (a.is_int_real(e) && m_engine != QPDR_ENGINE) {
m_engine = PDR_ENGINE;
}
else if (is_var(e) && m.is_bool(e)) {
m_engine = PDR_ENGINE;
}
else if (dt.is_datatype(m.get_sort(e))) {
m_engine = PDR_ENGINE;
else if (m_engine != QPDR_ENGINE) {
if (a.is_int_real(e)) {
m_engine = PDR_ENGINE;
}
else if (is_var(e) && m.is_bool(e)) {
m_engine = PDR_ENGINE;
}
else if (dt.is_datatype(m.get_sort(e))) {
m_engine = PDR_ENGINE;
}
}
}
};
@ -1017,6 +1005,9 @@ namespace datalog {
else if (e == symbol("tab")) {
m_engine = TAB_ENGINE;
}
else if (e == symbol("clp")) {
m_engine = CLP_ENGINE;
}
if (m_engine == LAST_ENGINE) {
expr_fast_mark1 mark;
@ -1030,42 +1021,45 @@ namespace datalog {
}
m_engine = proc.get_engine();
}
for (unsigned i = m_rule_fmls_head; m_engine == DATALOG_ENGINE && i < m_rule_fmls.size(); ++i) {
expr* fml = m_rule_fmls[i].get();
while (is_quantifier(fml)) {
fml = to_quantifier(fml)->get_expr();
}
quick_for_each_expr(proc, mark, fml);
m_engine = proc.get_engine();
}
}
}
lbool context::query(expr* query) {
new_query();
rule_set::iterator it = m_rule_set.begin(), end = m_rule_set.end();
rule_ref r(m_rule_manager);
for (; it != end; ++it) {
r = *it;
check_rule(r);
}
switch(get_engine()) {
m_mc = mk_skip_model_converter();
m_last_status = OK;
m_last_answer = 0;
switch (get_engine()) {
case DATALOG_ENGINE:
flush_add_rules();
return rel_query(query);
case PDR_ENGINE:
case QPDR_ENGINE:
flush_add_rules();
return pdr_query(query);
case BMC_ENGINE:
case QBMC_ENGINE:
flush_add_rules();
return bmc_query(query);
case TAB_ENGINE:
flush_add_rules();
return tab_query(query);
case CLP_ENGINE:
flush_add_rules();
return clp_query(query);
default:
UNREACHABLE();
return rel_query(query);
}
}
void context::new_query() {
m_mc = mk_skip_model_converter();
flush_add_rules();
m_last_status = OK;
m_last_answer = 0;
}
model_ref context::get_model() {
switch(get_engine()) {
case PDR_ENGINE:
@ -1116,11 +1110,22 @@ namespace datalog {
}
}
void context::ensure_clp() {
if (!m_clp.get()) {
m_clp = alloc(clp, *this);
}
}
lbool context::tab_query(expr* query) {
ensure_tab();
return m_tab->query(query);
}
lbool context::clp_query(expr* query) {
ensure_clp();
return m_clp->query(query);
}
void context::ensure_rel() {
if (!m_rel.get()) {
m_rel = alloc(rel_context, *this);
@ -1161,6 +1166,10 @@ namespace datalog {
ensure_tab();
m_last_answer = m_tab->get_answer();
return m_last_answer.get();
case CLP_ENGINE:
ensure_clp();
m_last_answer = m_clp->get_answer();
return m_last_answer.get();
default:
UNREACHABLE();
}
@ -1186,6 +1195,10 @@ namespace datalog {
ensure_tab();
m_tab->display_certificate(out);
return true;
case CLP_ENGINE:
ensure_clp();
m_clp->display_certificate(out);
return true;
default:
return false;
}
@ -1273,14 +1286,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) {
for (unsigned i = m_rule_fmls_head; 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,14 +1300,13 @@ 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);
rules.push_back(fml);
names.push_back((*it)->name());
}
for (unsigned i = 0; i < m_rule_fmls.size(); ++i) {
for (unsigned i = m_rule_fmls_head; i < m_rule_fmls.size(); ++i) {
rules.push_back(m_rule_fmls[i].get());
names.push_back(m_rule_names[i]);
}

View file

@ -45,6 +45,9 @@ Revision History:
#include"model2expr.h"
#include"smt_params.h"
#include"dl_rule_transformer.h"
#include"expr_abstract.h"
#include"expr_functors.h"
#include"clp_context.h"
namespace datalog {
@ -76,6 +79,18 @@ namespace datalog {
typedef obj_map<const func_decl, svector<symbol> > pred2syms;
typedef obj_map<const sort, sort_domain*> sort_domain_map;
class contains_pred : public i_expr_pred {
context const& ctx;
public:
contains_pred(context& ctx): ctx(ctx) {}
virtual ~contains_pred() {}
virtual bool operator()(expr* e) {
return ctx.is_predicate(e);
}
};
ast_manager & m;
smt_params & m_fparams;
params_ref m_params_ref;
@ -84,16 +99,22 @@ namespace datalog {
th_rewriter m_rewriter;
var_subst m_var_subst;
rule_manager m_rule_manager;
unused_vars_eliminator m_elim_unused_vars;
expr_abstractor m_abstractor;
contains_pred m_contains_p;
check_pred m_check_pred;
rule_transformer m_transf;
trail_stack<context> m_trail;
ast_ref_vector m_pinned;
app_ref_vector m_vars;
svector<symbol> m_names;
sort_domain_map m_sorts;
func_decl_set m_preds;
sym2decl m_preds_by_name;
pred2syms m_argument_var_names;
rule_set m_rule_set;
rule_set m_transformed_rule_set;
unsigned m_rule_fmls_head;
expr_ref_vector m_rule_fmls;
svector<symbol> m_rule_names;
expr_ref_vector m_background;
@ -104,6 +125,7 @@ namespace datalog {
scoped_ptr<bmc> m_bmc;
scoped_ptr<rel_context> m_rel;
scoped_ptr<tab> m_tab;
scoped_ptr<clp> m_clp;
bool m_closed;
bool m_saturation_was_run;
@ -185,7 +207,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 +270,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 +282,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 +359,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 +369,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);
}
@ -457,9 +479,9 @@ namespace datalog {
void ensure_tab();
void ensure_rel();
void ensure_clp();
void new_query();
void ensure_rel();
lbool rel_query(expr* query);
@ -469,6 +491,8 @@ namespace datalog {
lbool tab_query(expr* query);
lbool clp_query(expr* query);
void check_quantifier_free(rule_ref& r);
void check_uninterpreted_free(rule_ref& r);
void check_existential_tail(rule_ref& r);

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 {
@ -1291,8 +1291,8 @@ namespace datalog {
m_renaming_for_inner_rel(m_manager) {
relation_manager & rmgr = r.get_manager();
idx_set cond_columns;
collect_vars(m_manager, m_cond, cond_columns);
rule_manager& rm = r.get_context().get_rule_manager();
idx_set& cond_columns = rm.collect_vars(m_cond);
unsigned sig_sz = r.get_signature().size();
for(unsigned i=0; i<sig_sz; i++) {
@ -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

@ -47,7 +47,7 @@ namespace datalog {
}
struct hash {
unsigned operator()(const rel_spec & o) const {
return o.m_inner_kind^int_vector_hash(o.m_table_cols);
return o.m_inner_kind^svector_hash<bool_hash>()(o.m_table_cols);
}
};
};

View file

@ -359,21 +359,7 @@ namespace datalog {
r2.get_signature().output(ctx.get_rel_context().get_manager(), tout);
tout<<":"<<r2.get_size_estimate_rows()<<" ->\n";);
try {
ctx.set_reg(m_res, (*fn)(r1, r2));
}
catch(...)
{
std::string annotation;
unsigned sz;
ctx.get_register_annotation(m_rel1, annotation);
sz = ctx.reg(m_rel1)?ctx.reg(m_rel1)->get_size_estimate_rows():0;
std::cout << m_rel1 << "\t" << sz << "\t" << annotation << "\n";
ctx.get_register_annotation(m_rel2, annotation);
sz = ctx.reg(m_rel2)?ctx.reg(m_rel2)->get_size_estimate_rows():0;
std::cout << m_rel2 << "\t" << sz << "\t" << annotation << "\n";
throw;
}
ctx.set_reg(m_res, (*fn)(r1, r2));
TRACE("dl",
ctx.reg(m_res)->get_signature().output(ctx.get_rel_context().get_manager(), tout);
@ -452,7 +438,7 @@ namespace datalog {
class instr_filter_identical : public instruction {
typedef vector<unsigned> column_vector;
typedef unsigned_vector column_vector;
reg_idx m_reg;
column_vector m_cols;
public:
@ -540,6 +526,64 @@ namespace datalog {
return alloc(instr_filter_interpreted, reg, condition);
}
class instr_filter_interpreted_and_project : public instruction {
reg_idx m_src;
reg_idx m_res;
app_ref m_cond;
unsigned_vector m_cols;
public:
instr_filter_interpreted_and_project(reg_idx src, app_ref & condition,
unsigned col_cnt, const unsigned * removed_cols, reg_idx result)
: m_src(src), m_cond(condition), m_cols(col_cnt, removed_cols),
m_res(result) {}
virtual bool perform(execution_context & ctx) {
if (!ctx.reg(m_src)) {
ctx.make_empty(m_res);
return true;
}
relation_transformer_fn * fn;
relation_base & reg = *ctx.reg(m_src);
if (!find_fn(reg, fn)) {
fn = reg.get_manager().mk_filter_interpreted_and_project_fn(reg, m_cond, m_cols.size(), m_cols.c_ptr());
if (!fn) {
throw default_exception(
"trying to perform unsupported filter_interpreted_and_project operation on a relation of kind %s",
reg.get_plugin().get_name().bare_str());
}
store_fn(reg, fn);
}
ctx.set_reg(m_res, (*fn)(reg));
if (ctx.eager_emptiness_checking() && ctx.reg(m_res)->empty()) {
ctx.make_empty(m_res);
}
return true;
}
virtual void display_head_impl(rel_context const& ctx, std::ostream & out) const {
out << "filter_interpreted_and_project " << m_src << " into " << m_res;
out << " using " << mk_pp(m_cond, m_cond.get_manager());
out << " deleting columns ";
print_container(m_cols, out);
}
virtual void make_annotations(execution_context & ctx) {
std::stringstream s;
std::string a = "rel_src";
ctx.get_register_annotation(m_src, a);
s << "filter_interpreted_and_project " << mk_pp(m_cond, m_cond.get_manager());
ctx.set_register_annotation(m_res, s.str());
}
};
instruction * instruction::mk_filter_interpreted_and_project(reg_idx reg, app_ref & condition,
unsigned col_cnt, const unsigned * removed_cols, reg_idx result) {
return alloc(instr_filter_interpreted_and_project, reg, condition, col_cnt, removed_cols, result);
}
class instr_union : public instruction {
reg_idx m_src;
@ -606,6 +650,7 @@ namespace datalog {
}
}
SASSERT(r_src.get_signature().size() == r_tgt.get_signature().size());
TRACE("dl_verbose", r_tgt.display(tout <<"pre-union:"););
(*fn)(r_tgt, r_src, r_delta);
@ -651,7 +696,7 @@ namespace datalog {
class instr_project_rename : public instruction {
typedef vector<unsigned> column_vector;
typedef unsigned_vector column_vector;
bool m_projection;
reg_idx m_src;
column_vector m_cols;
@ -723,7 +768,8 @@ namespace datalog {
instr_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)
: m_rel1(rel1), m_rel2(rel2), m_cols1(joined_col_cnt, cols1),
m_cols2(joined_col_cnt, cols2), m_removed_cols(removed_col_cnt, removed_cols), m_res(result) {}
m_cols2(joined_col_cnt, cols2), m_removed_cols(removed_col_cnt, removed_cols), m_res(result) {
}
virtual bool perform(execution_context & ctx) {
ctx.make_empty(m_res);
if (!ctx.reg(m_rel1) || !ctx.reg(m_rel2)) {
@ -830,7 +876,7 @@ namespace datalog {
class instr_filter_by_negation : public instruction {
typedef vector<unsigned> column_vector;
typedef unsigned_vector column_vector;
reg_idx m_tgt;
reg_idx m_neg_rel;
column_vector m_cols1;

View file

@ -260,6 +260,8 @@ namespace datalog {
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,

View file

@ -99,11 +99,9 @@ namespace datalog {
}
class interval_relation_plugin::rename_fn : public convenient_relation_rename_fn {
interval_relation_plugin& m_plugin;
public:
rename_fn(interval_relation_plugin& p, const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle)
: convenient_relation_rename_fn(orig_sig, cycle_len, cycle),
m_plugin(p){
rename_fn(const relation_signature & orig_sig, unsigned cycle_len, const unsigned * cycle)
: convenient_relation_rename_fn(orig_sig, cycle_len, cycle) {
}
virtual relation_base * operator()(const relation_base & _r) {
@ -120,7 +118,7 @@ namespace datalog {
if(!check_kind(r)) {
return 0;
}
return alloc(rename_fn, *this, r.get_signature(), cycle_len, permutation_cycle);
return alloc(rename_fn, r.get_signature(), cycle_len, permutation_cycle);
}
interval interval_relation_plugin::unite(interval const& src1, interval const& src2) {
@ -194,11 +192,9 @@ namespace datalog {
}
class interval_relation_plugin::union_fn : public relation_union_fn {
interval_relation_plugin& m_plugin;
bool m_is_widen;
public:
union_fn(interval_relation_plugin& p, bool is_widen) :
m_plugin(p),
union_fn(bool is_widen) :
m_is_widen(is_widen) {
}
@ -223,7 +219,7 @@ namespace datalog {
if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) {
return 0;
}
return alloc(union_fn, *this, false);
return alloc(union_fn, false);
}
relation_union_fn * interval_relation_plugin::mk_widen_fn(
@ -232,7 +228,7 @@ namespace datalog {
if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) {
return 0;
}
return alloc(union_fn, *this, true);
return alloc(union_fn, true);
}
class interval_relation_plugin::filter_identical_fn : public relation_mutator_fn {

View file

@ -145,7 +145,6 @@ namespace datalog {
expr_ref_vector conjs(m), new_conjs(m);
expr_ref tmp(m);
expr_safe_replace sub(m);
uint_set lhs_vars, rhs_vars;
bool change = false;
bool inserted = false;
@ -161,10 +160,8 @@ namespace datalog {
if (is_store_def(e, x, y)) {
// enforce topological order consistency:
uint_set lhs;
collect_vars(m, x, lhs_vars);
collect_vars(m, y, rhs_vars);
lhs = lhs_vars;
uint_set lhs = rm.collect_vars(x);
uint_set rhs_vars = rm.collect_vars(y);
lhs &= rhs_vars;
if (!lhs.empty()) {
TRACE("dl", tout << "unusable equality " << mk_pp(e, m) << "\n";);
@ -182,7 +179,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 +195,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 +210,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

@ -0,0 +1,78 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
dl_mk_backwards.cpp
Abstract:
Create Horn clauses for backwards flow.
Author:
Nikolaj Bjorner (nbjorner) 2013-04-17
Revision History:
--*/
#include"dl_mk_backwards.h"
#include"dl_context.h"
namespace datalog {
mk_backwards::mk_backwards(context & ctx, unsigned priority):
plugin(priority),
m(ctx.get_manager()),
m_ctx(ctx) {
}
mk_backwards::~mk_backwards() { }
rule_set * mk_backwards::operator()(rule_set const & source) {
context& ctx = source.get_context();
rule_manager& rm = source.get_rule_manager();
rule_set * result = alloc(rule_set, ctx);
unsigned sz = source.get_num_rules();
rule_ref new_rule(rm);
app_ref_vector tail(m);
app_ref head(m);
svector<bool> neg;
app_ref query(m);
query = m.mk_fresh_const("Q", m.mk_bool_sort());
result->set_output_predicate(query->get_decl());
m_ctx.register_predicate(query->get_decl(), false);
for (unsigned i = 0; i < sz; ++i) {
tail.reset();
neg.reset();
rule & r = *source.get_rule(i);
unsigned utsz = r.get_uninterpreted_tail_size();
unsigned tsz = r.get_tail_size();
if (!source.is_output_predicate(r.get_decl())) {
tail.push_back(r.get_head());
neg.push_back(false);
}
for (unsigned j = utsz; j < tsz; ++j) {
tail.push_back(r.get_tail(j));
neg.push_back(false);
}
for (unsigned j = 0; j <= utsz; ++j) {
if (j == utsz && j > 0) {
break;
}
if (j == utsz) {
head = query;
}
else {
head = r.get_tail(j);
}
new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true);
result->add_rule(new_rule);
}
}
TRACE("dl", result->display(tout););
return result;
}
};

View file

@ -0,0 +1,38 @@
/*++
Copyright (c) 2013 Microsoft Corporation
Module Name:
dl_mk_backwards.h
Abstract:
Create Horn clauses for backwards flow.
Author:
Nikolaj Bjorner (nbjorner) 2013-04-17
Revision History:
--*/
#ifndef _DL_MK_BACKWARDS_H_
#define _DL_MK_BACKWARDS_H_
#include"dl_rule_transformer.h"
namespace datalog {
class mk_backwards : public rule_transformer::plugin {
ast_manager& m;
context& m_ctx;
public:
mk_backwards(context & ctx, unsigned priority = 33000);
~mk_backwards();
rule_set * operator()(rule_set const & source);
};
};
#endif /* _DL_MK_BACKWARDS_H_ */

View file

@ -108,43 +108,50 @@ 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; }
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
rule_manager& rm = m_context.get_rule_manager();
bool found = false;
for (unsigned j = 0; !found && j < num; ++j) {
found = m_util.is_mkbv(args[j]);
}
if (!found) {
if (num == 0) {
if (m_src->is_output_predicate(f))
m_dst->set_output_predicate(f);
return BR_FAILED;
}
for (unsigned i = 0; i < num; ++i) {
if (!m_util.is_mkbv(args[i]))
return BR_FAILED;
}
//
// f(mk_bv(args),...)
//
@ -183,14 +190,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 +200,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 +212,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 +238,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 +259,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);
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,15 +270,21 @@ 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));
// copy output predicates without any rule (bit-blasting not really needed)
const func_decl_set& decls = source.get_output_predicates();
for (func_decl_set::iterator I = decls.begin(), E = decls.end(); I != E; ++I) {
if (!source.contains(*I))
result->set_output_predicate(*I);
}
if (m_context.get_model_converter()) {

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,43 +520,42 @@ 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);
}
class explanation_relation_plugin::intersection_filter_fn : public relation_intersection_filter_fn {
explanation_relation_plugin & m_plugin;
func_decl_ref m_union_decl;
public:
intersection_filter_fn(explanation_relation_plugin & plugin)
: m_plugin(plugin), m_union_decl(plugin.m_union_decl) {}
: m_union_decl(plugin.m_union_decl) {}
virtual void operator()(relation_base & tgt0, const relation_base & src0) {
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 +569,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 +594,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 +619,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 +667,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 +676,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 +715,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 +729,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 +753,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 +793,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 +815,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 +829,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 +859,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

@ -27,10 +27,12 @@ namespace datalog {
mk_filter_rules::mk_filter_rules(context & ctx):
plugin(2000),
m_context(ctx),
m_manager(ctx.get_manager()),
m(ctx.get_manager()),
rm(ctx.get_rule_manager()),
m_result(0),
m_pinned(m_manager) {
m_pinned(m) {
}
mk_filter_rules::~mk_filter_rules() {
ptr_vector<filter_key> to_dealloc;
filter_cache::iterator it = m_tail2filter.begin();
@ -50,15 +52,15 @@ 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)) {
TRACE("mk_filter_rules", tout << mk_pp(pred, m_manager) << "\nis not a candidate because it is interpreted.\n";);
if (!m_context.is_predicate(pred)) {
TRACE("mk_filter_rules", tout << mk_pp(pred, m) << "\nis not a candidate because it is interpreted.\n";);
return false;
}
var_idx_set used_vars;
unsigned n = pred->get_num_args();
for (unsigned i = 0; i < n; i++) {
expr * arg = pred->get_arg(i);
if (m_manager.is_value(arg))
if (m.is_value(arg))
return true;
SASSERT(is_var(arg));
unsigned vidx = to_var(arg)->get_idx();
@ -73,10 +75,10 @@ namespace datalog {
\brief Create a "filter" (if it doesn't exist already) for the given predicate.
*/
func_decl * mk_filter_rules::mk_filter_decl(app * pred, var_idx_set const & non_local_vars) {
sort_ref_buffer filter_domain(m_manager);
sort_ref_buffer filter_domain(m);
filter_key * key = alloc(filter_key, m_manager);
mk_new_rule_tail(m_manager, pred, non_local_vars, filter_domain, key->filter_args, key->new_pred);
filter_key * key = alloc(filter_key, m);
mk_new_rule_tail(m, pred, non_local_vars, filter_domain, key->filter_args, key->new_pred);
func_decl * filter_decl = 0;
if (!m_tail2filter.find(key, filter_decl)) {
filter_decl = m_context.mk_fresh_head_predicate(pred->get_decl()->get_name(), symbol("filter"),
@ -84,8 +86,8 @@ namespace datalog {
m_pinned.push_back(filter_decl);
m_tail2filter.insert(key, filter_decl);
app_ref filter_head(m_manager);
filter_head = m_manager.mk_app(filter_decl, key->filter_args.size(), key->filter_args.c_ptr());
app_ref filter_head(m);
filter_head = m.mk_app(filter_decl, key->filter_args.size(), key->filter_args.c_ptr());
app * filter_tail = key->new_pred;
rule * filter_rule = m_context.get_rule_manager().mk(filter_head, 1, &filter_tail, (const bool *)0);
filter_rule->set_accounting_parent_object(m_context, m_current);
@ -103,16 +105,15 @@ namespace datalog {
void mk_filter_rules::process(rule * r) {
m_current = r;
app * new_head = r->get_head();
app_ref_vector new_tail(m_manager);
app_ref_vector new_tail(m);
svector<bool> new_is_negated;
unsigned sz = r->get_tail_size();
bool rule_modified = false;
for (unsigned i = 0; i < sz; i++) {
app * tail = r->get_tail(i);
if (is_candidate(tail)) {
TRACE("mk_filter_rules", tout << "is_candidate: " << mk_pp(tail, m_manager) << "\n";);
var_idx_set non_local_vars;
collect_non_local_vars(m_manager, r, tail, non_local_vars);
TRACE("mk_filter_rules", tout << "is_candidate: " << mk_pp(tail, m) << "\n";);
var_idx_set non_local_vars = rm.collect_rule_vars_ex(r, tail);
func_decl * filter_decl = mk_filter_decl(tail, non_local_vars);
ptr_buffer<expr> new_args;
var_idx_set used_vars;
@ -128,7 +129,7 @@ namespace datalog {
}
}
SASSERT(new_args.size() == filter_decl->get_arity());
new_tail.push_back(m_manager.mk_app(filter_decl, new_args.size(), new_args.c_ptr()));
new_tail.push_back(m.mk_app(filter_decl, new_args.size(), new_args.c_ptr()));
rule_modified = true;
}
else {
@ -151,19 +152,18 @@ namespace datalog {
}
rule_set * mk_filter_rules::operator()(rule_set const & source) {
// TODO mc, pc
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

@ -45,17 +45,22 @@ namespace datalog {
filter_key(ast_manager & m) : new_pred(m), filter_args(m) {}
unsigned hash() const {
return new_pred->hash() ^ int_vector_hash(filter_args);
unsigned r = new_pred->hash();
for (unsigned i = 0; i < filter_args.size(); ++i) {
r ^= filter_args[i]->hash();
}
return r;
}
bool operator==(const filter_key & o) const {
return o.new_pred==new_pred && vectors_equal(o.filter_args, filter_args);
}
};
typedef map<filter_key*, func_decl*, obj_ptr_hash<filter_key>, deref_eq<filter_key> > filter_cache;
typedef obj_map<filter_key, func_decl*> filter_cache;
context & m_context;
ast_manager & m_manager;
ast_manager & m;
rule_manager & rm;
filter_cache m_tail2filter;
rule_set * m_result;
rule * m_current;

View file

@ -67,24 +67,23 @@ namespace datalog {
void mk_interp_tail_simplifier::rule_substitution::get_result(rule_ref & res) {
SASSERT(m_rule);
app_ref new_head(m);
apply(m_rule->get_head(), new_head);
apply(m_rule->get_head(), m_head);
app_ref_vector tail(m);
svector<bool> tail_neg;
m_tail.reset();
m_neg.reset();
unsigned tail_len = m_rule->get_tail_size();
for (unsigned i=0; i<tail_len; i++) {
app_ref new_tail_el(m);
apply(m_rule->get_tail(i), new_tail_el);
tail.push_back(new_tail_el);
tail_neg.push_back(m_rule->is_neg_tail(i));
m_tail.push_back(new_tail_el);
m_neg.push_back(m_rule->is_neg_tail(i));
}
mk_rule_inliner::remove_duplicate_tails(tail, tail_neg);
mk_rule_inliner::remove_duplicate_tails(m_tail, m_neg);
SASSERT(tail.size() == tail_neg.size());
res = m_context.get_rule_manager().mk(new_head, tail.size(), tail.c_ptr(), tail_neg.c_ptr());
SASSERT(m_tail.size() == m_neg.size());
res = m_context.get_rule_manager().mk(m_head, m_tail.size(), m_tail.c_ptr(), m_neg.c_ptr());
res->set_accounting_parent_object(m_context, m_rule);
res->norm_vars(res.get_manager());
}
@ -362,14 +361,37 @@ namespace datalog {
}
};
class mk_interp_tail_simplifier::normalizer_rw : public rewriter_tpl<normalizer_cfg> {
public:
normalizer_rw(ast_manager& m, normalizer_cfg& cfg): rewriter_tpl<normalizer_cfg>(m, false, cfg) {}
};
mk_interp_tail_simplifier::mk_interp_tail_simplifier(context & ctx, unsigned priority)
: plugin(priority),
m(ctx.get_manager()),
m_context(ctx),
m_simp(ctx.get_rewriter()),
a(m),
m_rule_subst(ctx),
m_tail(m),
m_itail_members(m),
m_conj(m) {
m_cfg = alloc(normalizer_cfg, m);
m_rw = alloc(normalizer_rw, m, *m_cfg);
}
mk_interp_tail_simplifier::~mk_interp_tail_simplifier() {
dealloc(m_rw);
dealloc(m_cfg);
}
void mk_interp_tail_simplifier::simplify_expr(app * a, expr_ref& res)
{
expr_ref simp1_res(m);
m_simp(a, simp1_res);
normalizer_cfg r_cfg(m);
rewriter_tpl<normalizer_cfg> rwr(m, false, r_cfg);
expr_ref dl_form_e(m);
rwr(simp1_res.get(), res);
(*m_rw)(simp1_res.get(), res);
/*if (simp1_res.get()!=res.get()) {
std::cout<<"pre norm:\n"<<mk_pp(simp1_res.get(),m)<<"post norm:\n"<<mk_pp(res.get(),m)<<"\n";
@ -385,15 +407,15 @@ namespace datalog {
return false;
}
ptr_vector<expr> todo;
m_todo.reset();
m_leqs.reset();
for (unsigned i = u_len; i < len; i++) {
todo.push_back(r->get_tail(i));
m_todo.push_back(r->get_tail(i));
SASSERT(!r->is_neg_tail(i));
}
m_rule_subst.reset(r);
obj_hashtable<expr> leqs;
expr_ref_vector trail(m);
expr_ref tmp1(m), tmp2(m);
bool found_something = false;
@ -401,10 +423,10 @@ namespace datalog {
#define TRY_UNIFY(_x,_y) if (m_rule_subst.unify(_x,_y)) { found_something = true; }
#define IS_FLEX(_x) (is_var(_x) || m.is_value(_x))
while (!todo.empty()) {
while (!m_todo.empty()) {
expr * arg1, *arg2;
expr * t0 = todo.back();
todo.pop_back();
expr * t0 = m_todo.back();
m_todo.pop_back();
expr* t = t0;
bool neg = m.is_not(t, t);
if (is_var(t)) {
@ -412,7 +434,7 @@ namespace datalog {
}
else if (!neg && m.is_and(t)) {
app* a = to_app(t);
todo.append(a->get_num_args(), a->get_args());
m_todo.append(a->get_num_args(), a->get_args());
}
else if (!neg && m.is_eq(t, arg1, arg2) && IS_FLEX(arg1) && IS_FLEX(arg2)) {
TRY_UNIFY(arg1, arg2);
@ -440,12 +462,12 @@ namespace datalog {
else if (!neg && (a.is_le(t, arg1, arg2) || a.is_ge(t, arg2, arg1))) {
tmp1 = a.mk_sub(arg1, arg2);
tmp2 = a.mk_sub(arg2, arg1);
if (false && leqs.contains(tmp2) && IS_FLEX(arg1) && IS_FLEX(arg2)) {
if (false && m_leqs.contains(tmp2) && IS_FLEX(arg1) && IS_FLEX(arg2)) {
TRY_UNIFY(arg1, arg2);
}
else {
trail.push_back(tmp1);
leqs.insert(tmp1);
m_leqs.insert(tmp1);
}
}
}
@ -485,12 +507,12 @@ namespace datalog {
}
app_ref head(r->get_head(), m);
app_ref_vector tail(m);
svector<bool> tail_neg;
m_tail.reset();
m_tail_neg.reset();
for (unsigned i=0; i<u_len; i++) {
tail.push_back(r->get_tail(i));
tail_neg.push_back(r->is_neg_tail(i));
m_tail.push_back(r->get_tail(i));
m_tail_neg.push_back(r->is_neg_tail(i));
}
bool modified = false;
@ -502,12 +524,12 @@ namespace datalog {
SASSERT(!r->is_neg_tail(u_len));
}
else {
expr_ref_vector itail_members(m);
m_itail_members.reset();
for (unsigned i=u_len; i<len; i++) {
itail_members.push_back(r->get_tail(i));
m_itail_members.push_back(r->get_tail(i));
SASSERT(!r->is_neg_tail(i));
}
itail = m.mk_and(itail_members.size(), itail_members.c_ptr());
itail = m.mk_and(m_itail_members.size(), m_itail_members.c_ptr());
modified = true;
}
@ -523,21 +545,21 @@ namespace datalog {
SASSERT(m.is_bool(simp_res));
if (modified) {
expr_ref_vector conjs(m);
flatten_and(simp_res, conjs);
for (unsigned i = 0; i < conjs.size(); ++i) {
expr* e = conjs[i].get();
m_conj.reset();
flatten_and(simp_res, m_conj);
for (unsigned i = 0; i < m_conj.size(); ++i) {
expr* e = m_conj[i].get();
if (is_app(e)) {
tail.push_back(to_app(e));
m_tail.push_back(to_app(e));
}
else {
tail.push_back(m.mk_eq(e, m.mk_true()));
m_tail.push_back(m.mk_eq(e, m.mk_true()));
}
tail_neg.push_back(false);
m_tail_neg.push_back(false);
}
SASSERT(tail.size() == tail_neg.size());
res = m_context.get_rule_manager().mk(head, tail.size(), tail.c_ptr(), tail_neg.c_ptr());
SASSERT(m_tail.size() == m_tail_neg.size());
res = m_context.get_rule_manager().mk(head, m_tail.size(), m_tail.c_ptr(), m_tail_neg.c_ptr());
res->set_accounting_parent_object(m_context, r);
}
else {
@ -583,7 +605,9 @@ namespace datalog {
}
rule_set * res = alloc(rule_set, m_context);
if (!transform_rules(source, *res)) {
if (transform_rules(source, *res)) {
res->inherit_predicates(source);
} else {
dealloc(res);
res = 0;
}

View file

@ -34,15 +34,17 @@ namespace datalog {
{
ast_manager& m;
context& m_context;
substitution m_subst;
unifier m_unif;
rule * m_rule;
substitution m_subst;
unifier m_unif;
app_ref m_head;
app_ref_vector m_tail;
svector<bool> m_neg;
rule * m_rule;
void apply(app * a, app_ref& res);
public:
rule_substitution(context & ctx)
: m(ctx.get_manager()), m_context(ctx), m_subst(m), m_unif(m), m_rule(0) {}
: m(ctx.get_manager()), m_context(ctx), m_subst(m), m_unif(m), m_head(m), m_tail(m), m_rule(0) {}
/**
Reset substitution and get it ready for working with rule r.
@ -61,13 +63,23 @@ namespace datalog {
}
};
class normalizer_cfg;
class normalizer_rw;
ast_manager & m;
context & m_context;
th_rewriter & m_simp;
arith_util a;
rule_substitution m_rule_subst;
ptr_vector<expr> m_todo;
obj_hashtable<expr> m_leqs;
app_ref_vector m_tail;
expr_ref_vector m_itail_members;
expr_ref_vector m_conj;
svector<bool> m_tail_neg;
normalizer_cfg* m_cfg;
normalizer_rw* m_rw;
class normalizer_cfg;
void simplify_expr(app * a, expr_ref& res);
@ -77,13 +89,8 @@ namespace datalog {
/** Return true if something was modified */
bool transform_rules(const rule_set & orig, rule_set & tgt);
public:
mk_interp_tail_simplifier(context & ctx, unsigned priority=40000)
: plugin(priority),
m(ctx.get_manager()),
m_context(ctx),
m_simp(ctx.get_rewriter()),
a(m),
m_rule_subst(ctx) {}
mk_interp_tail_simplifier(context & ctx, unsigned priority=40000);
virtual ~mk_interp_tail_simplifier();
/**If rule should be retained, assign transformed version to res and return true;
if rule can be deleted, return false.

View file

@ -35,6 +35,9 @@ Revision History:
#include"dl_mk_karr_invariants.h"
#include"expr_safe_replace.h"
#include"bool_rewriter.h"
#include"dl_mk_backwards.h"
#include"dl_mk_loop_counter.h"
#include "for_each_expr.h"
namespace datalog {
@ -45,7 +48,8 @@ namespace datalog {
m(ctx.get_manager()),
rm(ctx.get_rule_manager()),
m_inner_ctx(m, ctx.get_fparams()),
a(m) {
a(m),
m_pinned(m) {
params_ref params;
params.set_sym("default_relation", symbol("karr_relation"));
params.set_sym("engine", symbol("datalog"));
@ -199,48 +203,90 @@ namespace datalog {
return 0;
}
}
mk_loop_counter lc(m_ctx);
mk_backwards bwd(m_ctx);
scoped_ptr<rule_set> src_loop = lc(source);
TRACE("dl", src_loop->display(tout << "source loop\n"););
get_invariants(*src_loop);
// figure out whether to update same rules as used for saturation.
scoped_ptr<rule_set> rev_source = bwd(*src_loop);
get_invariants(*rev_source);
scoped_ptr<rule_set> src_annot = update_rules(*src_loop);
rule_set* rules = lc.revert(*src_annot);
rules->inherit_predicates(source);
TRACE("dl", rules->display(tout););
m_pinned.reset();
m_fun2inv.reset();
return rules;
}
void mk_karr_invariants::get_invariants(rule_set const& src) {
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(src);
m_inner_ctx.close();
rule_set::decl2rules::iterator dit = source.begin_grouped_rules();
rule_set::decl2rules::iterator dend = source.end_grouped_rules();
rule_set::decl2rules::iterator dit = src.begin_grouped_rules();
rule_set::decl2rules::iterator dend = src.end_grouped_rules();
for (; dit != dend; ++dit) {
heads.push_back(dit->m_key);
}
m_inner_ctx.rel_query(heads.size(), heads.c_ptr());
rule_set* rules = alloc(rule_set, m_ctx);
it = source.begin();
// retrieve invariants.
dit = src.begin_grouped_rules();
for (; dit != dend; ++dit) {
func_decl* p = dit->m_key;
relation_base* rb = rctx.try_get_relation(p);
if (rb) {
expr_ref fml(m);
rb->to_formula(fml);
if (m.is_true(fml)) {
continue;
}
expr* inv = 0;
if (m_fun2inv.find(p, inv)) {
fml = m.mk_and(inv, fml);
}
m_pinned.push_back(fml);
m_fun2inv.insert(p, fml);
}
}
}
rule_set* mk_karr_invariants::update_rules(rule_set const& src) {
scoped_ptr<rule_set> dst = alloc(rule_set, m_ctx);
rule_set::iterator it = src.begin(), end = src.end();
for (; it != end; ++it) {
update_body(rctx, *rules, **it);
update_body(*dst, **it);
}
if (m_ctx.get_model_converter()) {
add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m);
rule_set::decl2rules::iterator git = source.begin_grouped_rules();
rule_set::decl2rules::iterator gend = source.end_grouped_rules();
rule_set::decl2rules::iterator git = src.begin_grouped_rules();
rule_set::decl2rules::iterator gend = src.end_grouped_rules();
for (; git != gend; ++git) {
func_decl* p = git->m_key;
expr_ref fml(m);
relation_base* rb = rctx.try_get_relation(p);
if (rb) {
rb->to_formula(fml);
expr* fml = 0;
if (m_fun2inv.find(p, fml)) {
kmc->add(p, fml);
}
}
m_ctx.add_model_converter(kmc);
}
TRACE("dl", rules->display(tout););
return rules;
dst->inherit_predicates(src);
return dst.detach();
}
void mk_karr_invariants::update_body(rel_context& rctx, rule_set& rules, rule& r) {
void mk_karr_invariants::update_body(rule_set& rules, rule& r) {
unsigned utsz = r.get_uninterpreted_tail_size();
unsigned tsz = r.get_tail_size();
app_ref_vector tail(m);
@ -250,16 +296,16 @@ namespace datalog {
}
for (unsigned i = 0; i < utsz; ++i) {
func_decl* q = r.get_decl(i);
relation_base* rb = rctx.try_get_relation(r.get_decl(i));
if (rb) {
rb->to_formula(fml);
expr* fml = 0;
if (m_fun2inv.find(q, fml)) {
expr_safe_replace rep(m);
for (unsigned j = 0; j < q->get_arity(); ++j) {
rep.insert(m.mk_var(j, q->get_domain(j)),
r.get_tail(i)->get_arg(j));
}
rep(fml);
tail.push_back(to_app(fml));
expr_ref tmp(fml, m);
rep(tmp);
tail.push_back(to_app(tmp));
}
}
rule* new_rule = &r;
@ -937,11 +983,8 @@ namespace datalog {
class karr_relation_plugin::union_fn : public relation_union_fn {
karr_relation_plugin& m_plugin;
public:
union_fn(karr_relation_plugin& p) :
m_plugin(p) {
}
union_fn() {}
virtual void operator()(relation_base & _r, const relation_base & _src, relation_base * _delta) {
@ -965,7 +1008,7 @@ namespace datalog {
if (!check_kind(tgt) || !check_kind(src) || (delta && !check_kind(*delta))) {
return 0;
}
return alloc(union_fn, *this);
return alloc(union_fn);
}
class karr_relation_plugin::filter_identical_fn : public relation_mutator_fn {
@ -1006,16 +1049,17 @@ namespace datalog {
class karr_relation_plugin::filter_equal_fn : public relation_mutator_fn {
unsigned m_col;
rational m_value;
bool m_valid;
public:
filter_equal_fn(relation_manager & m, const relation_element & value, unsigned col)
: m_col(col) {
arith_util arith(m.get_context().get_manager());
VERIFY(arith.is_numeral(value, m_value));
m_valid = arith.is_numeral(value, m_value) && m_value.is_int();
}
virtual void operator()(relation_base & _r) {
karr_relation & r = get(_r);
if (m_value.is_int()) {
if (m_valid) {
r.get_ineqs();
vector<rational> row;
row.resize(r.get_signature().size());
@ -1031,7 +1075,7 @@ namespace datalog {
relation_mutator_fn * karr_relation_plugin::mk_filter_equal_fn(const relation_base & r,
const relation_element & value, unsigned col) {
if(check_kind(r)) {
if (check_kind(r)) {
return alloc(filter_equal_fn, get_manager(), value, col);
}
return 0;

View file

@ -55,8 +55,13 @@ namespace datalog {
rule_manager& rm;
context m_inner_ctx;
arith_util a;
void update_body(rel_context& rctx, rule_set& result, rule& r);
obj_map<func_decl, expr*> m_fun2inv;
ast_ref_vector m_pinned;
void get_invariants(rule_set const& src);
void update_body(rule_set& result, rule& r);
rule_set* update_rules(rule_set const& src);
public:
mk_karr_invariants(context & ctx, unsigned priority);
@ -89,12 +94,7 @@ namespace datalog {
{}
virtual bool can_handle_signature(const relation_signature & sig) {
for (unsigned i = 0; i < sig.size(); ++i) {
if (a.is_int(sig[i])) {
return true;
}
}
return false;
return true;
}
static symbol get_name() { return symbol("karr_relation"); }

View file

@ -25,13 +25,14 @@ 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) {
}
mk_loop_counter::~mk_loop_counter() { }
app_ref mk_loop_counter::add_arg(app* fn, unsigned idx) {
app_ref mk_loop_counter::add_arg(rule_set const& src, rule_set& dst, app* fn, unsigned idx) {
expr_ref_vector args(m);
func_decl* new_fn, *old_fn = fn->get_decl();
args.append(fn->get_num_args(), fn->get_args());
@ -45,17 +46,29 @@ namespace datalog {
m_old2new.insert(old_fn, new_fn);
m_new2old.insert(new_fn, old_fn);
m_refs.push_back(new_fn);
m_ctx.register_predicate(new_fn, false);
if (src.is_output_predicate(old_fn)) {
dst.set_output_predicate(new_fn);
}
}
return app_ref(m.mk_app(new_fn, args.size(), args.c_ptr()), m);
}
app_ref mk_loop_counter::del_arg(app* fn) {
expr_ref_vector args(m);
func_decl* old_fn, *new_fn = fn->get_decl();
SASSERT(fn->get_num_args() > 0);
args.append(fn->get_num_args()-1, fn->get_args());
VERIFY (m_new2old.find(new_fn, old_fn));
return app_ref(m.mk_app(old_fn, args.size(), args.c_ptr()), m);
}
rule_set * mk_loop_counter::operator()(rule_set const & source) {
m_refs.reset();
m_old2new.reset();
m_new2old.reset();
context& ctx = source.get_context();
rule_manager& rm = source.get_rule_manager();
rule_set * result = alloc(rule_set, ctx);
rule_set * result = alloc(rule_set, m_ctx);
unsigned sz = source.get_num_rules();
rule_ref new_rule(rm);
app_ref_vector tail(m);
@ -70,16 +83,14 @@ namespace datalog {
unsigned utsz = r.get_uninterpreted_tail_size();
unsigned tsz = r.get_tail_size();
for (unsigned j = 0; j < utsz; ++j, ++cnt) {
tail.push_back(add_arg(r.get_tail(j), cnt));
tail.push_back(add_arg(source, *result, r.get_tail(j), cnt));
neg.push_back(r.is_neg_tail(j));
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);
head = add_arg(source, *result, r.get_head(), cnt);
// set the loop counter to be an increment of the previous
bool found = false;
unsigned last = head->get_num_args()-1;
@ -110,4 +121,38 @@ namespace datalog {
return result;
}
rule_set * mk_loop_counter::revert(rule_set const & source) {
context& ctx = source.get_context();
rule_manager& rm = source.get_rule_manager();
rule_set * result = alloc(rule_set, ctx);
unsigned sz = source.get_num_rules();
rule_ref new_rule(rm);
app_ref_vector tail(m);
app_ref head(m);
svector<bool> neg;
for (unsigned i = 0; i < sz; ++i) {
tail.reset();
neg.reset();
rule & r = *source.get_rule(i);
unsigned utsz = r.get_uninterpreted_tail_size();
unsigned tsz = r.get_tail_size();
for (unsigned j = 0; j < utsz; ++j) {
tail.push_back(del_arg(r.get_tail(j)));
neg.push_back(r.is_neg_tail(j));
}
for (unsigned j = utsz; j < tsz; ++j) {
tail.push_back(r.get_tail(j));
neg.push_back(false);
}
head = del_arg(r.get_head());
new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true);
result->add_rule(new_rule);
}
// model converter: ...
// proof converter: ...
return result;
}
};

View file

@ -26,12 +26,14 @@ 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;
obj_map<func_decl, func_decl*> m_old2new;
app_ref add_arg(app* fn, unsigned idx);
app_ref add_arg(rule_set const& src, rule_set& dst, app* fn, unsigned idx);
app_ref del_arg(app* fn);
public:
mk_loop_counter(context & ctx, unsigned priority = 33000);
~mk_loop_counter();
@ -39,6 +41,8 @@ namespace datalog {
rule_set * operator()(rule_set const & source);
func_decl* get_old(func_decl* f) const { return m_new2old.find(f); }
rule_set * revert(rule_set const& source);
};
};

View file

@ -24,13 +24,13 @@ 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()),
rm(ctx.get_rule_manager()),
m_pinned(m),
m_goal(goal, m) {
}
void mk_magic_sets::reset() {
@ -39,14 +39,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 +56,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 +65,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 +80,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 +100,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 +126,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 +141,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 +179,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 +193,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 +220,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 +232,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 +255,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);
bound_vars |= rm.collect_vars(curr);
}
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,43 +281,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) {
SASSERT(!m_context.get_model_converter());
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 {
@ -337,9 +334,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
@ -347,48 +344,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

@ -47,6 +47,11 @@ namespace datalog {
AD_BOUND
};
struct a_flag_hash {
typedef a_flag data;
unsigned operator()(a_flag x) const { return x; }
};
struct adornment : public svector<a_flag> {
void populate(app * lit, const var_idx_set & bound_vars);
@ -71,7 +76,7 @@ namespace datalog {
return m_pred==o.m_pred && m_adornment==o.m_adornment;
}
unsigned hash() const {
return m_pred->hash()^int_vector_hash(m_adornment);
return m_pred->hash()^svector_hash<a_flag_hash>()(m_adornment);
}
};
@ -88,21 +93,21 @@ 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;
rule_manager& rm;
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 +115,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);
}
}
@ -505,9 +505,6 @@ namespace datalog {
unsigned head_arity = head_pred->get_arity();
//var_idx_set head_vars;
//var_idx_set same_strat_vars;
//collect_vars(m, r->get_head(), head_vars);
unsigned pt_len = r->get_positive_tail_size();
for (unsigned ti=0; ti<pt_len; ++ti) {
@ -518,7 +515,6 @@ namespace datalog {
SASSERT(pred_strat<=head_strat);
if (pred_strat==head_strat) {
//collect_vars(m, r->get_head(), same_strat_vars);
if (pred->get_arity()>head_arity
|| (pred->get_arity()==head_arity && pred->get_id()>=head_pred->get_id()) ) {
return false;
@ -667,7 +663,7 @@ namespace datalog {
return et->get_data().m_value;
}
void mk_rule_inliner::add_rule(rule* r, unsigned i) {
void mk_rule_inliner::add_rule(rule_set const& source, rule* r, unsigned i) {
svector<bool>& can_remove = m_head_visitor.can_remove();
svector<bool>& can_expand = m_head_visitor.can_expand();
app* head = r->get_head();
@ -676,7 +672,7 @@ namespace datalog {
m_head_index.insert(head);
m_pinned.push_back(r);
if (m_context.is_output_predicate(headd) ||
if (source.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 +688,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));
&& !source.is_output_predicate(r->get_decl(0));
can_expand.set(i, can_exp);
}
@ -710,7 +706,6 @@ namespace datalog {
#define PRT(_x_) ((_x_)?"T":"F")
bool mk_rule_inliner::inline_linear(scoped_ptr<rule_set>& rules) {
scoped_ptr<rule_set> res = alloc(rule_set, m_context);
bool done_something = false;
unsigned sz = rules->get_num_rules();
@ -731,7 +726,7 @@ namespace datalog {
svector<bool>& can_expand = m_head_visitor.can_expand();
for (unsigned i = 0; i < sz; ++i) {
add_rule(acc[i].get(), i);
add_rule(*rules, acc[i].get(), i);
}
// initialize substitution.
@ -808,7 +803,7 @@ namespace datalog {
TRACE("dl", r->display(m_context, tout); r2->display(m_context, tout); rl_res->display(m_context, tout); );
del_rule(r, i);
add_rule(rl_res.get(), i);
add_rule(*rules, rl_res.get(), i);
r = rl_res;
@ -828,13 +823,15 @@ namespace datalog {
}
}
if (done_something) {
rules = alloc(rule_set, m_context);
scoped_ptr<rule_set> res = alloc(rule_set, m_context);
for (unsigned i = 0; i < sz; ++i) {
if (valid.get(i)) {
rules->add_rule(acc[i].get());
res->add_rule(acc[i].get());
}
}
TRACE("dl", rules->display(tout););
res->inherit_predicates(*rules);
TRACE("dl", res->display(tout););
rules = res.detach();
}
return done_something;
}
@ -874,6 +871,12 @@ namespace datalog {
}
TRACE("dl", res->display(tout << "after eager inlining\n"););
}
if (something_done) {
res->inherit_predicates(source);
}
else {
res = alloc(rule_set, source);
}
if (m_context.get_params().inline_linear() && inline_linear(res)) {
something_done = true;

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);
@ -174,7 +174,7 @@ namespace datalog {
*/
bool inline_linear(scoped_ptr<rule_set>& rules);
void add_rule(rule* r, unsigned i);
void add_rule(rule_set const& rule_set, rule* r, unsigned i);
void del_rule(rule* r, unsigned i);
public:

View file

@ -23,14 +23,15 @@ 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_modified(false),
m_pinned(m_manager) {
SASSERT(m_threshold_count>1);
}
void mk_similarity_compressor::reset() {
@ -43,10 +44,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);
}
@ -55,19 +56,25 @@ namespace datalog {
return (a>b) ? 1 : ( (a==b) ? 0 : -1);
}
template<typename T>
static int aux_compare(T* a, T* b);
static int compare_var_args(app* t1, app* t2) {
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 +84,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; }
res = aux_compare(t1->get_arg(i)->get_id(), t2->get_arg(i)->get_id());
if (res!=0) { return res; }
}
return 0;
}
@ -100,26 +107,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; }
res = aux_compare(t1->get_decl()->get_id(), t2->get_decl()->get_id());
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++) {
res = aux_compare(r1->get_tail(i), r2->get_tail(i));
if(res!=0) { return res; }
for (unsigned i=pos_tail_sz; i<tail_sz; i++) {
res = aux_compare(r1->get_tail(i)->get_id(), r2->get_tail(i)->get_id());
if (res!=0) { return res; }
}
return 0;
@ -132,9 +139,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 +174,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 +185,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 +194,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 +208,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 +231,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 +270,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 +294,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 +312,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 +320,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 +355,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 +364,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 +374,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 +382,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 +394,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++;
@ -426,7 +433,7 @@ namespace datalog {
m_modified = true;
}
void mk_similarity_compressor::process_class(rule_vector::iterator first,
void mk_similarity_compressor::process_class(rule_set const& source, rule_vector::iterator first,
rule_vector::iterator after_last) {
SASSERT(first!=after_last);
//remove duplicates
@ -435,7 +442,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 +457,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 +468,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 +491,9 @@ namespace datalog {
//TODO: compress also rules with pairs (or tuples) of equal constants
#if 1
if(const_cnt>0) {
if (const_cnt>0 && !source.is_output_predicate((*first)->get_decl())) {
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 +502,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 +512,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 +524,20 @@ namespace datalog {
while(it!=end) {
rule_vector::iterator prev = it;
++it;
if(it==end || rough_compare(*prev, *it)!=0) {
process_class(cl_begin, it);
if (it==end || rough_compare(*prev, *it)!=0) {
process_class(source, 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

@ -63,11 +63,11 @@ namespace datalog {
ast_ref_vector m_pinned;
void merge_class(rule_vector::iterator first, rule_vector::iterator after_last);
void process_class(rule_vector::iterator first, rule_vector::iterator after_last);
void process_class(rule_set const& source, rule_vector::iterator first, rule_vector::iterator after_last);
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

@ -29,7 +29,8 @@ namespace datalog {
mk_simple_joins::mk_simple_joins(context & ctx):
plugin(1000),
m_context(ctx) {
m_context(ctx),
rm(ctx.get_rule_manager()) {
}
class join_planner {
@ -89,7 +90,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;
@ -120,6 +121,7 @@ namespace datalog {
context & m_context;
ast_manager & m;
rule_manager & rm;
var_subst & m_var_subst;
rule_set & m_rs_aux_copy; //reference to a rule_set that will allow to ask for stratum levels
@ -130,10 +132,13 @@ namespace datalog {
ptr_hashtable<rule, ptr_hash<rule>, ptr_eq<rule> > m_modified_rules;
ast_ref_vector m_pinned;
mutable ptr_vector<sort> m_vars;
public:
join_planner(context & ctx, rule_set & rs_aux_copy)
: m_context(ctx), m(ctx.get_manager()), m_var_subst(ctx.get_var_subst()),
: m_context(ctx), m(ctx.get_manager()),
rm(ctx.get_rule_manager()),
m_var_subst(ctx.get_var_subst()),
m_rs_aux_copy(rs_aux_copy),
m_introduced_rules(ctx.get_rule_manager()),
m_pinned(ctx.get_manager())
@ -175,9 +180,7 @@ namespace datalog {
unsigned max_var_idx = 0;
{
var_idx_set orig_var_set;
collect_vars(m, t1, orig_var_set);
collect_vars(m, t2, orig_var_set);
var_idx_set& orig_var_set = rm.collect_vars(t1, t2);
var_idx_set::iterator ovit = orig_var_set.begin();
var_idx_set::iterator ovend = orig_var_set.end();
for(; ovit!=ovend; ++ovit) {
@ -323,14 +326,13 @@ namespace datalog {
}
for(unsigned i=0; i<pos_tail_size; i++) {
app * t1 = r->get_tail(i);
var_idx_set t1_vars;
collect_vars(m, t1, t1_vars);
var_idx_set t1_vars = rm.collect_vars(t1);
counter.count_vars(m, t1, -1); //temporarily remove t1 variables from counter
for(unsigned j=i+1; j<pos_tail_size; j++) {
app * t2 = r->get_tail(j);
counter.count_vars(m, t2, -1); //temporarily remove t2 variables from counter
var_idx_set scope_vars(t1_vars);
collect_vars(m, t2, scope_vars);
var_idx_set scope_vars = rm.collect_vars(t2);
scope_vars |= t1_vars;
var_idx_set non_local_vars;
counter.collect_positive(non_local_vars);
counter.count_vars(m, t2, 1); //restore t2 variables in counter
@ -383,7 +385,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) {
@ -472,8 +474,7 @@ namespace datalog {
while(!added_tails.empty()) {
app * a_tail = added_tails.back(); //added tail
var_idx_set a_tail_vars;
collect_vars(m, a_tail, a_tail_vars);
var_idx_set a_tail_vars = rm.collect_vars(a_tail);
counter.count_vars(m, a_tail, -1); //temporarily remove a_tail variables from counter
for(unsigned i=0; i<len; i++) {
@ -484,8 +485,8 @@ namespace datalog {
}
counter.count_vars(m, o_tail, -1); //temporarily remove o_tail variables from counter
var_idx_set scope_vars(a_tail_vars);
collect_vars(m, o_tail, scope_vars);
var_idx_set scope_vars = rm.collect_vars(o_tail);
scope_vars |= a_tail_vars;
var_idx_set non_local_vars;
counter.collect_positive(non_local_vars);
counter.count_vars(m, o_tail, 1); //restore o_tail variables in counter
@ -714,13 +715,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

@ -49,7 +49,8 @@ namespace datalog {
We say that a rule containing C_i's is a rule with a "big tail".
*/
class mk_simple_joins : public rule_transformer::plugin {
context & m_context;
context & m_context;
rule_manager & rm;
public:
mk_simple_joins(context & ctx);

View file

@ -120,12 +120,11 @@ namespace datalog {
obj_map<rule, rule*>::iterator end = m_rule2slice.end();
expr_ref fml(m);
for (; it != end; ++it) {
TRACE("dl",
it->m_key->display(m_ctx, tout << "orig:\n");
it->m_value->display(m_ctx, tout << "new:\n"););
it->m_value->to_formula(fml);
m_pinned_exprs.push_back(fml);
TRACE("dl",
tout << "orig: " << mk_pp(fml, m) << "\n";
it->m_value->display(m_ctx, tout << "new:\n"););
m_sliceform2rule.insert(fml, it->m_key);
}
}
@ -202,9 +201,10 @@ namespace datalog {
proof* p0_new = m_new_proof.find(p0);
expr* fact0 = m.get_fact(p0);
TRACE("dl", tout << "fact0: " << mk_pp(fact0, m) << "\n";);
rule* orig0 = m_sliceform2rule.find(fact0);
/* rule* slice0 = */ m_rule2slice.find(orig0);
/* unsigned_vector const& renaming0 = m_renaming.find(orig0); */
rule* orig0;
if (!m_sliceform2rule.find(fact0, orig0)) {
return false;
}
premises.push_back(p0_new);
rule_ref r1(rm), r2(rm), r3(rm);
r1 = orig0;
@ -214,9 +214,10 @@ namespace datalog {
proof* p1_new = m_new_proof.find(p1);
expr* fact1 = m.get_fact(p1);
TRACE("dl", tout << "fact1: " << mk_pp(fact1, m) << "\n";);
rule* orig1 = m_sliceform2rule.find(fact1);
/* rule* slice1 = */ m_rule2slice.find(orig1);
/* unsigned_vector const& renaming1 = m_renaming.find(orig1); TBD */
rule* orig1 = 0;
if (!m_sliceform2rule.find(fact1, orig1)) {
return false;
}
premises.push_back(p1_new);
// TODO: work with substitutions.
@ -241,6 +242,9 @@ namespace datalog {
proof* new_p = m.mk_hyper_resolve(premises.size(), premises.c_ptr(), concl, positions, substs);
m_pinned_exprs.push_back(new_p);
m_pinned_rules.push_back(r1.get());
TRACE("dl",
tout << "orig: " << mk_pp(slice_concl, m) << "\n";
r1->display(m_ctx, tout << "new:"););
m_sliceform2rule.insert(slice_concl, r1.get());
m_rule2slice.insert(r1.get(), 0);
m_renaming.insert(r1.get(), unsigned_vector());
@ -703,9 +707,10 @@ 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;
bool has_output = false;
func_decl* f;
for (; it != end; ++it) {
domain.reset();
@ -720,10 +725,19 @@ 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);
}
}
else if (src.is_output_predicate(p)) {
dst.set_output_predicate(p);
has_output = true;
}
}
// disable slicing if the output predicates don't occur in rules.
if (!has_output) {
m_predicates.reset();
}
}
@ -820,13 +834,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;
@ -244,30 +241,30 @@ namespace datalog {
tgt.add_rule(new_rule);
subs_index.add(new_rule);
}
tgt.inherit_predicates(orig);
TRACE("dl",
tout << "original set size: "<<orig.get_num_rules()<<"\n"
<< "reduced set size: "<<tgt.get_num_rules()<<"\n"; );
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 +304,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; }
@ -324,9 +321,7 @@ namespace datalog {
if(!m_ground_unconditional_rule_heads.contains(pred)) {
m_ground_unconditional_rule_heads.insert(pred, alloc(obj_hashtable<app>));
}
obj_hashtable<app> * head_store;
m_ground_unconditional_rule_heads.find(pred, head_store);
head_store->insert(head);
m_ground_unconditional_rule_heads.find(pred)->insert(head);
next_rule:;
}
@ -337,14 +332,14 @@ 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;
rule_set * res = alloc(rule_set, m_context);
bool modified = transform_rules(source, *res);
if(!m_have_new_total_rule && !modified) {
if (!m_have_new_total_rule && !modified) {
dealloc(res);
return 0;
}
@ -353,7 +348,7 @@ namespace datalog {
//During the construction of the new set we may discover new total relations
//(by quantifier elimination on the uninterpreted tails).
SASSERT(m_new_total_relation_discovery_during_transformation || !m_have_new_total_rule);
while(m_have_new_total_rule) {
while (m_have_new_total_rule) {
m_have_new_total_rule = false;
rule_set * old = 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,10 @@ namespace datalog {
mk_unbound_compressor::mk_unbound_compressor(context & ctx) :
plugin(500),
m_context(ctx),
m_manager(ctx.get_manager()),
m_rules(ctx.get_rule_manager()),
m_pinned(m_manager) {
m(ctx.get_manager()),
rm(ctx.get_rule_manager()),
m_rules(rm),
m_pinned(m) {
}
void mk_unbound_compressor::reset() {
@ -47,10 +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);
return tail_vars.contains(var_idx);
return rm.collect_tail_vars(r).contains(var_idx);
}
void mk_unbound_compressor::add_task(func_decl * pred, unsigned arg_index) {
@ -81,22 +79,21 @@ 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);
var_idx_set& tail_vars = rm.collect_tail_vars(r);
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;
}
unsigned n = head_pred->get_arity();
var_counter head_var_counter;
head_var_counter.count_vars(m_manager, head, 1);
rm.get_counter().reset();
rm.get_counter().count_vars(m, head, 1);
for (unsigned i=0; i<n; i++) {
expr * arg = head->get_arg(i);
@ -107,7 +104,7 @@ namespace datalog {
if (!tail_vars.contains(var_idx)) {
//unbound
unsigned occurence_cnt = head_var_counter.get(var_idx);
unsigned occurence_cnt = rm.get_counter().get(var_idx);
SASSERT(occurence_cnt>0);
if (occurence_cnt == 1) {
TRACE("dl", r->display(m_context, tout << "Compress: "););
@ -118,18 +115,17 @@ 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);
var_idx_set& tail_vars = rm.collect_tail_vars(r);
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);
rm.get_counter().reset();
rm.get_counter().count_vars(m, head);
unsigned arg_index;
for (arg_index = 0; arg_index < head_arity; arg_index++) {
@ -140,7 +136,7 @@ namespace datalog {
unsigned var_idx = to_var(arg)->get_idx();
if (!tail_vars.contains(var_idx)) {
//unbound
unsigned occurence_cnt = head_var_counter.get(var_idx);
unsigned occurence_cnt = rm.get_counter().get(var_idx);
SASSERT(occurence_cnt>0);
if ( occurence_cnt==1 && m_in_progress.contains(c_info(head_pred, arg_index)) ) {
//we have found what to compress
@ -163,13 +159,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 +177,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 +201,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 +228,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 +254,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 +265,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 +302,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 +341,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 +356,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 +371,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,9 @@ 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_manager & rm;
rule_ref_vector m_rules;
bool m_modified;
todo_stack m_todo;
@ -71,13 +72,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

@ -269,7 +269,7 @@ namespace datalog {
unsigned_vector r1_tables_indexes;
unsigned_vector r2_tables_indexes;
for (unsigned i = 0; i < num_rels1; ++i) {
if(is_tableish_relation(*r1[i])) {
if (is_tableish_relation(*r1[i])) {
r1_tables_indexes.push_back(i);
continue;
}
@ -291,7 +291,7 @@ namespace datalog {
if (!found) {
relation_plugin & r1_plugin = get_nonsieve_plugin(*r1[i]);
relation_base* rel2;
if(r1_plugin.can_handle_signature(r2_sig)) {
if (r1_plugin.can_handle_signature(r2_sig)) {
rel2 = r1_plugin.mk_full(p, r2_sig, r1_kind);
}
else {
@ -307,7 +307,7 @@ namespace datalog {
}
}
for (unsigned i = 0; i < num_rels2; ++i) {
if(is_tableish_relation(*r2[i])) {
if (is_tableish_relation(*r2[i])) {
r2_tables_indexes.push_back(i);
continue;
}
@ -315,7 +315,7 @@ namespace datalog {
relation_plugin & r2_plugin = get_nonsieve_plugin(*r2[i]);
family_id r2_kind = get_nonsieve_kind(*r2[i]);
relation_base* rel1;
if(r2_plugin.can_handle_signature(r1_sig)) {
if (r2_plugin.can_handle_signature(r1_sig)) {
rel1 = r2_plugin.mk_full(p, r1_sig, r2_kind);
}
else {
@ -331,7 +331,7 @@ namespace datalog {
}
}
if(!r1_tables_indexes.empty() && !r2_tables_indexes.empty()) {
if (!r1_tables_indexes.empty() && !r2_tables_indexes.empty()) {
//We may perhaps want to group the table relations by kinds so that tables of the same kind
//get joined...

View file

@ -40,8 +40,12 @@ namespace datalog {
class filter_equal_fn;
class filter_identical_fn;
class filter_interpreted_fn;
struct fid_hash {
typedef family_id data;
unsigned operator()(data x) const { return static_cast<unsigned>(x); }
};
rel_spec_store<rel_spec> m_spec_store;
rel_spec_store<rel_spec, svector_hash<fid_hash> > m_spec_store;
family_id get_relation_kind(const product_relation & r);

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) {
@ -728,6 +720,13 @@ namespace datalog {
return t.get_plugin().mk_filter_interpreted_fn(t, condition);
}
relation_transformer_fn * relation_manager::mk_filter_interpreted_and_project_fn(const relation_base & t,
app * condition,
unsigned removed_col_cnt,
const unsigned * removed_cols) {
return t.get_plugin().mk_filter_interpreted_and_project_fn(t, condition, removed_col_cnt, removed_cols);
}
class relation_manager::default_relation_select_equal_and_project_fn : public relation_transformer_fn {
scoped_ptr<relation_mutator_fn> m_filter;
@ -748,7 +747,6 @@ namespace datalog {
relation_transformer_fn * relation_manager::mk_select_equal_and_project_fn(const relation_base & t,
const relation_element & value, unsigned col) {
relation_transformer_fn * res = t.get_plugin().mk_select_equal_and_project_fn(t, value, col);
TRACE("dl", tout << t.get_plugin().get_name() << " " << value << " " << col << "\n";);
if(!res) {
relation_mutator_fn * selector = mk_filter_equal_fn(t, value, col);
if(selector) {
@ -1098,12 +1096,10 @@ namespace datalog {
class relation_manager::default_table_rename_fn
: public convenient_table_rename_fn, auxiliary_table_transformer_fn {
const unsigned m_cycle_len;
public:
default_table_rename_fn(const table_signature & orig_sig, unsigned permutation_cycle_len,
const unsigned * permutation_cycle)
: convenient_table_rename_fn(orig_sig, permutation_cycle_len, permutation_cycle),
m_cycle_len(permutation_cycle_len) {
: convenient_table_rename_fn(orig_sig, permutation_cycle_len, permutation_cycle) {
SASSERT(permutation_cycle_len>=2);
}
@ -1398,6 +1394,45 @@ namespace datalog {
}
class relation_manager::default_table_filter_interpreted_and_project_fn
: public table_transformer_fn {
scoped_ptr<table_mutator_fn> m_filter;
scoped_ptr<table_transformer_fn> m_project;
app_ref m_condition;
unsigned_vector m_removed_cols;
public:
default_table_filter_interpreted_and_project_fn(context & ctx, table_mutator_fn * filter,
app * condition, unsigned removed_col_cnt, const unsigned * removed_cols)
: m_filter(filter), m_condition(condition, ctx.get_manager()),
m_removed_cols(removed_col_cnt, removed_cols) {}
virtual table_base* operator()(const table_base & tb) {
table_base *t2 = tb.clone();
(*m_filter)(*t2);
if (!m_project) {
relation_manager & rmgr = t2->get_plugin().get_manager();
m_project = rmgr.mk_project_fn(*t2, m_removed_cols.size(), m_removed_cols.c_ptr());
if (!m_project) {
throw default_exception("projection does not exist");
}
}
return (*m_project)(*t2);
}
};
table_transformer_fn * relation_manager::mk_filter_interpreted_and_project_fn(const table_base & t,
app * condition, unsigned removed_col_cnt, const unsigned * removed_cols) {
table_transformer_fn * res = t.get_plugin().mk_filter_interpreted_and_project_fn(t, condition, removed_col_cnt, removed_cols);
if (res)
return res;
table_mutator_fn * filter = mk_filter_interpreted_fn(t, condition);
SASSERT(filter);
res = alloc(default_table_filter_interpreted_and_project_fn, get_context(), filter, condition, removed_col_cnt, removed_cols);
return res;
}
table_intersection_filter_fn * relation_manager::mk_filter_by_intersection_fn(const table_base & t,
const table_base & src, unsigned joined_col_cnt, const unsigned * t_cols, const unsigned * src_cols) {
table_intersection_filter_fn * res = t.get_plugin().mk_filter_by_negation_fn(t, src, joined_col_cnt,

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;
@ -56,6 +55,7 @@ namespace datalog {
class default_table_filter_equal_fn;
class default_table_filter_identical_fn;
class default_table_filter_interpreted_fn;
class default_table_filter_interpreted_and_project_fn;
class default_table_negation_filter_fn;
class default_table_filter_not_equal_fn;
class default_table_select_equal_and_project_fn;
@ -153,7 +153,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);
@ -352,6 +351,9 @@ namespace datalog {
relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition);
relation_transformer_fn * mk_filter_interpreted_and_project_fn(const relation_base & t, app * condition,
unsigned removed_col_cnt, const unsigned * removed_cols);
/**
\brief Operations that returns all rows of \c t for which is column \c col equal to \c value
with the column \c col removed.
@ -524,6 +526,9 @@ namespace datalog {
table_mutator_fn * mk_filter_interpreted_fn(const table_base & t, app * condition);
table_transformer_fn * mk_filter_interpreted_and_project_fn(const table_base & t, app * condition,
unsigned removed_col_cnt, const unsigned * removed_cols);
/**
\brief Operations that returns all rows of \c t for which is column \c col equal to \c value
with the column \c col removed.
@ -595,7 +600,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,
@ -607,7 +612,7 @@ namespace datalog {
/**
This is a helper class for relation_plugins whose relations can be of various kinds.
*/
template<class Spec, class Hash=int_vector_hash_proc<Spec>, class Eq=vector_eq_proc<Spec> >
template<class Spec, class Hash, class Eq=vector_eq_proc<Spec> >
class rel_spec_store {
typedef relation_signature::hash r_hash;
typedef relation_signature::eq r_eq;
@ -663,17 +668,15 @@ namespace datalog {
SASSERT(res_idx<m_allocated_kinds.size());
ids.insert(spec, res_idx);
family_id2spec * idspecs;
VERIFY( m_kind_specs.find(sig, idspecs) );
family_id2spec * idspecs = m_kind_specs.find(sig);
idspecs->insert(m_allocated_kinds[res_idx], spec);
}
return m_allocated_kinds[res_idx];
}
void get_relation_spec(const relation_signature & sig, family_id kind, Spec & spec) {
family_id2spec * idspecs;
VERIFY( m_kind_specs.find(sig, idspecs) );
VERIFY( idspecs->find(kind, spec) );
family_id2spec * idspecs = m_kind_specs.find(sig);
spec = idspecs->find(kind);
}
};

Some files were not shown because too many files have changed in this diff Show more