3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 17:15:31 +00:00

Nlsat simplify (#7227)

* dev branch for simplification

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* bug fixes

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* bugfixes

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* fix factorization

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* separate out simplification functionality

* reorder initialization

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* reorder initialization

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* Update README.md

* initial warppers for seq-map/seq-fold

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* expose fold as well

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* add C++ bindings for sequence operations

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* add abs function to API

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* add parameter validation to ternary and 4-ary functions for API #7219

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* add pre-processing and reorder

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* add pre-processing and reorder

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

---------

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2024-05-14 22:19:33 -07:00 committed by GitHub
parent e036a5bd9b
commit 8fe357f1f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 1275 additions and 844 deletions

View file

@ -128,8 +128,12 @@ struct statistics {
unsigned m_grobner_conflicts;
unsigned m_offset_eqs;
unsigned m_fixed_eqs;
::statistics m_st;
statistics() { reset(); }
void reset() { memset(this, 0, sizeof(*this)); }
void reset() {
memset(this, 0, sizeof(*this));
m_st.reset();
}
void collect_statistics(::statistics& st) const {
st.update("arith-factorizations", m_num_factorizations);
st.update("arith-make-feasible", m_make_feasible);
@ -157,7 +161,7 @@ struct statistics {
st.update("arith-nla-lemmas", m_nla_lemmas);
st.update("arith-nra-calls", m_nra_calls);
st.update("arith-bounds-improvements", m_nla_bounds_improvements);
st.copy(m_st);
}
};

View file

@ -34,7 +34,7 @@ struct solver::imp {
scoped_ptr<scoped_anum_vector> m_values; // values provided by LRA solver
scoped_ptr<scoped_anum> m_tmp1, m_tmp2;
nla::core& m_nla_core;
imp(lp::lar_solver& s, reslimit& lim, params_ref const& p, nla::core& nla_core):
lra(s),
m_limit(lim),
@ -180,6 +180,7 @@ struct solver::imp {
}
lbool r = l_undef;
statistics& st = m_nla_core.lp_settings().stats().m_st;
try {
r = m_nlsat->check();
}
@ -188,9 +189,11 @@ struct solver::imp {
r = l_undef;
}
else {
m_nlsat->collect_statistics(st);
throw;
}
}
m_nlsat->collect_statistics(st);
TRACE("nra",
m_nlsat->display(tout << r << "\n");
display(tout);
@ -234,6 +237,7 @@ struct solver::imp {
return r;
}
void add_monic_eq_bound(mon_eq const& m) {
if (!lra.column_has_lower_bound(m.var()) &&
!lra.column_has_upper_bound(m.var()))
@ -374,6 +378,7 @@ struct solver::imp {
}
lbool r = l_undef;
statistics& st = m_nla_core.lp_settings().stats().m_st;
try {
r = m_nlsat->check();
}
@ -382,9 +387,11 @@ struct solver::imp {
r = l_undef;
}
else {
m_nlsat->collect_statistics(st);
throw;
}
}
m_nlsat->collect_statistics(st);
switch (r) {
case l_true:
@ -665,7 +672,7 @@ nlsat::anum_manager& solver::am() {
scoped_anum& solver::tmp1() { return m_imp->tmp1(); }
scoped_anum& solver::tmp2() { return m_imp->tmp2(); }
void solver::updt_params(params_ref& p) {
m_imp->updt_params(p);

View file

@ -2594,27 +2594,28 @@ namespace algebraic_numbers {
void int_lt(numeral const & a, numeral & b) {
scoped_mpz v(qm());
if (!a.is_basic())
refine_until_prec(const_cast<numeral&>(a), 1);
if (a.is_basic()) {
qm().floor(basic_value(a), v);
qm().dec(v);
}
else {
refine_until_prec(const_cast<numeral&>(a), 1);
bqm().floor(qm(), lower(a.to_algebraic()), v);
}
else
bqm().floor(qm(), lower(a.to_algebraic()), v);
m_wrapper.set(b, v);
}
void int_gt(numeral const & a, numeral & b) {
scoped_mpz v(qm());
if (!a.is_basic())
refine_until_prec(const_cast<numeral&>(a), 1);
if (a.is_basic()) {
qm().ceil(basic_value(a), v);
qm().inc(v);
}
else {
refine_until_prec(const_cast<numeral&>(a), 1);
else
bqm().ceil(qm(), upper(a.to_algebraic()), v);
}
m_wrapper.set(b, v);
}

View file

@ -2504,30 +2504,139 @@ namespace polynomial {
return p;
}
void gcd_simplify(polynomial * p) {
if (m_manager.finite()) return;
void gcd_simplify(polynomial_ref& p, manager::ineq_type t) {
auto& m = m_manager.m();
unsigned sz = p->size();
if (sz == 0)
return;
unsigned g = 0;
for (unsigned i = 0; i < sz; i++) {
for (unsigned i = 0; i < sz; i++) {
if (!m.is_int(p->a(i))) {
gcd_simplify_slow(p, t);
return;
}
if (t != EQ && is_unit(p->m(i)))
continue;
int j = m.get_int(p->a(i));
if (j == INT_MIN || j == 1 || j == -1)
if (j == INT_MIN) {
gcd_simplify_slow(p, t);
return;
}
if (j == 1 || j == -1)
return;
g = u_gcd(abs(j), g);
if (g == 1)
return;
}
scoped_mpz r(m), gg(m);
scoped_mpz gg(m);
m.set(gg, g);
for (unsigned i = 0; i < sz; ++i) {
m.div_gcd(p->a(i), gg, r);
m.set(p->a(i), r);
apply_gcd_simplify(gg, p, t);
}
void apply_gcd_simplify(mpz & g, polynomial_ref& p, manager::ineq_type t) {
auto& m = m_manager.m();
#if 0
m.display(verbose_stream() << "gcd ", g);
p->display(verbose_stream() << "\n", m_manager, false);
char const* tt = "";
switch (t) {
case ineq_type::GT: tt = ">"; break;
case ineq_type::LT: tt = "<"; break;
case ineq_type::EQ: tt = "="; break;
}
verbose_stream() << " " << tt << " 0\n ->\n";
#endif
scoped_mpz r(m);
unsigned sz = p->size();
m_som_buffer.reset();
for (unsigned i = 0; i < sz; ++i) {
if (t != EQ && is_unit(p->m(i))) {
scoped_mpz one(m);
m.set(one, 1);
if (t == GT) {
// p - 2 - 1 >= 0
// p div 2 + floor((-2 - 1 ) / 2) >= 0
// p div 2 + floor(-3 / 2) >= 0
// p div 2 - 2 >= 0
// p div 2 - 1 > 0
//
// p + k > 0
// p + k - 1 >= 0
// p div g + (k - 1) div g >= 0
// p div g + (k - 1) div g + 1 > 0
m.sub(p->a(i), one, r);
bool is_neg = m.is_neg(r);
if (is_neg) {
m.neg(r);
m.add(r, g, r);
m.sub(r, one, r);
m.div_gcd(r, g, r);
m.neg(r);
}
else {
m.div_gcd(r, g, r);
}
m.add(r, one, r);
}
else {
// p + k < 0
// p + k + 1 <= 0
// p div g + (k + 1 + g - 1) div g <= 0
// p div g + (k + 1 + g - 1) div g - 1 < 0
m.add(p->a(i), one, r);
bool is_neg = m.is_neg(r);
if (is_neg) {
// p - k <= 0
// p <= k
// p div g <= k div g
// p div g - k div g <= 0
// p div g - k div g - 1 < 0
m.neg(r);
m.div_gcd(r, g, r);
m.neg(r);
m.sub(r, one, r);
}
else {
m.div_gcd(p->a(i), g, r);
m.add(p->a(i), g, r);
m.div_gcd(r, g, r);
m.sub(r, one, r);
}
}
}
else {
m.div_gcd(p->a(i), g, r);
}
if (!m.is_zero(r))
m_som_buffer.add(r, p->m(i));
}
p = m_som_buffer.mk();
// p->display(verbose_stream(), m_manager, false);
// verbose_stream() << " " << tt << " 0\n";
}
void gcd_simplify_slow(polynomial_ref& p, manager::ineq_type t) {
auto& m = m_manager.m();
unsigned sz = p->size();
scoped_mpz g(m);
m.set(g, 0);
for (unsigned i = 0; i < sz; i++) {
auto const& a = p->a(i);
if (m.is_one(a) || m.is_minus_one(a))
return;
if (t != EQ && is_unit(p->m(i)))
continue;
m.gcd(a, g, g);
if (m.is_one(g))
return;
}
apply_gcd_simplify(g, p, t);
}
polynomial * mk_zero() {
@ -6087,9 +6196,11 @@ namespace polynomial {
}
return false;
}
if (!m_manager.ge(a1, a2))
return false;
++i, ++j;
if (m_manager.eq(a1, a2) || (m1->is_square() && m_manager.ge(a1, a2))) {
++i, ++j;
continue;
}
return false;
}
return i == sz1 && j == sz2;
}
@ -6971,8 +7082,8 @@ namespace polynomial {
return m_imp->hash(p);
}
void manager::gcd_simplify(polynomial * p) {
m_imp->gcd_simplify(p);
void manager::gcd_simplify(polynomial_ref& p, ineq_type t) {
m_imp->gcd_simplify(p, t);
}
polynomial * manager::coeff(polynomial const * p, var x, unsigned k) {

View file

@ -285,7 +285,8 @@ namespace polynomial {
/**
\brief Normalize coefficients by dividing by their gcd
*/
void gcd_simplify(polynomial* p);
enum ineq_type { EQ, LT, GT };
void gcd_simplify(polynomial_ref& p, ineq_type t);
/**
\brief Return true if \c m is the unit monomial.

View file

@ -117,20 +117,14 @@ namespace polynomial {
}
void reset_psc_chain_cache() {
psc_chain_cache::iterator it = m_psc_chain_cache.begin();
psc_chain_cache::iterator end = m_psc_chain_cache.end();
for (; it != end; ++it) {
del_psc_chain_entry(*it);
}
for (auto & k : m_psc_chain_cache)
del_psc_chain_entry(k);
m_psc_chain_cache.reset();
}
void reset_factor_cache() {
factor_cache::iterator it = m_factor_cache.begin();
factor_cache::iterator end = m_factor_cache.end();
for (; it != end; ++it) {
del_factor_entry(*it);
}
for (auto & e : m_factor_cache)
del_factor_entry(e);
m_factor_cache.reset();
}
@ -139,7 +133,6 @@ namespace polynomial {
polynomial * mk_unique(polynomial * p) {
if (m_in_cache.get(pid(p), false))
return p;
// m.gcd_simplify(p);
polynomial * p_prime = m_poly_table.insert_if_not_there(p);
if (p == p_prime) {
m_cached_polys.push_back(p_prime);