mirror of
https://github.com/Z3Prover/z3
synced 2025-04-27 02:45:51 +00:00
Merge branch 'unstable' into contrib
This commit is contained in:
commit
d2a2dbb4b6
230 changed files with 9263 additions and 13830 deletions
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
src/api/dotnet/Properties/AssemblyInfo.cs text eol=crlf
|
|
@ -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) {
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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) {
|
||||
|
@ -1680,6 +1711,30 @@ namespace z3 {
|
|||
d.check_error();
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -399,4 +399,4 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
This directory contains scripts to build the test application using
|
||||
OCaml. You also need CamlIDL to be able to generate the OCaml API.
|
||||
|
||||
- To download OCaml:
|
||||
http://caml.inria.fr/ocaml/
|
||||
|
||||
- To download CamlIDL:
|
||||
http://forge.ocamlcore.org/projects/camlidl/
|
||||
|
||||
- One must build the OCaml library before compiling the example.
|
||||
Go to directory ../ocaml
|
||||
|
||||
- Use 'build-test.cmd' to build the test application using the OCaml compiler.
|
||||
|
||||
Remark: The OCaml and C compiler tool chains must be configured in your environment.
|
||||
Running from the Visual Studio Command Prompt configures the Microsoft C compiler.
|
||||
|
||||
- The script 'exec.cmd' adds the bin directory to the path. So,
|
||||
test_mlapi.exe can find z3.dll.
|
||||
|
||||
|
||||
|
||||
|
||||
This directory contains scripts to build the test application using
|
||||
OCaml. You also need CamlIDL to be able to generate the OCaml API.
|
||||
|
||||
- To download OCaml:
|
||||
http://caml.inria.fr/ocaml/
|
||||
|
||||
- To download CamlIDL:
|
||||
http://forge.ocamlcore.org/projects/camlidl/
|
||||
|
||||
- One must build the OCaml library before compiling the example.
|
||||
Go to directory ../ocaml
|
||||
|
||||
- Use 'build-test.cmd' to build the test application using the OCaml compiler.
|
||||
|
||||
Remark: The OCaml and C compiler tool chains must be configured in your environment.
|
||||
Running from the Visual Studio Command Prompt configures the Microsoft C compiler.
|
||||
|
||||
- The script 'exec.cmd' adds the bin directory to the path. So,
|
||||
test_mlapi.exe can find z3.dll.
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
The OCaml API for Z3 was tested using OCaml 3.12.1.
|
||||
You also need CamlIDL to be able to generate the OCaml API.
|
||||
|
||||
- To download OCaml:
|
||||
http://caml.inria.fr/ocaml/
|
||||
|
||||
- To download CamlIDL:
|
||||
http://forge.ocamlcore.org/projects/camlidl/
|
||||
|
||||
- To build the OCaml API for Z3:
|
||||
.\build-lib.cmd
|
||||
|
||||
Remark: The OCaml and C compiler tool chains must be configured in your environment.
|
||||
Running from the Visual Studio Command Prompt configures the Microsoft C compiler.
|
||||
|
||||
Remark: Building the OCaml API copies some pathnames into files,
|
||||
so the OCaml API must be recompiled if the Z3 library files are moved.
|
||||
|
||||
See ..\examples\ocaml\build-test.cmd for an example of how to compile and link with Z3.
|
||||
|
||||
Acknowledgements:
|
||||
The OCaml interface for Z3 was written by Josh Berdine and Jakob Lichtenberg.
|
||||
Many thanks to them!
|
||||
The OCaml API for Z3 was tested using OCaml 3.12.1.
|
||||
You also need CamlIDL to be able to generate the OCaml API.
|
||||
|
||||
- To download OCaml:
|
||||
http://caml.inria.fr/ocaml/
|
||||
|
||||
- To download CamlIDL:
|
||||
http://forge.ocamlcore.org/projects/camlidl/
|
||||
|
||||
- To build the OCaml API for Z3:
|
||||
.\build-lib.cmd
|
||||
|
||||
Remark: The OCaml and C compiler tool chains must be configured in your environment.
|
||||
Running from the Visual Studio Command Prompt configures the Microsoft C compiler.
|
||||
|
||||
Remark: Building the OCaml API copies some pathnames into files,
|
||||
so the OCaml API must be recompiled if the Z3 library files are moved.
|
||||
|
||||
See ..\examples\ocaml\build-test.cmd for an example of how to compile and link with Z3.
|
||||
|
||||
Acknowledgements:
|
||||
The OCaml interface for Z3 was written by Josh Berdine and Jakob Lichtenberg.
|
||||
Many thanks to them!
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
@echo off
|
||||
|
||||
call .\compile_mlapi.cmd ..\include ..\bin ..\bin
|
||||
@echo off
|
||||
|
||||
call .\compile_mlapi.cmd ..\include ..\bin ..\bin
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
@echo off
|
||||
|
||||
if not exist ..\..\ocaml\z3.cmxa (
|
||||
echo "YOU MUST BUILD OCAML API! Go to directory ..\ocaml"
|
||||
goto :EOF
|
||||
)
|
||||
|
||||
REM ocaml (>= 3.11) calls the linker through flexlink
|
||||
ocamlc -version >> ocaml_version
|
||||
set /p OCAML_VERSION= <ocaml_version
|
||||
if %OCAML_VERSION% GEQ 3.11 (
|
||||
set XCFLAGS=
|
||||
) else (
|
||||
set XCFLAGS=/nologo /MT /DWIN32
|
||||
)
|
||||
|
||||
ocamlc -w A -ccopt "%XCFLAGS%" -o test_mlapi_byte.exe -I ..\..\ocaml z3.cma test_mlapi.ml
|
||||
|
||||
ocamlopt -w A -ccopt "%XCFLAGS%" -o test_mlapi.exe -I ..\..\ocaml z3.cmxa test_mlapi.ml
|
||||
@echo off
|
||||
|
||||
if not exist ..\..\ocaml\z3.cmxa (
|
||||
echo "YOU MUST BUILD OCAML API! Go to directory ..\ocaml"
|
||||
goto :EOF
|
||||
)
|
||||
|
||||
REM ocaml (>= 3.11) calls the linker through flexlink
|
||||
ocamlc -version >> ocaml_version
|
||||
set /p OCAML_VERSION= <ocaml_version
|
||||
if %OCAML_VERSION% GEQ 3.11 (
|
||||
set XCFLAGS=
|
||||
) else (
|
||||
set XCFLAGS=/nologo /MT /DWIN32
|
||||
)
|
||||
|
||||
ocamlc -w A -ccopt "%XCFLAGS%" -o test_mlapi_byte.exe -I ..\..\ocaml z3.cma test_mlapi.ml
|
||||
|
||||
ocamlopt -w A -ccopt "%XCFLAGS%" -o test_mlapi.exe -I ..\..\ocaml z3.cmxa test_mlapi.ml
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
@echo off
|
||||
SETLOCAL
|
||||
set PATH=..\..\bin;%PATH%
|
||||
test_mlapi.exe
|
||||
ENDLOCAL
|
||||
@echo off
|
||||
SETLOCAL
|
||||
set PATH=..\..\bin;%PATH%
|
||||
test_mlapi.exe
|
||||
ENDLOCAL
|
||||
|
|
|
@ -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`.
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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); }
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,9 +637,13 @@ namespace datalog {
|
|||
|
||||
app* dl_decl_util::mk_numeral(uint64 value, sort* s) {
|
||||
if (is_finite_sort(s)) {
|
||||
uint64 sz = 0;
|
||||
if (try_get_size(s, sz) && sz <= value) {
|
||||
m.raise_exception("value is out of bounds");
|
||||
}
|
||||
parameter params[2] = { parameter(rational(value, rational::ui64())), parameter(s) };
|
||||
return m.mk_const(m.mk_func_decl(m_fid, OP_DL_CONSTANT, 2, params, 0, (sort*const*)0));
|
||||
}
|
||||
}
|
||||
if (m_arith.is_int(s) || m_arith.is_real(s)) {
|
||||
return m_arith.mk_numeral(rational(value, rational::ui64()), s);
|
||||
}
|
||||
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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();
|
||||
|
||||
/**
|
||||
|
|
|
@ -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))))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -169,7 +169,9 @@ 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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -145,7 +143,12 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
|
|||
num_no_patterns,
|
||||
new_no_patterns.c_ptr());
|
||||
to_quantifier(result)->set_no_unused_vars();
|
||||
SASSERT(is_well_sorted(m, 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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
Command context provides the infrastructure for executing commands in front-ends such as SMT-LIB 2.0.
|
||||
It is also provides the solver abstraction to plugin solvers in this kind of front-end.
|
||||
It is also provides the solver abstraction to plugin solvers in this kind of front-end.
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
Basic Euclidean solver for linear integer equations.
|
||||
This solver generates "explanations".
|
||||
This solver generates "explanations".
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
Template for interval arithmetic. The template can be instantiated using different numeral (integers/mpz, rationals/mpq, floating-point/mpf, etc) packages.
|
||||
The class im_default_config defines a default configuration for the template that uses rationals. It also shows what is the expected signature used by the template.
|
||||
The class im_default_config defines a default configuration for the template that uses rationals. It also shows what is the expected signature used by the template.
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
Polynomial manipulation package.
|
||||
It contains support for univariate (upolynomial.*) and multivariate polynomials (polynomial.*).
|
||||
Multivariate polynomial factorization does not work yet (polynomial_factorization.*), and it is disabled.
|
||||
Multivariate polynomial factorization does not work yet (polynomial_factorization.*), and it is disabled.
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
328
src/muz_qe/aig_exporter.cpp
Executable 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
68
src/muz_qe/aig_exporter.h
Executable 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
235
src/muz_qe/clp_context.cpp
Normal 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
45
src/muz_qe/clp_context.h
Normal 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
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
expr_ref bg_assertion = m_ctx.get_background_assertion();
|
||||
|
||||
m_ctx.set_output_predicate(m_query_pred);
|
||||
datalog::rule_set old_rules(m_ctx.get_rules());
|
||||
rule_manager.mk_query(query, m_ctx.get_rules());
|
||||
expr_ref bg_assertion = m_ctx.get_background_assertion();
|
||||
m_ctx.apply_default_transformation();
|
||||
|
||||
if (m_ctx.get_params().slice()) {
|
||||
|
@ -1436,10 +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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,18 +623,130 @@ 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);
|
||||
m_context.get_rewriter()(t, simplified);
|
||||
|
@ -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;
|
||||
|
@ -804,13 +960,13 @@ namespace datalog {
|
|||
ast_mark m_visited;
|
||||
|
||||
void traverse(T v) {
|
||||
SASSERT(!m_stack_content.is_marked(v));
|
||||
if(m_visited.is_marked(v) || m_removed.contains(v)) {
|
||||
SASSERT(!m_stack_content.is_marked(v));
|
||||
if(m_visited.is_marked(v) || m_removed.contains(v)) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_stack.push_back(v);
|
||||
m_stack_content.mark(v, true);
|
||||
m_stack_content.mark(v, true);
|
||||
m_visited.mark(v, true);
|
||||
|
||||
const item_set & deps = m_deps.get_deps(v);
|
||||
|
@ -818,7 +974,7 @@ namespace datalog {
|
|||
item_set::iterator end = deps.end();
|
||||
for(; it!=end; ++it) {
|
||||
T d = *it;
|
||||
if(m_stack_content.is_marked(d)) {
|
||||
if(m_stack_content.is_marked(d)) {
|
||||
//TODO: find the best vertex to remove in the cycle
|
||||
m_removed.insert(v);
|
||||
break;
|
||||
|
@ -828,8 +984,9 @@ namespace datalog {
|
|||
SASSERT(m_stack.back()==v);
|
||||
|
||||
m_stack.pop_back();
|
||||
m_stack_content.mark(v, false);
|
||||
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++) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,21 +821,32 @@ 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
|
||||
|
@ -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,11 +1005,14 @@ 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;
|
||||
engine_type_proc proc(m);
|
||||
m_engine = DATALOG_ENGINE;
|
||||
m_engine = DATALOG_ENGINE;
|
||||
for (unsigned i = 0; m_engine == DATALOG_ENGINE && i < m_rule_set.get_num_rules(); ++i) {
|
||||
rule * r = m_rule_set.get_rule(i);
|
||||
quick_for_each_expr(proc, mark, r->get_head());
|
||||
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
78
src/muz_qe/dl_mk_backwards.cpp
Normal file
78
src/muz_qe/dl_mk_backwards.cpp
Normal 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;
|
||||
}
|
||||
|
||||
};
|
38
src/muz_qe/dl_mk_backwards.h
Normal file
38
src/muz_qe/dl_mk_backwards.h
Normal 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_ */
|
||||
|
|
@ -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,27 +259,34 @@ namespace datalog {
|
|||
rule_manager& rm = m_context.get_rule_manager();
|
||||
unsigned sz = source.get_num_rules();
|
||||
expr_ref fml(m);
|
||||
reset();
|
||||
rule_set * result = alloc(rule_set, m_context);
|
||||
rule_set * result = alloc(rule_set, m_context);
|
||||
m_rewriter.m_cfg.set_src(&source);
|
||||
m_rewriter.m_cfg.set_dst(result);
|
||||
for (unsigned i = 0; !m_context.canceled() && i < sz; ++i) {
|
||||
rule * r = source.get_rule(i);
|
||||
r->to_formula(fml);
|
||||
r->to_formula(fml);
|
||||
if (blast(r, fml)) {
|
||||
proof_ref pr(m);
|
||||
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()) {
|
||||
filter_model_converter* fmc = alloc(filter_model_converter, m);
|
||||
bit_blast_model_converter* bvmc = alloc(bit_blast_model_converter, m);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
@ -249,17 +295,17 @@ namespace datalog {
|
|||
tail.push_back(r.get_tail(i));
|
||||
}
|
||||
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);
|
||||
func_decl* q = r.get_decl(i);
|
||||
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;
|
||||
|
|
|
@ -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"); }
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
@ -871,8 +868,14 @@ namespace datalog {
|
|||
// try eager inlining
|
||||
if (do_eager_inlining(res)) {
|
||||
something_done = true;
|
||||
}
|
||||
}
|
||||
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)) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -23,16 +23,17 @@ 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() {
|
||||
m_rules.reset();
|
||||
m_result_rules.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;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue