mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 01:25:31 +00:00
Added rewriter.ignore_patterns_on_ground_qbody option to disable simplification of quantifiers that have their universals appear only in patterns, but otherwise have a ground body.
This commit is contained in:
parent
9a757ffffe
commit
27a1758857
19 changed files with 795 additions and 776 deletions
|
@ -47,14 +47,14 @@ Revision History:
|
|||
|
||||
namespace datalog {
|
||||
|
||||
rule_manager::rule_manager(context& ctx)
|
||||
rule_manager::rule_manager(context& ctx)
|
||||
: m(ctx.get_manager()),
|
||||
m_ctx(ctx),
|
||||
m_body(m),
|
||||
m_head(m),
|
||||
m_args(m),
|
||||
m_hnf(m),
|
||||
m_qe(m),
|
||||
m_qe(m, params_ref()),
|
||||
m_rwr(m),
|
||||
m_ufproc(m) {}
|
||||
|
||||
|
@ -98,7 +98,7 @@ namespace datalog {
|
|||
var_idx_set& rule_manager::finalize_collect_vars() {
|
||||
unsigned sz = m_free_vars.size();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
if (m_free_vars[i]) m_var_idx.insert(i);
|
||||
if (m_free_vars[i]) m_var_idx.insert(i);
|
||||
}
|
||||
return m_var_idx;
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ namespace datalog {
|
|||
}
|
||||
|
||||
|
||||
void rule_manager::mk_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) {
|
||||
void rule_manager::mk_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) {
|
||||
scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED);
|
||||
proof_ref pr(p, m);
|
||||
expr_ref fml1(m);
|
||||
|
@ -147,7 +147,7 @@ namespace datalog {
|
|||
if (fml1 != fml && pr) {
|
||||
pr = m.mk_asserted(fml1);
|
||||
}
|
||||
remove_labels(fml1, pr);
|
||||
remove_labels(fml1, pr);
|
||||
mk_rule_core(fml1, pr, rules, name);
|
||||
}
|
||||
|
||||
|
@ -162,7 +162,7 @@ namespace datalog {
|
|||
else {
|
||||
is_negated.push_back(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rule_manager::mk_rule_core(expr* fml, proof* p, rule_set& rules, symbol const& name) {
|
||||
|
@ -170,7 +170,7 @@ namespace datalog {
|
|||
proof_ref_vector prs(m);
|
||||
m_hnf.reset();
|
||||
m_hnf.set_name(name);
|
||||
|
||||
|
||||
m_hnf(fml, p, fmls, prs);
|
||||
for (unsigned i = 0; i < m_hnf.get_fresh_predicates().size(); ++i) {
|
||||
m_ctx.register_predicate(m_hnf.get_fresh_predicates()[i], false);
|
||||
|
@ -181,7 +181,7 @@ namespace datalog {
|
|||
}
|
||||
|
||||
void rule_manager::mk_horn_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) {
|
||||
|
||||
|
||||
m_body.reset();
|
||||
m_neg.reset();
|
||||
unsigned index = extract_horn(fml, m_body, m_head);
|
||||
|
@ -208,13 +208,13 @@ namespace datalog {
|
|||
}
|
||||
else if (is_quantifier(fml1)) {
|
||||
p = m.mk_modus_ponens(p, m.mk_symmetry(m.mk_der(to_quantifier(fml1), fml)));
|
||||
}
|
||||
}
|
||||
else {
|
||||
p = m.mk_modus_ponens(p, m.mk_rewrite(fml, fml1));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_ctx.fix_unbound_vars()) {
|
||||
if (m_ctx.fix_unbound_vars()) {
|
||||
fix_unbound_vars(r, true);
|
||||
}
|
||||
|
||||
|
@ -242,10 +242,10 @@ namespace datalog {
|
|||
for (unsigned i = 0; i < m_args.size(); ++i) {
|
||||
body.push_back(ensure_app(m_args[i].get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
head = ensure_app(fml);
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
|
@ -262,12 +262,12 @@ namespace datalog {
|
|||
|
||||
func_decl* rule_manager::mk_query(expr* query, rule_set& rules) {
|
||||
TRACE("dl", tout << mk_pp(query, m) << "\n";);
|
||||
|
||||
|
||||
ptr_vector<sort> vars;
|
||||
svector<symbol> names;
|
||||
app_ref_vector body(m);
|
||||
expr_ref q(m);
|
||||
|
||||
|
||||
// Add implicit variables.
|
||||
// Remove existential prefix.
|
||||
bind_variables(query, false, q);
|
||||
|
@ -278,7 +278,7 @@ namespace datalog {
|
|||
m_free_vars(q);
|
||||
vars.append(m_free_vars.size(), m_free_vars.c_ptr());
|
||||
if (vars.contains(static_cast<sort*>(0))) {
|
||||
var_subst sub(m, false);
|
||||
var_subst sub(m, false);
|
||||
expr_ref_vector args(m);
|
||||
// [s0, 0, s2, ..]
|
||||
// [0 -> 0, 1 -> x, 2 -> 1, ..]
|
||||
|
@ -313,7 +313,7 @@ namespace datalog {
|
|||
}
|
||||
}
|
||||
|
||||
// we want outermost declared variable first to
|
||||
// we want outermost declared variable first to
|
||||
// follow order of quantified variables so we reverse vars.
|
||||
while (vars.size() > names.size()) {
|
||||
names.push_back(symbol(names.size()));
|
||||
|
@ -321,9 +321,9 @@ namespace datalog {
|
|||
vars.reverse();
|
||||
names.reverse();
|
||||
func_decl* qpred = m_ctx.mk_fresh_head_predicate(symbol("query"), symbol(), vars.size(), vars.c_ptr(), body_pred);
|
||||
m_ctx.register_predicate(qpred, false);
|
||||
m_ctx.register_predicate(qpred, false);
|
||||
rules.set_output_predicate(qpred);
|
||||
|
||||
|
||||
if (m_ctx.get_model_converter()) {
|
||||
filter_model_converter* mc = alloc(filter_model_converter, m);
|
||||
mc->insert(qpred);
|
||||
|
@ -366,7 +366,7 @@ namespace datalog {
|
|||
for (unsigned i = 0; i < r.size(); ++i) {
|
||||
body.push_back(ensure_app(r[i].get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rule_manager::hoist_compound(unsigned& num_bound, app_ref& fml, app_ref_vector& body) {
|
||||
|
||||
|
@ -440,7 +440,7 @@ namespace datalog {
|
|||
if (is_quantifier(e)) {
|
||||
q = to_quantifier(e);
|
||||
return q->is_forall();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -454,7 +454,7 @@ namespace datalog {
|
|||
return app_ref(m.mk_eq(e, m.mk_true()), m);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rule_manager::check_app(expr* e) {
|
||||
if (!is_app(e)) {
|
||||
std::ostringstream out;
|
||||
|
@ -481,7 +481,7 @@ namespace datalog {
|
|||
bool has_neg = false;
|
||||
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
bool is_neg = (is_negated != 0 && is_negated[i]);
|
||||
bool is_neg = (is_negated != 0 && is_negated[i]);
|
||||
app * curr = tail[i];
|
||||
|
||||
if (is_neg && !m_ctx.is_predicate(curr)) {
|
||||
|
@ -571,7 +571,7 @@ namespace datalog {
|
|||
case 1: fml = m.mk_implies(body[0].get(), fml); break;
|
||||
default: fml = m.mk_implies(m.mk_and(body.size(), body.c_ptr()), fml); break;
|
||||
}
|
||||
|
||||
|
||||
m_free_vars(fml);
|
||||
if (m_free_vars.empty()) {
|
||||
return;
|
||||
|
@ -579,7 +579,7 @@ namespace datalog {
|
|||
svector<symbol> names;
|
||||
used_symbols<> us;
|
||||
m_free_vars.set_default_sort(m.mk_bool_sort());
|
||||
|
||||
|
||||
us(fml);
|
||||
m_free_vars.reverse();
|
||||
for (unsigned j = 0, i = 0; i < m_free_vars.size(); ++j) {
|
||||
|
@ -594,8 +594,8 @@ namespace datalog {
|
|||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
fml = m.mk_forall(m_free_vars.size(), m_free_vars.c_ptr(), names.c_ptr(), fml);
|
||||
}
|
||||
fml = m.mk_forall(m_free_vars.size(), m_free_vars.c_ptr(), names.c_ptr(), fml);
|
||||
}
|
||||
|
||||
std::ostream& rule_manager::display_smt2(rule const& r, std::ostream & out) {
|
||||
|
@ -749,7 +749,7 @@ namespace datalog {
|
|||
quant_tail = m.mk_exists(q_var_cnt, qsorts.c_ptr(), qnames.c_ptr(), unbound_tail_pre_quant);
|
||||
|
||||
if (try_quantifier_elimination) {
|
||||
TRACE("dl_rule_unbound_fix_pre_qe",
|
||||
TRACE("dl_rule_unbound_fix_pre_qe",
|
||||
tout<<"rule: ";
|
||||
r->display(m_ctx, tout);
|
||||
tout<<"tail with unbound vars: "<<mk_pp(unbound_tail, m)<<"\n";
|
||||
|
@ -764,7 +764,7 @@ namespace datalog {
|
|||
fixed_tail = quant_tail;
|
||||
}
|
||||
|
||||
TRACE("dl_rule_unbound_fix",
|
||||
TRACE("dl_rule_unbound_fix",
|
||||
tout<<"rule: ";
|
||||
r->display(m_ctx, tout);
|
||||
tout<<"tail with unbound vars: "<<mk_pp(unbound_tail, m)<<"\n";
|
||||
|
@ -796,7 +796,7 @@ namespace datalog {
|
|||
to_formula(new_rule, fml);
|
||||
scoped_proof _sc(m);
|
||||
proof* p = m.mk_rewrite(m.get_fact(old_rule.get_proof()), fml);
|
||||
new_rule.set_proof(m, m.mk_modus_ponens(old_rule.get_proof(), p));
|
||||
new_rule.set_proof(m, m.mk_modus_ponens(old_rule.get_proof(), p));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -824,7 +824,7 @@ namespace datalog {
|
|||
}
|
||||
r = mk(new_head.get(), new_tail.size(), new_tail.c_ptr(), tail_neg.c_ptr(), r->name(), false);
|
||||
|
||||
// keep old variable indices around so we can compose with substitutions.
|
||||
// keep old variable indices around so we can compose with substitutions.
|
||||
// r->norm_vars(*this);
|
||||
}
|
||||
|
||||
|
@ -835,7 +835,7 @@ namespace datalog {
|
|||
|
||||
void rule_manager::check_valid_head(expr * head) const {
|
||||
SASSERT(head);
|
||||
|
||||
|
||||
if (!m_ctx.is_predicate(head)) {
|
||||
std::ostringstream out;
|
||||
out << "Illegal head. The head predicate needs to be uninterpreted and registered (as recursive) " << mk_pp(head, m);
|
||||
|
@ -874,14 +874,14 @@ namespace datalog {
|
|||
m.get_allocator().deallocate(get_obj_size(n), this);
|
||||
}
|
||||
|
||||
void rule::set_proof(ast_manager& m, proof* p) {
|
||||
void rule::set_proof(ast_manager& m, proof* p) {
|
||||
if (p) {
|
||||
m.inc_ref(p);
|
||||
m.inc_ref(p);
|
||||
}
|
||||
if (m_proof) {
|
||||
m.dec_ref(m_proof);
|
||||
m.dec_ref(m_proof);
|
||||
}
|
||||
m_proof = p;
|
||||
m_proof = p;
|
||||
}
|
||||
|
||||
bool rule::is_in_tail(const func_decl * p, bool only_positive) const {
|
||||
|
@ -896,7 +896,7 @@ namespace datalog {
|
|||
|
||||
|
||||
//
|
||||
// non-predicates may appear only in the interpreted tail, it is therefore
|
||||
// non-predicates may appear only in the interpreted tail, it is therefore
|
||||
// sufficient only to check the tail.
|
||||
//
|
||||
bool rule_manager::has_uninterpreted_non_predicates(rule const& r, func_decl*& f) const {
|
||||
|
@ -911,7 +911,7 @@ namespace datalog {
|
|||
|
||||
|
||||
//
|
||||
// Quantifiers may appear only in the interpreted tail, it is therefore
|
||||
// Quantifiers may appear only in the interpreted tail, it is therefore
|
||||
// sufficient only to check the interpreted tail.
|
||||
//
|
||||
void rule_manager::has_quantifiers(rule const& r, bool& existential, bool& universal) const {
|
||||
|
@ -945,7 +945,7 @@ namespace datalog {
|
|||
unsigned sz = get_tail_size();
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
used.process(get_tail(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rule::get_vars(ast_manager& m, ptr_vector<sort>& sorts) const {
|
||||
|
@ -994,13 +994,13 @@ namespace datalog {
|
|||
app * old_tail = get_tail(i);
|
||||
expr_ref new_tail_e(m);
|
||||
vs(old_tail, subst_vals.size(), subst_vals.c_ptr(), new_tail_e);
|
||||
bool sign = is_neg_tail(i);
|
||||
bool sign = is_neg_tail(i);
|
||||
m.inc_ref(new_tail_e);
|
||||
m.dec_ref(old_tail);
|
||||
m_tail[i] = TAG(app *, to_app(new_tail_e), sign);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void rule::display(context & ctx, std::ostream & out) const {
|
||||
ast_manager & m = ctx.get_manager();
|
||||
//out << mk_pp(m_head, m);
|
||||
|
@ -1068,7 +1068,7 @@ namespace datalog {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1007,7 +1007,7 @@ namespace pdr {
|
|||
return m_cache[l];
|
||||
}
|
||||
|
||||
void model_search::erase_children(model_node& n, bool backtrack) {
|
||||
void model_search::erase_children(model_node& n, bool backtrack) {
|
||||
ptr_vector<model_node> todo, nodes;
|
||||
todo.append(n.children());
|
||||
remove_goal(n);
|
||||
|
@ -2241,7 +2241,7 @@ namespace pdr {
|
|||
vars.append(aux_vars.size(), aux_vars.c_ptr());
|
||||
|
||||
scoped_ptr<expr_replacer> rep;
|
||||
qe_lite qe(m);
|
||||
qe_lite qe(m, m_params.p);
|
||||
expr_ref phi1 = m_pm.mk_and(Phi);
|
||||
qe(vars, phi1);
|
||||
TRACE("pdr", tout << "Eliminated\n" << mk_pp(phi1, m) << "\n";);
|
||||
|
|
|
@ -53,10 +53,10 @@ namespace tb {
|
|||
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";);
|
||||
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;
|
||||
|
@ -75,7 +75,7 @@ namespace tb {
|
|||
return state;
|
||||
}
|
||||
else {
|
||||
IF_VERBOSE(2, verbose_stream() << "different constructors:" << mk_pp(s, m) << " " << mk_pp(t, m) << "\n";);
|
||||
IF_VERBOSE(2, verbose_stream() << "different constructors:" << mk_pp(s, m) << " " << mk_pp(t, m) << "\n";);
|
||||
return l_false;
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ namespace tb {
|
|||
case l_false:
|
||||
return false;
|
||||
default:
|
||||
conds.push_back(m.mk_eq(p, t));
|
||||
conds.push_back(m.mk_eq(p, t));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ namespace tb {
|
|||
|
||||
public:
|
||||
matcher(ast_manager& m): m(m), m_dt(m) {}
|
||||
|
||||
|
||||
bool operator()(app* pat, app* term, substitution& s, expr_ref_vector& conds) {
|
||||
// top-most term to match is a predicate. The predicates should be the same.
|
||||
if (pat->get_decl() != term->get_decl() ||
|
||||
|
@ -149,7 +149,7 @@ namespace tb {
|
|||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class clause {
|
||||
|
@ -165,22 +165,22 @@ namespace tb {
|
|||
unsigned m_next_rule; // next rule to expand goal on
|
||||
unsigned m_ref; // reference count
|
||||
|
||||
public:
|
||||
|
||||
public:
|
||||
|
||||
clause(ast_manager& m):
|
||||
m_head(m),
|
||||
m_predicates(m),
|
||||
m_constraint(m),
|
||||
m_seqno(0),
|
||||
m_index(0),
|
||||
m_index(0),
|
||||
m_num_vars(0),
|
||||
m_predicate_index(0),
|
||||
m_predicate_index(0),
|
||||
m_parent_rule(0),
|
||||
m_parent_index(0),
|
||||
m_next_rule(static_cast<unsigned>(-1)),
|
||||
m_ref(0) {
|
||||
}
|
||||
|
||||
|
||||
void set_seqno(unsigned seqno) { m_seqno = seqno; }
|
||||
unsigned get_seqno() const { return m_seqno; }
|
||||
unsigned get_next_rule() const { return m_next_rule; }
|
||||
|
@ -198,10 +198,10 @@ namespace tb {
|
|||
void set_head(app* h) { m_head = h; }
|
||||
unsigned get_parent_index() const { return m_parent_index; }
|
||||
unsigned get_parent_rule() const { return m_parent_rule; }
|
||||
void set_parent(ref<tb::clause>& parent) {
|
||||
void set_parent(ref<tb::clause>& parent) {
|
||||
m_parent_index = parent->get_index();
|
||||
m_parent_rule = parent->get_next_rule();
|
||||
}
|
||||
}
|
||||
|
||||
expr_ref get_body() const {
|
||||
ast_manager& m = get_manager();
|
||||
|
@ -247,7 +247,7 @@ namespace tb {
|
|||
}
|
||||
if (!vars.empty()) {
|
||||
body = m.mk_forall(vars.size(), vars.c_ptr(), names.c_ptr(), body);
|
||||
}
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
|
@ -273,18 +273,18 @@ namespace tb {
|
|||
reduce_equalities();
|
||||
// IF_VERBOSE(1, display(verbose_stream()););
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
@ -304,7 +304,7 @@ namespace tb {
|
|||
}
|
||||
out << mk_pp(fml, m) << "\n";
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
ast_manager& get_manager() const { return m_head.get_manager(); }
|
||||
|
@ -314,7 +314,7 @@ namespace tb {
|
|||
// - m_head - head predicate
|
||||
// - m_predicates - auxiliary predicates in body.
|
||||
// - m_constraint - side constraint
|
||||
//
|
||||
//
|
||||
void init_from_rule(datalog::rule_ref const& r) {
|
||||
ast_manager& m = get_manager();
|
||||
expr_ref_vector fmls(m);
|
||||
|
@ -328,7 +328,7 @@ namespace tb {
|
|||
m_predicates.reset();
|
||||
for (unsigned i = 0; i < utsz; ++i) {
|
||||
m_predicates.push_back(r->get_tail(i));
|
||||
}
|
||||
}
|
||||
bool_rewriter(m).mk_and(fmls.size(), fmls.c_ptr(), m_constraint);
|
||||
}
|
||||
|
||||
|
@ -348,13 +348,13 @@ namespace tb {
|
|||
if (get_subst(rw, subst, i, fmls)) {
|
||||
fmls[i] = m.mk_true();
|
||||
}
|
||||
}
|
||||
}
|
||||
subst.apply(1, delta, expr_offset(m_head, 0), tmp);
|
||||
m_head = to_app(tmp);
|
||||
for (unsigned i = 0; i < m_predicates.size(); ++i) {
|
||||
subst.apply(1, delta, expr_offset(m_predicates[i].get(), 0), tmp);
|
||||
m_predicates[i] = to_app(tmp);
|
||||
}
|
||||
}
|
||||
bool_rewriter(m).mk_and(fmls.size(), fmls.c_ptr(), m_constraint);
|
||||
subst.apply(1, delta, expr_offset(m_constraint, 0), m_constraint);
|
||||
rw(m_constraint);
|
||||
|
@ -404,7 +404,7 @@ namespace tb {
|
|||
throw non_constructor();
|
||||
}
|
||||
}
|
||||
void operator()(var* v) { }
|
||||
void operator()(var* v) { }
|
||||
void operator()(quantifier* ) {
|
||||
throw non_constructor();
|
||||
}
|
||||
|
@ -421,7 +421,7 @@ namespace tb {
|
|||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
// rules
|
||||
class rules {
|
||||
|
@ -456,7 +456,7 @@ namespace tb {
|
|||
func_decl* f = g->get_decl();
|
||||
map::obj_map_entry* e = m_index.insert_if_not_there2(f, unsigned_vector());
|
||||
SASSERT(e);
|
||||
e->get_data().m_value.push_back(idx);
|
||||
e->get_data().m_value.push_back(idx);
|
||||
}
|
||||
|
||||
unsigned get_num_rules(func_decl* p) const {
|
||||
|
@ -475,14 +475,14 @@ namespace tb {
|
|||
for (; it != end; ++it) {
|
||||
decls.push_back(it->m_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ref<clause> get_rule(func_decl* p, unsigned idx) const {
|
||||
map::obj_map_entry* e = m_index.find_core(p);
|
||||
SASSERT(p);
|
||||
unsigned rule_id = e->get_data().get_value()[idx];
|
||||
return m_rules[rule_id];
|
||||
}
|
||||
}
|
||||
private:
|
||||
void reset() {
|
||||
m_rules.reset();
|
||||
|
@ -509,7 +509,7 @@ namespace tb {
|
|||
bool_rewriter m_rw;
|
||||
smt_params m_fparams;
|
||||
smt::kernel m_solver;
|
||||
|
||||
|
||||
public:
|
||||
index(ast_manager& m):
|
||||
m(m),
|
||||
|
@ -520,7 +520,7 @@ namespace tb {
|
|||
m_matcher(m),
|
||||
m_refs(m),
|
||||
m_subst(m),
|
||||
m_qe(m),
|
||||
m_qe(m, params_ref()),
|
||||
m_rw(m),
|
||||
m_solver(m, m_fparams) {}
|
||||
|
||||
|
@ -544,7 +544,7 @@ namespace tb {
|
|||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
void setup(clause const& g) {
|
||||
m_preds.reset();
|
||||
m_refs.reset();
|
||||
|
@ -569,8 +569,8 @@ namespace tb {
|
|||
}
|
||||
vs(g.get_constraint(), vars.size(), vars.c_ptr(), fml);
|
||||
fmls.push_back(fml);
|
||||
m_precond = m.mk_and(fmls.size(), fmls.c_ptr());
|
||||
IF_VERBOSE(2,
|
||||
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) << " ";
|
||||
|
@ -587,18 +587,18 @@ namespace tb {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
//
|
||||
// check that each predicate in r is matched by some predicate in premise.
|
||||
// for now: skip multiple matches within the same rule (incomplete).
|
||||
//
|
||||
bool match_rule(unsigned rule_index) {
|
||||
clause const& g = *m_index[rule_index];
|
||||
clause const& g = *m_index[rule_index];
|
||||
m_sideconds.reset();
|
||||
m_subst.reset();
|
||||
m_subst.reserve(2, g.get_num_vars());
|
||||
|
||||
|
||||
IF_VERBOSE(2, g.display(verbose_stream() << "try-match\n"););
|
||||
|
||||
return match_head(g);
|
||||
|
@ -628,9 +628,9 @@ namespace tb {
|
|||
}
|
||||
verbose_stream() << mk_pp(q, m) << " = " << mk_pp(p, m) << "\n";
|
||||
);
|
||||
|
||||
|
||||
if (q->get_decl() == p->get_decl() &&
|
||||
|
||||
if (q->get_decl() == p->get_decl() &&
|
||||
m_matcher(q, p, m_subst, m_sideconds) &&
|
||||
match_predicates(predicate_index + 1, g)) {
|
||||
return true;
|
||||
|
@ -646,7 +646,7 @@ namespace tb {
|
|||
expr_ref q(m), postcond(m);
|
||||
expr_ref_vector fmls(m_sideconds);
|
||||
m_subst.reset_cache();
|
||||
|
||||
|
||||
for (unsigned i = 0; !m.canceled() && i < fmls.size(); ++i) {
|
||||
m_subst.apply(2, deltas, expr_offset(fmls[i].get(), 0), q);
|
||||
fmls[i] = q;
|
||||
|
@ -680,7 +680,7 @@ namespace tb {
|
|||
verbose_stream() << "check: " << mk_pp(postcond, m, 7 + g.get_num_predicates()) << "\n";);
|
||||
|
||||
if (!is_ground(postcond)) {
|
||||
IF_VERBOSE(1, verbose_stream() << "TBD: non-ground\n"
|
||||
IF_VERBOSE(1, verbose_stream() << "TBD: non-ground\n"
|
||||
<< mk_pp(postcond, m) << "\n";
|
||||
m_clause->display(verbose_stream());
|
||||
verbose_stream() << "\n=>\n";
|
||||
|
@ -743,7 +743,7 @@ namespace tb {
|
|||
double m_weight_multiply;
|
||||
unsigned m_update_frequency;
|
||||
unsigned m_next_update;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
selection(datalog::context& ctx):
|
||||
|
@ -766,7 +766,7 @@ namespace tb {
|
|||
scores.reset();
|
||||
basic_score_predicate(p, scores);
|
||||
insert_score(p->get_decl(), scores);
|
||||
}
|
||||
}
|
||||
normalize_scores(rs);
|
||||
}
|
||||
|
||||
|
@ -783,7 +783,7 @@ namespace tb {
|
|||
default:
|
||||
return weight_select(g);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
|
@ -867,8 +867,8 @@ namespace tb {
|
|||
}
|
||||
}
|
||||
IF_VERBOSE(1, verbose_stream() << "select:" << result << "\n";);
|
||||
|
||||
return result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned basic_weight_select(clause const& g) {
|
||||
|
@ -957,7 +957,7 @@ namespace tb {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
double score_predicate(app* p) {
|
||||
double score = 1;
|
||||
if (find_score(p, score)) {
|
||||
|
@ -1031,7 +1031,7 @@ namespace tb {
|
|||
}
|
||||
else {
|
||||
m_score_map.insert(f, scores);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1044,15 +1044,15 @@ namespace tb {
|
|||
expr_ref_vector m_sub1;
|
||||
expr_ref_vector m_sub2;
|
||||
public:
|
||||
unifier(ast_manager& m):
|
||||
m(m),
|
||||
unifier(ast_manager& m):
|
||||
m(m),
|
||||
m_unifier(m),
|
||||
m_S1(m),
|
||||
m_S2(m, false),
|
||||
m_rename(m),
|
||||
m_sub1(m),
|
||||
m_sub1(m),
|
||||
m_sub2(m) {}
|
||||
|
||||
|
||||
bool operator()(ref<clause>& tgt, unsigned idx, ref<clause>& src, bool compute_subst, ref<clause>& result) {
|
||||
return unify(*tgt, idx, *src, compute_subst, result);
|
||||
}
|
||||
|
@ -1066,12 +1066,12 @@ namespace tb {
|
|||
}
|
||||
}
|
||||
|
||||
bool unify(clause const& tgt, unsigned idx, clause const& src, bool compute_subst, ref<clause>& result) {
|
||||
qe_lite qe(m);
|
||||
bool unify(clause const& tgt, unsigned idx, clause const& src, bool compute_subst, ref<clause>& result) {
|
||||
qe_lite qe(m, params_ref());
|
||||
reset();
|
||||
SASSERT(tgt.get_predicate(idx)->get_decl() == src.get_decl());
|
||||
unsigned var_cnt = std::max(tgt.get_num_vars(), src.get_num_vars());
|
||||
m_S1.reserve(2, var_cnt);
|
||||
m_S1.reserve(2, var_cnt);
|
||||
if (!m_unifier(tgt.get_predicate(idx), src.get_head(), m_S1)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1080,7 +1080,7 @@ namespace tb {
|
|||
app_ref head(m);
|
||||
result = alloc(clause, m);
|
||||
unsigned delta[2] = { 0, var_cnt };
|
||||
m_S1.apply(2, delta, expr_offset(tgt.get_head(), 0), tmp);
|
||||
m_S1.apply(2, delta, expr_offset(tgt.get_head(), 0), tmp);
|
||||
head = to_app(tmp);
|
||||
for (unsigned i = 0; i < tgt.get_num_predicates(); ++i) {
|
||||
if (i != idx) {
|
||||
|
@ -1096,7 +1096,7 @@ namespace tb {
|
|||
}
|
||||
m_S1.apply(2, delta, expr_offset(tgt.get_constraint(), 0), tmp);
|
||||
m_S1.apply(2, delta, expr_offset(src.get_constraint(), 1), tmp2);
|
||||
constraint = m.mk_and(tmp, tmp2);
|
||||
constraint = m.mk_and(tmp, tmp2);
|
||||
|
||||
// perform trival quantifier-elimination:
|
||||
uint_set index_set;
|
||||
|
@ -1114,7 +1114,7 @@ namespace tb {
|
|||
if (m.is_false(constraint)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// initialize rule.
|
||||
result->init(head, predicates, constraint);
|
||||
ptr_vector<sort> vars;
|
||||
|
@ -1147,10 +1147,10 @@ namespace tb {
|
|||
extract_subst(delta, src, 1);
|
||||
}
|
||||
// init result using head, predicates, constraint
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private:
|
||||
void reset() {
|
||||
m_S1.reset();
|
||||
|
@ -1175,9 +1175,9 @@ namespace tb {
|
|||
else {
|
||||
insert_subst(offset, m.mk_true());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void insert_subst(unsigned offset, expr* e) {
|
||||
if (offset == 0) {
|
||||
m_sub1.push_back(e);
|
||||
|
@ -1201,7 +1201,7 @@ namespace tb {
|
|||
|
||||
|
||||
//
|
||||
// Given a clause
|
||||
// Given a clause
|
||||
// P(s) :- P(t), Phi(x).
|
||||
// Compute the clauses:
|
||||
// acc: P(s) :- Delta(z,t), P(z), Phi(x).
|
||||
|
@ -1237,7 +1237,7 @@ namespace tb {
|
|||
head = m.mk_app(delta, zszs.size(), zszs.c_ptr());
|
||||
for (unsigned i = 0; i < zs.size(); ++i) {
|
||||
zszs[i+zs.size()] = q->get_arg(i);
|
||||
}
|
||||
}
|
||||
pred = m.mk_app(delta, zszs.size(), zszs.c_ptr());
|
||||
preds.push_back(pred);
|
||||
for (unsigned i = 1; i < g.get_num_predicates(); ++i) {
|
||||
|
@ -1247,28 +1247,28 @@ namespace tb {
|
|||
preds.push_back(m.mk_app(q->get_decl(), zs.size(), zs.c_ptr()));
|
||||
acc->init(p, preds, g.get_constraint());
|
||||
|
||||
IF_VERBOSE(1,
|
||||
IF_VERBOSE(1,
|
||||
delta1->display(verbose_stream() << "delta1:\n");
|
||||
delta2->display(verbose_stream() << "delta2:\n");
|
||||
acc->display(verbose_stream() << "acc:\n"););
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Given a sequence of clauses and inference rules
|
||||
// compute a super-predicate and auxiliary clauses.
|
||||
//
|
||||
//
|
||||
// P1(x) :- P2(y), R(z)
|
||||
// P2(y) :- P3(z), T(u)
|
||||
// P3(z) :- P1(x), U(v)
|
||||
// =>
|
||||
// P1(x) :- P1(x), R(z), T(u), U(v)
|
||||
//
|
||||
//
|
||||
|
||||
ref<clause> resolve_rules(unsigned num_clauses, clause*const* clauses, unsigned const* positions) {
|
||||
ref<clause> result = clauses[0];
|
||||
ref<clause> tmp;
|
||||
unsigned offset = 0;
|
||||
for (unsigned i = 0; i + 1 < num_clauses; ++i) {
|
||||
for (unsigned i = 0; i + 1 < num_clauses; ++i) {
|
||||
clause const& cl = *clauses[i+1];
|
||||
offset += positions[i];
|
||||
VERIFY (m_unifier.unify(*result, offset, cl, false, tmp));
|
||||
|
@ -1276,7 +1276,7 @@ namespace tb {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
@ -1286,7 +1286,7 @@ namespace tb {
|
|||
unsigned num_vars = g.get_num_vars();
|
||||
for (unsigned i = 0; i < p->get_num_args(); ++i) {
|
||||
result.push_back(m.mk_var(num_vars+i, m.get_sort(p->get_arg(i))));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
@ -1341,7 +1341,7 @@ namespace datalog {
|
|||
uint_set m_displayed_rules;
|
||||
public:
|
||||
imp(context& ctx):
|
||||
m_ctx(ctx),
|
||||
m_ctx(ctx),
|
||||
m(ctx.get_manager()),
|
||||
rm(ctx.get_rule_manager()),
|
||||
m_index(m),
|
||||
|
@ -1358,7 +1358,7 @@ namespace datalog {
|
|||
m_fparams.m_timeout = 1000;
|
||||
}
|
||||
|
||||
~imp() {}
|
||||
~imp() {}
|
||||
|
||||
lbool query(expr* query) {
|
||||
m_ctx.ensure_opened();
|
||||
|
@ -1378,7 +1378,7 @@ namespace datalog {
|
|||
IF_VERBOSE(1, display_clause(*get_clause(), verbose_stream() << "g" << get_clause()->get_seqno() << " "););
|
||||
return run();
|
||||
}
|
||||
|
||||
|
||||
void cleanup() {
|
||||
m_clauses.reset();
|
||||
}
|
||||
|
@ -1400,7 +1400,7 @@ namespace datalog {
|
|||
|
||||
expr_ref get_answer() const {
|
||||
switch(m_status) {
|
||||
case l_undef:
|
||||
case l_undef:
|
||||
UNREACHABLE();
|
||||
return expr_ref(m.mk_false(), m);
|
||||
case l_true: {
|
||||
|
@ -1415,7 +1415,7 @@ namespace datalog {
|
|||
return expr_ref(m.mk_true(), m);
|
||||
}
|
||||
private:
|
||||
|
||||
|
||||
void select_predicate() {
|
||||
tb::clause & g = *get_clause();
|
||||
unsigned num_predicates = g.get_num_predicates();
|
||||
|
@ -1430,17 +1430,17 @@ namespace datalog {
|
|||
IF_VERBOSE(2, verbose_stream() << mk_pp(g.get_predicate(pi), m) << "\n";);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void apply_rule(ref<tb::clause>& r) {
|
||||
ref<tb::clause> clause = get_clause();
|
||||
ref<tb::clause> next_clause;
|
||||
ref<tb::clause> next_clause;
|
||||
if (m_unifier(clause, clause->get_predicate_index(), r, false, next_clause) &&
|
||||
!query_is_tautology(*next_clause)) {
|
||||
init_clause(next_clause);
|
||||
unsigned subsumer = 0;
|
||||
IF_VERBOSE(1,
|
||||
IF_VERBOSE(1,
|
||||
display_rule(*clause, verbose_stream());
|
||||
display_premise(*clause,
|
||||
display_premise(*clause,
|
||||
verbose_stream() << "g" << next_clause->get_seqno() << " ");
|
||||
display_clause(*next_clause, verbose_stream());
|
||||
);
|
||||
|
@ -1462,8 +1462,8 @@ namespace datalog {
|
|||
m_instruction = tb::SELECT_RULE;
|
||||
}
|
||||
}
|
||||
|
||||
void select_rule() {
|
||||
|
||||
void select_rule() {
|
||||
tb::clause& g = *get_clause();
|
||||
g.inc_next_rule();
|
||||
unsigned pi = g.get_predicate_index();
|
||||
|
@ -1481,7 +1481,7 @@ namespace datalog {
|
|||
|
||||
void backtrack() {
|
||||
SASSERT(!m_clauses.empty());
|
||||
m_clauses.pop_back();
|
||||
m_clauses.pop_back();
|
||||
if (m_clauses.empty()) {
|
||||
m_instruction = tb::SATISFIABLE;
|
||||
}
|
||||
|
@ -1500,16 +1500,16 @@ namespace datalog {
|
|||
return l_undef;
|
||||
}
|
||||
switch(m_instruction) {
|
||||
case tb::SELECT_PREDICATE:
|
||||
select_predicate();
|
||||
case tb::SELECT_PREDICATE:
|
||||
select_predicate();
|
||||
break;
|
||||
case tb::SELECT_RULE:
|
||||
select_rule();
|
||||
case tb::SELECT_RULE:
|
||||
select_rule();
|
||||
break;
|
||||
case tb::BACKTRACK:
|
||||
backtrack();
|
||||
break;
|
||||
case tb::SATISFIABLE:
|
||||
case tb::SATISFIABLE:
|
||||
m_status = l_false;
|
||||
return l_false;
|
||||
case tb::UNSATISFIABLE:
|
||||
|
@ -1522,18 +1522,18 @@ namespace datalog {
|
|||
return l_undef;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool query_is_tautology(tb::clause const& g) {
|
||||
expr_ref fml = g.to_formula();
|
||||
fml = m.mk_not(fml);
|
||||
m_solver.push();
|
||||
m_solver.assert_expr(fml);
|
||||
lbool is_sat = m_solver.check();
|
||||
lbool is_sat = m_solver.check();
|
||||
m_solver.pop(1);
|
||||
|
||||
TRACE("dl", tout << is_sat << ":\n" << mk_pp(fml, m) << "\n";);
|
||||
|
||||
|
||||
return l_false == is_sat;
|
||||
|
||||
}
|
||||
|
@ -1560,7 +1560,7 @@ namespace datalog {
|
|||
|
||||
void display_premise(tb::clause& p, std::ostream& out) {
|
||||
func_decl* f = p.get_predicate(p.get_predicate_index())->get_decl();
|
||||
out << "{g" << p.get_seqno() << " " << f->get_name() << " pos: "
|
||||
out << "{g" << p.get_seqno() << " " << f->get_name() << " pos: "
|
||||
<< p.get_predicate_index() << " rule: " << p.get_next_rule() << "}\n";
|
||||
}
|
||||
|
||||
|
@ -1576,21 +1576,21 @@ namespace datalog {
|
|||
ref<tb::clause> replayed_clause;
|
||||
replace_proof_converter pc(m);
|
||||
|
||||
// clause is a empty clause.
|
||||
// clause is a empty clause.
|
||||
// Pretend it is asserted.
|
||||
// It gets replaced by premises.
|
||||
SASSERT(clause->get_num_predicates() == 0);
|
||||
SASSERT(clause->get_num_predicates() == 0);
|
||||
expr_ref root = clause->to_formula();
|
||||
|
||||
vector<expr_ref_vector> substs;
|
||||
while (0 != clause->get_index()) {
|
||||
SASSERT(clause->get_parent_index() < clause->get_index());
|
||||
while (0 != clause->get_index()) {
|
||||
SASSERT(clause->get_parent_index() < clause->get_index());
|
||||
unsigned p_index = clause->get_parent_index();
|
||||
unsigned p_rule = clause->get_parent_rule();
|
||||
ref<tb::clause> parent = m_clauses[p_index];
|
||||
unsigned pi = parent->get_predicate_index();
|
||||
func_decl* pred = parent->get_predicate(pi)->get_decl();
|
||||
ref<tb::clause> rl = m_rules.get_rule(pred, p_rule);
|
||||
ref<tb::clause> rl = m_rules.get_rule(pred, p_rule);
|
||||
VERIFY(m_unifier(parent, parent->get_predicate_index(), rl, true, replayed_clause));
|
||||
expr_ref_vector s1(m_unifier.get_rule_subst(true));
|
||||
expr_ref_vector s2(m_unifier.get_rule_subst(false));
|
||||
|
@ -1614,36 +1614,36 @@ namespace datalog {
|
|||
}
|
||||
expr_ref body = clause.get_body();
|
||||
var_subst vs(m, false);
|
||||
vs(body, subst.size(), subst.c_ptr(), body);
|
||||
vs(body, subst.size(), subst.c_ptr(), body);
|
||||
out << mk_pp(body, m) << "\n";
|
||||
}
|
||||
|
||||
void resolve_rule(replace_proof_converter& pc, tb::clause const& r1, tb::clause const& r2,
|
||||
void resolve_rule(replace_proof_converter& pc, tb::clause const& r1, tb::clause const& r2,
|
||||
expr_ref_vector const& s1, expr_ref_vector const& s2, tb::clause const& res) const {
|
||||
unsigned idx = r1.get_predicate_index();
|
||||
expr_ref fml = res.to_formula();
|
||||
vector<expr_ref_vector> substs;
|
||||
svector<std::pair<unsigned, unsigned> > positions;
|
||||
substs.push_back(s1);
|
||||
substs.push_back(s2);
|
||||
substs.push_back(s2);
|
||||
scoped_proof _sc(m);
|
||||
proof_ref pr(m);
|
||||
proof_ref_vector premises(m);
|
||||
premises.push_back(m.mk_asserted(r1.to_formula()));
|
||||
premises.push_back(m.mk_asserted(r2.to_formula()));
|
||||
positions.push_back(std::make_pair(idx+1, 0));
|
||||
positions.push_back(std::make_pair(idx+1, 0));
|
||||
pr = m.mk_hyper_resolve(2, premises.c_ptr(), fml, positions, substs);
|
||||
pc.insert(pr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
tab::tab(context& ctx):
|
||||
datalog::engine_base(ctx.get_manager(),"tabulation"),
|
||||
m_imp(alloc(imp, ctx)) {
|
||||
m_imp(alloc(imp, ctx)) {
|
||||
}
|
||||
tab::~tab() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
}
|
||||
lbool tab::query(expr* query) {
|
||||
return m_imp->query(query);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue