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
							
								
									05bcf0bed7
								
							
						
					
					
						commit
						788de7d614
					
				
					 9 changed files with 174 additions and 45 deletions
				
			
		|  | @ -301,5 +301,36 @@ namespace dd { | |||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     bool_vector fdd::rational2bits(rational const& r) const { | ||||
|         bool_vector result; | ||||
|         for (unsigned i = 0; i < num_bits(); ++i) | ||||
|             result.push_back(r.get_bit(i)); | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     rational fdd::bits2rational(bool_vector const& v) const { | ||||
|         rational result(0); | ||||
|         for (unsigned i = 0; i < num_bits(); ++i) | ||||
|             if (v[i]) | ||||
|                 result += rational::power_of_two(i); | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     bool fdd::sup(bdd const& b, rational& _lo) const { | ||||
|         bool_vector lo = rational2bits(_lo); | ||||
|         if (!sup(b, lo)) | ||||
|             return false; | ||||
|         _lo = bits2rational(lo); | ||||
|         return true; | ||||
|     } | ||||
|      | ||||
|     bool fdd::inf(bdd const& b, rational& _hi) const { | ||||
|         bool_vector hi = rational2bits(_hi); | ||||
|         if (!inf(b, hi)) | ||||
|             return false; | ||||
|         _hi = bits2rational(hi); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -47,6 +47,10 @@ namespace dd { | |||
| 
 | ||||
|         bool contains(bdd const& b, bool_vector const& value) const; | ||||
| 
 | ||||
|         rational bits2rational(bool_vector const& v) const; | ||||
| 
 | ||||
|         bool_vector rational2bits(rational const& r) const; | ||||
| 
 | ||||
|     public: | ||||
|         /** Initialize FDD using BDD variables from 0 to num_bits-1. */ | ||||
|         fdd(bdd_manager& manager, unsigned num_bits, unsigned start = 0, unsigned step = 1) : fdd(manager, seq(num_bits, start, step)) { } | ||||
|  | @ -89,6 +93,10 @@ namespace dd { | |||
| 	bool sup(bdd const& b, bool_vector& lo) const; | ||||
|        | ||||
| 	bool inf(bdd const& b, bool_vector& hi) const;  | ||||
| 
 | ||||
|         bool sup(bdd const& b, rational& lo) const; | ||||
| 
 | ||||
|         bool inf(bdd const& b, rational& hi) const; | ||||
|        | ||||
|     }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,6 +18,8 @@ Author: | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "util/rational.h" | ||||
| 
 | ||||
| 
 | ||||
| template<typename Numeral> | ||||
| struct pp { | ||||
|  | @ -32,6 +34,10 @@ inline std::ostream& operator<<(std::ostream& out, pp<Numeral> const& p) { | |||
|     return out << p.n; | ||||
| } | ||||
| 
 | ||||
| inline std::ostream& operator<<(std::ostream& out, pp<rational> const& p) { | ||||
|     return out << p.n; | ||||
| } | ||||
| 
 | ||||
| template<typename Numeral> | ||||
| class mod_interval { | ||||
|     bool emp { false }; | ||||
|  |  | |||
|  | @ -211,8 +211,8 @@ namespace polysat { | |||
| 
 | ||||
|         explicit operator bool() const { return !!m_constraint; } | ||||
|         bool operator!() const { return !m_constraint; } | ||||
|         polysat::constraint* operator->() const { return m_constraint.get(); } | ||||
|         polysat::constraint const& operator*() const { return *m_constraint; } | ||||
|         constraint* operator->() const { return m_constraint.get(); } | ||||
|         constraint const& operator*() const { return *m_constraint; } | ||||
| 
 | ||||
|         constraint_literal& operator=(nullptr_t) { m_literal = sat::null_literal; m_constraint = nullptr; return *this; } | ||||
|     private: | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ Author: | |||
| namespace polysat { | ||||
| 
 | ||||
|     std::ostream& eq_constraint::display(std::ostream& out) const { | ||||
|         out << p() << " == 0 "; | ||||
|         out << p() << (is_positive() ? " == 0 " : " != 0"); | ||||
|         return display_extra(out); | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -39,7 +39,7 @@ namespace polysat { | |||
|             if (!c->is_undef()) | ||||
|                 m_conflict.push_back(c); | ||||
|         for (auto* c : confl.clauses()) | ||||
|                 m_conflict.push_back(c); | ||||
|             m_conflict.push_back(c); | ||||
| 
 | ||||
|         // TODO: we should share work done for examining constraints between different resolution methods
 | ||||
|         clause_ref lemma; | ||||
|  | @ -81,16 +81,58 @@ namespace polysat { | |||
|         return lemma; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      *  Polynomial superposition. | ||||
|      *  So far between two equalities. | ||||
|      *  TODO: Also handle =, != superposition here? | ||||
|      *  TODO: handle case when m_conflict.units().size() > 2 | ||||
|      *  TODO: handle super-position into a clause? | ||||
|      */ | ||||
|     clause_ref conflict_explainer::by_polynomial_superposition() { | ||||
|         if (m_conflict.units().size() != 2 || m_conflict.clauses().size() > 0) | ||||
|         LOG_H3("units-size: " << m_conflict.units().size() << " conflict-clauses " << m_conflict.clauses().size()); | ||||
|         constraint* c1 = nullptr, *c2 = nullptr; | ||||
|         if (m_conflict.units().size() == 2 && m_conflict.clauses().size() == 0) { | ||||
|             c1 = m_conflict.units()[0]; | ||||
|             c2 = m_conflict.units()[1]; | ||||
|         } | ||||
|         else { | ||||
|             // other combinations?
 | ||||
| 
 | ||||
| #if 0 | ||||
|             // A clause can also be a unit.
 | ||||
|             // Even if a clause is not a unit, we could still resolve a propagation 
 | ||||
|             // into some literal in the current conflict clause.
 | ||||
|             // Selecting resolvents should not be specific to superposition.
 | ||||
|             // 
 | ||||
| 
 | ||||
|             for (auto clause : m_conflict.clauses()) { | ||||
|                 if (clause->size() == 1) {                     | ||||
|                     sat::literal lit = (*clause)[0]; | ||||
|                     if (lit.sign()) | ||||
|                         continue; | ||||
|                     constraint* c = m_solver.m_constraints.lookup(lit.var());                     | ||||
|                     LOG("unit clause: " << *c); | ||||
|                     if (c->is_eq() && c->is_positive()) { | ||||
|                         c1 = c; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             if (!c1) | ||||
|                 return nullptr; | ||||
| 
 | ||||
|             for (constraint* c : m_conflict.units()) { | ||||
|                 if (c->is_eq() && c->is_positive()) { | ||||
|                     c2 = c; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|             std::cout << c1 << " " << c2 << "\n"; | ||||
| #endif | ||||
|         } | ||||
|         if (!c1 || !c2 || c1 == c2) | ||||
|             return nullptr; | ||||
|         constraint* c1 = m_conflict.units()[0]; | ||||
|         constraint* c2 = m_conflict.units()[1]; | ||||
|         if (c1 == c2) | ||||
|             return nullptr; | ||||
|         if (!c1->is_eq() || !c2->is_eq()) | ||||
|             return nullptr; | ||||
|         if (c1->is_positive() && c2->is_positive()) { | ||||
|         if (c1->is_eq() && c2->is_eq() && c1->is_positive() && c2->is_positive()) { | ||||
|             pdd a = c1->to_eq().p(); | ||||
|             pdd b = c2->to_eq().p(); | ||||
|             pdd r = a; | ||||
|  |  | |||
|  | @ -97,8 +97,8 @@ namespace polysat { | |||
|         search_state             m_search; | ||||
|         assignment_t const& assignment() const { return m_search.assignment(); } | ||||
| 
 | ||||
|         unsigned                 m_qhead { 0 }; // next item to propagate (index into m_search)
 | ||||
|         unsigned                 m_level { 0 }; | ||||
|         unsigned                 m_qhead = 0; // next item to propagate (index into m_search)
 | ||||
|         unsigned                 m_level = 0; | ||||
| 
 | ||||
|         svector<trail_instr_t>   m_trail; | ||||
|         unsigned_vector          m_qhead_trail; | ||||
|  | @ -157,8 +157,7 @@ namespace polysat { | |||
|         void decide_bool(sat::literal lit, clause& lemma); | ||||
|         void propagate_bool(sat::literal lit, clause* reason); | ||||
| 
 | ||||
|         void assign_core(pvar v, rational const& val, justification | ||||
|             const& j); | ||||
|         void assign_core(pvar v, rational const& val, justification const& j); | ||||
|         bool is_assigned(pvar v) const { return !m_justification[v].is_unassigned(); } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -73,11 +73,11 @@ namespace polysat { | |||
|             else if (hi == 0 && is_max(a)) | ||||
|                 hi = a; | ||||
|             else  | ||||
|                 std::cout << "diseq " << lo << " " << a << " " << hi << "\n"; | ||||
|                 std::cout << "unhandled diseq " << lo << " " << a << " " << hi << "\n"; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void viable_set::intersect_eq(rational const& a, rational const& b, bool is_positive) { | ||||
|     bool viable_set::intersect_eq(rational const& a, rational const& b, bool is_positive) { | ||||
|         if (a.is_odd()) { | ||||
|             if (b == 0) | ||||
|                 intersect_eq(b, is_positive); | ||||
|  | @ -86,11 +86,21 @@ namespace polysat { | |||
|                 VERIFY(a.mult_inverse(m_num_bits, a_inv)); | ||||
|                 intersect_eq(mod(a_inv * -b, p2()), is_positive); | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
|         else { | ||||
|             return false; | ||||
|         } | ||||
| 	    else | ||||
| 	        std::cout << "intersect " << a << "*x " << " == " << b << " " << is_positive << "\n"; | ||||
|     } | ||||
| 
 | ||||
|     void viable_set::intersect_eq(rational const& a, rational const& b, bool is_positive, unsigned& budget) { | ||||
|         std::function<bool(rational const&)> eval = [&](rational const& x) { | ||||
|             return is_positive == (mod(a * x + b, p2()) == 0); | ||||
|         };        | ||||
|         narrow(eval, budget); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     bool viable_set::intersect_ule(rational const& a, rational const& b, rational const& c, rational const& d, bool is_positive) { | ||||
|         // x <= 0
 | ||||
|         if (a.is_odd() && b == 0 && c == 0 && d == 0) | ||||
|  | @ -114,21 +124,13 @@ namespace polysat { | |||
|             else | ||||
|                 set_hi(b - 1); | ||||
|         } | ||||
|         else if (c == 0 && d == 0) { | ||||
|             // ax + b <= 0
 | ||||
|             // or ax + b > 0
 | ||||
|             intersect_eq(a, b, is_positive); | ||||
|         } | ||||
|         else | ||||
|             return false; | ||||
| 
 | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     void viable_set::intersect_ule(rational const& a, rational const& b, rational const& c, rational const& d, bool is_positive, unsigned& budget) { | ||||
|         auto eval = [&](rational const& x) { | ||||
|             return is_positive == mod(a * x + b, p2()) <= mod(c * x + d, p2()); | ||||
|         };         | ||||
|     void viable_set::narrow(std::function<bool(rational const&)>& eval, unsigned& budget) { | ||||
|         while (budget > 0 && !eval(lo) && !is_max(lo) && !is_empty()) { | ||||
|             --budget; | ||||
|             lo += 1; | ||||
|  | @ -141,6 +143,13 @@ namespace polysat { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void viable_set::intersect_ule(rational const& a, rational const& b, rational const& c, rational const& d, bool is_positive, unsigned& budget) { | ||||
|         std::function<bool(rational const&)> eval = [&](rational const& x) { | ||||
|             return is_positive == mod(a * x + b, p2()) <= mod(c * x + d, p2()); | ||||
|         };        | ||||
|         narrow(eval, budget); | ||||
|     } | ||||
| 
 | ||||
|     void viable_set::set_hi(rational const& d) { | ||||
|         if (is_max(d)) | ||||
|             return; | ||||
|  | @ -149,9 +158,11 @@ namespace polysat { | |||
|         else if (lo > d) | ||||
|             set_empty(); | ||||
|         else if (hi != 0 || d + 1 < hi) | ||||
|             hi = d + 1;        | ||||
|             hi = d + 1;   | ||||
|         else if (d + 1 == hi) | ||||
|             return; | ||||
|         else  | ||||
|             std::cout << "set hi " << lo << " " << d << " " << hi << "\n"; | ||||
|             std::cout << "set hi " << d << " " << *this << "\n"; | ||||
|     } | ||||
| 
 | ||||
|     void viable_set::set_lo(rational const& b) { | ||||
|  | @ -161,8 +172,10 @@ namespace polysat { | |||
|             lo = b, hi = 0; | ||||
|         else if (lo < b) | ||||
|             lo = b;                     | ||||
|         else if (lo == b) | ||||
|             return; | ||||
|         else  | ||||
|             std::cout << "set lo " << lo << " " << b << " " << hi << "\n"; | ||||
|             std::cout << "set lo " << b << " " << *this << "\n"; | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|  | @ -187,7 +200,15 @@ namespace polysat { | |||
|     void viable::intersect_eq(rational const& a, pvar v, rational const& b, bool is_positive) { | ||||
| #if NEW_VIABLE | ||||
|         push_viable(v); | ||||
|         m_viable[v].intersect_eq(a, b, is_positive); | ||||
|         if (!m_viable[v].intersect_eq(a, b, is_positive)) { | ||||
|             IF_VERBOSE(10, verbose_stream() << "could not intersect v" << v << " " << m_viable[v] << "\n"); | ||||
|             unsigned budget = 10; | ||||
|             m_viable[v].intersect_eq(a, b, is_positive, budget); | ||||
|             if (budget == 0) { | ||||
|                 std::cout << "budget used\n"; | ||||
|                 // then narrow the range using BDDs
 | ||||
|             } | ||||
|         } | ||||
|         if (m_viable[v].is_empty()) | ||||
|             s.set_conflict(v); | ||||
| #else | ||||
|  | @ -218,6 +239,9 @@ namespace polysat { | |||
| 
 | ||||
|     void viable::intersect_ule(pvar v, rational const& a, rational const& b, rational const& c, rational const& d, bool is_positive) { | ||||
| #if NEW_VIABLE | ||||
|         // 
 | ||||
|         // TODO This code needs to be partitioned into self-contained pieces.
 | ||||
|         //
 | ||||
|         push_viable(v); | ||||
|         if (!m_viable[v].intersect_ule(a, b, c, d, is_positive)) { | ||||
|             unsigned budget = 10; | ||||
|  | @ -235,15 +259,30 @@ namespace polysat { | |||
|                     other = alloc(ineq_entry, sz, a, b, c, d, le); | ||||
|                     m_ineq_cache.insert(other); | ||||
|                 } | ||||
|                 le = is_positive ? other->repr : !other->repr; | ||||
|                 bdd gt = is_positive ? !other->repr : other->repr; | ||||
|                 other->m_activity++; | ||||
| 
 | ||||
|                 // 
 | ||||
|                 // instead of using activity for GC, use the Move-To-Front approach 
 | ||||
|                 // see sat/smt/bv_ackerman.h or sat/smt/euf_ackerman.h
 | ||||
|                 // where hash table entries use a dll_base.
 | ||||
|                 // 
 | ||||
| 
 | ||||
|                 // le(lo) is false: find min x >= lo, such that le(x) is false, le(x+1) is true
 | ||||
|                 // le(hi) is false: find max x =< hi, such that le(x) is false, le(x-1) is true
 | ||||
|                  | ||||
|                 // bdd x_is_lo = m.mk_num(sz, m_viable[v].lo) == var2bits(v).var();
 | ||||
|                 // bdd lo_is_sat = x_is_lo && lo;
 | ||||
|                 // if (lo_is_sat.is_false())
 | ||||
|                 //     find_min_above(lo, le);
 | ||||
|                 rational bound = m_viable[v].lo; | ||||
|                 if (var2bits(v).sup(gt, bound)) { | ||||
|                     m_viable[v].set_lo(bound); | ||||
|                     m_viable[v].set_ne(bound); | ||||
|                 } | ||||
|                 bound = m_viable[v].hi; | ||||
|                 if (bound != 0) { | ||||
|                     bound = bound - 1; | ||||
|                     if (var2bits(v).inf(gt, bound)) { | ||||
|                         std::cout << "TODO: new upper bound " << bound << "\n"; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|  | @ -285,8 +324,8 @@ namespace polysat { | |||
|     void viable::add_non_viable(pvar v, rational const& val) { | ||||
| #if NEW_VIABLE | ||||
|         push_viable(v); | ||||
|         IF_VERBOSE(10, verbose_stream() << " v" << v << " != " << val << "\n"); | ||||
|         m_viable[v].set_ne(val); | ||||
|         std::cout << " v" << v << " != " << val << "\n"; | ||||
|         if (m_viable[v].is_empty()) | ||||
|             s.set_conflict(v); | ||||
| #else | ||||
|  |  | |||
|  | @ -11,6 +11,11 @@ Author: | |||
|     Nikolaj Bjorner (nbjorner) 2021-03-19 | ||||
|     Jakob Rath 2021-04-6 | ||||
| 
 | ||||
| Notes: | ||||
| 
 | ||||
|     NEW_VIABLE uses cheaper book-keeping, but is partial. | ||||
|     The implementation of NEW_VIABLE is atm incomplete and ad-hoc. | ||||
|      | ||||
| --*/ | ||||
| #pragma once | ||||
| 
 | ||||
|  | @ -18,10 +23,7 @@ Author: | |||
| 
 | ||||
| #include <limits> | ||||
| 
 | ||||
| #if !NEW_VIABLE | ||||
| #include "math/dd/dd_bdd.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "math/polysat/types.h" | ||||
| #include "math/interval/mod_interval.h" | ||||
| 
 | ||||
|  | @ -43,15 +45,17 @@ namespace polysat { | |||
|         unsigned m_num_bits; | ||||
|         rational p2() const { return rational::power_of_two(m_num_bits); } | ||||
|         bool is_max(rational const& a) const; | ||||
|         void set_lo(rational const& lo); | ||||
|         void set_hi(rational const& hi); | ||||
|         void intersect_eq(rational const& a, bool is_positive); | ||||
|         void narrow(std::function<bool(rational const&)>& eval, unsigned& budget); | ||||
|     public: | ||||
|         viable_set(unsigned num_bits): m_num_bits(num_bits) {} | ||||
|         bool is_singleton() const;  | ||||
|         dd::find_t find_hint(rational const& c, rational& val) const; | ||||
|         void set_ne(rational const& a) { intersect_eq(a, false); } | ||||
|         void intersect_eq(rational const& a, rational const& b, bool is_positive); | ||||
|         void set_lo(rational const& lo); | ||||
|         void set_hi(rational const& hi); | ||||
|         bool intersect_eq(rational const& a, rational const& b, bool is_positive); | ||||
|         void intersect_eq(rational const& a, rational const& b, bool is_positive, unsigned& budget); | ||||
|         bool intersect_ule(rational const& a, rational const& b, rational const& c, rational const& d, bool is_positive); | ||||
|         void intersect_ule(rational const& a, rational const& b, rational const& c, rational const& d, bool is_positive, unsigned& budget); | ||||
|     }; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue