mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	fix #5016
This commit is contained in:
		
							parent
							
								
									04a1d4245c
								
							
						
					
					
						commit
						083d09aa81
					
				
					 14 changed files with 366 additions and 294 deletions
				
			
		|  | @ -66,6 +66,7 @@ namespace recfun { | |||
|      */ | ||||
|     void solver::assert_macro_axiom(case_expansion & e) { | ||||
|         m_stats.m_macro_expansions++; | ||||
|         TRACEFN("case expansion " << e); | ||||
|         SASSERT(e.m_def->is_fun_macro()); | ||||
|         auto & vars = e.m_def->get_vars(); | ||||
|         auto lhs = e.m_lhs; | ||||
|  | @ -84,6 +85,14 @@ namespace recfun { | |||
|      * also body-expand paths that do not depend on any defined fun | ||||
|      */ | ||||
|     void solver::assert_case_axioms(case_expansion & e) { | ||||
|         if (e.m_def->is_fun_macro()) { | ||||
|             assert_macro_axiom(e); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         ++m_stats.m_case_expansions; | ||||
|         TRACEFN("assert_case_axioms " << e | ||||
|                 << " with " << e.m_def->get_cases().size() << " cases"); | ||||
|         SASSERT(e.m_def->is_fun_defined()); | ||||
|         // add case-axioms for all case-paths
 | ||||
|         // assert this was not defined before.
 | ||||
|  | @ -106,36 +115,41 @@ namespace recfun { | |||
|                 disable_guard(pred_applied, guards); | ||||
|                 continue; | ||||
|             } | ||||
|             activate_guard(pred_applied, guards); | ||||
|             assert_guard(pred_applied, guards); | ||||
|         } | ||||
|         add_clause(preds); | ||||
|     } | ||||
|      | ||||
|     void solver::activate_guard(expr* pred_applied, expr_ref_vector const& guards) { | ||||
|     void solver::assert_guard(expr* pred_applied, expr_ref_vector const& guards) { | ||||
|         sat::literal_vector lguards; | ||||
|         for (expr* ga : guards)  | ||||
|             lguards.push_back(mk_literal(ga)); | ||||
|         add_equiv_and(mk_literal(pred_applied), lguards); | ||||
|     } | ||||
| 
 | ||||
|     void solver::block_core(expr_ref_vector const& core) { | ||||
|         sat::literal_vector clause; | ||||
|         for (expr* e : core) | ||||
|             clause.push_back(~mk_literal(e)); | ||||
|         add_clause(clause); | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * make clause `depth_limit => ~guard` | ||||
|      * the guard appears at a depth below the current cutoff. | ||||
|      */ | ||||
|     void solver::disable_guard(expr* guard, expr_ref_vector const& guards) { | ||||
|         expr_ref nguard(m.mk_not(guard), m); | ||||
|         if (is_disabled_guard(nguard))  | ||||
|             return; | ||||
|         SASSERT(!is_enabled_guard(nguard)); | ||||
|         sat::literal_vector c; | ||||
|         SASSERT(!is_enabled_guard(guard)); | ||||
|         app_ref dlimit = m_util.mk_num_rounds_pred(m_num_rounds); | ||||
|         c.push_back(~mk_literal(dlimit)); | ||||
|         c.push_back(~mk_literal(guard));  | ||||
|         m_disabled_guards.push_back(nguard); | ||||
|         SASSERT(!m_guard2pending.contains(nguard)); | ||||
|         m_guard2pending.insert(nguard, alloc(expr_ref_vector, guards)); | ||||
|         TRACEFN("add clause\n" << c); | ||||
|         m_propagation_queue.push_back(alloc(propagation_item, c)); | ||||
|         expr_ref_vector core(m); | ||||
|         core.push_back(dlimit); | ||||
|         core.push_back(guard); | ||||
|         if (!m_guard2pending.contains(guard)) { | ||||
|             m_disabled_guards.push_back(guard); | ||||
|             m_guard2pending.insert(guard, alloc(expr_ref_vector, guards)); | ||||
|         } | ||||
|         TRACEFN("add clause\n" << core); | ||||
|         push_core(core); | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|  | @ -147,6 +161,7 @@ namespace recfun { | |||
|      * | ||||
|      */ | ||||
|     void solver::assert_body_axiom(body_expansion & e) { | ||||
|         ++m_stats.m_body_expansions; | ||||
|         recfun::def & d = *e.m_cdef->get_def(); | ||||
|         auto & vars = d.get_vars(); | ||||
|         auto & args = e.m_args; | ||||
|  | @ -184,11 +199,6 @@ namespace recfun { | |||
|         return out << "disabled guards:\n" << m_disabled_guards << "\n"; | ||||
|     } | ||||
| 
 | ||||
|     std::ostream& solver::display_constraint(std::ostream& out, sat::ext_constraint_idx idx) const { | ||||
|         UNREACHABLE(); | ||||
|         return out; | ||||
|     } | ||||
| 
 | ||||
|     void solver::collect_statistics(statistics& st) const { | ||||
|         st.update("recfun macro expansion", m_stats.m_macro_expansions); | ||||
|         st.update("recfun case expansion", m_stats.m_case_expansions); | ||||
|  | @ -196,53 +206,35 @@ namespace recfun { | |||
|     } | ||||
| 
 | ||||
|     euf::th_solver* solver::clone(euf::solver& ctx) { | ||||
|         return nullptr; | ||||
|         return alloc(solver, ctx); | ||||
|     } | ||||
| 
 | ||||
|     bool solver::unit_propagate() { | ||||
|         force_push(); | ||||
|         if (m_qhead == m_propagation_queue.size()) | ||||
|             return false; | ||||
|         ctx.push(value_trail<unsigned>(m_qhead)); | ||||
|         for (; m_qhead < m_propagation_queue.size() && !s().inconsistent(); ++m_qhead) { | ||||
|             auto& p = *m_propagation_queue[m_qhead]; | ||||
|             if (p.is_guard()) { | ||||
|                 expr* ng = nullptr; | ||||
|                 VERIFY(m.is_not(p.m_guard, ng)); | ||||
|                 activate_guard(ng, *m_guard2pending[p.m_guard]); | ||||
|             } | ||||
|             else if (p.is_clause()) { | ||||
|                 add_clause(p.m_clause); | ||||
|             } | ||||
|             else if (p.is_case()) { | ||||
|                 recfun::case_expansion& e = *p.m_case; | ||||
|                 if (e.m_def->is_fun_macro())  | ||||
|                     assert_macro_axiom(e); | ||||
|                 else  | ||||
|                     assert_case_axioms(e);                 | ||||
|                 ++m_stats.m_case_expansions; | ||||
|             }  | ||||
|             else { | ||||
|                 SASSERT(p.is_body()); | ||||
|                 assert_body_axiom(*p.m_body); | ||||
|                 ++m_stats.m_body_expansions; | ||||
|             }                 | ||||
|             if (p.is_guard())  | ||||
|                 assert_guard(p.guard(), *m_guard2pending[p.guard()]); | ||||
|             else if (p.is_core())  | ||||
|                 block_core(p.core()); | ||||
|             else if (p.is_case())  | ||||
|                 assert_case_axioms(p.case_ex()); | ||||
|             else  | ||||
|                 assert_body_axiom(p.body()); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     void solver::push_body_expand(expr* e) { | ||||
|         auto* b = alloc(body_expansion, u(), to_app(e)); | ||||
|         m_propagation_queue.push_back(alloc(propagation_item, b)); | ||||
|         ctx.push(push_back_vector<scoped_ptr_vector<propagation_item>>(m_propagation_queue)); | ||||
|     } | ||||
| 
 | ||||
|     void solver::push_case_expand(expr* e) { | ||||
|         auto* c = alloc(case_expansion, u(), to_app(e)); | ||||
|         m_propagation_queue.push_back(alloc(propagation_item, c)); | ||||
|     void solver::push(propagation_item* p) { | ||||
|         m_propagation_queue.push_back(p);          | ||||
|         ctx.push(push_back_vector<scoped_ptr_vector<propagation_item>>(m_propagation_queue));         | ||||
|     } | ||||
| 
 | ||||
|     sat::literal solver::internalize(expr* e, bool sign, bool root, bool redundant) { | ||||
|         force_push(); | ||||
|         SASSERT(m.is_bool(e)); | ||||
|         if (!visit_rec(m, e, sign, root, redundant)) { | ||||
|             TRACE("array", tout << mk_pp(e, m) << "\n";); | ||||
|  | @ -255,6 +247,7 @@ namespace recfun { | |||
|     } | ||||
| 
 | ||||
|     void solver::internalize(expr* e, bool redundant) { | ||||
|         force_push(); | ||||
|         visit_rec(m, e, false, false, redundant); | ||||
|     } | ||||
| 
 | ||||
|  | @ -268,8 +261,6 @@ namespace recfun { | |||
|             return true; | ||||
|         if (!is_app(e) || to_app(e)->get_family_id() != get_id()) { | ||||
|             ctx.internalize(e, m_is_redundant); | ||||
|             euf::enode* n = expr2enode(e); | ||||
|             // TODO ensure_var(n);
 | ||||
|             return true; | ||||
|         } | ||||
|         m_stack.push_back(sat::eframe(e)); | ||||
|  | @ -284,35 +275,57 @@ namespace recfun { | |||
|             n = mk_enode(e, false); | ||||
|         SASSERT(!n->is_attached_to(get_id())); | ||||
|         mk_var(n); | ||||
| #if 0 | ||||
|         for (auto* arg : euf::enode_args(n)) | ||||
|             ensure_var(arg);   | ||||
|         switch (a->get_decl_kind()) { | ||||
|         default: | ||||
|             UNREACHABLE(); | ||||
|             break;             | ||||
|         } | ||||
| #endif | ||||
|         if (u().is_defined(e) && u().has_defs())  | ||||
|             push_case_expand(e); | ||||
| 
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     euf::theory_var solver::mk_var(euf::enode* n) { | ||||
|         return euf::null_theory_var; | ||||
|     } | ||||
| 
 | ||||
|     void solver::init_search() { | ||||
| 
 | ||||
|     void solver::add_assumptions() { | ||||
|         if (u().has_defs() || m_disabled_guards.empty()) { | ||||
|             app_ref dlimit = m_util.mk_num_rounds_pred(m_num_rounds); | ||||
|             TRACEFN("add_theory_assumption " << dlimit); | ||||
|             s().assign_scoped(mk_literal(dlimit)); | ||||
|             for (auto g : m_disabled_guards) | ||||
|                 s().assign_scoped(~mk_literal(g)); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     void solver::finalize_model(model& mdl) { | ||||
|          | ||||
|     bool solver::should_research(sat::literal_vector const& core) { | ||||
|         bool found = false; | ||||
|         unsigned min_gen = UINT_MAX; | ||||
|         expr* to_delete = nullptr; | ||||
|         unsigned n = 0; | ||||
|         for (sat::literal lit : core) { | ||||
|             expr* e = ctx.bool_var2expr(lit.var()); | ||||
|             if (lit.sign() && is_disabled_guard(e)) { | ||||
|                 found = true; | ||||
|                 unsigned gen = ctx.get_max_generation(e); | ||||
|                 if (gen < min_gen)  | ||||
|                     n = 0; | ||||
| 
 | ||||
|                 if (gen <= min_gen && s().rand()() % (++n) == 0) { | ||||
|                     to_delete = e; | ||||
|                     min_gen = gen; | ||||
|                 } | ||||
|             } | ||||
|             else if (u().is_num_rounds(e))  | ||||
|                 found = true; | ||||
|         } | ||||
|         if (found) { | ||||
|             ++m_num_rounds; | ||||
|             if (to_delete) { | ||||
|                 m_disabled_guards.erase(to_delete); | ||||
|                 m_enabled_guards.push_back(to_delete); | ||||
|                 push_guard(to_delete); | ||||
|                 IF_VERBOSE(2, verbose_stream() << "(smt.recfun :enable-guard " << mk_pp(to_delete, m) << ")\n"); | ||||
|             } | ||||
|             else { | ||||
|                 IF_VERBOSE(2, verbose_stream() << "(smt.recfun :increment-round)\n"); | ||||
|             } | ||||
|             for (expr* g : m_enabled_guards) | ||||
|                 push_guard(g); | ||||
|         } | ||||
|         return found; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|      | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue