diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 4b60d7d62..fc696d4b2 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -646,7 +646,6 @@ class lar_solver : public column_namer { inline const static_matrix& A_r() const { return m_mpq_lar_core_solver.m_r_A; } // columns bool column_is_int(column_index const& j) const { return column_is_int((unsigned)j); } - // const impq& get_ivalue(column_index const& j) const { return get_column_value(j); } const impq& get_column_value(column_index const& j) const { return m_mpq_lar_core_solver.m_r_x[j]; } inline var_index external_to_local(unsigned j) const { var_index local_j; diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp index 61afa8859..76241786d 100644 --- a/src/math/lp/nla_core.cpp +++ b/src/math/lp/nla_core.cpp @@ -1574,10 +1574,10 @@ lbool core::check(vector& lits, vector& l_vec) { if (no_effect()) m_divisions.check(); - if (!conflict_found() && !done() && run_bounded_nlsat) + if (no_effect() && run_bounded_nlsat) ret = bounded_nlsat(); - if (l_vec.empty() && !done() && ret == l_undef) { + if (no_effect() && ret == l_undef) { std::function check1 = [&]() { m_order.order_lemma(); }; std::function check2 = [&]() { m_monotone.monotonicity_lemma(); }; std::function check3 = [&]() { m_tangents.tangent_lemma(); }; @@ -1593,7 +1593,7 @@ lbool core::check(vector& lits, vector& l_vec) { ret = bounded_nlsat(); } - if (l_vec.empty() && !done() && params().arith_nl_nra() && ret == l_undef) { + if (no_effect() && params().arith_nl_nra() && ret == l_undef) { ret = m_nra.check(); m_stats.m_nra_calls++; } @@ -1811,6 +1811,46 @@ bool core::improve_bounds() { return bounds_improved; } +void core::propagate(vector& lemmas) { + // disable for now + return; + + // propagate linear monomials + lemmas.reset(); + for (auto const& m : m_emons) + if (propagate(m, lemmas)) + break; +} + +bool core::propagate(monic const& m, vector& lemmas) { + m_propagated.reserve(m.var() + 1, false); + if (m_propagated[m.var()]) + return false; + + if (!is_linear(m)) + return false; + + trail().push(set_bitvector_trail(m_propagated, m.var())); + + mpq k = fixed_var_product(m); + // todo + + // return true if m_emons changes (so the iterator is invalid) + return false; +} + +bool core::is_linear(monic const& m) { + // todo + return false; +} + + +mpq core::fixed_var_product(monic const& m) { + // todo + return mpq(0); +} + + } // end of nla diff --git a/src/math/lp/nla_core.h b/src/math/lp/nla_core.h index e2a66c321..47e992c32 100644 --- a/src/math/lp/nla_core.h +++ b/src/math/lp/nla_core.h @@ -59,6 +59,7 @@ class core { friend class solver; friend class monomial_bounds; friend class nra::solver; + friend class divisions; struct stats { unsigned m_nla_explanations; @@ -390,6 +391,8 @@ public: void check_bounded_divisions(vector&); bool no_lemmas_hold() const; + + void propagate(vector& lemmas); lbool test_check(vector& l); lpvar map_to_root(lpvar) const; @@ -432,6 +435,13 @@ private: void restore_tableau(); void save_tableau(); bool integrality_holds(); + + // monomial propagation + bool_vector m_propagated; + bool propagate(monic const& m, vector& lemmas); + bool is_linear(monic const& m); + mpq fixed_var_product(monic const& m); + }; // end of core struct pp_mon { diff --git a/src/math/lp/nla_divisions.cpp b/src/math/lp/nla_divisions.cpp index cbb30d9d9..7d52cd0ba 100644 --- a/src/math/lp/nla_divisions.cpp +++ b/src/math/lp/nla_divisions.cpp @@ -19,19 +19,30 @@ Description: namespace nla { void divisions::add_idivision(lpvar q, lpvar x, lpvar y) { + auto& lra = m_core.lra; if (x == null_lpvar || y == null_lpvar || q == null_lpvar) return; - if (lp::tv::is_term(x) || lp::tv::is_term(y) || lp::tv::is_term(q)) - return; + if (lp::tv::is_term(x)) + x = lra.map_term_index_to_column_index(x); + if (lp::tv::is_term(y)) + y = lra.map_term_index_to_column_index(y); + if (lp::tv::is_term(q)) + q = lra.map_term_index_to_column_index(q); m_idivisions.push_back({q, x, y}); m_core.trail().push(push_back_vector(m_idivisions)); } void divisions::add_rdivision(lpvar q, lpvar x, lpvar y) { + auto& lra = m_core.lra; if (x == null_lpvar || y == null_lpvar || q == null_lpvar) return; - if (lp::tv::is_term(x) || lp::tv::is_term(y) || lp::tv::is_term(q)) - return; + if (lp::tv::is_term(x)) + x = lra.map_term_index_to_column_index(x); + if (lp::tv::is_term(y)) + y = lra.map_term_index_to_column_index(y); + if (lp::tv::is_term(q)) + q = lra.map_term_index_to_column_index(q); + m_rdivisions.push_back({ q, x, y }); m_core.trail().push(push_back_vector(m_rdivisions)); } @@ -52,7 +63,7 @@ namespace nla { // y2 <= y1 < 0 & x1 <= x2 <= 0 => x1/y1 >= x2/y2 void divisions::check() { - core& c = m_core; + core& c = m_core; if (c.use_nra_model()) return; @@ -132,7 +143,7 @@ namespace nla { auto x2val = c.val(x2); auto y2val = c.val(y2); auto q2val = c.val(q2); - if (monotonicity(x, xval, y, yval, r, rval, x2, x2val, y2, y2val, q2, q2val)) + if (monotonicity(x, xval, y, yval, r, rval, x2, x2val, y2, y2val, q2, q2val)) return; } } diff --git a/src/math/lp/nla_solver.cpp b/src/math/lp/nla_solver.cpp index ccc7b6073..b7197ff2f 100644 --- a/src/math/lp/nla_solver.cpp +++ b/src/math/lp/nla_solver.cpp @@ -45,6 +45,10 @@ namespace nla { lbool solver::check(vector& lits, vector& lemmas) { 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/math/lp/nla_solver.h b/src/math/lp/nla_solver.h index c1ad5f32a..7a8a97b3f 100644 --- a/src/math/lp/nla_solver.h +++ b/src/math/lp/nla_solver.h @@ -37,6 +37,7 @@ namespace nla { 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&); bool is_monic_var(lpvar) const; bool influences_nl_var(lpvar) const; diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 9e9e2d730..41426e0d6 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -2152,11 +2152,20 @@ public: propagate_bounds_with_lp_solver(); break; case l_undef: + propagate_nla(); break; } return true; } + void propagate_nla() { + 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); + } + bool should_propagate() const { return bound_prop_mode::BP_NONE != propagation_mode(); }