diff --git a/src/math/lp/nla_grobner.cpp b/src/math/lp/nla_grobner.cpp index be7c4d519..f3367a4ea 100644 --- a/src/math/lp/nla_grobner.cpp +++ b/src/math/lp/nla_grobner.cpp @@ -72,7 +72,7 @@ namespace nla { if (propagate_factorization()) return; - if (false && propagate_linear_equations()) + if (propagate_linear_equations()) return; } catch (...) { @@ -81,6 +81,8 @@ namespace nla { // DEBUG_CODE(for (auto e : m_solver.equations()) check_missing_propagation(*e);); + // for (auto e : m_solver.equations()) check_missing_propagation(*e); + ++m_delay_base; if (m_quota > 0) --m_quota; @@ -383,6 +385,9 @@ namespace nla { bool grobner::propagate_linear_equations() { unsigned changed = 0; + m_mon2var.clear(); + for (auto const& m : c().emons()) + m_mon2var[m.vars()] = m.var(); for (auto eq : m_solver.equations()) if (propagate_linear_equations(*eq) && ++changed >= m_solver.number_of_conflicts_to_report()) return true; @@ -392,40 +397,40 @@ namespace nla { bool grobner::propagate_linear_equations(dd::solver::equation const& e) { if (equation_is_true(e)) return false; - if (!e.poly().is_linear()) + rational value(0); + for (auto const& [coeff, vars] : e.poly()) { + if (vars.empty()) + value += coeff; + else if (vars.size() == 1) + value += coeff*val(vars[0]); + else if (m_mon2var.find(vars) == m_mon2var.end()) + return false; + else + value += coeff*val(m_mon2var.find(vars)->second); + } + if (value == 0) return false; rational lc(1); - for (auto const& [coeff, vars] : e.poly()) + for (auto const& [coeff, vars] : e.poly()) lc = lcm(denominator(coeff), lc); - auto q = e.poly(); - -#if 1 - vector> coeffs; - while (!q.is_val()) { - coeffs.push_back({lc*q.hi().val(), q.var()}); - q = q.lo(); - } + vector> coeffs; + rational offset(0); + + for (auto const& [coeff, vars] : e.poly()) { + if (vars.size() == 0) + offset -= lc*coeff; + else if (vars.size() == 1) + coeffs.push_back({lc*coeff, vars[0]}); + else + coeffs.push_back({lc*coeff, m_mon2var.find(vars)->second}); + } lp::lpvar term_index = c().lra.add_term(coeffs, UINT_MAX); 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, -lc*q.val(), e.dep()); + c().lra.update_column_type_and_bound(term_index, lp::lconstraint_kind::EQ, offset, e.dep()); c().m_check_feasible = true; -#else - - new_lemma lemma(m_core,"nla-linear"); - lp::explanation exp; - explain(e, exp); - lemma &= exp; - term t; - while (!q.is_val()) { - t.add_monomial(lc*q.hi().val(), q.var()); - q = q.lo(); - } - lemma |= ineq(t, llc::EQ, -lc*q.val()); -#endif - return true; } @@ -690,12 +695,11 @@ namespace nla { auto dep = eq.dep(); cross_nested cn( - [this, dep](const nex* n) { bool r = c().m_intervals.check_nex(n, dep); TRACE("grobner", tout << "check " << r << " " << *n << "\n"); return r; }, + [this, dep](const nex* n) { return c().m_intervals.check_nex(n, dep); }, [this](unsigned j) { return c().var_is_fixed(j); }, [this]() { return c().random(); }, nc); cn.run(to_sum(e)); bool ret = cn.done(); - TRACE("grobner", tout << "Horner " << ret << " " << eq.poly() << "\n"); return ret; } @@ -714,10 +718,12 @@ namespace nla { void grobner::check_missing_propagation(const dd::solver::equation& e) { bool is_confl = is_nla_conflict(e); CTRACE("grobner", is_confl, m_solver.display(tout << "missed conflict ", e);); - if (is_confl) + if (is_confl) { + IF_VERBOSE(2, verbose_stream() << "missed conflict\n"); return; - lbool r = c().m_nra.check_tight(e.poly()); - CTRACE("grobner", r == l_false, m_solver.display(tout << "tight equality ", e);); + } + //lbool r = c().m_nra.check_tight(e.poly()); + //CTRACE("grobner", r == l_false, m_solver.display(tout << "tight equality ", e);); } diff --git a/src/math/lp/nla_grobner.h b/src/math/lp/nla_grobner.h index dc5a188a5..cbf0cf109 100644 --- a/src/math/lp/nla_grobner.h +++ b/src/math/lp/nla_grobner.h @@ -26,6 +26,7 @@ namespace nla { unsigned m_quota = 0; unsigned m_delay_base = 0; unsigned m_delay = 0; + std::unordered_map m_mon2var; lp::lp_settings& lp_settings();