mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 03:32:28 +00:00 
			
		
		
		
	generalize macro head detection and elaboration
This commit is contained in:
		
							parent
							
								
									fcaa85d7a8
								
							
						
					
					
						commit
						b9f34286a7
					
				
					 2 changed files with 53 additions and 8 deletions
				
			
		|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue