mirror of
https://github.com/Z3Prover/z3
synced 2025-04-13 12:28:44 +00:00
tidy verbose mode a bit, ackermannize special cases of arrays
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
8e5581b4fe
commit
7fd4e7861f
|
@ -49,6 +49,94 @@ namespace datalog {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool mk_array_blast::ackermanize(expr_ref& body, expr_ref& head) {
|
||||
expr_ref_vector conjs(m);
|
||||
flatten_and(body, conjs);
|
||||
defs_t defs;
|
||||
expr_safe_replace sub(m);
|
||||
ptr_vector<expr> todo;
|
||||
todo.push_back(head);
|
||||
for (unsigned i = 0; i < conjs.size(); ++i) {
|
||||
expr* e = conjs[i].get();
|
||||
expr* x, *y;
|
||||
if (m.is_eq(e, x, y) || m.is_iff(e, x, y)) {
|
||||
if (a.is_select(y)) {
|
||||
std::swap(x,y);
|
||||
}
|
||||
if (a.is_select(x) && is_var(y)) {
|
||||
//
|
||||
// For the Ackermann reduction we would like the arrays
|
||||
// to be variables, so that variables can be
|
||||
// assumed to represent difference (alias)
|
||||
// classes.
|
||||
//
|
||||
if (!is_var(to_app(x)->get_arg(0))) {
|
||||
return false;
|
||||
}
|
||||
sub.insert(x, y);
|
||||
defs.insert(to_app(x), to_var(y));
|
||||
}
|
||||
}
|
||||
todo.push_back(e);
|
||||
}
|
||||
// now check that all occurrences of select have been covered.
|
||||
ast_mark mark;
|
||||
while (!todo.empty()) {
|
||||
expr* e = todo.back();
|
||||
todo.pop_back();
|
||||
if (mark.is_marked(e)) {
|
||||
continue;
|
||||
}
|
||||
mark.mark(e, true);
|
||||
if (is_var(e)) {
|
||||
continue;
|
||||
}
|
||||
if (!is_app(e)) {
|
||||
return false;
|
||||
}
|
||||
app* ap = to_app(e);
|
||||
if (a.is_select(e) && !defs.contains(ap)) {
|
||||
return false;
|
||||
}
|
||||
for (unsigned i = 0; i < ap->get_num_args(); ++i) {
|
||||
todo.push_back(ap->get_arg(i));
|
||||
}
|
||||
}
|
||||
sub(body);
|
||||
sub(head);
|
||||
conjs.reset();
|
||||
|
||||
// perform the Ackermann reduction by creating implications
|
||||
// i1 = i2 => val1 = val2 for each equality pair:
|
||||
// (= val1 (select a_i i1))
|
||||
// (= val2 (select a_i i2))
|
||||
defs_t::iterator it1 = defs.begin(), end = defs.end();
|
||||
for (; it1 != end; ++it1) {
|
||||
app* a1 = it1->m_key;
|
||||
var* v1 = it1->m_value;
|
||||
defs_t::iterator it2 = it1;
|
||||
++it2;
|
||||
for (; it2 != end; ++it2) {
|
||||
app* a2 = it2->m_key;
|
||||
var* v2 = it2->m_value;
|
||||
if (a1->get_arg(0) != a2->get_arg(0)) {
|
||||
continue;
|
||||
}
|
||||
expr_ref_vector eqs(m);
|
||||
for (unsigned j = 1; j < a1->get_num_args(); ++j) {
|
||||
eqs.push_back(m.mk_eq(a1->get_arg(j), a2->get_arg(j)));
|
||||
}
|
||||
conjs.push_back(m.mk_implies(m.mk_and(eqs.size(), eqs.c_ptr()), m.mk_eq(v1, v2)));
|
||||
}
|
||||
}
|
||||
if (!conjs.empty()) {
|
||||
conjs.push_back(body);
|
||||
body = m.mk_and(conjs.size(), conjs.c_ptr());
|
||||
}
|
||||
m_rewriter(body);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mk_array_blast::blast(rule& r, rule_set& rules) {
|
||||
unsigned utsz = r.get_uninterpreted_tail_size();
|
||||
|
@ -92,10 +180,6 @@ namespace datalog {
|
|||
new_conjs.push_back(tmp);
|
||||
}
|
||||
}
|
||||
if (!inserted && !change) {
|
||||
rules.add_rule(&r);
|
||||
return false;
|
||||
}
|
||||
|
||||
rule_ref_vector new_rules(rm);
|
||||
expr_ref fml1(m), fml2(m), body(m), head(m);
|
||||
|
@ -106,11 +190,17 @@ namespace datalog {
|
|||
m_rewriter(body);
|
||||
sub(head);
|
||||
m_rewriter(head);
|
||||
change = ackermanize(body, head) || change;
|
||||
if (!inserted && !change) {
|
||||
rules.add_rule(&r);
|
||||
return false;
|
||||
}
|
||||
|
||||
fml2 = m.mk_implies(body, head);
|
||||
rm.mk_rule(fml2, new_rules, r.name());
|
||||
SASSERT(new_rules.size() == 1);
|
||||
|
||||
TRACE("dl", tout << "new body " << mk_pp(fml2, m) << "\n";);
|
||||
TRACE("dl", new_rules[0]->display(m_ctx, tout << "new rule\n"););
|
||||
|
||||
rules.add_rule(new_rules[0].get());
|
||||
if (m_pc) {
|
||||
|
|
|
@ -39,10 +39,14 @@ namespace datalog {
|
|||
th_rewriter m_rewriter;
|
||||
equiv_proof_converter* m_pc;
|
||||
|
||||
typedef obj_map<app, var*> defs_t;
|
||||
|
||||
bool blast(rule& r, rule_set& new_rules);
|
||||
|
||||
bool is_store_def(expr* e, expr*& x, expr*& y);
|
||||
|
||||
bool ackermanize(expr_ref& body, expr_ref& head);
|
||||
|
||||
public:
|
||||
/**
|
||||
\brief Create rule transformer that extracts universal quantifiers (over recursive predicates).
|
||||
|
|
|
@ -52,6 +52,20 @@ namespace pdr {
|
|||
static bool is_infty_level(unsigned lvl) { return lvl == infty_level; }
|
||||
|
||||
static unsigned next_level(unsigned lvl) { return is_infty_level(lvl)?lvl:(lvl+1); }
|
||||
|
||||
struct pp_level {
|
||||
unsigned m_level;
|
||||
pp_level(unsigned l): m_level(l) {}
|
||||
};
|
||||
|
||||
static std::ostream& operator<<(std::ostream& out, pp_level const& p) {
|
||||
if (is_infty_level(p.m_level)) {
|
||||
return out << "oo";
|
||||
}
|
||||
else {
|
||||
return out << p.m_level;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------
|
||||
// pred_tansformer
|
||||
|
@ -263,7 +277,7 @@ namespace pdr {
|
|||
else if (is_invariant(tgt_level, curr, false, assumes_level)) {
|
||||
|
||||
add_property(curr, assumes_level?tgt_level:infty_level);
|
||||
TRACE("pdr", tout << "is invariant: "<< tgt_level << " " << mk_pp(curr, m) << "\n";);
|
||||
TRACE("pdr", tout << "is invariant: "<< pp_level(tgt_level) << " " << mk_pp(curr, m) << "\n";);
|
||||
src[i] = src.back();
|
||||
src.pop_back();
|
||||
++m_stats.m_num_propagations;
|
||||
|
@ -273,14 +287,7 @@ namespace pdr {
|
|||
++i;
|
||||
}
|
||||
}
|
||||
IF_VERBOSE(2, verbose_stream() << "propagate: ";
|
||||
if (is_infty_level(src_level)) {
|
||||
verbose_stream() << "infty";
|
||||
}
|
||||
else {
|
||||
verbose_stream() << src_level;
|
||||
}
|
||||
verbose_stream() << "\n";
|
||||
IF_VERBOSE(3, verbose_stream() << "propagate: " << pp_level(src_level) << "\n";
|
||||
for (unsigned i = 0; i < src.size(); ++i) {
|
||||
verbose_stream() << mk_pp(src[i].get(), m) << "\n";
|
||||
});
|
||||
|
@ -304,14 +311,14 @@ namespace pdr {
|
|||
ensure_level(lvl);
|
||||
unsigned old_level;
|
||||
if (!m_prop2level.find(lemma, old_level) || old_level < lvl) {
|
||||
TRACE("pdr", tout << "property1: " << lvl << " " << head()->get_name() << " " << mk_pp(lemma, m) << "\n";);
|
||||
TRACE("pdr", tout << "property1: " << pp_level(lvl) << " " << head()->get_name() << " " << mk_pp(lemma, m) << "\n";);
|
||||
m_levels[lvl].push_back(lemma);
|
||||
m_prop2level.insert(lemma, lvl);
|
||||
m_solver.add_level_formula(lemma, lvl);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
TRACE("pdr", tout << "old-level: " << old_level << " " << head()->get_name() << " " << mk_pp(lemma, m) << "\n";);
|
||||
TRACE("pdr", tout << "old-level: " << pp_level(old_level) << " " << head()->get_name() << " " << mk_pp(lemma, m) << "\n";);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -337,7 +344,7 @@ namespace pdr {
|
|||
for (unsigned i = 0; i < lemmas.size(); ++i) {
|
||||
expr* lemma_i = lemmas[i].get();
|
||||
if (add_property1(lemma_i, lvl)) {
|
||||
IF_VERBOSE(2, verbose_stream() << lvl << " " << mk_pp(lemma_i, m) << "\n";);
|
||||
IF_VERBOSE(2, verbose_stream() << pp_level(lvl) << " " << mk_pp(lemma_i, m) << "\n";);
|
||||
for (unsigned j = 0; j < m_use.size(); ++j) {
|
||||
m_use[j]->add_child_property(*this, lemma_i, next_level(lvl));
|
||||
}
|
||||
|
@ -1914,7 +1921,7 @@ namespace pdr {
|
|||
model_node* child = alloc(model_node, &n, n_cube, pt, n.level()-1);
|
||||
++m_stats.m_num_nodes;
|
||||
m_search.add_leaf(*child);
|
||||
IF_VERBOSE(2, verbose_stream() << "Predecessor: " << mk_pp(o_cube, m) << "\n";);
|
||||
IF_VERBOSE(3, verbose_stream() << "Predecessor: " << mk_pp(o_cube, m) << "\n";);
|
||||
m_stats.m_max_depth = std::max(m_stats.m_max_depth, child->depth());
|
||||
}
|
||||
check_pre_closed(n);
|
||||
|
|
Loading…
Reference in a new issue