mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 19:52:29 +00:00 
			
		
		
		
	produce the first lemma in niil_solver
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
		
							parent
							
								
									0911fc2bda
								
							
						
					
					
						commit
						49ae42cebd
					
				
					 6 changed files with 136 additions and 66 deletions
				
			
		|  | @ -430,7 +430,6 @@ class theory_lra::imp { | |||
|     } | ||||
|     void ensure_niil() { | ||||
|         if (!m_niil) { | ||||
|             std::cout << "ensure_niil\n"; | ||||
|             m_niil = alloc(niil::solver, *m_solver.get(), m.limit(), ctx().get_params()); | ||||
|             m_switcher.m_niil = &m_niil; | ||||
|             for (auto const& _s : m_scopes) { | ||||
|  |  | |||
|  | @ -32,5 +32,6 @@ public: | |||
|         m_explanation.push_back(std::make_pair(one_of_type<mpq>(), j)); | ||||
|     } | ||||
|     void reset() { m_explanation.reset(); } | ||||
|     template <typename A> void add(const A& a) { for (constraint_index j : a) push_justification(j); } | ||||
| }; | ||||
| } | ||||
|  |  | |||
|  | @ -195,9 +195,6 @@ public: | |||
|         mpq big_number = m_abs_max.expt(3); | ||||
|         mpq d = hnf_calc::determinant_of_rectangular_matrix(m_A, basis_rows, big_number); | ||||
|          | ||||
|         // std::cout << "max = " << m_abs_max << ", d = " << d << ", d/max = " << ceil (d /m_abs_max) << std::endl;
 | ||||
|         // std::cout << "max cube " << m_abs_max * m_abs_max * m_abs_max << std::endl;
 | ||||
| 
 | ||||
|         if (d >= big_number) { | ||||
|             return lia_move::undef; | ||||
|         } | ||||
|  |  | |||
|  | @ -13,6 +13,8 @@ namespace nra { | |||
|         svector<lp::var_index> m_vs; | ||||
|         unsigned var() const { return m_v; } | ||||
|         unsigned size() const { return m_vs.size(); } | ||||
|         svector<lp::var_index>::const_iterator begin() const { return m_vs.begin(); } | ||||
|         svector<lp::var_index>::const_iterator end() const { return m_vs.end(); } | ||||
|     }; | ||||
| 
 | ||||
| typedef std::unordered_map<lp::var_index, rational> variable_map_type; | ||||
|  |  | |||
|  | @ -22,30 +22,57 @@ Revision History: | |||
| #include "util/lp/mon_eq.h" | ||||
| #include "util/lp/lp_utils.h" | ||||
| namespace niil { | ||||
| 
 | ||||
| typedef std::unordered_set<lp::constraint_index> expl_set; | ||||
| typedef nra::mon_eq mon_eq; | ||||
| typedef lp::var_index lpvar; | ||||
| struct solver::imp { | ||||
|     struct vars_equivalence { | ||||
|         struct signed_var { | ||||
|             lpvar m_var; | ||||
|             int   m_sign; | ||||
|             signed_var(lpvar j, int sign) : m_var(j), m_sign(sign) {} | ||||
|         }; | ||||
|         struct equiv { | ||||
|             lpvar             m_i; | ||||
|             signed_var        m_signed_var; | ||||
|             equiv(lpvar i, lpvar j, int sign) :m_i(i), m_signed_var(j, sign) { | ||||
|             lpvar                m_i; | ||||
|             lpvar                m_j; | ||||
|             int                  m_sign; | ||||
|             lp::constraint_index m_c0; | ||||
|             lp::constraint_index m_c1; | ||||
|              | ||||
|             equiv(lpvar i, lpvar j, int sign, lp::constraint_index c0, lp::constraint_index c1) : | ||||
|                 m_i(i), | ||||
|                 m_j(j), | ||||
|                 m_sign(sign), | ||||
|                 m_c0(c0), | ||||
|                 m_c1(c1) | ||||
|             { | ||||
|                 SASSERT(i > j); | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         // the resulting mapping
 | ||||
|         std::unordered_map<lpvar, signed_var> m_map; | ||||
|         // all equivalences extracted from constraints
 | ||||
|         vector<equiv>                         m_equivs; | ||||
|         struct eq_var { | ||||
|             lpvar m_var; | ||||
|             int   m_sign; | ||||
|             expl_set m_explanation; | ||||
|             eq_var(const equiv& e) : | ||||
|                 m_var(e.m_j), | ||||
|                 m_sign(e.m_sign) { | ||||
|                 m_explanation.insert(e.m_c0); m_explanation.insert(e.m_c1); | ||||
|             } | ||||
|             void improve(const equiv & e) { | ||||
|                 SASSERT(e.m_j > m_var); | ||||
|                 m_var = e.m_j; | ||||
|                 m_sign *= e.m_sign; | ||||
|                 m_explanation.insert(e.m_c0); m_explanation.insert(e.m_c1); | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         std::unordered_map<lpvar, eq_var> m_map;         // the resulting mapping
 | ||||
|         vector<equiv>                     m_equivs;         // all equivalences extracted from constraints
 | ||||
| 
 | ||||
|         void clear() { | ||||
|             m_equivs.clear(); | ||||
|             m_map.clear(); | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         unsigned size() const { return m_map.size(); } | ||||
|         void add_equivalence_maybe(const lp::lar_term *t) { | ||||
|         void add_equivalence_maybe(const lp::lar_term *t, lp::constraint_index c0, lp::constraint_index c1) { | ||||
|             if (t->size() != 2 || ! t->m_v.is_zero()) | ||||
|                 return; | ||||
|             bool seen_minus = false; | ||||
|  | @ -72,7 +99,7 @@ struct solver::imp { | |||
|                 j = tmp; | ||||
|             } | ||||
|             int sign = (seen_minus && seen_plus)? 1 : -1; | ||||
|             m_equivs.push_back(equiv(i, j, sign)); | ||||
|             m_equivs.push_back(equiv(i, j, sign, c0, c1)); | ||||
|         } | ||||
| 
 | ||||
|         void collect_equivs(const lp::lar_solver& s) { | ||||
|  | @ -87,46 +114,42 @@ struct solver::imp { | |||
|                 if (s.get_upper_bound(j) != lp::zero_of_type<lp::impq>() || | ||||
|                     s.get_lower_bound(j) != lp::zero_of_type<lp::impq>()) | ||||
|                     continue; | ||||
|                 add_equivalence_maybe(s.terms()[i]); | ||||
|                 add_equivalence_maybe(s.terms()[i], s.get_column_upper_bound_witness(j), s.get_column_lower_bound_witness(j)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         void create_map() { | ||||
|             bool progress = true; | ||||
|             while (progress) { | ||||
|             bool progress; | ||||
|             do { | ||||
|                 progress = false; | ||||
|                 for (const auto & e : m_equivs) { | ||||
|                     unsigned i = e.m_i; | ||||
|                     auto it = m_map.find(i); | ||||
|                     if (it == m_map.end()) { | ||||
|                         m_map.insert(std::pair<lpvar, signed_var>(i, e.m_signed_var)); | ||||
|                         m_map.emplace(i, eq_var(e)); | ||||
|                         progress = true; | ||||
|                     } else { | ||||
|                         if (it->second.m_var > e.m_signed_var.m_var) { | ||||
|                             it->second = signed_var( | ||||
|                                 e.m_signed_var.m_var, | ||||
|                                 e.m_signed_var.m_sign * it->second.m_sign); | ||||
|                         if (it->second.m_var > e.m_j) { | ||||
|                             it->second.improve(e); | ||||
|                             progress = true; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             } while(progress); | ||||
|         } | ||||
|          | ||||
|         void init(const lp::lar_solver& s) { | ||||
|             clear(); | ||||
|             collect_equivs(s); | ||||
|             create_map(); | ||||
|         } | ||||
|         lpvar get_equivalent_var(lpvar j, bool & sign) { | ||||
|             SASSERT(false); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         bool empty() const { | ||||
|             return m_map.empty(); | ||||
|         } | ||||
| 
 | ||||
|         // the sign is flipped if needed
 | ||||
|         lpvar map_to_min(lpvar j, int sign) const { | ||||
|         lpvar map_to_min(lpvar j, int& sign) const { | ||||
|             auto it = m_map.find(j); | ||||
|             if (it == m_map.end()) | ||||
|                 return j; | ||||
|  | @ -136,13 +159,28 @@ struct solver::imp { | |||
|             } | ||||
|             return it->second.m_var; | ||||
|         } | ||||
| 
 | ||||
|         template <typename T> | ||||
|         void add_expl_from_monomial(const T & m, expl_set & exp) const { | ||||
|             for (auto j : m) | ||||
|                 add_equiv_exp(j, exp); | ||||
|         } | ||||
|          | ||||
|     }; | ||||
|         void add_equiv_exp(lpvar j, expl_set & exp) const { | ||||
|             auto it = m_map.find(j); | ||||
|             if (it == m_map.end()) | ||||
|                 return; | ||||
|             for (auto k : it->second.m_explanation) | ||||
|                 exp.insert(k); | ||||
|         } | ||||
|     }; // end of vars_equivalence
 | ||||
|     vars_equivalence                                       m_vars_equivalence; | ||||
|     vector<mon_eq>                                         m_monomials; | ||||
|     unsigned_vector                                        m_monomials_lim; | ||||
|     lp::lar_solver&                                        m_lar_solver; | ||||
|     std::unordered_map<lpvar, svector<unsigned>>   m_var_to_monomials; | ||||
|     std::unordered_map<lpvar, svector<unsigned>>           m_var_to_monomials; | ||||
|     lp::explanation *                                      m_expl; | ||||
|     lemma *                                                m_lemma; | ||||
|     imp(lp::lar_solver& s, reslimit& lim, params_ref const& p) | ||||
|         : m_lar_solver(s) | ||||
|         // m_limit(lim),
 | ||||
|  | @ -189,7 +227,7 @@ struct solver::imp { | |||
|         unsigned i_mon, | ||||
|         unsigned j_var, | ||||
|         const svector<unsigned> & mon_vars, | ||||
|         const mon_eq& other_m, int sign, lemma& l) { | ||||
|         const mon_eq& other_m, int sign) { | ||||
|         if (mon_vars.size() != other_m.size()) | ||||
|             return false; | ||||
| 
 | ||||
|  | @ -199,7 +237,9 @@ struct solver::imp { | |||
|         if (var_vectors_are_equal(mon_vars, other_vars_copy) | ||||
|             && values_are_different(m_monomials[i_mon].var(), | ||||
|                                     sign * other_sign, other_m.var())) { | ||||
|             fill_lemma(); | ||||
|             fill_explanation_and_lemma(m_monomials[i_mon], | ||||
|                                        other_m, | ||||
|                                        sign* other_sign); | ||||
|             return true; | ||||
|         } | ||||
|              | ||||
|  | @ -210,13 +250,46 @@ struct solver::imp { | |||
|         SASSERT(sign == 1 || sign == -1); | ||||
|         return ! ( sign * m_lar_solver.get_column_value(j) == m_lar_solver.get_column_value(k)); | ||||
|     } | ||||
|      | ||||
|     void fill_lemma() { | ||||
|         SASSERT(false); // not implemented
 | ||||
| 
 | ||||
|     void add_expl_from_monomial(const mon_eq& m, expl_set & eset) const { | ||||
|         m_vars_equivalence.add_expl_from_monomial(m, eset); | ||||
|     } | ||||
| 
 | ||||
|     void print_monomial(const mon_eq& m, std::ostream& out) { | ||||
|         out << m_lar_solver.get_column_name(m.var()) << " = "; | ||||
|         for (unsigned j : m) { | ||||
|             out << m_lar_solver.get_column_name(j) << "*"; | ||||
|         } | ||||
|     } | ||||
|     // the monomials should be equal by modulo sign, but they are not equal in the model
 | ||||
|     void fill_explanation_and_lemma(const mon_eq& a, const mon_eq & b, int sign) { | ||||
|         expl_set expl; | ||||
|         SASSERT(sign == 1 || sign == -1); | ||||
|         add_expl_from_monomial(a, expl); | ||||
|         add_expl_from_monomial(b, expl); | ||||
|         m_expl->clear(); | ||||
|         m_expl->add(expl); | ||||
|         TRACE("niil_solver", | ||||
|         for (auto &p : *m_expl) | ||||
|             m_lar_solver.print_constraint(p.second, tout); tout << "\n"; | ||||
|               ); | ||||
|         lp::lar_term t; | ||||
|         t.add_monomial(rational(1), a.var()); | ||||
|         t.add_monomial(rational(- sign), b.var()); | ||||
|         TRACE("niil_solver",  | ||||
|         m_lar_solver.print_term(t, tout); | ||||
|         tout << "\n"; | ||||
|         print_monomial(a, tout); | ||||
|         tout << "\n"; | ||||
|         print_monomial(b, tout); | ||||
|               ); | ||||
| 
 | ||||
|         ineq in(lp::lconstraint_kind::NE, t); | ||||
|         m_lemma->push_back(in); | ||||
|     } | ||||
|      | ||||
|     bool generate_basic_lemma_for_mon_sign_var(unsigned i_mon, | ||||
|                                                unsigned j_var, const svector<lpvar>& mon_vars, lemma& l, int sign) { | ||||
|                                                unsigned j_var, const svector<lpvar>& mon_vars, int sign) { | ||||
|         auto it = m_var_to_monomials.find(j_var); | ||||
|         for (auto other_i_mon : it->second) { | ||||
|             if (other_i_mon == i_mon) continue; | ||||
|  | @ -225,8 +298,7 @@ struct solver::imp { | |||
|                     j_var, | ||||
|                     mon_vars, | ||||
|                     m_monomials[other_i_mon], | ||||
|                     sign, | ||||
|                     l)) | ||||
|                     sign)) | ||||
|                 return true; | ||||
|         } | ||||
|         return false; | ||||
|  | @ -239,12 +311,9 @@ struct solver::imp { | |||
|         } | ||||
|     } | ||||
|      | ||||
|     bool generate_basic_lemma_for_mon_sign(unsigned i_mon, lemma& l) { | ||||
|     bool generate_basic_lemma_for_mon_sign(unsigned i_mon) { | ||||
|         if (m_vars_equivalence.empty()) { | ||||
|             std::cout << "empty m_vars_equivalence\n"; | ||||
|             return false; | ||||
|         } else { | ||||
|             std::cout << "m_vars_equivalence size = " << m_vars_equivalence.size() << std::endl; | ||||
|         } | ||||
|         const mon_eq& m_of_i = m_monomials[i_mon]; | ||||
|         int sign = 1; | ||||
|  | @ -252,33 +321,33 @@ struct solver::imp { | |||
|         auto mon_vars =  m_of_i.m_vs; | ||||
|         reduce_monomial_to_minimal(mon_vars, sign); | ||||
|         for (unsigned j_var : mon_vars) | ||||
|             if (generate_basic_lemma_for_mon_sign_var(i_mon, j_var, mon_vars, l, sign)) | ||||
|             if (generate_basic_lemma_for_mon_sign_var(i_mon, j_var, mon_vars, sign)) | ||||
|                 return true; | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     bool generate_basic_lemma_for_mon_zero(unsigned i_mon, lemma& l) { | ||||
|     bool generate_basic_lemma_for_mon_zero(unsigned i_mon) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     bool generate_basic_lemma_for_mon_neutral(unsigned i_mon, lemma& l) { | ||||
|     bool generate_basic_lemma_for_mon_neutral(unsigned i_mon) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     bool generate_basic_lemma_for_mon_proportionality(unsigned i_mon, lemma& l) { | ||||
|     bool generate_basic_lemma_for_mon_proportionality(unsigned i_mon) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     bool generate_basic_lemma_for_mon(unsigned i_mon, lemma & l) { | ||||
|         return generate_basic_lemma_for_mon_sign(i_mon, l) | ||||
|             || generate_basic_lemma_for_mon_zero(i_mon, l) | ||||
|             || generate_basic_lemma_for_mon_neutral(i_mon, l) | ||||
|             || generate_basic_lemma_for_mon_proportionality(i_mon, l); | ||||
|     bool generate_basic_lemma_for_mon(unsigned i_mon) { | ||||
|         return generate_basic_lemma_for_mon_sign(i_mon) | ||||
|             || generate_basic_lemma_for_mon_zero(i_mon) | ||||
|             || generate_basic_lemma_for_mon_neutral(i_mon) | ||||
|             || generate_basic_lemma_for_mon_proportionality(i_mon); | ||||
|     } | ||||
| 
 | ||||
|     bool generate_basic_lemma(lemma & l, svector<unsigned> & to_refine) { | ||||
|     bool generate_basic_lemma(svector<unsigned> & to_refine) { | ||||
|         for (unsigned i : to_refine) | ||||
|             if (generate_basic_lemma_for_mon(i, l)) | ||||
|             if (generate_basic_lemma_for_mon(i)) | ||||
|                 return true; | ||||
|         return false; | ||||
|     } | ||||
|  | @ -312,27 +381,27 @@ struct solver::imp { | |||
|         init_vars_equivalence(); | ||||
|     } | ||||
|      | ||||
|     lbool check(lemma& l) { | ||||
|     lbool check(lp::explanation & exp, lemma& l) { | ||||
|         m_expl =   &exp; | ||||
|         m_lemma =  &l; | ||||
|         lp_assert(m_lar_solver.get_status() == lp::lp_status::OPTIMAL); | ||||
|         svector<unsigned> to_refine; | ||||
|         for (unsigned i = 0; i < m_monomials.size(); i++) { | ||||
|             if (!check_monomial(m_monomials[i])) | ||||
|                 to_refine.push_back(i); | ||||
|         } | ||||
|         std::cout << "to_refine size = " << to_refine.size() << std::endl; | ||||
| 
 | ||||
|         if (to_refine.size() == 0) | ||||
|             return l_true; | ||||
| 
 | ||||
|         init_search(); | ||||
|          | ||||
|         if (generate_basic_lemma(l, to_refine)) | ||||
|             return l_true; | ||||
|         if (generate_basic_lemma(to_refine)) | ||||
|             return l_false; | ||||
|          | ||||
|         return l_undef; | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| }; // end of imp
 | ||||
| 
 | ||||
| void solver::add_monomial(lpvar v, unsigned sz, lpvar const* vs) { | ||||
|     m_imp->add(v, sz, vs); | ||||
|  | @ -341,7 +410,7 @@ void solver::add_monomial(lpvar v, unsigned sz, lpvar const* vs) { | |||
| bool solver::need_check() { return true; } | ||||
| 
 | ||||
| lbool solver::check(lp::explanation & ex, lemma& l) { | ||||
|     return m_imp->check(l); | ||||
|     return m_imp->check(ex, l); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -28,6 +28,8 @@ namespace niil { | |||
| struct ineq { | ||||
|     lp::lconstraint_kind m_cmp; | ||||
|     lp::lar_term         m_term; | ||||
|     ineq(lp::lconstraint_kind cmp, | ||||
|          const lp::lar_term& term) : m_cmp(cmp), m_term(term) {}  | ||||
| }; | ||||
| 
 | ||||
| typedef vector<ineq> lemma; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue