mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 04:03:39 +00:00
Merge branch 'unstable' of https://git01.codeplex.com/z3 into unstable
This commit is contained in:
commit
7cad0b4a1f
|
@ -58,6 +58,7 @@ void substitution::pop_scope(unsigned num_scopes) {
|
||||||
}
|
}
|
||||||
m_vars.shrink(old_sz);
|
m_vars.shrink(old_sz);
|
||||||
m_scopes.shrink(new_lvl);
|
m_scopes.shrink(new_lvl);
|
||||||
|
m_apply_cache.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void substitution::apply_visit(expr_offset const & n, bool & visited) {
|
inline void substitution::apply_visit(expr_offset const & n, bool & visited) {
|
||||||
|
|
|
@ -36,6 +36,7 @@ Revision History:
|
||||||
#include "for_each_expr.h"
|
#include "for_each_expr.h"
|
||||||
#include "expr_safe_replace.h"
|
#include "expr_safe_replace.h"
|
||||||
#include "cooperate.h"
|
#include "cooperate.h"
|
||||||
|
#include "datatype_decl_plugin.h"
|
||||||
|
|
||||||
class is_variable_proc {
|
class is_variable_proc {
|
||||||
public:
|
public:
|
||||||
|
@ -80,6 +81,7 @@ namespace eq {
|
||||||
class der {
|
class der {
|
||||||
ast_manager & m;
|
ast_manager & m;
|
||||||
arith_util a;
|
arith_util a;
|
||||||
|
datatype_util dt;
|
||||||
is_variable_proc* m_is_variable;
|
is_variable_proc* m_is_variable;
|
||||||
var_subst m_subst;
|
var_subst m_subst;
|
||||||
expr_ref_vector m_new_exprs;
|
expr_ref_vector m_new_exprs;
|
||||||
|
@ -215,14 +217,15 @@ namespace eq {
|
||||||
(not T) is used because this formula is equivalent to (not (iff (VAR 2) (not T))),
|
(not T) is used because this formula is equivalent to (not (iff (VAR 2) (not T))),
|
||||||
and can be viewed as a disequality.
|
and can be viewed as a disequality.
|
||||||
*/
|
*/
|
||||||
bool is_var_diseq(expr * e, var * & v, expr_ref & t) {
|
bool is_var_diseq(expr * e, ptr_vector<var>& vs, expr_ref_vector& ts) {
|
||||||
expr* e1;
|
expr* e1;
|
||||||
if (m.is_not(e, e1)) {
|
if (m.is_not(e, e1)) {
|
||||||
return is_var_eq(e, v, t);
|
return is_var_eq(e, vs, ts);
|
||||||
}
|
}
|
||||||
else if (is_var_eq(e, v, t) && m.is_bool(v)) {
|
else if (is_var_eq(e, vs, ts) && vs.size() == 1 && m.is_bool(vs[0])) {
|
||||||
bool_rewriter(m).mk_not(t, t);
|
expr_ref tmp(m);
|
||||||
m_new_exprs.push_back(t);
|
bool_rewriter(m).mk_not(ts[0].get(), tmp);
|
||||||
|
ts[0] = tmp;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -230,11 +233,11 @@ namespace eq {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool solve_arith_core(app * lhs, expr * rhs, expr * eq, var* & var, expr_ref & def) {
|
bool solve_arith_core(app * lhs, expr * rhs, expr * eq, ptr_vector<var>& vs, expr_ref_vector& ts) {
|
||||||
SASSERT(a.is_add(lhs));
|
SASSERT(a.is_add(lhs));
|
||||||
bool is_int = a.is_int(lhs);
|
bool is_int = a.is_int(lhs);
|
||||||
expr * a1;
|
expr * a1, *v;
|
||||||
expr * v;
|
expr_ref def(m);
|
||||||
rational a_val;
|
rational a_val;
|
||||||
unsigned num = lhs->get_num_args();
|
unsigned num = lhs->get_num_args();
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
@ -255,7 +258,7 @@ namespace eq {
|
||||||
}
|
}
|
||||||
if (i == num)
|
if (i == num)
|
||||||
return false;
|
return false;
|
||||||
var = to_var(v);
|
vs.push_back(to_var(v));
|
||||||
expr_ref inv_a(m);
|
expr_ref inv_a(m);
|
||||||
if (!a_val.is_one()) {
|
if (!a_val.is_one()) {
|
||||||
inv_a = a.mk_numeral(rational(1)/a_val, is_int);
|
inv_a = a.mk_numeral(rational(1)/a_val, is_int);
|
||||||
|
@ -282,35 +285,48 @@ namespace eq {
|
||||||
def = a.mk_sub(rhs, a.mk_add(other_args.size(), other_args.c_ptr()));
|
def = a.mk_sub(rhs, a.mk_add(other_args.size(), other_args.c_ptr()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_new_exprs.push_back(def);
|
ts.push_back(def);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool arith_solve(expr * lhs, expr * rhs, expr * eq, var* & var, expr_ref & t) {
|
bool arith_solve(expr * lhs, expr * rhs, expr * eq, ptr_vector<var>& vs, expr_ref_vector& ts) {
|
||||||
return
|
return
|
||||||
(a.is_add(lhs) && solve_arith_core(to_app(lhs), rhs, eq, var, t)) ||
|
(a.is_add(lhs) && solve_arith_core(to_app(lhs), rhs, eq, vs, ts)) ||
|
||||||
(a.is_add(rhs) && solve_arith_core(to_app(rhs), lhs, eq, var, t));
|
(a.is_add(rhs) && solve_arith_core(to_app(rhs), lhs, eq, vs, ts));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool trival_solve(expr* lhs, expr* rhs, expr* eq, var* & v, expr_ref& t) {
|
bool trivial_solve(expr* lhs, expr* rhs, expr* eq, ptr_vector<var>& vs, expr_ref_vector& ts) {
|
||||||
if (!is_variable(lhs)) {
|
if (!is_variable(lhs)) {
|
||||||
std::swap(lhs, rhs);
|
std::swap(lhs, rhs);
|
||||||
}
|
}
|
||||||
if (!is_variable(lhs)) {
|
if (!is_variable(lhs)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
v = to_var(lhs);
|
vs.push_back(to_var(lhs));
|
||||||
t = rhs;
|
ts.push_back(rhs);
|
||||||
TRACE("der", tout << mk_pp(eq, m) << "\n";);
|
TRACE("qe_lite", tout << mk_pp(eq, m) << "\n";);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool same_vars(ptr_vector<var> const& vs1, ptr_vector<var> const& vs2) const {
|
||||||
|
if (vs1.size() != vs2.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < vs1.size(); ++i) {
|
||||||
|
if (vs1[i] != vs2[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Return true if e can be viewed as a variable equality.
|
\brief Return true if e can be viewed as a variable equality.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool is_var_eq(expr * e, var * & v, expr_ref & t) {
|
bool is_var_eq(expr * e, ptr_vector<var>& vs, expr_ref_vector & ts) {
|
||||||
expr* lhs, *rhs;
|
expr* lhs, *rhs;
|
||||||
|
|
||||||
// (= VAR t), (iff VAR t), (iff (not VAR) t), (iff t (not VAR)) cases
|
// (= VAR t), (iff VAR t), (iff (not VAR) t), (iff t (not VAR)) cases
|
||||||
|
@ -323,16 +339,15 @@ namespace eq {
|
||||||
if (!is_neg_var(m, lhs)) {
|
if (!is_neg_var(m, lhs)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
v = to_var(lhs);
|
vs.push_back(to_var(lhs));
|
||||||
t = m.mk_not(rhs);
|
ts.push_back(m.mk_not(rhs));
|
||||||
m_new_exprs.push_back(t);
|
TRACE("qe_lite", tout << mk_pp(e, m) << "\n";);
|
||||||
TRACE("der", tout << mk_pp(e, m) << "\n";);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (trival_solve(lhs, rhs, e, v, t)) {
|
if (trivial_solve(lhs, rhs, e, vs, ts)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (arith_solve(lhs, rhs, e, v, t)) {
|
if (arith_solve(lhs, rhs, e, vs, ts)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -341,12 +356,13 @@ namespace eq {
|
||||||
// (ite cond (= VAR t) (= VAR t2)) case
|
// (ite cond (= VAR t) (= VAR t2)) case
|
||||||
expr* cond, *e2, *e3;
|
expr* cond, *e2, *e3;
|
||||||
if (m.is_ite(e, cond, e2, e3)) {
|
if (m.is_ite(e, cond, e2, e3)) {
|
||||||
if (is_var_eq(e2, v, t)) {
|
if (is_var_eq(e2, vs, ts)) {
|
||||||
expr_ref t2(m);
|
expr_ref_vector ts2(m);
|
||||||
var* v2;
|
ptr_vector<var> vs2;
|
||||||
if (is_var_eq(e3, v2, t2) && v2 == v) {
|
if (is_var_eq(e3, vs2, ts2) && same_vars(vs, vs2)) {
|
||||||
t = m.mk_ite(cond, t, t2);
|
for (unsigned i = 0; i < vs.size(); ++i) {
|
||||||
m_new_exprs.push_back(t);
|
ts[i] = m.mk_ite(cond, ts[i].get(), ts2[i].get());
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -355,17 +371,17 @@ namespace eq {
|
||||||
|
|
||||||
// VAR = true case
|
// VAR = true case
|
||||||
if (is_variable(e)) {
|
if (is_variable(e)) {
|
||||||
t = m.mk_true();
|
ts.push_back(m.mk_true());
|
||||||
v = to_var(e);
|
vs.push_back(to_var(e));
|
||||||
TRACE("der", tout << mk_pp(e, m) << "\n";);
|
TRACE("qe_lite", tout << mk_pp(e, m) << "\n";);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// VAR = false case
|
// VAR = false case
|
||||||
if (is_neg_var(m, e)) {
|
if (is_neg_var(m, e)) {
|
||||||
t = m.mk_false();
|
ts.push_back(m.mk_false());
|
||||||
v = to_var(to_app(e)->get_arg(0));
|
vs.push_back(to_var(to_app(e)->get_arg(0)));
|
||||||
TRACE("der", tout << mk_pp(e, m) << "\n";);
|
TRACE("qe_lite", tout << mk_pp(e, m) << "\n";);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,12 +389,12 @@ namespace eq {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_var_def(bool check_eq, expr* e, var*& v, expr_ref& t) {
|
bool is_var_def(bool check_eq, expr* e, ptr_vector<var>& vs, expr_ref_vector& ts) {
|
||||||
if (check_eq) {
|
if (check_eq) {
|
||||||
return is_var_eq(e, v, t);
|
return is_var_eq(e, vs, ts);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return is_var_diseq(e, v, t);
|
return is_var_diseq(e, vs, ts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,7 +409,7 @@ namespace eq {
|
||||||
|
|
||||||
der_sort_vars(m_inx2var, m_map, m_order);
|
der_sort_vars(m_inx2var, m_map, m_order);
|
||||||
|
|
||||||
TRACE("der",
|
TRACE("qe_lite",
|
||||||
tout << "Elimination m_order:" << std::endl;
|
tout << "Elimination m_order:" << std::endl;
|
||||||
for(unsigned i=0; i<m_order.size(); i++)
|
for(unsigned i=0; i<m_order.size(); i++)
|
||||||
{
|
{
|
||||||
|
@ -520,8 +536,6 @@ namespace eq {
|
||||||
}
|
}
|
||||||
|
|
||||||
void find_definitions(unsigned num_args, expr* const* args, bool is_exists, unsigned& def_count, unsigned& largest_vinx) {
|
void find_definitions(unsigned num_args, expr* const* args, bool is_exists, unsigned& def_count, unsigned& largest_vinx) {
|
||||||
var * v = 0;
|
|
||||||
expr_ref t(m);
|
|
||||||
def_count = 0;
|
def_count = 0;
|
||||||
largest_vinx = 0;
|
largest_vinx = 0;
|
||||||
m_map.reset();
|
m_map.reset();
|
||||||
|
@ -532,24 +546,102 @@ namespace eq {
|
||||||
// Find all definitions
|
// Find all definitions
|
||||||
for (unsigned i = 0; i < num_args; i++) {
|
for (unsigned i = 0; i < num_args; i++) {
|
||||||
checkpoint();
|
checkpoint();
|
||||||
if (is_var_def(is_exists, args[i], v, t)) {
|
ptr_vector<var> vs;
|
||||||
unsigned idx = v->get_idx();
|
expr_ref_vector ts(m);
|
||||||
if(m_map.get(idx, 0) == 0) {
|
if (is_var_def(is_exists, args[i], vs, ts)) {
|
||||||
m_map.reserve(idx + 1, 0);
|
for (unsigned j = 0; j < vs.size(); ++j) {
|
||||||
m_inx2var.reserve(idx + 1, 0);
|
var* v = vs[j];
|
||||||
m_map[idx] = t;
|
expr* t = ts[j].get();
|
||||||
m_inx2var[idx] = v;
|
unsigned idx = v->get_idx();
|
||||||
m_pos2var[i] = idx;
|
if (m_map.get(idx, 0) == 0) {
|
||||||
def_count++;
|
m_map.reserve(idx + 1, 0);
|
||||||
largest_vinx = std::max(idx, largest_vinx);
|
m_inx2var.reserve(idx + 1, 0);
|
||||||
|
m_map[idx] = t;
|
||||||
|
m_inx2var[idx] = v;
|
||||||
|
m_pos2var[i] = idx;
|
||||||
|
def_count++;
|
||||||
|
largest_vinx = std::max(idx, largest_vinx);
|
||||||
|
m_new_exprs.push_back(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void flatten_definitions(expr_ref_vector& conjs) {
|
||||||
|
TRACE("qe_lite",
|
||||||
|
expr_ref tmp(m);
|
||||||
|
tmp = m.mk_and(conjs.size(), conjs.c_ptr());
|
||||||
|
tout << mk_pp(tmp, m) << "\n";);
|
||||||
|
for (unsigned i = 0; i < conjs.size(); ++i) {
|
||||||
|
expr* c = conjs[i].get();
|
||||||
|
expr* l, *r;
|
||||||
|
if (m.is_false(c)) {
|
||||||
|
conjs[0] = c;
|
||||||
|
conjs.resize(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (is_ground(c)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!m.is_eq(c, l, r)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!is_app(l) || !is_app(r)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (dt.is_constructor(to_app(l)->get_decl())) {
|
||||||
|
flatten_constructor(to_app(l), to_app(r), conjs);
|
||||||
|
conjs[i] = conjs.back();
|
||||||
|
conjs.pop_back();
|
||||||
|
--i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (dt.is_constructor(to_app(r)->get_decl())) {
|
||||||
|
flatten_constructor(to_app(r), to_app(l), conjs);
|
||||||
|
conjs[i] = conjs.back();
|
||||||
|
conjs.pop_back();
|
||||||
|
--i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TRACE("qe_lite",
|
||||||
|
expr_ref tmp(m);
|
||||||
|
tmp = m.mk_and(conjs.size(), conjs.c_ptr());
|
||||||
|
tout << "after flatten\n" << mk_pp(tmp, m) << "\n";);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flatten_constructor(app* c, app* r, expr_ref_vector& conjs) {
|
||||||
|
SASSERT(dt.is_constructor(c));
|
||||||
|
|
||||||
|
func_decl* d = c->get_decl();
|
||||||
|
|
||||||
|
if (dt.is_constructor(r->get_decl())) {
|
||||||
|
app* b = to_app(r);
|
||||||
|
if (d == b->get_decl()) {
|
||||||
|
for (unsigned j = 0; j < c->get_num_args(); ++j) {
|
||||||
|
conjs.push_back(m.mk_eq(c->get_arg(j), b->get_arg(j)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
conjs.push_back(m.mk_false());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
func_decl* rec = dt.get_constructor_recognizer(d);
|
||||||
|
conjs.push_back(m.mk_app(rec, r));
|
||||||
|
ptr_vector<func_decl> const& acc = *dt.get_constructor_accessors(d);
|
||||||
|
for (unsigned i = 0; i < acc.size(); ++i) {
|
||||||
|
conjs.push_back(m.mk_eq(c->get_arg(i), m.mk_app(acc[i], r)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool reduce_var_set(expr_ref_vector& conjs) {
|
bool reduce_var_set(expr_ref_vector& conjs) {
|
||||||
unsigned def_count = 0;
|
unsigned def_count = 0;
|
||||||
unsigned largest_vinx = 0;
|
unsigned largest_vinx = 0;
|
||||||
|
|
||||||
|
flatten_definitions(conjs);
|
||||||
|
|
||||||
find_definitions(conjs.size(), conjs.c_ptr(), true, def_count, largest_vinx);
|
find_definitions(conjs.size(), conjs.c_ptr(), true, def_count, largest_vinx);
|
||||||
|
|
||||||
|
@ -578,12 +670,22 @@ namespace eq {
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
der(ast_manager & m): m(m), a(m), m_is_variable(0), m_subst(m), m_new_exprs(m), m_subst_map(m), m_new_args(m), m_rewriter(m), m_cancel(false) {}
|
der(ast_manager & m):
|
||||||
|
m(m),
|
||||||
|
a(m),
|
||||||
|
dt(m),
|
||||||
|
m_is_variable(0),
|
||||||
|
m_subst(m),
|
||||||
|
m_new_exprs(m),
|
||||||
|
m_subst_map(m),
|
||||||
|
m_new_args(m),
|
||||||
|
m_rewriter(m),
|
||||||
|
m_cancel(false) {}
|
||||||
|
|
||||||
void set_is_variable_proc(is_variable_proc& proc) { m_is_variable = &proc;}
|
void set_is_variable_proc(is_variable_proc& proc) { m_is_variable = &proc;}
|
||||||
|
|
||||||
void operator()(quantifier * q, expr_ref & r, proof_ref & pr) {
|
void operator()(quantifier * q, expr_ref & r, proof_ref & pr) {
|
||||||
TRACE("der", tout << mk_pp(q, m) << "\n";);
|
TRACE("qe_lite", tout << mk_pp(q, m) << "\n";);
|
||||||
pr = 0;
|
pr = 0;
|
||||||
r = q;
|
r = q;
|
||||||
reduce_quantifier(q, r, pr);
|
reduce_quantifier(q, r, pr);
|
||||||
|
|
|
@ -23,93 +23,324 @@ Revision History:
|
||||||
#include "dl_context.h"
|
#include "dl_context.h"
|
||||||
#include "dl_mk_rule_inliner.h"
|
#include "dl_mk_rule_inliner.h"
|
||||||
#include "smt_kernel.h"
|
#include "smt_kernel.h"
|
||||||
#include "matcher.h"
|
|
||||||
#include "qe_lite.h"
|
#include "qe_lite.h"
|
||||||
#include "bool_rewriter.h"
|
#include "bool_rewriter.h"
|
||||||
|
#include "th_rewriter.h"
|
||||||
|
#include "datatype_decl_plugin.h"
|
||||||
|
|
||||||
namespace datalog {
|
namespace tb {
|
||||||
|
|
||||||
#if 0
|
|
||||||
// semantic matcher.
|
// semantic matcher.
|
||||||
class tab_matcher {
|
class matcher {
|
||||||
typedef std::pair<expr *, expr *> expr_pair;
|
typedef std::pair<expr *, expr *> expr_pair;
|
||||||
|
ast_manager& m;
|
||||||
svector<expr_pair> m_todo;
|
svector<expr_pair> m_todo;
|
||||||
|
datatype_util m_dt;
|
||||||
|
|
||||||
|
lbool is_eq(expr* _s, expr* _t) {
|
||||||
|
if (_s == _t) {
|
||||||
|
return l_true;
|
||||||
|
}
|
||||||
|
if (!is_app(_s) || !is_app(_t)) {
|
||||||
|
return l_undef;
|
||||||
|
}
|
||||||
|
app* s = to_app(_s);
|
||||||
|
app* t = to_app(_t);
|
||||||
|
|
||||||
|
if (m.is_value(s) && m.is_value(t)) {
|
||||||
|
IF_VERBOSE(2, verbose_stream() << "different:" << mk_pp(s, m) << " " << mk_pp(t, m) << "\n";);
|
||||||
|
return l_false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_dt.is_constructor(s) && m_dt.is_constructor(t)) {
|
||||||
|
if (s->get_decl() == t->get_decl()) {
|
||||||
|
lbool state = l_true;
|
||||||
|
for (unsigned i = 0; i < s->get_num_args(); ++i) {
|
||||||
|
// move is_eq: decompose arguments to constraints.
|
||||||
|
switch (is_eq(s->get_arg(i), t->get_arg(i))) {
|
||||||
|
case l_undef:
|
||||||
|
state = l_undef;
|
||||||
|
break;
|
||||||
|
case l_false:
|
||||||
|
return l_false;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
IF_VERBOSE(2, verbose_stream() << "different constructors:" << mk_pp(s, m) << " " << mk_pp(t, m) << "\n";);
|
||||||
|
return l_false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return l_undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool match_var(var* v, app* t, substitution& s, expr_ref_vector& conds) {
|
||||||
|
expr_offset r;
|
||||||
|
if (s.find(v, 0, r)) {
|
||||||
|
app* p = to_app(r.get_expr());
|
||||||
|
switch (is_eq(p, t)) {
|
||||||
|
case l_true:
|
||||||
|
break;
|
||||||
|
case l_false:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
conds.push_back(m.mk_eq(p, t));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s.insert(v, 0, expr_offset(t, 1));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool match_app(app* p, app* t, substitution& s, expr_ref_vector& conds) {
|
||||||
|
if (p->get_decl() == t->get_decl() &&
|
||||||
|
p->get_num_args() == t->get_num_args()) {
|
||||||
|
for (unsigned i = 0; i < p->get_num_args(); ++i) {
|
||||||
|
m_todo.push_back(expr_pair(p->get_arg(i), t->get_arg(i)));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch(is_eq(p, t)) {
|
||||||
|
case l_true:
|
||||||
|
return true;
|
||||||
|
case l_false:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
conds.push_back(m.mk_eq(p, t));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
matcher(ast_manager& m): m(m) {}
|
matcher(ast_manager& m): m(m), m_dt(m) {}
|
||||||
|
|
||||||
bool operator()(expr* pat, expr* term, substitution& s, expr_ref_vector& side_conds) {
|
bool operator()(expr* pat, expr* term, substitution& s, expr_ref_vector& conds) {
|
||||||
m_todo.reset();
|
m_todo.reset();
|
||||||
m_todo.push_back(expr_pair(pat, term));
|
m_todo.push_back(expr_pair(pat, term));
|
||||||
while (!m_todo.empty()) {
|
while (!m_todo.empty()) {
|
||||||
expr_pair const& p = m_todo.back();
|
expr_pair const& p = m_todo.back();
|
||||||
pat = p.first;
|
pat = p.first;
|
||||||
term = p.second;
|
term = p.second;
|
||||||
if (is_var(pat)) {
|
m_todo.pop_back();
|
||||||
|
if (!is_app(term)) {
|
||||||
|
IF_VERBOSE(2, verbose_stream() << "term is not app\n";);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (is_var(pat) && match_var(to_var(pat), to_app(term), s, conds)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (!is_app(pat)) {
|
||||||
|
IF_VERBOSE(2, verbose_stream() << "pattern is not app\n";);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (!match_app(to_app(pat), to_app(term), s, conds)) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
class goal {
|
||||||
|
th_rewriter m_rw;
|
||||||
|
datalog::rule_ref m_goal;
|
||||||
|
app_ref m_head;
|
||||||
|
app_ref_vector m_predicates;
|
||||||
|
expr_ref m_constraint;
|
||||||
|
unsigned m_index;
|
||||||
|
unsigned m_num_vars;
|
||||||
|
unsigned m_predicate_index;
|
||||||
|
unsigned m_rule_index;
|
||||||
|
unsigned m_ref;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
goal(datalog::rule_manager& rm):
|
||||||
|
m_rw(rm.get_manager()),
|
||||||
|
m_goal(rm),
|
||||||
|
m_head(rm.get_manager()),
|
||||||
|
m_predicates(rm.get_manager()),
|
||||||
|
m_constraint(rm.get_manager()),
|
||||||
|
m_index(0),
|
||||||
|
m_num_vars(0),
|
||||||
|
m_predicate_index(0),
|
||||||
|
m_rule_index(0),
|
||||||
|
m_ref(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_rule_index(unsigned i) { m_rule_index = i; }
|
||||||
|
unsigned get_rule_index() const { return m_rule_index; }
|
||||||
|
void inc_rule_index() { m_rule_index++; }
|
||||||
|
unsigned get_predicate_index() const { return m_predicate_index; }
|
||||||
|
void set_predicate_index(unsigned i) { m_predicate_index = i; }
|
||||||
|
unsigned get_num_predicates() const { return m_predicates.size(); }
|
||||||
|
app* get_predicate(unsigned i) const { return m_predicates[i]; }
|
||||||
|
expr* get_constraint() const { return m_constraint; }
|
||||||
|
datalog::rule const& get_rule() const { return *m_goal; }
|
||||||
|
unsigned get_num_vars() const { return m_num_vars; }
|
||||||
|
unsigned get_index() const { return m_index; }
|
||||||
|
app* get_head() const { return m_head; }
|
||||||
|
|
||||||
|
void init(datalog::rule_ref& g) {
|
||||||
|
m_goal = g;
|
||||||
|
m_index = 0;
|
||||||
|
m_predicate_index = 0;
|
||||||
|
m_rule_index = 0;
|
||||||
|
m_num_vars = 1 + g.get_manager().get_var_counter().get_max_var(*g);
|
||||||
|
init();
|
||||||
|
|
||||||
|
// IF_VERBOSE(1, display(verbose_stream()););
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_index(unsigned index) {
|
||||||
|
m_index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void inc_ref() {
|
||||||
|
m_ref++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dec_ref() {
|
||||||
|
--m_ref;
|
||||||
|
if (m_ref == 0) {
|
||||||
|
dealloc(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void display(std::ostream& out) const {
|
||||||
|
ast_manager& m = m_head.get_manager();
|
||||||
|
expr_ref_vector fmls(m);
|
||||||
|
expr_ref fml(m);
|
||||||
|
for (unsigned i = 0; i < m_predicates.size(); ++i) {
|
||||||
|
fmls.push_back(m_predicates[i]);
|
||||||
|
}
|
||||||
|
fmls.push_back(m_constraint);
|
||||||
|
bool_rewriter(m).mk_and(fmls.size(), fmls.c_ptr(), fml);
|
||||||
|
out << mk_pp(fml, m) << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// x = t[y], if x does not occur in t[y], then add t[y] to subst.
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
m_predicates.reset();
|
||||||
|
ast_manager& m = m_head.get_manager();
|
||||||
|
unsigned delta[1] = { 0 };
|
||||||
|
datalog::rule_manager& rm = m_goal.m();
|
||||||
|
unsigned num_vars = rm.get_var_counter().get_max_var(*m_goal);
|
||||||
|
substitution subst(m);
|
||||||
|
subst.reserve(1, num_vars+1);
|
||||||
|
expr_ref_vector fmls(m);
|
||||||
|
expr_ref tmp(m);
|
||||||
|
unsigned utsz = m_goal->get_uninterpreted_tail_size();
|
||||||
|
unsigned tsz = m_goal->get_tail_size();
|
||||||
|
for (unsigned i = utsz; i < tsz; ++i) {
|
||||||
|
fmls.push_back(m_goal->get_tail(i));
|
||||||
|
}
|
||||||
|
datalog::flatten_and(fmls);
|
||||||
|
for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||||
|
expr* e = fmls[i].get();
|
||||||
|
expr* t, *v;
|
||||||
|
if ((m.is_eq(e, v, t) && is_var(v) && !subst.contains(to_var(v), 0)) ||
|
||||||
|
(m.is_eq(e, t, v) && is_var(v) && !subst.contains(to_var(v), 0))) {
|
||||||
|
subst.push_scope();
|
||||||
|
subst.insert(to_var(v)->get_idx(), 0, expr_offset(t, 0));
|
||||||
|
if (!subst.acyclic()) {
|
||||||
|
subst.pop_scope();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool_rewriter(m).mk_and(fmls.size(), fmls.c_ptr(), m_constraint);
|
||||||
|
subst.apply(1, delta, expr_offset(m_constraint, 0), m_constraint);
|
||||||
|
subst.apply(1, delta, expr_offset(m_goal->get_head(), 0), tmp);
|
||||||
|
m_head = to_app(tmp);
|
||||||
|
m_rw(m_constraint);
|
||||||
|
for (unsigned i = 0; i < utsz; ++i) {
|
||||||
|
subst.apply(1, delta, expr_offset(m_goal->get_tail(i), 0), tmp);
|
||||||
|
m_predicates.push_back(to_app(tmp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// subsumption index structure.
|
// subsumption index structure.
|
||||||
class tab_index {
|
class index {
|
||||||
ast_manager& m;
|
ast_manager& m;
|
||||||
rule_manager& rm;
|
datalog::rule_manager& rm;
|
||||||
context& m_ctx;
|
datalog::context& m_ctx;
|
||||||
app_ref_vector m_preds;
|
app_ref_vector m_preds;
|
||||||
expr_ref m_precond;
|
expr_ref m_precond;
|
||||||
rule_ref_vector m_rules;
|
expr_ref_vector m_sideconds;
|
||||||
svector<unsigned> m_num_vars;
|
vector<ref<goal> > m_index;
|
||||||
matcher m_matcher;
|
matcher m_matcher;
|
||||||
substitution m_subst;
|
substitution m_subst;
|
||||||
qe_lite m_qe;
|
qe_lite m_qe;
|
||||||
uint_set m_empty_set;
|
uint_set m_empty_set;
|
||||||
bool_rewriter m_rw;
|
bool_rewriter m_rw;
|
||||||
smt_params m_fparams;
|
smt_params m_fparams;
|
||||||
smt::kernel m_solver;
|
smt::kernel m_solver;
|
||||||
|
volatile bool m_cancel;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
tab_index(ast_manager& m, rule_manager& rm, context& ctx):
|
index(datalog::context& ctx):
|
||||||
m(m),
|
m(ctx.get_manager()),
|
||||||
rm(rm),
|
rm(ctx.get_rule_manager()),
|
||||||
m_ctx(ctx),
|
m_ctx(ctx),
|
||||||
m_preds(m),
|
m_preds(m),
|
||||||
m_precond(m),
|
m_precond(m),
|
||||||
m_rules(rm),
|
m_sideconds(m),
|
||||||
m_matcher(m),
|
m_matcher(m),
|
||||||
m_subst(m),
|
m_subst(m),
|
||||||
m_qe(m),
|
m_qe(m),
|
||||||
m_rw(m),
|
m_rw(m),
|
||||||
m_solver(m, m_fparams) {}
|
m_solver(m, m_fparams),
|
||||||
|
m_cancel(false) {}
|
||||||
|
|
||||||
void insert(rule* r) {
|
void insert(ref<goal>& g) {
|
||||||
m_rules.push_back(r);
|
m_index.push_back(g);
|
||||||
m_num_vars.push_back(1+rm.get_var_counter().get_max_var(*r));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_subsumed(rule const& r) {
|
bool is_subsumed(goal const& g, unsigned& subsumer) {
|
||||||
setup(r);
|
setup(g);
|
||||||
m_solver.push();
|
m_solver.push();
|
||||||
m_solver.assert_expr(m_precond);
|
m_solver.assert_expr(m_precond);
|
||||||
bool found = find_match();
|
bool found = find_match(subsumer);
|
||||||
m_solver.pop(1);
|
m_solver.pop(1);
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cancel() {
|
||||||
|
m_cancel = true;
|
||||||
|
m_solver.cancel();
|
||||||
|
m_qe.set_cancel(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup() {
|
||||||
|
m_solver.reset_cancel();
|
||||||
|
m_qe.set_cancel(false);
|
||||||
|
m_cancel = false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void setup(rule const& r) {
|
void setup(goal const& g) {
|
||||||
m_preds.reset();
|
m_preds.reset();
|
||||||
expr_ref_vector fmls(m);
|
expr_ref_vector fmls(m);
|
||||||
expr_ref_vector vars(m);
|
expr_ref_vector vars(m);
|
||||||
expr_ref fml(m);
|
expr_ref fml(m);
|
||||||
ptr_vector<sort> sorts;
|
ptr_vector<sort> sorts;
|
||||||
r.get_vars(sorts);
|
for (unsigned i = 0; i < g.get_num_predicates(); ++i) {
|
||||||
unsigned utsz = r.get_uninterpreted_tail_size();
|
get_free_vars(g.get_predicate(i), sorts);
|
||||||
unsigned tsz = r.get_tail_size();
|
}
|
||||||
|
get_free_vars(g.get_constraint(), sorts);
|
||||||
var_subst vs(m, false);
|
var_subst vs(m, false);
|
||||||
for (unsigned i = 0; i < sorts.size(); ++i) {
|
for (unsigned i = 0; i < sorts.size(); ++i) {
|
||||||
if (!sorts[i]) {
|
if (!sorts[i]) {
|
||||||
|
@ -117,24 +348,27 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
vars.push_back(m.mk_const(symbol(i), sorts[i]));
|
vars.push_back(m.mk_const(symbol(i), sorts[i]));
|
||||||
}
|
}
|
||||||
for (unsigned i = 0; i < utsz; ++i) {
|
for (unsigned i = 0; i < g.get_num_predicates(); ++i) {
|
||||||
fml = r.get_tail(i);
|
vs(g.get_predicate(i), vars.size(), vars.c_ptr(), fml);
|
||||||
vs(fml, vars.size(), vars.c_ptr(), fml);
|
|
||||||
m_preds.push_back(to_app(fml));
|
m_preds.push_back(to_app(fml));
|
||||||
}
|
}
|
||||||
for (unsigned i = utsz; i < tsz; ++i) {
|
vs(g.get_constraint(), vars.size(), vars.c_ptr(), fml);
|
||||||
fml = r.get_tail(i);
|
fmls.push_back(fml);
|
||||||
vs(fml, vars.size(), vars.c_ptr(), fml);
|
|
||||||
fmls.push_back(fml);
|
|
||||||
}
|
|
||||||
m_precond = m.mk_and(fmls.size(), fmls.c_ptr());
|
m_precond = m.mk_and(fmls.size(), fmls.c_ptr());
|
||||||
|
IF_VERBOSE(2,
|
||||||
|
verbose_stream() << "setup-match: ";
|
||||||
|
for (unsigned i = 0; i < m_preds.size(); ++i) {
|
||||||
|
verbose_stream() << mk_pp(m_preds[i].get(), m) << " ";
|
||||||
|
}
|
||||||
|
verbose_stream() << mk_pp(m_precond, m) << "\n";);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// extract pre_cond => post_cond validation obligation from match.
|
// extract pre_cond => post_cond validation obligation from match.
|
||||||
bool find_match() {
|
bool find_match(unsigned& subsumer) {
|
||||||
for (unsigned i = 0; i < m_rules.size(); ++i) {
|
for (unsigned i = 0; !m_cancel && i < m_index.size(); ++i) {
|
||||||
if (match_rule(i)) {
|
if (match_rule(i)) {
|
||||||
|
subsumer = m_index[i]->get_index();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,44 +379,62 @@ namespace datalog {
|
||||||
// for now: skip multiple matches within the same rule (incomplete).
|
// for now: skip multiple matches within the same rule (incomplete).
|
||||||
//
|
//
|
||||||
bool match_rule(unsigned rule_index) {
|
bool match_rule(unsigned rule_index) {
|
||||||
rule const& r = *m_rules[rule_index];
|
goal const& g = *m_index[rule_index];
|
||||||
unsigned num_vars = m_num_vars[rule_index];
|
|
||||||
m_subst.reset();
|
m_subst.reset();
|
||||||
m_subst.reserve(2, num_vars);
|
m_subst.reserve(2, g.get_num_vars());
|
||||||
|
|
||||||
// IF_VERBOSE(1, r.display(m_ctx, verbose_stream() << "try-match\n"););
|
IF_VERBOSE(2, g.display(verbose_stream() << "try-match\n"););
|
||||||
|
|
||||||
return match_predicates(0, r);
|
return match_predicates(0, g);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool match_predicates(unsigned predicate_index, rule const& r) {
|
|
||||||
if (predicate_index == r.get_uninterpreted_tail_size()) {
|
bool match_predicates(unsigned predicate_index, goal const& g) {
|
||||||
return check_substitution(r);
|
if (predicate_index == g.get_num_predicates()) {
|
||||||
|
return check_substitution(g);
|
||||||
}
|
}
|
||||||
app* p = r.get_tail(predicate_index);
|
|
||||||
for (unsigned i = 0; i < m_preds.size(); ++i) {
|
app* q = g.get_predicate(predicate_index);
|
||||||
|
|
||||||
|
for (unsigned i = 0; !m_cancel && i < m_preds.size(); ++i) {
|
||||||
|
app* p = m_preds[i].get();
|
||||||
m_subst.push_scope();
|
m_subst.push_scope();
|
||||||
if (m_matcher(p, m_preds[i].get(), m_subst) &&
|
unsigned limit = m_sideconds.size();
|
||||||
match_predicates(predicate_index + 1, r)) {
|
IF_VERBOSE(2,
|
||||||
|
for (unsigned j = 0; j < predicate_index; ++j) verbose_stream() << " ";
|
||||||
|
verbose_stream() << mk_pp(q, m) << " = " << mk_pp(p, m) << "\n";
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (q->get_decl() == p->get_decl() &&
|
||||||
|
m_matcher(q, p, m_subst, m_sideconds) &&
|
||||||
|
match_predicates(predicate_index + 1, g)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
m_subst.pop_scope();
|
m_subst.pop_scope(1);
|
||||||
|
m_sideconds.resize(limit);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_substitution(rule const& r) {
|
bool check_substitution(goal const& g) {
|
||||||
unsigned utsz = r.get_uninterpreted_tail_size();
|
|
||||||
unsigned tsz = r.get_tail_size();
|
|
||||||
unsigned deltas[2] = {0, 0};
|
unsigned deltas[2] = {0, 0};
|
||||||
expr_ref_vector fmls(m);
|
|
||||||
expr_ref q(m), postcond(m);
|
expr_ref q(m), postcond(m);
|
||||||
|
expr_ref_vector fmls(m_sideconds);
|
||||||
|
|
||||||
for (unsigned i = utsz; i < tsz; ++i) {
|
for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||||
app* p = r.get_tail(i);
|
m_subst.apply(2, deltas, expr_offset(fmls[i].get(), 0), q);
|
||||||
m_subst.apply(2, deltas, expr_offset(p, 0), q);
|
fmls[i] = q;
|
||||||
fmls.push_back(q);
|
|
||||||
}
|
}
|
||||||
|
m_subst.apply(2, deltas, expr_offset(g.get_constraint(), 0), q);
|
||||||
|
fmls.push_back(q);
|
||||||
|
|
||||||
|
IF_VERBOSE(2,
|
||||||
|
for (unsigned i = 0; i < g.get_num_predicates(); ++i) {
|
||||||
|
verbose_stream() << " ";
|
||||||
|
}
|
||||||
|
q = m.mk_and(fmls.size(), fmls.c_ptr());
|
||||||
|
verbose_stream() << "check: " << mk_pp(q, m) << "\n";);
|
||||||
|
|
||||||
m_qe(m_empty_set, false, fmls);
|
m_qe(m_empty_set, false, fmls);
|
||||||
m_rw.mk_and(fmls.size(), fmls.c_ptr(), postcond);
|
m_rw.mk_and(fmls.size(), fmls.c_ptr(), postcond);
|
||||||
|
@ -205,7 +457,107 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum tab_instruction {
|
// predicate selection strategy.
|
||||||
|
class selection {
|
||||||
|
datalog::context& m_ctx;
|
||||||
|
ast_manager& m;
|
||||||
|
datalog::rule_manager& rm;
|
||||||
|
datatype_util dt;
|
||||||
|
obj_map<func_decl, unsigned_vector> m_scores;
|
||||||
|
unsigned_vector m_score_values;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
selection(datalog::context& ctx):
|
||||||
|
m_ctx(ctx),
|
||||||
|
m(ctx.get_manager()),
|
||||||
|
rm(ctx.get_rule_manager()),
|
||||||
|
dt(m) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(datalog::rule_set const& rules) {
|
||||||
|
m_scores.reset();
|
||||||
|
goal g(rm);
|
||||||
|
datalog::rule_ref r(rm);
|
||||||
|
datalog::rule_set::iterator it = rules.begin();
|
||||||
|
datalog::rule_set::iterator end = rules.end();
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
r = *it;
|
||||||
|
g.init(r);
|
||||||
|
app* p = g.get_head();
|
||||||
|
unsigned_vector scores;
|
||||||
|
score_predicate(p, scores);
|
||||||
|
insert_score(p->get_decl(), scores);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned select(goal const& g) {
|
||||||
|
unsigned min_distance = UINT_MAX;
|
||||||
|
unsigned result = 0;
|
||||||
|
unsigned_vector& scores = m_score_values;
|
||||||
|
for (unsigned i = 0; i < g.get_num_predicates(); ++i) {
|
||||||
|
scores.reset();
|
||||||
|
score_predicate(g.get_predicate(i), scores);
|
||||||
|
unsigned dist = compute_distance(g.get_predicate(i)->get_decl(), scores);
|
||||||
|
if (dist < min_distance) {
|
||||||
|
min_distance = dist;
|
||||||
|
result = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
unsigned compute_distance(func_decl* f, unsigned_vector const& scores) {
|
||||||
|
unsigned_vector f_scores;
|
||||||
|
unsigned dist = 0;
|
||||||
|
if (m_scores.find(f, f_scores)) {
|
||||||
|
SASSERT(f_scores.size() == scores.size());
|
||||||
|
for (unsigned i = 0; i < scores.size(); ++i) {
|
||||||
|
unsigned d1 = scores[i] - f_scores[i];
|
||||||
|
dist += d1*d1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else there is no rule.
|
||||||
|
return dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
void score_predicate(app* p, unsigned_vector& scores) {
|
||||||
|
for (unsigned i = 0; i < p->get_num_args(); ++i) {
|
||||||
|
scores.push_back(score_argument(p->get_arg(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned score_argument(expr* arg) {
|
||||||
|
if (is_var(arg)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (m.is_value(arg)) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
if (is_app(arg) && dt.is_constructor(to_app(arg)->get_decl())) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert_score(func_decl* f, unsigned_vector const& scores) {
|
||||||
|
obj_map<func_decl, unsigned_vector>::obj_map_entry* e = m_scores.find_core(f);
|
||||||
|
if (e) {
|
||||||
|
unsigned_vector & old_scores = e->get_data().m_value;
|
||||||
|
SASSERT(scores.size() == old_scores.size());
|
||||||
|
for (unsigned i = 0; i < scores.size(); ++i) {
|
||||||
|
old_scores[i] += scores[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_scores.insert(f, scores);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum instruction {
|
||||||
SELECT_RULE,
|
SELECT_RULE,
|
||||||
SELECT_PREDICATE,
|
SELECT_PREDICATE,
|
||||||
BACKTRACK,
|
BACKTRACK,
|
||||||
|
@ -214,7 +566,7 @@ namespace datalog {
|
||||||
CANCEL
|
CANCEL
|
||||||
};
|
};
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& out, tab_instruction i) {
|
std::ostream& operator<<(std::ostream& out, instruction i) {
|
||||||
switch(i) {
|
switch(i) {
|
||||||
case SELECT_RULE: return out << "select-rule";
|
case SELECT_RULE: return out << "select-rule";
|
||||||
case SELECT_PREDICATE: return out << "select-predicate";
|
case SELECT_PREDICATE: return out << "select-predicate";
|
||||||
|
@ -225,8 +577,9 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
return out << "unmatched instruction";
|
return out << "unmatched instruction";
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace datalog {
|
||||||
|
|
||||||
class tab::imp {
|
class tab::imp {
|
||||||
struct stats {
|
struct stats {
|
||||||
|
@ -234,58 +587,20 @@ namespace datalog {
|
||||||
void reset() { memset(this, 0, sizeof(*this)); }
|
void reset() { memset(this, 0, sizeof(*this)); }
|
||||||
unsigned m_num_unfold;
|
unsigned m_num_unfold;
|
||||||
unsigned m_num_no_unfold;
|
unsigned m_num_no_unfold;
|
||||||
unsigned m_num_subsume;
|
unsigned m_num_subsumed;
|
||||||
};
|
};
|
||||||
|
|
||||||
class goal {
|
|
||||||
public:
|
|
||||||
rule_ref m_goal;
|
|
||||||
// app_ref m_head;
|
|
||||||
// app_ref_vector m_predicates;
|
|
||||||
// expr_ref m_constraint;
|
|
||||||
unsigned m_index;
|
|
||||||
unsigned m_predicate_index;
|
|
||||||
unsigned m_rule_index;
|
|
||||||
|
|
||||||
goal(rule_manager& rm):
|
|
||||||
m_goal(rm),
|
|
||||||
// m_head(m),
|
|
||||||
// m_predicates(m),
|
|
||||||
// m_constraint(m),
|
|
||||||
m_index(0),
|
|
||||||
m_predicate_index(0),
|
|
||||||
m_rule_index(0) {
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
private:
|
|
||||||
void init() {
|
|
||||||
m_head = m_goal.get_head();
|
|
||||||
unsigned utsz = m_goal->get_uninterpreted_tail_size();
|
|
||||||
unsigned tsz = m_goal->get_tail_size();
|
|
||||||
for (unsigned i = 0; i < utsz; ++i) {
|
|
||||||
m_predicates.push_back(m_goal->get_tail(i));
|
|
||||||
}
|
|
||||||
expr_ref fmls(m);
|
|
||||||
for (unsigned i = utsz; i < tsz; ++i) {
|
|
||||||
fmls.push_back(m_goal->get_tail(i));
|
|
||||||
}
|
|
||||||
bool_rewriter(m).mk_and(fmls.size(), fmls.c_ptr(), m_constraint);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
context& m_ctx;
|
context& m_ctx;
|
||||||
ast_manager& m;
|
ast_manager& m;
|
||||||
rule_manager& rm;
|
rule_manager& rm;
|
||||||
tab_index m_subsumption_index;
|
tb::index m_index;
|
||||||
|
tb::selection m_selection;
|
||||||
smt_params m_fparams;
|
smt_params m_fparams;
|
||||||
smt::kernel m_solver;
|
smt::kernel m_solver;
|
||||||
rule_unifier m_unifier;
|
rule_unifier m_unifier;
|
||||||
rule_set m_rules;
|
rule_set m_rules;
|
||||||
vector<goal> m_goals;
|
vector<ref<tb::goal> > m_goals;
|
||||||
goal m_goal;
|
tb::instruction m_instruction;
|
||||||
tab_instruction m_instruction;
|
|
||||||
unsigned m_goal_index;
|
unsigned m_goal_index;
|
||||||
volatile bool m_cancel;
|
volatile bool m_cancel;
|
||||||
stats m_stats;
|
stats m_stats;
|
||||||
|
@ -294,12 +609,12 @@ namespace datalog {
|
||||||
m_ctx(ctx),
|
m_ctx(ctx),
|
||||||
m(ctx.get_manager()),
|
m(ctx.get_manager()),
|
||||||
rm(ctx.get_rule_manager()),
|
rm(ctx.get_rule_manager()),
|
||||||
m_subsumption_index(m, rm, ctx),
|
m_index(ctx),
|
||||||
|
m_selection(ctx),
|
||||||
m_solver(m, m_fparams),
|
m_solver(m, m_fparams),
|
||||||
m_unifier(ctx),
|
m_unifier(ctx),
|
||||||
m_rules(ctx),
|
m_rules(ctx),
|
||||||
m_goal(rm),
|
m_instruction(tb::SELECT_PREDICATE),
|
||||||
m_instruction(SELECT_PREDICATE),
|
|
||||||
m_cancel(false),
|
m_cancel(false),
|
||||||
m_goal_index(0)
|
m_goal_index(0)
|
||||||
{
|
{
|
||||||
|
@ -314,21 +629,27 @@ namespace datalog {
|
||||||
m_ctx.ensure_opened();
|
m_ctx.ensure_opened();
|
||||||
m_rules.reset();
|
m_rules.reset();
|
||||||
m_rules.add_rules(m_ctx.get_rules());
|
m_rules.add_rules(m_ctx.get_rules());
|
||||||
|
m_selection.init(m_rules);
|
||||||
rule_ref_vector query_rules(rm);
|
rule_ref_vector query_rules(rm);
|
||||||
rule_ref goal(rm);
|
rule_ref goal(rm);
|
||||||
func_decl_ref query_pred(m);
|
func_decl_ref query_pred(m);
|
||||||
rm.mk_query(query, query_pred, query_rules, goal);
|
rm.mk_query(query, query_pred, query_rules, goal);
|
||||||
init_goal(goal);
|
init_goal(goal);
|
||||||
IF_VERBOSE(1, display_goal(m_goal, verbose_stream()););
|
IF_VERBOSE(1, display_goal(*get_goal(), verbose_stream() << "g" << get_goal()->get_index() << " "););
|
||||||
return run();
|
return run();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cancel() {
|
void cancel() {
|
||||||
m_cancel = true;
|
m_cancel = true;
|
||||||
|
m_index.cleanup();
|
||||||
|
m_solver.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup() {
|
void cleanup() {
|
||||||
m_cancel = false;
|
m_cancel = false;
|
||||||
m_goals.reset();
|
m_goals.reset();
|
||||||
|
m_index.cleanup();
|
||||||
|
m_solver.reset_cancel();
|
||||||
}
|
}
|
||||||
void reset_statistics() {
|
void reset_statistics() {
|
||||||
m_stats.reset();
|
m_stats.reset();
|
||||||
|
@ -336,7 +657,7 @@ namespace datalog {
|
||||||
void collect_statistics(statistics& st) const {
|
void collect_statistics(statistics& st) const {
|
||||||
st.update("tab.num_unfold", m_stats.m_num_unfold);
|
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_unfold_fail", m_stats.m_num_no_unfold);
|
||||||
st.update("tab.num_subsume", m_stats.m_num_subsume);
|
st.update("tab.num_subsumed", m_stats.m_num_subsumed);
|
||||||
}
|
}
|
||||||
void display_certificate(std::ostream& out) const {
|
void display_certificate(std::ostream& out) const {
|
||||||
// TBD
|
// TBD
|
||||||
|
@ -348,90 +669,100 @@ namespace datalog {
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void select_predicate() {
|
void select_predicate() {
|
||||||
rule_ref& query = m_goal.m_goal;
|
unsigned num_predicates = get_goal()->get_num_predicates();
|
||||||
unsigned num_predicates = query->get_uninterpreted_tail_size();
|
|
||||||
if (num_predicates == 0) {
|
if (num_predicates == 0) {
|
||||||
m_instruction = UNSATISFIABLE;
|
m_instruction = tb::UNSATISFIABLE;
|
||||||
IF_VERBOSE(2, query->display(m_ctx, verbose_stream()); );
|
IF_VERBOSE(2, get_goal()->display(verbose_stream()); );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_instruction = SELECT_RULE;
|
m_instruction = tb::SELECT_RULE;
|
||||||
unsigned pi = 0; // TBD replace by better selection function.
|
unsigned pi = m_selection.select(*get_goal());
|
||||||
m_goal.m_predicate_index = pi;
|
get_goal()->set_predicate_index(pi);
|
||||||
m_goal.m_rule_index = 0;
|
get_goal()->set_rule_index(0);
|
||||||
IF_VERBOSE(2, verbose_stream() << mk_pp(query->get_tail(pi), m) << "\n";);
|
IF_VERBOSE(2, verbose_stream() << mk_pp(get_goal()->get_predicate(pi), m) << "\n";);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_rule(rule const& r) {
|
void apply_rule(rule const& r) {
|
||||||
rule_ref& query = m_goal.m_goal;
|
ref<tb::goal> goal = get_goal();
|
||||||
|
rule const& query = goal->get_rule();
|
||||||
rule_ref new_query(rm);
|
rule_ref new_query(rm);
|
||||||
if (m_unifier.unify_rules(*query, m_goal.m_predicate_index, r) &&
|
if (m_unifier.unify_rules(query, goal->get_predicate_index(), r) &&
|
||||||
m_unifier.apply(*query, m_goal.m_predicate_index, r, new_query) &&
|
m_unifier.apply(query, goal->get_predicate_index(), r, new_query) &&
|
||||||
l_false != query_is_sat(*new_query.get()) &&
|
l_false != query_is_sat(*new_query.get())) {
|
||||||
!query_is_subsumed(*new_query.get())) {
|
ref<tb::goal> next_goal = init_goal(new_query);
|
||||||
m_stats.m_num_unfold++;
|
unsigned subsumer = 0;
|
||||||
m_subsumption_index.insert(query.get());
|
|
||||||
m_goals.push_back(m_goal);
|
|
||||||
init_goal(new_query);
|
|
||||||
IF_VERBOSE(1,
|
IF_VERBOSE(1,
|
||||||
display_premise(m_goals.back(), verbose_stream());
|
display_premise(*goal, verbose_stream() << "g" << next_goal->get_index() << " ");
|
||||||
display_goal(m_goal, verbose_stream()););
|
display_goal(*next_goal, verbose_stream()););
|
||||||
m_instruction = SELECT_PREDICATE;
|
if (m_index.is_subsumed(*next_goal, subsumer)) {
|
||||||
|
IF_VERBOSE(1, verbose_stream() << "subsumed by " << subsumer << "\n";);
|
||||||
|
m_stats.m_num_subsumed++;
|
||||||
|
m_goals.pop_back();
|
||||||
|
m_instruction = tb::SELECT_RULE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_stats.m_num_unfold++;
|
||||||
|
m_index.insert(next_goal);
|
||||||
|
m_instruction = tb::SELECT_PREDICATE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_stats.m_num_no_unfold++;
|
m_stats.m_num_no_unfold++;
|
||||||
m_instruction = SELECT_RULE;
|
m_instruction = tb::SELECT_RULE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void select_rule() {
|
void select_rule() {
|
||||||
|
|
||||||
func_decl* p = m_goal.m_goal->get_decl(m_goal.m_predicate_index);
|
func_decl* p = get_goal()->get_predicate(get_goal()->get_predicate_index())->get_decl();
|
||||||
rule_vector const& rules = m_rules.get_predicate_rules(p);
|
rule_vector const& rules = m_rules.get_predicate_rules(p);
|
||||||
if (rules.size() <= m_goal.m_rule_index) {
|
if (rules.size() <= get_goal()->get_rule_index()) {
|
||||||
m_instruction = BACKTRACK;
|
m_instruction = tb::BACKTRACK;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
apply_rule(*rules[m_goal.m_rule_index++]);
|
unsigned index = get_goal()->get_rule_index();
|
||||||
|
get_goal()->inc_rule_index();
|
||||||
|
apply_rule(*rules[index]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void backtrack() {
|
void backtrack() {
|
||||||
|
SASSERT(!m_goals.empty());
|
||||||
|
m_goals.pop_back();
|
||||||
if (m_goals.empty()) {
|
if (m_goals.empty()) {
|
||||||
m_instruction = SATISFIABLE;
|
m_instruction = tb::SATISFIABLE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_goal = m_goals.back();
|
m_instruction = tb::SELECT_RULE;
|
||||||
m_goals.pop_back();
|
|
||||||
m_instruction = SELECT_RULE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lbool run() {
|
lbool run() {
|
||||||
m_instruction = SELECT_PREDICATE;
|
m_instruction = tb::SELECT_PREDICATE;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
IF_VERBOSE(2, verbose_stream() << m_instruction << "\n";);
|
||||||
if (m_cancel) {
|
if (m_cancel) {
|
||||||
cleanup();
|
cleanup();
|
||||||
return l_undef;
|
return l_undef;
|
||||||
}
|
}
|
||||||
switch(m_instruction) {
|
switch(m_instruction) {
|
||||||
case SELECT_PREDICATE:
|
case tb::SELECT_PREDICATE:
|
||||||
select_predicate();
|
select_predicate();
|
||||||
break;
|
break;
|
||||||
case SELECT_RULE:
|
case tb::SELECT_RULE:
|
||||||
select_rule();
|
select_rule();
|
||||||
break;
|
break;
|
||||||
case BACKTRACK:
|
case tb::BACKTRACK:
|
||||||
backtrack();
|
backtrack();
|
||||||
break;
|
break;
|
||||||
case SATISFIABLE:
|
case tb::SATISFIABLE:
|
||||||
return l_false;
|
return l_false;
|
||||||
case UNSATISFIABLE:
|
case tb::UNSATISFIABLE:
|
||||||
return l_true;
|
return l_true;
|
||||||
case CANCEL:
|
case tb::CANCEL:
|
||||||
m_cancel = false;
|
cleanup();
|
||||||
return l_undef;
|
return l_undef;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -456,7 +787,9 @@ namespace datalog {
|
||||||
names.push_back(symbol(i));
|
names.push_back(symbol(i));
|
||||||
}
|
}
|
||||||
fml = m.mk_and(fmls.size(), fmls.c_ptr());
|
fml = m.mk_and(fmls.size(), fmls.c_ptr());
|
||||||
fml = m.mk_exists(sorts.size(), sorts.c_ptr(), names.c_ptr(), fml);
|
if (!sorts.empty()) {
|
||||||
|
fml = m.mk_exists(sorts.size(), sorts.c_ptr(), names.c_ptr(), fml);
|
||||||
|
}
|
||||||
m_solver.push();
|
m_solver.push();
|
||||||
m_solver.assert_expr(fml);
|
m_solver.assert_expr(fml);
|
||||||
lbool is_sat = m_solver.check();
|
lbool is_sat = m_solver.check();
|
||||||
|
@ -467,24 +800,21 @@ namespace datalog {
|
||||||
return is_sat;
|
return is_sat;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool query_is_subsumed(rule const& query) {
|
ref<tb::goal> init_goal(rule_ref& new_query) {
|
||||||
return m_subsumption_index.is_subsumed(query);
|
ref<tb::goal> goal = alloc(tb::goal, rm);
|
||||||
|
goal->init(new_query);
|
||||||
|
goal->set_index(m_goal_index++);
|
||||||
|
m_goals.push_back(goal);
|
||||||
|
return goal;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_goal(rule_ref& new_query) {
|
ref<tb::goal> get_goal() const { return m_goals.back(); }
|
||||||
m_goal.m_goal = new_query;
|
|
||||||
m_goal.m_index = m_goal_index++;
|
|
||||||
m_goal.m_predicate_index = 0;
|
|
||||||
m_goal.m_rule_index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void display_premise(tb::goal& p, std::ostream& out) {
|
||||||
void display_premise(goal& p, std::ostream& out) {
|
out << "{g" << p.get_index() << " p" << p.get_predicate_index() << " r" << p.get_rule_index() << "}\n";
|
||||||
out << "[" << p.m_index << "]: " << p.m_predicate_index << ":" << p.m_rule_index << "\n";
|
|
||||||
}
|
}
|
||||||
void display_goal(goal& g, std::ostream& out) {
|
void display_goal(tb::goal& g, std::ostream& out) {
|
||||||
out << g.m_index << " ";
|
g.display(out);
|
||||||
g.m_goal->display(m_ctx, out);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue