mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	separate out bounds
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									1657fc6ebf
								
							
						
					
					
						commit
						cf54e985e8
					
				
					 6 changed files with 103 additions and 30 deletions
				
			
		|  | @ -24,6 +24,7 @@ z3_add_component(lp | ||||||
|     monomial_bounds.cpp |     monomial_bounds.cpp | ||||||
|     nex_creator.cpp |     nex_creator.cpp | ||||||
|     nla_basics_lemmas.cpp |     nla_basics_lemmas.cpp | ||||||
|  |     nla_bounds.cpp | ||||||
|     nla_coi.cpp |     nla_coi.cpp | ||||||
|     nla_common.cpp |     nla_common.cpp | ||||||
|     nla_core.cpp |     nla_core.cpp | ||||||
|  |  | ||||||
							
								
								
									
										42
									
								
								src/math/lp/nla_bounds.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/math/lp/nla_bounds.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | ||||||
|  | 
 | ||||||
|  | /*++
 | ||||||
|  |   Copyright (c) 2025 Microsoft Corporation | ||||||
|  | 
 | ||||||
|  |   Module Name: | ||||||
|  | 
 | ||||||
|  |   nla_bounds.cpp | ||||||
|  | 
 | ||||||
|  |   Author: | ||||||
|  |     Lev Nachmanson (levnach) | ||||||
|  |     Nikolaj Bjorner (nbjorner) | ||||||
|  | 
 | ||||||
|  | --*/ | ||||||
|  | 
 | ||||||
|  | #include "nla_bounds.h" | ||||||
|  | #include "nla_core.h" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | namespace nla { | ||||||
|  | 
 | ||||||
|  |     bounds::bounds(core *c) : common(c) {} | ||||||
|  | 
 | ||||||
|  |     // looking for a free variable inside of a monic to split
 | ||||||
|  |     void bounds::operator()() { | ||||||
|  |         for (lpvar i : c().to_refine()) { | ||||||
|  |             auto const &m = c().emons()[i]; | ||||||
|  |             for (lpvar j : m.vars()) { | ||||||
|  |                 if (!c().var_is_free(j)) | ||||||
|  |                     continue; | ||||||
|  |                 if (m.is_bound_propagated()) | ||||||
|  |                     continue; | ||||||
|  |                 c().emons().set_bound_propagated(m); | ||||||
|  |                 // split the free variable (j <= 0, or j > 0), and return
 | ||||||
|  |                 auto i(ineq(j, lp::lconstraint_kind::LE, rational::zero())); | ||||||
|  |                 c().add_literal(i); | ||||||
|  |                 TRACE(nla_solver, c().print_ineq(i, tout) << "\n"); | ||||||
|  |                 ++c().lp_settings().stats().m_nla_add_bounds; | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }  // namespace nla
 | ||||||
							
								
								
									
										40
									
								
								src/math/lp/nla_bounds.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/math/lp/nla_bounds.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | ||||||
|  | 
 | ||||||
|  | /*++
 | ||||||
|  |   Copyright (c) 2025 Microsoft Corporation | ||||||
|  | 
 | ||||||
|  |   Module Name: | ||||||
|  | 
 | ||||||
|  |   nla_bounds.h | ||||||
|  | 
 | ||||||
|  |   Author: | ||||||
|  |     Lev Nachmanson (levnach) | ||||||
|  |     Nikolaj Bjorner (nbjorner) | ||||||
|  | 
 | ||||||
|  |   Abstract: | ||||||
|  |      Create bounds for variables that occur in non-linear monomials. | ||||||
|  |      The bounds should ensure that variables are either fixes at -1, 0, 1, below or above these values. | ||||||
|  |      This ensures that basic lemmas that case split on values -1, 0, 1 are robust under model changes. | ||||||
|  | 
 | ||||||
|  | --*/ | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #include "math/lp/nla_common.h" | ||||||
|  | #include "math/lp/nla_intervals.h" | ||||||
|  | #include "math/lp/nex.h" | ||||||
|  | #include "math/lp/cross_nested.h" | ||||||
|  | #include "util/uint_set.h" | ||||||
|  | #include "math/grobner/pdd_solver.h" | ||||||
|  | 
 | ||||||
|  | namespace nla { | ||||||
|  |     class core; | ||||||
|  | 
 | ||||||
|  |     class bounds : common { | ||||||
|  |     public: | ||||||
|  |         bounds(core *core); | ||||||
|  |         void operator()(); | ||||||
|  |      | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | }  // namespace nla
 | ||||||
|  | @ -37,7 +37,8 @@ core::core(lp::lar_solver& s, params_ref const& p, reslimit & lim) : | ||||||
|     m_monomial_bounds(this), |     m_monomial_bounds(this), | ||||||
|     m_stellensatz(this), |     m_stellensatz(this), | ||||||
|     m_horner(this), |     m_horner(this), | ||||||
|     m_grobner(this), |     m_grobner(this),  | ||||||
|  |     m_bounds(this), | ||||||
|     m_emons(m_evars), |     m_emons(m_evars), | ||||||
|     m_use_nra_model(false), |     m_use_nra_model(false), | ||||||
|     m_nra(s, m_nra_lim, *this, p), |     m_nra(s, m_nra_lim, *this, p), | ||||||
|  | @ -1268,24 +1269,6 @@ void core::check_bounded_divisions() { | ||||||
|     clear(); |     clear(); | ||||||
|     m_divisions.check_bounded_divisions(); |     m_divisions.check_bounded_divisions(); | ||||||
| } | } | ||||||
| // looking for a free variable inside of a monic to split
 |  | ||||||
| void core::add_bounds() { |  | ||||||
|     for (auto i : m_to_refine) { |  | ||||||
|         auto const& m = m_emons[i]; |  | ||||||
|         for (lpvar j : m.vars()) { |  | ||||||
|             if (!var_is_free(j)) |  | ||||||
|                 continue; |  | ||||||
| 	    if (m.is_bound_propagated()) |  | ||||||
|                 continue; |  | ||||||
| 	    m_emons.set_bound_propagated(m); |  | ||||||
|             // split the free variable (j <= 0, or j > 0), and return
 |  | ||||||
|             m_literals.push_back(ineq(j, lp::lconstraint_kind::EQ, rational::zero())); |  | ||||||
|             TRACE(nla_solver, print_ineq(m_literals.back(), tout) << "\n");                   |  | ||||||
|             ++lp_settings().stats().m_nla_add_bounds; |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|     }     |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| lbool core::check() { | lbool core::check() { | ||||||
|     lp_settings().stats().m_nla_calls++; |     lp_settings().stats().m_nla_calls++; | ||||||
|  | @ -1321,7 +1304,7 @@ lbool core::check() { | ||||||
|     { |     { | ||||||
|         std::function<void(void)> check1 = [&]() { if (no_effect() && run_horner) m_horner.horner_lemmas(); }; |         std::function<void(void)> check1 = [&]() { if (no_effect() && run_horner) m_horner.horner_lemmas(); }; | ||||||
|         std::function<void(void)> check2 = [&]() { if (no_effect() && run_grobner) m_grobner(); }; |         std::function<void(void)> check2 = [&]() { if (no_effect() && run_grobner) m_grobner(); }; | ||||||
|         std::function<void(void)> check3 = [&]() { if (no_effect() && run_bounds) add_bounds(); }; |         std::function<void(void)> check3 = [&]() { if (no_effect() && run_bounds) m_bounds(); }; | ||||||
| 
 | 
 | ||||||
|         std::pair<unsigned, std::function<void(void)>> checks[] = |         std::pair<unsigned, std::function<void(void)>> checks[] = | ||||||
|             { {1, check1}, |             { {1, check1}, | ||||||
|  |  | ||||||
|  | @ -14,14 +14,15 @@ | ||||||
| #include "math/lp/factorization.h" | #include "math/lp/factorization.h" | ||||||
| #include "math/lp/lp_types.h" | #include "math/lp/lp_types.h" | ||||||
| #include "math/lp/var_eqs.h" | #include "math/lp/var_eqs.h" | ||||||
| #include "math/lp/nla_tangent_lemmas.h" |  | ||||||
| #include "math/lp/nla_basics_lemmas.h" | #include "math/lp/nla_basics_lemmas.h" | ||||||
| #include "math/lp/nla_order_lemmas.h" | #include "math/lp/nla_bounds.h" | ||||||
| #include "math/lp/nla_monotone_lemmas.h" |  | ||||||
| #include "math/lp/nla_grobner.h" |  | ||||||
| #include "math/lp/nla_powers.h" |  | ||||||
| #include "math/lp/nla_divisions.h" | #include "math/lp/nla_divisions.h" | ||||||
|  | #include "math/lp/nla_grobner.h" | ||||||
|  | #include "math/lp/nla_monotone_lemmas.h" | ||||||
|  | #include "math/lp/nla_order_lemmas.h" | ||||||
|  | #include "math/lp/nla_powers.h" | ||||||
| #include "math/lp/nla_stellensatz.h" | #include "math/lp/nla_stellensatz.h" | ||||||
|  | #include "math/lp/nla_tangent_lemmas.h" | ||||||
| #include "math/lp/emonics.h" | #include "math/lp/emonics.h" | ||||||
| #include "math/lp/nex.h" | #include "math/lp/nex.h" | ||||||
| #include "math/lp/horner.h" | #include "math/lp/horner.h" | ||||||
|  | @ -95,6 +96,7 @@ class core { | ||||||
|     bool                     m_check_feasible = false; |     bool                     m_check_feasible = false; | ||||||
|     horner                   m_horner; |     horner                   m_horner; | ||||||
|     grobner                  m_grobner; |     grobner                  m_grobner; | ||||||
|  |     bounds                   m_bounds; | ||||||
|     emonics                  m_emons; |     emonics                  m_emons; | ||||||
|     svector<lpvar>           m_add_buffer; |     svector<lpvar>           m_add_buffer; | ||||||
|     mutable indexed_uint_set m_active_var_set; |     mutable indexed_uint_set m_active_var_set; | ||||||
|  | @ -113,7 +115,6 @@ class core { | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     void check_weighted(unsigned sz, std::pair<unsigned, std::function<void(void)>>* checks); |     void check_weighted(unsigned sz, std::pair<unsigned, std::function<void(void)>>* checks); | ||||||
|     void add_bounds(); |  | ||||||
| 
 | 
 | ||||||
|     bool refine_pseudo_linear(); |     bool refine_pseudo_linear(); | ||||||
|     bool is_pseudo_linear(monic const& m) const;     |     bool is_pseudo_linear(monic const& m) const;     | ||||||
|  | @ -454,6 +455,9 @@ public: | ||||||
|     bool use_nra_model() const { return m_use_nra_model; } |     bool use_nra_model() const { return m_use_nra_model; } | ||||||
|     vector<nla::lemma> const& lemmas() const { return m_lemmas; } |     vector<nla::lemma> const& lemmas() const { return m_lemmas; } | ||||||
|     vector<nla::ineq> const& literals() const { return m_literals; } |     vector<nla::ineq> const& literals() const { return m_literals; } | ||||||
|  |     void add_literal(const ineq &n) { | ||||||
|  |         m_literals.push_back(n); | ||||||
|  |     } | ||||||
|     vector<lp::equality> const& equalities() const { return m_equalities; } |     vector<lp::equality> const& equalities() const { return m_equalities; } | ||||||
|     vector<lp::fixed_equality> const& fixed_equalities() const { return m_fixed_equalities; } |     vector<lp::fixed_equality> const& fixed_equalities() const { return m_fixed_equalities; } | ||||||
|     bool should_check_feasible() const { return m_check_feasible; } |     bool should_check_feasible() const { return m_check_feasible; } | ||||||
|  |  | ||||||
|  | @ -317,9 +317,11 @@ namespace nla { | ||||||
|         lhs.add_monomial(rational(1), j); |         lhs.add_monomial(rational(1), j); | ||||||
|         if (non_unit != lp::null_lpvar) { |         if (non_unit != lp::null_lpvar) { | ||||||
|             lhs.add_monomial(rational(-sign), non_unit); |             lhs.add_monomial(rational(-sign), non_unit); | ||||||
|             add_ineq(bounds, lhs, lp::lconstraint_kind::EQ, rational(0)); |             add_ineq(bounds, lhs, lp::lconstraint_kind::GE, rational(0)); | ||||||
|  |             add_ineq(bounds, lhs, lp::lconstraint_kind::LE, rational(0)); | ||||||
|         } else { |         } else { | ||||||
|             add_ineq(bounds, lhs, lp::lconstraint_kind::EQ, rational(sign)); |             add_ineq(bounds, lhs, lp::lconstraint_kind::GE, rational(sign)); | ||||||
|  |             add_ineq(bounds, lhs, lp::lconstraint_kind::LE, rational(sign)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -617,8 +619,8 @@ namespace nla { | ||||||
| 
 | 
 | ||||||
|         while (!to_refine.empty()) { |         while (!to_refine.empty()) { | ||||||
|             lpvar j = to_refine.erase_min();             |             lpvar j = to_refine.erase_min();             | ||||||
|             IF_VERBOSE(2, verbose_stream() << "refining " << m_mon2vars[j] << "\n"); |  | ||||||
|             unsigned sz = m_monomials_to_refine.size(); |             unsigned sz = m_monomials_to_refine.size(); | ||||||
|  |             TRACE(arith, tout << "refining " << m_mon2vars[j] << " sz " << sz << "\n"); | ||||||
|             eliminate(j); |             eliminate(j); | ||||||
|             for (unsigned i = sz; i < m_monomials_to_refine.size(); ++i) { |             for (unsigned i = sz; i < m_monomials_to_refine.size(); ++i) { | ||||||
|                 auto e = m_monomials_to_refine.elem_at(i); |                 auto e = m_monomials_to_refine.elem_at(i); | ||||||
|  | @ -678,6 +680,7 @@ namespace nla { | ||||||
|                 // punt on equality constraints for now
 |                 // punt on equality constraints for now
 | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         TRACE(arith, tout << "eliminate " << m_mon2vars[mi] << " los: " << los << " his: " << his << "\n"); | ||||||
|         if (los.empty() || his.empty()) |         if (los.empty() || his.empty()) | ||||||
|             return; |             return; | ||||||
|         IF_VERBOSE(3, verbose_stream() << "lo " << los << " hi " << his << "\n"); |         IF_VERBOSE(3, verbose_stream() << "lo " << los << " hi " << his << "\n"); | ||||||
|  | @ -1522,7 +1525,7 @@ namespace nla { | ||||||
|             TRACE(arith, s.display(tout)); |             TRACE(arith, s.display(tout)); | ||||||
|             if (!s.saturate_factors()) |             if (!s.saturate_factors()) | ||||||
|                 return l_false; |                 return l_false; | ||||||
|             // s.saturate_constraints(); ?
 |             s.saturate_constraints2(); | ||||||
|             if (sz == lra_solver->number_of_vars()) |             if (sz == lra_solver->number_of_vars()) | ||||||
|                 return l_undef; |                 return l_undef; | ||||||
|         } |         } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue