From 5509b468e95626e195732cc0dcda4d89402a550b Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 31 Aug 2023 17:35:41 -0700 Subject: [PATCH 01/69] handle monomial_bounds::unit_propagate() --- src/math/lp/monomial_bounds.cpp | 16 +++++++++------- src/math/lp/nla_core.cpp | 4 +--- src/smt/theory_lra.cpp | 3 ++- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index 84af29d05..28d287477 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -283,7 +283,7 @@ namespace nla { break; } } - lemma |= ineq(m.var(), lp::lconstraint_kind::EQ, 0); + lemma |= ineq(m.var(), lp::lconstraint_kind::NE, 0); } else { for (auto v : m) @@ -291,12 +291,14 @@ namespace nla { lemma.explain_fixed(v); lpvar w = non_fixed_var(m); - SASSERT(w != null_lpvar); - - lp::lar_term term; - term.add_monomial(-m.rat_sign(), m.var()); - term.add_monomial(k, w); - lemma |= ineq(term, lp::lconstraint_kind::EQ, 0); + if (w != null_lpvar) { + lp::lar_term term; + term.add_var(m.var()); + term.add_monomial(-k, w); + lemma |= ineq(term, lp::lconstraint_kind::NE, 0); + } else { + lemma |= ineq(m.var(), lp::lconstraint_kind::NE, k); + } } } diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 3ab89e012..0e87f8a1d 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -1812,9 +1812,7 @@ bool core::improve_bounds() { } void core::propagate(vector& lemmas) { - // disable for now - return; - // propagate linear monomials + // propagate linear monomials, those that have all, or all but one, variables fixed lemmas.reset(); m_lemma_vec = &lemmas; diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 41426e0d6..31882ea11 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2150,9 +2150,10 @@ public: case l_true: propagate_basic_bounds(); propagate_bounds_with_lp_solver(); + propagate_nla(); break; case l_undef: - propagate_nla(); + UNREACHABLE(); break; } return true; From d3258e7084a17539baf523866cc6271333727c02 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 1 Sep 2023 11:18:03 -0700 Subject: [PATCH 02/69] propagate lineal monomial --- src/math/lp/monomial_bounds.cpp | 6 +++--- src/math/lp/nla_core.cpp | 11 +++++++++++ src/math/lp/nla_types.h | 1 + 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index 28d287477..e21891ee4 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -283,7 +283,7 @@ namespace nla { break; } } - lemma |= ineq(m.var(), lp::lconstraint_kind::NE, 0); + lemma += ineq(m.var(), lp::lconstraint_kind::EQ, 0); } else { for (auto v : m) @@ -295,9 +295,9 @@ namespace nla { lp::lar_term term; term.add_var(m.var()); term.add_monomial(-k, w); - lemma |= ineq(term, lp::lconstraint_kind::NE, 0); + lemma += ineq(term, lp::lconstraint_kind::EQ, 0); } else { - lemma |= ineq(m.var(), lp::lconstraint_kind::NE, k); + lemma += ineq(m.var(), lp::lconstraint_kind::EQ, k); } } diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 0e87f8a1d..622475cf4 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -1056,6 +1056,17 @@ new_lemma& new_lemma::operator|=(ineq const& ineq) { } return *this; } + +// Contrary to new_lemma::operator|=, this method does not assert that the model does not satisfy the ineq. +// If ineq holds then it is a nop. +new_lemma& new_lemma::operator+=(ineq const& ineq) { + if (c.ineq_holds(ineq)) return *this; + + if (!c.explain_ineq(*this, ineq.term(), ineq.cmp(), ineq.rs())) { + current().push_back(ineq); + } + return *this; +} new_lemma::~new_lemma() { diff --git a/src/math/lp/nla_types.h b/src/math/lp/nla_types.h index 8169266cc..186c2e902 100644 --- a/src/math/lp/nla_types.h +++ b/src/math/lp/nla_types.h @@ -83,6 +83,7 @@ namespace nla { new_lemma& operator&=(const factorization& f); new_lemma& operator&=(lpvar j); new_lemma& operator|=(ineq const& i); + new_lemma& operator+=(ineq const& i); new_lemma& explain_fixed(lpvar j); new_lemma& explain_equiv(lpvar u, lpvar v); new_lemma& explain_var_separated_from_zero(lpvar j); From 318d7d7564425ed003d6a342f8c77a0885b838ee Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 1 Sep 2023 11:32:26 -0700 Subject: [PATCH 03/69] fixes a bug --- src/math/lp/nla_core.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 622475cf4..4d4fa6cbe 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -1058,10 +1058,7 @@ new_lemma& new_lemma::operator|=(ineq const& ineq) { } // Contrary to new_lemma::operator|=, this method does not assert that the model does not satisfy the ineq. -// If ineq holds then it is a nop. new_lemma& new_lemma::operator+=(ineq const& ineq) { - if (c.ineq_holds(ineq)) return *this; - if (!c.explain_ineq(*this, ineq.term(), ineq.cmp(), ineq.rs())) { current().push_back(ineq); } From 41f59cb1ed22a344b2b16271a7414c5be168f7d8 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 5 Sep 2023 18:49:59 -0700 Subject: [PATCH 04/69] propagate monomial is nla --- src/math/lp/int_solver.cpp | 2 +- src/math/lp/lar_solver.cpp | 139 ++++++++++++++++++------------ src/math/lp/lar_solver.h | 12 +-- src/math/lp/lp_core_solver_base.h | 4 +- src/math/lp/monomial_bounds.cpp | 132 ++++++++++++++++++++-------- src/math/lp/monomial_bounds.h | 6 +- src/math/lp/nla_core.cpp | 10 ++- src/math/lp/nla_core.h | 2 +- src/smt/theory_arith_aux.h | 5 +- src/smt/theory_arith_nl.h | 3 + src/smt/theory_lra.cpp | 10 ++- 11 files changed, 210 insertions(+), 115 deletions(-) diff --git a/src/math/lp/int_solver.cpp b/src/math/lp/int_solver.cpp index 0ab7d1e40..bd1ac5313 100644 --- a/src/math/lp/int_solver.cpp +++ b/src/math/lp/int_solver.cpp @@ -31,7 +31,7 @@ namespace lp { lra.remove_fixed_vars_from_base(); lp_assert(lia.is_feasible()); for (unsigned j : lra.r_basis()) - if (!lra.get_value(j).is_int() && lra.column_is_int(j)) + if (!lra.get_value(j).is_int() && lra.column_is_int(j)&& !lia.is_fixed(j)) patch_basic_column(j); if (!lia.has_inf_int()) { lia.settings().stats().m_patches_success++; diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 1bd55b9bb..5f82516ef 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -22,7 +22,8 @@ namespace lp { } lar_solver::lar_solver() : - m_crossed_bounds_column(-1), + m_crossed_bounds_column(null_lpvar), + m_crossed_bounds_deps(nullptr), m_mpq_lar_core_solver(m_settings, *this), m_var_register(false), m_term_register(true), @@ -213,17 +214,10 @@ namespace lp { } void lar_solver::fill_explanation_from_crossed_bounds_column(explanation& evidence) const { - lp_assert(static_cast(get_column_type(m_crossed_bounds_column)) >= static_cast(column_type::boxed)); - lp_assert(!column_is_feasible(m_crossed_bounds_column)); - // this is the case when the lower bound is in conflict with the upper one - const ul_pair& ul = m_columns_to_ul_pairs[m_crossed_bounds_column]; svector deps; - m_dependencies.linearize(ul.upper_bound_witness(), deps); - for (auto d : deps) - evidence.add_pair(d, numeric_traits::one()); - deps.reset(); - m_dependencies.linearize(ul.lower_bound_witness(), deps); + SASSERT(m_crossed_bounds_deps != nullptr); + m_dependencies.linearize(m_crossed_bounds_deps, deps); for (auto d : deps) evidence.add_pair(d, -numeric_traits::one()); } @@ -232,7 +226,8 @@ namespace lp { m_simplex_strategy = m_settings.simplex_strategy(); m_simplex_strategy.push(); m_columns_to_ul_pairs.push(); - m_crossed_bounds_column.push(); + m_crossed_bounds_column = null_lpvar; + m_crossed_bounds_deps = nullptr; m_mpq_lar_core_solver.push(); m_term_count = m_terms.size(); m_term_count.push(); @@ -262,7 +257,8 @@ namespace lp { void lar_solver::pop(unsigned k) { TRACE("lar_solver", tout << "k = " << k << std::endl;); - m_crossed_bounds_column.pop(k); + m_crossed_bounds_column = null_lpvar; + m_crossed_bounds_deps = nullptr; unsigned n = m_columns_to_ul_pairs.peek_size(k); m_var_register.shrink(n); pop_tableau(n); @@ -1021,7 +1017,7 @@ namespace lp { void lar_solver::get_infeasibility_explanation(explanation& exp) const { exp.clear(); - if (m_crossed_bounds_column != -1) { + if (m_crossed_bounds_column != null_lpvar) { fill_explanation_from_crossed_bounds_column(exp); return; } @@ -1828,7 +1824,6 @@ namespace lp { if (is_base(j) && column_is_fixed(j)) m_fixed_base_var_set.insert(j); - TRACE("lar_solver_feas", tout << "j = " << j << " became " << (this->column_is_feasible(j) ? "feas" : "non-feas") << ", and " << (this->column_is_bounded(j) ? "bounded" : "non-bounded") << std::endl;); } @@ -1924,7 +1919,6 @@ namespace lp { } } - // clang-format on void lar_solver::update_bound_with_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep) { lp_assert(column_has_lower_bound(j) && column_has_upper_bound(j)); lp_assert(m_mpq_lar_core_solver.m_column_types[j] == column_type::boxed || @@ -1937,12 +1931,14 @@ namespace lp { case LE: { auto up = numeric_pair(right_side, y_of_bound); if (up < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { - set_infeasible_column(j); + set_infeasible_column_and_witness(j, true, dep); + } + else { + if (up >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) return; + m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; + set_upper_bound_witness(j, dep); + insert_to_columns_with_changed_bounds(j); } - if (up >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) return; - m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; - set_upper_bound_witness(j, dep); - insert_to_columns_with_changed_bounds(j); break; } case GT: @@ -1950,25 +1946,33 @@ namespace lp { case GE: { auto low = numeric_pair(right_side, y_of_bound); if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - set_infeasible_column(j); + set_infeasible_column_and_witness(j, false, dep); + } else { + if (low < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { + return; + } + m_mpq_lar_core_solver.m_r_lower_bounds[j] = low; + set_lower_bound_witness(j, dep); + m_mpq_lar_core_solver.m_column_types[j] = (low == m_mpq_lar_core_solver.m_r_upper_bounds[j] ? column_type::fixed : column_type::boxed); + insert_to_columns_with_changed_bounds(j); } - if (low < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { - return; - } - m_mpq_lar_core_solver.m_r_lower_bounds[j] = low; - set_lower_bound_witness(j, dep); - m_mpq_lar_core_solver.m_column_types[j] = (low == m_mpq_lar_core_solver.m_r_upper_bounds[j] ? column_type::fixed : column_type::boxed); - insert_to_columns_with_changed_bounds(j); break; + } case EQ: { auto v = numeric_pair(right_side, zero_of_type()); - if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j] || v < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { - set_infeasible_column(j); + if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]){ + set_infeasible_column_and_witness(j, false, dep); + } + else if (v < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { + set_infeasible_column_and_witness(j, true, dep); + } + else { + set_upper_bound_witness(j, dep); + set_lower_bound_witness(j, dep); + m_mpq_lar_core_solver.m_r_upper_bounds[j] = m_mpq_lar_core_solver.m_r_lower_bounds[j] = v; + insert_to_columns_with_changed_bounds(j); } - set_upper_bound_witness(j, dep); - set_lower_bound_witness(j, dep); - m_mpq_lar_core_solver.m_r_upper_bounds[j] = m_mpq_lar_core_solver.m_r_lower_bounds[j] = v; break; } @@ -1979,7 +1983,7 @@ namespace lp { m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; } } - // clang-format off + void lar_solver::update_bound_with_no_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep) { lp_assert(column_has_lower_bound(j) && !column_has_upper_bound(j)); lp_assert(m_mpq_lar_core_solver.m_column_types[j] == column_type::lower_bound); @@ -1991,12 +1995,14 @@ namespace lp { case LE: { auto up = numeric_pair(right_side, y_of_bound); if (up < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { - set_infeasible_column(j); + set_infeasible_column_and_witness(j, true, dep); + } + else { + m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; + set_upper_bound_witness(j, dep); + m_mpq_lar_core_solver.m_column_types[j] = (up == m_mpq_lar_core_solver.m_r_lower_bounds[j] ? column_type::fixed : column_type::boxed); + insert_to_columns_with_changed_bounds(j); } - m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; - set_upper_bound_witness(j, dep); - m_mpq_lar_core_solver.m_column_types[j] = (up == m_mpq_lar_core_solver.m_r_lower_bounds[j] ? column_type::fixed : column_type::boxed); - insert_to_columns_with_changed_bounds(j); break; } case GT: @@ -2014,13 +2020,15 @@ namespace lp { case EQ: { auto v = numeric_pair(right_side, zero_of_type()); if (v < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { - set_infeasible_column(j); + set_infeasible_column_and_witness(j, true, dep); + } + else { + set_upper_bound_witness(j, dep); + set_lower_bound_witness(j, dep); + m_mpq_lar_core_solver.m_r_upper_bounds[j] = m_mpq_lar_core_solver.m_r_lower_bounds[j] = v; + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + insert_to_columns_with_changed_bounds(j); } - - set_upper_bound_witness(j, dep); - set_lower_bound_witness(j, dep); - m_mpq_lar_core_solver.m_r_upper_bounds[j] = m_mpq_lar_core_solver.m_r_lower_bounds[j] = v; - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; break; } @@ -2051,26 +2059,29 @@ namespace lp { { auto low = numeric_pair(right_side, y_of_bound); if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - set_infeasible_column(j); + set_infeasible_column_and_witness(j, false, dep); + } + else { + m_mpq_lar_core_solver.m_r_lower_bounds[j] = low; + set_lower_bound_witness(j, dep); + m_mpq_lar_core_solver.m_column_types[j] = (low == m_mpq_lar_core_solver.m_r_upper_bounds[j] ? column_type::fixed : column_type::boxed); + insert_to_columns_with_changed_bounds(j); } - m_mpq_lar_core_solver.m_r_lower_bounds[j] = low; - set_lower_bound_witness(j, dep); - m_mpq_lar_core_solver.m_column_types[j] = (low == m_mpq_lar_core_solver.m_r_upper_bounds[j] ? column_type::fixed : column_type::boxed); - insert_to_columns_with_changed_bounds(j); - } break; case EQ: { auto v = numeric_pair(right_side, zero_of_type()); if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - set_infeasible_column(j); + set_infeasible_column_and_witness(j, false, dep); + } + else { + set_upper_bound_witness(j, dep); + set_lower_bound_witness(j, dep); + m_mpq_lar_core_solver.m_r_upper_bounds[j] = m_mpq_lar_core_solver.m_r_lower_bounds[j] = v; + m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; + insert_to_columns_with_changed_bounds(j); } - - set_upper_bound_witness(j, dep); - set_lower_bound_witness(j, dep); - m_mpq_lar_core_solver.m_r_upper_bounds[j] = m_mpq_lar_core_solver.m_r_lower_bounds[j] = v; - m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; break; } @@ -2345,7 +2356,21 @@ namespace lp { return false; return true; } + // If lower_bound is true than the new asserted upper bound is less than the existing lower bound. + // Otherwise the new asserted lower bound is is greater than the existing upper bound. + // dep is the reason for the new bound + void lar_solver::set_infeasible_column_and_witness(unsigned j, bool lower_bound, u_dependency* dep) { + bool was_feas = column_is_feasible(j); + bool in_heap = m_mpq_lar_core_solver.m_r_solver.inf_heap().contains(j); + SASSERT(m_crossed_bounds_deps == nullptr && m_crossed_bounds_deps == nullptr); + set_status(lp_status::INFEASIBLE); + m_crossed_bounds_column = j; + const auto& ul = this->m_columns_to_ul_pairs()[j]; + u_dependency* bdep = lower_bound? ul.lower_bound_witness() : ul.upper_bound_witness(); + SASSERT(bdep != nullptr); + m_crossed_bounds_deps = m_dependencies.mk_join(bdep, dep); + } } // namespace lp diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index fc696d4b2..a689d6665 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -78,7 +78,8 @@ class lar_solver : public column_namer { lp_status m_status = lp_status::UNKNOWN; stacked_value m_simplex_strategy; // such can be found at the initialization step: u < l - stacked_value m_crossed_bounds_column; + lpvar m_crossed_bounds_column; + u_dependency* m_crossed_bounds_deps; lar_core_solver m_mpq_lar_core_solver; int_solver* m_int_solver = nullptr; bool m_need_register_terms = false; @@ -139,10 +140,14 @@ class lar_solver : public column_namer { bool compare_values(impq const& lhs, lconstraint_kind k, const mpq& rhs); inline void clear_columns_with_changed_bounds() { m_columns_with_changed_bounds.reset(); } + public: void insert_to_columns_with_changed_bounds(unsigned j); + private: void update_column_type_and_bound_check_on_equal(unsigned j, const mpq& right_side, constraint_index ci, unsigned&); void update_column_type_and_bound(unsigned j, const mpq& right_side, constraint_index ci); + public: void update_column_type_and_bound(unsigned j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); + private: void update_column_type_and_bound_with_ub(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); void update_column_type_and_bound_with_no_ub(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); void update_bound_with_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); @@ -152,10 +157,7 @@ class lar_solver : public column_namer { void register_in_fixed_var_table(unsigned, unsigned&); void remove_non_fixed_from_fixed_var_table(); constraint_index add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq& right_side); - inline void set_infeasible_column(unsigned j) { - set_status(lp_status::INFEASIBLE); - m_crossed_bounds_column = j; - } + void set_infeasible_column_and_witness(unsigned j, bool lower_bound, u_dependency* dep); constraint_index add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, lconstraint_kind kind, const mpq& right_side); unsigned row_of_basic_column(unsigned) const; diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index e7570d5dd..d7d1666d0 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -540,9 +540,9 @@ public: } void add_delta_to_x_and_track_feasibility(unsigned j, const X & del) { - TRACE("lar_solver_feas_bug", tout << "del = " << del << ", was x[" << j << "] = " << m_x[j] << "\n";); + TRACE("lar_solver_feas", tout << "del = " << del << ", was x[" << j << "] = " << m_x[j] << "\n";); m_x[j] += del; - TRACE("lar_solver_feas_bug", tout << "became x[" << j << "] = " << m_x[j] << "\n";); + TRACE("lar_solver_feas", tout << "became x[" << j << "] = " << m_x[j] << "\n";); track_column_feasibility(j); } diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index e21891ee4..9dd4ffa90 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -258,51 +258,113 @@ namespace nla { } } - void monomial_bounds::unit_propagate() { - for (auto const& m : c().m_emons) - unit_propagate(m); + bool monomial_bounds::unit_propagate() { + unsigned sz = 0; + vector monics_vars; + for (auto const& m : c().m_emons) { + monics_vars.push_back(m.var()); + sz++; + } + unsigned l = this->random(); + for (unsigned i = 0; i < sz; ++i) { + lpvar v = monics_vars[(i + l) % sz]; + if (!unit_propagate(c().m_emons[v])) { + return false; + } + } + + return true; } - void monomial_bounds::unit_propagate(monic const& m) { +// returns false if and only if there is a conflict + bool monomial_bounds::unit_propagate(monic const& m) { m_propagated.reserve(m.var() + 1, false); if (m_propagated[m.var()]) - return; + return true; if (!is_linear(m)) - return; + return true; c().trail().push(set_bitvector_trail(m_propagated, m.var())); - - rational k = fixed_var_product(m); - - new_lemma lemma(c(), "fixed-values"); - if (k == 0) { - for (auto v : m) { - if (c().var_is_fixed(v) && c().val(v).is_zero()) { - lemma.explain_fixed(v); + lpvar zero_fixed = null_lpvar, non_fixed = null_lpvar; + // find a zero fixed variable and a non-fixed variable + for (lpvar v : m) { + if (c().var_is_fixed(v)) { + if (c().val(v).is_zero()) { + zero_fixed = v; break; } } - lemma += ineq(m.var(), lp::lconstraint_kind::EQ, 0); - } - else { - for (auto v : m) - if (c().var_is_fixed(v)) - lemma.explain_fixed(v); - - lpvar w = non_fixed_var(m); - if (w != null_lpvar) { - lp::lar_term term; - term.add_var(m.var()); - term.add_monomial(-k, w); - lemma += ineq(term, lp::lconstraint_kind::EQ, 0); - } else { - lemma += ineq(m.var(), lp::lconstraint_kind::EQ, k); + else { + non_fixed = v; } } - + + if (zero_fixed != null_lpvar) { + // the m.var() has to have a zero value + u_dependency* d = this->dep.mk_join(c().lra.get_column_lower_bound_witness(zero_fixed), + c().lra.get_column_upper_bound_witness(zero_fixed)); + + c().lra.update_column_type_and_bound(m.var(), lp::lconstraint_kind::EQ, mpq(0), d); + } else if (non_fixed != null_lpvar) { + u_dependency* d = nullptr; + rational k(1); + for (auto v : m) + if (v != non_fixed) { + d = this->dep.mk_join(d, c().lra.get_column_upper_bound_witness(v)); + d = this->dep.mk_join(d, c().lra.get_column_lower_bound_witness(v)); + k *= c().val(v); + } + SASSERT(k.is_pos() || k.is_neg()); + // we have m = k* non_fixed: m.var() getting the bounds witnesses of non_fixed + if (k.is_pos()) { + d = c().lra.get_column_upper_bound_witness(non_fixed); + if (d) { + const auto& b = c().lra.get_column_value(non_fixed); + bool strict = b.y.is_neg(); + c().lra.update_column_type_and_bound(m.var(), strict ? lp::lconstraint_kind::LT : lp::lconstraint_kind::LE, k * b.x, d); + } + d = c().lra.get_column_lower_bound_witness(non_fixed); + if (d) { + const auto& b = c().lra.get_column_value(non_fixed); + bool strict = b.y.is_pos(); + c().lra.update_column_type_and_bound(m.var(), strict ? lp::lconstraint_kind::GT : lp::lconstraint_kind::GE, k * b.x, d); + } + + } else { + d = c().lra.get_column_upper_bound_witness(non_fixed); + if (d) { + const auto& b = c().lra.get_column_value(non_fixed); + bool strict = b.y.is_neg(); + c().lra.update_column_type_and_bound(m.var(), strict ? lp::lconstraint_kind::GT : lp::lconstraint_kind::GE, k * b.x, d); + } + d = c().lra.get_column_lower_bound_witness(non_fixed); + if (d) { + const auto& b = c().lra.get_column_value(non_fixed); + bool strict = b.y.is_pos(); + c().lra.update_column_type_and_bound(m.var(), strict ? lp::lconstraint_kind::LT : lp::lconstraint_kind::LE, k * b.x, d); + } + } + } else { + SASSERT(non_fixed == null_lpvar && zero_fixed == null_lpvar); + rational k(1); + u_dependency* d = nullptr; + for (auto v : m) { + SASSERT(c().var_is_fixed(v)); + d = this->dep.mk_join(d, c().lra.get_column_upper_bound_witness(v)); + d = this->dep.mk_join(d, c().lra.get_column_lower_bound_witness(v)); + k *= c().val(v); + } + SASSERT(k.is_pos() || k.is_neg()); + // we have m = k: m.var() getting the bounds witnesses of all fixed variables + c().lra.update_column_type_and_bound(m.var(), lp::lconstraint_kind::EQ, k, d); + } + if (c().lra.get_status() == lp::lp_status::INFEASIBLE) { + TRACE("nla_solver", tout << "conflict in unit_propagate\n";); + return false; + } + return true; } - bool monomial_bounds::is_linear(monic const& m) { unsigned non_fixed = 0; for (lpvar v : m) { @@ -324,12 +386,6 @@ namespace nla { return r; } - lpvar monomial_bounds::non_fixed_var(monic const& m) { - for (lpvar v : m) - if (!c().var_is_fixed(v)) - return v; - return null_lpvar; - } - + } diff --git a/src/math/lp/monomial_bounds.h b/src/math/lp/monomial_bounds.h index c728d1a4c..41aa48f6c 100644 --- a/src/math/lp/monomial_bounds.h +++ b/src/math/lp/monomial_bounds.h @@ -32,14 +32,12 @@ namespace nla { // monomial propagation bool_vector m_propagated; - void unit_propagate(monic const& m); + bool unit_propagate(monic const& m); bool is_linear(monic const& m); rational fixed_var_product(monic const& m); - lpvar non_fixed_var(monic const& m); - public: monomial_bounds(core* core); void propagate(); - void unit_propagate(); + bool unit_propagate(); }; } diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 4d4fa6cbe..08a768ee5 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -1818,14 +1818,18 @@ bool core::improve_bounds() { } return bounds_improved; } - -void core::propagate(vector& lemmas) { + // returns false if and only if makes lp_solver inconsistent +bool core::propagate(vector& lemmas) { // propagate linear monomials, those that have all, or all but one, variables fixed lemmas.reset(); m_lemma_vec = &lemmas; m_monomial_bounds.unit_propagate(); - + if (lra.get_status() == lp::lp_status::INFEASIBLE) { + TRACE("nla_solver", tout << "propagation found infeasibility\n";); + return false; + } + return true; } diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index 9c96f2fbf..340b94430 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -392,7 +392,7 @@ public: bool no_lemmas_hold() const; - void propagate(vector& lemmas); + bool propagate(vector& lemmas); lbool test_check(vector& l); lpvar map_to_root(lpvar) const; diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 470ea5f7b..ae224e3ec 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1532,11 +1532,12 @@ namespace smt { bool max, bool maintain_integrality, bool& has_shared) { + return UNBOUNDED; + m_stats.m_max_min++; unsigned best_efforts = 0; bool inc = false; - - + SASSERT(!maintain_integrality || valid_assignment()); SASSERT(satisfy_bounds()); diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index f44516cad..77e2b25f3 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -511,6 +511,7 @@ bool theory_arith::propagate_nl_downward(expr * n, var_power_pair const& p) */ template bool theory_arith::propagate_nl_bounds(expr * m) { + return false; TRACE("non_linear", tout << "propagate several bounds using:\n"; display_monomial(tout, m); tout << "\n";); bool result = propagate_nl_upward(m); buffer vp; @@ -530,6 +531,7 @@ bool theory_arith::propagate_nl_bounds(expr * m) { */ template bool theory_arith::propagate_nl_bounds() { + return false; m_dep_manager.reset(); bool propagated = false; for (unsigned i = 0; i < m_nl_monomials.size(); i++) { @@ -1632,6 +1634,7 @@ bool theory_arith::is_cross_nested_consistent(row const & r) { */ template bool theory_arith::is_cross_nested_consistent(svector const & nl_cluster) { + return true; for (theory_var v : nl_cluster) { if (!is_base(v)) continue; diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 31882ea11..29a46db19 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2163,8 +2163,14 @@ public: if (!m_nla) return; m_nla->propagate(m_nla_lemma_vector); - for (nla::lemma const& l : m_nla_lemma_vector) - false_case_of_check_nla(l); + if (lp().get_status() == lp::lp_status::INFEASIBLE) { + TRACE("arith", tout << "propagation conflict\n";); + get_infeasibility_explanation_and_set_conflict(); + } + else { + for (nla::lemma const& l : m_nla_lemma_vector) + false_case_of_check_nla(l); + } } bool should_propagate() const { From 288e66de590c654051172d30e768f7a181ee6629 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 6 Sep 2023 09:27:30 -0700 Subject: [PATCH 05/69] restore m_crossed* and create lemmas Signed-off-by: Lev Nachmanson --- src/math/lp/lar_solver.cpp | 2 -- src/math/lp/lar_solver.h | 9 +++++- src/math/lp/monomial_bounds.cpp | 49 ++++++++++++++------------------- src/math/lp/monomial_bounds.h | 5 ++-- 4 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 5f82516ef..8480025f2 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -2361,8 +2361,6 @@ namespace lp { // dep is the reason for the new bound void lar_solver::set_infeasible_column_and_witness(unsigned j, bool lower_bound, u_dependency* dep) { - bool was_feas = column_is_feasible(j); - bool in_heap = m_mpq_lar_core_solver.m_r_solver.inf_heap().contains(j); SASSERT(m_crossed_bounds_deps == nullptr && m_crossed_bounds_deps == nullptr); set_status(lp_status::INFEASIBLE); m_crossed_bounds_column = j; diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index a689d6665..03d20c793 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -79,7 +79,7 @@ class lar_solver : public column_namer { stacked_value m_simplex_strategy; // such can be found at the initialization step: u < l lpvar m_crossed_bounds_column; - u_dependency* m_crossed_bounds_deps; + u_dependency* m_crossed_bounds_deps; lar_core_solver m_mpq_lar_core_solver; int_solver* m_int_solver = nullptr; bool m_need_register_terms = false; @@ -142,6 +142,13 @@ class lar_solver : public column_namer { inline void clear_columns_with_changed_bounds() { m_columns_with_changed_bounds.reset(); } public: void insert_to_columns_with_changed_bounds(unsigned j); + const u_dependency* crossed_bounds_deps() const { return m_crossed_bounds_deps;} + u_dependency*& crossed_bounds_deps() { return m_crossed_bounds_deps;} + + lpvar crossed_bounds_column() const { return m_crossed_bounds_column; } + lpvar& crossed_bounds_column() { return m_crossed_bounds_column; } + + private: void update_column_type_and_bound_check_on_equal(unsigned j, const mpq& right_side, constraint_index ci, unsigned&); void update_column_type_and_bound(unsigned j, const mpq& right_side, constraint_index ci); diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index 9dd4ffa90..8061444c8 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -258,32 +258,30 @@ namespace nla { } } - bool monomial_bounds::unit_propagate() { - unsigned sz = 0; - vector monics_vars; - for (auto const& m : c().m_emons) { - monics_vars.push_back(m.var()); - sz++; - } - unsigned l = this->random(); - for (unsigned i = 0; i < sz; ++i) { - lpvar v = monics_vars[(i + l) % sz]; - if (!unit_propagate(c().m_emons[v])) { - return false; - } - } - - return true; + void monomial_bounds::unit_propagate() { + for (auto const& m : c().m_emons) + unit_propagate(m); } -// returns false if and only if there is a conflict - bool monomial_bounds::unit_propagate(monic const& m) { + void monomial_bounds::check_for_conflict() { + if (c().lra.crossed_bounds_deps() != nullptr) { + new_lemma lemma(c(), "fixed-values"); + lp::explanation ex; + c().lra.fill_explanation_from_crossed_bounds_column(ex); + lemma &= ex; + c().lra.crossed_bounds_deps() = nullptr; + c().lra.crossed_bounds_column() = null_lpvar; + c().lra.set_status(lp::lp_status::OPTIMAL); + } + } + + void monomial_bounds::unit_propagate(monic const& m) { m_propagated.reserve(m.var() + 1, false); if (m_propagated[m.var()]) - return true; + return; if (!is_linear(m)) - return true; + return; c().trail().push(set_bitvector_trail(m_propagated, m.var())); lpvar zero_fixed = null_lpvar, non_fixed = null_lpvar; @@ -303,8 +301,7 @@ namespace nla { if (zero_fixed != null_lpvar) { // the m.var() has to have a zero value u_dependency* d = this->dep.mk_join(c().lra.get_column_lower_bound_witness(zero_fixed), - c().lra.get_column_upper_bound_witness(zero_fixed)); - + c().lra.get_column_upper_bound_witness(zero_fixed)); c().lra.update_column_type_and_bound(m.var(), lp::lconstraint_kind::EQ, mpq(0), d); } else if (non_fixed != null_lpvar) { u_dependency* d = nullptr; @@ -330,7 +327,6 @@ namespace nla { bool strict = b.y.is_pos(); c().lra.update_column_type_and_bound(m.var(), strict ? lp::lconstraint_kind::GT : lp::lconstraint_kind::GE, k * b.x, d); } - } else { d = c().lra.get_column_upper_bound_witness(non_fixed); if (d) { @@ -358,12 +354,9 @@ namespace nla { SASSERT(k.is_pos() || k.is_neg()); // we have m = k: m.var() getting the bounds witnesses of all fixed variables c().lra.update_column_type_and_bound(m.var(), lp::lconstraint_kind::EQ, k, d); - } - if (c().lra.get_status() == lp::lp_status::INFEASIBLE) { - TRACE("nla_solver", tout << "conflict in unit_propagate\n";); - return false; } - return true; + check_for_conflict(); + SASSERT (c().lra.get_status() != lp::lp_status::INFEASIBLE); } bool monomial_bounds::is_linear(monic const& m) { unsigned non_fixed = 0; diff --git a/src/math/lp/monomial_bounds.h b/src/math/lp/monomial_bounds.h index 41aa48f6c..9faf0e470 100644 --- a/src/math/lp/monomial_bounds.h +++ b/src/math/lp/monomial_bounds.h @@ -32,12 +32,13 @@ namespace nla { // monomial propagation bool_vector m_propagated; - bool unit_propagate(monic const& m); + void unit_propagate(monic const& m); bool is_linear(monic const& m); rational fixed_var_product(monic const& m); public: monomial_bounds(core* core); void propagate(); - bool unit_propagate(); + void unit_propagate(); + void check_for_conflict(); }; } From 47b64e689cc26a79ff88e46465dce9dc6df054ff Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 7 Sep 2023 11:33:14 -0700 Subject: [PATCH 06/69] restore the lemma scheme Signed-off-by: Lev Nachmanson --- src/math/lp/int_solver.cpp | 2 +- src/math/lp/monomial_bounds.cpp | 113 +++++++++----------------------- src/math/lp/monomial_bounds.h | 3 +- src/math/lp/nla_core.cpp | 10 +-- src/math/lp/nla_core.h | 2 +- 5 files changed, 39 insertions(+), 91 deletions(-) diff --git a/src/math/lp/int_solver.cpp b/src/math/lp/int_solver.cpp index bd1ac5313..1964262f3 100644 --- a/src/math/lp/int_solver.cpp +++ b/src/math/lp/int_solver.cpp @@ -31,7 +31,7 @@ namespace lp { lra.remove_fixed_vars_from_base(); lp_assert(lia.is_feasible()); for (unsigned j : lra.r_basis()) - if (!lra.get_value(j).is_int() && lra.column_is_int(j)&& !lia.is_fixed(j)) + if (!lra.get_value(j).is_int() && lra.column_is_int(j) && !lia.is_fixed(j)) patch_basic_column(j); if (!lia.has_inf_int()) { lia.settings().stats().m_patches_success++; diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index 8061444c8..e21891ee4 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -258,23 +258,11 @@ namespace nla { } } - void monomial_bounds::unit_propagate() { - for (auto const& m : c().m_emons) + void monomial_bounds::unit_propagate() { + for (auto const& m : c().m_emons) unit_propagate(m); } - void monomial_bounds::check_for_conflict() { - if (c().lra.crossed_bounds_deps() != nullptr) { - new_lemma lemma(c(), "fixed-values"); - lp::explanation ex; - c().lra.fill_explanation_from_crossed_bounds_column(ex); - lemma &= ex; - c().lra.crossed_bounds_deps() = nullptr; - c().lra.crossed_bounds_column() = null_lpvar; - c().lra.set_status(lp::lp_status::OPTIMAL); - } - } - void monomial_bounds::unit_propagate(monic const& m) { m_propagated.reserve(m.var() + 1, false); if (m_propagated[m.var()]) @@ -284,80 +272,37 @@ namespace nla { return; c().trail().push(set_bitvector_trail(m_propagated, m.var())); - lpvar zero_fixed = null_lpvar, non_fixed = null_lpvar; - // find a zero fixed variable and a non-fixed variable - for (lpvar v : m) { - if (c().var_is_fixed(v)) { - if (c().val(v).is_zero()) { - zero_fixed = v; + + rational k = fixed_var_product(m); + + new_lemma lemma(c(), "fixed-values"); + if (k == 0) { + for (auto v : m) { + if (c().var_is_fixed(v) && c().val(v).is_zero()) { + lemma.explain_fixed(v); break; } } - else { - non_fixed = v; - } + lemma += ineq(m.var(), lp::lconstraint_kind::EQ, 0); } - - if (zero_fixed != null_lpvar) { - // the m.var() has to have a zero value - u_dependency* d = this->dep.mk_join(c().lra.get_column_lower_bound_witness(zero_fixed), - c().lra.get_column_upper_bound_witness(zero_fixed)); - c().lra.update_column_type_and_bound(m.var(), lp::lconstraint_kind::EQ, mpq(0), d); - } else if (non_fixed != null_lpvar) { - u_dependency* d = nullptr; - rational k(1); - for (auto v : m) - if (v != non_fixed) { - d = this->dep.mk_join(d, c().lra.get_column_upper_bound_witness(v)); - d = this->dep.mk_join(d, c().lra.get_column_lower_bound_witness(v)); - k *= c().val(v); - } - SASSERT(k.is_pos() || k.is_neg()); - // we have m = k* non_fixed: m.var() getting the bounds witnesses of non_fixed - if (k.is_pos()) { - d = c().lra.get_column_upper_bound_witness(non_fixed); - if (d) { - const auto& b = c().lra.get_column_value(non_fixed); - bool strict = b.y.is_neg(); - c().lra.update_column_type_and_bound(m.var(), strict ? lp::lconstraint_kind::LT : lp::lconstraint_kind::LE, k * b.x, d); - } - d = c().lra.get_column_lower_bound_witness(non_fixed); - if (d) { - const auto& b = c().lra.get_column_value(non_fixed); - bool strict = b.y.is_pos(); - c().lra.update_column_type_and_bound(m.var(), strict ? lp::lconstraint_kind::GT : lp::lconstraint_kind::GE, k * b.x, d); - } + else { + for (auto v : m) + if (c().var_is_fixed(v)) + lemma.explain_fixed(v); + + lpvar w = non_fixed_var(m); + if (w != null_lpvar) { + lp::lar_term term; + term.add_var(m.var()); + term.add_monomial(-k, w); + lemma += ineq(term, lp::lconstraint_kind::EQ, 0); } else { - d = c().lra.get_column_upper_bound_witness(non_fixed); - if (d) { - const auto& b = c().lra.get_column_value(non_fixed); - bool strict = b.y.is_neg(); - c().lra.update_column_type_and_bound(m.var(), strict ? lp::lconstraint_kind::GT : lp::lconstraint_kind::GE, k * b.x, d); - } - d = c().lra.get_column_lower_bound_witness(non_fixed); - if (d) { - const auto& b = c().lra.get_column_value(non_fixed); - bool strict = b.y.is_pos(); - c().lra.update_column_type_and_bound(m.var(), strict ? lp::lconstraint_kind::LT : lp::lconstraint_kind::LE, k * b.x, d); - } + lemma += ineq(m.var(), lp::lconstraint_kind::EQ, k); } - } else { - SASSERT(non_fixed == null_lpvar && zero_fixed == null_lpvar); - rational k(1); - u_dependency* d = nullptr; - for (auto v : m) { - SASSERT(c().var_is_fixed(v)); - d = this->dep.mk_join(d, c().lra.get_column_upper_bound_witness(v)); - d = this->dep.mk_join(d, c().lra.get_column_lower_bound_witness(v)); - k *= c().val(v); - } - SASSERT(k.is_pos() || k.is_neg()); - // we have m = k: m.var() getting the bounds witnesses of all fixed variables - c().lra.update_column_type_and_bound(m.var(), lp::lconstraint_kind::EQ, k, d); } - check_for_conflict(); - SASSERT (c().lra.get_status() != lp::lp_status::INFEASIBLE); + } + bool monomial_bounds::is_linear(monic const& m) { unsigned non_fixed = 0; for (lpvar v : m) { @@ -379,6 +324,12 @@ namespace nla { return r; } - + lpvar monomial_bounds::non_fixed_var(monic const& m) { + for (lpvar v : m) + if (!c().var_is_fixed(v)) + return v; + return null_lpvar; + } + } diff --git a/src/math/lp/monomial_bounds.h b/src/math/lp/monomial_bounds.h index 9faf0e470..c728d1a4c 100644 --- a/src/math/lp/monomial_bounds.h +++ b/src/math/lp/monomial_bounds.h @@ -35,10 +35,11 @@ namespace nla { void unit_propagate(monic const& m); bool is_linear(monic const& m); rational fixed_var_product(monic const& m); + lpvar non_fixed_var(monic const& m); + public: monomial_bounds(core* core); void propagate(); void unit_propagate(); - void check_for_conflict(); }; } diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 08a768ee5..4d4fa6cbe 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -1818,18 +1818,14 @@ bool core::improve_bounds() { } return bounds_improved; } - // returns false if and only if makes lp_solver inconsistent -bool core::propagate(vector& lemmas) { + +void core::propagate(vector& lemmas) { // propagate linear monomials, those that have all, or all but one, variables fixed lemmas.reset(); m_lemma_vec = &lemmas; m_monomial_bounds.unit_propagate(); - if (lra.get_status() == lp::lp_status::INFEASIBLE) { - TRACE("nla_solver", tout << "propagation found infeasibility\n";); - return false; - } - return true; + } diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index 340b94430..9c96f2fbf 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -392,7 +392,7 @@ public: bool no_lemmas_hold() const; - bool propagate(vector& lemmas); + void propagate(vector& lemmas); lbool test_check(vector& l); lpvar map_to_root(lpvar) const; From c43b99daae35e86926df9cf4b0e8cb0e8a3c1a30 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 7 Sep 2023 11:57:20 -0700 Subject: [PATCH 07/69] renaming Signed-off-by: Lev Nachmanson --- src/math/lp/lar_solver.cpp | 18 +++++++++--------- src/math/lp/lar_solver.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 8480025f2..bf38a9269 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -1931,7 +1931,7 @@ namespace lp { case LE: { auto up = numeric_pair(right_side, y_of_bound); if (up < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { - set_infeasible_column_and_witness(j, true, dep); + set_crossed_bounds_column_and_deps(j, true, dep); } else { if (up >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) return; @@ -1946,7 +1946,7 @@ namespace lp { case GE: { auto low = numeric_pair(right_side, y_of_bound); if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - set_infeasible_column_and_witness(j, false, dep); + set_crossed_bounds_column_and_deps(j, false, dep); } else { if (low < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { return; @@ -1962,10 +1962,10 @@ namespace lp { case EQ: { auto v = numeric_pair(right_side, zero_of_type()); if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]){ - set_infeasible_column_and_witness(j, false, dep); + set_crossed_bounds_column_and_deps(j, false, dep); } else if (v < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { - set_infeasible_column_and_witness(j, true, dep); + set_crossed_bounds_column_and_deps(j, true, dep); } else { set_upper_bound_witness(j, dep); @@ -1995,7 +1995,7 @@ namespace lp { case LE: { auto up = numeric_pair(right_side, y_of_bound); if (up < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { - set_infeasible_column_and_witness(j, true, dep); + set_crossed_bounds_column_and_deps(j, true, dep); } else { m_mpq_lar_core_solver.m_r_upper_bounds[j] = up; @@ -2020,7 +2020,7 @@ namespace lp { case EQ: { auto v = numeric_pair(right_side, zero_of_type()); if (v < m_mpq_lar_core_solver.m_r_lower_bounds[j]) { - set_infeasible_column_and_witness(j, true, dep); + set_crossed_bounds_column_and_deps(j, true, dep); } else { set_upper_bound_witness(j, dep); @@ -2059,7 +2059,7 @@ namespace lp { { auto low = numeric_pair(right_side, y_of_bound); if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - set_infeasible_column_and_witness(j, false, dep); + set_crossed_bounds_column_and_deps(j, false, dep); } else { m_mpq_lar_core_solver.m_r_lower_bounds[j] = low; @@ -2073,7 +2073,7 @@ namespace lp { { auto v = numeric_pair(right_side, zero_of_type()); if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) { - set_infeasible_column_and_witness(j, false, dep); + set_crossed_bounds_column_and_deps(j, false, dep); } else { set_upper_bound_witness(j, dep); @@ -2360,7 +2360,7 @@ namespace lp { // Otherwise the new asserted lower bound is is greater than the existing upper bound. // dep is the reason for the new bound - void lar_solver::set_infeasible_column_and_witness(unsigned j, bool lower_bound, u_dependency* dep) { + void lar_solver::set_crossed_bounds_column_and_deps(unsigned j, bool lower_bound, u_dependency* dep) { SASSERT(m_crossed_bounds_deps == nullptr && m_crossed_bounds_deps == nullptr); set_status(lp_status::INFEASIBLE); m_crossed_bounds_column = j; diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 03d20c793..4b8cd0c1b 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -164,7 +164,7 @@ class lar_solver : public column_namer { void register_in_fixed_var_table(unsigned, unsigned&); void remove_non_fixed_from_fixed_var_table(); constraint_index add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq& right_side); - void set_infeasible_column_and_witness(unsigned j, bool lower_bound, u_dependency* dep); + void set_crossed_bounds_column_and_deps(unsigned j, bool lower_bound, u_dependency* dep); constraint_index add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term, lconstraint_kind kind, const mpq& right_side); unsigned row_of_basic_column(unsigned) const; From c050af922f9858bcca9070b8ac1c9e8e4fb2349c Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 7 Sep 2023 15:59:20 -0700 Subject: [PATCH 08/69] fixing the bugs --- src/math/lp/lar_solver.cpp | 2 ++ src/math/lp/lar_solver.h | 1 + src/math/lp/monomial_bounds.cpp | 4 +-- src/math/lp/nla_core.cpp | 52 ++++++++++++++++++++------------- src/math/lp/nla_core.h | 3 +- src/smt/theory_arith_aux.h | 2 -- 6 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index bf38a9269..08ff3b0d4 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -789,6 +789,8 @@ namespace lp { void lar_solver::detect_rows_with_changed_bounds() { for (auto j : m_columns_with_changed_bounds) detect_rows_with_changed_bounds_for_column(j); + if (m_find_monics_with_changed_bounds_func) + m_find_monics_with_changed_bounds_func(m_columns_with_changed_bounds); } void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds_tableau() { diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 4b8cd0c1b..acab137b5 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -670,6 +670,7 @@ class lar_solver : public column_namer { return 0; return m_usage_in_terms[j]; } + std::function m_find_monics_with_changed_bounds_func = nullptr; friend int_solver; friend int_branch; }; diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index e21891ee4..77e01c2db 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -259,8 +259,8 @@ namespace nla { } void monomial_bounds::unit_propagate() { - for (auto const& m : c().m_emons) - unit_propagate(m); + for (lpvar v : c().m_monics_with_changed_bounds) + unit_propagate(c().emons()[v]); } void monomial_bounds::unit_propagate(monic const& m) { diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 4d4fa6cbe..cc2f0f1b5 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -21,28 +21,40 @@ namespace nla { typedef lp::lar_term term; -core::core(lp::lar_solver& s, params_ref const& p, reslimit & lim) : - m_evars(), - lra(s), - m_reslim(lim), - m_params(p), - m_tangents(this), - m_basics(this), - m_order(this), - m_monotone(this), - m_powers(*this), - m_divisions(*this), - m_intervals(this, lim), - m_monomial_bounds(this), - m_horner(this), - m_grobner(this), - m_emons(m_evars), - m_use_nra_model(false), - m_nra(s, m_nra_lim, *this) -{ +core::core(lp::lar_solver& s, params_ref const& p, reslimit& lim) : m_evars(), + lra(s), + m_reslim(lim), + m_params(p), + m_tangents(this), + m_basics(this), + m_order(this), + m_monotone(this), + m_powers(*this), + m_divisions(*this), + m_intervals(this, lim), + m_monomial_bounds(this), + m_horner(this), + m_grobner(this), + m_emons(m_evars), + m_use_nra_model(false), + m_nra(s, m_nra_lim, *this) { m_nlsat_delay = lp_settings().nlsat_delay(); + lra.m_find_monics_with_changed_bounds_func = [&](const indexed_uint_set& columns_with_changed_bounds) { + m_monics_with_changed_bounds.clear(); + for (const auto& m : m_emons) { + if (columns_with_changed_bounds.contains(m.var())) { + m_monics_with_changed_bounds.push_back(m.var()); + continue; + } + for (lpvar j : m.vars()) { + if (columns_with_changed_bounds.contains(j)) { + m_monics_with_changed_bounds.push_back(m.var()); + break; + } + } + } }; } - + bool core::compare_holds(const rational& ls, llc cmp, const rational& rs) const { switch(cmp) { case llc::LE: return ls <= rs; diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index 9c96f2fbf..8dee571ae 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -87,7 +87,8 @@ class core { std::function m_relevant; vector * m_lemma_vec; vector * m_literal_vec = nullptr; - indexed_uint_set m_to_refine; + indexed_uint_set m_to_refine; + vector m_monics_with_changed_bounds; tangents m_tangents; basics m_basics; order m_order; diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index ae224e3ec..dd9ba2dfe 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1532,8 +1532,6 @@ namespace smt { bool max, bool maintain_integrality, bool& has_shared) { - return UNBOUNDED; - m_stats.m_max_min++; unsigned best_efforts = 0; bool inc = false; From c309d522831b4b62812399b6571624899e1557cd Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 13 Sep 2023 08:12:00 -0700 Subject: [PATCH 09/69] runs a simple test --- src/math/lp/bound_analyzer_on_row.h | 31 ++++++- src/math/lp/implied_bound.h | 31 +++---- src/math/lp/lar_solver.h | 56 ++++++++---- src/math/lp/lp_bound_propagator.h | 132 ++++++++++++++++++++++++++-- src/math/lp/monomial_bounds.cpp | 74 +++++++--------- src/math/lp/monomial_bounds.h | 6 +- src/math/lp/nla_core.cpp | 8 +- src/math/lp/nla_core.h | 4 +- src/math/lp/nla_solver.h | 3 +- src/sat/smt/arith_solver.cpp | 2 +- src/smt/theory_lra.cpp | 56 ++++++++---- 11 files changed, 291 insertions(+), 112 deletions(-) diff --git a/src/math/lp/bound_analyzer_on_row.h b/src/math/lp/bound_analyzer_on_row.h index 0008a0ee9..35e3bb6ed 100644 --- a/src/math/lp/bound_analyzer_on_row.h +++ b/src/math/lp/bound_analyzer_on_row.h @@ -26,6 +26,8 @@ Revision History: #include "math/lp/test_bound_analyzer.h" namespace lp { + + template // C plays a role of a container, B - lp_bound_propagator class bound_analyzer_on_row { const C& m_row; @@ -301,8 +303,12 @@ private: // */ // } - void limit_j(unsigned j, const mpq& u, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict){ - m_bp.try_add_bound(u, j, is_lower_bound, coeff_before_j_is_pos, m_row_index, strict); + + void limit_j(unsigned bound_j, const mpq& u, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict){ + lar_solver* lar = & this->m_bp.lp(); + unsigned row_index = this->m_row_index; + auto explain = [lar, bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index]() { return explain_bound_on_var_on_coeff(lar, bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index); }; + m_bp.add_bound(u, bound_j, is_lower_bound, strict, explain ); } void advance_u(unsigned j) { @@ -335,6 +341,27 @@ private: break; } } + static u_dependency* explain_bound_on_var_on_coeff(lar_solver* lar, unsigned bound_j, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict, unsigned row_index) { + int bound_sign = (is_lower_bound ? 1 : -1); + int j_sign = (coeff_before_j_is_pos ? 1 : -1) * bound_sign; + + if (tv::is_term(bound_j)) + bound_j = lar->map_term_index_to_column_index(bound_j); + u_dependency* ret = nullptr; + for (auto const& r : lar->get_row(row_index)) { + unsigned j = r.var(); + if (j == bound_j) + continue; + mpq const& a = r.coeff(); + int a_sign = is_pos(a) ? 1 : -1; + int sign = j_sign * a_sign; + u_dependency* witness = sign > 0 ? lar->get_column_upper_bound_witness(j) : lar->get_column_lower_bound_witness(j); + ret = lar->join_deps(ret, witness); + } + return ret; + } }; + + } diff --git a/src/math/lp/implied_bound.h b/src/math/lp/implied_bound.h index 9435edcdc..2e7fcbbcb 100644 --- a/src/math/lp/implied_bound.h +++ b/src/math/lp/implied_bound.h @@ -21,37 +21,34 @@ Revision History: #include "math/lp/lp_settings.h" #include "math/lp/lar_constraints.h" namespace lp { -struct implied_bound { +class implied_bound { + public: mpq m_bound; unsigned m_j; // the column for which the bound has been found bool m_is_lower_bound; - bool m_coeff_before_j_is_pos; - unsigned m_row_or_term_index; - bool m_strict; + bool m_strict; + private: + std::function m_explain_bound = nullptr; + public: + u_dependency* explain() const { return m_explain_bound(); } + void set_explain(std::function f) { m_explain_bound = f; } lconstraint_kind kind() const { lconstraint_kind k = m_is_lower_bound? GE : LE; if (m_strict) k = static_cast(k / 2); return k; } - bool operator==(const implied_bound & o) const { - return m_j == o.m_j && m_is_lower_bound == o.m_is_lower_bound && m_bound == o.m_bound && - m_coeff_before_j_is_pos == o.m_coeff_before_j_is_pos && - m_row_or_term_index == o.m_row_or_term_index && m_strict == o.m_strict; - } implied_bound(){} implied_bound(const mpq & a, unsigned j, - bool lower_bound, - bool coeff_before_j_is_pos, - unsigned row_or_term_index, - bool strict): + bool is_lower_bound, + bool is_strict, + std::function get_dep): m_bound(a), m_j(j), - m_is_lower_bound(lower_bound), - m_coeff_before_j_is_pos(coeff_before_j_is_pos), - m_row_or_term_index(row_or_term_index), - m_strict(strict) { + m_is_lower_bound(is_lower_bound), + m_strict(is_strict), + m_explain_bound(get_dep) { } }; } diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index acab137b5..7d16c7b63 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -311,26 +311,34 @@ class lar_solver : public column_namer { template void explain_implied_bound(const implied_bound& ib, lp_bound_propagator& bp) { - unsigned i = ib.m_row_or_term_index; - int bound_sign = (ib.m_is_lower_bound ? 1 : -1); - int j_sign = (ib.m_coeff_before_j_is_pos ? 1 : -1) * bound_sign; - unsigned bound_j = ib.m_j; - if (tv::is_term(bound_j)) - bound_j = m_var_register.external_to_local(bound_j); + u_dependency* dep = ib.explain(); + for (auto ci : flatten(dep)) + bp.consume(mpq(1), ci); // TODO: flatten should provid the coefficients + /* + if (ib.m_is_monic) { + NOT_IMPLEMENTED_YET(); + } else { + unsigned i = ib.m_row_or_term_index; + int bound_sign = (ib.m_is_lower_bound ? 1 : -1); + int j_sign = (ib.m_coeff_before_j_is_pos ? 1 : -1) * bound_sign; + unsigned bound_j = ib.m_j; + if (tv::is_term(bound_j)) + bound_j = m_var_register.external_to_local(bound_j); - for (auto const& r : get_row(i)) { - unsigned j = r.var(); - if (j == bound_j) - continue; - mpq const& a = r.coeff(); - int a_sign = is_pos(a) ? 1 : -1; - int sign = j_sign * a_sign; - const ul_pair& ul = m_columns_to_ul_pairs[j]; - auto* witness = sign > 0 ? ul.upper_bound_witness() : ul.lower_bound_witness(); - lp_assert(witness); - for (auto ci : flatten(witness)) - bp.consume(a, ci); - } + for (auto const& r : get_row(i)) { + unsigned j = r.var(); + if (j == bound_j) + continue; + mpq const& a = r.coeff(); + int a_sign = is_pos(a) ? 1 : -1; + int sign = j_sign * a_sign; + const ul_pair& ul = m_columns_to_ul_pairs[j]; + auto* witness = sign > 0 ? ul.upper_bound_witness() : ul.lower_bound_witness(); + lp_assert(witness); + for (auto ci : flatten(witness)) + bp.consume(a, ci); + } + }*/ } void set_value_for_nbasic_column(unsigned j, const impq& new_val); @@ -564,6 +572,16 @@ class lar_solver : public column_namer { const ul_pair& ul = m_columns_to_ul_pairs[j]; return m_dependencies.mk_join(ul.lower_bound_witness(), ul.upper_bound_witness()); } + template + u_dependency* get_bound_constraint_witnesses_for_columns(const T& collection) { + u_dependency* dep = nullptr; + for (auto j : collection) { + u_dependency* d = get_bound_constraint_witnesses_for_column(j); + dep = m_dependencies.mk_join(dep, d); + } + return dep; + } + u_dependency* join_deps(u_dependency* a, u_dependency *b) { return m_dependencies.mk_join(a, b); } inline constraint_set const& constraints() const { return m_constraints; } void push(); void pop(); diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index f676b0e1d..7ee647200 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -40,6 +40,7 @@ class lp_bound_propagator { return x != UINT_MAX; } + void try_add_equation_with_internal_fixed_tables(unsigned r1) { unsigned v1, v2; if (!only_one_nfixed(r1, v1)) @@ -94,6 +95,115 @@ class lp_bound_propagator { m_ibounds.reset(); m_column_types = &lp().get_column_types(); } + + bool is_linear(const svector& m, lpvar& zero_var, lpvar& non_fixed) { + zero_var = non_fixed = null_lpvar; + unsigned n_of_non_fixed = 0; + bool big_bound = false; + for (lpvar v : m) { + if (!this->column_is_fixed(v)) { + n_of_non_fixed++; + non_fixed = v; + continue; + } + const auto & b = get_lower_bound(v).x; + if (b.is_zero()) { + zero_var = v; + return true; + } + if (b.is_big()) { + big_bound |= true; + } + } + return n_of_non_fixed <= 1 && !big_bound; + } + + void add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var) { + add_lower_bound_monic(monic_var, mpq(0), false, [&](){return lp().get_bound_constraint_witnesses_for_column(zero_var);}); + add_upper_bound_monic(monic_var, mpq(0), false, [&](){return lp().get_bound_constraint_witnesses_for_column(zero_var);}); + } + + void add_lower_bound_monic(lpvar monic_var, const mpq& v, bool is_strict, std::function explain_dep) { + unsigned k; + if (!try_get_value(m_improved_lower_bounds, monic_var, k)) { + m_improved_lower_bounds[monic_var] = m_ibounds.size(); + m_ibounds.push_back(implied_bound(v, monic_var, true, is_strict, explain_dep)); + } else { + auto& found_bound = m_ibounds[k]; + if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && is_strict)) { + found_bound = implied_bound(v, monic_var, true, is_strict, explain_dep); + TRACE("add_bound", m_imp.lp().print_implied_bound(found_bound, tout);); + } + } + } + + void add_upper_bound_monic(lpvar monic_var, const mpq& bound_val, bool is_strict, std::function explain_bound) { + unsigned k; + if (!try_get_value(m_improved_upper_bounds, monic_var, k)) { + m_improved_upper_bounds[monic_var] = m_ibounds.size(); + m_ibounds.push_back(implied_bound(bound_val, monic_var, false, is_strict, explain_bound)); + } else { + auto& found_bound = m_ibounds[k]; + if (bound_val > found_bound.m_bound || (bound_val == found_bound.m_bound && !found_bound.m_strict && is_strict)) { + found_bound = implied_bound(bound_val, monic_var, false, is_strict, explain_bound); + TRACE("add_bound", m_imp.lp().print_implied_bound(found_bound, tout);); + } + } + } + + void propagate_monic(lpvar monic_var, const svector& vars) { + lpvar non_fixed, zero_var; + if (!is_linear(vars, zero_var, non_fixed)) { + return; + } + + if (zero_var != null_lpvar) { + add_bounds_for_zero_var(monic_var, zero_var); + } else { + if (non_fixed != null_lpvar && get_column_type(non_fixed) == column_type::free_column) return; + rational k = rational(1); + for (auto v : vars) + if (v != non_fixed) { + k *= lp().get_column_value(v).x; + if (k.is_big()) return; + } + u_dependency* dep; + lp::mpq bound_value; + bool is_strict; + if (non_fixed != null_lpvar) { + if (this->lp().has_lower_bound(non_fixed, dep, bound_value, is_strict)) { + if (k.is_pos()) + add_lower_bound_monic(monic_var, k * bound_value, is_strict, [&]() { return dep; }); + else + add_upper_bound_monic(monic_var, k * bound_value, is_strict, [&]() {return dep;}); + } + if (this->lp().has_upper_bound(non_fixed, dep, bound_value, is_strict)) { + if (k.is_neg()) + add_lower_bound_monic(monic_var, k * bound_value, is_strict, [&]() {return dep;}); + else + add_upper_bound_monic(monic_var, k * bound_value, is_strict, [&]() {return dep;}); + } + + if (this->lp().has_lower_bound(monic_var, dep, bound_value, is_strict)) { + if (k.is_pos()) + add_lower_bound_monic(non_fixed, bound_value / k, is_strict, [&]() {return dep;}); + else + add_upper_bound_monic(non_fixed, bound_value / k, is_strict, [&]() {return dep;}); + } + + if (this->lp().has_upper_bound(monic_var, dep, bound_value, is_strict)) { + if (k.is_neg()) + add_lower_bound_monic(non_fixed, bound_value / k, is_strict, [&]() {return dep;}); + else + add_upper_bound_monic(non_fixed, bound_value / k, is_strict, [&]() {return dep;}); + } + + } else { // all variables are fixed + add_lower_bound_monic(monic_var, k, false, [&](){return lp().get_bound_constraint_witnesses_for_columns(vars);}); + add_upper_bound_monic(monic_var, k, false, [&](){return lp().get_bound_constraint_witnesses_for_columns(vars);}); + } + } + } const lar_solver& lp() const { return m_imp.lp(); } lar_solver& lp() { return m_imp.lp(); } @@ -123,7 +233,7 @@ class lp_bound_propagator { return (*m_column_types)[j] == column_type::fixed && get_lower_bound(j).y.is_zero(); } - void try_add_bound(mpq const& v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict) { + void add_bound(mpq const& v, unsigned j, bool is_low, bool strict, std::function explain_bound) { j = m_imp.lp().column_to_reported_index(j); lconstraint_kind kind = is_low ? GE : LE; @@ -137,25 +247,29 @@ class lp_bound_propagator { if (try_get_value(m_improved_lower_bounds, j, k)) { auto& found_bound = m_ibounds[k]; if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) { - found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict); - TRACE("try_add_bound", m_imp.lp().print_implied_bound(found_bound, tout);); + found_bound.m_bound = v; + found_bound.m_strict = strict; + found_bound.set_explain(explain_bound); + TRACE("add_bound", m_imp.lp().print_implied_bound(found_bound, tout);); } } else { m_improved_lower_bounds[j] = m_ibounds.size(); - m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict)); - TRACE("try_add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout);); + m_ibounds.push_back(implied_bound(v, j, is_low, strict, explain_bound)); + TRACE("add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout);); } } else { // the upper bound case if (try_get_value(m_improved_upper_bounds, j, k)) { auto& found_bound = m_ibounds[k]; if (v < found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) { - found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict); - TRACE("try_add_bound", m_imp.lp().print_implied_bound(found_bound, tout);); + found_bound.m_bound = v; + found_bound.m_strict = strict; + found_bound.set_explain(explain_bound); + TRACE("add_bound", m_imp.lp().print_implied_bound(found_bound, tout);); } } else { m_improved_upper_bounds[j] = m_ibounds.size(); - m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict)); - TRACE("try_add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout);); + m_ibounds.push_back(implied_bound(v, j, is_low, strict, explain_bound)); + TRACE("add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout);); } } } diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index 77e01c2db..ad2b20c07 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -261,6 +261,7 @@ namespace nla { void monomial_bounds::unit_propagate() { for (lpvar v : c().m_monics_with_changed_bounds) unit_propagate(c().emons()[v]); + c().m_monics_with_changed_bounds.clear(); } void monomial_bounds::unit_propagate(monic const& m) { @@ -268,68 +269,61 @@ namespace nla { if (m_propagated[m.var()]) return; - if (!is_linear(m)) + lpvar non_fixed = null_lpvar, zero_var = null_lpvar; + if (!is_linear(m, zero_var, non_fixed)) return; c().trail().push(set_bitvector_trail(m_propagated, m.var())); - rational k = fixed_var_product(m); - new_lemma lemma(c(), "fixed-values"); - if (k == 0) { - for (auto v : m) { - if (c().var_is_fixed(v) && c().val(v).is_zero()) { - lemma.explain_fixed(v); - break; - } - } + if (zero_var != null_lpvar) { + new_lemma lemma(c(), "fixed-values"); + lemma.explain_fixed(zero_var); lemma += ineq(m.var(), lp::lconstraint_kind::EQ, 0); } else { + rational k = rational(1); for (auto v : m) - if (c().var_is_fixed(v)) + if (v != non_fixed) { + k *= c().lra.get_column_value(v).x; + if (k.is_big()) return; + } + + new_lemma lemma(c(), "fixed-values"); + + for (auto v : m) + if (v != non_fixed) lemma.explain_fixed(v); - lpvar w = non_fixed_var(m); - if (w != null_lpvar) { + if (non_fixed != null_lpvar) { lp::lar_term term; term.add_var(m.var()); - term.add_monomial(-k, w); + term.add_monomial(-k, non_fixed); lemma += ineq(term, lp::lconstraint_kind::EQ, 0); } else { lemma += ineq(m.var(), lp::lconstraint_kind::EQ, k); } } - } - - bool monomial_bounds::is_linear(monic const& m) { - unsigned non_fixed = 0; + // returns true iff (all variables are fixed, + // or all but one variable are fixed) and the bounds are not big, + // or at least one variable is fixed to zero. + bool monomial_bounds::is_linear(monic const& m, lpvar& zero_var, lpvar& non_fixed) { + zero_var = non_fixed = null_lpvar; + unsigned n_of_non_fixed = 0; + bool big_bound = false; for (lpvar v : m) { - if (!c().var_is_fixed(v)) - ++non_fixed; - else if (c().val(v).is_zero()) + if (!c().var_is_fixed(v)) { + n_of_non_fixed++; + non_fixed = v; + } else if (c().var_is_fixed_to_zero(v)) { + zero_var = v; return true; + } else if (c().fixed_var_has_big_bound(v)) { + big_bound |= true; + } } - return non_fixed <= 1; + return n_of_non_fixed <= 1 && !big_bound; } - - - rational monomial_bounds::fixed_var_product(monic const& m) { - rational r(1); - for (lpvar v : m) { - if (c().var_is_fixed(v)) - r *= c().lra.get_column_value(v).x; - } - return r; - } - - lpvar monomial_bounds::non_fixed_var(monic const& m) { - for (lpvar v : m) - if (!c().var_is_fixed(v)) - return v; - return null_lpvar; - } - } diff --git a/src/math/lp/monomial_bounds.h b/src/math/lp/monomial_bounds.h index c728d1a4c..15ab6b992 100644 --- a/src/math/lp/monomial_bounds.h +++ b/src/math/lp/monomial_bounds.h @@ -33,10 +33,8 @@ namespace nla { // monomial propagation bool_vector m_propagated; void unit_propagate(monic const& m); - bool is_linear(monic const& m); - rational fixed_var_product(monic const& m); - lpvar non_fixed_var(monic const& m); - + bool is_linear(monic const& m, lpvar& zero_var, lpvar& non_fixed); + public: monomial_bounds(core* core); void propagate(); diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index cc2f0f1b5..20003f947 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -40,7 +40,6 @@ core::core(lp::lar_solver& s, params_ref const& p, reslimit& lim) : m_evars(), m_nra(s, m_nra_lim, *this) { m_nlsat_delay = lp_settings().nlsat_delay(); lra.m_find_monics_with_changed_bounds_func = [&](const indexed_uint_set& columns_with_changed_bounds) { - m_monics_with_changed_bounds.clear(); for (const auto& m : m_emons) { if (columns_with_changed_bounds.contains(m.var())) { m_monics_with_changed_bounds.push_back(m.var()); @@ -553,6 +552,13 @@ bool core::var_is_fixed_to_zero(lpvar j) const { lra.column_is_fixed(j) && lra.get_lower_bound(j) == lp::zero_of_type(); } + +bool core::fixed_var_has_big_bound(lpvar j) const { + SASSERT(lra.column_is_fixed(j)); + const auto& b = lra.get_lower_bound(j); + return b.x.is_big() || b.y.is_big(); +} + bool core::var_is_fixed_to_val(lpvar j, const rational& v) const { return lra.column_is_fixed(j) && diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index 8dee571ae..3b888f8ef 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -120,7 +120,8 @@ class core { public: // constructor core(lp::lar_solver& s, params_ref const& p, reslimit&); - + const auto& monics_with_changed_bounds() const { return m_monics_with_changed_bounds; } + void reset_monics_with_changed_bounds() { m_monics_with_changed_bounds.reset(); } void insert_to_refine(lpvar j); void erase_from_to_refine(lpvar j); @@ -310,6 +311,7 @@ public: bool sign_contradiction(const monic& m) const; bool var_is_fixed_to_zero(lpvar j) const; + bool fixed_var_has_big_bound(lpvar j) const; bool var_is_fixed_to_val(lpvar j, const rational& v) const; bool var_is_fixed(lpvar j) const; diff --git a/src/math/lp/nla_solver.h b/src/math/lp/nla_solver.h index 7a8a97b3f..07bf095a6 100644 --- a/src/math/lp/nla_solver.h +++ b/src/math/lp/nla_solver.h @@ -26,7 +26,8 @@ namespace nla { solver(lp::lar_solver& s, params_ref const& p, reslimit& limit); ~solver(); - + const auto& monics_with_changed_bounds() const { return m_core->monics_with_changed_bounds(); } + void reset_monics_with_changed_bounds() { m_core->reset_monics_with_changed_bounds(); } void add_monic(lpvar v, unsigned sz, lpvar const* vs); void add_idivision(lpvar q, lpvar x, lpvar y); void add_rdivision(lpvar q, lpvar x, lpvar y); diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index c06b8fafb..e4bec83cc 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -253,7 +253,7 @@ namespace arith { first = false; reset_evidence(); m_explanation.clear(); - lp().explain_implied_bound(be, m_bp); + be.explain(); } CTRACE("arith", m_unassigned_bounds[v] == 0, tout << "missed bound\n";); updt_unassigned_bounds(v, -1); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 29a46db19..1a022e087 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2150,7 +2150,7 @@ public: case l_true: propagate_basic_bounds(); propagate_bounds_with_lp_solver(); - propagate_nla(); + propagate_bounds_with_nlp(); break; case l_undef: UNREACHABLE(); @@ -2185,33 +2185,55 @@ public: set_evidence(j, m_core, m_eqs); m_explanation.add_pair(j, v); } - - void propagate_bounds_with_lp_solver() { - if (!should_propagate()) - return; - - m_bp.init(); - lp().propagate_bounds_for_touched_rows(m_bp); - - if (!m.inc()) - return; + void finish_bound_propagation() { if (is_infeasible()) { get_infeasibility_explanation_and_set_conflict(); // verbose_stream() << "unsat\n"; - } - else { - unsigned count = 0, prop = 0; - for (auto& ib : m_bp.ibounds()) { + } else { + for (auto &ib : m_bp.ibounds()) { m.inc(); if (ctx().inconsistent()) break; - ++prop; - count += propagate_lp_solver_bound(ib); + propagate_lp_solver_bound(ib); } } } + void propagate_bounds_with_lp_solver() { + if (!should_propagate()) + return; + m_bp.init(); + lp().propagate_bounds_for_touched_rows(m_bp); + + if (m.inc()) + finish_bound_propagation(); + } + + void calculate_implied_bounds_for_monic(lpvar monic_var, const svector& vars) { + m_bp.propagate_monic(monic_var, vars); + } + + void propagate_bounds_for_touched_monomials() { + for (unsigned v : m_nla->monics_with_changed_bounds()) { + calculate_implied_bounds_for_monic(v, m_nla->get_core().emons()[v].vars()); + } + m_nla->reset_monics_with_changed_bounds(); + } + + void propagate_bounds_with_nlp() { + if (!m_nla) + return; + if (is_infeasible() || !should_propagate()) + return; + + m_bp.init(); + propagate_bounds_for_touched_monomials(); + + if (m.inc()) + finish_bound_propagation(); + } + bool bound_is_interesting(unsigned vi, lp::lconstraint_kind kind, const rational & bval) const { theory_var v = lp().local_to_external(vi); if (v == null_theory_var) From cbad61ba2e157b86abaf03dfb4db0d3c912f5988 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 13 Sep 2023 14:27:34 -0700 Subject: [PATCH 10/69] propagate monics with lp_bound_propagator --- src/math/lp/bound_analyzer_on_row.h | 43 ++++------------- src/math/lp/implied_bound.h | 16 ++++-- src/math/lp/lar_solver.h | 2 +- src/math/lp/lp_bound_propagator.h | 75 ++++++++++++++++++++--------- src/sat/smt/arith_solver.cpp | 2 +- 5 files changed, 74 insertions(+), 64 deletions(-) diff --git a/src/math/lp/bound_analyzer_on_row.h b/src/math/lp/bound_analyzer_on_row.h index 35e3bb6ed..5af864220 100644 --- a/src/math/lp/bound_analyzer_on_row.h +++ b/src/math/lp/bound_analyzer_on_row.h @@ -93,39 +93,17 @@ private: } bool bound_is_available(unsigned j, bool lower_bound) { - return (lower_bound && lower_bound_is_available(j)) || - (!lower_bound && upper_bound_is_available(j)); - } - - bool upper_bound_is_available(unsigned j) const { - switch (m_bp.get_column_type(j)) { - case column_type::fixed: - case column_type::boxed: - case column_type::upper_bound: - return true; - default: - return false; - } - } - - bool lower_bound_is_available(unsigned j) const { - switch (m_bp.get_column_type(j)) { - case column_type::fixed: - case column_type::boxed: - case column_type::lower_bound: - return true; - default: - return false; - } + return (lower_bound && m_bp.lower_bound_is_available(j)) || + (!lower_bound && m_bp.upper_bound_is_available(j)); } const impq & ub(unsigned j) const { - lp_assert(upper_bound_is_available(j)); + lp_assert(m_bp.upper_bound_is_available(j)); return m_bp.get_upper_bound(j); } const impq & lb(unsigned j) const { - lp_assert(lower_bound_is_available(j)); + lp_assert(m_bp.lower_bound_is_available(j)); return m_bp.get_lower_bound(j); } @@ -305,9 +283,8 @@ private: void limit_j(unsigned bound_j, const mpq& u, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict){ - lar_solver* lar = & this->m_bp.lp(); unsigned row_index = this->m_row_index; - auto explain = [lar, bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index]() { return explain_bound_on_var_on_coeff(lar, bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index); }; + auto explain = [bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index](lar_solver& s) { return explain_bound_on_var_on_coeff(s, bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index); }; m_bp.add_bound(u, bound_j, is_lower_bound, strict, explain ); } @@ -341,22 +318,22 @@ private: break; } } - static u_dependency* explain_bound_on_var_on_coeff(lar_solver* lar, unsigned bound_j, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict, unsigned row_index) { + static u_dependency* explain_bound_on_var_on_coeff(lar_solver& lar, unsigned bound_j, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict, unsigned row_index) { int bound_sign = (is_lower_bound ? 1 : -1); int j_sign = (coeff_before_j_is_pos ? 1 : -1) * bound_sign; if (tv::is_term(bound_j)) - bound_j = lar->map_term_index_to_column_index(bound_j); + bound_j = lar.map_term_index_to_column_index(bound_j); u_dependency* ret = nullptr; - for (auto const& r : lar->get_row(row_index)) { + for (auto const& r : lar.get_row(row_index)) { unsigned j = r.var(); if (j == bound_j) continue; mpq const& a = r.coeff(); int a_sign = is_pos(a) ? 1 : -1; int sign = j_sign * a_sign; - u_dependency* witness = sign > 0 ? lar->get_column_upper_bound_witness(j) : lar->get_column_lower_bound_witness(j); - ret = lar->join_deps(ret, witness); + u_dependency* witness = sign > 0 ? lar.get_column_upper_bound_witness(j) : lar.get_column_lower_bound_witness(j); + ret = lar.join_deps(ret, witness); } return ret; } diff --git a/src/math/lp/implied_bound.h b/src/math/lp/implied_bound.h index 2e7fcbbcb..0df1f4f60 100644 --- a/src/math/lp/implied_bound.h +++ b/src/math/lp/implied_bound.h @@ -20,18 +20,24 @@ Revision History: #pragma once #include "math/lp/lp_settings.h" #include "math/lp/lar_constraints.h" +#include "math/lp/lar_solver.h" namespace lp { class implied_bound { public: mpq m_bound; - unsigned m_j; // the column for which the bound has been found + // It is either the column for which the bound has been found, or, + // in the case the column was created as + // the slack variable to a term, it is the term index. + // It is the same index that was returned by lar_solver::add_var(), or + // by lar_solver::add_term() + unsigned m_j; bool m_is_lower_bound; bool m_strict; private: - std::function m_explain_bound = nullptr; + std::function m_explain_bound = nullptr; public: - u_dependency* explain() const { return m_explain_bound(); } - void set_explain(std::function f) { m_explain_bound = f; } + u_dependency* explain(lar_solver& s) const { return m_explain_bound(s); } + void set_explain(std::function f) { m_explain_bound = f; } lconstraint_kind kind() const { lconstraint_kind k = m_is_lower_bound? GE : LE; if (m_strict) @@ -43,7 +49,7 @@ class implied_bound { unsigned j, bool is_lower_bound, bool is_strict, - std::function get_dep): + std::function get_dep): m_bound(a), m_j(j), m_is_lower_bound(is_lower_bound), diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 7d16c7b63..50e9de7a3 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -311,7 +311,7 @@ class lar_solver : public column_namer { template void explain_implied_bound(const implied_bound& ib, lp_bound_propagator& bp) { - u_dependency* dep = ib.explain(); + u_dependency* dep = ib.explain(*this); for (auto ci : flatten(dep)) bp.consume(mpq(1), ci); // TODO: flatten should provid the coefficients /* diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index 7ee647200..c67e99651 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -39,8 +39,28 @@ class lp_bound_propagator { } return x != UINT_MAX; } - - +public: + bool upper_bound_is_available(unsigned j) const { + switch (get_column_type(j)) { + case column_type::fixed: + case column_type::boxed: + case column_type::upper_bound: + return true; + default: + return false; + } + } + bool lower_bound_is_available(unsigned j) const { + switch (get_column_type(j)) { + case column_type::fixed: + case column_type::boxed: + case column_type::lower_bound: + return true; + default: + return false; + } + } +private: void try_add_equation_with_internal_fixed_tables(unsigned r1) { unsigned v1, v2; if (!only_one_nfixed(r1, v1)) @@ -119,11 +139,11 @@ class lp_bound_propagator { } void add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var) { - add_lower_bound_monic(monic_var, mpq(0), false, [&](){return lp().get_bound_constraint_witnesses_for_column(zero_var);}); - add_upper_bound_monic(monic_var, mpq(0), false, [&](){return lp().get_bound_constraint_witnesses_for_column(zero_var);}); + add_lower_bound_monic(monic_var, mpq(0), false, [zero_var](lar_solver& s){return s.get_bound_constraint_witnesses_for_column(zero_var);}); + add_upper_bound_monic(monic_var, mpq(0), false, [zero_var](lar_solver& s){return s.get_bound_constraint_witnesses_for_column(zero_var);}); } - void add_lower_bound_monic(lpvar monic_var, const mpq& v, bool is_strict, std::function explain_dep) { + void add_lower_bound_monic(lpvar monic_var, const mpq& v, bool is_strict, std::function explain_dep) { unsigned k; if (!try_get_value(m_improved_lower_bounds, monic_var, k)) { m_improved_lower_bounds[monic_var] = m_ibounds.size(); @@ -137,7 +157,7 @@ class lp_bound_propagator { } } - void add_upper_bound_monic(lpvar monic_var, const mpq& bound_val, bool is_strict, std::function explain_bound) { + void add_upper_bound_monic(lpvar monic_var, const mpq& bound_val, bool is_strict, std::function explain_bound) { unsigned k; if (!try_get_value(m_improved_upper_bounds, monic_var, k)) { m_improved_upper_bounds[monic_var] = m_ibounds.size(); @@ -160,47 +180,54 @@ class lp_bound_propagator { if (zero_var != null_lpvar) { add_bounds_for_zero_var(monic_var, zero_var); } else { - if (non_fixed != null_lpvar && get_column_type(non_fixed) == column_type::free_column) return; rational k = rational(1); for (auto v : vars) if (v != non_fixed) { k *= lp().get_column_value(v).x; if (k.is_big()) return; } - u_dependency* dep; - lp::mpq bound_value; + lp::impq bound_value; bool is_strict; if (non_fixed != null_lpvar) { - if (this->lp().has_lower_bound(non_fixed, dep, bound_value, is_strict)) { + if (lower_bound_is_available(non_fixed)) { + bound_value = lp().column_lower_bound(non_fixed); + is_strict = !bound_value.y.is_zero(); if (k.is_pos()) - add_lower_bound_monic(monic_var, k * bound_value, is_strict, [&]() { return dep; }); + add_lower_bound_monic(monic_var, k * bound_value.x, is_strict , [non_fixed](lar_solver& s) { return s.get_column_lower_bound_witness(non_fixed); }); else - add_upper_bound_monic(monic_var, k * bound_value, is_strict, [&]() {return dep;}); + add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, [non_fixed](lar_solver& s) {return s.get_column_lower_bound_witness(non_fixed);}); } - if (this->lp().has_upper_bound(non_fixed, dep, bound_value, is_strict)) { + if (upper_bound_is_available(non_fixed)) { + bound_value = lp().column_upper_bound(non_fixed); + is_strict = !bound_value.y.is_zero(); if (k.is_neg()) - add_lower_bound_monic(monic_var, k * bound_value, is_strict, [&]() {return dep;}); + add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, [non_fixed](lar_solver& s) {return s.get_column_upper_bound_witness(non_fixed);}); else - add_upper_bound_monic(monic_var, k * bound_value, is_strict, [&]() {return dep;}); + add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, [non_fixed](lar_solver& s) {return s.get_column_upper_bound_witness(non_fixed);}); } - if (this->lp().has_lower_bound(monic_var, dep, bound_value, is_strict)) { + if (lower_bound_is_available(monic_var)) { + bound_value = lp().column_lower_bound(monic_var); + is_strict = !bound_value.y.is_zero(); if (k.is_pos()) - add_lower_bound_monic(non_fixed, bound_value / k, is_strict, [&]() {return dep;}); + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](lar_solver& s) {return s.get_column_lower_bound_witness(monic_var);}); else - add_upper_bound_monic(non_fixed, bound_value / k, is_strict, [&]() {return dep;}); + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](lar_solver & s) {return s.get_column_lower_bound_witness(monic_var);}); } - if (this->lp().has_upper_bound(monic_var, dep, bound_value, is_strict)) { + if (upper_bound_is_available(monic_var)) { + bound_value = lp().column_upper_bound(monic_var); + is_strict = !bound_value.y.is_zero(); if (k.is_neg()) - add_lower_bound_monic(non_fixed, bound_value / k, is_strict, [&]() {return dep;}); + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](lar_solver& s) {return s.get_column_upper_bound_witness(monic_var);}); else - add_upper_bound_monic(non_fixed, bound_value / k, is_strict, [&]() {return dep;}); + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](lar_solver & s) {return s.get_column_upper_bound_witness(monic_var);}); } + } else { // all variables are fixed - add_lower_bound_monic(monic_var, k, false, [&](){return lp().get_bound_constraint_witnesses_for_columns(vars);}); - add_upper_bound_monic(monic_var, k, false, [&](){return lp().get_bound_constraint_witnesses_for_columns(vars);}); + add_lower_bound_monic(monic_var, k, false, [vars](lar_solver& s){return s.get_bound_constraint_witnesses_for_columns(vars);}); + add_upper_bound_monic(monic_var, k, false, [vars](lar_solver& s){return s.get_bound_constraint_witnesses_for_columns(vars);}); } } } @@ -233,7 +260,7 @@ class lp_bound_propagator { return (*m_column_types)[j] == column_type::fixed && get_lower_bound(j).y.is_zero(); } - void add_bound(mpq const& v, unsigned j, bool is_low, bool strict, std::function explain_bound) { + void add_bound(mpq const& v, unsigned j, bool is_low, bool strict, std::function explain_bound) { j = m_imp.lp().column_to_reported_index(j); lconstraint_kind kind = is_low ? GE : LE; diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index e4bec83cc..346fbb7a9 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -253,7 +253,7 @@ namespace arith { first = false; reset_evidence(); m_explanation.clear(); - be.explain(); + be.explain(lp()); } CTRACE("arith", m_unassigned_bounds[v] == 0, tout << "missed bound\n";); updt_unassigned_bounds(v, -1); From b3673d491e45e3319e155979630f9b74a1cccf11 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 14 Sep 2023 19:20:47 -0700 Subject: [PATCH 11/69] fix the build for gcc --- src/math/lp/bound_analyzer_on_row.h | 7 ++-- src/math/lp/implied_bound.h | 9 ++--- src/math/lp/lar_constraints.h | 4 +- src/math/lp/lar_solver.h | 2 +- src/math/lp/lp_bound_propagator.h | 58 ++++++++++++++--------------- src/sat/smt/arith_solver.cpp | 2 +- 6 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/math/lp/bound_analyzer_on_row.h b/src/math/lp/bound_analyzer_on_row.h index 5af864220..fa29d6201 100644 --- a/src/math/lp/bound_analyzer_on_row.h +++ b/src/math/lp/bound_analyzer_on_row.h @@ -284,8 +284,8 @@ private: void limit_j(unsigned bound_j, const mpq& u, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict){ unsigned row_index = this->m_row_index; - auto explain = [bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index](lar_solver& s) { return explain_bound_on_var_on_coeff(s, bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index); }; - m_bp.add_bound(u, bound_j, is_lower_bound, strict, explain ); + auto explain = [bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index](int * s) { return explain_bound_on_var_on_coeff((B*)s, bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index); }; + m_bp.add_bound(u, bound_j, is_lower_bound, strict, explain); } void advance_u(unsigned j) { @@ -318,7 +318,8 @@ private: break; } } - static u_dependency* explain_bound_on_var_on_coeff(lar_solver& lar, unsigned bound_j, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict, unsigned row_index) { + static u_dependency* explain_bound_on_var_on_coeff(B* bp, unsigned bound_j, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict, unsigned row_index) { + auto& lar = bp->lp(); int bound_sign = (is_lower_bound ? 1 : -1); int j_sign = (coeff_before_j_is_pos ? 1 : -1) * bound_sign; diff --git a/src/math/lp/implied_bound.h b/src/math/lp/implied_bound.h index 0df1f4f60..04f55f867 100644 --- a/src/math/lp/implied_bound.h +++ b/src/math/lp/implied_bound.h @@ -20,7 +20,6 @@ Revision History: #pragma once #include "math/lp/lp_settings.h" #include "math/lp/lar_constraints.h" -#include "math/lp/lar_solver.h" namespace lp { class implied_bound { public: @@ -34,10 +33,10 @@ class implied_bound { bool m_is_lower_bound; bool m_strict; private: - std::function m_explain_bound = nullptr; + std::function m_explain_bound = nullptr; public: - u_dependency* explain(lar_solver& s) const { return m_explain_bound(s); } - void set_explain(std::function f) { m_explain_bound = f; } + u_dependency* explain(int * s) const { return m_explain_bound(s); } + void set_explain(std::function f) { m_explain_bound = f; } lconstraint_kind kind() const { lconstraint_kind k = m_is_lower_bound? GE : LE; if (m_strict) @@ -49,7 +48,7 @@ class implied_bound { unsigned j, bool is_lower_bound, bool is_strict, - std::function get_dep): + std::function get_dep): m_bound(a), m_j(j), m_is_lower_bound(is_lower_bound), diff --git a/src/math/lp/lar_constraints.h b/src/math/lp/lar_constraints.h index 0a16353c1..b5e679e7e 100644 --- a/src/math/lp/lar_constraints.h +++ b/src/math/lp/lar_constraints.h @@ -137,8 +137,8 @@ class constraint_set { public: constraint_set(u_dependency_manager& d, column_namer& cn): - m_dep_manager(d), - m_namer(cn) {} + m_namer(cn), + m_dep_manager(d) {} ~constraint_set() { for (auto* c : m_constraints) diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 50e9de7a3..e2023aeaa 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -311,7 +311,7 @@ class lar_solver : public column_namer { template void explain_implied_bound(const implied_bound& ib, lp_bound_propagator& bp) { - u_dependency* dep = ib.explain(*this); + u_dependency* dep = ib.explain((int*)&bp); for (auto ci : flatten(dep)) bp.consume(mpq(1), ci); // TODO: flatten should provid the coefficients /* diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index c67e99651..d48d9b50c 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -40,6 +40,8 @@ class lp_bound_propagator { return x != UINT_MAX; } public: + const lar_solver& lp() const { return m_imp.lp(); } + lar_solver& lp() { return m_imp.lp(); } bool upper_bound_is_available(unsigned j) const { switch (get_column_type(j)) { case column_type::fixed: @@ -138,12 +140,13 @@ private: return n_of_non_fixed <= 1 && !big_bound; } + void add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var) { - add_lower_bound_monic(monic_var, mpq(0), false, [zero_var](lar_solver& s){return s.get_bound_constraint_witnesses_for_column(zero_var);}); - add_upper_bound_monic(monic_var, mpq(0), false, [zero_var](lar_solver& s){return s.get_bound_constraint_witnesses_for_column(zero_var);}); + add_lower_bound_monic(monic_var, mpq(0), false, [zero_var](int* s){return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_column(zero_var);}); + add_upper_bound_monic(monic_var, mpq(0), false, [zero_var](int* s){return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_column(zero_var);}); } - void add_lower_bound_monic(lpvar monic_var, const mpq& v, bool is_strict, std::function explain_dep) { + void add_lower_bound_monic(lpvar monic_var, const mpq& v, bool is_strict, std::function explain_dep) { unsigned k; if (!try_get_value(m_improved_lower_bounds, monic_var, k)) { m_improved_lower_bounds[monic_var] = m_ibounds.size(); @@ -152,12 +155,12 @@ private: auto& found_bound = m_ibounds[k]; if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && is_strict)) { found_bound = implied_bound(v, monic_var, true, is_strict, explain_dep); - TRACE("add_bound", m_imp.lp().print_implied_bound(found_bound, tout);); + TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); } } } - void add_upper_bound_monic(lpvar monic_var, const mpq& bound_val, bool is_strict, std::function explain_bound) { + void add_upper_bound_monic(lpvar monic_var, const mpq& bound_val, bool is_strict, std::function explain_bound) { unsigned k; if (!try_get_value(m_improved_upper_bounds, monic_var, k)) { m_improved_upper_bounds[monic_var] = m_ibounds.size(); @@ -166,7 +169,7 @@ private: auto& found_bound = m_ibounds[k]; if (bound_val > found_bound.m_bound || (bound_val == found_bound.m_bound && !found_bound.m_strict && is_strict)) { found_bound = implied_bound(bound_val, monic_var, false, is_strict, explain_bound); - TRACE("add_bound", m_imp.lp().print_implied_bound(found_bound, tout);); + TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); } } } @@ -193,66 +196,63 @@ private: bound_value = lp().column_lower_bound(non_fixed); is_strict = !bound_value.y.is_zero(); if (k.is_pos()) - add_lower_bound_monic(monic_var, k * bound_value.x, is_strict , [non_fixed](lar_solver& s) { return s.get_column_lower_bound_witness(non_fixed); }); + add_lower_bound_monic(monic_var, k * bound_value.x, is_strict , [non_fixed](int* s) { return ((lp_bound_propagator*)s)->lp().get_column_lower_bound_witness(non_fixed); }); else - add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, [non_fixed](lar_solver& s) {return s.get_column_lower_bound_witness(non_fixed);}); + add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, [non_fixed](int* s) {return ((lp_bound_propagator*)s)->lp().get_column_lower_bound_witness(non_fixed);}); } if (upper_bound_is_available(non_fixed)) { bound_value = lp().column_upper_bound(non_fixed); is_strict = !bound_value.y.is_zero(); if (k.is_neg()) - add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, [non_fixed](lar_solver& s) {return s.get_column_upper_bound_witness(non_fixed);}); + add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, [non_fixed](int* s) {return ((lp_bound_propagator*)s)->lp().get_column_upper_bound_witness(non_fixed);}); else - add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, [non_fixed](lar_solver& s) {return s.get_column_upper_bound_witness(non_fixed);}); + add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, [non_fixed](int* s) {return ((lp_bound_propagator*)s)->lp().get_column_upper_bound_witness(non_fixed);}); } if (lower_bound_is_available(monic_var)) { bound_value = lp().column_lower_bound(monic_var); is_strict = !bound_value.y.is_zero(); if (k.is_pos()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](lar_solver& s) {return s.get_column_lower_bound_witness(monic_var);}); + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](int* s) {return ((lp_bound_propagator*)s)->lp().get_column_lower_bound_witness(monic_var);}); else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](lar_solver & s) {return s.get_column_lower_bound_witness(monic_var);}); + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](int* s) {return ((lp_bound_propagator*)s)->lp().get_column_lower_bound_witness(monic_var);}); } if (upper_bound_is_available(monic_var)) { bound_value = lp().column_upper_bound(monic_var); is_strict = !bound_value.y.is_zero(); if (k.is_neg()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](lar_solver& s) {return s.get_column_upper_bound_witness(monic_var);}); + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](int* s) {return ((lp_bound_propagator*)s)->lp().get_column_upper_bound_witness(monic_var);}); else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](lar_solver & s) {return s.get_column_upper_bound_witness(monic_var);}); + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](int* s) {return ((lp_bound_propagator*)s)->lp().get_column_upper_bound_witness(monic_var);}); } } else { // all variables are fixed - add_lower_bound_monic(monic_var, k, false, [vars](lar_solver& s){return s.get_bound_constraint_witnesses_for_columns(vars);}); - add_upper_bound_monic(monic_var, k, false, [vars](lar_solver& s){return s.get_bound_constraint_witnesses_for_columns(vars);}); + add_lower_bound_monic(monic_var, k, false, [vars](int* s){return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_columns(vars);}); + add_upper_bound_monic(monic_var, k, false, [vars](int* s){return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_columns(vars);}); } } } - const lar_solver& lp() const { return m_imp.lp(); } - lar_solver& lp() { return m_imp.lp(); } - column_type get_column_type(unsigned j) const { return (*m_column_types)[j]; } const impq& get_lower_bound(unsigned j) const { - return m_imp.lp().get_lower_bound(j); + return lp().get_lower_bound(j); } const mpq& get_lower_bound_rational(unsigned j) const { - return m_imp.lp().get_lower_bound(j).x; + return lp().get_lower_bound(j).x; } const impq& get_upper_bound(unsigned j) const { - return m_imp.lp().get_upper_bound(j); + return lp().get_upper_bound(j); } const mpq& get_upper_bound_rational(unsigned j) const { - return m_imp.lp().get_upper_bound(j).x; + return lp().get_upper_bound(j).x; } // require also the zero infinitesemal part @@ -260,8 +260,8 @@ private: return (*m_column_types)[j] == column_type::fixed && get_lower_bound(j).y.is_zero(); } - void add_bound(mpq const& v, unsigned j, bool is_low, bool strict, std::function explain_bound) { - j = m_imp.lp().column_to_reported_index(j); + void add_bound(mpq const& v, unsigned j, bool is_low, bool strict, std::function explain_bound) { + j = lp().column_to_reported_index(j); lconstraint_kind kind = is_low ? GE : LE; if (strict) @@ -277,12 +277,12 @@ private: found_bound.m_bound = v; found_bound.m_strict = strict; found_bound.set_explain(explain_bound); - TRACE("add_bound", m_imp.lp().print_implied_bound(found_bound, tout);); + TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); } } else { m_improved_lower_bounds[j] = m_ibounds.size(); m_ibounds.push_back(implied_bound(v, j, is_low, strict, explain_bound)); - TRACE("add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout);); + TRACE("add_bound", lp().print_implied_bound(m_ibounds.back(), tout);); } } else { // the upper bound case if (try_get_value(m_improved_upper_bounds, j, k)) { @@ -291,12 +291,12 @@ private: found_bound.m_bound = v; found_bound.m_strict = strict; found_bound.set_explain(explain_bound); - TRACE("add_bound", m_imp.lp().print_implied_bound(found_bound, tout);); + TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); } } else { m_improved_upper_bounds[j] = m_ibounds.size(); m_ibounds.push_back(implied_bound(v, j, is_low, strict, explain_bound)); - TRACE("add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout);); + TRACE("add_bound", lp().print_implied_bound(m_ibounds.back(), tout);); } } } diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 346fbb7a9..d2e8e5b39 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -253,7 +253,7 @@ namespace arith { first = false; reset_evidence(); m_explanation.clear(); - be.explain(lp()); + be.explain((int*)&m_bp); } CTRACE("arith", m_unassigned_bounds[v] == 0, tout << "missed bound\n";); updt_unassigned_bounds(v, -1); From a55aa1a6489bb1db7442e0ceb7523169b4891a6d Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 14 Sep 2023 19:29:48 -0700 Subject: [PATCH 12/69] add a comment --- src/math/lp/implied_bound.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/math/lp/implied_bound.h b/src/math/lp/implied_bound.h index 04f55f867..e6d2bb898 100644 --- a/src/math/lp/implied_bound.h +++ b/src/math/lp/implied_bound.h @@ -35,6 +35,7 @@ class implied_bound { private: std::function m_explain_bound = nullptr; public: + // s is expected to be the pointer to lp_bound_propagator. u_dependency* explain(int * s) const { return m_explain_bound(s); } void set_explain(std::function f) { m_explain_bound = f; } lconstraint_kind kind() const { From 762ade2a798e127a96f939eb08052853f7f8ff1c Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 15 Sep 2023 06:15:22 -0700 Subject: [PATCH 13/69] check m_unassigned_bounds in bound_is_interesting --- src/smt/theory_lra.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 1a022e087..d88d54a69 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2239,6 +2239,9 @@ public: if (v == null_theory_var) return false; + if (m_unassigned_bounds[v] == 0) + return false; + if (should_refine_bounds()) return true; From 4cfba9787b5639cd0d2092071465d4d113693f4d Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 15 Sep 2023 17:41:10 -0700 Subject: [PATCH 14/69] debug lp_bound_propagator --- src/math/lp/lp_bound_propagator.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index d48d9b50c..1c9dff84f 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -146,29 +146,31 @@ private: add_upper_bound_monic(monic_var, mpq(0), false, [zero_var](int* s){return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_column(zero_var);}); } - void add_lower_bound_monic(lpvar monic_var, const mpq& v, bool is_strict, std::function explain_dep) { + void add_lower_bound_monic(lpvar j, const mpq& v, bool is_strict, std::function explain_dep) { unsigned k; - if (!try_get_value(m_improved_lower_bounds, monic_var, k)) { - m_improved_lower_bounds[monic_var] = m_ibounds.size(); - m_ibounds.push_back(implied_bound(v, monic_var, true, is_strict, explain_dep)); + j = lp().column_to_reported_index(j); + if (!try_get_value(m_improved_lower_bounds, j, k)) { + m_improved_lower_bounds[j] = m_ibounds.size(); + m_ibounds.push_back(implied_bound(v, j, true, is_strict, explain_dep)); } else { auto& found_bound = m_ibounds[k]; if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && is_strict)) { - found_bound = implied_bound(v, monic_var, true, is_strict, explain_dep); + found_bound = implied_bound(v, j, true, is_strict, explain_dep); TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); } } } - void add_upper_bound_monic(lpvar monic_var, const mpq& bound_val, bool is_strict, std::function explain_bound) { + void add_upper_bound_monic(lpvar j, const mpq& bound_val, bool is_strict, std::function explain_bound) { + j = lp().column_to_reported_index(j); unsigned k; - if (!try_get_value(m_improved_upper_bounds, monic_var, k)) { - m_improved_upper_bounds[monic_var] = m_ibounds.size(); - m_ibounds.push_back(implied_bound(bound_val, monic_var, false, is_strict, explain_bound)); + if (!try_get_value(m_improved_upper_bounds, j, k)) { + m_improved_upper_bounds[j] = m_ibounds.size(); + m_ibounds.push_back(implied_bound(bound_val, j, false, is_strict, explain_bound)); } else { auto& found_bound = m_ibounds[k]; if (bound_val > found_bound.m_bound || (bound_val == found_bound.m_bound && !found_bound.m_strict && is_strict)) { - found_bound = implied_bound(bound_val, monic_var, false, is_strict, explain_bound); + found_bound = implied_bound(bound_val, j, false, is_strict, explain_bound); TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); } } From b621c9fa1c53151529d030b33820b4f35114aa10 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 15 Sep 2023 17:42:18 -0700 Subject: [PATCH 15/69] remove an extrac check in bound_is_interesting --- src/smt/theory_lra.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index d88d54a69..1a022e087 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2239,9 +2239,6 @@ public: if (v == null_theory_var) return false; - if (m_unassigned_bounds[v] == 0) - return false; - if (should_refine_bounds()) return true; From c240f62ca86cc21a3d1d50a631d46c51019ec605 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 15 Sep 2023 17:44:10 -0700 Subject: [PATCH 16/69] is_linear does not check for is_big --- src/math/lp/lp_bound_propagator.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index 1c9dff84f..61eeae325 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -121,7 +121,6 @@ private: bool is_linear(const svector& m, lpvar& zero_var, lpvar& non_fixed) { zero_var = non_fixed = null_lpvar; unsigned n_of_non_fixed = 0; - bool big_bound = false; for (lpvar v : m) { if (!this->column_is_fixed(v)) { n_of_non_fixed++; @@ -133,11 +132,9 @@ private: zero_var = v; return true; } - if (b.is_big()) { - big_bound |= true; - } + } - return n_of_non_fixed <= 1 && !big_bound; + return n_of_non_fixed <= 1; } From 77e56b0a6953ff1e03063c600b9f5f447ffcfe1c Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 16 Sep 2023 13:54:14 -0700 Subject: [PATCH 17/69] debug --- src/math/lp/bound_analyzer_on_row.h | 1 + src/math/lp/implied_bound.h | 2 +- src/math/lp/lar_solver.h | 4 ++-- src/math/lp/lp_bound_propagator.h | 10 +++++++--- src/sat/smt/arith_solver.cpp | 2 +- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/math/lp/bound_analyzer_on_row.h b/src/math/lp/bound_analyzer_on_row.h index fa29d6201..642ed9d1c 100644 --- a/src/math/lp/bound_analyzer_on_row.h +++ b/src/math/lp/bound_analyzer_on_row.h @@ -319,6 +319,7 @@ private: } } static u_dependency* explain_bound_on_var_on_coeff(B* bp, unsigned bound_j, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict, unsigned row_index) { + TRACE("bound_analyzer", tout << "explain_bound_on_var_on_coeff, bound_j = " << bound_j << ", coeff_before_j_is_pos = " << coeff_before_j_is_pos << ", is_lower_bound = " << is_lower_bound << ", strict = " << strict << ", row_index = " << row_index << "\n";); auto& lar = bp->lp(); int bound_sign = (is_lower_bound ? 1 : -1); int j_sign = (coeff_before_j_is_pos ? 1 : -1) * bound_sign; diff --git a/src/math/lp/implied_bound.h b/src/math/lp/implied_bound.h index e6d2bb898..66b3453d2 100644 --- a/src/math/lp/implied_bound.h +++ b/src/math/lp/implied_bound.h @@ -36,7 +36,7 @@ class implied_bound { std::function m_explain_bound = nullptr; public: // s is expected to be the pointer to lp_bound_propagator. - u_dependency* explain(int * s) const { return m_explain_bound(s); } + u_dependency* explain_implied(int * s) const { return m_explain_bound(s); } void set_explain(std::function f) { m_explain_bound = f; } lconstraint_kind kind() const { lconstraint_kind k = m_is_lower_bound? GE : LE; diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index e2023aeaa..9af24d567 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -311,9 +311,9 @@ class lar_solver : public column_namer { template void explain_implied_bound(const implied_bound& ib, lp_bound_propagator& bp) { - u_dependency* dep = ib.explain((int*)&bp); + u_dependency* dep = ib.explain_implied((int*)&bp); for (auto ci : flatten(dep)) - bp.consume(mpq(1), ci); // TODO: flatten should provid the coefficients + bp.consume(mpq(1), ci); // TODO: flatten should provide the coefficients /* if (ib.m_is_monic) { NOT_IMPLEMENTED_YET(); diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index 61eeae325..c7b0d1f3f 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -137,14 +137,18 @@ private: return n_of_non_fixed <= 1; } - void add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var) { - add_lower_bound_monic(monic_var, mpq(0), false, [zero_var](int* s){return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_column(zero_var);}); - add_upper_bound_monic(monic_var, mpq(0), false, [zero_var](int* s){return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_column(zero_var);}); + auto lambda = [zero_var](int* s) { + return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_column(zero_var); + }; + TRACE("add_bound", lp().print_column_info(zero_var, tout) << std::endl;); + add_lower_bound_monic(monic_var, mpq(0), false, lambda); + add_upper_bound_monic(monic_var, mpq(0), false, lambda); } void add_lower_bound_monic(lpvar j, const mpq& v, bool is_strict, std::function explain_dep) { unsigned k; + TRACE("add_bound", lp().print_column_info(j, tout) << std::endl;); j = lp().column_to_reported_index(j); if (!try_get_value(m_improved_lower_bounds, j, k)) { m_improved_lower_bounds[j] = m_ibounds.size(); diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index d2e8e5b39..65329f9c4 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -253,7 +253,7 @@ namespace arith { first = false; reset_evidence(); m_explanation.clear(); - be.explain((int*)&m_bp); + be.explain_implied((int*)&m_bp); } CTRACE("arith", m_unassigned_bounds[v] == 0, tout << "missed bound\n";); updt_unassigned_bounds(v, -1); From 7353d7fb4dd2730281ee1d1f9edd30f29c4795f8 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 17 Sep 2023 06:48:12 -0700 Subject: [PATCH 18/69] fix dep calculations in lp_bound_propagator --- src/math/lp/bound_analyzer_on_row.h | 3 +- src/math/lp/lp_bound_propagator.h | 61 ++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/src/math/lp/bound_analyzer_on_row.h b/src/math/lp/bound_analyzer_on_row.h index 642ed9d1c..4bad3c0bc 100644 --- a/src/math/lp/bound_analyzer_on_row.h +++ b/src/math/lp/bound_analyzer_on_row.h @@ -324,8 +324,7 @@ private: int bound_sign = (is_lower_bound ? 1 : -1); int j_sign = (coeff_before_j_is_pos ? 1 : -1) * bound_sign; - if (tv::is_term(bound_j)) - bound_j = lar.map_term_index_to_column_index(bound_j); + SASSERT(!tv::is_term(bound_j)); u_dependency* ret = nullptr; for (auto const& r : lar.get_row(row_index)) { unsigned j = r.var(); diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index c7b0d1f3f..e104459a3 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -198,42 +198,83 @@ private: if (lower_bound_is_available(non_fixed)) { bound_value = lp().column_lower_bound(non_fixed); is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, non_fixed](int* s) { + auto& l = ((lp_bound_propagator*)s)->lp(); + u_dependency* dep = l.get_column_lower_bound_witness(non_fixed); + for (auto v : vars) { + if (v != non_fixed) { + dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); + } + } + return dep; + }; if (k.is_pos()) - add_lower_bound_monic(monic_var, k * bound_value.x, is_strict , [non_fixed](int* s) { return ((lp_bound_propagator*)s)->lp().get_column_lower_bound_witness(non_fixed); }); + add_lower_bound_monic(monic_var, k * bound_value.x, is_strict , lambda); else - add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, [non_fixed](int* s) {return ((lp_bound_propagator*)s)->lp().get_column_lower_bound_witness(non_fixed);}); + add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); } if (upper_bound_is_available(non_fixed)) { bound_value = lp().column_upper_bound(non_fixed); is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, non_fixed](int* s) { + auto& l = ((lp_bound_propagator*)s)->lp(); + u_dependency* dep = l.get_column_upper_bound_witness(non_fixed); + for (auto v : vars) { + if (v != non_fixed) { + dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); + } + } + return dep; + }; if (k.is_neg()) - add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, [non_fixed](int* s) {return ((lp_bound_propagator*)s)->lp().get_column_upper_bound_witness(non_fixed);}); + add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); else - add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, [non_fixed](int* s) {return ((lp_bound_propagator*)s)->lp().get_column_upper_bound_witness(non_fixed);}); + add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); } if (lower_bound_is_available(monic_var)) { + auto lambda = [vars, monic_var, non_fixed](int* s) { + auto& l = ((lp_bound_propagator*)s)->lp(); + u_dependency* dep = l.get_column_lower_bound_witness(monic_var); + for (auto v : vars) { + if (v != non_fixed) { + dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); + } + } + return dep; + }; bound_value = lp().column_lower_bound(monic_var); is_strict = !bound_value.y.is_zero(); if (k.is_pos()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](int* s) {return ((lp_bound_propagator*)s)->lp().get_column_lower_bound_witness(monic_var);}); + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](int* s) {return ((lp_bound_propagator*)s)->lp().get_column_lower_bound_witness(monic_var);}); + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); } if (upper_bound_is_available(monic_var)) { bound_value = lp().column_upper_bound(monic_var); is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, monic_var, non_fixed](int* s) { + auto& l = ((lp_bound_propagator*)s)->lp(); + u_dependency* dep = l.get_column_upper_bound_witness(monic_var); + for (auto v : vars) { + if (v != non_fixed) { + dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); + } + } + return dep; + }; if (k.is_neg()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](int* s) {return ((lp_bound_propagator*)s)->lp().get_column_upper_bound_witness(monic_var);}); + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, [monic_var](int* s) {return ((lp_bound_propagator*)s)->lp().get_column_upper_bound_witness(monic_var);}); + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); } } else { // all variables are fixed - add_lower_bound_monic(monic_var, k, false, [vars](int* s){return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_columns(vars);}); - add_upper_bound_monic(monic_var, k, false, [vars](int* s){return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_columns(vars);}); + auto lambda = [vars](int* s){return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_columns(vars);}; + add_lower_bound_monic(monic_var, k, false, lambda); + add_upper_bound_monic(monic_var, k, false, lambda); } } } From 30b743d7b3278f7b5d2720240f950eb0d1fae266 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 17 Sep 2023 10:45:54 -0700 Subject: [PATCH 19/69] refactor propagat_monic --- src/math/lp/lp_bound_propagator.h | 183 ++++++++++++++++-------------- 1 file changed, 96 insertions(+), 87 deletions(-) diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index e104459a3..13e6bbb9b 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -178,105 +178,114 @@ private: } void propagate_monic(lpvar monic_var, const svector& vars) { - lpvar non_fixed, zero_var; - if (!is_linear(vars, zero_var, non_fixed)) { + lpvar non_fixed, zero_var; + if (!is_linear(vars, zero_var, non_fixed)) { return; - } + } - if (zero_var != null_lpvar) { + if (zero_var != null_lpvar) { add_bounds_for_zero_var(monic_var, zero_var); - } else { + } else { rational k = rational(1); for (auto v : vars) if (v != non_fixed) { k *= lp().get_column_value(v).x; if (k.is_big()) return; } - lp::impq bound_value; - bool is_strict; + if (non_fixed != null_lpvar) { - if (lower_bound_is_available(non_fixed)) { - bound_value = lp().column_lower_bound(non_fixed); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, non_fixed](int* s) { - auto& l = ((lp_bound_propagator*)s)->lp(); - u_dependency* dep = l.get_column_lower_bound_witness(non_fixed); - for (auto v : vars) { - if (v != non_fixed) { - dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); - } - } - return dep; - }; - if (k.is_pos()) - add_lower_bound_monic(monic_var, k * bound_value.x, is_strict , lambda); - else - add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - } - if (upper_bound_is_available(non_fixed)) { - bound_value = lp().column_upper_bound(non_fixed); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, non_fixed](int* s) { - auto& l = ((lp_bound_propagator*)s)->lp(); - u_dependency* dep = l.get_column_upper_bound_witness(non_fixed); - for (auto v : vars) { - if (v != non_fixed) { - dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); - } - } - return dep; - }; - if (k.is_neg()) - add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - else - add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - } - - if (lower_bound_is_available(monic_var)) { - auto lambda = [vars, monic_var, non_fixed](int* s) { - auto& l = ((lp_bound_propagator*)s)->lp(); - u_dependency* dep = l.get_column_lower_bound_witness(monic_var); - for (auto v : vars) { - if (v != non_fixed) { - dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); - } - } - return dep; - }; - bound_value = lp().column_lower_bound(monic_var); - is_strict = !bound_value.y.is_zero(); - if (k.is_pos()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - } - - if (upper_bound_is_available(monic_var)) { - bound_value = lp().column_upper_bound(monic_var); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, monic_var, non_fixed](int* s) { - auto& l = ((lp_bound_propagator*)s)->lp(); - u_dependency* dep = l.get_column_upper_bound_witness(monic_var); - for (auto v : vars) { - if (v != non_fixed) { - dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); - } - } - return dep; - }; - if (k.is_neg()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - } - - + propagate_monic_with_non_fixed(monic_var, vars, non_fixed, k); } else { // all variables are fixed - auto lambda = [vars](int* s){return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_columns(vars);}; - add_lower_bound_monic(monic_var, k, false, lambda); - add_upper_bound_monic(monic_var, k, false, lambda); + propagate_monic_with_all_fixed(monic_var, vars, k); } - } + } + } + + void propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, rational k) { + lp::impq bound_value; + bool is_strict; + + if (lower_bound_is_available(non_fixed)) { + bound_value = lp().column_lower_bound(non_fixed); + is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, non_fixed](int* s) { + auto& l = ((lp_bound_propagator*)s)->lp(); + u_dependency* dep = l.get_column_lower_bound_witness(non_fixed); + for (auto v : vars) { + if (v != non_fixed) { + dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); + } + } + return dep; + }; + if (k.is_pos()) + add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + else + add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + } + + if (upper_bound_is_available(non_fixed)) { + bound_value = lp().column_upper_bound(non_fixed); + is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, non_fixed](int* s) { + auto& l = ((lp_bound_propagator*)s)->lp(); + u_dependency* dep = l.get_column_upper_bound_witness(non_fixed); + for (auto v : vars) { + if (v != non_fixed) { + dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); + } + } + return dep; + }; + if (k.is_neg()) + add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + else + add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + } + + if (lower_bound_is_available(monic_var)) { + auto lambda = [vars, monic_var, non_fixed](int* s) { + auto& l = ((lp_bound_propagator*)s)->lp(); + u_dependency* dep = l.get_column_lower_bound_witness(monic_var); + for (auto v : vars) { + if (v != non_fixed) { + dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); + } + } + return dep; + }; + bound_value = lp().column_lower_bound(monic_var); + is_strict = !bound_value.y.is_zero(); + if (k.is_pos()) + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + else + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + } + + if (upper_bound_is_available(monic_var)) { + bound_value = lp().column_upper_bound(monic_var); + is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, monic_var, non_fixed](int* s) { + auto& l = ((lp_bound_propagator*)s)->lp(); + u_dependency* dep = l.get_column_upper_bound_witness(monic_var); + for (auto v : vars) { + if (v != non_fixed) { + dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); + } + } + return dep; + }; + if (k.is_neg()) + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + else + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + } + } + + void propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, rational k) { + auto lambda = [vars](int* s) { return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_columns(vars); }; + add_lower_bound_monic(monic_var, k, false, lambda); + add_upper_bound_monic(monic_var, k, false, lambda); } column_type get_column_type(unsigned j) const { From 66f6a0327f5149d7fa7bf3fc42415e4a5c5f3d75 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 17 Sep 2023 11:00:48 -0700 Subject: [PATCH 20/69] change type of m_ibounds to std::vector --- src/math/lp/lp_bound_propagator.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index 13e6bbb9b..764ec4a52 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -18,7 +18,7 @@ class lp_bound_propagator { std::unordered_map m_improved_upper_bounds; T& m_imp; - vector m_ibounds; + std::vector m_ibounds; map, default_eq> m_val2fixed_row; // works for rows of the form x + y + sum of fixed = 0 @@ -109,12 +109,12 @@ private: public: lp_bound_propagator(T& imp) : m_imp(imp) {} - const vector& ibounds() const { return m_ibounds; } + const std::vector& ibounds() const { return m_ibounds; } void init() { m_improved_upper_bounds.clear(); m_improved_lower_bounds.clear(); - m_ibounds.reset(); + m_ibounds.clear(); m_column_types = &lp().get_column_types(); } @@ -151,7 +151,7 @@ private: TRACE("add_bound", lp().print_column_info(j, tout) << std::endl;); j = lp().column_to_reported_index(j); if (!try_get_value(m_improved_lower_bounds, j, k)) { - m_improved_lower_bounds[j] = m_ibounds.size(); + m_improved_lower_bounds[j] = static_cast(m_ibounds.size()); m_ibounds.push_back(implied_bound(v, j, true, is_strict, explain_dep)); } else { auto& found_bound = m_ibounds[k]; @@ -166,7 +166,7 @@ private: j = lp().column_to_reported_index(j); unsigned k; if (!try_get_value(m_improved_upper_bounds, j, k)) { - m_improved_upper_bounds[j] = m_ibounds.size(); + m_improved_upper_bounds[j] = static_cast(m_ibounds.size()); m_ibounds.push_back(implied_bound(bound_val, j, false, is_strict, explain_bound)); } else { auto& found_bound = m_ibounds[k]; @@ -333,7 +333,7 @@ private: TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); } } else { - m_improved_lower_bounds[j] = m_ibounds.size(); + m_improved_lower_bounds[j] = static_cast(m_ibounds.size()); m_ibounds.push_back(implied_bound(v, j, is_low, strict, explain_bound)); TRACE("add_bound", lp().print_implied_bound(m_ibounds.back(), tout);); } @@ -347,7 +347,7 @@ private: TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); } } else { - m_improved_upper_bounds[j] = m_ibounds.size(); + m_improved_upper_bounds[j] = static_cast(m_ibounds.size()); m_ibounds.push_back(implied_bound(v, j, is_low, strict, explain_bound)); TRACE("add_bound", lp().print_implied_bound(m_ibounds.back(), tout);); } From 10095a30b7b2d9a5a61f0815e96a8162fb8d8288 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 17 Sep 2023 12:25:11 -0700 Subject: [PATCH 21/69] add an include file --- src/math/lp/lp_bound_propagator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index 764ec4a52..bbddd6357 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -6,9 +6,9 @@ */ #pragma once #include - #include "math/lp/lp_settings.h" #include "util/uint_set.h" +#include "math/lp/implied_bound.h" namespace lp { template class lp_bound_propagator { From af8d1923928bfc8e30e0c3d43258216ab163d03e Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 17 Sep 2023 13:14:36 -0700 Subject: [PATCH 22/69] add an include --- src/math/lp/lp_bound_propagator.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index bbddd6357..2c5c654c2 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -9,6 +9,7 @@ #include "math/lp/lp_settings.h" #include "util/uint_set.h" #include "math/lp/implied_bound.h" +#include namespace lp { template class lp_bound_propagator { From cf63e7589887a4e2b6ed02b8bd8088b923a6c7c9 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 18 Sep 2023 13:25:24 -0700 Subject: [PATCH 23/69] using structures from util in lp_bound_propagator Signed-off-by: Lev Nachmanson --- src/math/lp/lp_bound_propagator.h | 66 +++++++++++++++++++------------ 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index 2c5c654c2..01fe42dff 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -12,14 +12,26 @@ #include namespace lp { template +struct my_allocator { + using value_type = T; + + T* allocate(std::size_t n) { + return static_cast(memory::allocate(n * sizeof(T))); + } + + void deallocate(T* p, std::size_t n) { + memory::deallocate(p); + } +}; +template class lp_bound_propagator { uint_set m_visited_rows; // these maps map a column index to the corresponding index in ibounds - std::unordered_map m_improved_lower_bounds; - std::unordered_map m_improved_upper_bounds; + u_map m_improved_lower_bounds; + u_map m_improved_upper_bounds; T& m_imp; - std::vector m_ibounds; + std::vector> m_ibounds; map, default_eq> m_val2fixed_row; // works for rows of the form x + y + sum of fixed = 0 @@ -110,11 +122,11 @@ private: public: lp_bound_propagator(T& imp) : m_imp(imp) {} - const std::vector& ibounds() const { return m_ibounds; } + const std::vector>& ibounds() const { return m_ibounds; } void init() { - m_improved_upper_bounds.clear(); - m_improved_lower_bounds.clear(); + m_improved_upper_bounds.reset(); + m_improved_lower_bounds.reset(); m_ibounds.clear(); m_column_types = &lp().get_column_types(); } @@ -148,14 +160,14 @@ private: } void add_lower_bound_monic(lpvar j, const mpq& v, bool is_strict, std::function explain_dep) { - unsigned k; TRACE("add_bound", lp().print_column_info(j, tout) << std::endl;); j = lp().column_to_reported_index(j); - if (!try_get_value(m_improved_lower_bounds, j, k)) { - m_improved_lower_bounds[j] = static_cast(m_ibounds.size()); + auto *e = m_improved_lower_bounds.find_core(j); + if (!e) { + m_improved_lower_bounds.insert(j,static_cast(m_ibounds.size())); m_ibounds.push_back(implied_bound(v, j, true, is_strict, explain_dep)); } else { - auto& found_bound = m_ibounds[k]; + auto& found_bound = m_ibounds[e->get_data().m_value]; if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && is_strict)) { found_bound = implied_bound(v, j, true, is_strict, explain_dep); TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); @@ -165,12 +177,12 @@ private: void add_upper_bound_monic(lpvar j, const mpq& bound_val, bool is_strict, std::function explain_bound) { j = lp().column_to_reported_index(j); - unsigned k; - if (!try_get_value(m_improved_upper_bounds, j, k)) { - m_improved_upper_bounds[j] = static_cast(m_ibounds.size()); + auto *e = m_improved_upper_bounds.find_core(j); + if (!e) { + m_improved_upper_bounds.insert(j, static_cast(m_ibounds.size())); m_ibounds.push_back(implied_bound(bound_val, j, false, is_strict, explain_bound)); - } else { - auto& found_bound = m_ibounds[k]; + } else { + auto& found_bound = m_ibounds[e->get_data().m_value]; if (bound_val > found_bound.m_bound || (bound_val == found_bound.m_bound && !found_bound.m_strict && is_strict)) { found_bound = implied_bound(bound_val, j, false, is_strict, explain_bound); TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); @@ -202,7 +214,7 @@ private: } } - void propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, rational k) { + void propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { lp::impq bound_value; bool is_strict; @@ -283,7 +295,7 @@ private: } } - void propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, rational k) { + void propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k) { auto lambda = [vars](int* s) { return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_columns(vars); }; add_lower_bound_monic(monic_var, k, false, lambda); add_upper_bound_monic(monic_var, k, false, lambda); @@ -323,10 +335,10 @@ private: if (!m_imp.bound_is_interesting(j, kind, v)) return; - unsigned k; // index to ibounds if (is_low) { - if (try_get_value(m_improved_lower_bounds, j, k)) { - auto& found_bound = m_ibounds[k]; + auto *e = m_improved_lower_bounds.find_core(j); + if (e) { + auto& found_bound = m_ibounds[e->get_data().m_value]; if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) { found_bound.m_bound = v; found_bound.m_strict = strict; @@ -334,13 +346,14 @@ private: TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); } } else { - m_improved_lower_bounds[j] = static_cast(m_ibounds.size()); + m_improved_lower_bounds.insert(j, static_cast(m_ibounds.size())); m_ibounds.push_back(implied_bound(v, j, is_low, strict, explain_bound)); TRACE("add_bound", lp().print_implied_bound(m_ibounds.back(), tout);); } } else { // the upper bound case - if (try_get_value(m_improved_upper_bounds, j, k)) { - auto& found_bound = m_ibounds[k]; + auto *e = m_improved_upper_bounds.find_core(j); + if (e) { + auto& found_bound = m_ibounds[e->get_data().m_value]; if (v < found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) { found_bound.m_bound = v; found_bound.m_strict = strict; @@ -348,7 +361,7 @@ private: TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); } } else { - m_improved_upper_bounds[j] = static_cast(m_ibounds.size()); + m_improved_upper_bounds.insert(j, static_cast(m_ibounds.size())); m_ibounds.push_back(implied_bound(v, j, is_low, strict, explain_bound)); TRACE("add_bound", lp().print_implied_bound(m_ibounds.back(), tout);); } @@ -578,11 +591,12 @@ private: lp_assert(y_sign == 1 || y_sign == -1); auto& table = y_sign == 1 ? m_row2index_pos : m_row2index_neg; const auto& v = val(x); - unsigned found_i; - if (!table.find(v, found_i)) { + auto * e = table.find_core(v); + if (!e) { table.insert(v, i); } else { explanation ex; + unsigned found_i = e->get_data().m_value; unsigned base_of_found = lp().get_base_column_in_row(found_i); if (is_int(x) != is_int(base_of_found) || ival(x).y != ival(base_of_found).y) continue; From c5cfd62e0a0858f3c37df5e9f325593983402960 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 19 Sep 2023 10:56:09 -0700 Subject: [PATCH 24/69] remove dead code related to nla unit propagation Signed-off-by: Lev Nachmanson --- src/math/lp/lp_bound_propagator.h | 30 +++++++++---------- src/math/lp/monomial_bounds.cpp | 48 ------------------------------- src/math/lp/monomial_bounds.h | 4 +-- src/math/lp/nla_core.cpp | 11 ------- src/math/lp/nla_solver.cpp | 4 --- src/smt/theory_lra.cpp | 14 --------- 6 files changed, 16 insertions(+), 95 deletions(-) diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index 01fe42dff..6a01d4ace 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -162,12 +162,12 @@ private: void add_lower_bound_monic(lpvar j, const mpq& v, bool is_strict, std::function explain_dep) { TRACE("add_bound", lp().print_column_info(j, tout) << std::endl;); j = lp().column_to_reported_index(j); - auto *e = m_improved_lower_bounds.find_core(j); - if (!e) { + unsigned k; + if (!m_improved_lower_bounds.find(j, k)) { m_improved_lower_bounds.insert(j,static_cast(m_ibounds.size())); m_ibounds.push_back(implied_bound(v, j, true, is_strict, explain_dep)); } else { - auto& found_bound = m_ibounds[e->get_data().m_value]; + auto& found_bound = m_ibounds[k]; if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && is_strict)) { found_bound = implied_bound(v, j, true, is_strict, explain_dep); TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); @@ -177,12 +177,12 @@ private: void add_upper_bound_monic(lpvar j, const mpq& bound_val, bool is_strict, std::function explain_bound) { j = lp().column_to_reported_index(j); - auto *e = m_improved_upper_bounds.find_core(j); - if (!e) { + unsigned k; + if (!m_improved_upper_bounds.find(j, k)) { m_improved_upper_bounds.insert(j, static_cast(m_ibounds.size())); m_ibounds.push_back(implied_bound(bound_val, j, false, is_strict, explain_bound)); } else { - auto& found_bound = m_ibounds[e->get_data().m_value]; + auto& found_bound = m_ibounds[k]; if (bound_val > found_bound.m_bound || (bound_val == found_bound.m_bound && !found_bound.m_strict && is_strict)) { found_bound = implied_bound(bound_val, j, false, is_strict, explain_bound); TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); @@ -336,9 +336,9 @@ private: if (!m_imp.bound_is_interesting(j, kind, v)) return; if (is_low) { - auto *e = m_improved_lower_bounds.find_core(j); - if (e) { - auto& found_bound = m_ibounds[e->get_data().m_value]; + unsigned k; + if (m_improved_lower_bounds.find(j, k)) { + auto& found_bound = m_ibounds[k]; if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) { found_bound.m_bound = v; found_bound.m_strict = strict; @@ -351,9 +351,9 @@ private: TRACE("add_bound", lp().print_implied_bound(m_ibounds.back(), tout);); } } else { // the upper bound case - auto *e = m_improved_upper_bounds.find_core(j); - if (e) { - auto& found_bound = m_ibounds[e->get_data().m_value]; + unsigned k; + if (m_improved_upper_bounds.find(j, k)) { + auto& found_bound = m_ibounds[k]; if (v < found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) { found_bound.m_bound = v; found_bound.m_strict = strict; @@ -591,12 +591,12 @@ private: lp_assert(y_sign == 1 || y_sign == -1); auto& table = y_sign == 1 ? m_row2index_pos : m_row2index_neg; const auto& v = val(x); - auto * e = table.find_core(v); - if (!e) { + unsigned found_i;; + + if (!table.find(v, found_i)) { table.insert(v, i); } else { explanation ex; - unsigned found_i = e->get_data().m_value; unsigned base_of_found = lp().get_base_column_in_row(found_i); if (is_int(x) != is_int(base_of_found) || ival(x).y != ival(base_of_found).y) continue; diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index ad2b20c07..7d2dc5ce6 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -24,7 +24,6 @@ namespace nla { } } - bool monomial_bounds::is_too_big(mpq const& q) const { return rational(q).bitsize() > 256; } @@ -258,53 +257,6 @@ namespace nla { } } - void monomial_bounds::unit_propagate() { - for (lpvar v : c().m_monics_with_changed_bounds) - unit_propagate(c().emons()[v]); - c().m_monics_with_changed_bounds.clear(); - } - - void monomial_bounds::unit_propagate(monic const& m) { - m_propagated.reserve(m.var() + 1, false); - if (m_propagated[m.var()]) - return; - - lpvar non_fixed = null_lpvar, zero_var = null_lpvar; - if (!is_linear(m, zero_var, non_fixed)) - return; - - c().trail().push(set_bitvector_trail(m_propagated, m.var())); - - - if (zero_var != null_lpvar) { - new_lemma lemma(c(), "fixed-values"); - lemma.explain_fixed(zero_var); - lemma += ineq(m.var(), lp::lconstraint_kind::EQ, 0); - } - else { - rational k = rational(1); - for (auto v : m) - if (v != non_fixed) { - k *= c().lra.get_column_value(v).x; - if (k.is_big()) return; - } - - new_lemma lemma(c(), "fixed-values"); - - for (auto v : m) - if (v != non_fixed) - lemma.explain_fixed(v); - - if (non_fixed != null_lpvar) { - lp::lar_term term; - term.add_var(m.var()); - term.add_monomial(-k, non_fixed); - lemma += ineq(term, lp::lconstraint_kind::EQ, 0); - } else { - lemma += ineq(m.var(), lp::lconstraint_kind::EQ, k); - } - } - } // returns true iff (all variables are fixed, // or all but one variable are fixed) and the bounds are not big, // or at least one variable is fixed to zero. diff --git a/src/math/lp/monomial_bounds.h b/src/math/lp/monomial_bounds.h index 15ab6b992..6253af744 100644 --- a/src/math/lp/monomial_bounds.h +++ b/src/math/lp/monomial_bounds.h @@ -20,7 +20,6 @@ namespace nla { void var2interval(lpvar v, scoped_dep_interval& i); bool is_too_big(mpq const& q) const; - bool propagate_down(monic const& m, lpvar u); bool propagate_value(dep_interval& range, lpvar v); bool propagate_value(dep_interval& range, lpvar v, unsigned power); void compute_product(unsigned start, monic const& m, scoped_dep_interval& i); @@ -32,12 +31,11 @@ namespace nla { // monomial propagation bool_vector m_propagated; - void unit_propagate(monic const& m); bool is_linear(monic const& m, lpvar& zero_var, lpvar& non_fixed); public: monomial_bounds(core* core); void propagate(); - void unit_propagate(); + }; } diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 20003f947..63dd29d9b 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -1836,17 +1836,6 @@ bool core::improve_bounds() { } return bounds_improved; } - -void core::propagate(vector& lemmas) { - // propagate linear monomials, those that have all, or all but one, variables fixed - lemmas.reset(); - m_lemma_vec = &lemmas; - - m_monomial_bounds.unit_propagate(); - -} - - } // end of nla diff --git a/src/math/lp/nla_solver.cpp b/src/math/lp/nla_solver.cpp index b7197ff2f..8be918f01 100644 --- a/src/math/lp/nla_solver.cpp +++ b/src/math/lp/nla_solver.cpp @@ -46,10 +46,6 @@ namespace nla { return m_core->check(lits, lemmas); } - void solver::propagate(vector& lemmas) { - m_core->propagate(lemmas); - } - void solver::push(){ m_core->push(); } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 1a022e087..fa73788e6 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2159,20 +2159,6 @@ public: return true; } - void propagate_nla() { - if (!m_nla) - return; - m_nla->propagate(m_nla_lemma_vector); - if (lp().get_status() == lp::lp_status::INFEASIBLE) { - TRACE("arith", tout << "propagation conflict\n";); - get_infeasibility_explanation_and_set_conflict(); - } - else { - for (nla::lemma const& l : m_nla_lemma_vector) - false_case_of_check_nla(l); - } - } - bool should_propagate() const { return bound_prop_mode::BP_NONE != propagation_mode(); } From 85db8163fa6a9e9c99c15899a306d59e20be9b6c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Sep 2023 13:57:28 -0700 Subject: [PATCH 25/69] move allocator to memory_manager and std_vector to vector Signed-off-by: Nikolaj Bjorner --- src/math/lp/lp_bound_propagator.h | 23 ++++++----------------- src/math/lp/nla_monotone_lemmas.h | 2 +- src/util/memory_manager.h | 13 +++++++++++++ src/util/vector.h | 3 +++ 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index 6a01d4ace..d035d9bcb 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -9,29 +9,18 @@ #include "math/lp/lp_settings.h" #include "util/uint_set.h" #include "math/lp/implied_bound.h" -#include +#include "util/vector.h" namespace lp { -template -struct my_allocator { - using value_type = T; - - T* allocate(std::size_t n) { - return static_cast(memory::allocate(n * sizeof(T))); - } - - void deallocate(T* p, std::size_t n) { - memory::deallocate(p); - } -}; + template class lp_bound_propagator { - uint_set m_visited_rows; + uint_set m_visited_rows; // these maps map a column index to the corresponding index in ibounds u_map m_improved_lower_bounds; u_map m_improved_upper_bounds; T& m_imp; - std::vector> m_ibounds; + std_vector m_ibounds; map, default_eq> m_val2fixed_row; // works for rows of the form x + y + sum of fixed = 0 @@ -119,10 +108,10 @@ private: ~reset_cheap_eq() { p.reset_cheap_eq_eh(); } }; - public: +public: lp_bound_propagator(T& imp) : m_imp(imp) {} - const std::vector>& ibounds() const { return m_ibounds; } + const std_vector& ibounds() const { return m_ibounds; } void init() { m_improved_upper_bounds.reset(); diff --git a/src/math/lp/nla_monotone_lemmas.h b/src/math/lp/nla_monotone_lemmas.h index d13f588e8..2cb646777 100644 --- a/src/math/lp/nla_monotone_lemmas.h +++ b/src/math/lp/nla_monotone_lemmas.h @@ -16,7 +16,7 @@ private: void monotonicity_lemma(monic const& m); void monotonicity_lemma_gt(const monic& m); void monotonicity_lemma_lt(const monic& m); - std::vector get_sorted_key(const monic& rm) const; + // std_vector get_sorted_key(const monic& rm) const; vector> get_sorted_key_with_rvars(const monic& a) const; }; } diff --git a/src/util/memory_manager.h b/src/util/memory_manager.h index 7dab520df..053816449 100644 --- a/src/util/memory_manager.h +++ b/src/util/memory_manager.h @@ -128,6 +128,19 @@ void dealloc_svect(T * ptr) { memory::deallocate(ptr); } +template +struct std_allocator { + using value_type = T; + + T* allocate(std::size_t n) { + return static_cast(memory::allocate(n * sizeof(T))); + } + + void deallocate(T* p, std::size_t n) { + memory::deallocate(p); + } +}; + struct mem_stat { }; diff --git a/src/util/vector.h b/src/util/vector.h index 1cb25a8c4..9ca9a1103 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -33,6 +33,7 @@ Revision History: #include "util/memory_manager.h" #include "util/hash.h" #include "util/z3_exception.h" +#include // disable warning for constant 'if' expressions. // these are used heavily in templates. @@ -40,6 +41,8 @@ Revision History: #pragma warning(disable:4127) #endif +template +class std_vector : public std::vector> {}; #if 0 From 4d742001ab4d871e2929224d4f7649bd20d20667 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Sep 2023 14:36:21 -0700 Subject: [PATCH 26/69] formatting of else Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index fa73788e6..9357b7a65 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2176,7 +2176,8 @@ public: if (is_infeasible()) { get_infeasibility_explanation_and_set_conflict(); // verbose_stream() << "unsat\n"; - } else { + } + else { for (auto &ib : m_bp.ibounds()) { m.inc(); if (ctx().inconsistent()) From f07553ed3a2ca03c69b0a60b13671a579b7313b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 19 Sep 2023 15:18:38 -0700 Subject: [PATCH 27/69] formatting updates Signed-off-by: Nikolaj Bjorner --- src/math/lp/lp_bound_propagator.h | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index d035d9bcb..8af04c793 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -181,13 +181,12 @@ public: void propagate_monic(lpvar monic_var, const svector& vars) { lpvar non_fixed, zero_var; - if (!is_linear(vars, zero_var, non_fixed)) { - return; - } + if (!is_linear(vars, zero_var, non_fixed)) + return; - if (zero_var != null_lpvar) { + if (zero_var != null_lpvar) add_bounds_for_zero_var(monic_var, zero_var); - } else { + else { rational k = rational(1); for (auto v : vars) if (v != non_fixed) { @@ -195,19 +194,18 @@ public: if (k.is_big()) return; } - if (non_fixed != null_lpvar) { + if (non_fixed != null_lpvar) propagate_monic_with_non_fixed(monic_var, vars, non_fixed, k); - } else { // all variables are fixed + else // all variables are fixed propagate_monic_with_all_fixed(monic_var, vars, k); - } } } void propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { - lp::impq bound_value; - bool is_strict; + lp::impq bound_value; + bool is_strict; - if (lower_bound_is_available(non_fixed)) { + if (lower_bound_is_available(non_fixed)) { bound_value = lp().column_lower_bound(non_fixed); is_strict = !bound_value.y.is_zero(); auto lambda = [vars, non_fixed](int* s) { From d77c91b1aa1531703208d100f12c211c36b4c45c Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 19 Sep 2023 15:46:59 -0700 Subject: [PATCH 28/69] trying to get else on a new line with clang-formatter --- src/math/lp/.clang-format | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/math/lp/.clang-format b/src/math/lp/.clang-format index f5c8a41b2..d7f8d6171 100644 --- a/src/math/lp/.clang-format +++ b/src/math/lp/.clang-format @@ -1,4 +1,5 @@ BasedOnStyle: Google IndentWidth: 4 ColumnLimit: 0 -NamespaceIndentation: All \ No newline at end of file +NamespaceIndentation: All +BreakBeforeBraces: Stroustrup \ No newline at end of file From 9648793206a6ddd6554af14080c0d1493e8d5c82 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 20 Sep 2023 14:11:38 -0700 Subject: [PATCH 29/69] add features to std_allocator --- src/util/memory_manager.h | 10 ++++++++++ src/util/vector.h | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/util/memory_manager.h b/src/util/memory_manager.h index 053816449..a50d03ac3 100644 --- a/src/util/memory_manager.h +++ b/src/util/memory_manager.h @@ -131,6 +131,10 @@ void dealloc_svect(T * ptr) { template struct std_allocator { using value_type = T; + // the constructors must be proveded according to cpp docs + std_allocator() = default; + template constexpr std_allocator(const std_allocator&) noexcept {} + T* allocate(std::size_t n) { return static_cast(memory::allocate(n * sizeof(T))); @@ -141,6 +145,12 @@ struct std_allocator { } }; +// the comparison operators must be proveded according to cpp docs +template +bool operator==(const std_allocator&, const std_allocator&) { return true; } +template +bool operator!=(const std_allocator&, const std_allocator&) { return false; } + struct mem_stat { }; diff --git a/src/util/vector.h b/src/util/vector.h index 9ca9a1103..55b52d745 100644 --- a/src/util/vector.h +++ b/src/util/vector.h @@ -42,7 +42,7 @@ Revision History: #endif template -class std_vector : public std::vector> {}; +using std_vector = std::vector>; #if 0 From 24512d5ec2b595c68fff96e2929f22683db83a5d Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 20 Sep 2023 14:12:36 -0700 Subject: [PATCH 30/69] typo --- src/util/memory_manager.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/memory_manager.h b/src/util/memory_manager.h index a50d03ac3..af56c4507 100644 --- a/src/util/memory_manager.h +++ b/src/util/memory_manager.h @@ -131,7 +131,7 @@ void dealloc_svect(T * ptr) { template struct std_allocator { using value_type = T; - // the constructors must be proveded according to cpp docs + // the constructors must be provided according to cpp docs std_allocator() = default; template constexpr std_allocator(const std_allocator&) noexcept {} @@ -145,7 +145,7 @@ struct std_allocator { } }; -// the comparison operators must be proveded according to cpp docs +// the comparison operators must be provided according to cpp docs template bool operator==(const std_allocator&, const std_allocator&) { return true; } template From 7a74b099baa40326f5f954f3e42af1f517c5d3e6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Sep 2023 15:04:24 -0700 Subject: [PATCH 31/69] remove experimental code Signed-off-by: Nikolaj Bjorner --- src/smt/theory_arith_nl.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 77e2b25f3..f44516cad 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -511,7 +511,6 @@ bool theory_arith::propagate_nl_downward(expr * n, var_power_pair const& p) */ template bool theory_arith::propagate_nl_bounds(expr * m) { - return false; TRACE("non_linear", tout << "propagate several bounds using:\n"; display_monomial(tout, m); tout << "\n";); bool result = propagate_nl_upward(m); buffer vp; @@ -531,7 +530,6 @@ bool theory_arith::propagate_nl_bounds(expr * m) { */ template bool theory_arith::propagate_nl_bounds() { - return false; m_dep_manager.reset(); bool propagated = false; for (unsigned i = 0; i < m_nl_monomials.size(); i++) { @@ -1634,7 +1632,6 @@ bool theory_arith::is_cross_nested_consistent(row const & r) { */ template bool theory_arith::is_cross_nested_consistent(svector const & nl_cluster) { - return true; for (theory_var v : nl_cluster) { if (!is_base(v)) continue; From 615aad77795d7aaa35c9afb335f3c26563923c8a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Sep 2023 15:18:37 -0700 Subject: [PATCH 32/69] get rid of int*, use lambda scoping Signed-off-by: Nikolaj Bjorner --- src/math/lp/bound_analyzer_on_row.h | 4 +- src/math/lp/implied_bound.h | 12 ++-- src/math/lp/lar_solver.h | 2 +- src/math/lp/lp_bound_propagator.h | 91 ++++++++++++++--------------- src/sat/smt/arith_solver.cpp | 2 +- 5 files changed, 55 insertions(+), 56 deletions(-) diff --git a/src/math/lp/bound_analyzer_on_row.h b/src/math/lp/bound_analyzer_on_row.h index 4bad3c0bc..074b6e464 100644 --- a/src/math/lp/bound_analyzer_on_row.h +++ b/src/math/lp/bound_analyzer_on_row.h @@ -284,7 +284,9 @@ private: void limit_j(unsigned bound_j, const mpq& u, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict){ unsigned row_index = this->m_row_index; - auto explain = [bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index](int * s) { return explain_bound_on_var_on_coeff((B*)s, bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index); }; + auto explain = [bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index,this]() { + return explain_bound_on_var_on_coeff((B*)&m_bp, bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index); + }; m_bp.add_bound(u, bound_j, is_lower_bound, strict, explain); } diff --git a/src/math/lp/implied_bound.h b/src/math/lp/implied_bound.h index 66b3453d2..195ec0359 100644 --- a/src/math/lp/implied_bound.h +++ b/src/math/lp/implied_bound.h @@ -31,13 +31,13 @@ class implied_bound { // by lar_solver::add_term() unsigned m_j; bool m_is_lower_bound; - bool m_strict; + bool m_strict; private: - std::function m_explain_bound = nullptr; + std::function m_explain_bound = nullptr; public: // s is expected to be the pointer to lp_bound_propagator. - u_dependency* explain_implied(int * s) const { return m_explain_bound(s); } - void set_explain(std::function f) { m_explain_bound = f; } + u_dependency* explain_implied() const { return m_explain_bound(); } + void set_explain(std::function f) { m_explain_bound = f; } lconstraint_kind kind() const { lconstraint_kind k = m_is_lower_bound? GE : LE; if (m_strict) @@ -48,8 +48,8 @@ class implied_bound { implied_bound(const mpq & a, unsigned j, bool is_lower_bound, - bool is_strict, - std::function get_dep): + bool is_strict, + std::function get_dep): m_bound(a), m_j(j), m_is_lower_bound(is_lower_bound), diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 9af24d567..9f878e363 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -311,7 +311,7 @@ class lar_solver : public column_namer { template void explain_implied_bound(const implied_bound& ib, lp_bound_propagator& bp) { - u_dependency* dep = ib.explain_implied((int*)&bp); + u_dependency* dep = ib.explain_implied(); for (auto ci : flatten(dep)) bp.consume(mpq(1), ci); // TODO: flatten should provide the coefficients /* diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index 8af04c793..e912d4f23 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -140,22 +140,24 @@ public: } void add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var) { - auto lambda = [zero_var](int* s) { - return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_column(zero_var); + auto& lps = lp(); + auto lambda = [zero_var,&lps]() { + return lps.get_bound_constraint_witnesses_for_column(zero_var); }; TRACE("add_bound", lp().print_column_info(zero_var, tout) << std::endl;); add_lower_bound_monic(monic_var, mpq(0), false, lambda); add_upper_bound_monic(monic_var, mpq(0), false, lambda); } - void add_lower_bound_monic(lpvar j, const mpq& v, bool is_strict, std::function explain_dep) { + void add_lower_bound_monic(lpvar j, const mpq& v, bool is_strict, std::function explain_dep) { TRACE("add_bound", lp().print_column_info(j, tout) << std::endl;); j = lp().column_to_reported_index(j); unsigned k; if (!m_improved_lower_bounds.find(j, k)) { m_improved_lower_bounds.insert(j,static_cast(m_ibounds.size())); m_ibounds.push_back(implied_bound(v, j, true, is_strict, explain_dep)); - } else { + } + else { auto& found_bound = m_ibounds[k]; if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && is_strict)) { found_bound = implied_bound(v, j, true, is_strict, explain_dep); @@ -164,13 +166,14 @@ public: } } - void add_upper_bound_monic(lpvar j, const mpq& bound_val, bool is_strict, std::function explain_bound) { + void add_upper_bound_monic(lpvar j, const mpq& bound_val, bool is_strict, std::function explain_bound) { j = lp().column_to_reported_index(j); unsigned k; if (!m_improved_upper_bounds.find(j, k)) { m_improved_upper_bounds.insert(j, static_cast(m_ibounds.size())); m_ibounds.push_back(implied_bound(bound_val, j, false, is_strict, explain_bound)); - } else { + } + else { auto& found_bound = m_ibounds[k]; if (bound_val > found_bound.m_bound || (bound_val == found_bound.m_bound && !found_bound.m_strict && is_strict)) { found_bound = implied_bound(bound_val, j, false, is_strict, explain_bound); @@ -204,18 +207,16 @@ public: void propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { lp::impq bound_value; bool is_strict; + auto& lps = lp(); if (lower_bound_is_available(non_fixed)) { bound_value = lp().column_lower_bound(non_fixed); is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, non_fixed](int* s) { - auto& l = ((lp_bound_propagator*)s)->lp(); - u_dependency* dep = l.get_column_lower_bound_witness(non_fixed); - for (auto v : vars) { - if (v != non_fixed) { - dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); - } - } + auto lambda = [vars, non_fixed,&lps]() { + u_dependency* dep = lps.get_column_lower_bound_witness(non_fixed); + for (auto v : vars) + if (v != non_fixed) + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); return dep; }; if (k.is_pos()) @@ -227,14 +228,11 @@ public: if (upper_bound_is_available(non_fixed)) { bound_value = lp().column_upper_bound(non_fixed); is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, non_fixed](int* s) { - auto& l = ((lp_bound_propagator*)s)->lp(); - u_dependency* dep = l.get_column_upper_bound_witness(non_fixed); - for (auto v : vars) { - if (v != non_fixed) { - dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); - } - } + auto lambda = [vars, non_fixed,&lps]() { + u_dependency* dep = lps.get_column_upper_bound_witness(non_fixed); + for (auto v : vars) + if (v != non_fixed) + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); return dep; }; if (k.is_neg()) @@ -244,33 +242,31 @@ public: } if (lower_bound_is_available(monic_var)) { - auto lambda = [vars, monic_var, non_fixed](int* s) { - auto& l = ((lp_bound_propagator*)s)->lp(); - u_dependency* dep = l.get_column_lower_bound_witness(monic_var); - for (auto v : vars) { - if (v != non_fixed) { - dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); - } - } - return dep; - }; - bound_value = lp().column_lower_bound(monic_var); - is_strict = !bound_value.y.is_zero(); - if (k.is_pos()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + auto lambda = [vars, monic_var, non_fixed,&lps]() { + u_dependency* dep = lps.get_column_lower_bound_witness(monic_var); + for (auto v : vars) { + if (v != non_fixed) { + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + } + } + return dep; + }; + bound_value = lp().column_lower_bound(monic_var); + is_strict = !bound_value.y.is_zero(); + if (k.is_pos()) + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + else + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); } - + if (upper_bound_is_available(monic_var)) { bound_value = lp().column_upper_bound(monic_var); is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, monic_var, non_fixed](int* s) { - auto& l = ((lp_bound_propagator*)s)->lp(); - u_dependency* dep = l.get_column_upper_bound_witness(monic_var); + auto lambda = [vars, monic_var, non_fixed,&lps]() { + u_dependency* dep = lps.get_column_upper_bound_witness(monic_var); for (auto v : vars) { if (v != non_fixed) { - dep = l.join_deps(dep, l.get_bound_constraint_witnesses_for_column(v)); + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); } } return dep; @@ -283,9 +279,10 @@ public: } void propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k) { - auto lambda = [vars](int* s) { return ((lp_bound_propagator*)s)->lp().get_bound_constraint_witnesses_for_columns(vars); }; - add_lower_bound_monic(monic_var, k, false, lambda); - add_upper_bound_monic(monic_var, k, false, lambda); + auto& lps = lp(); + auto lambda = [vars,&lps]() { return lps.get_bound_constraint_witnesses_for_columns(vars); }; + add_lower_bound_monic(monic_var, k, false, lambda); + add_upper_bound_monic(monic_var, k, false, lambda); } column_type get_column_type(unsigned j) const { @@ -313,7 +310,7 @@ public: return (*m_column_types)[j] == column_type::fixed && get_lower_bound(j).y.is_zero(); } - void add_bound(mpq const& v, unsigned j, bool is_low, bool strict, std::function explain_bound) { + void add_bound(mpq const& v, unsigned j, bool is_low, bool strict, std::function explain_bound) { j = lp().column_to_reported_index(j); lconstraint_kind kind = is_low ? GE : LE; diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 65329f9c4..fd55fb7d7 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -253,7 +253,7 @@ namespace arith { first = false; reset_evidence(); m_explanation.clear(); - be.explain_implied((int*)&m_bp); + be.explain_implied(); } CTRACE("arith", m_unassigned_bounds[v] == 0, tout << "missed bound\n";); updt_unassigned_bounds(v, -1); From f9de65a464265655557f7656a3a3f6c3c0e11d9d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 20 Sep 2023 15:22:28 -0700 Subject: [PATCH 33/69] indetation Signed-off-by: Nikolaj Bjorner --- src/math/lp/lp_bound_propagator.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index e912d4f23..f6cc83825 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -183,27 +183,27 @@ public: } void propagate_monic(lpvar monic_var, const svector& vars) { - lpvar non_fixed, zero_var; - if (!is_linear(vars, zero_var, non_fixed)) - return; - - if (zero_var != null_lpvar) + lpvar non_fixed, zero_var; + if (!is_linear(vars, zero_var, non_fixed)) + return; + + if (zero_var != null_lpvar) add_bounds_for_zero_var(monic_var, zero_var); - else { + else { rational k = rational(1); for (auto v : vars) if (v != non_fixed) { k *= lp().get_column_value(v).x; if (k.is_big()) return; } - + if (non_fixed != null_lpvar) propagate_monic_with_non_fixed(monic_var, vars, non_fixed, k); else // all variables are fixed propagate_monic_with_all_fixed(monic_var, vars, k); - } + } } - + void propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { lp::impq bound_value; bool is_strict; From 20c02f4f45c4d04545ff74780904e82ee5d8ae8f Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 20 Sep 2023 17:02:35 -0700 Subject: [PATCH 34/69] fix a lambda bug Signed-off-by: Lev Nachmanson --- src/math/lp/bound_analyzer_on_row.h | 48 ++++++++++++++--------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/math/lp/bound_analyzer_on_row.h b/src/math/lp/bound_analyzer_on_row.h index 074b6e464..576f14599 100644 --- a/src/math/lp/bound_analyzer_on_row.h +++ b/src/math/lp/bound_analyzer_on_row.h @@ -281,15 +281,32 @@ private: // */ // } - - void limit_j(unsigned bound_j, const mpq& u, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict){ + void limit_j(unsigned bound_j, const mpq& u, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict) + { unsigned row_index = this->m_row_index; - auto explain = [bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index,this]() { - return explain_bound_on_var_on_coeff((B*)&m_bp, bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index); + auto* lar = &m_bp.lp(); + auto explain = [bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index, lar]() { + TRACE("bound_analyzer", tout << "explain_bound_on_var_on_coeff, bound_j = " << bound_j << ", coeff_before_j_is_pos = " << coeff_before_j_is_pos << ", is_lower_bound = " << is_lower_bound << ", strict = " << strict << ", row_index = " << row_index << "\n";); + int bound_sign = (is_lower_bound ? 1 : -1); + int j_sign = (coeff_before_j_is_pos ? 1 : -1) * bound_sign; + + SASSERT(!tv::is_term(bound_j)); + u_dependency* ret = nullptr; + for (auto const& r : lar->get_row(row_index)) { + unsigned j = r.var(); + if (j == bound_j) + continue; + mpq const& a = r.coeff(); + int a_sign = is_pos(a) ? 1 : -1; + int sign = j_sign * a_sign; + u_dependency* witness = sign > 0 ? lar->get_column_upper_bound_witness(j) : lar->get_column_lower_bound_witness(j); + ret = lar->join_deps(ret, witness); + } + return ret; }; m_bp.add_bound(u, bound_j, is_lower_bound, strict, explain); } - + void advance_u(unsigned j) { m_column_of_u = (m_column_of_u == -1) ? j : -2; } @@ -320,26 +337,7 @@ private: break; } } - static u_dependency* explain_bound_on_var_on_coeff(B* bp, unsigned bound_j, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict, unsigned row_index) { - TRACE("bound_analyzer", tout << "explain_bound_on_var_on_coeff, bound_j = " << bound_j << ", coeff_before_j_is_pos = " << coeff_before_j_is_pos << ", is_lower_bound = " << is_lower_bound << ", strict = " << strict << ", row_index = " << row_index << "\n";); - auto& lar = bp->lp(); - int bound_sign = (is_lower_bound ? 1 : -1); - int j_sign = (coeff_before_j_is_pos ? 1 : -1) * bound_sign; - - SASSERT(!tv::is_term(bound_j)); - u_dependency* ret = nullptr; - for (auto const& r : lar.get_row(row_index)) { - unsigned j = r.var(); - if (j == bound_j) - continue; - mpq const& a = r.coeff(); - int a_sign = is_pos(a) ? 1 : -1; - int sign = j_sign * a_sign; - u_dependency* witness = sign > 0 ? lar.get_column_upper_bound_witness(j) : lar.get_column_lower_bound_witness(j); - ret = lar.join_deps(ret, witness); - } - return ret; - } + }; From 536930b4a160cf5e1f7260016629f0a17adc8459 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 20 Sep 2023 17:13:25 -0700 Subject: [PATCH 35/69] make m_ibounds inside of lp_bound_propagator a reference --- src/math/lp/lp_bound_propagator.h | 4 ++-- src/sat/smt/arith_solver.cpp | 2 +- src/sat/smt/arith_solver.h | 1 + src/smt/theory_lra.cpp | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index f6cc83825..99755f606 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -20,7 +20,7 @@ class lp_bound_propagator { u_map m_improved_upper_bounds; T& m_imp; - std_vector m_ibounds; + std_vector& m_ibounds; map, default_eq> m_val2fixed_row; // works for rows of the form x + y + sum of fixed = 0 @@ -109,7 +109,7 @@ private: }; public: - lp_bound_propagator(T& imp) : m_imp(imp) {} + lp_bound_propagator(T& imp, std_vector & ibounds) : m_imp(imp), m_ibounds(ibounds) {} const std_vector& ibounds() const { return m_ibounds; } diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index fd55fb7d7..3cf991c20 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -26,7 +26,7 @@ namespace arith { m_model_eqs(DEFAULT_HASHTABLE_INITIAL_CAPACITY, var_value_hash(*this), var_value_eq(*this)), m_local_search(*this), m_resource_limit(*this), - m_bp(*this), + m_bp(*this, m_implied_bounds), a(m), m_bound_terms(m), m_bound_predicate(m) diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index e23162393..8917a3e42 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -243,6 +243,7 @@ namespace arith { resource_limit m_resource_limit; lp_bounds m_new_bounds; symbol m_farkas; + std_vector m_implied_bounds; lp::lp_bound_propagator m_bp; mutable vector> m_todo_terms; diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 9357b7a65..aeb138d3c 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -225,6 +225,7 @@ class theory_lra::imp { lp_bounds m_new_bounds; symbol m_farkas; vector m_bound_params; + std_vector m_implied_bounds; lp::lp_bound_propagator m_bp; context& ctx() const { return th.get_context(); } @@ -873,7 +874,7 @@ public: m_solver(nullptr), m_resource_limit(*this), m_farkas("farkas"), - m_bp(*this), + m_bp(*this, m_implied_bounds), m_bounded_range_idx(0), m_bounded_range_lit(null_literal), m_bound_terms(m), From e31cecf5dbe7b6d0542434451e8ed64497bd3075 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 21 Sep 2023 11:27:53 -0700 Subject: [PATCH 36/69] transfer propagate monomial bounds to nla_solver --- src/math/lp/lp_bound_propagator.h | 165 ----------------------- src/math/lp/nla_core.cpp | 213 +++++++++++++++++++++++++++++- src/math/lp/nla_core.h | 22 ++- src/math/lp/nla_solver.cpp | 11 +- src/math/lp/nla_solver.h | 4 +- src/sat/smt/arith_internalize.cpp | 2 +- src/smt/theory_lra.cpp | 9 +- 7 files changed, 243 insertions(+), 183 deletions(-) diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index 99755f606..7ed872aa2 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -120,171 +120,6 @@ public: m_column_types = &lp().get_column_types(); } - bool is_linear(const svector& m, lpvar& zero_var, lpvar& non_fixed) { - zero_var = non_fixed = null_lpvar; - unsigned n_of_non_fixed = 0; - for (lpvar v : m) { - if (!this->column_is_fixed(v)) { - n_of_non_fixed++; - non_fixed = v; - continue; - } - const auto & b = get_lower_bound(v).x; - if (b.is_zero()) { - zero_var = v; - return true; - } - - } - return n_of_non_fixed <= 1; - } - - void add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var) { - auto& lps = lp(); - auto lambda = [zero_var,&lps]() { - return lps.get_bound_constraint_witnesses_for_column(zero_var); - }; - TRACE("add_bound", lp().print_column_info(zero_var, tout) << std::endl;); - add_lower_bound_monic(monic_var, mpq(0), false, lambda); - add_upper_bound_monic(monic_var, mpq(0), false, lambda); - } - - void add_lower_bound_monic(lpvar j, const mpq& v, bool is_strict, std::function explain_dep) { - TRACE("add_bound", lp().print_column_info(j, tout) << std::endl;); - j = lp().column_to_reported_index(j); - unsigned k; - if (!m_improved_lower_bounds.find(j, k)) { - m_improved_lower_bounds.insert(j,static_cast(m_ibounds.size())); - m_ibounds.push_back(implied_bound(v, j, true, is_strict, explain_dep)); - } - else { - auto& found_bound = m_ibounds[k]; - if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && is_strict)) { - found_bound = implied_bound(v, j, true, is_strict, explain_dep); - TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); - } - } - } - - void add_upper_bound_monic(lpvar j, const mpq& bound_val, bool is_strict, std::function explain_bound) { - j = lp().column_to_reported_index(j); - unsigned k; - if (!m_improved_upper_bounds.find(j, k)) { - m_improved_upper_bounds.insert(j, static_cast(m_ibounds.size())); - m_ibounds.push_back(implied_bound(bound_val, j, false, is_strict, explain_bound)); - } - else { - auto& found_bound = m_ibounds[k]; - if (bound_val > found_bound.m_bound || (bound_val == found_bound.m_bound && !found_bound.m_strict && is_strict)) { - found_bound = implied_bound(bound_val, j, false, is_strict, explain_bound); - TRACE("add_bound", lp().print_implied_bound(found_bound, tout);); - } - } - } - - void propagate_monic(lpvar monic_var, const svector& vars) { - lpvar non_fixed, zero_var; - if (!is_linear(vars, zero_var, non_fixed)) - return; - - if (zero_var != null_lpvar) - add_bounds_for_zero_var(monic_var, zero_var); - else { - rational k = rational(1); - for (auto v : vars) - if (v != non_fixed) { - k *= lp().get_column_value(v).x; - if (k.is_big()) return; - } - - if (non_fixed != null_lpvar) - propagate_monic_with_non_fixed(monic_var, vars, non_fixed, k); - else // all variables are fixed - propagate_monic_with_all_fixed(monic_var, vars, k); - } - } - - void propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { - lp::impq bound_value; - bool is_strict; - auto& lps = lp(); - - if (lower_bound_is_available(non_fixed)) { - bound_value = lp().column_lower_bound(non_fixed); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, non_fixed,&lps]() { - u_dependency* dep = lps.get_column_lower_bound_witness(non_fixed); - for (auto v : vars) - if (v != non_fixed) - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); - return dep; - }; - if (k.is_pos()) - add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - else - add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - } - - if (upper_bound_is_available(non_fixed)) { - bound_value = lp().column_upper_bound(non_fixed); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, non_fixed,&lps]() { - u_dependency* dep = lps.get_column_upper_bound_witness(non_fixed); - for (auto v : vars) - if (v != non_fixed) - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); - return dep; - }; - if (k.is_neg()) - add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - else - add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - } - - if (lower_bound_is_available(monic_var)) { - auto lambda = [vars, monic_var, non_fixed,&lps]() { - u_dependency* dep = lps.get_column_lower_bound_witness(monic_var); - for (auto v : vars) { - if (v != non_fixed) { - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); - } - } - return dep; - }; - bound_value = lp().column_lower_bound(monic_var); - is_strict = !bound_value.y.is_zero(); - if (k.is_pos()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - } - - if (upper_bound_is_available(monic_var)) { - bound_value = lp().column_upper_bound(monic_var); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, monic_var, non_fixed,&lps]() { - u_dependency* dep = lps.get_column_upper_bound_witness(monic_var); - for (auto v : vars) { - if (v != non_fixed) { - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); - } - } - return dep; - }; - if (k.is_neg()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - } - } - - void propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k) { - auto& lps = lp(); - auto lambda = [vars,&lps]() { return lps.get_bound_constraint_witnesses_for_columns(vars); }; - add_lower_bound_monic(monic_var, k, false, lambda); - add_upper_bound_monic(monic_var, k, false, lambda); - } - column_type get_column_type(unsigned j) const { return (*m_column_types)[j]; } diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 63dd29d9b..4e16793ec 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -17,11 +17,12 @@ Author: #include "math/grobner/pdd_solver.h" #include "math/dd/pdd_interval.h" #include "math/dd/pdd_eval.h" +#include "nla_core.h" namespace nla { typedef lp::lar_term term; -core::core(lp::lar_solver& s, params_ref const& p, reslimit& lim) : m_evars(), +core::core(lp::lar_solver& s, params_ref const& p, reslimit& lim, std_vector& implied_bounds) : m_evars(), lra(s), m_reslim(lim), m_params(p), @@ -37,7 +38,8 @@ core::core(lp::lar_solver& s, params_ref const& p, reslimit& lim) : m_evars(), m_grobner(this), m_emons(m_evars), m_use_nra_model(false), - m_nra(s, m_nra_lim, *this) { + m_nra(s, m_nra_lim, *this), + m_implied_bounds(implied_bounds) { m_nlsat_delay = lp_settings().nlsat_delay(); lra.m_find_monics_with_changed_bounds_func = [&](const indexed_uint_set& columns_with_changed_bounds) { for (const auto& m : m_emons) { @@ -1837,5 +1839,210 @@ bool core::improve_bounds() { return bounds_improved; } -} // end of nla +bool core::is_linear(const svector& m, lpvar& zero_var, lpvar& non_fixed) +{ + zero_var = non_fixed = null_lpvar; + unsigned n_of_non_fixed = 0; + for (lpvar v : m) { + if (!this->var_is_fixed(v)) { + n_of_non_fixed++; + non_fixed = v; + continue; + } + const auto& b = get_lower_bound(v); + if (b.is_zero()) { + zero_var = v; + return true; + } + } + return n_of_non_fixed <= 1; +} + +void core::add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std::function explain_dep) +{ + TRACE("add_bound", lra.print_column_info(j, tout) << std::endl;); + j = lra.column_to_reported_index(j); + unsigned k; + if (!m_improved_lower_bounds.find(j, k)) { + m_improved_lower_bounds.insert(j, static_cast(m_implied_bounds.size())); + m_implied_bounds.push_back(lp::implied_bound(v, j, true, is_strict, explain_dep)); + } + else { + auto& found_bound = m_implied_bounds[k]; + if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && is_strict)) { + found_bound = lp::implied_bound(v, j, true, is_strict, explain_dep); + TRACE("add_bound", lra.print_implied_bound(found_bound, tout);); + } + } +} + +void core::add_upper_bound_monic(lpvar j, const lp::mpq& bound_val, bool is_strict, std::function explain_dep) +{ + j = lra.column_to_reported_index(j); + unsigned k; + if (!m_improved_upper_bounds.find(j, k)) { + m_improved_upper_bounds.insert(j, static_cast(m_implied_bounds.size())); + m_implied_bounds.push_back(lp::implied_bound(bound_val, j, false, is_strict, explain_dep)); + } + else { + auto& found_bound = m_implied_bounds[k]; + if (bound_val > found_bound.m_bound || (bound_val == found_bound.m_bound && !found_bound.m_strict && is_strict)) { + found_bound = lp::implied_bound(bound_val, j, false, is_strict, explain_dep); + TRACE("add_bound", lra.print_implied_bound(found_bound, tout);); + } + } +} + +bool core::upper_bound_is_available(unsigned j) const +{ + switch (get_column_type(j)) { + case lp::column_type::fixed: + case lp::column_type::boxed: + case lp::column_type::upper_bound: + return true; + default: + return false; + } +} + +bool core::lower_bound_is_available(unsigned j) const +{ + switch (get_column_type(j)) { + case lp::column_type::fixed: + case lp::column_type::boxed: + case lp::column_type::lower_bound: + return true; + default: + return false; + } +} + +void core::propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) +{ + lp::impq bound_value; + bool is_strict; + auto& lps = lra; + + if (lower_bound_is_available(non_fixed)) { + bound_value = lra.column_lower_bound(non_fixed); + is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, non_fixed, &lps]() { + u_dependency* dep = lps.get_column_lower_bound_witness(non_fixed); + for (auto v : vars) + if (v != non_fixed) + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + return dep; + }; + if (k.is_pos()) + add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + else + add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + } + + if (upper_bound_is_available(non_fixed)) { + bound_value = lra.column_upper_bound(non_fixed); + is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, non_fixed, &lps]() { + u_dependency* dep = lps.get_column_upper_bound_witness(non_fixed); + for (auto v : vars) + if (v != non_fixed) + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + return dep; + }; + if (k.is_neg()) + add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + else + add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + } + + if (lower_bound_is_available(monic_var)) { + auto lambda = [vars, monic_var, non_fixed, &lps]() { + u_dependency* dep = lps.get_column_lower_bound_witness(monic_var); + for (auto v : vars) { + if (v != non_fixed) { + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + } + } + return dep; + }; + bound_value = lra.column_lower_bound(monic_var); + is_strict = !bound_value.y.is_zero(); + if (k.is_pos()) + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + else + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + } + + if (upper_bound_is_available(monic_var)) { + bound_value = lra.column_upper_bound(monic_var); + is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, monic_var, non_fixed, &lps]() { + u_dependency* dep = lps.get_column_upper_bound_witness(monic_var); + for (auto v : vars) { + if (v != non_fixed) { + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + } + } + return dep; + }; + if (k.is_neg()) + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + else + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + } +} + +void core::propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k) +{ + auto* lps = &lra; + auto lambda = [vars, lps]() { return lps->get_bound_constraint_witnesses_for_columns(vars); }; + add_lower_bound_monic(monic_var, k, false, lambda); + add_upper_bound_monic(monic_var, k, false, lambda); +} + +void core::add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var) +{ + auto* lps = &lra; + auto lambda = [zero_var, lps]() { + return lps->get_bound_constraint_witnesses_for_column(zero_var); + }; + TRACE("add_bound", lra.print_column_info(zero_var, tout) << std::endl;); + add_lower_bound_monic(monic_var, lp::mpq(0), false, lambda); + add_upper_bound_monic(monic_var, lp::mpq(0), false, lambda); +} + +void core::calculate_implied_bounds_for_monic(lp::lpvar monic_var) +{ + lpvar non_fixed, zero_var; + const auto& vars = m_emons[monic_var].vars(); + if (!is_linear(vars, zero_var, non_fixed)) + return; + + if (zero_var != null_lpvar) + add_bounds_for_zero_var(monic_var, zero_var); + else { + rational k = rational(1); + for (auto v : vars) + if (v != non_fixed) { + k *= val(v); + if (k.is_big()) return; + } + + if (non_fixed != null_lpvar) + propagate_monic_with_non_fixed(monic_var, vars, non_fixed, k); + else // all variables are fixed + propagate_monic_with_all_fixed(monic_var, vars, k); + } +} + +void core::init_bound_propagation() +{ + this->m_implied_bounds.clear(); + this->m_improved_lower_bounds.reset(); + this->m_improved_upper_bounds.reset(); + this->m_column_types = &lra.get_column_types(); +} + +} // namespace nla + diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index 3b888f8ef..54c7e1df1 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -103,7 +103,10 @@ class core { emonics m_emons; svector m_add_buffer; mutable indexed_uint_set m_active_var_set; - + // these maps map a column index to the corresponding index in ibounds + u_map m_improved_lower_bounds; + u_map m_improved_upper_bounds; + const vector* m_column_types; reslimit m_nra_lim; bool m_use_nra_model = false; @@ -114,12 +117,13 @@ class core { void check_weighted(unsigned sz, std::pair>* checks); void add_bounds(); + std_vector & m_implied_bounds; // try to improve bounds for variables in monomials. bool improve_bounds(); public: // constructor - core(lp::lar_solver& s, params_ref const& p, reslimit&); + core(lp::lar_solver& s, params_ref const& p, reslimit&, std_vector & implied_bounds); const auto& monics_with_changed_bounds() const { return m_monics_with_changed_bounds; } void reset_monics_with_changed_bounds() { m_monics_with_changed_bounds.reset(); } void insert_to_refine(lpvar j); @@ -431,15 +435,23 @@ public: void set_use_nra_model(bool m); bool use_nra_model() const { return m_use_nra_model; } void collect_statistics(::statistics&); + bool is_linear(const svector& m, lpvar& zero_var, lpvar& non_fixed); + void add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var); + void propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k); + void propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k); + void add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std::function explain_dep); + void add_upper_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std::function explain_dep); + bool upper_bound_is_available(unsigned j) const; + bool lower_bound_is_available(unsigned j) const; private: - void restore_patched_values(); + lp::column_type get_column_type(unsigned j) const { return (*m_column_types)[j]; } void constrain_nl_in_tableau(); bool solve_tableau(); void restore_tableau(); void save_tableau(); bool integrality_holds(); - - + void calculate_implied_bounds_for_monic(lp::lpvar v); + void init_bound_propagation(); }; // end of core struct pp_mon { diff --git a/src/math/lp/nla_solver.cpp b/src/math/lp/nla_solver.cpp index 8be918f01..3475a3509 100644 --- a/src/math/lp/nla_solver.cpp +++ b/src/math/lp/nla_solver.cpp @@ -54,8 +54,8 @@ namespace nla { m_core->pop(n); } - solver::solver(lp::lar_solver& s, params_ref const& p, reslimit& limit): - m_core(alloc(core, s, p, limit)) { + solver::solver(lp::lar_solver& s, params_ref const& p, reslimit& limit, std_vector & implied_bounds): + m_core(alloc(core, s, p, limit, implied_bounds)) { } bool solver::influences_nl_var(lpvar j) const { @@ -88,6 +88,9 @@ namespace nla { m_core->collect_statistics(st); } + void solver::calculate_implied_bounds_for_monic(lp::lpvar v) { + m_core->calculate_implied_bounds_for_monic(v); + } // ensure r = x^y, add abstraction/refinement lemmas lbool solver::check_power(lpvar r, lpvar x, lpvar y, vector& lemmas) { return m_core->check_power(r, x, y, lemmas); @@ -97,4 +100,8 @@ namespace nla { m_core->check_bounded_divisions(lemmas); } + void solver::init_bound_propagation() { + m_core->init_bound_propagation(); + } + } diff --git a/src/math/lp/nla_solver.h b/src/math/lp/nla_solver.h index 07bf095a6..a4de90320 100644 --- a/src/math/lp/nla_solver.h +++ b/src/math/lp/nla_solver.h @@ -24,7 +24,7 @@ namespace nla { core* m_core; public: - solver(lp::lar_solver& s, params_ref const& p, reslimit& limit); + solver(lp::lar_solver& s, params_ref const& p, reslimit& limit, std_vector & implied_bounds); ~solver(); const auto& monics_with_changed_bounds() const { return m_core->monics_with_changed_bounds(); } void reset_monics_with_changed_bounds() { m_core->reset_monics_with_changed_bounds(); } @@ -48,5 +48,7 @@ namespace nla { nlsat::anum_manager& am(); nlsat::anum const& am_value(lp::var_index v) const; void collect_statistics(::statistics & st); + void calculate_implied_bounds_for_monic(lp::lpvar v); + void init_bound_propagation(); }; } diff --git a/src/sat/smt/arith_internalize.cpp b/src/sat/smt/arith_internalize.cpp index 3174ad775..5893c8520 100644 --- a/src/sat/smt/arith_internalize.cpp +++ b/src/sat/smt/arith_internalize.cpp @@ -61,7 +61,7 @@ namespace arith { void solver::ensure_nla() { if (!m_nla) { - m_nla = alloc(nla::solver, *m_solver.get(), s().params(), m.limit()); + m_nla = alloc(nla::solver, *m_solver.get(), s().params(), m.limit(), m_implied_bounds); for (auto const& _s : m_scopes) { (void)_s; m_nla->push(); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index aeb138d3c..ef7ab7091 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -264,7 +264,7 @@ class theory_lra::imp { void ensure_nla() { if (!m_nla) { - m_nla = alloc(nla::solver, *m_solver.get(), ctx().get_params(), m.limit()); + m_nla = alloc(nla::solver, *m_solver.get(), ctx().get_params(), m.limit(), m_implied_bounds); for (auto const& _s : m_scopes) { (void)_s; m_nla->push(); @@ -2198,13 +2198,10 @@ public: finish_bound_propagation(); } - void calculate_implied_bounds_for_monic(lpvar monic_var, const svector& vars) { - m_bp.propagate_monic(monic_var, vars); - } - void propagate_bounds_for_touched_monomials() { + m_nla->init_bound_propagation(); for (unsigned v : m_nla->monics_with_changed_bounds()) { - calculate_implied_bounds_for_monic(v, m_nla->get_core().emons()[v].vars()); + m_nla->calculate_implied_bounds_for_monic(v); } m_nla->reset_monics_with_changed_bounds(); } From f423642e9b609eb4206519ef95cff4abff3910b1 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 21 Sep 2023 12:18:21 -0700 Subject: [PATCH 37/69] try the lemma scheme --- src/math/lp/nla_core.cpp | 182 +++++++++++++------------------------ src/math/lp/nla_core.h | 2 +- src/math/lp/nla_solver.cpp | 4 +- src/math/lp/nla_solver.h | 2 +- src/smt/theory_lra.cpp | 5 +- 5 files changed, 72 insertions(+), 123 deletions(-) diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 4e16793ec..514b2ad61 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -1844,7 +1844,7 @@ bool core::is_linear(const svector& m, lpvar& zero_var, lpvar& non_fixed) zero_var = non_fixed = null_lpvar; unsigned n_of_non_fixed = 0; for (lpvar v : m) { - if (!this->var_is_fixed(v)) { + if (!var_is_fixed(v)) { n_of_non_fixed++; non_fixed = v; continue; @@ -1920,129 +1920,75 @@ bool core::lower_bound_is_available(unsigned j) const void core::propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { lp::impq bound_value; - bool is_strict; - auto& lps = lra; + new_lemma lemma(*this, "propagate monic with non fixed"); + // using += to not assert thath the inequality does not hold + lemma += ineq(term(rational(1), monic_var, -k, non_fixed), llc::EQ, 0); + lp::explanation exp; + for (auto v : m_emons[monic_var].vars()) { + if (v == non_fixed) continue; + u_dependency* dep = lra.get_column_lower_bound_witness(v); + for (auto ci : lra.flatten(dep)) { + exp.push_back(ci); + } + dep = lra.get_column_upper_bound_witness(v); + for (auto ci : lra.flatten(dep)) { + exp.push_back(ci); + } + } + lemma &= exp; +} - if (lower_bound_is_available(non_fixed)) { - bound_value = lra.column_lower_bound(non_fixed); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, non_fixed, &lps]() { - u_dependency* dep = lps.get_column_lower_bound_witness(non_fixed); + void core::propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k) + { + auto* lps = &lra; + auto lambda = [vars, lps]() { return lps->get_bound_constraint_witnesses_for_columns(vars); }; + add_lower_bound_monic(monic_var, k, false, lambda); + add_upper_bound_monic(monic_var, k, false, lambda); + } + + void core::add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var) + { + auto* lps = &lra; + auto lambda = [zero_var, lps]() { + return lps->get_bound_constraint_witnesses_for_column(zero_var); + }; + TRACE("add_bound", lra.print_column_info(zero_var, tout) << std::endl;); + add_lower_bound_monic(monic_var, lp::mpq(0), false, lambda); + add_upper_bound_monic(monic_var, lp::mpq(0), false, lambda); + } + + void core::calculate_implied_bounds_for_monic(lp::lpvar monic_var) + { + lpvar non_fixed, zero_var; + const auto& vars = m_emons[monic_var].vars(); + if (!is_linear(vars, zero_var, non_fixed)) + return; + + if (zero_var != null_lpvar) + add_bounds_for_zero_var(monic_var, zero_var); + else { + rational k = rational(1); for (auto v : vars) - if (v != non_fixed) - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); - return dep; - }; - if (k.is_pos()) - add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - else - add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - } - - if (upper_bound_is_available(non_fixed)) { - bound_value = lra.column_upper_bound(non_fixed); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, non_fixed, &lps]() { - u_dependency* dep = lps.get_column_upper_bound_witness(non_fixed); - for (auto v : vars) - if (v != non_fixed) - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); - return dep; - }; - if (k.is_neg()) - add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - else - add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - } - - if (lower_bound_is_available(monic_var)) { - auto lambda = [vars, monic_var, non_fixed, &lps]() { - u_dependency* dep = lps.get_column_lower_bound_witness(monic_var); - for (auto v : vars) { if (v != non_fixed) { - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + k *= val(v); + if (k.is_big()) return; } - } - return dep; - }; - bound_value = lra.column_lower_bound(monic_var); - is_strict = !bound_value.y.is_zero(); - if (k.is_pos()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + + if (non_fixed != null_lpvar) + propagate_monic_with_non_fixed(monic_var, vars, non_fixed, k); + else // all variables are fixed + propagate_monic_with_all_fixed(monic_var, vars, k); + } } - if (upper_bound_is_available(monic_var)) { - bound_value = lra.column_upper_bound(monic_var); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, monic_var, non_fixed, &lps]() { - u_dependency* dep = lps.get_column_upper_bound_witness(monic_var); - for (auto v : vars) { - if (v != non_fixed) { - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); - } - } - return dep; - }; - if (k.is_neg()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + void core::init_bound_propagation(vector & l_vec) + { + m_implied_bounds.clear(); + m_improved_lower_bounds.reset(); + m_improved_upper_bounds.reset(); + m_column_types = &lra.get_column_types(); + m_lemma_vec = &l_vec; + m_lemma_vec->clear(); } -} - -void core::propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k) -{ - auto* lps = &lra; - auto lambda = [vars, lps]() { return lps->get_bound_constraint_witnesses_for_columns(vars); }; - add_lower_bound_monic(monic_var, k, false, lambda); - add_upper_bound_monic(monic_var, k, false, lambda); -} - -void core::add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var) -{ - auto* lps = &lra; - auto lambda = [zero_var, lps]() { - return lps->get_bound_constraint_witnesses_for_column(zero_var); - }; - TRACE("add_bound", lra.print_column_info(zero_var, tout) << std::endl;); - add_lower_bound_monic(monic_var, lp::mpq(0), false, lambda); - add_upper_bound_monic(monic_var, lp::mpq(0), false, lambda); -} - -void core::calculate_implied_bounds_for_monic(lp::lpvar monic_var) -{ - lpvar non_fixed, zero_var; - const auto& vars = m_emons[monic_var].vars(); - if (!is_linear(vars, zero_var, non_fixed)) - return; - - if (zero_var != null_lpvar) - add_bounds_for_zero_var(monic_var, zero_var); - else { - rational k = rational(1); - for (auto v : vars) - if (v != non_fixed) { - k *= val(v); - if (k.is_big()) return; - } - - if (non_fixed != null_lpvar) - propagate_monic_with_non_fixed(monic_var, vars, non_fixed, k); - else // all variables are fixed - propagate_monic_with_all_fixed(monic_var, vars, k); - } -} - -void core::init_bound_propagation() -{ - this->m_implied_bounds.clear(); - this->m_improved_lower_bounds.reset(); - this->m_improved_upper_bounds.reset(); - this->m_column_types = &lra.get_column_types(); -} } // namespace nla - - diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index 54c7e1df1..456709771 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -451,7 +451,7 @@ private: void save_tableau(); bool integrality_holds(); void calculate_implied_bounds_for_monic(lp::lpvar v); - void init_bound_propagation(); + void init_bound_propagation(vector&); }; // end of core struct pp_mon { diff --git a/src/math/lp/nla_solver.cpp b/src/math/lp/nla_solver.cpp index 3475a3509..08c1e1e62 100644 --- a/src/math/lp/nla_solver.cpp +++ b/src/math/lp/nla_solver.cpp @@ -100,8 +100,8 @@ namespace nla { m_core->check_bounded_divisions(lemmas); } - void solver::init_bound_propagation() { - m_core->init_bound_propagation(); + void solver::init_bound_propagation(vector& lemmas) { + m_core->init_bound_propagation(lemmas); } } diff --git a/src/math/lp/nla_solver.h b/src/math/lp/nla_solver.h index a4de90320..fa206ea40 100644 --- a/src/math/lp/nla_solver.h +++ b/src/math/lp/nla_solver.h @@ -49,6 +49,6 @@ namespace nla { nlsat::anum const& am_value(lp::var_index v) const; void collect_statistics(::statistics & st); void calculate_implied_bounds_for_monic(lp::lpvar v); - void init_bound_propagation(); + void init_bound_propagation(vector&); }; } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index ef7ab7091..ea1dcd9b9 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2199,11 +2199,14 @@ public: } void propagate_bounds_for_touched_monomials() { - m_nla->init_bound_propagation(); + m_nla->init_bound_propagation(m_nla_lemma_vector); for (unsigned v : m_nla->monics_with_changed_bounds()) { m_nla->calculate_implied_bounds_for_monic(v); } m_nla->reset_monics_with_changed_bounds(); + for (const auto & l:m_nla_lemma_vector) { + false_case_of_check_nla(l); + } } void propagate_bounds_with_nlp() { From c0b55d14352fa76f3a2eabf346a8d20fb93b4e9e Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 21 Sep 2023 15:53:53 -0700 Subject: [PATCH 38/69] reject rows with columns with big numbers for lp bound propagation Signed-off-by: Lev Nachmanson --- src/math/lp/lar_solver.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 08ff3b0d4..dc114e9e0 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -135,9 +135,15 @@ namespace lp { bool lar_solver::row_has_a_big_num(unsigned i) const { - for (const auto& c : A_r().m_rows[i]) + for (const auto& c : A_r().m_rows[i]) { if (c.coeff().is_big()) return true; + if (column_has_lower_bound(c.var())&& get_lower_bound(c.var()).x.is_big()) + return true; + if (column_has_upper_bound(c.var())&& get_upper_bound(c.var()).x.is_big()) + return true; + } + return false; } From 576309a16fe8e6d30dd19bebaeaa1bc0b4856b6a Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 21 Sep 2023 16:30:43 -0700 Subject: [PATCH 39/69] Revert "reject rows with columns with big numbers for lp bound propagation" This reverts commit c0b55d14352fa76f3a2eabf346a8d20fb93b4e9e. --- src/math/lp/lar_solver.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index dc114e9e0..08ff3b0d4 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -135,15 +135,9 @@ namespace lp { bool lar_solver::row_has_a_big_num(unsigned i) const { - for (const auto& c : A_r().m_rows[i]) { + for (const auto& c : A_r().m_rows[i]) if (c.coeff().is_big()) return true; - if (column_has_lower_bound(c.var())&& get_lower_bound(c.var()).x.is_big()) - return true; - if (column_has_upper_bound(c.var())&& get_upper_bound(c.var()).x.is_big()) - return true; - } - return false; } From caa929f01f4ba66f5fcacd4e83c5fe7c7bfe363f Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 22 Sep 2023 14:27:26 -0700 Subject: [PATCH 40/69] do not use lemmase in monomial propagation --- src/math/lp/nla_core.cpp | 88 ++++++++++++++++++++++++++++++-------- src/math/lp/nla_core.h | 2 +- src/math/lp/nla_solver.cpp | 4 +- src/math/lp/nla_solver.h | 2 +- src/smt/theory_lra.cpp | 5 +-- 5 files changed, 75 insertions(+), 26 deletions(-) diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 514b2ad61..916b80f6c 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -1920,22 +1920,76 @@ bool core::lower_bound_is_available(unsigned j) const void core::propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { lp::impq bound_value; - new_lemma lemma(*this, "propagate monic with non fixed"); - // using += to not assert thath the inequality does not hold - lemma += ineq(term(rational(1), monic_var, -k, non_fixed), llc::EQ, 0); - lp::explanation exp; - for (auto v : m_emons[monic_var].vars()) { - if (v == non_fixed) continue; - u_dependency* dep = lra.get_column_lower_bound_witness(v); - for (auto ci : lra.flatten(dep)) { - exp.push_back(ci); - } - dep = lra.get_column_upper_bound_witness(v); - for (auto ci : lra.flatten(dep)) { - exp.push_back(ci); - } + bool is_strict; + auto& lps = lra; + + if (lower_bound_is_available(non_fixed)) { + bound_value = lra.column_lower_bound(non_fixed); + is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, non_fixed, &lps]() { + u_dependency* dep = lps.get_column_lower_bound_witness(non_fixed); + for (auto v : vars) + if (v != non_fixed) + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + return dep; + }; + if (k.is_pos()) + add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + else + add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + } + + if (upper_bound_is_available(non_fixed)) { + bound_value = lra.column_upper_bound(non_fixed); + is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, non_fixed, &lps]() { + u_dependency* dep = lps.get_column_upper_bound_witness(non_fixed); + for (auto v : vars) + if (v != non_fixed) + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + return dep; + }; + if (k.is_neg()) + add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + else + add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + } + + if (lower_bound_is_available(monic_var)) { + auto lambda = [vars, monic_var, non_fixed, &lps]() { + u_dependency* dep = lps.get_column_lower_bound_witness(monic_var); + for (auto v : vars) { + if (v != non_fixed) { + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + } + } + return dep; + }; + bound_value = lra.column_lower_bound(monic_var); + is_strict = !bound_value.y.is_zero(); + if (k.is_pos()) + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + else + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + } + + if (upper_bound_is_available(monic_var)) { + bound_value = lra.column_upper_bound(monic_var); + is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, monic_var, non_fixed, &lps]() { + u_dependency* dep = lps.get_column_upper_bound_witness(monic_var); + for (auto v : vars) { + if (v != non_fixed) { + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + } + } + return dep; + }; + if (k.is_neg()) + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + else + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); } - lemma &= exp; } void core::propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k) @@ -1981,14 +2035,12 @@ void core::propagate_monic_with_non_fixed(lpvar monic_var, const svector& } } - void core::init_bound_propagation(vector & l_vec) + void core::init_bound_propagation() { m_implied_bounds.clear(); m_improved_lower_bounds.reset(); m_improved_upper_bounds.reset(); m_column_types = &lra.get_column_types(); - m_lemma_vec = &l_vec; - m_lemma_vec->clear(); } } // namespace nla diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index 456709771..54c7e1df1 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -451,7 +451,7 @@ private: void save_tableau(); bool integrality_holds(); void calculate_implied_bounds_for_monic(lp::lpvar v); - void init_bound_propagation(vector&); + void init_bound_propagation(); }; // end of core struct pp_mon { diff --git a/src/math/lp/nla_solver.cpp b/src/math/lp/nla_solver.cpp index 08c1e1e62..3475a3509 100644 --- a/src/math/lp/nla_solver.cpp +++ b/src/math/lp/nla_solver.cpp @@ -100,8 +100,8 @@ namespace nla { m_core->check_bounded_divisions(lemmas); } - void solver::init_bound_propagation(vector& lemmas) { - m_core->init_bound_propagation(lemmas); + void solver::init_bound_propagation() { + m_core->init_bound_propagation(); } } diff --git a/src/math/lp/nla_solver.h b/src/math/lp/nla_solver.h index fa206ea40..a4de90320 100644 --- a/src/math/lp/nla_solver.h +++ b/src/math/lp/nla_solver.h @@ -49,6 +49,6 @@ namespace nla { nlsat::anum const& am_value(lp::var_index v) const; void collect_statistics(::statistics & st); void calculate_implied_bounds_for_monic(lp::lpvar v); - void init_bound_propagation(vector&); + void init_bound_propagation(); }; } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index ea1dcd9b9..ef7ab7091 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2199,14 +2199,11 @@ public: } void propagate_bounds_for_touched_monomials() { - m_nla->init_bound_propagation(m_nla_lemma_vector); + m_nla->init_bound_propagation(); for (unsigned v : m_nla->monics_with_changed_bounds()) { m_nla->calculate_implied_bounds_for_monic(v); } m_nla->reset_monics_with_changed_bounds(); - for (const auto & l:m_nla_lemma_vector) { - false_case_of_check_nla(l); - } } void propagate_bounds_with_nlp() { From 940775d12d1b214bdf010aae4f8476fbbefa9b9b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Sep 2023 16:48:40 -0700 Subject: [PATCH 41/69] indentation Signed-off-by: Nikolaj Bjorner --- src/math/lp/nla_core.cpp | 121 +++++++++++++++++++-------------------- src/smt/smt_context.cpp | 2 + src/smt/theory_lra.cpp | 15 +++-- 3 files changed, 70 insertions(+), 68 deletions(-) diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 514b2ad61..079eccd74 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -22,24 +22,25 @@ namespace nla { typedef lp::lar_term term; -core::core(lp::lar_solver& s, params_ref const& p, reslimit& lim, std_vector& implied_bounds) : m_evars(), - lra(s), - m_reslim(lim), - m_params(p), - m_tangents(this), - m_basics(this), - m_order(this), - m_monotone(this), - m_powers(*this), - m_divisions(*this), - m_intervals(this, lim), - m_monomial_bounds(this), - m_horner(this), - m_grobner(this), - m_emons(m_evars), - m_use_nra_model(false), - m_nra(s, m_nra_lim, *this), - m_implied_bounds(implied_bounds) { +core::core(lp::lar_solver& s, params_ref const& p, reslimit& lim, std_vector& implied_bounds) : + m_evars(), + lra(s), + m_reslim(lim), + m_params(p), + m_tangents(this), + m_basics(this), + m_order(this), + m_monotone(this), + m_powers(*this), + m_divisions(*this), + m_intervals(this, lim), + m_monomial_bounds(this), + m_horner(this), + m_grobner(this), + m_emons(m_evars), + m_use_nra_model(false), + m_nra(s, m_nra_lim, *this), + m_implied_bounds(implied_bounds) { m_nlsat_delay = lp_settings().nlsat_delay(); lra.m_find_monics_with_changed_bounds_func = [&](const indexed_uint_set& columns_with_changed_bounds) { for (const auto& m : m_emons) { @@ -1839,8 +1840,7 @@ bool core::improve_bounds() { return bounds_improved; } -bool core::is_linear(const svector& m, lpvar& zero_var, lpvar& non_fixed) -{ +bool core::is_linear(const svector& m, lpvar& zero_var, lpvar& non_fixed) { zero_var = non_fixed = null_lpvar; unsigned n_of_non_fixed = 0; for (lpvar v : m) { @@ -1858,8 +1858,7 @@ bool core::is_linear(const svector& m, lpvar& zero_var, lpvar& non_fixed) return n_of_non_fixed <= 1; } -void core::add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std::function explain_dep) -{ +void core::add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std::function explain_dep) { TRACE("add_bound", lra.print_column_info(j, tout) << std::endl;); j = lra.column_to_reported_index(j); unsigned k; @@ -1876,67 +1875,63 @@ void core::add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std: } } -void core::add_upper_bound_monic(lpvar j, const lp::mpq& bound_val, bool is_strict, std::function explain_dep) -{ - j = lra.column_to_reported_index(j); - unsigned k; - if (!m_improved_upper_bounds.find(j, k)) { - m_improved_upper_bounds.insert(j, static_cast(m_implied_bounds.size())); - m_implied_bounds.push_back(lp::implied_bound(bound_val, j, false, is_strict, explain_dep)); - } - else { - auto& found_bound = m_implied_bounds[k]; - if (bound_val > found_bound.m_bound || (bound_val == found_bound.m_bound && !found_bound.m_strict && is_strict)) { - found_bound = lp::implied_bound(bound_val, j, false, is_strict, explain_dep); - TRACE("add_bound", lra.print_implied_bound(found_bound, tout);); + void core::add_upper_bound_monic(lpvar j, const lp::mpq& bound_val, bool is_strict, std::function explain_dep) { + j = lra.column_to_reported_index(j); + unsigned k; + if (!m_improved_upper_bounds.find(j, k)) { + m_improved_upper_bounds.insert(j, static_cast(m_implied_bounds.size())); + m_implied_bounds.push_back(lp::implied_bound(bound_val, j, false, is_strict, explain_dep)); + } + else { + auto& found_bound = m_implied_bounds[k]; + if (bound_val > found_bound.m_bound || (bound_val == found_bound.m_bound && !found_bound.m_strict && is_strict)) { + found_bound = lp::implied_bound(bound_val, j, false, is_strict, explain_dep); + TRACE("add_bound", lra.print_implied_bound(found_bound, tout);); + } } } -} -bool core::upper_bound_is_available(unsigned j) const -{ - switch (get_column_type(j)) { + bool core::upper_bound_is_available(unsigned j) const { + switch (get_column_type(j)) { case lp::column_type::fixed: case lp::column_type::boxed: case lp::column_type::upper_bound: return true; default: return false; + } } -} - -bool core::lower_bound_is_available(unsigned j) const -{ - switch (get_column_type(j)) { + + bool core::lower_bound_is_available(unsigned j) const { + switch (get_column_type(j)) { case lp::column_type::fixed: case lp::column_type::boxed: case lp::column_type::lower_bound: return true; default: return false; + } } -} -void core::propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) -{ - lp::impq bound_value; - new_lemma lemma(*this, "propagate monic with non fixed"); - // using += to not assert thath the inequality does not hold - lemma += ineq(term(rational(1), monic_var, -k, non_fixed), llc::EQ, 0); - lp::explanation exp; - for (auto v : m_emons[monic_var].vars()) { - if (v == non_fixed) continue; - u_dependency* dep = lra.get_column_lower_bound_witness(v); - for (auto ci : lra.flatten(dep)) { - exp.push_back(ci); - } - dep = lra.get_column_upper_bound_witness(v); - for (auto ci : lra.flatten(dep)) { - exp.push_back(ci); + void core::propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { + lp::impq bound_value; + new_lemma lemma(*this, "propagate monic with non fixed"); + // using += to not assert thath the inequality does not hold + lemma += ineq(term(rational(1), monic_var, -k, non_fixed), llc::EQ, 0); + lp::explanation exp; + for (auto v : m_emons[monic_var].vars()) { + if (v == non_fixed) continue; + u_dependency* dep = lra.get_column_lower_bound_witness(v); + for (auto ci : lra.flatten(dep)) { + exp.push_back(ci); + } + dep = lra.get_column_upper_bound_witness(v); + for (auto ci : lra.flatten(dep)) { + exp.push_back(ci); + } } + lemma &= exp; } - lemma &= exp; -} void core::propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k) { diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 64c7bbf2e..a3cd99e37 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4522,6 +4522,8 @@ namespace smt { theory_var_list * l = n->get_th_var_list(); theory_id th_id = l->get_id(); + verbose_stream() << "num parents " << n->get_num_parents() << "\n"; + for (enode * parent : enode::parents(n)) { app* p = parent->get_expr(); family_id fid = p->get_family_id(); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index ea1dcd9b9..beec02d98 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1480,6 +1480,7 @@ public: m_model_eqs.reset(); svector vars; theory_var sz = static_cast(th.get_num_vars()); + verbose_stream() << "check " << sz << "\n"; for (theory_var v = 0; v < sz; ++v) { enode * n1 = get_enode(v); if (!th.is_relevant_and_shared(n1)) { @@ -1528,12 +1529,16 @@ public: unsigned old_sz = m_assume_eq_candidates.size(); unsigned num_candidates = 0; int start = ctx().get_random_value(); + verbose_stream() << "assume-eqs " << sz << "\n"; + unsigned num_relevant = 0; for (theory_var i = 0; i < sz; ++i) { theory_var v = (i + start) % sz; enode* n1 = get_enode(v); + verbose_stream() << enode_pp(n1, ctx()) << "\n"; if (!th.is_relevant_and_shared(n1)) { continue; } + ++num_relevant; ensure_column(v); if (!is_registered_var(v)) continue; @@ -1551,7 +1556,8 @@ public: num_candidates++; } } - + + verbose_stream() << "candidates " << num_candidates << " num relevant " << num_relevant << "\n"; if (num_candidates > 0) { ctx().push_trail(restore_vector(m_assume_eq_candidates, old_sz)); } @@ -2200,13 +2206,12 @@ public: void propagate_bounds_for_touched_monomials() { m_nla->init_bound_propagation(m_nla_lemma_vector); - for (unsigned v : m_nla->monics_with_changed_bounds()) { + for (unsigned v : m_nla->monics_with_changed_bounds()) m_nla->calculate_implied_bounds_for_monic(v); - } + m_nla->reset_monics_with_changed_bounds(); - for (const auto & l:m_nla_lemma_vector) { + for (const auto & l : m_nla_lemma_vector) false_case_of_check_nla(l); - } } void propagate_bounds_with_nlp() { From 886d3f43511eb997dc16607daa24c75456f57532 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Sep 2023 16:55:34 -0700 Subject: [PATCH 42/69] indentation Signed-off-by: Nikolaj Bjorner --- src/math/lp/nla_core.cpp | 151 +++++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 78 deletions(-) diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 904da26cd..38f741388 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -1913,91 +1913,88 @@ void core::add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std: } } -void core::propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) -{ - lp::impq bound_value; - bool is_strict; - auto& lps = lra; + void core::propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { + lp::impq bound_value; + bool is_strict; + auto& lps = lra; + + if (lower_bound_is_available(non_fixed)) { + bound_value = lra.column_lower_bound(non_fixed); + is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, non_fixed, &lps]() { + u_dependency* dep = lps.get_column_lower_bound_witness(non_fixed); + for (auto v : vars) + if (v != non_fixed) + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + return dep; + }; + if (k.is_pos()) + add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + else + add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + } + + if (upper_bound_is_available(non_fixed)) { + bound_value = lra.column_upper_bound(non_fixed); + is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, non_fixed, &lps]() { + u_dependency* dep = lps.get_column_upper_bound_witness(non_fixed); + for (auto v : vars) + if (v != non_fixed) + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + return dep; + }; + if (k.is_neg()) + add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + else + add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); + } - if (lower_bound_is_available(non_fixed)) { - bound_value = lra.column_lower_bound(non_fixed); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, non_fixed, &lps]() { - u_dependency* dep = lps.get_column_lower_bound_witness(non_fixed); - for (auto v : vars) - if (v != non_fixed) - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); - return dep; - }; - if (k.is_pos()) - add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - else - add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - } - - if (upper_bound_is_available(non_fixed)) { - bound_value = lra.column_upper_bound(non_fixed); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, non_fixed, &lps]() { - u_dependency* dep = lps.get_column_upper_bound_witness(non_fixed); - for (auto v : vars) - if (v != non_fixed) - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); - return dep; - }; - if (k.is_neg()) - add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - else - add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - } - - if (lower_bound_is_available(monic_var)) { - auto lambda = [vars, monic_var, non_fixed, &lps]() { - u_dependency* dep = lps.get_column_lower_bound_witness(monic_var); - for (auto v : vars) { - if (v != non_fixed) { - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + if (lower_bound_is_available(monic_var)) { + auto lambda = [vars, monic_var, non_fixed, &lps]() { + u_dependency* dep = lps.get_column_lower_bound_witness(monic_var); + for (auto v : vars) { + if (v != non_fixed) { + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + } } - } - return dep; - }; - bound_value = lra.column_lower_bound(monic_var); - is_strict = !bound_value.y.is_zero(); - if (k.is_pos()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - } - - if (upper_bound_is_available(monic_var)) { - bound_value = lra.column_upper_bound(monic_var); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, monic_var, non_fixed, &lps]() { - u_dependency* dep = lps.get_column_upper_bound_witness(monic_var); - for (auto v : vars) { - if (v != non_fixed) { - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + return dep; + }; + bound_value = lra.column_lower_bound(monic_var); + is_strict = !bound_value.y.is_zero(); + if (k.is_pos()) + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + else + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + } + + if (upper_bound_is_available(monic_var)) { + bound_value = lra.column_upper_bound(monic_var); + is_strict = !bound_value.y.is_zero(); + auto lambda = [vars, monic_var, non_fixed, &lps]() { + u_dependency* dep = lps.get_column_upper_bound_witness(monic_var); + for (auto v : vars) { + if (v != non_fixed) { + dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); + } } - } - return dep; - }; - if (k.is_neg()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + return dep; + }; + if (k.is_neg()) + add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + else + add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); + } } -} - void core::propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k) - { + void core::propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k) { auto* lps = &lra; auto lambda = [vars, lps]() { return lps->get_bound_constraint_witnesses_for_columns(vars); }; add_lower_bound_monic(monic_var, k, false, lambda); add_upper_bound_monic(monic_var, k, false, lambda); } - void core::add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var) - { + void core::add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var) { auto* lps = &lra; auto lambda = [zero_var, lps]() { return lps->get_bound_constraint_witnesses_for_column(zero_var); @@ -2007,8 +2004,7 @@ void core::propagate_monic_with_non_fixed(lpvar monic_var, const svector& add_upper_bound_monic(monic_var, lp::mpq(0), false, lambda); } - void core::calculate_implied_bounds_for_monic(lp::lpvar monic_var) - { + void core::calculate_implied_bounds_for_monic(lp::lpvar monic_var) { lpvar non_fixed, zero_var; const auto& vars = m_emons[monic_var].vars(); if (!is_linear(vars, zero_var, non_fixed)) @@ -2031,8 +2027,7 @@ void core::propagate_monic_with_non_fixed(lpvar monic_var, const svector& } } - void core::init_bound_propagation() - { + void core::init_bound_propagation() { m_implied_bounds.clear(); m_improved_lower_bounds.reset(); m_improved_upper_bounds.reset(); From 421fe946079ffb79ccae99bd85ffc6211c9570f7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 22 Sep 2023 17:59:07 -0700 Subject: [PATCH 43/69] rmove debug out Signed-off-by: Nikolaj Bjorner --- src/smt/theory_lra.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 8ffeff3fb..8bf17ec4d 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1529,12 +1529,10 @@ public: unsigned old_sz = m_assume_eq_candidates.size(); unsigned num_candidates = 0; int start = ctx().get_random_value(); - verbose_stream() << "assume-eqs " << sz << "\n"; unsigned num_relevant = 0; for (theory_var i = 0; i < sz; ++i) { theory_var v = (i + start) % sz; enode* n1 = get_enode(v); - verbose_stream() << enode_pp(n1, ctx()) << "\n"; if (!th.is_relevant_and_shared(n1)) { continue; } @@ -1557,7 +1555,6 @@ public: } } - verbose_stream() << "candidates " << num_candidates << " num relevant " << num_relevant << "\n"; if (num_candidates > 0) { ctx().push_trail(restore_vector(m_assume_eq_candidates, old_sz)); } From acad9fa62c0cab9089ee385098e50545d544b2bb Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Sep 2023 16:25:46 -0700 Subject: [PATCH 44/69] Update smt_context.cpp --- src/smt/smt_context.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index a3cd99e37..64c7bbf2e 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -4522,8 +4522,6 @@ namespace smt { theory_var_list * l = n->get_th_var_list(); theory_id th_id = l->get_id(); - verbose_stream() << "num parents " << n->get_num_parents() << "\n"; - for (enode * parent : enode::parents(n)) { app* p = parent->get_expr(); family_id fid = p->get_family_id(); From a3e2e68d93dcb4f2891e779fbe4419cc00db2b5e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Sep 2023 16:26:31 -0700 Subject: [PATCH 45/69] Update theory_lra.cpp --- src/smt/theory_lra.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 8bf17ec4d..21e021ea7 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1480,7 +1480,6 @@ public: m_model_eqs.reset(); svector vars; theory_var sz = static_cast(th.get_num_vars()); - verbose_stream() << "check " << sz << "\n"; for (theory_var v = 0; v < sz; ++v) { enode * n1 = get_enode(v); if (!th.is_relevant_and_shared(n1)) { From 87a839c794a78c0ac2962b5769b66e34b78fb653 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Sep 2023 18:07:56 -0700 Subject: [PATCH 46/69] fixup unit test for added argument to constructor of nla_solver Signed-off-by: Nikolaj Bjorner --- src/test/lp/nla_solver_test.cpp | 36 ++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/test/lp/nla_solver_test.cpp b/src/test/lp/nla_solver_test.cpp index ce934e7ca..c9ab08f28 100644 --- a/src/test/lp/nla_solver_test.cpp +++ b/src/test/lp/nla_solver_test.cpp @@ -169,7 +169,8 @@ void test_basic_lemma_for_mon_neutral_from_factors_to_monomial_0() { reslimit l; params_ref p; - solver nla(s, p, l); + std_vector ib; + solver nla(s, p, l, ib); svector v; v.push_back(lp_b);v.push_back(lp_d);v.push_back(lp_e); nla.add_monic(lp_bde, v.size(), v.begin()); v.clear(); @@ -246,7 +247,8 @@ void test_basic_lemma_for_mon_neutral_from_factors_to_monomial_1() { reslimit l; params_ref p; - solver nla(s, p, l); + std_vector ib; + solver nla(s, p, l, ib); svector v; v.push_back(lp_b);v.push_back(lp_d);v.push_back(lp_e); nla.add_monic(lp_bde, v.size(), v.begin()); @@ -317,7 +319,8 @@ void test_basic_lemma_for_mon_zero_from_factors_to_monomial() { reslimit l; params_ref p; - solver nla(s, p, l); + std_vector ib; + solver nla(s, p, l, ib); create_abcde(nla, lp_a, @@ -379,7 +382,8 @@ void test_basic_lemma_for_mon_zero_from_monomial_to_factors() { reslimit l; params_ref p; - solver nla(s, p, l); + std_vector ib; + solver nla(s, p, l, ib); // create monomial acd unsigned_vector vec; @@ -439,7 +443,8 @@ void test_basic_lemma_for_mon_neutral_from_monomial_to_factors() { reslimit l; params_ref p; - solver nla(s, p, l); + std_vector ib; + solver nla(s, p, l, ib); create_abcde(nla, lp_a, @@ -514,7 +519,8 @@ void test_horner() { reslimit l; params_ref p; - solver nla(s, p, l); + std_vector ib; + solver nla(s, p, l, ib); vector v; v.push_back(a); v.push_back(b); nla.add_monic(lp_ab, v.size(), v.begin()); @@ -551,7 +557,8 @@ void test_basic_sign_lemma() { reslimit l; params_ref p; - solver nla(s, p, l); + std_vector ib; + solver nla(s, p, l, ib); // create monomial bde vector vec; @@ -626,7 +633,8 @@ void test_order_lemma_params(bool var_equiv, int sign) { reslimit l; params_ref p; - solver nla(s,p,l); + std_vector ib; + solver nla(s,p,l,ib); // create monomial ab vector vec; vec.push_back(lp_a); @@ -757,7 +765,8 @@ void test_monotone_lemma() { reslimit l; params_ref p; - solver nla(s, p, l); + std_vector ib; + solver nla(s, p, l, ib); // create monomial ab vector vec; vec.push_back(lp_a); @@ -814,7 +823,8 @@ void test_tangent_lemma_rat() { s_set_column_value_test(s, lp_ab, v); reslimit l; params_ref p; - solver nla(s, p, l); + std_vector ib; + solver nla(s, p, l, ib); // create monomial ab vector vec; vec.push_back(lp_a); @@ -841,7 +851,8 @@ void test_tangent_lemma_reg() { s_set_column_value_test(s, lp_ab, rational(11)); reslimit l; params_ref p; - solver nla(s, p, l); + std_vector ib; + solver nla(s, p, l, ib); // create monomial ab vector vec; vec.push_back(lp_a); @@ -885,7 +896,8 @@ void test_tangent_lemma_equiv() { s_set_column_value_test(s, lp_a, - s.get_column_value(lp_k)); reslimit l; params_ref p; - solver nla(s, p, l); + std_vector ib; + solver nla(s, p, l, ib); // create monomial ab vector vec; vec.push_back(lp_a); From 26a9b776c65076c647f9793fbe512ab43ff46d3e Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 25 Sep 2023 12:10:59 -0700 Subject: [PATCH 47/69] clean m_nla_lemma_vector in nla_solver Signed-off-by: Lev Nachmanson --- src/math/lp/nla_core.cpp | 3 ++- src/math/lp/nla_core.h | 2 +- src/math/lp/nla_solver.cpp | 4 ++-- src/math/lp/nla_solver.h | 2 +- src/smt/theory_lra.cpp | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 38f741388..84367fbbc 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -2027,11 +2027,12 @@ void core::add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std: } } - void core::init_bound_propagation() { + void core::init_bound_propagation(vector& lemma_vector) { m_implied_bounds.clear(); m_improved_lower_bounds.reset(); m_improved_upper_bounds.reset(); m_column_types = &lra.get_column_types(); + lemma_vector.clear(); } } // namespace nla diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index 54c7e1df1..c561b91c0 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -451,7 +451,7 @@ private: void save_tableau(); bool integrality_holds(); void calculate_implied_bounds_for_monic(lp::lpvar v); - void init_bound_propagation(); + void init_bound_propagation(vector &); }; // end of core struct pp_mon { diff --git a/src/math/lp/nla_solver.cpp b/src/math/lp/nla_solver.cpp index 3475a3509..e8b2d9d1d 100644 --- a/src/math/lp/nla_solver.cpp +++ b/src/math/lp/nla_solver.cpp @@ -100,8 +100,8 @@ namespace nla { m_core->check_bounded_divisions(lemmas); } - void solver::init_bound_propagation() { - m_core->init_bound_propagation(); + void solver::init_bound_propagation(vector& nla_lemma_vector) { + m_core->init_bound_propagation(nla_lemma_vector); } } diff --git a/src/math/lp/nla_solver.h b/src/math/lp/nla_solver.h index a4de90320..7f52b5c92 100644 --- a/src/math/lp/nla_solver.h +++ b/src/math/lp/nla_solver.h @@ -49,6 +49,6 @@ namespace nla { nlsat::anum const& am_value(lp::var_index v) const; void collect_statistics(::statistics & st); void calculate_implied_bounds_for_monic(lp::lpvar v); - void init_bound_propagation(); + void init_bound_propagation(vector&); }; } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 21e021ea7..5405f7ff1 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2201,7 +2201,7 @@ public: } void propagate_bounds_for_touched_monomials() { - m_nla->init_bound_propagation(); + m_nla->init_bound_propagation(m_nla_lemma_vector); for (unsigned v : m_nla->monics_with_changed_bounds()) m_nla->calculate_implied_bounds_for_monic(v); From 0a1ade6f9547040f7564623ec79fc1efbdf777a7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Sep 2023 12:40:52 -0700 Subject: [PATCH 48/69] move m_nla_lemma_vector to be internal to nla_core Signed-off-by: Nikolaj Bjorner --- src/math/lp/nla_basics_lemmas.cpp | 2 +- src/math/lp/nla_core.cpp | 49 +++++++++++++++---------------- src/math/lp/nla_core.h | 16 +++++----- src/math/lp/nla_solver.cpp | 20 ++++++++----- src/math/lp/nla_solver.h | 14 +++++---- src/sat/smt/arith_solver.cpp | 4 +-- src/sat/smt/arith_solver.h | 1 - src/smt/theory_lra.cpp | 20 ++++++------- 8 files changed, 65 insertions(+), 61 deletions(-) diff --git a/src/math/lp/nla_basics_lemmas.cpp b/src/math/lp/nla_basics_lemmas.cpp index 7124fd409..191e59a79 100644 --- a/src/math/lp/nla_basics_lemmas.cpp +++ b/src/math/lp/nla_basics_lemmas.cpp @@ -104,7 +104,7 @@ bool basics::basic_sign_lemma_model_based() { return true; } } - return c().m_lemma_vec->size() > 0; + return c().m_lemmas.size() > 0; } diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 84367fbbc..365f81774 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -829,7 +829,7 @@ void core::print_stats(std::ostream& out) { void core::clear() { - m_lemma_vec->clear(); + m_lemmas.clear(); m_literal_vec->clear(); } @@ -1066,7 +1066,7 @@ rational core::val(const factorization& f) const { } new_lemma::new_lemma(core& c, char const* name):name(name), c(c) { - c.m_lemma_vec->push_back(lemma()); + c.m_lemmas.push_back(lemma()); } new_lemma& new_lemma::operator|=(ineq const& ineq) { @@ -1096,7 +1096,7 @@ new_lemma::~new_lemma() { } lemma& new_lemma::current() const { - return c.m_lemma_vec->back(); + return c.m_lemmas.back(); } new_lemma& new_lemma::operator&=(lp::explanation const& e) { @@ -1209,7 +1209,7 @@ void core::negate_relation(new_lemma& lemma, unsigned j, const rational& a) { } bool core::conflict_found() const { - for (const auto & l : * m_lemma_vec) { + for (const auto & l : m_lemmas) { if (l.is_conflict()) return true; } @@ -1217,7 +1217,7 @@ bool core::conflict_found() const { } bool core::done() const { - return m_lemma_vec->size() >= 10 || + return m_lemmas.size() >= 10 || conflict_found() || lp_settings().get_cancel_flag(); } @@ -1506,7 +1506,7 @@ void core::check_weighted(unsigned sz, std::pair 0 && !done() && m_lemma_vec->empty()) { + while (bound > 0 && !done() && m_lemmas.empty()) { unsigned n = random() % bound; for (unsigned i = 0; i < sz; ++i) { if (seen.contains(i)) @@ -1522,13 +1522,13 @@ void core::check_weighted(unsigned sz, std::pair& l_vec) { - m_lemma_vec = &l_vec; - return m_powers.check(r, x, y, l_vec); +lbool core::check_power(lpvar r, lpvar x, lpvar y) { + m_lemmas.reset(); + return m_powers.check(r, x, y, m_lemmas); } -void core::check_bounded_divisions(vector& l_vec) { - m_lemma_vec = &l_vec; +void core::check_bounded_divisions() { + m_lemmas.reset(); m_divisions.check_bounded_divisions(); } // looking for a free variable inside of a monic to split @@ -1547,11 +1547,10 @@ void core::add_bounds() { } } -lbool core::check(vector& lits, vector& l_vec) { +lbool core::check(vector& lits) { lp_settings().stats().m_nla_calls++; TRACE("nla_solver", tout << "calls = " << lp_settings().stats().m_nla_calls << "\n";); lra.get_rid_of_inf_eps(); - m_lemma_vec = &l_vec; m_literal_vec = &lits; if (!(lra.get_status() == lp::lp_status::OPTIMAL || lra.get_status() == lp::lp_status::FEASIBLE)) { @@ -1572,7 +1571,7 @@ lbool core::check(vector& lits, vector& l_vec) { bool run_bounded_nlsat = should_run_bounded_nlsat(); bool run_bounds = params().arith_nl_branching(); - auto no_effect = [&]() { return !done() && l_vec.empty() && lits.empty(); }; + auto no_effect = [&]() { return !done() && m_lemmas.empty() && lits.empty(); }; if (no_effect()) m_monomial_bounds.propagate(); @@ -1590,7 +1589,7 @@ lbool core::check(vector& lits, vector& l_vec) { {1, check2}, {1, check3} }; check_weighted(3, checks); - if (!l_vec.empty() || !lits.empty()) + if (!m_lemmas.empty() || !lits.empty()) return l_false; } @@ -1627,15 +1626,15 @@ lbool core::check(vector& lits, vector& l_vec) { m_stats.m_nra_calls++; } - if (ret == l_undef && !l_vec.empty() && m_reslim.inc()) + if (ret == l_undef && !m_lemmas.empty() && m_reslim.inc()) ret = l_false; - m_stats.m_nla_lemmas += l_vec.size(); - for (const auto& l : l_vec) + m_stats.m_nla_lemmas += m_lemmas.size(); + for (const auto& l : m_lemmas) m_stats.m_nla_explanations += static_cast(l.expl().size()); - TRACE("nla_solver", tout << "ret = " << ret << ", lemmas count = " << l_vec.size() << "\n";); + TRACE("nla_solver", tout << "ret = " << ret << ", lemmas count = " << m_lemmas.size() << "\n";); IF_VERBOSE(2, if(ret == l_undef) {verbose_stream() << "Monomials\n"; print_monics(verbose_stream());}); CTRACE("nla_solver", ret == l_undef, tout << "Monomials\n"; print_monics(tout);); return ret; @@ -1670,13 +1669,13 @@ lbool core::bounded_nlsat() { m_nlsat_delay /= 2; } if (ret == l_true) { - m_lemma_vec->reset(); + m_lemmas.reset(); } return ret; } bool core::no_lemmas_hold() const { - for (auto & l : * m_lemma_vec) { + for (auto & l : m_lemmas) { if (lemma_holds(l)) { TRACE("nla_solver", print_lemma(l, tout);); return false; @@ -1685,10 +1684,10 @@ bool core::no_lemmas_hold() const { return true; } -lbool core::test_check(vector& l) { +lbool core::test_check() { vector lits; lra.set_status(lp::lp_status::OPTIMAL); - return check(lits, l); + return check(lits); } std::ostream& core::print_terms(std::ostream& out) const { @@ -2027,12 +2026,12 @@ void core::add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std: } } - void core::init_bound_propagation(vector& lemma_vector) { + void core::init_bound_propagation() { m_implied_bounds.clear(); m_improved_lower_bounds.reset(); m_improved_upper_bounds.reset(); m_column_types = &lra.get_column_types(); - lemma_vector.clear(); + m_lemmas.clear(); } } // namespace nla diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index c561b91c0..90bfa18ca 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -85,7 +85,7 @@ class core { reslimit& m_reslim; smt_params_helper m_params; std::function m_relevant; - vector * m_lemma_vec; + vector m_lemmas; vector * m_literal_vec = nullptr; indexed_uint_set m_to_refine; vector m_monics_with_changed_bounds; @@ -393,15 +393,15 @@ public: bool conflict_found() const; - lbool check(vector& ineqs, vector& l_vec); - lbool check_power(lpvar r, lpvar x, lpvar y, vector& l_vec); - void check_bounded_divisions(vector&); + lbool check(vector& ineqs); + lbool check_power(lpvar r, lpvar x, lpvar y); + void check_bounded_divisions(); bool no_lemmas_hold() const; - void propagate(vector& lemmas); + // void propagate(); - lbool test_check(vector& l); + lbool test_check(); lpvar map_to_root(lpvar) const; std::ostream& print_terms(std::ostream&) const; std::ostream& print_term(const lp::lar_term&, std::ostream&) const; @@ -443,6 +443,8 @@ public: void add_upper_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std::function explain_dep); bool upper_bound_is_available(unsigned j) const; bool lower_bound_is_available(unsigned j) const; + vector const& lemmas() const { return m_lemmas; } + private: lp::column_type get_column_type(unsigned j) const { return (*m_column_types)[j]; } void constrain_nl_in_tableau(); @@ -451,7 +453,7 @@ private: void save_tableau(); bool integrality_holds(); void calculate_implied_bounds_for_monic(lp::lpvar v); - void init_bound_propagation(vector &); + void init_bound_propagation(); }; // end of core struct pp_mon { diff --git a/src/math/lp/nla_solver.cpp b/src/math/lp/nla_solver.cpp index e8b2d9d1d..b16d14021 100644 --- a/src/math/lp/nla_solver.cpp +++ b/src/math/lp/nla_solver.cpp @@ -42,8 +42,8 @@ namespace nla { bool solver::need_check() { return m_core->has_relevant_monomial(); } - lbool solver::check(vector& lits, vector& lemmas) { - return m_core->check(lits, lemmas); + lbool solver::check(vector& lits) { + return m_core->check(lits); } void solver::push(){ @@ -92,16 +92,20 @@ namespace nla { m_core->calculate_implied_bounds_for_monic(v); } // ensure r = x^y, add abstraction/refinement lemmas - lbool solver::check_power(lpvar r, lpvar x, lpvar y, vector& lemmas) { - return m_core->check_power(r, x, y, lemmas); + lbool solver::check_power(lpvar r, lpvar x, lpvar y) { + return m_core->check_power(r, x, y); } - void solver::check_bounded_divisions(vector& lemmas) { - m_core->check_bounded_divisions(lemmas); + void solver::check_bounded_divisions() { + m_core->check_bounded_divisions(); } - void solver::init_bound_propagation(vector& nla_lemma_vector) { - m_core->init_bound_propagation(nla_lemma_vector); + void solver::init_bound_propagation() { + m_core->init_bound_propagation(); + } + + vector const& solver::lemmas() const { + return m_core->lemmas(); } } diff --git a/src/math/lp/nla_solver.h b/src/math/lp/nla_solver.h index 7f52b5c92..b4fba1f86 100644 --- a/src/math/lp/nla_solver.h +++ b/src/math/lp/nla_solver.h @@ -23,7 +23,7 @@ namespace nla { class solver { core* m_core; public: - + solver(lp::lar_solver& s, params_ref const& p, reslimit& limit, std_vector & implied_bounds); ~solver(); const auto& monics_with_changed_bounds() const { return m_core->monics_with_changed_bounds(); } @@ -32,14 +32,14 @@ namespace nla { void add_idivision(lpvar q, lpvar x, lpvar y); void add_rdivision(lpvar q, lpvar x, lpvar y); void add_bounded_division(lpvar q, lpvar x, lpvar y); - void check_bounded_divisions(vector&); + void check_bounded_divisions(); void set_relevant(std::function& is_relevant); void push(); void pop(unsigned scopes); bool need_check(); - lbool check(vector& lits, vector&); - void propagate(vector& lemmas); - lbool check_power(lpvar r, lpvar x, lpvar y, vector&); + lbool check(vector& lits); + void propagate(); + lbool check_power(lpvar r, lpvar x, lpvar y); bool is_monic_var(lpvar) const; bool influences_nl_var(lpvar) const; std::ostream& display(std::ostream& out) const; @@ -49,6 +49,8 @@ namespace nla { nlsat::anum const& am_value(lp::var_index v) const; void collect_statistics(::statistics & st); void calculate_implied_bounds_for_monic(lp::lpvar v); - void init_bound_propagation(vector&); + void init_bound_propagation(); + vector const& lemmas() const; + }; } diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 3cf991c20..893fe4a43 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -1459,11 +1459,11 @@ namespace arith { return l_true; m_a1 = nullptr; m_a2 = nullptr; - lbool r = m_nla->check(m_nla_literals, m_nla_lemma_vector); + lbool r = m_nla->check(m_nla_literals); switch (r) { case l_false: assume_literals(); - for (const nla::lemma& l : m_nla_lemma_vector) + for (const nla::lemma& l : m_nla->lemmas()) false_case_of_check_nla(l); break; case l_true: diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 8917a3e42..53b49a658 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -249,7 +249,6 @@ namespace arith { // lemmas lp::explanation m_explanation; - vector m_nla_lemma_vector; vector m_nla_literals; literal_vector m_core, m_core2; vector m_coeffs; diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 5405f7ff1..ce53b8f25 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1601,11 +1601,11 @@ public: return FC_DONE; if (!m_nla) return FC_GIVEUP; - switch (m_nla->check_power(get_lpvar(e), get_lpvar(x), get_lpvar(y), m_nla_lemma_vector)) { + switch (m_nla->check_power(get_lpvar(e), get_lpvar(x), get_lpvar(y))) { case l_true: return FC_DONE; case l_false: - for (const nla::lemma & l : m_nla_lemma_vector) + for (const nla::lemma & l : m_nla->lemmas()) false_case_of_check_nla(l); return FC_CONTINUE; case l_undef: @@ -1802,11 +1802,10 @@ public: bool check_idiv_bounds() { if (!m_nla) return true; - m_nla_lemma_vector.reset(); - m_nla->check_bounded_divisions(m_nla_lemma_vector); - for (auto & lemma : m_nla_lemma_vector) + m_nla->check_bounded_divisions(); + for (auto & lemma : m_nla->lemmas()) false_case_of_check_nla(lemma); - return m_nla_lemma_vector.empty(); + return m_nla->lemmas().empty(); } expr_ref var2expr(lpvar v) { @@ -2025,13 +2024,13 @@ public: final_check_status check_nla_continue() { m_a1 = nullptr; m_a2 = nullptr; - lbool r = m_nla->check(m_nla_literals, m_nla_lemma_vector); + lbool r = m_nla->check(m_nla_literals); switch (r) { case l_false: for (const nla::ineq& i : m_nla_literals) assume_literal(i); - for (const nla::lemma & l : m_nla_lemma_vector) + for (const nla::lemma & l : m_nla->lemmas()) false_case_of_check_nla(l); return FC_CONTINUE; case l_true: @@ -2201,12 +2200,12 @@ public: } void propagate_bounds_for_touched_monomials() { - m_nla->init_bound_propagation(m_nla_lemma_vector); + m_nla->init_bound_propagation(); for (unsigned v : m_nla->monics_with_changed_bounds()) m_nla->calculate_implied_bounds_for_monic(v); m_nla->reset_monics_with_changed_bounds(); - for (const auto & l : m_nla_lemma_vector) + for (const auto & l : m_nla->lemmas()) false_case_of_check_nla(l); } @@ -3210,7 +3209,6 @@ public: } lp::explanation m_explanation; - vector m_nla_lemma_vector; vector m_nla_literals; literal_vector m_core; svector m_eqs; From d2c0f7dba797f3823f1c82f200e9d6acc98f01a5 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 25 Sep 2023 12:48:52 -0700 Subject: [PATCH 49/69] fix test build Signed-off-by: Nikolaj Bjorner --- src/test/lp/nla_solver_test.cpp | 37 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/test/lp/nla_solver_test.cpp b/src/test/lp/nla_solver_test.cpp index c9ab08f28..c7ff5b256 100644 --- a/src/test/lp/nla_solver_test.cpp +++ b/src/test/lp/nla_solver_test.cpp @@ -180,7 +180,6 @@ void test_basic_lemma_for_mon_neutral_from_factors_to_monomial_0() { v.push_back(lp_a);v.push_back(lp_c); nla.add_monic(lp_ac, v.size(), v.begin()); - vector lv; // set abcde = ac * bde // ac = 1 then abcde = bde, but we have abcde < bde @@ -194,9 +193,9 @@ void test_basic_lemma_for_mon_neutral_from_factors_to_monomial_0() { s.set_column_value_test(lp_bde, lp::impq(rational(16))); - VERIFY(nla.get_core().test_check(lv) == l_false); - - nla.get_core().print_lemma(lv.back(), std::cout); + VERIFY(nla.get_core().test_check() == l_false); + auto const& lemmas = nla.get_core().lemmas(); + nla.get_core().print_lemma(lemmas.back(), std::cout); ineq i0(lp_ac, llc::NE, 1); lp::lar_term t1, t2; @@ -209,7 +208,7 @@ void test_basic_lemma_for_mon_neutral_from_factors_to_monomial_0() { bool found0 = false; bool found1 = false; bool found2 = false; - for (const auto& k : lv[0].ineqs()){ + for (const auto& k : lemmas[0].ineqs()){ if (k == i0) { found0 = true; } else if (k == i1) { @@ -252,7 +251,6 @@ void test_basic_lemma_for_mon_neutral_from_factors_to_monomial_1() { svector v; v.push_back(lp_b);v.push_back(lp_d);v.push_back(lp_e); nla.add_monic(lp_bde, v.size(), v.begin()); - vector lemma; s_set_column_value_test(s, lp_a, rational(1)); s_set_column_value_test(s, lp_b, rational(1)); @@ -261,7 +259,8 @@ void test_basic_lemma_for_mon_neutral_from_factors_to_monomial_1() { s_set_column_value_test(s, lp_e, rational(1)); s_set_column_value_test(s, lp_bde, rational(3)); - VERIFY(nla.get_core().test_check(lemma) == l_false); + VERIFY(nla.get_core().test_check() == l_false); + auto const& lemma = nla.get_core().lemmas(); SASSERT(lemma[0].size() == 4); nla.get_core().print_lemma(lemma.back(), std::cout); @@ -333,7 +332,6 @@ void test_basic_lemma_for_mon_zero_from_factors_to_monomial() { lp_bde, lp_acd, lp_be); - vector lemma; // set vars s_set_column_value_test(s, lp_a, rational(1)); @@ -347,7 +345,8 @@ void test_basic_lemma_for_mon_zero_from_factors_to_monomial() { s_set_column_value_test(s, lp_acd, rational(1)); s_set_column_value_test(s, lp_be, rational(1)); - VERIFY(nla.get_core().test_check(lemma) == l_false); + VERIFY(nla.get_core().test_check() == l_false); + auto const& lemma = nla.get_core().lemmas(); nla.get_core().print_lemma(lemma.back(), std::cout); SASSERT(lemma.size() == 1 && lemma[0].size() == 2); lp::lar_term t0, t1; @@ -393,13 +392,13 @@ void test_basic_lemma_for_mon_zero_from_monomial_to_factors() { vec.push_back(lp_d); nla.add_monic(lp_acd, vec.size(), vec.begin()); - vector lemma; s_set_column_value_test(s, lp_a, rational(1)); s_set_column_value_test(s, lp_c, rational(1)); s_set_column_value_test(s, lp_d, rational(1)); s_set_column_value_test(s, lp_acd, rational(0)); - VERIFY(nla.get_core().test_check(lemma) == l_false); + VERIFY(nla.get_core().test_check() == l_false); + auto const& lemma = nla.get_core().lemmas(); nla.get_core().print_lemma(lemma.back(), std::cout); @@ -457,7 +456,6 @@ void test_basic_lemma_for_mon_neutral_from_monomial_to_factors() { lp_bde, lp_acd, lp_be); - vector lemma; // set all vars to 1 s_set_column_value_test(s, lp_a, rational(1)); @@ -476,7 +474,8 @@ void test_basic_lemma_for_mon_neutral_from_monomial_to_factors() { s_set_column_value_test(s, lp_b, - rational(2)); // we have bde = -b, therefore d = +-1 and e = +-1 s_set_column_value_test(s, lp_d, rational(3)); - VERIFY(nla.get_core().test_check(lemma) == l_false); + VERIFY(nla.get_core().test_check() == l_false); + auto const& lemma = nla.get_core().lemmas(); nla.get_core().print_lemma(lemma.back(), std::cout); @@ -591,8 +590,8 @@ void test_basic_sign_lemma() { s_set_column_value_test(s, lp_bde, rational(5)); s_set_column_value_test(s, lp_acd, rational(3)); - vector lemmas; - VERIFY(nla.get_core().test_check(lemmas) == l_false); + VERIFY(nla.get_core().test_check() == l_false); + auto const& lemmas = nla.get_core().lemmas(); lp::lar_term t; t.add_var(lp_bde); @@ -831,8 +830,8 @@ void test_tangent_lemma_rat() { vec.push_back(lp_b); nla.add_monic(lp_ab, vec.size(), vec.begin()); - vector lemma; - VERIFY(nla.get_core().test_check(lemma) == l_false); + VERIFY(nla.get_core().test_check() == l_false); + auto const& lemma = nla.get_core().lemmas(); nla.get_core().print_lemma(lemma.back(), std::cout); } @@ -859,8 +858,8 @@ void test_tangent_lemma_reg() { vec.push_back(lp_b); nla.add_monic(lp_ab, vec.size(), vec.begin()); - vector lemma; - VERIFY(nla.get_core().test_check(lemma) == l_false); + VERIFY(nla.get_core().test_check() == l_false); + auto const& lemma = nla.get_core().lemmas(); nla.get_core().print_lemma(lemma.back(), std::cout); } From 896aba31f8b173a2108e7bf6fee778037acb4662 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 25 Sep 2023 14:20:24 -0700 Subject: [PATCH 50/69] move monomial propagation from theory_lra to nla_solver Signed-off-by: Lev Nachmanson --- src/math/lp/nla_solver.cpp | 6 ++++++ src/math/lp/nla_solver.h | 2 +- src/smt/theory_lra.cpp | 11 +++-------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/math/lp/nla_solver.cpp b/src/math/lp/nla_solver.cpp index b16d14021..236b85d4f 100644 --- a/src/math/lp/nla_solver.cpp +++ b/src/math/lp/nla_solver.cpp @@ -108,4 +108,10 @@ namespace nla { return m_core->lemmas(); } + void solver::propagate_bounds_for_touched_monomials() { + init_bound_propagation(); + for (unsigned v : monics_with_changed_bounds()) + calculate_implied_bounds_for_monic(v); + reset_monics_with_changed_bounds(); + } } diff --git a/src/math/lp/nla_solver.h b/src/math/lp/nla_solver.h index b4fba1f86..0448d840f 100644 --- a/src/math/lp/nla_solver.h +++ b/src/math/lp/nla_solver.h @@ -51,6 +51,6 @@ namespace nla { void calculate_implied_bounds_for_monic(lp::lpvar v); void init_bound_propagation(); vector const& lemmas() const; - + void propagate_bounds_for_touched_monomials(); }; } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index ce53b8f25..3b6a71b3d 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2199,12 +2199,8 @@ public: finish_bound_propagation(); } - void propagate_bounds_for_touched_monomials() { - m_nla->init_bound_propagation(); - for (unsigned v : m_nla->monics_with_changed_bounds()) - m_nla->calculate_implied_bounds_for_monic(v); - - m_nla->reset_monics_with_changed_bounds(); + void propagate_bounds_for_monomials() { + m_nla->propagate_bounds_for_touched_monomials(); for (const auto & l : m_nla->lemmas()) false_case_of_check_nla(l); } @@ -2215,8 +2211,7 @@ public: if (is_infeasible() || !should_propagate()) return; - m_bp.init(); - propagate_bounds_for_touched_monomials(); + propagate_bounds_for_monomials(); if (m.inc()) finish_bound_propagation(); From 6ff4856e38fffa278c2a076ba18038199cddd12a Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 25 Sep 2023 16:47:34 -0700 Subject: [PATCH 51/69] throttle monomial unit prop and and nl params --- src/math/lp/nla_core.cpp | 31 +++++++++++++++++++++++++++- src/math/lp/nla_core.h | 3 ++- src/smt/params/smt_params_helper.pyg | 2 ++ src/smt/theory_lra.cpp | 2 +- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 365f81774..0788510ef 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -1913,6 +1913,10 @@ void core::add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std: } void core::propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { + if (params().arith_nl_use_lemmas_in_unit_prop()) { + propagate_monic_non_fixed_with_lemma(monic_var, vars, non_fixed, k); + return; + } lp::impq bound_value; bool is_strict; auto& lps = lra; @@ -2002,13 +2006,38 @@ void core::add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std: add_lower_bound_monic(monic_var, lp::mpq(0), false, lambda); add_upper_bound_monic(monic_var, lp::mpq(0), false, lambda); } + + void core::propagate_monic_non_fixed_with_lemma(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { + lp::impq bound_value; + new_lemma lemma(*this, "propagate monic with non fixed"); + // using += to not assert thath the inequality does not hold + lemma += ineq(term(rational(1), monic_var, -k, non_fixed), llc::EQ, 0); + lp::explanation exp; + for (auto v : m_emons[monic_var].vars()) { + if (v == non_fixed) continue; + u_dependency* dep = lra.get_column_lower_bound_witness(v); + for (auto ci : lra.flatten(dep)) { + exp.push_back(ci); + } + dep = lra.get_column_upper_bound_witness(v); + for (auto ci : lra.flatten(dep)) { + exp.push_back(ci); + } + } + lemma &= exp; + } void core::calculate_implied_bounds_for_monic(lp::lpvar monic_var) { + m_propagated.reserve(monic_var + 1, false); + bool throttle = params().arith_nl_throttle_unit_prop(); + if (throttle && m_propagated[monic_var]) + return; lpvar non_fixed, zero_var; const auto& vars = m_emons[monic_var].vars(); if (!is_linear(vars, zero_var, non_fixed)) return; - + if (throttle) + trail().push(set_bitvector_trail(m_propagated, monic_var)); if (zero_var != null_lpvar) add_bounds_for_zero_var(monic_var, zero_var); else { diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index 90bfa18ca..e1fae2aff 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -114,7 +114,7 @@ class core { bool m_cautious_patching = true; lpvar m_patched_var = 0; monic const* m_patched_monic = nullptr; - + bool_vector m_propagated; void check_weighted(unsigned sz, std::pair>* checks); void add_bounds(); std_vector & m_implied_bounds; @@ -438,6 +438,7 @@ public: bool is_linear(const svector& m, lpvar& zero_var, lpvar& non_fixed); void add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var); void propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k); + void core::propagate_monic_non_fixed_with_lemma(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k); void propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k); void add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std::function explain_dep); void add_upper_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std::function explain_dep); diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index f059dccb8..ab9f56c96 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -71,6 +71,8 @@ def_module_params(module_name='smt', ('arith.nl.grobner_row_length_limit', UINT, 10, 'row is disregarded by the heuristic if its length is longer than the value'), ('arith.nl.grobner_frequency', UINT, 4, 'grobner\'s call frequency'), ('arith.nl.grobner', BOOL, True, 'run grobner\'s basis heuristic'), + ('arith.nl.use_lemmas_in_unit_prop', BOOL, False, 'use lemmas in monomial unit propagation'), + ('arith.nl.throttle_unit_prop', BOOL, True, 'unit propogate a monomial only once per scope'), ('arith.nl.grobner_eqs_growth', UINT, 10, 'grobner\'s number of equalities growth '), ('arith.nl.grobner_expr_size_growth', UINT, 2, 'grobner\'s maximum expr size growth'), ('arith.nl.grobner_expr_degree_growth', UINT, 2, 'grobner\'s maximum expr degree growth'), diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 3b6a71b3d..e85b2722a 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -3209,7 +3209,7 @@ public: svector m_eqs; vector m_params; - void reset_evidence() { + void reset_evidence() { m_core.reset(); m_eqs.reset(); m_params.reset(); From 368fe80b3d31e946fbca1b4758994eb29aa26d1d Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 25 Sep 2023 16:55:02 -0700 Subject: [PATCH 52/69] fix the build --- src/math/lp/nla_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index e1fae2aff..a6bc6b3b4 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -438,7 +438,7 @@ public: bool is_linear(const svector& m, lpvar& zero_var, lpvar& non_fixed); void add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var); void propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k); - void core::propagate_monic_non_fixed_with_lemma(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k); + void propagate_monic_non_fixed_with_lemma(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k); void propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k); void add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std::function explain_dep); void add_upper_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std::function explain_dep); From 29b5c47a8d416d2ab1ff2008626c845b58b25d01 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 27 Sep 2023 09:09:38 -0700 Subject: [PATCH 53/69] track changed monics efficiently Signed-off-by: Lev Nachmanson --- src/math/lp/nla_core.cpp | 21 ++++++++++----------- src/math/lp/nla_core.h | 3 +-- src/math/lp/nla_solver.cpp | 1 - src/math/lp/nla_solver.h | 1 - 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index fe4c1a29a..97c9c82d9 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -43,18 +43,17 @@ core::core(lp::lar_solver& s, params_ref const& p, reslimit& lim, std_vector m_lemmas; vector * m_literal_vec = nullptr; indexed_uint_set m_to_refine; - vector m_monics_with_changed_bounds; + indexed_uint_set m_monics_with_changed_bounds; tangents m_tangents; basics m_basics; order m_order; @@ -125,7 +125,6 @@ public: // constructor core(lp::lar_solver& s, params_ref const& p, reslimit&, std_vector & implied_bounds); const auto& monics_with_changed_bounds() const { return m_monics_with_changed_bounds; } - void reset_monics_with_changed_bounds() { m_monics_with_changed_bounds.reset(); } void insert_to_refine(lpvar j); void erase_from_to_refine(lpvar j); diff --git a/src/math/lp/nla_solver.cpp b/src/math/lp/nla_solver.cpp index 236b85d4f..144ecefd3 100644 --- a/src/math/lp/nla_solver.cpp +++ b/src/math/lp/nla_solver.cpp @@ -112,6 +112,5 @@ namespace nla { init_bound_propagation(); for (unsigned v : monics_with_changed_bounds()) calculate_implied_bounds_for_monic(v); - reset_monics_with_changed_bounds(); } } diff --git a/src/math/lp/nla_solver.h b/src/math/lp/nla_solver.h index 0448d840f..0fe9733f1 100644 --- a/src/math/lp/nla_solver.h +++ b/src/math/lp/nla_solver.h @@ -27,7 +27,6 @@ namespace nla { solver(lp::lar_solver& s, params_ref const& p, reslimit& limit, std_vector & implied_bounds); ~solver(); const auto& monics_with_changed_bounds() const { return m_core->monics_with_changed_bounds(); } - void reset_monics_with_changed_bounds() { m_core->reset_monics_with_changed_bounds(); } void add_monic(lpvar v, unsigned sz, lpvar const* vs); void add_idivision(lpvar q, lpvar x, lpvar y); void add_rdivision(lpvar q, lpvar x, lpvar y); From f30a2c13be7384eda00ecc3e336bcf9a21f0fa8f Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 28 Sep 2023 17:24:34 -0700 Subject: [PATCH 54/69] propagate only one non-fixed monomial intrernally lar_solver --- src/math/lp/monomial_bounds.cpp | 20 +++++++++ src/math/lp/monomial_bounds.h | 4 +- src/math/lp/nla_core.cpp | 80 +-------------------------------- src/math/lp/nla_core.h | 1 - 4 files changed, 23 insertions(+), 82 deletions(-) diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index 7d2dc5ce6..981677ab0 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -12,6 +12,26 @@ #include "math/lp/nla_intervals.h" namespace nla { + // here non_fixed is the only non-fixed variable in the monomial, + // vars is the vector of the monomial variables, + // k is the product of all fixed variables in vars + void monomial_bounds::propagate_nonfixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { + vector> coeffs; + coeffs.push_back(std::make_pair(-k, non_fixed)); + coeffs.push_back(std::make_pair(rational::one(), monic_var)); + lp::lpvar term_index = c().lra.add_term(coeffs, UINT_MAX); + auto* dep = explain_fixed(vars, non_fixed); + term_index = c().lra.map_term_index_to_column_index(term_index); + c().lra.update_column_type_and_bound(term_index, lp::lconstraint_kind::EQ, mpq(0), dep); + } + + u_dependency* monomial_bounds::explain_fixed(const svector& vars, lpvar non_fixed) { + u_dependency* dep = nullptr; + for (auto v : vars) + if (v != non_fixed) + dep = c().lra.join_deps(dep, c().lra.get_bound_constraint_witnesses_for_column(v)); + return dep; + } monomial_bounds::monomial_bounds(core* c): common(c), diff --git a/src/math/lp/monomial_bounds.h b/src/math/lp/monomial_bounds.h index 15477e19a..76524012f 100644 --- a/src/math/lp/monomial_bounds.h +++ b/src/math/lp/monomial_bounds.h @@ -17,7 +17,7 @@ namespace nla { class monomial_bounds : common { dep_intervals& dep; - + u_dependency* explain_fixed(const svector& vars, lpvar non_fixed); void var2interval(lpvar v, scoped_dep_interval& i); bool is_too_big(mpq const& q) const; bool propagate_value(dep_interval& range, lpvar v); @@ -35,6 +35,6 @@ namespace nla { public: monomial_bounds(core* core); void propagate(); - + void propagate_nonfixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k); }; } diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 97c9c82d9..f574f20ad 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -1912,84 +1912,6 @@ void core::add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std: } } - void core::propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { - if (params().arith_nl_use_lemmas_in_unit_prop()) { - propagate_monic_non_fixed_with_lemma(monic_var, vars, non_fixed, k); - return; - } - lp::impq bound_value; - bool is_strict; - auto& lps = lra; - - if (lower_bound_is_available(non_fixed)) { - bound_value = lra.column_lower_bound(non_fixed); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, non_fixed, &lps]() { - u_dependency* dep = lps.get_column_lower_bound_witness(non_fixed); - for (auto v : vars) - if (v != non_fixed) - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); - return dep; - }; - if (k.is_pos()) - add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - else - add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - } - - if (upper_bound_is_available(non_fixed)) { - bound_value = lra.column_upper_bound(non_fixed); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, non_fixed, &lps]() { - u_dependency* dep = lps.get_column_upper_bound_witness(non_fixed); - for (auto v : vars) - if (v != non_fixed) - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); - return dep; - }; - if (k.is_neg()) - add_lower_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - else - add_upper_bound_monic(monic_var, k * bound_value.x, is_strict, lambda); - } - - if (lower_bound_is_available(monic_var)) { - auto lambda = [vars, monic_var, non_fixed, &lps]() { - u_dependency* dep = lps.get_column_lower_bound_witness(monic_var); - for (auto v : vars) { - if (v != non_fixed) { - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); - } - } - return dep; - }; - bound_value = lra.column_lower_bound(monic_var); - is_strict = !bound_value.y.is_zero(); - if (k.is_pos()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - } - - if (upper_bound_is_available(monic_var)) { - bound_value = lra.column_upper_bound(monic_var); - is_strict = !bound_value.y.is_zero(); - auto lambda = [vars, monic_var, non_fixed, &lps]() { - u_dependency* dep = lps.get_column_upper_bound_witness(monic_var); - for (auto v : vars) { - if (v != non_fixed) { - dep = lps.join_deps(dep, lps.get_bound_constraint_witnesses_for_column(v)); - } - } - return dep; - }; - if (k.is_neg()) - add_lower_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - else - add_upper_bound_monic(non_fixed, bound_value.x / k, is_strict, lambda); - } - } - void core::propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k) { auto* lps = &lra; auto lambda = [vars, lps]() { return lps->get_bound_constraint_witnesses_for_columns(vars); }; @@ -2049,7 +1971,7 @@ void core::add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std: } if (non_fixed != null_lpvar) - propagate_monic_with_non_fixed(monic_var, vars, non_fixed, k); + m_monomial_bounds.propagate_nonfixed(monic_var, vars, non_fixed, k); else // all variables are fixed propagate_monic_with_all_fixed(monic_var, vars, k); } diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index d5feac8a2..ef7863817 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -435,7 +435,6 @@ public: bool is_linear(const svector& m, lpvar& zero_var, lpvar& non_fixed); void add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var); - void propagate_monic_with_non_fixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k); void propagate_monic_non_fixed_with_lemma(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k); void propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k); void add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std::function explain_dep); From b64fdef41f4e1ff9b7c700d10541c7552286fa82 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 29 Sep 2023 15:27:22 -0700 Subject: [PATCH 55/69] better tracking changinc rows and monomials --- src/math/lp/lar_solver.cpp | 18 +++++------------- src/math/lp/lar_solver.h | 18 +++++++++++------- src/math/lp/nla_core.cpp | 25 +++++++++++-------------- src/math/lp/nla_core.h | 2 +- src/math/lp/nla_solver.cpp | 9 +++++++-- src/math/lp/nla_solver.h | 1 - 6 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 08ff3b0d4..4db3a9531 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -200,16 +200,10 @@ namespace lp { } lp_status lar_solver::solve() { - if (m_status == lp_status::INFEASIBLE) { + if (m_status == lp_status::INFEASIBLE) return m_status; - } + solve_with_core_solver(); - if (m_status != lp_status::INFEASIBLE) { - if (m_settings.bound_propagation()) - detect_rows_with_changed_bounds(); - } - - clear_columns_with_changed_bounds(); return m_status; } @@ -789,8 +783,7 @@ namespace lp { void lar_solver::detect_rows_with_changed_bounds() { for (auto j : m_columns_with_changed_bounds) detect_rows_with_changed_bounds_for_column(j); - if (m_find_monics_with_changed_bounds_func) - m_find_monics_with_changed_bounds_func(m_columns_with_changed_bounds); + } void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds_tableau() { @@ -1623,10 +1616,9 @@ namespace lp { SASSERT(m_terms.size() == m_term_register.size()); unsigned adjusted_term_index = m_terms.size() - 1; var_index ret = tv::mask_term(adjusted_term_index); - if (!coeffs.empty()) { + if (!coeffs.empty()) add_row_from_term_no_constraint(m_terms.back(), ret); - add_touched_row(A_r().row_count() - 1); - } + lp_assert(m_var_register.size() == A_r().column_count()); if (m_need_register_terms) register_normalized_term(*t, A_r().column_count() - 1); diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 9f878e363..2a1f8644c 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -89,6 +89,11 @@ class lar_solver : public column_namer { constraint_set m_constraints; // the set of column indices j such that bounds have changed for j indexed_uint_set m_columns_with_changed_bounds; +public: + const indexed_uint_set& columns_with_changed_bounds() const { return m_columns_with_changed_bounds; } + inline void clear_columns_with_changed_bounds() { m_columns_with_changed_bounds.reset(); } +private: + // m_touched_rows contains rows that have been changed by a pivoting or have a column with changed bounds indexed_uint_set m_touched_rows; unsigned_vector m_row_bounds_to_replay; u_dependency_manager m_dependencies; @@ -138,9 +143,7 @@ class lar_solver : public column_namer { void add_row_from_term_no_constraint(const lar_term* term, unsigned term_ext_index); void add_basic_var_to_core_fields(); bool compare_values(impq const& lhs, lconstraint_kind k, const mpq& rhs); - - inline void clear_columns_with_changed_bounds() { m_columns_with_changed_bounds.reset(); } - public: +public: void insert_to_columns_with_changed_bounds(unsigned j); const u_dependency* crossed_bounds_deps() const { return m_crossed_bounds_deps;} u_dependency*& crossed_bounds_deps() { return m_crossed_bounds_deps;} @@ -149,12 +152,12 @@ class lar_solver : public column_namer { lpvar& crossed_bounds_column() { return m_crossed_bounds_column; } - private: +private: void update_column_type_and_bound_check_on_equal(unsigned j, const mpq& right_side, constraint_index ci, unsigned&); void update_column_type_and_bound(unsigned j, const mpq& right_side, constraint_index ci); - public: +public: void update_column_type_and_bound(unsigned j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); - private: +private: void update_column_type_and_bound_with_ub(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); void update_column_type_and_bound_with_no_ub(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); void update_bound_with_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); @@ -358,6 +361,8 @@ class lar_solver : public column_namer { void add_column_rows_to_touched_rows(lpvar j); template void propagate_bounds_for_touched_rows(lp_bound_propagator& bp) { + detect_rows_with_changed_bounds(); + clear_columns_with_changed_bounds(); if (settings().propagate_eqs()) { if (settings().random_next() % 10 == 0) remove_fixed_vars_from_base(); @@ -688,7 +693,6 @@ class lar_solver : public column_namer { return 0; return m_usage_in_terms[j]; } - std::function m_find_monics_with_changed_bounds_func = nullptr; friend int_solver; friend int_branch; }; diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index f574f20ad..6641347e4 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -41,19 +41,7 @@ core::core(lp::lar_solver& s, params_ref const& p, reslimit& lim, std_vector & m_implied_bounds; // try to improve bounds for variables in monomials. bool improve_bounds(); - + void clear_monics_with_changed_bounds() { m_monics_with_changed_bounds.reset(); } public: // constructor core(lp::lar_solver& s, params_ref const& p, reslimit&, std_vector & implied_bounds); diff --git a/src/math/lp/nla_solver.cpp b/src/math/lp/nla_solver.cpp index 144ecefd3..53d8b0da6 100644 --- a/src/math/lp/nla_solver.cpp +++ b/src/math/lp/nla_solver.cpp @@ -110,7 +110,12 @@ namespace nla { void solver::propagate_bounds_for_touched_monomials() { init_bound_propagation(); - for (unsigned v : monics_with_changed_bounds()) - calculate_implied_bounds_for_monic(v); + for (unsigned v : m_core->monics_with_changed_bounds()) { + calculate_implied_bounds_for_monic(v); + if (m_core->lra.get_status() == lp::lp_status::INFEASIBLE) { + break; + } + } + m_core->clear_monics_with_changed_bounds(); } } diff --git a/src/math/lp/nla_solver.h b/src/math/lp/nla_solver.h index 0fe9733f1..acd724af9 100644 --- a/src/math/lp/nla_solver.h +++ b/src/math/lp/nla_solver.h @@ -26,7 +26,6 @@ namespace nla { solver(lp::lar_solver& s, params_ref const& p, reslimit& limit, std_vector & implied_bounds); ~solver(); - const auto& monics_with_changed_bounds() const { return m_core->monics_with_changed_bounds(); } void add_monic(lpvar v, unsigned sz, lpvar const* vs); void add_idivision(lpvar q, lpvar x, lpvar y); void add_rdivision(lpvar q, lpvar x, lpvar y); From 702322a6e92ae794c8b8dd35de0b963e97795d81 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 29 Sep 2023 15:31:32 -0700 Subject: [PATCH 56/69] change the order of lp and nlp propagation --- src/smt/theory_lra.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index cd4aa5388..d355b9118 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2151,8 +2151,8 @@ public: break; case l_true: propagate_basic_bounds(); + propagate_bounds_with_nlp(); propagate_bounds_with_lp_solver(); - propagate_bounds_with_nlp(); break; case l_undef: UNREACHABLE(); From a297a2b25c06ee541c8d414a060f93de0c770c16 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 1 Oct 2023 11:39:58 -0700 Subject: [PATCH 57/69] fixes in lar_solver around nl unit propagation Signed-off-by: Lev Nachmanson --- src/math/lp/lar_solver.cpp | 11 +++++++++-- src/math/lp/lar_solver.h | 2 ++ src/math/lp/lp_core_solver_base.h | 2 +- src/math/lp/lp_core_solver_base_def.h | 4 +++- src/math/lp/lp_primal_core_solver.h | 5 +++-- src/math/lp/monomial_bounds.cpp | 6 ++++++ src/math/lp/nla_core.cpp | 2 ++ src/smt/theory_lra.cpp | 2 ++ 8 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 4db3a9531..729b5865e 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -476,6 +476,9 @@ namespace lp { auto& x = m_mpq_lar_core_solver.m_r_x[j]; auto delta = new_val - x; x = new_val; + TRACE("lar_solver_feas", tout << "setting " << j << " to " + << new_val << (column_is_feasible(j)?"feas":"non-feas") << "\n";); + m_mpq_lar_core_solver.m_r_solver.track_column_feasibility(j); change_basic_columns_dependend_on_a_given_nb_column(j, delta); } @@ -1101,7 +1104,6 @@ namespace lp { mpq lar_solver::get_value(column_index const& j) const { SASSERT(get_status() == lp_status::OPTIMAL || get_status() == lp_status::FEASIBLE); - SASSERT(m_columns_with_changed_bounds.empty()); numeric_pair const& rp = get_column_value(j); return from_model_in_impq_to_mpq(rp); } @@ -1818,7 +1820,7 @@ namespace lp { if (is_base(j) && column_is_fixed(j)) m_fixed_base_var_set.insert(j); - TRACE("lar_solver_feas", tout << "j = " << j << " became " << (this->column_is_feasible(j) ? "feas" : "non-feas") << ", and " << (this->column_is_bounded(j) ? "bounded" : "non-bounded") << std::endl;); + TRACE("lar_solver_feas", tout << "j = " << j << " became " << (this->column_is_feasible(j) ? "feas" : "non-feas") << ", and " << (this->column_is_bounded(j) ? "bounded" : "non-bounded") << " val = " << get_column_value(j) << std::endl;); } void lar_solver::insert_to_columns_with_changed_bounds(unsigned j) { @@ -2363,6 +2365,11 @@ namespace lp { SASSERT(bdep != nullptr); m_crossed_bounds_deps = m_dependencies.mk_join(bdep, dep); } + + void lar_solver::track_column_feasibility(lpvar j) { + m_mpq_lar_core_solver.m_r_solver.track_column_feasibility(j); + } + } // namespace lp diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 2a1f8644c..0748d2507 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -92,6 +92,8 @@ class lar_solver : public column_namer { public: const indexed_uint_set& columns_with_changed_bounds() const { return m_columns_with_changed_bounds; } inline void clear_columns_with_changed_bounds() { m_columns_with_changed_bounds.reset(); } + void track_column_feasibility(lpvar j); + private: // m_touched_rows contains rows that have been changed by a pivoting or have a column with changed bounds indexed_uint_set m_touched_rows; diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index d7d1666d0..1d6634c06 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -571,7 +571,7 @@ public: } void remove_column_from_inf_heap(unsigned j) { if (m_inf_heap.contains(j)) { - TRACE("lar_solver_inf_heap", tout << "insert into heap j = " << j << "\n";); + TRACE("lar_solver_inf_heap", tout << "erase from heap j = " << j << "\n";); m_inf_heap.erase(j); } lp_assert(column_is_feasible(j)); diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index 0552b8e82..b4a53e872 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -115,10 +115,12 @@ pretty_print(std::ostream & out) { template void lp_core_solver_base:: add_delta_to_entering(unsigned entering, const X& delta) { - m_x[entering] += delta; + m_x[entering] += delta; + TRACE("lar_solver_feas", tout << "not tracking feas entering = " << entering << " = " << m_x[entering] << (column_is_feasible(entering) ? " feas" : " non-feas") << "\n";); for (const auto & c : m_A.m_columns[entering]) { unsigned i = c.var(); m_x[m_basis[i]] -= delta * m_A.get_val(c); + TRACE("lar_solver_feas", tout << "not tracking feas m_basis[i] = " << m_basis[i] << " = " << m_x[m_basis[i]] << (column_is_feasible(m_basis[i]) ? " feas" : " non-feas") << "\n";); } } diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index 9871ec691..f5d7314db 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -394,9 +394,10 @@ namespace lp { const X &new_val_for_leaving = get_val_for_leaving(leaving); X theta = (this->m_x[leaving] - new_val_for_leaving) / a_ent; this->m_x[leaving] = new_val_for_leaving; - // this will remove the leaving from the heap - TRACE("lar_solver_inf_heap", tout << "leaving = " << leaving + TRACE("lar_solver_feas", tout << "entering = " << entering << ", leaving = " << leaving << ", new_val_for_leaving = " << new_val_for_leaving << ", theta = " << theta << "\n";); + TRACE("lar_solver_feas", tout << "leaving = " << leaving << " removed from inf_heap()\n";); + // this will remove the leaving from the heap this->inf_heap().erase_min(); advance_on_entering_and_leaving_tableau_rows(entering, leaving, theta); if (this->current_x_is_feasible()) diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index 981677ab0..177cfb3d3 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -21,8 +21,14 @@ namespace nla { coeffs.push_back(std::make_pair(rational::one(), monic_var)); lp::lpvar term_index = c().lra.add_term(coeffs, UINT_MAX); auto* dep = explain_fixed(vars, non_fixed); + // term_index becomes the column index of the term slack variable term_index = c().lra.map_term_index_to_column_index(term_index); c().lra.update_column_type_and_bound(term_index, lp::lconstraint_kind::EQ, mpq(0), dep); + c().lra.track_column_feasibility(term_index); + if (!c().lra.column_is_feasible(term_index)) { + c().lra.set_status(lp::lp_status::UNKNOWN); + } + } u_dependency* monomial_bounds::explain_fixed(const svector& vars, lpvar non_fixed) { diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 6641347e4..5a6af5659 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -138,6 +138,7 @@ void core::add_monic(lpvar v, unsigned sz, lpvar const* vs) { m_add_buffer[i] = j; } m_emons.add(v, m_add_buffer); + m_monics_with_changed_bounds.insert(v); } void core::push() { @@ -1938,6 +1939,7 @@ void core::add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std: } void core::calculate_implied_bounds_for_monic(lp::lpvar monic_var) { + if (!is_monic_var(monic_var)) return; m_propagated.reserve(monic_var + 1, false); bool throttle = params().arith_nl_throttle_unit_prop(); if (throttle && m_propagated[monic_var]) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index d355b9118..2a7412c29 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -3191,6 +3191,8 @@ public: lbool make_feasible() { TRACE("pcs", tout << lp().constraints();); TRACE("arith_verbose", tout << "before calling lp().find_feasible_solution()\n"; display(tout);); + // todo: remove later : debug!!!!! + lp().move_non_basic_columns_to_bounds(false); auto status = lp().find_feasible_solution(); TRACE("arith_verbose", display(tout);); if (lp().is_feasible()) From 7de06c4350fa7f387c1823e3c8f0ecdda45249e7 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 2 Oct 2023 16:42:59 -0700 Subject: [PATCH 58/69] merging master to unit_prop_on_monomials --- src/math/lp/monomial_bounds.cpp | 166 ++++++++++++++------ src/math/lp/monomial_bounds.h | 16 +- src/math/lp/nla_core.cpp | 216 ++++----------------------- src/math/lp/nla_core.h | 49 +++--- src/math/lp/nla_solver.cpp | 41 +++-- src/math/lp/nla_solver.h | 15 +- src/math/lp/nla_types.h | 15 +- src/sat/smt/arith_internalize.cpp | 2 +- src/sat/smt/arith_solver.cpp | 6 +- src/sat/smt/arith_solver.h | 1 - src/sat/smt/euf_proof_checker.cpp | 6 +- src/smt/params/smt_params_helper.pyg | 2 - src/smt/smt_clause_proof.cpp | 22 ++- src/smt/smt_clause_proof.h | 6 +- src/smt/smt_conflict_resolution.cpp | 1 + src/smt/smt_internalizer.cpp | 6 +- src/smt/theory_arith_aux.h | 3 +- src/smt/theory_arith_nl.h | 15 +- src/smt/theory_lra.cpp | 120 ++++++++------- 19 files changed, 333 insertions(+), 375 deletions(-) diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index 177cfb3d3..8bb6ab306 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -10,34 +10,9 @@ #include "math/lp/monomial_bounds.h" #include "math/lp/nla_core.h" #include "math/lp/nla_intervals.h" +#include "math/lp/numeric_pair.h" namespace nla { - // here non_fixed is the only non-fixed variable in the monomial, - // vars is the vector of the monomial variables, - // k is the product of all fixed variables in vars - void monomial_bounds::propagate_nonfixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { - vector> coeffs; - coeffs.push_back(std::make_pair(-k, non_fixed)); - coeffs.push_back(std::make_pair(rational::one(), monic_var)); - lp::lpvar term_index = c().lra.add_term(coeffs, UINT_MAX); - auto* dep = explain_fixed(vars, non_fixed); - // term_index becomes the column index of the term slack variable - term_index = c().lra.map_term_index_to_column_index(term_index); - c().lra.update_column_type_and_bound(term_index, lp::lconstraint_kind::EQ, mpq(0), dep); - c().lra.track_column_feasibility(term_index); - if (!c().lra.column_is_feasible(term_index)) { - c().lra.set_status(lp::lp_status::UNKNOWN); - } - - } - - u_dependency* monomial_bounds::explain_fixed(const svector& vars, lpvar non_fixed) { - u_dependency* dep = nullptr; - for (auto v : vars) - if (v != non_fixed) - dep = c().lra.join_deps(dep, c().lra.get_bound_constraint_witnesses_for_column(v)); - return dep; - } monomial_bounds::monomial_bounds(core* c): common(c), @@ -50,6 +25,7 @@ namespace nla { } } + bool monomial_bounds::is_too_big(mpq const& q) const { return rational(q).bitsize() > 256; } @@ -283,25 +259,127 @@ namespace nla { } } - // returns true iff (all variables are fixed, - // or all but one variable are fixed) and the bounds are not big, - // or at least one variable is fixed to zero. - bool monomial_bounds::is_linear(monic const& m, lpvar& zero_var, lpvar& non_fixed) { - zero_var = non_fixed = null_lpvar; - unsigned n_of_non_fixed = 0; - bool big_bound = false; - for (lpvar v : m) { - if (!c().var_is_fixed(v)) { - n_of_non_fixed++; - non_fixed = v; - } else if (c().var_is_fixed_to_zero(v)) { - zero_var = v; - return true; - } else if (c().fixed_var_has_big_bound(v)) { - big_bound |= true; + void monomial_bounds::unit_propagate() { + for (auto const& m : c().m_emons) { + unit_propagate(m); + if (c().lra.get_status() == lp::lp_status::INFEASIBLE) { + lp::explanation exp; + c().lra.get_infeasibility_explanation(exp); + new_lemma lemma(c(), "propagate fixed - infeasible lra"); + lemma &= exp; + return; } - } - return n_of_non_fixed <= 1 && !big_bound; + if (c().m_conflicts > 0 ) { + return; + } + } } + + + void monomial_bounds::unit_propagate(monic const& m) { + if (m.is_propagated()) + return; + + if (!is_linear(m)) + return; + + + rational k = fixed_var_product(m); + lpvar w = non_fixed_var(m); + if (w == null_lpvar || k == 0) { + propagate_fixed(m, k); + } + else + propagate_nonfixed(m, k, w); + } + + lp::explanation monomial_bounds::get_explanation(u_dependency* dep) { + lp::explanation exp; + svector cs; + c().lra.dep_manager().linearize(dep, cs); + for (auto d : cs) + exp.add_pair(d, mpq(1)); + return exp; + } + + void monomial_bounds::propagate_fixed(monic const& m, rational const& k) { + auto* dep = explain_fixed(m, k); + if (!c().lra.is_base(m.var())) { + lp::impq val(k); + c().lra.set_value_for_nbasic_column(m.var(), val); + } + c().lra.update_column_type_and_bound(m.var(), lp::lconstraint_kind::EQ, k, dep); + + // propagate fixed equality + auto exp = get_explanation(dep); + c().add_fixed_equality(m.var(), k, exp); + } + + void monomial_bounds::propagate_nonfixed(monic const& m, rational const& k, lpvar w) { + VERIFY(k != 0); + vector> coeffs; + coeffs.push_back(std::make_pair(-k, w)); + coeffs.push_back(std::make_pair(rational::one(), m.var())); + lp::lpvar term_index = c().lra.add_term(coeffs, UINT_MAX); + auto* dep = explain_fixed(m, k); + term_index = c().lra.map_term_index_to_column_index(term_index); + c().lra.update_column_type_and_bound(term_index, lp::lconstraint_kind::EQ, mpq(0), dep); + + if (k == 1) { + lp::explanation exp = get_explanation(dep); + c().add_equality(m.var(), w, exp); + } + } + + u_dependency* monomial_bounds::explain_fixed(monic const& m, rational const& k) { + u_dependency* dep = nullptr; + auto update_dep = [&](unsigned j) { + dep = c().lra.dep_manager().mk_join(dep, c().lra.get_column_lower_bound_witness(j)); + dep = c().lra.dep_manager().mk_join(dep, c().lra.get_column_upper_bound_witness(j)); + return dep; + }; + + if (k == 0) { + for (auto j : m.vars()) + if (c().var_is_fixed_to_zero(j)) + return update_dep(j); + } + else { + for (auto j : m.vars()) + if (c().var_is_fixed(j)) + update_dep(j); + } + return dep; + } + + + bool monomial_bounds::is_linear(monic const& m) { + unsigned non_fixed = 0; + for (lpvar v : m) { + if (!c().var_is_fixed(v)) + ++non_fixed; + else if (c().val(v).is_zero()) + return true; + } + return non_fixed <= 1; + } + + + rational monomial_bounds::fixed_var_product(monic const& m) { + rational r(1); + for (lpvar v : m) { + if (c().var_is_fixed(v)) + r *= c().lra.get_column_value(v).x; + } + return r; + } + + lpvar monomial_bounds::non_fixed_var(monic const& m) { + for (lpvar v : m) + if (!c().var_is_fixed(v)) + return v; + return null_lpvar; + } + } diff --git a/src/math/lp/monomial_bounds.h b/src/math/lp/monomial_bounds.h index 76524012f..747aca9a2 100644 --- a/src/math/lp/monomial_bounds.h +++ b/src/math/lp/monomial_bounds.h @@ -17,24 +17,32 @@ namespace nla { class monomial_bounds : common { dep_intervals& dep; - u_dependency* explain_fixed(const svector& vars, lpvar non_fixed); + void var2interval(lpvar v, scoped_dep_interval& i); bool is_too_big(mpq const& q) const; + bool propagate_down(monic const& m, lpvar u); bool propagate_value(dep_interval& range, lpvar v); bool propagate_value(dep_interval& range, lpvar v, unsigned power); void compute_product(unsigned start, monic const& m, scoped_dep_interval& i); bool propagate(monic const& m); + void propagate_fixed(monic const& m, rational const& k); + void propagate_nonfixed(monic const& m, rational const& k, lpvar w); + u_dependency* explain_fixed(monic const& m, rational const& k); + lp::explanation get_explanation(u_dependency* dep); bool propagate_down(monic const& m, dep_interval& mi, lpvar v, unsigned power, dep_interval& product); void analyze_monomial(monic const& m, unsigned& num_free, lpvar& free_v, unsigned& power) const; bool is_free(lpvar v) const; bool is_zero(lpvar v) const; // monomial propagation - bool_vector m_propagated; - bool is_linear(monic const& m, lpvar& zero_var, lpvar& non_fixed); + void unit_propagate(monic const& m); + bool is_linear(monic const& m); + rational fixed_var_product(monic const& m); + lpvar non_fixed_var(monic const& m); + public: monomial_bounds(core* core); void propagate(); - void propagate_nonfixed(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k); + void unit_propagate(); }; } diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 5a6af5659..6a241e951 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -17,12 +17,11 @@ Author: #include "math/grobner/pdd_solver.h" #include "math/dd/pdd_interval.h" #include "math/dd/pdd_eval.h" -#include "nla_core.h" namespace nla { typedef lp::lar_term term; -core::core(lp::lar_solver& s, params_ref const& p, reslimit& lim, std_vector& implied_bounds) : +core::core(lp::lar_solver& s, params_ref const& p, reslimit & lim) : m_evars(), lra(s), m_reslim(lim), @@ -39,11 +38,11 @@ core::core(lp::lar_solver& s, params_ref const& p, reslimit& lim, std_vector(); } - -bool core::fixed_var_has_big_bound(lpvar j) const { - SASSERT(lra.column_is_fixed(j)); - const auto& b = lra.get_lower_bound(j); - return b.x.is_big() || b.y.is_big(); -} - bool core::var_is_fixed_to_val(lpvar j, const rational& v) const { return lra.column_is_fixed(j) && @@ -818,7 +809,10 @@ void core::print_stats(std::ostream& out) { void core::clear() { m_lemmas.clear(); - m_literal_vec->clear(); + m_literals.clear(); + m_fixed_equalities.clear(); + m_equalities.clear(); + m_conflicts = 0; } void core::init_search() { @@ -1065,14 +1059,6 @@ new_lemma& new_lemma::operator|=(ineq const& ineq) { } return *this; } - -// Contrary to new_lemma::operator|=, this method does not assert that the model does not satisfy the ineq. -new_lemma& new_lemma::operator+=(ineq const& ineq) { - if (!c.explain_ineq(*this, ineq.term(), ineq.cmp(), ineq.rs())) { - current().push_back(ineq); - } - return *this; -} new_lemma::~new_lemma() { @@ -1080,6 +1066,9 @@ new_lemma::~new_lemma() { (void)i; (void)name; // code for checking lemma can be added here + if (current().is_conflict()) { + c.m_conflicts++; + } TRACE("nla_solver", tout << name << " " << (++i) << "\n" << *this; ); } @@ -1511,12 +1500,12 @@ void core::check_weighted(unsigned sz, std::pair 0), and return - m_literal_vec->push_back(ineq(j, lp::lconstraint_kind::EQ, rational::zero())); + m_literals.push_back(ineq(j, lp::lconstraint_kind::EQ, rational::zero())); ++lp_settings().stats().m_nla_bounds; return; } } } -lbool core::check(vector& lits) { +lbool core::check() { lp_settings().stats().m_nla_calls++; TRACE("nla_solver", tout << "calls = " << lp_settings().stats().m_nla_calls << "\n";); lra.get_rid_of_inf_eps(); - m_literal_vec = &lits; if (!(lra.get_status() == lp::lp_status::OPTIMAL || lra.get_status() == lp::lp_status::FEASIBLE)) { TRACE("nla_solver", tout << "unknown because of the lra.m_status = " << lra.get_status() << "\n";); @@ -1559,7 +1547,7 @@ lbool core::check(vector& lits) { bool run_bounded_nlsat = should_run_bounded_nlsat(); bool run_bounds = params().arith_nl_branching(); - auto no_effect = [&]() { return !done() && m_lemmas.empty() && lits.empty(); }; + auto no_effect = [&]() { return !done() && m_lemmas.empty() && m_literals.empty(); }; if (no_effect()) m_monomial_bounds.propagate(); @@ -1577,7 +1565,7 @@ lbool core::check(vector& lits) { {1, check2}, {1, check3} }; check_weighted(3, checks); - if (!m_lemmas.empty() || !lits.empty()) + if (!m_lemmas.empty() || !m_literals.empty()) return l_false; } @@ -1656,9 +1644,8 @@ lbool core::bounded_nlsat() { m_nlsat_fails = 0; m_nlsat_delay /= 2; } - if (ret == l_true) { - m_lemmas.reset(); - } + if (ret == l_true) + clear(); return ret; } @@ -1672,10 +1659,10 @@ bool core::no_lemmas_hold() const { return true; } + lbool core::test_check() { - vector lits; lra.set_status(lp::lp_status::OPTIMAL); - return check(lits); + return check(); } std::ostream& core::print_terms(std::ostream& out) const { @@ -1826,162 +1813,13 @@ bool core::improve_bounds() { } return bounds_improved; } - -bool core::is_linear(const svector& m, lpvar& zero_var, lpvar& non_fixed) { - zero_var = non_fixed = null_lpvar; - unsigned n_of_non_fixed = 0; - for (lpvar v : m) { - if (!var_is_fixed(v)) { - n_of_non_fixed++; - non_fixed = v; - continue; - } - const auto& b = get_lower_bound(v); - if (b.is_zero()) { - zero_var = v; - return true; - } - } - return n_of_non_fixed <= 1; - + +void core::propagate() { + clear(); + m_monomial_bounds.unit_propagate(); } -void core::add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std::function explain_dep) { - TRACE("add_bound", lra.print_column_info(j, tout) << std::endl;); - j = lra.column_to_reported_index(j); - unsigned k; - if (!m_improved_lower_bounds.find(j, k)) { - m_improved_lower_bounds.insert(j, static_cast(m_implied_bounds.size())); - m_implied_bounds.push_back(lp::implied_bound(v, j, true, is_strict, explain_dep)); - } - else { - auto& found_bound = m_implied_bounds[k]; - if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && is_strict)) { - found_bound = lp::implied_bound(v, j, true, is_strict, explain_dep); - TRACE("add_bound", lra.print_implied_bound(found_bound, tout);); - } - } -} - void core::add_upper_bound_monic(lpvar j, const lp::mpq& bound_val, bool is_strict, std::function explain_dep) { - j = lra.column_to_reported_index(j); - unsigned k; - if (!m_improved_upper_bounds.find(j, k)) { - m_improved_upper_bounds.insert(j, static_cast(m_implied_bounds.size())); - m_implied_bounds.push_back(lp::implied_bound(bound_val, j, false, is_strict, explain_dep)); - } - else { - auto& found_bound = m_implied_bounds[k]; - if (bound_val > found_bound.m_bound || (bound_val == found_bound.m_bound && !found_bound.m_strict && is_strict)) { - found_bound = lp::implied_bound(bound_val, j, false, is_strict, explain_dep); - TRACE("add_bound", lra.print_implied_bound(found_bound, tout);); - } - } - } - bool core::upper_bound_is_available(unsigned j) const { - switch (get_column_type(j)) { - case lp::column_type::fixed: - case lp::column_type::boxed: - case lp::column_type::upper_bound: - return true; - default: - return false; - } - } - - bool core::lower_bound_is_available(unsigned j) const { - switch (get_column_type(j)) { - case lp::column_type::fixed: - case lp::column_type::boxed: - case lp::column_type::lower_bound: - return true; - default: - return false; - } - } +} // end of nla - void core::propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k) { - auto* lps = &lra; - auto lambda = [vars, lps]() { return lps->get_bound_constraint_witnesses_for_columns(vars); }; - add_lower_bound_monic(monic_var, k, false, lambda); - add_upper_bound_monic(monic_var, k, false, lambda); - } - - void core::add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var) { - auto* lps = &lra; - auto lambda = [zero_var, lps]() { - return lps->get_bound_constraint_witnesses_for_column(zero_var); - }; - TRACE("add_bound", lra.print_column_info(zero_var, tout) << std::endl;); - add_lower_bound_monic(monic_var, lp::mpq(0), false, lambda); - add_upper_bound_monic(monic_var, lp::mpq(0), false, lambda); - } - - void core::propagate_monic_non_fixed_with_lemma(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k) { - lp::impq bound_value; - new_lemma lemma(*this, "propagate monic with non fixed"); - // using += to not assert thath the inequality does not hold - lemma += ineq(term(rational(1), monic_var, -k, non_fixed), llc::EQ, 0); - lp::explanation exp; - for (auto v : m_emons[monic_var].vars()) { - if (v == non_fixed) continue; - u_dependency* dep = lra.get_column_lower_bound_witness(v); - for (auto ci : lra.flatten(dep)) { - exp.push_back(ci); - } - dep = lra.get_column_upper_bound_witness(v); - for (auto ci : lra.flatten(dep)) { - exp.push_back(ci); - } - } - lemma &= exp; - } - - void core::calculate_implied_bounds_for_monic(lp::lpvar monic_var) { - if (!is_monic_var(monic_var)) return; - m_propagated.reserve(monic_var + 1, false); - bool throttle = params().arith_nl_throttle_unit_prop(); - if (throttle && m_propagated[monic_var]) - return; - lpvar non_fixed, zero_var; - const auto& vars = m_emons[monic_var].vars(); - if (!is_linear(vars, zero_var, non_fixed)) - return; - if (throttle) - trail().push(set_bitvector_trail(m_propagated, monic_var)); - if (zero_var != null_lpvar) - add_bounds_for_zero_var(monic_var, zero_var); - else { - rational k = rational(1); - for (auto v : vars) - if (v != non_fixed) { - k *= val(v); - if (k.is_big()) return; - } - - if (non_fixed != null_lpvar) - m_monomial_bounds.propagate_nonfixed(monic_var, vars, non_fixed, k); - else // all variables are fixed - propagate_monic_with_all_fixed(monic_var, vars, k); - } - } - - void core::init_bound_propagation() { - m_implied_bounds.clear(); - m_improved_lower_bounds.reset(); - m_improved_upper_bounds.reset(); - m_column_types = &lra.get_column_types(); - m_lemmas.clear(); - // find m_monics_with_changed_bounds - for (lpvar j : lra.columns_with_changed_bounds()) { - if (is_monic_var(j)) - m_monics_with_changed_bounds.insert(j); - else { - for (const auto & m: m_emons.get_use_list(j)) { - m_monics_with_changed_bounds.insert(m.var()); - } - } - } - } -} // namespace nla diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index 76397d529..5a597ae67 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -44,7 +44,6 @@ bool try_insert(const A& elem, B& collection) { return true; } - class core { friend struct common; friend class new_lemma; @@ -86,9 +85,10 @@ class core { smt_params_helper m_params; std::function m_relevant; vector m_lemmas; - vector * m_literal_vec = nullptr; + vector m_literals; + vector m_equalities; + vector m_fixed_equalities; indexed_uint_set m_to_refine; - indexed_uint_set m_monics_with_changed_bounds; tangents m_tangents; basics m_basics; order m_order; @@ -97,16 +97,13 @@ class core { divisions m_divisions; intervals m_intervals; monomial_bounds m_monomial_bounds; - + unsigned m_conflicts; horner m_horner; grobner m_grobner; emonics m_emons; svector m_add_buffer; mutable indexed_uint_set m_active_var_set; - // these maps map a column index to the corresponding index in ibounds - u_map m_improved_lower_bounds; - u_map m_improved_upper_bounds; - const vector* m_column_types; + reslimit m_nra_lim; bool m_use_nra_model = false; @@ -114,17 +111,16 @@ class core { bool m_cautious_patching = true; lpvar m_patched_var = 0; monic const* m_patched_monic = nullptr; - bool_vector m_propagated; + void check_weighted(unsigned sz, std::pair>* checks); void add_bounds(); - std_vector & m_implied_bounds; // try to improve bounds for variables in monomials. bool improve_bounds(); - void clear_monics_with_changed_bounds() { m_monics_with_changed_bounds.reset(); } + public: // constructor - core(lp::lar_solver& s, params_ref const& p, reslimit&, std_vector & implied_bounds); - const auto& monics_with_changed_bounds() const { return m_monics_with_changed_bounds; } + core(lp::lar_solver& s, params_ref const& p, reslimit&); + void insert_to_refine(lpvar j); void erase_from_to_refine(lpvar j); @@ -314,7 +310,6 @@ public: bool sign_contradiction(const monic& m) const; bool var_is_fixed_to_zero(lpvar j) const; - bool fixed_var_has_big_bound(lpvar j) const; bool var_is_fixed_to_val(lpvar j, const rational& v) const; bool var_is_fixed(lpvar j) const; @@ -392,11 +387,13 @@ public: bool conflict_found() const; - lbool check(vector& ineqs); + lbool check(); lbool check_power(lpvar r, lpvar x, lpvar y); void check_bounded_divisions(); bool no_lemmas_hold() const; + + void propagate(); lbool test_check(); lpvar map_to_root(lpvar) const; @@ -432,26 +429,22 @@ public: void set_use_nra_model(bool m); bool use_nra_model() const { return m_use_nra_model; } void collect_statistics(::statistics&); + vector const& lemmas() const { return m_lemmas; } + vector const& literals() const { return m_literals; } + vector const& equalities() const { return m_equalities; } + vector const& fixed_equalities() const { return m_fixed_equalities; } - bool is_linear(const svector& m, lpvar& zero_var, lpvar& non_fixed); - void add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var); - void propagate_monic_non_fixed_with_lemma(lpvar monic_var, const svector& vars, lpvar non_fixed, const rational& k); - void propagate_monic_with_all_fixed(lpvar monic_var, const svector& vars, const rational& k); - void add_lower_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std::function explain_dep); - void add_upper_bound_monic(lpvar j, const lp::mpq& v, bool is_strict, std::function explain_dep); - bool upper_bound_is_available(unsigned j) const; - bool lower_bound_is_available(unsigned j) const; - vector const& lemmas() const { return m_lemmas; } - + void add_fixed_equality(lp::lpvar v, rational const& k, lp::explanation const& e) { m_fixed_equalities.push_back({v, k, e}); } + void add_equality(lp::lpvar i, lp::lpvar j, lp::explanation const& e) { m_equalities.push_back({i, j, e}); } private: - lp::column_type get_column_type(unsigned j) const { return (*m_column_types)[j]; } + void restore_patched_values(); void constrain_nl_in_tableau(); bool solve_tableau(); void restore_tableau(); void save_tableau(); bool integrality_holds(); - void calculate_implied_bounds_for_monic(lp::lpvar v); - void init_bound_propagation(); + + }; // end of core struct pp_mon { diff --git a/src/math/lp/nla_solver.cpp b/src/math/lp/nla_solver.cpp index 53d8b0da6..f4d09810e 100644 --- a/src/math/lp/nla_solver.cpp +++ b/src/math/lp/nla_solver.cpp @@ -42,10 +42,14 @@ namespace nla { bool solver::need_check() { return m_core->has_relevant_monomial(); } - lbool solver::check(vector& lits) { - return m_core->check(lits); + lbool solver::check() { + return m_core->check(); } + void solver::propagate() { + m_core->propagate(); + } + void solver::push(){ m_core->push(); } @@ -54,8 +58,8 @@ namespace nla { m_core->pop(n); } - solver::solver(lp::lar_solver& s, params_ref const& p, reslimit& limit, std_vector & implied_bounds): - m_core(alloc(core, s, p, limit, implied_bounds)) { + solver::solver(lp::lar_solver& s, params_ref const& p, reslimit& limit): + m_core(alloc(core, s, p, limit)) { } bool solver::influences_nl_var(lpvar j) const { @@ -88,9 +92,6 @@ namespace nla { m_core->collect_statistics(st); } - void solver::calculate_implied_bounds_for_monic(lp::lpvar v) { - m_core->calculate_implied_bounds_for_monic(v); - } // ensure r = x^y, add abstraction/refinement lemmas lbool solver::check_power(lpvar r, lpvar x, lpvar y) { return m_core->check_power(r, x, y); @@ -100,22 +101,20 @@ namespace nla { m_core->check_bounded_divisions(); } - void solver::init_bound_propagation() { - m_core->init_bound_propagation(); - } - vector const& solver::lemmas() const { return m_core->lemmas(); } - - void solver::propagate_bounds_for_touched_monomials() { - init_bound_propagation(); - for (unsigned v : m_core->monics_with_changed_bounds()) { - calculate_implied_bounds_for_monic(v); - if (m_core->lra.get_status() == lp::lp_status::INFEASIBLE) { - break; - } - } - m_core->clear_monics_with_changed_bounds(); + + vector const& solver::literals() const { + return m_core->literals(); } + + vector const& solver::equalities() const { + return m_core->equalities(); + } + + vector const& solver::fixed_equalities() const { + return m_core->fixed_equalities(); + } + } diff --git a/src/math/lp/nla_solver.h b/src/math/lp/nla_solver.h index acd724af9..fec27c32b 100644 --- a/src/math/lp/nla_solver.h +++ b/src/math/lp/nla_solver.h @@ -23,9 +23,10 @@ namespace nla { class solver { core* m_core; public: - - solver(lp::lar_solver& s, params_ref const& p, reslimit& limit, std_vector & implied_bounds); + + solver(lp::lar_solver& s, params_ref const& p, reslimit& limit); ~solver(); + void add_monic(lpvar v, unsigned sz, lpvar const* vs); void add_idivision(lpvar q, lpvar x, lpvar y); void add_rdivision(lpvar q, lpvar x, lpvar y); @@ -35,7 +36,7 @@ namespace nla { void push(); void pop(unsigned scopes); bool need_check(); - lbool check(vector& lits); + lbool check(); void propagate(); lbool check_power(lpvar r, lpvar x, lpvar y); bool is_monic_var(lpvar) const; @@ -46,9 +47,9 @@ namespace nla { nlsat::anum_manager& am(); nlsat::anum const& am_value(lp::var_index v) const; void collect_statistics(::statistics & st); - void calculate_implied_bounds_for_monic(lp::lpvar v); - void init_bound_propagation(); - vector const& lemmas() const; - void propagate_bounds_for_touched_monomials(); + vector const& lemmas() const; + vector const& literals() const; + vector const& fixed_equalities() const; + vector const& equalities() const; }; } diff --git a/src/math/lp/nla_types.h b/src/math/lp/nla_types.h index 186c2e902..3930a62a9 100644 --- a/src/math/lp/nla_types.h +++ b/src/math/lp/nla_types.h @@ -24,6 +24,20 @@ namespace nla { typedef lp::explanation expl_set; typedef lp::var_index lpvar; const lpvar null_lpvar = UINT_MAX; + + struct equality { + lp::lpvar i, j; + lp::explanation e; + equality(lp::lpvar i, lp::lpvar j, lp::explanation const& e):i(i),j(j),e(e) {} + }; + + struct fixed_equality { + lp::lpvar v; + rational k; + lp::explanation e; + fixed_equality(lp::lpvar v, rational const& k, lp::explanation const& e):v(v),k(k),e(e) {} + }; + inline int rat_sign(const rational& r) { return r.is_pos()? 1 : ( r.is_neg()? -1 : 0); } inline rational rrat_sign(const rational& r) { return rational(rat_sign(r)); } @@ -83,7 +97,6 @@ namespace nla { new_lemma& operator&=(const factorization& f); new_lemma& operator&=(lpvar j); new_lemma& operator|=(ineq const& i); - new_lemma& operator+=(ineq const& i); new_lemma& explain_fixed(lpvar j); new_lemma& explain_equiv(lpvar u, lpvar v); new_lemma& explain_var_separated_from_zero(lpvar j); diff --git a/src/sat/smt/arith_internalize.cpp b/src/sat/smt/arith_internalize.cpp index 5893c8520..3174ad775 100644 --- a/src/sat/smt/arith_internalize.cpp +++ b/src/sat/smt/arith_internalize.cpp @@ -61,7 +61,7 @@ namespace arith { void solver::ensure_nla() { if (!m_nla) { - m_nla = alloc(nla::solver, *m_solver.get(), s().params(), m.limit(), m_implied_bounds); + m_nla = alloc(nla::solver, *m_solver.get(), s().params(), m.limit()); for (auto const& _s : m_scopes) { (void)_s; m_nla->push(); diff --git a/src/sat/smt/arith_solver.cpp b/src/sat/smt/arith_solver.cpp index 893fe4a43..17ab03ee6 100644 --- a/src/sat/smt/arith_solver.cpp +++ b/src/sat/smt/arith_solver.cpp @@ -253,7 +253,7 @@ namespace arith { first = false; reset_evidence(); m_explanation.clear(); - be.explain_implied(); + lp().explain_implied_bound(be, m_bp); } CTRACE("arith", m_unassigned_bounds[v] == 0, tout << "missed bound\n";); updt_unassigned_bounds(v, -1); @@ -1416,7 +1416,7 @@ namespace arith { } void solver::assume_literals() { - for (auto const& ineq : m_nla_literals) { + for (auto const& ineq : m_nla->literals()) { auto lit = mk_ineq_literal(ineq); ctx.mark_relevant(lit); s().set_phase(lit); @@ -1459,7 +1459,7 @@ namespace arith { return l_true; m_a1 = nullptr; m_a2 = nullptr; - lbool r = m_nla->check(m_nla_literals); + lbool r = m_nla->check(); switch (r) { case l_false: assume_literals(); diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 53b49a658..801eb474c 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -249,7 +249,6 @@ namespace arith { // lemmas lp::explanation m_explanation; - vector m_nla_literals; literal_vector m_core, m_core2; vector m_coeffs; svector m_eqs; diff --git a/src/sat/smt/euf_proof_checker.cpp b/src/sat/smt/euf_proof_checker.cpp index a538b2a80..42cda4bfb 100644 --- a/src/sat/smt/euf_proof_checker.cpp +++ b/src/sat/smt/euf_proof_checker.cpp @@ -501,8 +501,9 @@ namespace euf { for (expr* arg : clause) std::cout << "\n " << mk_bounded_pp(arg, m); std::cout << ")\n"; + std::cout.flush(); - if (is_rup(proof_hint)) + if (false && is_rup(proof_hint)) diagnose_rup_failure(clause); add_clause(clause); @@ -527,9 +528,6 @@ namespace euf { for (expr* f : core) std::cout << mk_pp(f, m) << "\n"; } - SASSERT(false); - - exit(0); } void smt_proof_checker::collect_statistics(statistics& st) const { diff --git a/src/smt/params/smt_params_helper.pyg b/src/smt/params/smt_params_helper.pyg index fca7fcacf..9fcda7f64 100644 --- a/src/smt/params/smt_params_helper.pyg +++ b/src/smt/params/smt_params_helper.pyg @@ -71,8 +71,6 @@ def_module_params(module_name='smt', ('arith.nl.grobner_row_length_limit', UINT, 10, 'row is disregarded by the heuristic if its length is longer than the value'), ('arith.nl.grobner_frequency', UINT, 4, 'grobner\'s call frequency'), ('arith.nl.grobner', BOOL, True, 'run grobner\'s basis heuristic'), - ('arith.nl.use_lemmas_in_unit_prop', BOOL, False, 'use lemmas in monomial unit propagation'), - ('arith.nl.throttle_unit_prop', BOOL, True, 'unit propogate a monomial only once per scope'), ('arith.nl.grobner_eqs_growth', UINT, 10, 'grobner\'s number of equalities growth '), ('arith.nl.grobner_expr_size_growth', UINT, 2, 'grobner\'s maximum expr size growth'), ('arith.nl.grobner_expr_degree_growth', UINT, 2, 'grobner\'s maximum expr degree growth'), diff --git a/src/smt/smt_clause_proof.cpp b/src/smt/smt_clause_proof.cpp index 777961334..bf27777c4 100644 --- a/src/smt/smt_clause_proof.cpp +++ b/src/smt/smt_clause_proof.cpp @@ -90,14 +90,14 @@ namespace smt { return proof_ref(m); } - void clause_proof::add(clause& c) { + void clause_proof::add(clause& c, literal_buffer const* simp_lits) { if (!is_enabled()) return; justification* j = c.get_justification(); auto st = kind2st(c.get_kind()); auto pr = justification2proof(st, j); CTRACE("mk_clause", pr.get(), tout << mk_bounded_pp(pr, m, 4) << "\n";); - update(c, st, pr); + update(c, st, pr, simp_lits); } void clause_proof::add(unsigned n, literal const* lits, clause_kind k, justification* j) { @@ -137,12 +137,15 @@ namespace smt { update(st, m_lits, pr); } - void clause_proof::add(literal lit1, literal lit2, clause_kind k, justification* j) { + void clause_proof::add(literal lit1, literal lit2, clause_kind k, justification* j, literal_buffer const* simp_lits) { if (!is_enabled()) return; m_lits.reset(); m_lits.push_back(ctx.literal2expr(lit1)); m_lits.push_back(ctx.literal2expr(lit2)); + if (simp_lits) + for (auto lit : *simp_lits) + m_lits.push_back(ctx.literal2expr(~lit)); auto st = kind2st(k); auto pr = justification2proof(st, j); update(st, m_lits, pr); @@ -160,7 +163,7 @@ namespace smt { } void clause_proof::del(clause& c) { - update(c, status::deleted, justification2proof(status::deleted, nullptr)); + update(c, status::deleted, justification2proof(status::deleted, nullptr), nullptr); } std::ostream& clause_proof::display_literals(std::ostream& out, expr_ref_vector const& v) { @@ -190,7 +193,9 @@ namespace smt { if (ctx.get_fparams().m_clause_proof) m_trail.push_back(info(st, v, p)); if (m_on_clause_eh) - m_on_clause_eh(m_on_clause_ctx, p, 0, nullptr, v.size(), v.data()); + m_on_clause_eh(m_on_clause_ctx, p, 0, nullptr, v.size(), v.data()); + static unsigned s_count = 0; + if (m_has_log) { init_pp_out(); auto& out = *m_pp_out; @@ -220,12 +225,15 @@ namespace smt { } } - void clause_proof::update(clause& c, status st, proof* p) { + void clause_proof::update(clause& c, status st, proof* p, literal_buffer const* simp_lits) { if (!is_enabled()) return; m_lits.reset(); for (literal lit : c) - m_lits.push_back(ctx.literal2expr(lit)); + m_lits.push_back(ctx.literal2expr(lit)); + if (simp_lits) + for (auto lit : *simp_lits) + m_lits.push_back(ctx.literal2expr(~lit)); update(st, m_lits, p); } diff --git a/src/smt/smt_clause_proof.h b/src/smt/smt_clause_proof.h index 1c5931136..d7cc421cf 100644 --- a/src/smt/smt_clause_proof.h +++ b/src/smt/smt_clause_proof.h @@ -68,7 +68,7 @@ namespace smt { void init_pp_out(); void update(status st, expr_ref_vector& v, proof* p); - void update(clause& c, status st, proof* p); + void update(clause& c, status st, proof* p, literal_buffer const* simp_lits); status kind2st(clause_kind k); proof_ref justification2proof(status st, justification* j); void log(status st, proof* p); @@ -79,8 +79,8 @@ namespace smt { clause_proof(context& ctx); void shrink(clause& c, unsigned new_size); void add(literal lit, clause_kind k, justification* j); - void add(literal lit1, literal lit2, clause_kind k, justification* j); - void add(clause& c); + void add(literal lit1, literal lit2, clause_kind k, justification* j, literal_buffer const* simp_lits = nullptr); + void add(clause& c, literal_buffer const* simp_lits = nullptr); void add(unsigned n, literal const* lits, clause_kind k, justification* j); void propagate(literal lit, justification const& j, literal_vector const& ante); void del(clause& c); diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index d075c0652..2561fbb5a 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -601,6 +601,7 @@ namespace smt { finalize_resolve(conflict, not_l); + return true; } diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index 0e9e39996..b6d1e2f2b 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -1378,12 +1378,12 @@ namespace smt { clause * context::mk_clause(unsigned num_lits, literal * lits, justification * j, clause_kind k, clause_del_eh * del_eh) { TRACE("mk_clause", display_literals_verbose(tout << "creating clause: " << literal_vector(num_lits, lits) << "\n", num_lits, lits) << "\n";); m_clause_proof.add(num_lits, lits, k, j); + literal_buffer simp_lits; switch (k) { case CLS_TH_AXIOM: dump_axiom(num_lits, lits); Z3_fallthrough; case CLS_AUX: { - literal_buffer simp_lits; if (m_searching) dump_lemma(num_lits, lits); if (!simplify_aux_clause_literals(num_lits, lits, simp_lits)) { @@ -1451,7 +1451,7 @@ namespace smt { else if (get_assignment(l2) == l_false) { assign(l1, b_justification(~l2)); } - m_clause_proof.add(l1, l2, k, j); + m_clause_proof.add(l1, l2, k, j, &simp_lits); m_stats.m_num_mk_bin_clause++; return nullptr; } @@ -1464,7 +1464,7 @@ namespace smt { bool reinit = save_atoms; SASSERT(!lemma || j == 0 || !j->in_region()); clause * cls = clause::mk(m, num_lits, lits, k, j, del_eh, save_atoms, m_bool_var2expr.data()); - m_clause_proof.add(*cls); + m_clause_proof.add(*cls, &simp_lits); if (lemma) { cls->set_activity(activity); if (k == CLS_LEARNED) { diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index dd9ba2dfe..470ea5f7b 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -1535,7 +1535,8 @@ namespace smt { m_stats.m_max_min++; unsigned best_efforts = 0; bool inc = false; - + + SASSERT(!maintain_integrality || valid_assignment()); SASSERT(satisfy_bounds()); diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index ae0af89ec..0a2b6e938 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -765,10 +765,8 @@ typename theory_arith::numeral theory_arith::get_monomial_fixed_var_pr template expr * theory_arith::get_monomial_non_fixed_var(expr * m) const { SASSERT(is_pure_monomial(m)); - for (unsigned i = 0; i < to_app(m)->get_num_args(); i++) { - expr * arg = to_app(m)->get_arg(i); - theory_var _var = expr2var(arg); - if (!is_fixed(_var)) + for (expr* arg : *to_app(m)) { + if (!is_fixed(expr2var(arg))) return arg; } return nullptr; @@ -780,7 +778,7 @@ expr * theory_arith::get_monomial_non_fixed_var(expr * m) const { */ template bool theory_arith::propagate_linear_monomial(theory_var v) { - TRACE("non_linear", tout << "checking whether v" << v << " became linear...\n";); + TRACE("non_linear_verbose", tout << "checking whether v" << v << " became linear...\n";); if (m_data[v].m_nl_propagated) return false; // already propagated this monomial. expr * m = var2expr(v); @@ -819,6 +817,11 @@ bool theory_arith::propagate_linear_monomial(theory_var v) { ctx.mark_as_relevant(rhs); } TRACE("non_linear_bug", tout << "enode: " << ctx.get_enode(rhs) << " enode_id: " << ctx.get_enode(rhs)->get_owner_id() << "\n";); + IF_VERBOSE(3, + for (auto* arg : *to_app(m)) + if (is_fixed(expr2var(arg))) + verbose_stream() << mk_pp(arg, get_manager()) << " = " << -k << "\n"); + theory_var new_v = expr2var(rhs); SASSERT(new_v != null_theory_var); new_lower = alloc(derived_bound, new_v, inf_numeral(0), B_LOWER); @@ -906,7 +909,7 @@ bool theory_arith::propagate_linear_monomials() { return false; if (!reflection_enabled()) return false; - TRACE("non_linear", tout << "propagating linear monomials...\n";); + TRACE("non_linear_verbose", tout << "propagating linear monomials...\n";); bool p = false; // CMW: m_nl_monomials can grow during this loop, so // don't use iterators. diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 2a7412c29..a5c5084ab 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -264,7 +264,7 @@ class theory_lra::imp { void ensure_nla() { if (!m_nla) { - m_nla = alloc(nla::solver, *m_solver.get(), ctx().get_params(), m.limit(), m_implied_bounds); + m_nla = alloc(nla::solver, *m_solver.get(), ctx().get_params(), m.limit()); for (auto const& _s : m_scopes) { (void)_s; m_nla->push(); @@ -1528,14 +1528,12 @@ public: unsigned old_sz = m_assume_eq_candidates.size(); unsigned num_candidates = 0; int start = ctx().get_random_value(); - unsigned num_relevant = 0; for (theory_var i = 0; i < sz; ++i) { theory_var v = (i + start) % sz; enode* n1 = get_enode(v); if (!th.is_relevant_and_shared(n1)) { continue; } - ++num_relevant; ensure_column(v); if (!is_registered_var(v)) continue; @@ -1553,7 +1551,7 @@ public: num_candidates++; } } - + if (num_candidates > 0) { ctx().push_trail(restore_vector(m_assume_eq_candidates, old_sz)); } @@ -1605,8 +1603,7 @@ public: case l_true: return FC_DONE; case l_false: - for (const nla::lemma & l : m_nla->lemmas()) - false_case_of_check_nla(l); + add_lemmas(); return FC_CONTINUE; case l_undef: return FC_GIVEUP; @@ -1803,8 +1800,7 @@ public: if (!m_nla) return true; m_nla->check_bounded_divisions(); - for (auto & lemma : m_nla->lemmas()) - false_case_of_check_nla(lemma); + add_lemmas(); return m_nla->lemmas().empty(); } @@ -2003,7 +1999,7 @@ public: // create term >= 0 (or term <= 0) atom = mk_bound(ineq.term(), ineq.rs(), is_lower); return literal(ctx().get_bool_var(atom), pos); - } + } void false_case_of_check_nla(const nla::lemma & l) { m_lemma = l; //todo avoid the copy @@ -2024,14 +2020,11 @@ public: final_check_status check_nla_continue() { m_a1 = nullptr; m_a2 = nullptr; - lbool r = m_nla->check(m_nla_literals); + lbool r = m_nla->check(); switch (r) { case l_false: - for (const nla::ineq& i : m_nla_literals) - assume_literal(i); - for (const nla::lemma & l : m_nla->lemmas()) - false_case_of_check_nla(l); + add_lemmas(); return FC_CONTINUE; case l_true: return assume_eqs()? FC_CONTINUE: FC_DONE; @@ -2120,6 +2113,8 @@ public: bool propagate_core() { m_model_is_initialized = false; flush_bound_axioms(); + // disabled in master: + propagate_nla(); if (!can_propagate_core()) return false; m_new_def = false; @@ -2151,7 +2146,6 @@ public: break; case l_true: propagate_basic_bounds(); - propagate_bounds_with_nlp(); propagate_bounds_with_lp_solver(); break; case l_undef: @@ -2161,6 +2155,47 @@ public: return true; } + void propagate_nla() { + if (m_nla) { + m_nla->propagate(); + add_lemmas(); + add_equalities(); + } + } + + void add_equalities() { + if (!propagate_eqs()) + return; + for (auto const& [v,k,e] : m_nla->fixed_equalities()) + add_equality(v, k, e); + for (auto const& [i,j,e] : m_nla->equalities()) + add_eq(i,j,e,false); + } + + void add_equality(lpvar j, rational const& k, lp::explanation const& exp) { + //verbose_stream() << "equality " << j << " " << k << "\n"; + TRACE("arith", tout << "equality " << j << " " << k << "\n"); + theory_var v; + if (k == 1) + v = m_one_var; + else if (k == 0) + v = m_zero_var; + else if (!m_value2var.find(k, v)) + return; + theory_var w = lp().local_to_external(j); + if (w < 0) + return; + lpvar i = register_theory_var_in_lar_solver(v); + add_eq(i, j, exp, true); + } + + void add_lemmas() { + for (const nla::ineq& i : m_nla->literals()) + assume_literal(i); + for (const nla::lemma & l : m_nla->lemmas()) + false_case_of_check_nla(l); + } + bool should_propagate() const { return bound_prop_mode::BP_NONE != propagation_mode(); } @@ -2173,50 +2208,33 @@ public: set_evidence(j, m_core, m_eqs); m_explanation.add_pair(j, v); } + + void propagate_bounds_with_lp_solver() { + if (!should_propagate()) + return; + + m_bp.init(); + lp().propagate_bounds_for_touched_rows(m_bp); + + if (!m.inc()) + return; - void finish_bound_propagation() { if (is_infeasible()) { get_infeasibility_explanation_and_set_conflict(); // verbose_stream() << "unsat\n"; } else { - for (auto &ib : m_bp.ibounds()) { + unsigned count = 0, prop = 0; + for (auto& ib : m_bp.ibounds()) { m.inc(); if (ctx().inconsistent()) break; - propagate_lp_solver_bound(ib); + ++prop; + count += propagate_lp_solver_bound(ib); } } } - void propagate_bounds_with_lp_solver() { - if (!should_propagate()) - return; - m_bp.init(); - lp().propagate_bounds_for_touched_rows(m_bp); - - if (m.inc()) - finish_bound_propagation(); - } - - void propagate_bounds_for_monomials() { - m_nla->propagate_bounds_for_touched_monomials(); - for (const auto & l : m_nla->lemmas()) - false_case_of_check_nla(l); - } - - void propagate_bounds_with_nlp() { - if (!m_nla) - return; - if (is_infeasible() || !should_propagate()) - return; - - propagate_bounds_for_monomials(); - - if (m.inc()) - finish_bound_propagation(); - } - bool bound_is_interesting(unsigned vi, lp::lconstraint_kind kind, const rational & bval) const { theory_var v = lp().local_to_external(vi); if (v == null_theory_var) @@ -3161,8 +3179,7 @@ public: std::function fn = [&]() { return m.mk_eq(x->get_expr(), y->get_expr()); }; scoped_trace_stream _sts(th, fn); - - // SASSERT(validate_eq(x, y)); + //VERIFY(validate_eq(x, y)); ctx().assign_eq(x, y, eq_justification(js)); } @@ -3206,12 +3223,11 @@ public: } lp::explanation m_explanation; - vector m_nla_literals; literal_vector m_core; svector m_eqs; vector m_params; - void reset_evidence() { + void reset_evidence() { m_core.reset(); m_eqs.reset(); m_params.reset(); @@ -3278,6 +3294,7 @@ public: display(tout << "is-conflict: " << is_conflict << "\n");); for (auto ev : m_explanation) set_evidence(ev.ci(), m_core, m_eqs); + // SASSERT(validate_conflict(m_core, m_eqs)); if (is_conflict) { @@ -3533,6 +3550,8 @@ public: lbool r = nctx.check(); if (r == l_true) { nctx.display_asserted_formulas(std::cout); + std::cout.flush(); + std::cout.flush(); } return l_true != r; } @@ -3882,6 +3901,7 @@ public: IF_VERBOSE(1, verbose_stream() << enode_pp(n, ctx()) << " evaluates to " << r2 << " but arith solver has " << r1 << "\n"); } } + }; theory_lra::theory_lra(context& ctx): From 00ba064cd3735ef8035edbbde4be7a0d71b4104c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 3 Oct 2023 14:28:59 +0900 Subject: [PATCH 59/69] ensure bounds propagation on changed columns after nla propagation Signed-off-by: Nikolaj Bjorner --- src/math/lp/lar_solver.cpp | 2 ++ src/smt/theory_lra.cpp | 11 ++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 729b5865e..4049d7204 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -1067,6 +1067,8 @@ namespace lp { } bool lar_solver::init_model() const { + CTRACE("lar_solver_model",!m_columns_with_changed_bounds.empty(), tout << "non-empty changed bounds\n"); + TRACE("lar_solver_model", tout << get_status() << "\n"); if (get_status() != lp_status::OPTIMAL && get_status() != lp_status::FEASIBLE) return false; if (!m_columns_with_changed_bounds.empty()) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index a5c5084ab..b746a88bf 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2115,8 +2115,9 @@ public: flush_bound_axioms(); // disabled in master: propagate_nla(); - if (!can_propagate_core()) + if (!can_propagate_core()) return false; + m_new_def = false; while (m_asserted_qhead < m_asserted_atoms.size() && !ctx().inconsistent() && m.inc()) { auto [bv, is_true] = m_asserted_atoms[m_asserted_qhead]; @@ -2160,6 +2161,7 @@ public: m_nla->propagate(); add_lemmas(); add_equalities(); + propagate_bounds_with_lp_solver(); } } @@ -2210,9 +2212,6 @@ public: } void propagate_bounds_with_lp_solver() { - if (!should_propagate()) - return; - m_bp.init(); lp().propagate_bounds_for_touched_rows(m_bp); @@ -2224,13 +2223,11 @@ public: // verbose_stream() << "unsat\n"; } else { - unsigned count = 0, prop = 0; for (auto& ib : m_bp.ibounds()) { m.inc(); if (ctx().inconsistent()) break; - ++prop; - count += propagate_lp_solver_bound(ib); + propagate_lp_solver_bound(ib); } } } From a88aa7ffa51769e607c5a6a9384a4f34f2320b74 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 3 Oct 2023 16:25:49 -0700 Subject: [PATCH 60/69] debug new propagation scheme Signed-off-by: Lev Nachmanson --- src/math/lp/lar_solver.cpp | 4 +++- src/math/lp/lar_solver.h | 3 ++- src/math/lp/monomial_bounds.cpp | 6 +++--- src/smt/theory_lra.cpp | 4 ++++ 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 4049d7204..43acce576 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -1822,6 +1822,7 @@ namespace lp { if (is_base(j) && column_is_fixed(j)) m_fixed_base_var_set.insert(j); + track_column_feasibility(j); TRACE("lar_solver_feas", tout << "j = " << j << " became " << (this->column_is_feasible(j) ? "feas" : "non-feas") << ", and " << (this->column_is_bounded(j) ? "bounded" : "non-bounded") << " val = " << get_column_value(j) << std::endl;); } @@ -2359,7 +2360,8 @@ namespace lp { // dep is the reason for the new bound void lar_solver::set_crossed_bounds_column_and_deps(unsigned j, bool lower_bound, u_dependency* dep) { - SASSERT(m_crossed_bounds_deps == nullptr && m_crossed_bounds_deps == nullptr); + if (m_crossed_bounds_column != null_lpvar) return; // already set + SASSERT(m_crossed_bounds_deps == nullptr); set_status(lp_status::INFEASIBLE); m_crossed_bounds_column = j; const auto& ul = this->m_columns_to_ul_pairs()[j]; diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 0748d2507..9b0dd8381 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -152,7 +152,8 @@ public: lpvar crossed_bounds_column() const { return m_crossed_bounds_column; } lpvar& crossed_bounds_column() { return m_crossed_bounds_column; } - + bool current_x_is_feasible() const { return m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible(); } + private: void update_column_type_and_bound_check_on_equal(unsigned j, const mpq& right_side, constraint_index ci, unsigned&); diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index 8bb6ab306..0e4a5041e 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -311,8 +311,8 @@ namespace nla { c().lra.update_column_type_and_bound(m.var(), lp::lconstraint_kind::EQ, k, dep); // propagate fixed equality - auto exp = get_explanation(dep); - c().add_fixed_equality(m.var(), k, exp); + auto exp = get_explanation(dep); + c().add_fixed_equality(c().lra.column_to_reported_index(m.var()), k, exp); } void monomial_bounds::propagate_nonfixed(monic const& m, rational const& k, lpvar w) { @@ -327,7 +327,7 @@ namespace nla { if (k == 1) { lp::explanation exp = get_explanation(dep); - c().add_equality(m.var(), w, exp); + c().add_equality(c().lra.column_to_reported_index(m.var()), c().lra.column_to_reported_index(w), exp); } } diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index b746a88bf..7f7951b20 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2212,6 +2212,10 @@ public: } void propagate_bounds_with_lp_solver() { + if (!lp().current_x_is_feasible()) { + lp().clear_columns_with_changed_bounds(); + return; + } m_bp.init(); lp().propagate_bounds_for_touched_rows(m_bp); From edd1761ff3c3bfbaff638526e3e78e97a20188e4 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 4 Oct 2023 11:06:24 -0700 Subject: [PATCH 61/69] restore the scheme of m_columns_with_changed_bounds Signed-off-by: Lev Nachmanson --- src/math/lp/lar_solver.cpp | 20 ++++++++++++++------ src/math/lp/lar_solver.h | 25 +++++++++---------------- src/math/lp/monomial_bounds.cpp | 10 ++++++---- src/math/lp/monomial_bounds.h | 2 +- src/math/lp/nla_core.cpp | 13 +++++++++++++ src/math/lp/nla_core.h | 3 ++- src/math/lp/nla_solver.h | 2 +- src/smt/theory_lra.cpp | 6 +----- 8 files changed, 47 insertions(+), 34 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 43acce576..d47447b55 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -204,6 +204,12 @@ namespace lp { return m_status; solve_with_core_solver(); + if (m_status != lp_status::INFEASIBLE) { + if (m_settings.bound_propagation()) + detect_rows_with_changed_bounds(); + } + + clear_columns_with_changed_bounds(); return m_status; } @@ -478,7 +484,6 @@ namespace lp { x = new_val; TRACE("lar_solver_feas", tout << "setting " << j << " to " << new_val << (column_is_feasible(j)?"feas":"non-feas") << "\n";); - m_mpq_lar_core_solver.m_r_solver.track_column_feasibility(j); change_basic_columns_dependend_on_a_given_nb_column(j, delta); } @@ -786,7 +791,8 @@ namespace lp { void lar_solver::detect_rows_with_changed_bounds() { for (auto j : m_columns_with_changed_bounds) detect_rows_with_changed_bounds_for_column(j); - + if (m_find_monics_with_changed_bounds_func) + m_find_monics_with_changed_bounds_func(m_columns_with_changed_bounds); } void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds_tableau() { @@ -1106,6 +1112,7 @@ namespace lp { mpq lar_solver::get_value(column_index const& j) const { SASSERT(get_status() == lp_status::OPTIMAL || get_status() == lp_status::FEASIBLE); + SASSERT(m_columns_with_changed_bounds.empty()); numeric_pair const& rp = get_column_value(j); return from_model_in_impq_to_mpq(rp); } @@ -1822,8 +1829,7 @@ namespace lp { if (is_base(j) && column_is_fixed(j)) m_fixed_base_var_set.insert(j); - track_column_feasibility(j); - TRACE("lar_solver_feas", tout << "j = " << j << " became " << (this->column_is_feasible(j) ? "feas" : "non-feas") << ", and " << (this->column_is_bounded(j) ? "bounded" : "non-bounded") << " val = " << get_column_value(j) << std::endl;); + TRACE("lar_solver_feas", tout << "j = " << j << " became " << (this->column_is_feasible(j) ? "feas" : "non-feas") << ", and " << (this->column_is_bounded(j) ? "bounded" : "non-bounded") << std::endl;); } void lar_solver::insert_to_columns_with_changed_bounds(unsigned j) { @@ -2370,10 +2376,12 @@ namespace lp { m_crossed_bounds_deps = m_dependencies.mk_join(bdep, dep); } - void lar_solver::track_column_feasibility(lpvar j) { - m_mpq_lar_core_solver.m_r_solver.track_column_feasibility(j); + void lar_solver::collect_more_rows_for_lp_propagation(){ + for (auto j : m_columns_with_changed_bounds) + detect_rows_with_changed_bounds_for_column(j); } + } // namespace lp diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 9b0dd8381..298d1f879 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -89,13 +89,6 @@ class lar_solver : public column_namer { constraint_set m_constraints; // the set of column indices j such that bounds have changed for j indexed_uint_set m_columns_with_changed_bounds; -public: - const indexed_uint_set& columns_with_changed_bounds() const { return m_columns_with_changed_bounds; } - inline void clear_columns_with_changed_bounds() { m_columns_with_changed_bounds.reset(); } - void track_column_feasibility(lpvar j); - -private: - // m_touched_rows contains rows that have been changed by a pivoting or have a column with changed bounds indexed_uint_set m_touched_rows; unsigned_vector m_row_bounds_to_replay; u_dependency_manager m_dependencies; @@ -145,22 +138,23 @@ private: void add_row_from_term_no_constraint(const lar_term* term, unsigned term_ext_index); void add_basic_var_to_core_fields(); bool compare_values(impq const& lhs, lconstraint_kind k, const mpq& rhs); -public: + + inline void clear_columns_with_changed_bounds() { m_columns_with_changed_bounds.reset(); } + public: void insert_to_columns_with_changed_bounds(unsigned j); const u_dependency* crossed_bounds_deps() const { return m_crossed_bounds_deps;} u_dependency*& crossed_bounds_deps() { return m_crossed_bounds_deps;} lpvar crossed_bounds_column() const { return m_crossed_bounds_column; } lpvar& crossed_bounds_column() { return m_crossed_bounds_column; } - bool current_x_is_feasible() const { return m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible(); } - + -private: + private: void update_column_type_and_bound_check_on_equal(unsigned j, const mpq& right_side, constraint_index ci, unsigned&); void update_column_type_and_bound(unsigned j, const mpq& right_side, constraint_index ci); -public: + public: void update_column_type_and_bound(unsigned j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); -private: + private: void update_column_type_and_bound_with_ub(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); void update_column_type_and_bound_with_no_ub(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); void update_bound_with_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep); @@ -364,8 +358,6 @@ private: void add_column_rows_to_touched_rows(lpvar j); template void propagate_bounds_for_touched_rows(lp_bound_propagator& bp) { - detect_rows_with_changed_bounds(); - clear_columns_with_changed_bounds(); if (settings().propagate_eqs()) { if (settings().random_next() % 10 == 0) remove_fixed_vars_from_base(); @@ -386,7 +378,7 @@ private: } m_touched_rows.reset(); } - + void collect_more_rows_for_lp_propagation(); template void check_missed_propagations(lp_bound_propagator& bp) { for (unsigned i = 0; i < A_r().row_count(); i++) @@ -696,6 +688,7 @@ private: return 0; return m_usage_in_terms[j]; } + std::function m_find_monics_with_changed_bounds_func = nullptr; friend int_solver; friend int_branch; }; diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index 0e4a5041e..95f4586d8 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -260,8 +260,9 @@ namespace nla { } void monomial_bounds::unit_propagate() { - for (auto const& m : c().m_emons) { - unit_propagate(m); + for (lpvar v : c().m_monics_with_changed_bounds) { + if (!c().is_monic_var(v)) continue; + unit_propagate(c().emons()[v]); if (c().lra.get_status() == lp::lp_status::INFEASIBLE) { lp::explanation exp; c().lra.get_infeasibility_explanation(exp); @@ -276,14 +277,15 @@ namespace nla { } - void monomial_bounds::unit_propagate(monic const& m) { + void monomial_bounds::unit_propagate(monic & m) { if (m.is_propagated()) return; if (!is_linear(m)) return; - + c().emons().set_propagated(m); + rational k = fixed_var_product(m); lpvar w = non_fixed_var(m); if (w == null_lpvar || k == 0) { diff --git a/src/math/lp/monomial_bounds.h b/src/math/lp/monomial_bounds.h index 747aca9a2..a65ca7f4a 100644 --- a/src/math/lp/monomial_bounds.h +++ b/src/math/lp/monomial_bounds.h @@ -35,7 +35,7 @@ namespace nla { bool is_zero(lpvar v) const; // monomial propagation - void unit_propagate(monic const& m); + void unit_propagate(monic & m); bool is_linear(monic const& m); rational fixed_var_product(monic const& m); lpvar non_fixed_var(monic const& m); diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 6a241e951..2a23ba47b 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -41,6 +41,17 @@ core::core(lp::lar_solver& s, params_ref const& p, reslimit & lim) : m_nra(s, m_nra_lim, *this) { m_nlsat_delay = lp_settings().nlsat_delay(); + lra.m_find_monics_with_changed_bounds_func = [&](const indexed_uint_set& columns_with_changed_bounds) { + for (lpvar j : columns_with_changed_bounds) { + if (is_monic_var(j)) + m_monics_with_changed_bounds.insert(j); + else { + for (const auto & m: m_emons.get_use_list(j)) { + m_monics_with_changed_bounds.insert(m.var()); + } + } + } + }; } bool core::compare_holds(const rational& ls, llc cmp, const rational& rs) const { @@ -137,6 +148,7 @@ void core::add_monic(lpvar v, unsigned sz, lpvar const* vs) { m_add_buffer[i] = j; } m_emons.add(v, m_add_buffer); + m_monics_with_changed_bounds.insert(v); } void core::push() { @@ -1817,6 +1829,7 @@ bool core::improve_bounds() { void core::propagate() { clear(); m_monomial_bounds.unit_propagate(); + m_monics_with_changed_bounds.reset(); } diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index 5a597ae67..ae76f6d5a 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -89,6 +89,7 @@ class core { vector m_equalities; vector m_fixed_equalities; indexed_uint_set m_to_refine; + indexed_uint_set m_monics_with_changed_bounds; tangents m_tangents; basics m_basics; order m_order; @@ -120,7 +121,7 @@ class core { public: // constructor core(lp::lar_solver& s, params_ref const& p, reslimit&); - + const auto& monics_with_changed_bounds() const { return m_monics_with_changed_bounds; } void insert_to_refine(lpvar j); void erase_from_to_refine(lpvar j); diff --git a/src/math/lp/nla_solver.h b/src/math/lp/nla_solver.h index fec27c32b..c508e68d0 100644 --- a/src/math/lp/nla_solver.h +++ b/src/math/lp/nla_solver.h @@ -26,7 +26,7 @@ namespace nla { solver(lp::lar_solver& s, params_ref const& p, reslimit& limit); ~solver(); - + const auto& monics_with_changed_bounds() const { return m_core->monics_with_changed_bounds(); } void add_monic(lpvar v, unsigned sz, lpvar const* vs); void add_idivision(lpvar q, lpvar x, lpvar y); void add_rdivision(lpvar q, lpvar x, lpvar y); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 7f7951b20..e854db802 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2161,7 +2161,7 @@ public: m_nla->propagate(); add_lemmas(); add_equalities(); - propagate_bounds_with_lp_solver(); + lp().collect_more_rows_for_lp_propagation(); } } @@ -2212,10 +2212,6 @@ public: } void propagate_bounds_with_lp_solver() { - if (!lp().current_x_is_feasible()) { - lp().clear_columns_with_changed_bounds(); - return; - } m_bp.init(); lp().propagate_bounds_for_touched_rows(m_bp); From 45c0ed126e44bef4ff75d9179424f0c538a4f454 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 4 Oct 2023 17:39:22 -0700 Subject: [PATCH 62/69] remove unnecessery call Signed-off-by: Lev Nachmanson --- src/math/lp/lar_solver.cpp | 5 ++++- src/math/lp/lar_solver.h | 3 ++- src/math/lp/monomial_bounds.cpp | 10 +++++----- src/math/lp/monomial_bounds.h | 1 - src/smt/theory_lra.cpp | 2 -- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index d47447b55..05525c536 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -419,7 +419,9 @@ namespace lp { void lar_solver::move_non_basic_columns_to_bounds(bool shift_randomly) { auto& lcs = m_mpq_lar_core_solver; bool change = false; - for (unsigned j : lcs.m_r_nbasis) { + for (unsigned j : m_columns_with_changed_bounds) { + if (lcs.m_r_heading[j] >= 0) + continue; if (move_non_basic_column_to_bounds(j, shift_randomly)) change = true; } @@ -2374,6 +2376,7 @@ namespace lp { u_dependency* bdep = lower_bound? ul.lower_bound_witness() : ul.upper_bound_witness(); SASSERT(bdep != nullptr); m_crossed_bounds_deps = m_dependencies.mk_join(bdep, dep); + insert_to_columns_with_changed_bounds(j); } void lar_solver::collect_more_rows_for_lp_propagation(){ diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 298d1f879..09cb7796c 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -140,7 +140,8 @@ class lar_solver : public column_namer { bool compare_values(impq const& lhs, lconstraint_kind k, const mpq& rhs); inline void clear_columns_with_changed_bounds() { m_columns_with_changed_bounds.reset(); } - public: + public: + const auto& columns_with_changed_bounds() const { return m_columns_with_changed_bounds; } void insert_to_columns_with_changed_bounds(unsigned j); const u_dependency* crossed_bounds_deps() const { return m_crossed_bounds_deps;} u_dependency*& crossed_bounds_deps() { return m_crossed_bounds_deps;} diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index 95f4586d8..1b46cdf6b 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -268,15 +268,14 @@ namespace nla { c().lra.get_infeasibility_explanation(exp); new_lemma lemma(c(), "propagate fixed - infeasible lra"); lemma &= exp; - return; + break; } if (c().m_conflicts > 0 ) { - return; + break; } } } - void monomial_bounds::unit_propagate(monic & m) { if (m.is_propagated()) return; @@ -288,9 +287,8 @@ namespace nla { rational k = fixed_var_product(m); lpvar w = non_fixed_var(m); - if (w == null_lpvar || k == 0) { + if (w == null_lpvar || k == 0) propagate_fixed(m, k); - } else propagate_nonfixed(m, k, w); } @@ -310,6 +308,7 @@ namespace nla { lp::impq val(k); c().lra.set_value_for_nbasic_column(m.var(), val); } + TRACE("nla_solver", tout << "propagate fixed " << m << " = " << k << "\n";); c().lra.update_column_type_and_bound(m.var(), lp::lconstraint_kind::EQ, k, dep); // propagate fixed equality @@ -325,6 +324,7 @@ namespace nla { lp::lpvar term_index = c().lra.add_term(coeffs, UINT_MAX); auto* dep = explain_fixed(m, k); term_index = c().lra.map_term_index_to_column_index(term_index); + TRACE("nla_solver", tout << "propagate nonfixed " << m << " = " << k << "\n";); c().lra.update_column_type_and_bound(term_index, lp::lconstraint_kind::EQ, mpq(0), dep); if (k == 1) { diff --git a/src/math/lp/monomial_bounds.h b/src/math/lp/monomial_bounds.h index a65ca7f4a..b2079b4f1 100644 --- a/src/math/lp/monomial_bounds.h +++ b/src/math/lp/monomial_bounds.h @@ -39,7 +39,6 @@ namespace nla { bool is_linear(monic const& m); rational fixed_var_product(monic const& m); lpvar non_fixed_var(monic const& m); - public: monomial_bounds(core* core); void propagate(); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index e854db802..40cecd321 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -3205,8 +3205,6 @@ public: lbool make_feasible() { TRACE("pcs", tout << lp().constraints();); TRACE("arith_verbose", tout << "before calling lp().find_feasible_solution()\n"; display(tout);); - // todo: remove later : debug!!!!! - lp().move_non_basic_columns_to_bounds(false); auto status = lp().find_feasible_solution(); TRACE("arith_verbose", display(tout);); if (lp().is_feasible()) From b61f4ac51f527416dc1a76ba1a76d1a55dfacec0 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 5 Oct 2023 07:50:13 -0700 Subject: [PATCH 63/69] merge changes from master Signed-off-by: Lev Nachmanson --- src/math/lp/lar_solver.cpp | 6 ++++-- src/smt/theory_lra.cpp | 7 ++++++- src/smt/theory_user_propagator.cpp | 7 +++---- src/solver/simplifier_solver.cpp | 20 ++++++++++++++++---- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 05525c536..55a1686fa 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -1077,12 +1077,14 @@ namespace lp { bool lar_solver::init_model() const { CTRACE("lar_solver_model",!m_columns_with_changed_bounds.empty(), tout << "non-empty changed bounds\n"); TRACE("lar_solver_model", tout << get_status() << "\n"); - if (get_status() != lp_status::OPTIMAL && get_status() != lp_status::FEASIBLE) + auto status = get_status(); + SASSERT((status != lp_status::OPTIMAL && status != lp_status::FEASIBLE) + || m_mpq_lar_core_solver.m_r_solver.calc_current_x_is_feasible_include_non_basis()); + if (status != lp_status::OPTIMAL && status != lp_status::FEASIBLE) return false; if (!m_columns_with_changed_bounds.empty()) return false; - lp_assert(m_mpq_lar_core_solver.m_r_solver.calc_current_x_is_feasible_include_non_basis()); m_delta = m_mpq_lar_core_solver.find_delta_for_strict_bounds(mpq(1)); unsigned j; unsigned n = m_mpq_lar_core_solver.m_r_x.size(); diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 40cecd321..db4dba137 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2115,6 +2115,9 @@ public: flush_bound_axioms(); // disabled in master: propagate_nla(); + if (ctx().inconsistent()) + return true; + if (!can_propagate_core()) return false; @@ -2212,6 +2215,9 @@ public: } void propagate_bounds_with_lp_solver() { + if (!should_propagate()) + return; + m_bp.init(); lp().propagate_bounds_for_touched_rows(m_bp); @@ -3546,7 +3552,6 @@ public: if (r == l_true) { nctx.display_asserted_formulas(std::cout); std::cout.flush(); - std::cout.flush(); } return l_true != r; } diff --git a/src/smt/theory_user_propagator.cpp b/src/smt/theory_user_propagator.cpp index 7c72419c1..6735272a1 100644 --- a/src/smt/theory_user_propagator.cpp +++ b/src/smt/theory_user_propagator.cpp @@ -62,8 +62,7 @@ void theory_user_propagator::add_expr(expr* term, bool ensure_enode) { enode* n = ensure_enode ? this->ensure_enode(e) : ctx.get_enode(e); if (is_attached_to_var(n)) return; - - + theory_var v = mk_var(n); m_var2expr.reserve(v + 1); m_var2expr[v] = term; @@ -146,7 +145,7 @@ final_check_status theory_user_propagator::final_check_eh() { return FC_DONE; force_push(); unsigned sz1 = m_prop.size(); - unsigned sz2 = m_expr2var.size(); + unsigned sz2 = get_num_vars(); try { m_final_eh(m_user_context, this); } @@ -157,7 +156,7 @@ final_check_status theory_user_propagator::final_check_eh() { propagate(); CTRACE("user_propagate", ctx.inconsistent(), tout << "inconsistent\n"); // check if it became inconsistent or something new was propagated/registered - bool done = (sz1 == m_prop.size()) && (sz2 == m_expr2var.size()) && !ctx.inconsistent(); + bool done = (sz1 == m_prop.size()) && (sz2 == get_num_vars()) && !ctx.inconsistent(); return done ? FC_DONE : FC_CONTINUE; } diff --git a/src/solver/simplifier_solver.cpp b/src/solver/simplifier_solver.cpp index 0c4c2a7b6..bac75f1e5 100644 --- a/src/solver/simplifier_solver.cpp +++ b/src/solver/simplifier_solver.cpp @@ -24,6 +24,7 @@ Author: #include "ast/rewriter/expr_safe_replace.h" #include "ast/simplifiers/dependent_expr_state.h" #include "ast/simplifiers/then_simplifier.h" +#include "ast/rewriter/th_rewriter.h" #include "solver/solver.h" #include "solver/simplifier_solver.h" #include "solver/solver_preprocess.h" @@ -62,7 +63,16 @@ class simplifier_solver : public solver { if (s.m.is_false(f)) s.set_inconsistent(); } - void replay(unsigned qhead, expr_ref_vector& assumptions) { m_reconstruction_trail.replay(qhead, assumptions, *this); } + void replay(unsigned qhead, expr_ref_vector& assumptions) { + m_reconstruction_trail.replay(qhead, assumptions, *this); + th_rewriter rw(s.m); + expr_ref tmp(s.m); + for (unsigned i = 0; i < assumptions.size(); ++i) { + tmp = assumptions.get(i); + rw(tmp); + assumptions[i] = tmp; + } + } void flatten_suffix() override { expr_mark seen; unsigned j = qhead(); @@ -109,15 +119,16 @@ class simplifier_solver : public solver { unsigned qhead = m_preprocess_state.qhead(); expr_ref_vector orig_assumptions(assumptions); m_core_replace.reset(); - if (qhead < m_fmls.size() || !assumptions.empty()) { - m_preprocess_state.replay(qhead, assumptions); - m_preprocess_state.freeze(assumptions); + if (qhead < m_fmls.size()) { m_preprocess.reduce(); if (!m.inc()) return; TRACE("solver", tout << "qhead " << qhead << "\n"; m_preprocess_state.display(tout)); m_preprocess_state.advance_qhead(); + } + if (!assumptions.empty()) { + m_preprocess_state.replay(m_preprocess_state.qhead(), assumptions); for (unsigned i = 0; i < assumptions.size(); ++i) m_core_replace.insert(assumptions.get(i), orig_assumptions.get(i)); } @@ -203,6 +214,7 @@ public: lbool check_sat_core(unsigned num_assumptions, expr* const* assumptions) override { expr_ref_vector _assumptions(m, num_assumptions, assumptions); flush(_assumptions); + TRACE("simplifier", tout << _assumptions); return s->check_sat_core(num_assumptions, _assumptions.data()); } From bf3817ef7c1fd7db29135e258683c90ec2e88835 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 5 Oct 2023 18:14:52 -0700 Subject: [PATCH 64/69] restore move_non_basic_to_bounds Signed-off-by: Lev Nachmanson --- src/math/lp/core_solver_pretty_printer_def.h | 6 ++++-- src/math/lp/lar_solver.cpp | 11 ++++++----- src/math/lp/lp_core_solver_base.h | 1 + src/util/heap.h | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/math/lp/core_solver_pretty_printer_def.h b/src/math/lp/core_solver_pretty_printer_def.h index b8048b241..cbe67ea36 100644 --- a/src/math/lp/core_solver_pretty_printer_def.h +++ b/src/math/lp/core_solver_pretty_printer_def.h @@ -279,10 +279,12 @@ template void core_solver_pretty_printer::print() print_row(i); } m_out << std::endl; - if (m_core_solver.inf_heap().size()) { - m_out << "inf columns: "; + if (!m_core_solver.inf_heap().empty()) { + m_out << "inf columns: size() = " << m_core_solver.inf_heap().size() << std::endl; print_vector(m_core_solver.inf_heap(), m_out); m_out << std::endl; + } else { + m_out << "inf columns: none\n"; } } diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 55a1686fa..931e74f57 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -181,7 +181,10 @@ namespace lp { lp_status lar_solver::get_status() const { return m_status; } - void lar_solver::set_status(lp_status s) { m_status = s; } + void lar_solver::set_status(lp_status s) { + TRACE("lar_solver", tout << "setting status to " << s << "\n";); + m_status = s; + } lp_status lar_solver::find_feasible_solution() { stats().m_make_feasible++; @@ -419,9 +422,7 @@ namespace lp { void lar_solver::move_non_basic_columns_to_bounds(bool shift_randomly) { auto& lcs = m_mpq_lar_core_solver; bool change = false; - for (unsigned j : m_columns_with_changed_bounds) { - if (lcs.m_r_heading[j] >= 0) - continue; + for (unsigned j : lcs.m_r_nbasis) { if (move_non_basic_column_to_bounds(j, shift_randomly)) change = true; } @@ -439,7 +440,7 @@ namespace lp { switch (lcs.m_column_types()[j]) { case column_type::boxed: { bool at_l = val == lcs.m_r_lower_bounds()[j]; - bool at_u = !at_l && (val == lcs.m_r_upper_bounds()[j]); + bool at_u = (!at_l && (val == lcs.m_r_upper_bounds()[j])); if (!at_l && !at_u) { if (m_settings.random_next() % 2) set_value_for_nbasic_column(j, lcs.m_r_lower_bounds()[j]); diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index 1d6634c06..2c0993d71 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -564,6 +564,7 @@ public: } void insert_column_into_inf_heap(unsigned j) { if (!m_inf_heap.contains(j)) { + m_inf_heap.reserve(j+1); m_inf_heap.insert(j); TRACE("lar_solver_inf_heap", tout << "insert into inf_heap j = " << j << "\n";); } diff --git a/src/util/heap.h b/src/util/heap.h index df67b31be..332f4e53e 100644 --- a/src/util/heap.h +++ b/src/util/heap.h @@ -159,7 +159,7 @@ public: } unsigned size() const { - return m_value2indices.size(); + return m_values.size() - 1; } void reserve(int s) { From f847d039bc4f6c79874727f6da6cb2ecc070211b Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Thu, 5 Oct 2023 20:57:54 -0700 Subject: [PATCH 65/69] use the simple version of move_non_basic_column_to_bounds --- src/math/lp/gomory.cpp | 2 +- src/math/lp/int_branch.cpp | 2 +- src/math/lp/int_cube.cpp | 2 +- src/math/lp/lar_solver.cpp | 50 +++++++++++++++++--------------------- src/math/lp/lar_solver.h | 4 +-- 5 files changed, 27 insertions(+), 33 deletions(-) diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp index 775025018..e4267cbd4 100644 --- a/src/math/lp/gomory.cpp +++ b/src/math/lp/gomory.cpp @@ -417,7 +417,7 @@ int gomory::find_basic_var() { } lia_move gomory::operator()() { - lra.move_non_basic_columns_to_bounds(true); + lra.move_non_basic_columns_to_bounds(); int j = find_basic_var(); if (j == -1) return lia_move::undef; diff --git a/src/math/lp/int_branch.cpp b/src/math/lp/int_branch.cpp index 4bfe2b827..d6262a4d0 100644 --- a/src/math/lp/int_branch.cpp +++ b/src/math/lp/int_branch.cpp @@ -24,7 +24,7 @@ namespace lp { int_branch::int_branch(int_solver& lia):lia(lia), lra(lia.lra) {} lia_move int_branch::operator()() { - lra.move_non_basic_columns_to_bounds(true); + lra.move_non_basic_columns_to_bounds(); int j = find_inf_int_base_column(); return j == -1? lia_move::sat : create_branch_on_column(j); } diff --git a/src/math/lp/int_cube.cpp b/src/math/lp/int_cube.cpp index da724a543..9ef9aa341 100644 --- a/src/math/lp/int_cube.cpp +++ b/src/math/lp/int_cube.cpp @@ -43,7 +43,7 @@ namespace lp { if (st != lp_status::FEASIBLE && st != lp_status::OPTIMAL) { TRACE("cube", tout << "cannot find a feasible solution";); lra.pop(); - lra.move_non_basic_columns_to_bounds(false); + lra.move_non_basic_columns_to_bounds(); // it can happen that we found an integer solution here return !lra.r_basis_has_inf_int()? lia_move::sat: lia_move::undef; } diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 931e74f57..c3f0cd771 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -402,7 +402,7 @@ namespace lp { void lar_solver::prepare_costs_for_r_solver(const lar_term& term) { TRACE("lar_solver", print_term(term, tout << "prepare: ") << "\n";); - move_non_basic_columns_to_bounds(false); + move_non_basic_columns_to_bounds(); auto& rslv = m_mpq_lar_core_solver.m_r_solver; lp_assert(costs_are_zeros_for_r_solver()); lp_assert(reduced_costs_are_zeroes_for_r_solver()); @@ -419,11 +419,11 @@ namespace lp { lp_assert(rslv.reduced_costs_are_correct_tableau()); } - void lar_solver::move_non_basic_columns_to_bounds(bool shift_randomly) { + void lar_solver::move_non_basic_columns_to_bounds() { auto& lcs = m_mpq_lar_core_solver; bool change = false; for (unsigned j : lcs.m_r_nbasis) { - if (move_non_basic_column_to_bounds(j, shift_randomly)) + if (move_non_basic_column_to_bounds(j)) change = true; } if (!change) @@ -434,46 +434,40 @@ namespace lp { find_feasible_solution(); } - bool lar_solver::move_non_basic_column_to_bounds(unsigned j, bool force_change) { + bool lar_solver::move_non_basic_column_to_bounds(unsigned j) { auto& lcs = m_mpq_lar_core_solver; auto& val = lcs.m_r_x[j]; switch (lcs.m_column_types()[j]) { case column_type::boxed: { - bool at_l = val == lcs.m_r_lower_bounds()[j]; - bool at_u = (!at_l && (val == lcs.m_r_upper_bounds()[j])); - if (!at_l && !at_u) { - if (m_settings.random_next() % 2) - set_value_for_nbasic_column(j, lcs.m_r_lower_bounds()[j]); - else - set_value_for_nbasic_column(j, lcs.m_r_upper_bounds()[j]); - return true; - } - else if (force_change && m_settings.random_next() % 3 == 0) { - set_value_for_nbasic_column(j, - at_l ? lcs.m_r_upper_bounds()[j] : lcs.m_r_lower_bounds()[j]); - return true; - } - break; - } - case column_type::lower_bound: + const auto& l = lcs.m_r_lower_bounds()[j]; + if (val == l || val == lcs.m_r_upper_bounds()[j]) return false; + set_value_for_nbasic_column(j, l); + return true; + } + + case column_type::lower_bound: { + const auto& l = lcs.m_r_lower_bounds()[j]; if (val != lcs.m_r_lower_bounds()[j]) { - set_value_for_nbasic_column(j, lcs.m_r_lower_bounds()[j]); + set_value_for_nbasic_column(j, l); return true; } - break; + return false; + } case column_type::fixed: - case column_type::upper_bound: - if (val != lcs.m_r_upper_bounds()[j]) { - set_value_for_nbasic_column(j, lcs.m_r_upper_bounds()[j]); + case column_type::upper_bound: { + const auto & u = lcs.m_r_upper_bounds()[j]; + if (val != u) { + set_value_for_nbasic_column(j, u); return true; } - break; + return false; + } case column_type::free_column: if (column_is_int(j) && !val.is_int()) { set_value_for_nbasic_column(j, impq(floor(val))); return true; } - break; + return false; default: SASSERT(false); } diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 09cb7796c..d902f9a3a 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -635,8 +635,8 @@ class lar_solver : public column_namer { return *m_terms[t.id()]; } lp_status find_feasible_solution(); - void move_non_basic_columns_to_bounds(bool); - bool move_non_basic_column_to_bounds(unsigned j, bool); + void move_non_basic_columns_to_bounds(); + bool move_non_basic_column_to_bounds(unsigned j); inline bool r_basis_has_inf_int() const { for (unsigned j : r_basis()) { if (column_is_int(j) && !column_value_is_int(j)) From a94a75459e7146d9f92ec960f59c681bfde0089b Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Fri, 6 Oct 2023 06:51:00 -0700 Subject: [PATCH 66/69] fixin nla_solver_test.cpp --- src/test/lp/nla_solver_test.cpp | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/test/lp/nla_solver_test.cpp b/src/test/lp/nla_solver_test.cpp index 4e1dde11a..fa5a29e99 100644 --- a/src/test/lp/nla_solver_test.cpp +++ b/src/test/lp/nla_solver_test.cpp @@ -169,8 +169,7 @@ void test_basic_lemma_for_mon_neutral_from_factors_to_monomial_0() { reslimit l; params_ref p; - std_vector ib; - solver nla(s, p, l, ib); + solver nla(s, p, l); svector v; v.push_back(lp_b);v.push_back(lp_d);v.push_back(lp_e); nla.add_monic(lp_bde, v.size(), v.begin()); v.clear(); @@ -247,8 +246,7 @@ void test_basic_lemma_for_mon_neutral_from_factors_to_monomial_1() { reslimit l; params_ref p; - std_vector ib; - solver nla(s, p, l, ib); + solver nla(s, p, l); svector v; v.push_back(lp_b);v.push_back(lp_d);v.push_back(lp_e); nla.add_monic(lp_bde, v.size(), v.begin()); @@ -319,8 +317,7 @@ void test_basic_lemma_for_mon_zero_from_factors_to_monomial() { reslimit l; params_ref p; - std_vector ib; - solver nla(s, p, l, ib); + solver nla(s, p, l); create_abcde(nla, lp_a, @@ -382,8 +379,7 @@ void test_basic_lemma_for_mon_zero_from_monomial_to_factors() { reslimit l; params_ref p; - std_vector ib; - solver nla(s, p, l, ib); + solver nla(s, p, l); // create monomial acd unsigned_vector vec; @@ -443,8 +439,7 @@ void test_basic_lemma_for_mon_neutral_from_monomial_to_factors() { reslimit l; params_ref p; - std_vector ib; - solver nla(s, p, l, ib); + solver nla(s, p, l); create_abcde(nla, lp_a, @@ -556,8 +551,7 @@ void test_basic_sign_lemma() { reslimit l; params_ref p; - std_vector ib; - solver nla(s, p, l, ib); + solver nla(s, p, l); // create monomial bde vector vec; @@ -822,8 +816,7 @@ void test_tangent_lemma_rat() { s_set_column_value_test(s, lp_ab, v); reslimit l; params_ref p; - std_vector ib; - solver nla(s, p, l, ib); + solver nla(s, p, l); // create monomial ab vector vec; vec.push_back(lp_a); @@ -850,8 +843,7 @@ void test_tangent_lemma_reg() { s_set_column_value_test(s, lp_ab, rational(11)); reslimit l; params_ref p; - std_vector ib; - solver nla(s, p, l, ib); + solver nla(s, p, l); // create monomial ab vector vec; vec.push_back(lp_a); From 54f7aac0bc51556906af6ef6c2e47e960c85055d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Oct 2023 17:18:26 +0900 Subject: [PATCH 67/69] column value is not necessarily at bounds --- src/math/lp/monomial_bounds.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index 1b46cdf6b..1571d6cbf 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -324,7 +324,7 @@ namespace nla { lp::lpvar term_index = c().lra.add_term(coeffs, UINT_MAX); auto* dep = explain_fixed(m, k); term_index = c().lra.map_term_index_to_column_index(term_index); - TRACE("nla_solver", tout << "propagate nonfixed " << m << " = " << k << "\n";); + TRACE("nla_solver", tout << "propagate nonfixed " << m << " = " << k << " " << w << "\n";); c().lra.update_column_type_and_bound(term_index, lp::lconstraint_kind::EQ, mpq(0), dep); if (k == 1) { @@ -370,8 +370,9 @@ namespace nla { rational monomial_bounds::fixed_var_product(monic const& m) { rational r(1); for (lpvar v : m) { + // VERIFY(!c().var_is_fixed(v) || c().lra.get_column_value(v).x == c().lra.get_lower_bound(v).x); if (c().var_is_fixed(v)) - r *= c().lra.get_column_value(v).x; + r *= c().lra.get_lower_bound(v).x; } return r; } From 3aac528aef172ef97b41a3be7cf574801e5d9358 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 8 Oct 2023 07:34:03 -0700 Subject: [PATCH 68/69] add a comment Signed-off-by: Lev Nachmanson --- src/math/lp/monomial_bounds.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index 1571d6cbf..b2e62073a 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -370,7 +370,7 @@ namespace nla { rational monomial_bounds::fixed_var_product(monic const& m) { rational r(1); for (lpvar v : m) { - // VERIFY(!c().var_is_fixed(v) || c().lra.get_column_value(v).x == c().lra.get_lower_bound(v).x); + // we have to use the column bounds here, because the value of the column value may be outside the bounds if (c().var_is_fixed(v)) r *= c().lra.get_lower_bound(v).x; } From 1ba0f5aba944a28342a12ea194c663449fec3366 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sun, 8 Oct 2023 10:16:40 -0700 Subject: [PATCH 69/69] cosmetic changes --- src/math/lp/lar_solver.cpp | 2 +- src/math/lp/monomial_bounds.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index c3f0cd771..ebe14e407 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -447,7 +447,7 @@ namespace lp { case column_type::lower_bound: { const auto& l = lcs.m_r_lower_bounds()[j]; - if (val != lcs.m_r_lower_bounds()[j]) { + if (val != l) { set_value_for_nbasic_column(j, l); return true; } diff --git a/src/math/lp/monomial_bounds.cpp b/src/math/lp/monomial_bounds.cpp index b2e62073a..81c00d2f0 100644 --- a/src/math/lp/monomial_bounds.cpp +++ b/src/math/lp/monomial_bounds.cpp @@ -370,7 +370,7 @@ namespace nla { rational monomial_bounds::fixed_var_product(monic const& m) { rational r(1); for (lpvar v : m) { - // we have to use the column bounds here, because the value of the column value may be outside the bounds + // we have to use the column bounds here, because the column value may be outside the bounds if (c().var_is_fixed(v)) r *= c().lra.get_lower_bound(v).x; }