mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 19:52:29 +00:00 
			
		
		
		
	na
This commit is contained in:
		
							parent
							
								
									9c3489ba4b
								
							
						
					
					
						commit
						83efb1413a
					
				
					 10 changed files with 99 additions and 57 deletions
				
			
		|  | @ -308,9 +308,8 @@ namespace polysat { | |||
|             for (auto const& c : s.m_viable.get_constraints(v)) | ||||
|                 insert(c);         | ||||
| 
 | ||||
|         for (auto* engine : ex_engines) | ||||
|             if (engine->try_explain(v, *this)) | ||||
|                 return true; | ||||
|         if (try_explain(v)) | ||||
|             return true; | ||||
| 
 | ||||
|         // No value resolution method was successful => fall back to saturation and variable elimination
 | ||||
|         while (s.inc()) { | ||||
|  | @ -345,6 +344,13 @@ namespace polysat { | |||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     bool conflict::try_explain(pvar v) { | ||||
|         for (auto* engine : ex_engines) | ||||
|             if (engine->try_explain(v, *this)) | ||||
|                 return true; | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     void conflict::set_mark(signed_constraint c) { | ||||
|         if (c->is_marked()) | ||||
|             return; | ||||
|  |  | |||
|  | @ -110,6 +110,7 @@ namespace polysat { | |||
| 
 | ||||
|         bool try_eliminate(pvar v); | ||||
|         bool try_saturate(pvar v); | ||||
|         bool try_explain(pvar v); | ||||
| 
 | ||||
|         using const_iterator = conflict_iterator; | ||||
|         const_iterator begin() const; | ||||
|  |  | |||
|  | @ -202,6 +202,21 @@ namespace polysat { | |||
|         return ~ule(b, a);  | ||||
|     } | ||||
| 
 | ||||
|     bool signed_constraint::is_eq() const { | ||||
|         if (is_positive()) | ||||
|             return m_constraint->is_eq(); | ||||
|         else | ||||
|             return m_constraint->is_diseq(); | ||||
|     } | ||||
| 
 | ||||
|     pdd const& signed_constraint::eq() const { | ||||
|         SASSERT(is_eq()); | ||||
|         if (is_positive()) | ||||
|             return m_constraint->to_ule().lhs(); | ||||
|         else | ||||
|             return m_constraint->to_ule().rhs();         | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|     * encode that the i'th bit of p is 1. | ||||
|     * It holds if p << (K - i - 1) >= 2^{K-1}, where K is the bit-width. | ||||
|  |  | |||
|  | @ -159,6 +159,7 @@ namespace polysat { | |||
|         bool operator!=(constraint const& other) const { return !operator==(other); } | ||||
| 
 | ||||
|         virtual bool is_eq() const { return false; } | ||||
|         virtual bool is_diseq() const { return false; } | ||||
|         bool is_ule() const { return m_kind == ckind_t::ule_t; } | ||||
|         bool is_mul_ovfl() const { return m_kind == ckind_t::mul_ovfl_t; } | ||||
|         ckind_t kind() const { return m_kind; } | ||||
|  | @ -253,6 +254,9 @@ namespace polysat { | |||
|         constraint& operator*() { return *m_constraint; } | ||||
|         constraint const& operator*() const { return *m_constraint; } | ||||
| 
 | ||||
|         bool is_eq() const; | ||||
|         pdd const& eq() const; | ||||
| 
 | ||||
| 
 | ||||
|         signed_constraint& operator=(std::nullptr_t) { m_constraint = nullptr; return *this; } | ||||
| 
 | ||||
|  |  | |||
|  | @ -24,8 +24,8 @@ namespace polysat { | |||
|         LOG_H3("Resolving upon v" << v); | ||||
|         LOG("c1: " << c1); | ||||
|         LOG("c2: " << c2); | ||||
|         pdd a = c1->to_ule().p(); | ||||
|         pdd b = c2->to_ule().p(); | ||||
|         pdd a = c1.eq(); | ||||
|         pdd b = c2.eq(); | ||||
|         pdd r = a; | ||||
|         if (!a.resolve(v, b, r) && !b.resolve(v, a, r)) | ||||
|             return {}; | ||||
|  | @ -40,30 +40,19 @@ namespace polysat { | |||
|         return c; | ||||
|     } | ||||
| 
 | ||||
|     bool ex_polynomial_superposition::is_positive_equality_over(pvar v, signed_constraint const& c) { | ||||
|         return c.is_positive() && c->is_eq() && c->contains_var(v); | ||||
|     } | ||||
| 
 | ||||
|     // c2 ... constraint that is currently false
 | ||||
|     // Try to replace it with a new false constraint (derived from superposition with a true constraint)
 | ||||
|     lbool ex_polynomial_superposition::find_replacement(signed_constraint c2, pvar v, conflict& core) { | ||||
|         vector<signed_constraint> premises; | ||||
| 
 | ||||
|         // TBD: replacement can be obtained from stack not just core.
 | ||||
|         // see test_l5. Exposes unsoundness bug: a new consequence is derived 
 | ||||
|         // after some variable decision was already processed. Then the 
 | ||||
|         // behavior of evaluating literals "is_currently_true" and bvalue
 | ||||
|         // uses the full search stack
 | ||||
| #if 1 | ||||
|         for (auto si : s.m_search) { | ||||
|             if (!si.is_boolean()) | ||||
|                 continue; | ||||
|             auto c1 = s.lit2cnstr(si.lit()); | ||||
|          | ||||
| #else | ||||
|         for (auto c1 : core) { | ||||
| #endif | ||||
|             if (!is_positive_equality_over(v, c1)) | ||||
|             auto c1 = s.lit2cnstr(si.lit());        | ||||
|             if (!c1->contains_var(v)) | ||||
|                 continue; | ||||
|             if (!c1.is_eq()) | ||||
|                 continue; | ||||
|             if (!c1.is_currently_true(s)) | ||||
|                 continue; | ||||
|  | @ -107,7 +96,9 @@ namespace polysat { | |||
|     // TODO: can try multiple replacements at once; then the c2 loop needs to be done only once... (requires some reorganization for storing the premises)
 | ||||
|     lbool ex_polynomial_superposition::try_explain1(pvar v, conflict& core) { | ||||
|         for (auto c2 : core) { | ||||
|             if (!is_positive_equality_over(v, c2)) | ||||
|             if (!c2->contains_var(v)) | ||||
|                 continue; | ||||
|             if (!c2.is_eq()) | ||||
|                 continue; | ||||
|             if (!c2.is_currently_false(s)) | ||||
|                 continue; | ||||
|  | @ -124,52 +115,68 @@ namespace polysat { | |||
|     } | ||||
| 
 | ||||
|     void ex_polynomial_superposition::reduce_by(pvar v, conflict& core) { | ||||
|         //return;
 | ||||
|         bool progress = true; | ||||
|         while (progress) { | ||||
|             progress = false; | ||||
|             for (auto c : core) { | ||||
|                 if (is_positive_equality_over(v, c) && c.is_currently_true(s) && reduce_by(v, c, core)) { | ||||
|                     progress = true; | ||||
|                     break; | ||||
|                 } | ||||
|                 if (!c->contains_var(v)) | ||||
|                     continue; | ||||
|                 if (!c.is_eq()) | ||||
|                     continue; | ||||
| #if 0 | ||||
|                 if (!c.is_currently_true(s)) | ||||
|                     continue; | ||||
| #endif | ||||
| 
 | ||||
|                 if (!reduce_by(v, c, core)) | ||||
|                     continue; | ||||
|                 progress = true; | ||||
|                 break;                 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     bool ex_polynomial_superposition::reduce_by(pvar v, signed_constraint eq, conflict& core) { | ||||
|         pdd p = eq->to_ule().p(); | ||||
|         pdd p = eq.eq(); | ||||
|         LOG("using v" << v << " " << eq); | ||||
|         for (auto c : core) { | ||||
|             if (c == eq) | ||||
|                 continue; | ||||
|             if (is_positive_equality_over(v, c)) | ||||
|             if (!c->contains_var(v)) | ||||
|                 continue; | ||||
|             if (c.is_eq()) | ||||
|                 continue; | ||||
|             LOG("try-reduce: " << c << " " << c.is_currently_false(s)); | ||||
| #if 0 | ||||
|             if (!c.is_currently_false(s)) | ||||
|                 continue; | ||||
|             if (c->is_ule()) { | ||||
|                 auto lhs = c->to_ule().lhs(); | ||||
|                 auto rhs = c->to_ule().rhs(); | ||||
|                 auto a = lhs.reduce(v, p); | ||||
|                 auto b = rhs.reduce(v, p); | ||||
|                 if (a == lhs && b == rhs) | ||||
|                     continue; | ||||
|                 auto c2 = s.ule(a, b); | ||||
|                 if (!c.is_positive()) | ||||
|                     c2 = ~c2; | ||||
|                 SASSERT(c2.is_currently_false(s));                 | ||||
|                 if (!c2->has_bvar() || l_undef == c2.bvalue(s)) | ||||
|                     core.keep(c2);  // adds propagation of c to the search stack
 | ||||
|                 core.reset(); | ||||
|                 LOG_H3("Polynomial superposition " << eq << " " << c << " reduced to " << c2); | ||||
|                 if (c2.bvalue(s) == l_false) { | ||||
|                     core.insert(eq); | ||||
|                     core.insert(c); | ||||
|                     core.insert(~c2); | ||||
|                     return false; | ||||
|                 } | ||||
|                 core.set(c2);                 | ||||
|                 return true; | ||||
| #endif | ||||
|             if (!c->is_ule()) | ||||
|                 continue; | ||||
|             auto lhs = c->to_ule().lhs(); | ||||
|             auto rhs = c->to_ule().rhs(); | ||||
|             auto a = lhs.reduce(v, p); | ||||
|             auto b = rhs.reduce(v, p); | ||||
|             if (a == lhs && b == rhs) | ||||
|                 continue; | ||||
|             auto c2 = s.ule(a, b); | ||||
|             if (!c.is_positive()) | ||||
|                 c2 = ~c2; | ||||
|             if (!c2.is_currently_false(s)) | ||||
|                 continue; | ||||
|             SASSERT(c2.is_currently_false(s)); | ||||
|             if (!c2->has_bvar() || l_undef == c2.bvalue(s)) | ||||
|                 core.keep(c2);  // adds propagation of c to the search stack
 | ||||
|             core.reset(); | ||||
|             LOG_H3("Polynomial superposition " << eq << " " << c << " reduced to " << c2); | ||||
|             if (c2.bvalue(s) == l_false) { | ||||
|                 core.insert(eq); | ||||
|                 core.insert(c); | ||||
|                 core.insert(~c2); | ||||
|                 return false; | ||||
|             } | ||||
|             core.set(c2); | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  |  | |||
|  | @ -33,7 +33,6 @@ namespace polysat { | |||
| 
 | ||||
|     class ex_polynomial_superposition : public explainer { | ||||
|     private: | ||||
|         bool is_positive_equality_over(pvar v, signed_constraint const& c); | ||||
|         signed_constraint resolve1(pvar v, signed_constraint c1, signed_constraint c2); | ||||
|         lbool find_replacement(signed_constraint c2, pvar v, conflict& core); | ||||
|         void reduce_by(pvar v, conflict& core); | ||||
|  |  | |||
|  | @ -134,6 +134,8 @@ namespace polysat { | |||
|         //std::cout << "Already true " << conseq.is_currently_true(s) << "\n";
 | ||||
| 
 | ||||
|         SASSERT(premise.is_currently_true(s)); | ||||
|         SASSERT(bound * p.val() > max); | ||||
|         SASSERT((bound - 1) * p.val() <= max); | ||||
|         clause_builder cb(s); | ||||
|         cb.push_new(~sc); | ||||
|         cb.push_new(~premise); | ||||
|  |  | |||
|  | @ -462,9 +462,15 @@ namespace polysat { | |||
|             // This case corresponds to a propagation of conflict_var, except it's not explicitly on the stack.
 | ||||
|             VERIFY(m_viable.resolve(v, m_conflict)); | ||||
|             // TBD: saturate resulting conflict to get better lemmas.
 | ||||
|             LOG("try-saturate"); | ||||
|             m_conflict.try_saturate(v); | ||||
|             LOG("end-try-saturate"); | ||||
|             LOG("try-eliminate v" << v); | ||||
|             if (m_conflict.try_explain(v)) | ||||
|                 ; | ||||
|             else if (m_conflict.try_eliminate(v)) | ||||
|                 ; | ||||
|             else | ||||
|                 m_conflict.try_saturate(v); | ||||
|              | ||||
|             LOG("end-try-eliminate v"); | ||||
|         } | ||||
| 
 | ||||
|         search_iterator search_it(m_search); | ||||
|  |  | |||
|  | @ -41,7 +41,8 @@ namespace polysat { | |||
|         unsigned hash() const override; | ||||
|         bool operator==(constraint const& other) const override; | ||||
|         bool is_eq() const override { return m_rhs.is_zero(); } | ||||
|         pdd const& p() const { SASSERT(is_eq()); return m_lhs; } | ||||
|         bool is_diseq() const override { return m_lhs.is_one(); } | ||||
|         // pdd const& p() const { SASSERT(is_eq()); return m_lhs; }
 | ||||
|     }; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -170,6 +170,7 @@ namespace polysat { | |||
|     *   and division with coeff are valid. Is there a more relaxed scheme? | ||||
|     */ | ||||
|     bool viable::refine_viable(pvar v, rational const& val) { | ||||
|         //return true;
 | ||||
|         auto* e = m_non_units[v]; | ||||
|         if (!e) | ||||
|             return true; | ||||
|  | @ -408,7 +409,7 @@ namespace polysat { | |||
|         }              | ||||
|         while (e != first); | ||||
| 
 | ||||
|         core.set_bailout(); | ||||
|         // core.set_bailout();
 | ||||
|         for (auto c : core) { | ||||
|             if (c.bvalue(s) == l_false) { | ||||
|                 core.reset(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue