mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 12:08:18 +00:00
generalize macro head detection and elaboration
This commit is contained in:
parent
fcaa85d7a8
commit
b9f34286a7
|
@ -22,6 +22,7 @@ The simplifier
|
||||||
{a}, {b}, {~a,~b}, C, D and checks for an unsat core.
|
{a}, {b}, {~a,~b}, C, D and checks for an unsat core.
|
||||||
The core {a}, {b}, {~a, ~b} maps back to a definition for p
|
The core {a}, {b}, {~a, ~b} maps back to a definition for p
|
||||||
Then {p, C}, {~p, D} clauses are replaced based on the definition.
|
Then {p, C}, {~p, D} clauses are replaced based on the definition.
|
||||||
|
Claim: {C, D} is a consequence when we have created resolvents {C,X}, {D,Y}, where X => p => Y => X
|
||||||
(a task for a "Kitten"?)
|
(a task for a "Kitten"?)
|
||||||
- Handle various permutations of variables that are arguments to p?
|
- Handle various permutations of variables that are arguments to p?
|
||||||
- other SMT-based macro detection could be made here as well.
|
- other SMT-based macro detection could be made here as well.
|
||||||
|
@ -45,6 +46,7 @@ forbidden from macros vs forbidden from elimination
|
||||||
--*/
|
--*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "util/uint_set.h"
|
||||||
#include "ast/ast_pp.h"
|
#include "ast/ast_pp.h"
|
||||||
#include "ast/ast_ll_pp.h"
|
#include "ast/ast_ll_pp.h"
|
||||||
#include "ast/ast_util.h"
|
#include "ast/ast_util.h"
|
||||||
|
@ -56,7 +58,6 @@ forbidden from macros vs forbidden from elimination
|
||||||
#include "ast/rewriter/rewriter_def.h"
|
#include "ast/rewriter/rewriter_def.h"
|
||||||
#include "ast/simplifiers/eliminate_predicates.h"
|
#include "ast/simplifiers/eliminate_predicates.h"
|
||||||
#include "ast/rewriter/th_rewriter.h"
|
#include "ast/rewriter/th_rewriter.h"
|
||||||
#include "ast/macros/macro_util.h"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -195,6 +196,49 @@ void eliminate_predicates::add_use_list(clause& cl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that all arguments are distinct variables that are bound.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool eliminate_predicates::can_be_macro_head(app* head, unsigned num_bound) {
|
||||||
|
uint_set indices;
|
||||||
|
if (head->get_decl()->is_associative())
|
||||||
|
return false;
|
||||||
|
for (expr* arg : *head) {
|
||||||
|
if (!is_var(arg))
|
||||||
|
return false;
|
||||||
|
unsigned idx = to_var(arg)->get_idx();
|
||||||
|
if (indices.contains(idx))
|
||||||
|
return false;
|
||||||
|
if (idx >= num_bound)
|
||||||
|
return false;
|
||||||
|
indices.insert(idx);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr_ref eliminate_predicates::bind_free_variables_in_def(clause& cl, app* head, expr* def) {
|
||||||
|
unsigned num_bound = cl.m_bound.size();
|
||||||
|
if (head->get_num_args() == num_bound)
|
||||||
|
return expr_ref(def, m);
|
||||||
|
|
||||||
|
// head(x) <=> forall yx', x = x' => def(yx')
|
||||||
|
svector<symbol> names;
|
||||||
|
expr_ref_vector ors(m);
|
||||||
|
expr_ref result(m);
|
||||||
|
ors.push_back(def);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < num_bound; ++i)
|
||||||
|
names.push_back(symbol(i));
|
||||||
|
for (expr* arg : *head) {
|
||||||
|
unsigned idx = to_var(arg)->get_idx();
|
||||||
|
ors.push_back(m.mk_not(m.mk_eq(arg, m.mk_var(idx + num_bound, arg->get_sort()))));
|
||||||
|
}
|
||||||
|
result = mk_or(ors);
|
||||||
|
result = m.mk_forall(num_bound, cl.m_bound.data(), names.data(), result);
|
||||||
|
rewrite(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* cheap/simplistic heuristic to find definitions that are based on binary clauses
|
* cheap/simplistic heuristic to find definitions that are based on binary clauses
|
||||||
* (or (head x) (not (def x))
|
* (or (head x) (not (def x))
|
||||||
|
@ -204,13 +248,12 @@ bool eliminate_predicates::try_find_binary_definition(func_decl* p, app_ref& hea
|
||||||
if (m_disable_macro.is_marked(p))
|
if (m_disable_macro.is_marked(p))
|
||||||
return false;
|
return false;
|
||||||
expr_mark binary_pos, binary_neg;
|
expr_mark binary_pos, binary_neg;
|
||||||
macro_util mutil(m);
|
|
||||||
obj_map<expr, expr_dependency*> deps;
|
obj_map<expr, expr_dependency*> deps;
|
||||||
auto is_def_predicate = [&](expr* atom) {
|
auto is_def_predicate = [&](clause& cl, expr* atom) {
|
||||||
return is_app(atom) && to_app(atom)->get_decl() == p && mutil.is_macro_head(atom, p->get_arity());
|
return is_app(atom) && to_app(atom)->get_decl() == p && can_be_macro_head(to_app(atom), cl.m_bound.size());
|
||||||
};
|
};
|
||||||
auto add_def = [&](clause& cl, expr* atom1, bool sign1, expr* atom2, bool sign2) {
|
auto add_def = [&](clause& cl, expr* atom1, bool sign1, expr* atom2, bool sign2) {
|
||||||
if (is_def_predicate(atom1) && !sign1) {
|
if (is_def_predicate(cl, atom1) && !sign1) {
|
||||||
if (sign2)
|
if (sign2)
|
||||||
binary_neg.mark(atom2);
|
binary_neg.mark(atom2);
|
||||||
else
|
else
|
||||||
|
@ -233,10 +276,10 @@ bool eliminate_predicates::try_find_binary_definition(func_decl* p, app_ref& hea
|
||||||
auto const& [atom1, sign1] = cl.m_literals[i];
|
auto const& [atom1, sign1] = cl.m_literals[i];
|
||||||
auto const& [atom2, sign2] = cl.m_literals[j];
|
auto const& [atom2, sign2] = cl.m_literals[j];
|
||||||
expr_dependency* d = nullptr;
|
expr_dependency* d = nullptr;
|
||||||
if (is_def_predicate(atom1) && sign1) {
|
if (is_def_predicate(cl, atom1) && sign1) {
|
||||||
if (sign2 && binary_pos.is_marked(atom2) && is_macro_safe(atom2) && !occurs(p, atom2)) {
|
if (sign2 && binary_pos.is_marked(atom2) && is_macro_safe(atom2) && !occurs(p, atom2)) {
|
||||||
head = to_app(atom1);
|
head = to_app(atom1);
|
||||||
def = m.mk_not(atom2);
|
def = bind_free_variables_in_def(cl, head, m.mk_not(atom2));
|
||||||
dep = cl.m_dep;
|
dep = cl.m_dep;
|
||||||
if (deps.find(atom1, d))
|
if (deps.find(atom1, d))
|
||||||
dep = m.mk_join(dep, d);
|
dep = m.mk_join(dep, d);
|
||||||
|
@ -244,7 +287,7 @@ bool eliminate_predicates::try_find_binary_definition(func_decl* p, app_ref& hea
|
||||||
}
|
}
|
||||||
if (!sign2 && binary_neg.is_marked(atom2) && is_macro_safe(atom2) && !occurs(p, atom2)) {
|
if (!sign2 && binary_neg.is_marked(atom2) && is_macro_safe(atom2) && !occurs(p, atom2)) {
|
||||||
head = to_app(atom1);
|
head = to_app(atom1);
|
||||||
def = atom2;
|
def = bind_free_variables_in_def(cl, head, atom2);
|
||||||
dep = cl.m_dep;
|
dep = cl.m_dep;
|
||||||
if (deps.find(atom1, d))
|
if (deps.find(atom1, d))
|
||||||
dep = m.mk_join(dep, d);
|
dep = m.mk_join(dep, d);
|
||||||
|
|
|
@ -107,6 +107,8 @@ private:
|
||||||
void try_resolve_definition(func_decl* p);
|
void try_resolve_definition(func_decl* p);
|
||||||
void insert_macro(app_ref& head, expr_ref& def, expr_dependency_ref& dep);
|
void insert_macro(app_ref& head, expr_ref& def, expr_dependency_ref& dep);
|
||||||
bool has_macro(func_decl* p, app_ref& head, expr_ref& def, expr_dependency_ref& dep);
|
bool has_macro(func_decl* p, app_ref& head, expr_ref& def, expr_dependency_ref& dep);
|
||||||
|
expr_ref bind_free_variables_in_def(clause& cl, app* head, expr* def);
|
||||||
|
bool can_be_macro_head(app* head, unsigned num_bound);
|
||||||
bool is_macro_safe(expr* e);
|
bool is_macro_safe(expr* e);
|
||||||
|
|
||||||
void try_resolve(func_decl* p);
|
void try_resolve(func_decl* p);
|
||||||
|
|
Loading…
Reference in a new issue