mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 03:32:28 +00:00 
			
		
		
		
	na
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									2df104d9f0
								
							
						
					
					
						commit
						82c9aab106
					
				
					 2 changed files with 114 additions and 66 deletions
				
			
		|  | @ -53,7 +53,24 @@ namespace polysat { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     lbool solver::find_viable(unsigned var, rational & val) { |     lbool solver::find_viable(unsigned var, rational & val) { | ||||||
|         return l_false; |         val = 0; | ||||||
|  |         bdd viable = m_viable[var]; | ||||||
|  |         if (viable.is_false()) | ||||||
|  |             return l_false; | ||||||
|  |         unsigned num_vars = 0; | ||||||
|  |         while (!viable.is_true()) { | ||||||
|  |             unsigned k = viable.var(); | ||||||
|  |             if (viable.lo().is_false()) { | ||||||
|  |                 val += rational::power_of_two(k); | ||||||
|  |                 viable = viable.hi(); | ||||||
|  |             } | ||||||
|  |             else  | ||||||
|  |                 viable = viable.lo(); | ||||||
|  |             ++num_vars; | ||||||
|  |         } | ||||||
|  |         if (num_vars == size(var)) | ||||||
|  |             return l_true; | ||||||
|  |         return l_undef; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -68,7 +85,7 @@ namespace polysat { | ||||||
|         m_trail(s), |         m_trail(s), | ||||||
|         m_bdd(1000), |         m_bdd(1000), | ||||||
|         m_dep_manager(m_value_manager, m_alloc), |         m_dep_manager(m_value_manager, m_alloc), | ||||||
|         m_lemma_dep(nullptr, m_dep_manager), |         m_conflict_dep(nullptr, m_dep_manager), | ||||||
|         m_free_vars(m_activity) { |         m_free_vars(m_activity) { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -76,7 +93,7 @@ namespace polysat { | ||||||
|      |      | ||||||
|     lbool solver::check_sat() {  |     lbool solver::check_sat() {  | ||||||
|         while (true) { |         while (true) { | ||||||
|             if (is_conflict() && m_level == 0) return l_false; |             if (is_conflict() && at_base_level()) return l_false; | ||||||
|             else if (is_conflict()) resolve_conflict(); |             else if (is_conflict()) resolve_conflict(); | ||||||
|             else if (can_propagate()) propagate(); |             else if (can_propagate()) propagate(); | ||||||
|             else if (!can_decide()) return l_true; |             else if (!can_decide()) return l_true; | ||||||
|  | @ -116,7 +133,7 @@ namespace polysat { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void solver::add_eq(pdd const& p, unsigned dep) { |     void solver::add_eq(pdd const& p, unsigned dep) { | ||||||
|         p_dependency_ref d(m_dep_manager.mk_leaf(dep), m_dep_manager); |         p_dependency_ref d(mk_dep(dep), m_dep_manager); | ||||||
|         constraint* c = constraint::eq(m_level, p, d); |         constraint* c = constraint::eq(m_level, p, d); | ||||||
|         m_constraints.push_back(c); |         m_constraints.push_back(c); | ||||||
|         add_watch(*c); |         add_watch(*c); | ||||||
|  | @ -242,7 +259,6 @@ namespace polysat { | ||||||
|             VERIFY(a.mult_inverse(sz, inv_a));  |             VERIFY(a.mult_inverse(sz, inv_a));  | ||||||
|             rational val = mod(inv_a * -b, rational::power_of_two(sz)); |             rational val = mod(inv_a * -b, rational::power_of_two(sz)); | ||||||
|             m_cjust[other_var].push_back(&c); |             m_cjust[other_var].push_back(&c); | ||||||
|             m_trail.push(push_back_vector(m_cjust[other_var])); |  | ||||||
|             propagate(other_var, val, justification::propagation(m_level)); |             propagate(other_var, val, justification::propagation(m_level)); | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|  | @ -290,6 +306,8 @@ namespace polysat { | ||||||
|             auto v = m_search.back(); |             auto v = m_search.back(); | ||||||
|             m_justification[v] = justification::unassigned(); |             m_justification[v] = justification::unassigned(); | ||||||
|             m_free_vars.unassign_var_eh(v); |             m_free_vars.unassign_var_eh(v); | ||||||
|  |             m_cjust[v].reset(); | ||||||
|  |             m_viable[v] = m_bdd.mk_true(); | ||||||
|             m_search.pop_back(); |             m_search.pop_back(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -367,16 +385,23 @@ namespace polysat { | ||||||
|      *  |      *  | ||||||
|      */ |      */ | ||||||
|     void solver::resolve_conflict() { |     void solver::resolve_conflict() { | ||||||
|         SASSERT(m_conflict); |         SASSERT(!m_conflict.empty()); | ||||||
|         constraint& c = *m_conflict; |  | ||||||
|         m_conflict = nullptr; |  | ||||||
|         pdd p = c.p(); |  | ||||||
|         m_lemma_level = c.level();         |  | ||||||
|         m_lemma_dep = c.dep(); |  | ||||||
|         unsigned new_lemma_level = 0; |  | ||||||
|         reset_marks(); |         reset_marks(); | ||||||
|         for (auto v : c.vars()) |         m_conflict_level = 0; | ||||||
|             set_mark(v); |         m_conflict_dep = nullptr; | ||||||
|  |         pdd p = m_conflict[0]->p(); | ||||||
|  |         for (constraint* c : m_conflict) { | ||||||
|  |             for (auto v : c->vars()) | ||||||
|  |                 set_mark(v); | ||||||
|  |             pdd p = c->p(); | ||||||
|  |             m_conflict_level = std::max(m_conflict_level, c->level());         | ||||||
|  |             m_conflict_dep = m_dep_manager.mk_join(m_conflict_dep, c->dep()); | ||||||
|  |         } | ||||||
|  |         // TBD: deal with case of multiple constaints
 | ||||||
|  |         // to obtain single p or delay extracting p until resolution.
 | ||||||
|  |         // 
 | ||||||
|  |         m_conflict.reset(); | ||||||
|  |         unsigned new_lemma_level = 0; | ||||||
|         unsigned v = UINT_MAX; |         unsigned v = UINT_MAX; | ||||||
|         unsigned i = m_search.size(); |         unsigned i = m_search.size(); | ||||||
|         vector<std::pair<unsigned, rational>> sub; |         vector<std::pair<unsigned, rational>> sub; | ||||||
|  | @ -392,16 +417,17 @@ namespace polysat { | ||||||
|                 report_unsat(); |                 report_unsat(); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |             if (j.is_decision()) { | ||||||
|  |                 learn_lemma(v, p); | ||||||
|  |                 revert_decision(i); | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|             pdd r = resolve(v, p, new_lemma_level); |             pdd r = resolve(v, p, new_lemma_level); | ||||||
|             pdd rval = r.subst_val(sub); |             pdd rval = r.subst_val(sub); | ||||||
|             if (r.is_val() && rval.is_non_zero()) { |             if (r.is_val() && rval.is_non_zero()) { | ||||||
|                 report_unsat(); |                 report_unsat(); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             if (j.is_decision()) { |  | ||||||
|                 revert_decision(p, i); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|             if (!rval.is_non_zero()) { |             if (!rval.is_non_zero()) { | ||||||
|                 backtrack(i); |                 backtrack(i); | ||||||
|                 return; |                 return; | ||||||
|  | @ -411,11 +437,17 @@ namespace polysat { | ||||||
|             for (auto w : r.free_vars()) |             for (auto w : r.free_vars()) | ||||||
|                 set_mark(w); |                 set_mark(w); | ||||||
|             p = r; |             p = r; | ||||||
|             m_lemma_level = new_lemma_level; |             m_conflict_level = new_lemma_level; | ||||||
|         } |         } | ||||||
|         report_unsat(); |         report_unsat(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /**
 | ||||||
|  |      * TBD: m_conflict_dep is a justification that m_value[v] is not viable. | ||||||
|  |      * it is currently not yet being accounted for. | ||||||
|  |      * A more general data-structure could be to maintain a p_dependency | ||||||
|  |      * with each variable state. The dependencies are augmented on backtracking. | ||||||
|  |      */ | ||||||
|     void solver::backtrack(unsigned i) { |     void solver::backtrack(unsigned i) { | ||||||
|         do { |         do { | ||||||
|             auto v = m_search[i]; |             auto v = m_search[i]; | ||||||
|  | @ -423,72 +455,78 @@ namespace polysat { | ||||||
|             if (j.level() <= base_level())  |             if (j.level() <= base_level())  | ||||||
|                 break; |                 break; | ||||||
|             if (j.is_decision()) { |             if (j.is_decision()) { | ||||||
|                 // TBD: flip last decision.
 |                 revert_decision(i); | ||||||
|                 // subtract value from viable
 |                 return; | ||||||
|                 // m_viable[v] -= m_value[v];
 |  | ||||||
|                 if (m_viable[v].is_false())  |  | ||||||
|                     continue; |  | ||||||
|                 // 
 |  | ||||||
|                 // pop levels to i
 |  | ||||||
|                 // choose a new value for v as a decision.
 |  | ||||||
|                 // 
 |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         while (i-- > 0);         |         while (i-- > 0);         | ||||||
|          |  | ||||||
|         report_unsat(); |         report_unsat(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void solver::report_unsat() { |     void solver::report_unsat() { | ||||||
|         // dependencies for variables that are currently marked and below base level
 |         backjump(base_level()); | ||||||
|         // are in the unsat core that is produced as a side-effect        
 |         m_conflict.push_back(nullptr); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     void solver::unsat_core(unsigned_vector& deps) { | ||||||
|  |         deps.reset(); | ||||||
|  |         for (auto* c : m_conflict) { | ||||||
|  |             if (c) | ||||||
|  |                 m_conflict_dep = m_dep_manager.mk_join(c->dep(), m_conflict_dep); | ||||||
|  |         } | ||||||
|  |         m_dep_manager.linearize(m_conflict_dep, deps); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * variable v was assigned by a decision at position i in the search stack. |  | ||||||
|      * The polynomial p encodes an equality that the decision was infeasible. |      * The polynomial p encodes an equality that the decision was infeasible. | ||||||
|      * The effect of this function is that the assignment to v is undone and replaced  |      * The effect of this function is that the assignment to v is undone and replaced  | ||||||
|      * by a new decision or unit propagation or conflict. |      * by a new decision or unit propagation or conflict. | ||||||
|      * We add 'p == 0' as a lemma. The lemma depends on the dependencies used |      * We add 'p == 0' as a lemma. The lemma depends on the dependencies used | ||||||
|      * to derive p, and the level of the lemma is the maximal level of the dependencies. |      * to derive p, and the level of the lemma is the maximal level of the dependencies. | ||||||
|      */ |      */ | ||||||
|     void solver::revert_decision(pdd const& p, unsigned i) { |     void solver::learn_lemma(unsigned v, pdd const& p) { | ||||||
|         auto v = m_search[i]; |         SASSERT(m_conflict_level <= m_justification[v].level()); | ||||||
|         SASSERT(m_justification[v].is_decision()); |         constraint* c = constraint::eq(m_conflict_level, p, m_conflict_dep); | ||||||
|         SASSERT(m_lemma_level <= m_justification[v].level()); |  | ||||||
|         constraint* c = constraint::eq(m_lemma_level, p, m_lemma_dep); |  | ||||||
|         m_cjust[v].push_back(c);         |         m_cjust[v].push_back(c);         | ||||||
|         add_lemma(c); |         add_lemma(c); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * variable v was assigned by a decision at position i in the search stack. | ||||||
|  |      */ | ||||||
|  |     void solver::revert_decision(unsigned i) { | ||||||
|  |         auto v = m_search[i]; | ||||||
|  |         SASSERT(m_justification[v].is_decision()); | ||||||
|         add_non_viable(v, m_value[v]); |         add_non_viable(v, m_value[v]); | ||||||
| 
 | 
 | ||||||
|         // TBD conditions for when backjumping applies to be clarified.
 |         // TBD how much to backjump to be clarified
 | ||||||
|  |         // everything before v is reverted, but not assignment
 | ||||||
|  |         // to v. This is different from propositional CDCL
 | ||||||
|  |         // where decision on v is also reverted.
 | ||||||
|         unsigned new_level = m_justification[v].level(); |         unsigned new_level = m_justification[v].level(); | ||||||
|         backjump(new_level); |         backjump(new_level); | ||||||
|         // 
 |  | ||||||
|         // find a new decision if there is one, 
 |  | ||||||
|         // propagate if decision is singular,
 |  | ||||||
|         // otherwise if there are no viable decisions, backjump
 |  | ||||||
|         //  and set a new conflict.
 |  | ||||||
|         // 
 |  | ||||||
|         rational value; |         rational value; | ||||||
|  |         m_conflict_dep = nullptr; | ||||||
|         switch (find_viable(v, value)) { |         switch (find_viable(v, value)) { | ||||||
|         case l_true:  |         case l_true:  | ||||||
|             // unit propagation
 |             assign_core(v, value, justification::propagation(new_level)); | ||||||
|             break; |             break; | ||||||
|         case l_undef: |         case l_undef: | ||||||
|             // branch
 |             assign_core(v, value, justification::decision(new_level)); | ||||||
|             break; |             break; | ||||||
|         case l_false: |         case l_false: | ||||||
|             // no viable.
 |             set_conflict(m_cjust[v]); | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     void solver::backjump(unsigned new_level) { |     void solver::backjump(unsigned new_level) { | ||||||
|         unsigned num_levels = m_level - new_level; |         unsigned num_levels = m_level - new_level; | ||||||
|         SASSERT(num_levels > 0); |         if (num_levels > 0) { | ||||||
|         pop_levels(num_levels); |             pop_levels(num_levels); | ||||||
|         m_trail.pop_scope(num_levels);         |             m_trail.pop_scope(num_levels);         | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|      |      | ||||||
|     /**
 |     /**
 | ||||||
|  | @ -522,7 +560,7 @@ namespace polysat { | ||||||
|                     // add parity condition to presere falsification
 |                     // add parity condition to presere falsification
 | ||||||
|                     degree = r.degree(v); |                     degree = r.degree(v); | ||||||
|                     resolve_level = std::max(resolve_level, c->level()); |                     resolve_level = std::max(resolve_level, c->level()); | ||||||
|                     m_lemma_dep = m_dep_manager.mk_join(m_lemma_dep.get(), c->dep()); |                     m_conflict_dep = m_dep_manager.mk_join(m_conflict_dep.get(), c->dep()); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -30,6 +30,8 @@ namespace polysat { | ||||||
|     typedef dd::pdd pdd; |     typedef dd::pdd pdd; | ||||||
|     typedef dd::bdd bdd; |     typedef dd::bdd bdd; | ||||||
| 
 | 
 | ||||||
|  |     const unsigned null_dependency = UINT_MAX; | ||||||
|  | 
 | ||||||
|     struct dep_value_manager { |     struct dep_value_manager { | ||||||
|         void inc_ref(unsigned) {} |         void inc_ref(unsigned) {} | ||||||
|         void dec_ref(unsigned) {} |         void dec_ref(unsigned) {} | ||||||
|  | @ -117,7 +119,7 @@ namespace polysat { | ||||||
|         dep_value_manager        m_value_manager; |         dep_value_manager        m_value_manager; | ||||||
|         small_object_allocator   m_alloc; |         small_object_allocator   m_alloc; | ||||||
|         poly_dep_manager         m_dep_manager; |         poly_dep_manager         m_dep_manager; | ||||||
|         p_dependency_ref         m_lemma_dep; |         p_dependency_ref         m_conflict_dep; | ||||||
|         var_queue                m_free_vars; |         var_queue                m_free_vars; | ||||||
| 
 | 
 | ||||||
|         // Per constraint state
 |         // Per constraint state
 | ||||||
|  | @ -144,7 +146,7 @@ namespace polysat { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         // conflict state
 |         // conflict state
 | ||||||
|         constraint* m_conflict { nullptr }; |         ptr_vector<constraint> m_conflict; | ||||||
| 
 | 
 | ||||||
|         unsigned size(unsigned var) const { return m_size[var]; } |         unsigned size(unsigned var) const { return m_size[var]; } | ||||||
|         /**
 |         /**
 | ||||||
|  | @ -193,8 +195,8 @@ namespace polysat { | ||||||
|         void erase_watch(constraint& c); |         void erase_watch(constraint& c); | ||||||
|         void add_watch(constraint& c); |         void add_watch(constraint& c); | ||||||
| 
 | 
 | ||||||
|         void set_conflict(constraint& c) { m_conflict = &c; } |         void set_conflict(constraint& c) { m_conflict.push_back(&c); } | ||||||
|         void clear_conflict() { m_conflict = nullptr; } |         void set_conflict(ptr_vector<constraint>& cs) { m_conflict.append(cs); } | ||||||
| 
 | 
 | ||||||
|         unsigned_vector m_marks; |         unsigned_vector m_marks; | ||||||
|         unsigned        m_clock { 0 }; |         unsigned        m_clock { 0 }; | ||||||
|  | @ -202,20 +204,23 @@ namespace polysat { | ||||||
|         bool is_marked(unsigned v) const { return m_clock == m_marks[v]; } |         bool is_marked(unsigned v) const { return m_clock == m_marks[v]; } | ||||||
|         void set_mark(unsigned v) { m_marks[v] = m_clock; } |         void set_mark(unsigned v) { m_marks[v] = m_clock; } | ||||||
| 
 | 
 | ||||||
|         unsigned                 m_lemma_level { 0 }; |         unsigned                 m_conflict_level { 0 }; | ||||||
| 
 | 
 | ||||||
|         pdd isolate(unsigned v); |         pdd isolate(unsigned v); | ||||||
|         pdd resolve(unsigned v, pdd const& p, unsigned& resolve_level); |         pdd resolve(unsigned v, pdd const& p, unsigned& resolve_level); | ||||||
|         void decide(); |         void decide(); | ||||||
| 
 | 
 | ||||||
|         bool is_conflict() const { return nullptr != m_conflict; } |         p_dependency* mk_dep(unsigned dep) { return dep == null_dependency ? nullptr : m_dep_manager.mk_leaf(dep); } | ||||||
|  | 
 | ||||||
|  |         bool is_conflict() const { return !m_conflict.empty(); } | ||||||
|         bool at_base_level() const; |         bool at_base_level() const; | ||||||
|         unsigned base_level() const; |         unsigned base_level() const; | ||||||
| 
 | 
 | ||||||
|         void resolve_conflict();             |         void resolve_conflict();             | ||||||
|         void backtrack(unsigned i); |         void backtrack(unsigned i); | ||||||
|         void report_unsat(); |         void report_unsat(); | ||||||
|         void revert_decision(pdd const& p, unsigned i); |         void revert_decision(unsigned i); | ||||||
|  |         void learn_lemma(unsigned v, pdd const& p); | ||||||
|         void backjump(unsigned new_level); |         void backjump(unsigned new_level); | ||||||
|         void add_lemma(constraint* c); |         void add_lemma(constraint* c); | ||||||
| 
 | 
 | ||||||
|  | @ -242,6 +247,11 @@ namespace polysat { | ||||||
|          */ |          */ | ||||||
|         lbool check_sat(); |         lbool check_sat(); | ||||||
| 
 | 
 | ||||||
|  |         /**
 | ||||||
|  |          * retrieve unsat core dependencies | ||||||
|  |          */ | ||||||
|  |         void unsat_core(unsigned_vector& deps); | ||||||
|  |          | ||||||
|         /**
 |         /**
 | ||||||
|          * Add variable with bit-size.  |          * Add variable with bit-size.  | ||||||
|          */ |          */ | ||||||
|  | @ -257,12 +267,12 @@ namespace polysat { | ||||||
|          * Each constraint is tracked by a dependency. |          * Each constraint is tracked by a dependency. | ||||||
|          * assign sets the 'index'th bit of var. |          * assign sets the 'index'th bit of var. | ||||||
|          */ |          */ | ||||||
|         void add_eq(pdd const& p, unsigned dep = 0); |         void add_eq(pdd const& p, unsigned dep = null_dependency); | ||||||
|         void add_diseq(pdd const& p, unsigned dep = 0); |         void add_diseq(pdd const& p, unsigned dep = null_dependency); | ||||||
|         void add_ule(pdd const& p, pdd const& q, unsigned dep = 0); |         void add_ule(pdd const& p, pdd const& q, unsigned dep = null_dependency); | ||||||
|         void add_ult(pdd const& p, pdd const& q, unsigned dep = 0); |         void add_ult(pdd const& p, pdd const& q, unsigned dep = null_dependency); | ||||||
|         void add_sle(pdd const& p, pdd const& q, unsigned dep = 0); |         void add_sle(pdd const& p, pdd const& q, unsigned dep = null_dependency); | ||||||
|         void add_slt(pdd const& p, pdd const& q, unsigned dep = 0); |         void add_slt(pdd const& p, pdd const& q, unsigned dep = null_dependency); | ||||||
|          |          | ||||||
|         void assign(unsigned var, unsigned index, bool value, unsigned dep);         |         void assign(unsigned var, unsigned index, bool value, unsigned dep);         | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue