mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 19:52:29 +00:00 
			
		
		
		
	add comments
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									2bb22c6489
								
							
						
					
					
						commit
						d0a7b19806
					
				
					 1 changed files with 72 additions and 2 deletions
				
			
		|  | @ -25,6 +25,10 @@ Revision History: | ||||||
| 
 | 
 | ||||||
| namespace smt { | namespace smt { | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |     Constructor. | ||||||
|  |     Set up callback that adds axiom instantiations as clauses.  | ||||||
|  |     **/ | ||||||
|     theory_finite_set::theory_finite_set(context& ctx): |     theory_finite_set::theory_finite_set(context& ctx): | ||||||
|         theory(ctx, ctx.get_manager().mk_family_id("finite_set")), |         theory(ctx, ctx.get_manager().mk_family_id("finite_set")), | ||||||
|         u(m), |         u(m), | ||||||
|  | @ -38,6 +42,24 @@ namespace smt { | ||||||
|         m_axioms.set_add_clause(add_clause_fn); |         m_axioms.set_add_clause(add_clause_fn); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |     * Boolean atomic formulas for finite sets are one of: | ||||||
|  |     * (set.in x S) | ||||||
|  |     * (set.subset S T) | ||||||
|  |     * When an atomic formula is first created it is to be registered with the solver. | ||||||
|  |     * The internalize_atom method takes care of this. | ||||||
|  |     * Atomic formulas are special cases of terms (of non-Boolean type) so the first  | ||||||
|  |     * effect is to register the atom as a term. | ||||||
|  |     * The second effect is to set up tracking and assert axioms. | ||||||
|  |     * Tracking: | ||||||
|  |     *    For every occurrence (set.in x_i S_i) we track x_i.  | ||||||
|  |     * Axioms: | ||||||
|  |     *    We can immediately assert some axioms because they are unit literals: | ||||||
|  |     *    - (set.in x set.empty) is false | ||||||
|  |     *    - (set.subset S T) <=> (= (set.union S T) T)  (or (= (set.intersect S T) S)) | ||||||
|  |     *    Axioms can be deffered to when the atomic formulas become "relevant" for the theory solver. | ||||||
|  |     *     | ||||||
|  |     */ | ||||||
|     bool theory_finite_set::internalize_atom(app * atom, bool gate_ctx) { |     bool theory_finite_set::internalize_atom(app * atom, bool gate_ctx) { | ||||||
|         TRACE(finite_set, tout << "internalize_atom: " << mk_pp(atom, m) << "\n";); |         TRACE(finite_set, tout << "internalize_atom: " << mk_pp(atom, m) << "\n";); | ||||||
| 
 | 
 | ||||||
|  | @ -52,10 +74,22 @@ namespace smt { | ||||||
|                 ctx.push_trail(insert_obj_trail(m_elements, n)); |                 ctx.push_trail(insert_obj_trail(m_elements, n)); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         // Assert immediate axioms
 | ||||||
|  |         // add_immediate_axioms(atom);
 | ||||||
|          |          | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * When terms are registered with the solver , we need to ensure that: | ||||||
|  |      * - All subterms have an associated E-node | ||||||
|  |      * - Boolean terms are registered as boolean variables | ||||||
|  |      *   Registering a Boolean variable ensures that the solver will be notified about its truth value. | ||||||
|  |      * - Non-Boolean terms have an associated theory variable | ||||||
|  |      *   Registering a theory variable ensures that the solver will be notified about equalities and disequalites. | ||||||
|  |      *   The solver can use the theory variable to track auxiliary information about E-nodes.     | ||||||
|  |     */ | ||||||
|     bool theory_finite_set::internalize_term(app * term) { |     bool theory_finite_set::internalize_term(app * term) { | ||||||
|         TRACE(finite_set, tout << "internalize_term: " << mk_pp(term, m) << "\n";); |         TRACE(finite_set, tout << "internalize_term: " << mk_pp(term, m) << "\n";); | ||||||
|          |          | ||||||
|  | @ -95,6 +129,17 @@ namespace smt { | ||||||
|         // For now, we rely on the final_check to handle this
 |         // For now, we rely on the final_check to handle this
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |     * Final check for the finite set theory. | ||||||
|  |      * The Final Check method is called when the solver has assigned truth values to all Boolean variables. | ||||||
|  |      * It is responsible for asserting any remaining axioms and checking for inconsistencies. | ||||||
|  |      *  | ||||||
|  |      * It ensures saturation with respect to the theory axioms: | ||||||
|  |      * - Set membership is saturated with respect to set operations. | ||||||
|  |      *    For every (set.in x S) where S is a union, assert (or propagate) (set.in x S1) or (set.in x S2) | ||||||
|  |      * - It saturates with respect to extensionality: | ||||||
|  |      *   Sets corresponding to shared variables having the same interpretation should also be congruent | ||||||
|  |     */ | ||||||
|     final_check_status theory_finite_set::final_check_eh() { |     final_check_status theory_finite_set::final_check_eh() { | ||||||
|         TRACE(finite_set, tout << "final_check_eh\n";); |         TRACE(finite_set, tout << "final_check_eh\n";); | ||||||
| 
 | 
 | ||||||
|  | @ -102,6 +147,7 @@ namespace smt { | ||||||
|         // if a parent is of the form elem' in S u T, or similar.
 |         // if a parent is of the form elem' in S u T, or similar.
 | ||||||
|         // create clauses for elem in S u T.
 |         // create clauses for elem in S u T.
 | ||||||
| 
 | 
 | ||||||
|  |         // Saturate membership constraints
 | ||||||
|         expr* elem1 = nullptr, *set1 = nullptr; |         expr* elem1 = nullptr, *set1 = nullptr; | ||||||
|         for (auto elem : m_elements) { |         for (auto elem : m_elements) { | ||||||
|             if (!ctx.is_relevant(elem)) |             if (!ctx.is_relevant(elem)) | ||||||
|  | @ -124,9 +170,13 @@ namespace smt { | ||||||
|         if (instantiate_free_lemma()) |         if (instantiate_free_lemma()) | ||||||
|             return FC_CONTINUE; |             return FC_CONTINUE; | ||||||
|          |          | ||||||
|  |         // TODO: Extensionality axioms for sets
 | ||||||
|         return FC_DONE; |         return FC_DONE; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |     * Instantiate axioms for a given element in a set. | ||||||
|  |     */ | ||||||
|     void theory_finite_set::instantiate_axioms(expr* elem, expr* set) { |     void theory_finite_set::instantiate_axioms(expr* elem, expr* set) { | ||||||
|         TRACE(finite_set, tout << "instantiate_axioms: " << mk_pp(elem, m) << " in " << mk_pp(set, m) << "\n";); |         TRACE(finite_set, tout << "instantiate_axioms: " << mk_pp(elem, m) << " in " << mk_pp(set, m) << "\n";); | ||||||
|          |          | ||||||
|  | @ -206,6 +256,12 @@ namespace smt { | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |     * Lemmas that are currently assinged to false are conflicts.  | ||||||
|  |     * They should be asserted as soon as possible. | ||||||
|  |     * Only the first conflict needs to be asserted. | ||||||
|  |     *  | ||||||
|  |     */ | ||||||
|     bool theory_finite_set::instantiate_false_lemma() { |     bool theory_finite_set::instantiate_false_lemma() { | ||||||
|         for (auto const& clause : m_lemmas) { |         for (auto const& clause : m_lemmas) { | ||||||
|             bool all_false = all_of(clause, [&](expr *e) { return ctx.find_assignment(e) == l_false; }); |             bool all_false = all_of(clause, [&](expr *e) { return ctx.find_assignment(e) == l_false; }); | ||||||
|  | @ -217,7 +273,15 @@ namespace smt { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Lemmas that are unit propagating should be asserted as possible and can be asserted in a batch. | ||||||
|  |      * It is possible to assert a unit propagating lemma as a clause. | ||||||
|  |      * A more efficient approach is to add a Theory propagation with the solver. | ||||||
|  |      * A theory propagation gets recorded on the assignment trail and the overhead of undoing it is baked in to backtracking. | ||||||
|  |      * A theory axiom is also removed during backtracking. | ||||||
|  |     */ | ||||||
|     bool theory_finite_set::instantiate_unit_propagation() { |     bool theory_finite_set::instantiate_unit_propagation() { | ||||||
|  |         bool propagaed = false; | ||||||
|         for (auto const &clause : m_lemmas) { |         for (auto const &clause : m_lemmas) { | ||||||
|             expr *undef = nullptr; |             expr *undef = nullptr; | ||||||
|             bool is_unit_propagating = true; |             bool is_unit_propagating = true; | ||||||
|  | @ -237,11 +301,17 @@ namespace smt { | ||||||
|             if (!is_unit_propagating || undef == nullptr) |             if (!is_unit_propagating || undef == nullptr) | ||||||
|                 continue;       |                 continue;       | ||||||
|             assert_clause(clause); |             assert_clause(clause); | ||||||
|             return true; |             propagated = true; | ||||||
|         } |         } | ||||||
|         return false; |         return propagated; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * We assume the lemmas in the queue are necessary for completeness. | ||||||
|  |      * So they all have to be enforced through case analysis. | ||||||
|  |      * Lemmas with more than one unassigned literal are asserted here. | ||||||
|  |      * The solver will case split on the unassigned literals to satisfy the lemma. | ||||||
|  |     */ | ||||||
|     bool theory_finite_set::instantiate_free_lemma() { |     bool theory_finite_set::instantiate_free_lemma() { | ||||||
|         for (auto const& clause : m_lemmas) { |         for (auto const& clause : m_lemmas) { | ||||||
|             if (any_of(clause, [&](expr *e) { return ctx.find_assignment(e) == l_true; })) |             if (any_of(clause, [&](expr *e) { return ctx.find_assignment(e) == l_true; })) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue