mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 03:32:28 +00:00 
			
		
		
		
	bug fixes
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									c832802183
								
							
						
					
					
						commit
						d847a28589
					
				
					 10 changed files with 118 additions and 76 deletions
				
			
		|  | @ -843,7 +843,7 @@ class FuncDeclRef(AstRef): | |||
|             elif k == Z3_PARAMETER_RATIONAL: | ||||
|                 result[i] = Z3_get_decl_rational_parameter(self.ctx_ref(), self.ast, i) | ||||
|             elif k == Z3_PARAMETER_SYMBOL: | ||||
|                 result[i] = Z3_get_decl_symbol_parameter(self.ctx_ref(), self.ast, i) | ||||
|                 result[i] = _symbol2py(ctx, Z3_get_decl_symbol_parameter(self.ctx_ref(), self.ast, i)) | ||||
|             elif k == Z3_PARAMETER_SORT: | ||||
|                 result[i] = SortRef(Z3_get_decl_sort_parameter(self.ctx_ref(), self.ast, i), ctx) | ||||
|             elif k == Z3_PARAMETER_AST: | ||||
|  |  | |||
|  | @ -3338,26 +3338,12 @@ proof * ast_manager::mk_th_lemma( | |||
|     if (proofs_disabled()) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     proof_ref pr(*this); | ||||
|     ptr_buffer<expr> args; | ||||
|     vector<parameter> parameters; | ||||
|     parameters.push_back(parameter(get_family_name(tid))); | ||||
|     for (unsigned i = 0; i < num_params; ++i) { | ||||
|         auto const &p = params[i]; | ||||
|         parameters.push_back(p); | ||||
|         if (p.is_symbol()) | ||||
|             args.push_back(mk_app(p.get_symbol(), 0, nullptr, mk_proof_sort())); | ||||
|         else if (p.is_ast() && is_expr(p.get_ast())) | ||||
|             args.push_back(to_expr(p.get_ast())); | ||||
|         else if (p.is_rational()) { | ||||
|             arith_util autil(*this); | ||||
|             args.push_back(autil.mk_real(p.get_rational())); | ||||
|         }      | ||||
|     } | ||||
|     pr = mk_app(get_family_name(tid), args.size(), args.data(), mk_proof_sort()); | ||||
|     args.reset(); | ||||
|     for (unsigned i = 0; i < num_params; ++i)  | ||||
|         parameters.push_back(params[i]);         | ||||
|     ptr_buffer<expr> args; | ||||
|     args.append(num_proofs, (expr**) proofs); | ||||
|     args.push_back(pr.get()); | ||||
|     args.push_back(fact); | ||||
|     return mk_app(basic_family_id, PR_TH_LEMMA, parameters.size(), parameters.data(), args.size(), args.data()); | ||||
| } | ||||
|  |  | |||
|  | @ -2328,7 +2328,7 @@ public: | |||
|     unsigned get_num_parents(proof const * p) const { | ||||
|         SASSERT(is_proof(p)); | ||||
|         unsigned n = p->get_num_args(); | ||||
|         return p->get_decl()->get_decl_kind() == PR_TH_LEMMA ? n - 2 : !has_fact(p) ? n : n - 1; | ||||
|         return !has_fact(p) ? n : n - 1; | ||||
|     } | ||||
|     proof * get_parent(proof const * p, unsigned idx) const { SASSERT(is_proof(p)); return to_app(p->get_arg(idx)); } | ||||
|     proof * mk_true_proof(); | ||||
|  |  | |||
|  | @ -70,7 +70,7 @@ void finite_set_decl_plugin::init() { | |||
|     m_sigs[OP_FINITE_SET_MAP]        = alloc(polymorphism::psig, m, "set.map",        2, 2, arrABsetA, setB); | ||||
|     m_sigs[OP_FINITE_SET_FILTER]     = alloc(polymorphism::psig, m, "set.filter",     1, 2, arrABoolsetA, setA); | ||||
|     m_sigs[OP_FINITE_SET_RANGE]      = alloc(polymorphism::psig, m, "set.range",      0, 2, intintT, setInt); | ||||
|     m_sigs[OP_FINITE_SET_DIFF]       = alloc(polymorphism::psig, m, "set.diff", 1, 2, setAsetA, A); | ||||
|     m_sigs[OP_FINITE_SET_EXT]       = alloc(polymorphism::psig, m, "set.diff", 1, 2, setAsetA, A); | ||||
| //    m_sigs[OP_FINITE_SET_MAP_INVERSE] = alloc(polymorphism::psig, m, "set.map_inverse", 2, 3, arrABsetBsetA, A);
 | ||||
| } | ||||
| 
 | ||||
|  | @ -179,7 +179,7 @@ func_decl * finite_set_decl_plugin::mk_func_decl(decl_kind k, unsigned num_param | |||
|     case OP_FINITE_SET_MAP: | ||||
|     case OP_FINITE_SET_FILTER: | ||||
|     case OP_FINITE_SET_RANGE: | ||||
|     case OP_FINITE_SET_DIFF: | ||||
|     case OP_FINITE_SET_EXT: | ||||
|         return mk_finite_set_op(k, arity, domain, range); | ||||
|     default: | ||||
|         return nullptr; | ||||
|  |  | |||
|  | @ -47,7 +47,7 @@ enum finite_set_op_kind { | |||
|     OP_FINITE_SET_MAP, | ||||
|     OP_FINITE_SET_FILTER, | ||||
|     OP_FINITE_SET_RANGE, | ||||
|     OP_FINITE_SET_DIFF, | ||||
|     OP_FINITE_SET_EXT, | ||||
|     OP_FINITE_SET_MAP_INVERSE, | ||||
|     LAST_FINITE_SET_OP | ||||
| }; | ||||
|  | @ -154,6 +154,11 @@ public: | |||
|      | ||||
|     ast_manager& get_manager() const { return m_manager; } | ||||
| 
 | ||||
|     sort *mk_finite_set_sort(sort *elem_sort) { | ||||
|         parameter param(elem_sort); | ||||
|         return m_manager.mk_sort(m_fid, FINITE_SET_SORT, 1, ¶m); | ||||
|     } | ||||
| 
 | ||||
|     app * mk_empty(sort* set_sort) { | ||||
|         parameter param(set_sort); | ||||
|         return m_manager.mk_app(m_fid, OP_FINITE_SET_EMPTY, 1, ¶m, 0, nullptr); | ||||
|  | @ -175,6 +180,10 @@ public: | |||
|         return m_manager.mk_app(m_fid, OP_FINITE_SET_DIFFERENCE, s1, s2); | ||||
|     } | ||||
| 
 | ||||
|     app *mk_ext(expr *s1, expr *s2) { | ||||
|         return m_manager.mk_app(m_fid, OP_FINITE_SET_EXT, s1, s2); | ||||
|     } | ||||
| 
 | ||||
|     app * mk_in(expr* elem, expr* set) { | ||||
|         return m_manager.mk_app(m_fid, OP_FINITE_SET_IN, elem, set); | ||||
|     } | ||||
|  |  | |||
|  | @ -27,7 +27,10 @@ Revision History: | |||
| 
 | ||||
| 
 | ||||
| std::ostream& operator<<(std::ostream& out, theory_axiom const& ax) { | ||||
|     return out << "axiom"; | ||||
|     auto &m = ax.clause.get_manager(); | ||||
|     for (auto e : ax.clause) | ||||
|         out << mk_pp(e, m) << " "; | ||||
|     return out; | ||||
| } | ||||
| 
 | ||||
| // a ~ set.empty => not (x in a)
 | ||||
|  | @ -36,7 +39,8 @@ void finite_set_axioms::in_empty_axiom(expr *x) { | |||
|     // Generate: not (x in empty_set)
 | ||||
|     // where empty_set is the empty set of x's type
 | ||||
|     sort* elem_sort = x->get_sort(); | ||||
|     expr_ref empty_set(u.mk_empty(elem_sort), m); | ||||
|     sort *set_sort = u.mk_finite_set_sort(elem_sort); | ||||
|     expr_ref empty_set(u.mk_empty(set_sort), m); | ||||
|     expr_ref x_in_empty(u.mk_in(x, empty_set), m); | ||||
|      | ||||
|     theory_axiom* ax = alloc(theory_axiom, m, "in-empty", x); | ||||
|  | @ -357,7 +361,7 @@ void finite_set_axioms::subset_axiom(expr* a) { | |||
| 
 | ||||
| void finite_set_axioms::extensionality_axiom(expr *a, expr* b) { | ||||
|     // a != b => set.in (set.diff(a, b) a) != set.in (set.diff(a, b) b)
 | ||||
|     expr_ref diff_ab(u.mk_difference(a, b), m); | ||||
|     expr_ref diff_ab(u.mk_ext(a, b), m); | ||||
| 
 | ||||
|     expr_ref a_eq_b(m.mk_eq(a, b), m); | ||||
|     expr_ref diff_in_a(u.mk_in(diff_ab, a), m); | ||||
|  | @ -370,9 +374,9 @@ void finite_set_axioms::extensionality_axiom(expr *a, expr* b) { | |||
|     ax->clause.push_back(m.mk_not(diff_in_b)); | ||||
|     m_add_clause(ax); | ||||
| 
 | ||||
|     theory_axiom* ax2 = alloc(theory_axiom, m, "extensionality", a, b); | ||||
|     ax2->clause.push_back(m.mk_not(a_eq_b)); | ||||
|     ax2->clause.push_back(diff_in_a); | ||||
|     ax2->clause.push_back(diff_in_b); | ||||
|     m_add_clause(ax2); | ||||
|     ax = alloc(theory_axiom, m, "extensionality", a, b); | ||||
|     ax->clause.push_back(a_eq_b); | ||||
|     ax->clause.push_back(diff_in_a); | ||||
|     ax->clause.push_back(diff_in_b); | ||||
|     m_add_clause(ax); | ||||
| } | ||||
|  | @ -11,7 +11,7 @@ Abstract: | |||
| 
 | ||||
| Author: | ||||
| 
 | ||||
|     GitHub Copilot Agent 2025 | ||||
|     Nikolaj Bjorner (nbjorner) - October 2025 | ||||
| 
 | ||||
| --*/ | ||||
| 
 | ||||
|  | @ -222,6 +222,44 @@ br_status finite_set_rewriter::mk_in(expr * elem, expr * set, expr_ref & result) | |||
|         result = m.mk_eq(elem, singleton_elem); | ||||
|         return BR_REWRITE1; | ||||
|     } | ||||
|     // NB we don't rewrite (set.in x (set.union s t)) to (or (set.in x s) (set.in x t))
 | ||||
|     // because it creates two new sub-expressions. The expression (set.union s t) could
 | ||||
|     // be shared with other expressions so the net effect of this rewrite could be to create
 | ||||
|     // a larger formula for the solver.
 | ||||
|     return BR_FAILED; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
| * if a, b are set expressions we can create an on-the-fly heap for their min-elements | ||||
| * a, b are normalized to the form (set.union s t) or (set.empty) where  | ||||
| * s is a singleton or range expression such that every element in t are above s. | ||||
| * we distinguish numerical values from value expressions: | ||||
| * - for numerical values we use the ordering over numerals to pick minimal ranges | ||||
| * - for unique value expressions ranging over non-numerals use expression identifiers | ||||
| * - for other expressions use identifiers to sort expressions, but make sure to be inconclusive | ||||
| *   for set difference | ||||
| * We want mk_eq_core to produce a result true/false if the arguments are both (unique) values. | ||||
| * This allows to evaluate models for being well-formed conclusively. | ||||
| *  | ||||
| * A way to convert a set expression to a heap is as follows: | ||||
| *  | ||||
| * min({s}) = {s} u {} | ||||
| * min({}) = {} | ||||
| * min([l..u]) = [l..u] u {} | ||||
| * min(s u t) =  | ||||
| *   let range_s u s1 = min(s) | ||||
| *   let range_t u t1 = min(t) | ||||
| *   if range_s < range_t:  | ||||
| *        range_s u (t u s1) | ||||
| *   if range_t < range_t: | ||||
| *        range_t u (s u t1) | ||||
| *   if range_t n range_s != {}: | ||||
| *        min(range_t, range_s) u the rest ... | ||||
| *   etc. | ||||
| */ | ||||
| 
 | ||||
| br_status finite_set_rewriter::mk_eq_core(expr* a, expr* b, expr_ref& result) { | ||||
| 
 | ||||
|     return BR_FAILED; | ||||
| } | ||||
|  | @ -55,5 +55,7 @@ public: | |||
|     finite_set_util& util() { return m_util; } | ||||
| 
 | ||||
|     br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);    | ||||
| 
 | ||||
|     br_status mk_eq_core(expr *a, expr *b, expr_ref &result); | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -688,6 +688,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg { | |||
|             st = m_ar_rw.mk_eq_core(a, b, result); | ||||
|         else if (s_fid == m_seq_rw.get_fid()) | ||||
|             st = m_seq_rw.mk_eq_core(a, b, result); | ||||
|         else if (s_fid == m_fs_rw.get_fid()) | ||||
|             st = m_fs_rw.mk_eq_core(a, b, result); | ||||
|         if (st != BR_FAILED) | ||||
|             return st; | ||||
|         st = extended_bv_eq(a, b, result); | ||||
|  |  | |||
|  | @ -344,6 +344,7 @@ namespace smt { | |||
|             if (u.is_size(e)) | ||||
|                 has_size = true; | ||||
|         } | ||||
|         TRACE(finite_set, tout << "has-map " << has_map << " has-filter-size " << has_filter << has_size << "\n"); | ||||
|         if (has_map) | ||||
|             return false; // todo use more expensive model check here
 | ||||
|         if (has_filter && has_size) | ||||
|  | @ -630,11 +631,11 @@ namespace smt { | |||
|     void theory_finite_set::add_membership_axioms(expr *elem, expr *set) { | ||||
|         TRACE(finite_set, tout << "add_membership_axioms: " << mk_pp(elem, m) << " in " << mk_pp(set, m) << "\n";); | ||||
| 
 | ||||
|         if (!is_new_axiom(elem, set)) | ||||
|             return; | ||||
| 
 | ||||
|         try { | ||||
|             // Instantiate appropriate axiom based on set structure
 | ||||
|         if (u.is_empty(set)) { | ||||
|             if (!is_new_axiom(elem, set)) | ||||
|                 ; | ||||
|             else if (u.is_empty(set)) { | ||||
|                 m_axioms.in_empty_axiom(elem); | ||||
|             } | ||||
|             else if (u.is_singleton(set)) { | ||||
|  | @ -659,10 +660,15 @@ namespace smt { | |||
|             else if (u.is_filter(set)) { | ||||
|                 m_axioms.in_filter_axiom(elem, set); | ||||
|             } | ||||
|         } catch (...) { | ||||
|             TRACE(finite_set, tout << "exception\n"); | ||||
|             throw; | ||||
|         } | ||||
|         TRACE(finite_set, tout << "after add_membership_axioms: " << mk_pp(elem, m) << " in " << mk_pp(set, m) << "\n";); | ||||
|     } | ||||
| 
 | ||||
|     void theory_finite_set::add_clause(theory_axiom* ax) { | ||||
|         TRACE(finite_set, tout << "add_clause: " << ax << "\n"); | ||||
|         TRACE(finite_set, tout << "add_clause: " << *ax << "\n"); | ||||
|         ctx.push_trail(push_back_vector(m_clauses.axioms)); | ||||
|         ctx.push_trail(new_obj_trail(ax)); | ||||
|         m_clauses.axioms.push_back(ax); | ||||
|  | @ -951,15 +957,10 @@ namespace smt { | |||
|                 // only propagations that are processed by conflict resolution. 
 | ||||
|                 // this misses conflicts at base level.
 | ||||
|                 proof_ref pr(m); | ||||
|                 expr_ref_vector args(m); | ||||
|                 for (auto const &p : ax->params) { | ||||
|                     if (p.is_ast()) | ||||
|                         args.push_back(to_expr(p.get_ast())); | ||||
|                     else | ||||
|                         args.push_back(m.mk_const(p.get_symbol(), m.mk_proof_sort())); | ||||
|                 } | ||||
|                  | ||||
|                 pr = m.mk_app(m.get_family_name(get_family_id()), args.size(), args.data(), m.mk_proof_sort()); | ||||
|                 proof_ref_vector args(m); | ||||
|                 for (auto a : antecedent)  | ||||
|                     args.push_back(m.mk_hypothesis(ctx.literal2expr(a)));           | ||||
|                 pr = m.mk_th_lemma(get_id(), unit, args.size(), args.data(), ax->params.size(), ax->params.data()); | ||||
|                 justification_proof_wrapper jp(ctx, pr.get(), false); | ||||
|                 ctx.get_clause_proof().propagate(lit, &jp, antecedent); | ||||
|                 jp.del_eh(m); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue