mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	general form migration
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									7025d85da3
								
							
						
					
					
						commit
						a0d112b7b0
					
				
					 3 changed files with 114 additions and 68 deletions
				
			
		|  | @ -402,6 +402,7 @@ namespace dd { | |||
|         pdd reduce(pdd const& other) const { return m.reduce(*this, other); } | ||||
|         bool different_leading_term(pdd const& other) const { return m.different_leading_term(*this, other); } | ||||
|         void factor(unsigned v, unsigned degree, pdd& lc, pdd& rest) const { m.factor(*this, v, degree, lc, rest); } | ||||
|         bool resolve(unsigned v, pdd const& other, pdd& result) { return m.resolve(v, *this, other, result); } | ||||
| 
 | ||||
|         pdd subst_val(vector<std::pair<unsigned, rational>> const& s) const { return m.subst_val(*this, s); } | ||||
|         pdd subst_val(unsigned v, rational const& val) const { return m.subst_val(*this, v, val); } | ||||
|  |  | |||
|  | @ -291,12 +291,15 @@ namespace polysat { | |||
|             m_search.pop_back(); | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     // Base approach just clears all assignments.
 | ||||
|     // TBD approach allows constraints to constrain bits of v. They are 
 | ||||
|     // added to cjust and affect viable outside of search.
 | ||||
|     void solver::undo_var(pvar v) { | ||||
|         m_justification[v] = justification::unassigned(); | ||||
|         m_free_vars.unassign_var_eh(v); | ||||
|         m_cjust[v].reset(); | ||||
|         m_viable[v] = m_bdd.mk_true(); // TBD does not work with external bit-assignments
 | ||||
|         m_viable[v] = m_bdd.mk_true();  | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -359,28 +362,27 @@ namespace polysat { | |||
|     } | ||||
| 
 | ||||
|     void solver::set_conflict(constraint& c) {  | ||||
|         SASSERT(m_conflict_cs.empty()); | ||||
|         m_conflict_cs.push_back(&c);  | ||||
|         SASSERT(m_conflict.empty()); | ||||
|         m_conflict.push_back(&c);  | ||||
|     } | ||||
| 
 | ||||
|     void solver::set_conflict(pvar v) { | ||||
|         SASSERT(m_conflict_cs.empty()); | ||||
|         m_conflict_cs.append(m_cjust[v]); | ||||
|         SASSERT(m_conflict.empty()); | ||||
|         m_conflict.append(m_cjust[v]); | ||||
|         if (m_cjust[v].empty()) | ||||
|             m_conflict_cs.push_back(nullptr); | ||||
|             m_conflict.push_back(nullptr); | ||||
|     } | ||||
| 
 | ||||
|          | ||||
|     /**
 | ||||
|      * Conflict resolution. | ||||
|      * - m_conflict_cs are constraints that are infeasible in the current assignment. | ||||
|      * - m_conflict_dep are dependencies for infeasibility | ||||
|      * 1. walk m_search from top down until last variable in m_conflict_cs. | ||||
|      * - m_conflict are constraints that are infeasible in the current assignment. | ||||
|      * 1. walk m_search from top down until last variable in m_conflict. | ||||
|      * 2. resolve constraints in m_cjust to isolate lowest degree polynomials | ||||
|      *    using variable. | ||||
|      *    Use Olm-Seidl division by powers of 2 to preserve invertibility. | ||||
|      * 3. resolve conflict with result of resolution. | ||||
|      * 4. If the resulting equality is still infeasible continue, otherwise bail out | ||||
|      * 4. If the resulting lemma is still infeasible continue, otherwise bail out | ||||
|      *    and undo the last assignment by accumulating conflict trail (but without resolution). | ||||
|      * 5. When hitting the last decision, determine whether conflict polynomial is asserting, | ||||
|      *    If so, apply propagation. | ||||
|  | @ -392,22 +394,21 @@ namespace polysat { | |||
|      */ | ||||
|     void solver::resolve_conflict() { | ||||
| 
 | ||||
|         if (m_conflict_cs.size() == 1 && !m_conflict_cs[0]) { | ||||
|         SASSERT(!m_conflict.empty()); | ||||
| 
 | ||||
|         if (m_conflict.size() == 1 && !m_conflict[0]) { | ||||
|             report_unsat(); | ||||
|             return; | ||||
|         } | ||||
|          | ||||
|         if (m_conflict_cs.size() > 1) { | ||||
|             revert_decision(m_search.size()-1); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         constraint* c = m_conflict_cs[0]; | ||||
|         scoped_ptr<constraint> lemma; | ||||
|         reset_marks(); | ||||
|         for (auto v : c->vars())  | ||||
|             set_mark(v); | ||||
| 
 | ||||
|         for (constraint* c : m_conflict) { | ||||
|             SASSERT(c); | ||||
|             for (auto v : c->vars())  | ||||
|                 set_mark(v); | ||||
|         } | ||||
|          | ||||
|         for (unsigned i = m_search.size(); i-- > 0; ) { | ||||
|             pvar v = m_search[i].first; | ||||
|             if (!is_marked(v)) | ||||
|  | @ -419,45 +420,60 @@ namespace polysat { | |||
|             } | ||||
|             if (j.is_decision()) { | ||||
|                 learn_lemma(v, lemma.detach()); | ||||
|                 revert_decision(i); | ||||
|                 return; | ||||
|             } | ||||
|             constraint* new_lemma = resolve(v, lemma.get()); | ||||
|             if (!new_lemma) { | ||||
|                 backtrack(i); | ||||
|                 return; | ||||
|             } | ||||
|             lemma = new_lemma; | ||||
|             // TBD: this assumes lemma is an equality.
 | ||||
|             pdd r = lemma->p(); | ||||
|             pdd rval = r.subst_val(m_search); | ||||
|             if (r.is_val() && rval.is_never_zero()) { | ||||
|                 report_unsat(); | ||||
|                 return; | ||||
|             } | ||||
|             if (!rval.is_never_zero()) { | ||||
|                 backtrack(i); | ||||
|                 revert_decision(v); | ||||
|                 return; | ||||
|             } | ||||
|             SASSERT(j.is_propagation()); | ||||
|             scoped_ptr<constraint> new_lemma = resolve(v); | ||||
|             if (!new_lemma) { | ||||
|                 backtrack(i, lemma); | ||||
|                 return; | ||||
|             } | ||||
|             if (is_always_false(*new_lemma)) { | ||||
|                 learn_lemma(v, new_lemma.get()); | ||||
|                 m_conflict.reset(); | ||||
|                 m_conflict.push_back(new_lemma.detach()); | ||||
|                 report_unsat(); | ||||
|                 return; | ||||
|             } | ||||
|             if (!eval_to_false(*new_lemma)) { | ||||
|                 backtrack(i, lemma); | ||||
|                 return; | ||||
|             } | ||||
|             lemma = new_lemma.detach(); | ||||
|             reset_marks(); | ||||
|             for (auto w : lemma->vars()) | ||||
|                 set_mark(w); | ||||
|             c = lemma.get(); | ||||
|             m_conflict.reset(); | ||||
|             m_conflict.push_back(lemma.get()); | ||||
|         } | ||||
|         report_unsat(); | ||||
|     } | ||||
| 
 | ||||
|     void solver::backtrack(unsigned i) { | ||||
|     void solver::backtrack(unsigned i, scoped_ptr<constraint>& lemma) { | ||||
|         if (lemma) { | ||||
|             m_conflict.push_back(lemma.get()); | ||||
|             add_lemma(lemma.detach()); | ||||
|         } | ||||
|         do { | ||||
|             auto v = m_search[i].first; | ||||
|             if (!is_marked(v)) | ||||
|                 continue; | ||||
|             justification& j = m_justification[v]; | ||||
|             if (j.level() <= base_level())  | ||||
|                 break; | ||||
|             if (j.is_decision()) { | ||||
|                 revert_decision(i); | ||||
|                 revert_decision(v); | ||||
|                 return; | ||||
|             } | ||||
|             // retrieve constraint used for propagation
 | ||||
|             // add variables to COI
 | ||||
|             SASSERT(j.is_propagation()); | ||||
|             for (auto* c : m_cjust[v]) { | ||||
|                 for (auto w : c->vars()) | ||||
|                     set_mark(w); | ||||
|                 m_conflict.push_back(c); | ||||
|             } | ||||
|         } | ||||
|         while (i-- > 0);         | ||||
|         report_unsat(); | ||||
|  | @ -465,21 +481,19 @@ namespace polysat { | |||
| 
 | ||||
|     void solver::report_unsat() { | ||||
|         backjump(base_level()); | ||||
|         SASSERT(m_conflict_cs.empty()); | ||||
|         m_conflict_cs.push_back(nullptr); | ||||
|         SASSERT(!m_conflict.empty()); | ||||
|     } | ||||
| 
 | ||||
|     void solver::unsat_core(unsigned_vector& deps) { | ||||
|         deps.reset(); | ||||
|         p_dependency_ref conflict_dep(m_dm); | ||||
|         for (auto* c : m_conflict_cs) { | ||||
|         for (auto* c : m_conflict) { | ||||
|             if (c) | ||||
|                 conflict_dep = m_dm.mk_join(c->dep(), conflict_dep); | ||||
|         } | ||||
|         m_dm.linearize(conflict_dep, deps); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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  | ||||
|  | @ -497,22 +511,24 @@ namespace polysat { | |||
| 
 | ||||
|     /**
 | ||||
|      * variable v was assigned by a decision at position i in the search stack. | ||||
|      * TODO: we could resolve constraints in cjust[v] against each other to  | ||||
|      * obtain stronger propagation. Example: | ||||
|      *  (x + 1)*P = 0 and (x + 1)*Q = 0, where gcd(P,Q) = 1, then we have x + 1 = 0. | ||||
|      * We refer to this process as narrowing. | ||||
|      * In general form it can rely on factoring. | ||||
|      * Root finding can further prune viable. | ||||
|      */ | ||||
|     void solver::revert_decision(unsigned i) { | ||||
|         auto v = m_search[i].first; | ||||
|     void solver::revert_decision(pvar v) { | ||||
|         rational val = m_value[v]; | ||||
|         SASSERT(m_justification[v].is_decision()); | ||||
|         stash_deps(v); | ||||
|         m_conflict.append(m_cjust[v]); | ||||
|         backjump(m_justification[v].level()-1); | ||||
|         unstash_deps(v); | ||||
|         add_non_viable(v, m_value[v]); | ||||
|         SASSERT(m_cjust[v].empty()); | ||||
|         m_cjust[v].append(m_conflict); | ||||
|         m_conflict.reset(); | ||||
|         add_non_viable(v, val); | ||||
|         decide(v); | ||||
|     } | ||||
| 
 | ||||
|     void solver::stash_deps(pvar v) { | ||||
|     } | ||||
| 
 | ||||
|     void solver::unstash_deps(pvar v) { | ||||
|     } | ||||
|      | ||||
|     void solver::backjump(unsigned new_level) { | ||||
|         unsigned num_levels = m_level - new_level; | ||||
|  | @ -523,10 +539,43 @@ namespace polysat { | |||
|     /**
 | ||||
|      * Return residue of superposing p and q with respect to v. | ||||
|      */ | ||||
|     constraint* solver::resolve(pvar v, constraint* c) { | ||||
|     constraint* solver::resolve(pvar v) { | ||||
|         SASSERT(!m_cjust[v].empty()); | ||||
|         SASSERT(m_justification[v].is_propagation()); | ||||
|         if (m_conflict.size() > 1) | ||||
|             return nullptr; | ||||
|         if (m_cjust[v].size() > 1) | ||||
|             return nullptr; | ||||
|         constraint* c = m_conflict[0]; | ||||
|         constraint* d = m_cjust[v].back(); | ||||
|         if (c->is_eq() && d->is_eq()) { | ||||
|             pdd p = c->p(); | ||||
|             pdd q = d->p(); | ||||
|             pdd r = p; | ||||
|             if (!p.resolve(v, q, r))  | ||||
|                 return nullptr; | ||||
|             p_dependency_ref dep(m_dm); | ||||
|             dep = m_dm.mk_join(c->dep(), d->dep()); | ||||
|             unsigned level = std::max(c->level(), d->level()); | ||||
|             return constraint::eq(level, r, dep);              | ||||
|         } | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     bool solver::is_always_false(constraint& c) { | ||||
|         if (c.is_eq())  | ||||
|             return c.p().is_never_zero(); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     bool solver::eval_to_false(constraint& c) { | ||||
|         if (c.is_eq()) { | ||||
|             pdd r = c.p().subst_val(m_search); | ||||
|             return r.is_never_zero(); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     void solver::add_lemma(constraint* c) { | ||||
|         add_watch(*c); | ||||
|         m_redundant.push_back(c); | ||||
|  |  | |||
|  | @ -128,7 +128,7 @@ namespace polysat { | |||
|         dep_value_manager        m_value_manager; | ||||
|         small_object_allocator   m_alloc; | ||||
|         poly_dep_manager         m_dm; | ||||
|         constraints              m_conflict_cs; | ||||
|         constraints              m_conflict; | ||||
|         constraints              m_stash_just; | ||||
|         var_queue                m_free_vars; | ||||
| 
 | ||||
|  | @ -155,9 +155,6 @@ namespace polysat { | |||
|         unsigned_vector          m_base_levels;  // External clients can push/pop scope. 
 | ||||
| 
 | ||||
| 
 | ||||
|         // conflict state
 | ||||
|         ptr_vector<constraint> m_conflict; | ||||
| 
 | ||||
|         unsigned size(pvar v) const { return m_size[v]; } | ||||
|         /**
 | ||||
|          * check if value is viable according to m_viable. | ||||
|  | @ -221,15 +218,12 @@ namespace polysat { | |||
| 
 | ||||
|         unsigned                 m_conflict_level { 0 }; | ||||
| 
 | ||||
|         constraint* resolve(pvar v, constraint* c); | ||||
|         constraint* resolve(pvar v); | ||||
| 
 | ||||
|         bool can_decide() const { return !m_free_vars.empty(); } | ||||
|         void decide(); | ||||
|         void decide(pvar v); | ||||
| 
 | ||||
|         void stash_deps(pvar v); | ||||
|         void unstash_deps(pvar v); | ||||
| 
 | ||||
|         p_dependency* mk_dep(unsigned dep) { return dep == null_dependency ? nullptr : m_dm.mk_leaf(dep); } | ||||
| 
 | ||||
|         bool is_conflict() const { return !m_conflict.empty(); } | ||||
|  | @ -237,13 +231,15 @@ namespace polysat { | |||
|         unsigned base_level() const; | ||||
| 
 | ||||
|         void resolve_conflict();             | ||||
|         void backtrack(unsigned i); | ||||
|         void backtrack(unsigned i, scoped_ptr<constraint>& lemma); | ||||
|         void report_unsat(); | ||||
|         void revert_decision(unsigned i); | ||||
|         void revert_decision(pvar v); | ||||
|         void learn_lemma(pvar v, constraint* c); | ||||
|         void backjump(unsigned new_level); | ||||
|         void undo_var(pvar v); | ||||
|         void add_lemma(constraint* c); | ||||
|         bool is_always_false(constraint& c); | ||||
|         bool eval_to_false(constraint& c); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue