mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +00:00
working on reconciling perf for arithmetic solvers
this update integrates inferences to smt.arith.solver=6 related to grobner basis computation and handling of div/mod axioms to reconcile performance with smt.arith.solver=2. The default of smt.arth.nl.grobner_subs_fixed is changed to 1 to make comparison with solver=2 more direct. The selection of cluster equalities for solver=6 was reconciled with how it is done for solver=2.
This commit is contained in:
parent
9d9414c111
commit
b68af0c1e5
19 changed files with 357 additions and 282 deletions
|
@ -398,13 +398,17 @@ namespace dd {
|
|||
inline pdd operator-(rational const& r, pdd const& b) { return b.rev_sub(r); }
|
||||
inline pdd operator-(int x, pdd const& b) { return rational(x) - b; }
|
||||
inline pdd operator-(pdd const& b, int x) { return b + (-rational(x)); }
|
||||
|
||||
inline pdd operator-(pdd const& b, rational const& r) { return b + (-r); }
|
||||
|
||||
inline pdd& operator&=(pdd & p, pdd const& q) { p = p & q; return p; }
|
||||
inline pdd& operator^=(pdd & p, pdd const& q) { p = p ^ q; return p; }
|
||||
inline pdd& operator*=(pdd & p, pdd const& q) { p = p * q; return p; }
|
||||
inline pdd& operator|=(pdd & p, pdd const& q) { p = p | q; return p; }
|
||||
inline pdd& operator-=(pdd & p, pdd const& q) { p = p - q; return p; }
|
||||
inline pdd& operator+=(pdd & p, pdd const& q) { p = p + q; return p; }
|
||||
inline pdd& operator+=(pdd & p, rational const& v) { p = p + v; return p; }
|
||||
inline pdd& operator-=(pdd & p, rational const& v) { p = p - v; return p; }
|
||||
inline pdd& operator*=(pdd & p, rational const& v) { p = p * v; return p; }
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, pdd const& b);
|
||||
|
||||
|
|
|
@ -27,7 +27,33 @@ typedef dep_intervals::with_deps_t w_dep;
|
|||
class pdd_interval {
|
||||
dep_intervals& m_dep_intervals;
|
||||
std::function<void (unsigned, bool, scoped_dep_interval&)> m_var2interval;
|
||||
|
||||
|
||||
// retrieve intervals after distributing multiplication over addition.
|
||||
template <w_dep wd>
|
||||
void get_interval_distributed(pdd const& p, scoped_dep_interval& i, scoped_dep_interval& ret) {
|
||||
bool deps = wd == w_dep::with_deps;
|
||||
if (p.is_val()) {
|
||||
if (deps)
|
||||
m_dep_intervals.mul<dep_intervals::with_deps>(p.val(), i, ret);
|
||||
else
|
||||
m_dep_intervals.mul<dep_intervals::without_deps>(p.val(), i, ret);
|
||||
return;
|
||||
}
|
||||
scoped_dep_interval hi(m()), lo(m()), t(m()), a(m());
|
||||
get_interval_distributed<wd>(p.lo(), i, lo);
|
||||
m_var2interval(p.var(), deps, a);
|
||||
if (deps) {
|
||||
m_dep_intervals.mul<dep_intervals::with_deps>(a, i, t);
|
||||
get_interval_distributed<wd>(p.hi(), t, hi);
|
||||
m_dep_intervals.add<dep_intervals::with_deps>(hi, lo, ret);
|
||||
}
|
||||
else {
|
||||
m_dep_intervals.mul<dep_intervals::without_deps>(a, i, t);
|
||||
get_interval_distributed<wd>(p.hi(), t, hi);
|
||||
m_dep_intervals.add<dep_intervals::without_deps>(hi, lo, ret);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
pdd_interval(dep_intervals& d): m_dep_intervals(d) {}
|
||||
|
@ -57,5 +83,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
template <w_dep wd>
|
||||
void get_interval_distributed(pdd const& p, scoped_dep_interval& ret) {
|
||||
scoped_dep_interval i(m());
|
||||
m_dep_intervals.set_interval_for_scalar(i, rational::one());
|
||||
get_interval_distributed<wd>(p, i, ret);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ void grobner::display_vars(std::ostream & out, unsigned num_vars, expr * const *
|
|||
}
|
||||
}
|
||||
|
||||
void grobner::display_monomial(std::ostream & out, monomial const & m) const {
|
||||
void grobner::display_monomial(std::ostream & out, monomial const & m, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
if (!m.m_coeff.is_one() || m.m_vars.empty()) {
|
||||
out << m.m_coeff;
|
||||
if (!m.m_vars.empty())
|
||||
|
@ -165,7 +165,7 @@ void grobner::display_monomial(std::ostream & out, monomial const & m) const {
|
|||
}
|
||||
}
|
||||
|
||||
void grobner::display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials) const {
|
||||
void grobner::display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
bool first = true;
|
||||
for (unsigned i = 0; i < num_monomials; i++) {
|
||||
monomial const * m = monomials[i];
|
||||
|
@ -173,26 +173,26 @@ void grobner::display_monomials(std::ostream & out, unsigned num_monomials, mono
|
|||
first = false;
|
||||
else
|
||||
out << " + ";
|
||||
display_monomial(out, *m);
|
||||
display_monomial(out, *m, display_var);
|
||||
}
|
||||
}
|
||||
|
||||
void grobner::display_equation(std::ostream & out, equation const & eq) const {
|
||||
display_monomials(out, eq.m_monomials.size(), eq.m_monomials.data());
|
||||
void grobner::display_equation(std::ostream & out, equation const & eq, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
display_monomials(out, eq.m_monomials.size(), eq.m_monomials.data(), display_var);
|
||||
out << " = 0\n";
|
||||
}
|
||||
|
||||
void grobner::display_equations(std::ostream & out, equation_set const & v, char const * header) const {
|
||||
if (!v.empty()) {
|
||||
out << header << "\n";
|
||||
for (equation const* eq : v)
|
||||
display_equation(out, *eq);
|
||||
}
|
||||
void grobner::display_equations(std::ostream & out, equation_set const & v, char const * header, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
if (v.empty())
|
||||
return;
|
||||
out << header << "\n";
|
||||
for (equation const* eq : v)
|
||||
display_equation(out, *eq, display_var);
|
||||
}
|
||||
|
||||
void grobner::display(std::ostream & out) const {
|
||||
display_equations(out, m_processed, "processed:");
|
||||
display_equations(out, m_to_process, "to process:");
|
||||
void grobner::display(std::ostream & out, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
display_equations(out, m_processed, "processed:", display_var);
|
||||
display_equations(out, m_to_process, "to process:", display_var);
|
||||
}
|
||||
|
||||
void grobner::set_weight(expr * n, int weight) {
|
||||
|
@ -528,7 +528,7 @@ bool grobner::is_subset(monomial const * m1, monomial const * m2, ptr_vector<exp
|
|||
for (; i2 < sz2; i2++)
|
||||
rest.push_back(m2->m_vars[i2]);
|
||||
TRACE("grobner",
|
||||
tout << "monomail: "; display_monomial(tout, *m1); tout << " is a subset of ";
|
||||
tout << "monomial: "; display_monomial(tout, *m1); tout << " is a subset of ";
|
||||
display_monomial(tout, *m2); tout << "\n";
|
||||
tout << "rest: "; display_vars(tout, rest.size(), rest.data()); tout << "\n";);
|
||||
return true;
|
||||
|
@ -552,7 +552,7 @@ bool grobner::is_subset(monomial const * m1, monomial const * m2, ptr_vector<exp
|
|||
}
|
||||
}
|
||||
// is not subset
|
||||
TRACE("grobner", tout << "monomail: "; display_monomial(tout, *m1); tout << " is not a subset of ";
|
||||
TRACE("grobner", tout << "monomial: "; display_monomial(tout, *m1); tout << " is not a subset of ";
|
||||
display_monomial(tout, *m2); tout << "\n";);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -120,9 +120,16 @@ protected:
|
|||
|
||||
void display_var(std::ostream & out, expr * var) const;
|
||||
|
||||
void display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials) const;
|
||||
void display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
|
||||
void display_equations(std::ostream & out, equation_set const & v, char const * header) const;
|
||||
|
||||
void display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials) const {
|
||||
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { display_var(out, v); };
|
||||
display_monomials(out, num_monomials, monomials, _fn);
|
||||
}
|
||||
|
||||
|
||||
void display_equations(std::ostream & out, equation_set const & v, char const * header, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
|
||||
void del_equations(unsigned old_size);
|
||||
|
||||
|
@ -281,11 +288,26 @@ public:
|
|||
|
||||
void pop_scope(unsigned num_scopes);
|
||||
|
||||
void display_equation(std::ostream & out, equation const & eq) const;
|
||||
void display_equation(std::ostream & out, equation const & eq) const {
|
||||
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { display_var(out, v); };
|
||||
display_equation(out, eq, _fn);
|
||||
}
|
||||
|
||||
void display_monomial(std::ostream & out, monomial const & m) const;
|
||||
void display_monomial(std::ostream & out, monomial const & m) const {
|
||||
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { display_var(out, v); };
|
||||
display_monomial(out, m, _fn);
|
||||
}
|
||||
|
||||
void display_equation(std::ostream & out, equation const & eq, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
void display_monomial(std::ostream & out, monomial const & m, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
|
||||
void display(std::ostream & out) const {
|
||||
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { display_var(out, v); };
|
||||
display(out, _fn);
|
||||
}
|
||||
|
||||
void display(std::ostream & out, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
--*/
|
||||
|
||||
#include "util/uint_set.h"
|
||||
#include "math/grobner/pdd_solver.h"
|
||||
#include "math/grobner/pdd_simplifier.h"
|
||||
#include "util/uint_set.h"
|
||||
#include <math.h>
|
||||
|
||||
|
||||
|
|
|
@ -222,7 +222,6 @@ public:
|
|||
|
||||
template <enum with_deps_t wd>
|
||||
void mul(const rational& r, const interval& a, interval& b) const {
|
||||
if (r.is_zero()) return;
|
||||
m_imanager.mul(r.to_mpq(), a, b);
|
||||
if (wd == with_deps) {
|
||||
auto lower_dep = a.m_lower_dep;
|
||||
|
|
|
@ -40,7 +40,7 @@ bool horner::row_has_monomial_to_refine(const T& row) const {
|
|||
template <typename T>
|
||||
bool horner::row_is_interesting(const T& row) const {
|
||||
TRACE("nla_solver_details", c().print_row(row, tout););
|
||||
if (row.size() > c().m_nla_settings.horner_row_length_limit()) {
|
||||
if (row.size() > c().m_nla_settings.horner_row_length_limit) {
|
||||
TRACE("nla_solver_details", tout << "disregard\n";);
|
||||
return false;
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ bool horner::lemmas_on_row(const T& row) {
|
|||
}
|
||||
|
||||
bool horner::horner_lemmas() {
|
||||
if (!c().m_nla_settings.run_horner()) {
|
||||
if (!c().m_nla_settings.run_horner) {
|
||||
TRACE("nla_solver", tout << "not generating horner lemmas\n";);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -275,9 +275,6 @@ class lar_solver : public column_namer {
|
|||
return m_column_buffer;
|
||||
}
|
||||
bool bound_is_integer_for_integer_column(unsigned j, const mpq & right_side) const;
|
||||
inline unsigned get_base_column_in_row(unsigned row_index) const {
|
||||
return m_mpq_lar_core_solver.m_r_solver.get_base_column_in_row(row_index);
|
||||
}
|
||||
inline lar_core_solver & get_core_solver() { return m_mpq_lar_core_solver; }
|
||||
void catch_up_in_updating_int_solver();
|
||||
var_index to_column(unsigned ext_j) const;
|
||||
|
@ -357,6 +354,10 @@ public:
|
|||
}
|
||||
|
||||
void set_value_for_nbasic_column(unsigned j, const impq& new_val);
|
||||
inline unsigned get_base_column_in_row(unsigned row_index) const {
|
||||
return m_mpq_lar_core_solver.m_r_solver.get_base_column_in_row(row_index);
|
||||
}
|
||||
|
||||
|
||||
// lp_assert(implied_bound_is_correctly_explained(ib, explanation)); }
|
||||
constraint_index mk_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side);
|
||||
|
@ -630,6 +631,7 @@ public:
|
|||
}
|
||||
void round_to_integer_solution();
|
||||
inline const row_strip<mpq> & get_row(unsigned i) const { return A_r().m_rows[i]; }
|
||||
inline const row_strip<mpq> & basic2row(unsigned i) const { return A_r().m_rows[row_of_basic_column(i)]; }
|
||||
inline const column_strip & get_column(unsigned i) const { return A_r().m_columns[i]; }
|
||||
bool row_is_correct(unsigned i) const;
|
||||
bool ax_is_correct() const;
|
||||
|
|
|
@ -71,11 +71,11 @@ void common::add_deps_of_fixed(lpvar j, u_dependency*& dep) {
|
|||
// creates a nex expression for the coeff and var,
|
||||
nex * common::nexvar(const rational & coeff, lpvar j, nex_creator& cn, u_dependency*& dep) {
|
||||
SASSERT(!coeff.is_zero());
|
||||
if (c().m_nla_settings.horner_subs_fixed() == 1 && c().var_is_fixed(j)) {
|
||||
if (c().m_nla_settings.horner_subs_fixed == 1 && c().var_is_fixed(j)) {
|
||||
add_deps_of_fixed(j, dep);
|
||||
return cn.mk_scalar(coeff * c().m_lar_solver.column_lower_bound(j).x);
|
||||
}
|
||||
if (c().m_nla_settings.horner_subs_fixed() == 2 && c().var_is_fixed_to_zero(j)) {
|
||||
if (c().m_nla_settings.horner_subs_fixed == 2 && c().var_is_fixed_to_zero(j)) {
|
||||
add_deps_of_fixed(j, dep);
|
||||
return cn.mk_scalar(rational(0));
|
||||
}
|
||||
|
@ -89,10 +89,10 @@ nex * common::nexvar(const rational & coeff, lpvar j, nex_creator& cn, u_depende
|
|||
mf *= coeff;
|
||||
u_dependency * initial_dep = dep;
|
||||
for (lpvar k : m.vars()) {
|
||||
if (c().m_nla_settings.horner_subs_fixed() && c().var_is_fixed(k)) {
|
||||
if (c().m_nla_settings.horner_subs_fixed == 1 && c().var_is_fixed(k)) {
|
||||
add_deps_of_fixed(k, dep);
|
||||
mf *= c().m_lar_solver.column_lower_bound(k).x;
|
||||
} else if (c().m_nla_settings.horner_subs_fixed() == 2 &&
|
||||
} else if (c().m_nla_settings.horner_subs_fixed == 2 &&
|
||||
c().var_is_fixed_to_zero(k)) {
|
||||
dep = initial_dep;
|
||||
add_deps_of_fixed(k, dep);
|
||||
|
|
|
@ -557,7 +557,7 @@ std::ostream & core::print_ineq(const ineq & in, std::ostream & out) const {
|
|||
}
|
||||
|
||||
std::ostream & core::print_var(lpvar j, std::ostream & out) const {
|
||||
if (m_emons.is_monic_var(j)) {
|
||||
if (is_monic_var(j)) {
|
||||
print_monic(m_emons[j], out);
|
||||
}
|
||||
|
||||
|
@ -846,7 +846,7 @@ std::unordered_set<lpvar> core::collect_vars(const lemma& l) const {
|
|||
std::unordered_set<lpvar> vars;
|
||||
auto insert_j = [&](lpvar j) {
|
||||
vars.insert(j);
|
||||
if (m_emons.is_monic_var(j)) {
|
||||
if (is_monic_var(j)) {
|
||||
for (lpvar k : m_emons[j].vars())
|
||||
vars.insert(k);
|
||||
}
|
||||
|
@ -948,7 +948,7 @@ void core::maybe_add_a_factor(lpvar i,
|
|||
std::unordered_set<unsigned>& found_rm,
|
||||
vector<factor> & r) const {
|
||||
SASSERT(abs(val(i)) == abs(val(c)));
|
||||
if (!m_emons.is_monic_var(i)) {
|
||||
if (!is_monic_var(i)) {
|
||||
i = m_evars.find(i).var();
|
||||
if (try_insert(i, found_vars)) {
|
||||
r.push_back(factor(i, factor_type::VAR));
|
||||
|
@ -1228,7 +1228,7 @@ bool core::var_breaks_correct_monic_as_factor(lpvar j, const monic& m) const {
|
|||
}
|
||||
|
||||
bool core::var_breaks_correct_monic(lpvar j) const {
|
||||
if (emons().is_monic_var(j) && !m_to_refine.contains(j)) {
|
||||
if (is_monic_var(j) && !m_to_refine.contains(j)) {
|
||||
TRACE("nla_solver", tout << "j = " << j << ", m = "; print_monic(emons()[j], tout) << "\n";);
|
||||
return true; // changing the value of a correct monic
|
||||
}
|
||||
|
@ -1333,7 +1333,7 @@ bool in_power(const svector<lpvar>& vs, unsigned l) {
|
|||
|
||||
bool core::to_refine_is_correct() const {
|
||||
for (unsigned j = 0; j < m_lar_solver.number_of_vars(); j++) {
|
||||
if (!emons().is_monic_var(j)) continue;
|
||||
if (!is_monic_var(j)) continue;
|
||||
bool valid = check_monic(emons()[j]);
|
||||
if (valid == m_to_refine.contains(j)) {
|
||||
TRACE("nla_solver", tout << "inconstency in m_to_refine : ";
|
||||
|
@ -1414,7 +1414,7 @@ void core::patch_monomials_on_to_refine() {
|
|||
void core::patch_monomials() {
|
||||
m_cautious_patching = true;
|
||||
patch_monomials_on_to_refine();
|
||||
if (m_to_refine.size() == 0 || !m_nla_settings.expensive_patching()) {
|
||||
if (m_to_refine.size() == 0 || !m_nla_settings.expensive_patching) {
|
||||
return;
|
||||
}
|
||||
NOT_IMPLEMENTED_YET();
|
||||
|
@ -1530,11 +1530,11 @@ lbool core::check(vector<lemma>& l_vec) {
|
|||
check_weighted(3, checks);
|
||||
|
||||
unsigned num_calls = lp_settings().stats().m_nla_calls;
|
||||
if (!conflict_found() && m_nla_settings.run_nra() && num_calls % 50 == 0 && num_calls > 500)
|
||||
if (!conflict_found() && m_nla_settings.run_nra && num_calls % 50 == 0 && num_calls > 500)
|
||||
ret = bounded_nlsat();
|
||||
}
|
||||
|
||||
if (l_vec.empty() && !done() && m_nla_settings.run_nra() && ret == l_undef) {
|
||||
if (l_vec.empty() && !done() && m_nla_settings.run_nra && ret == l_undef) {
|
||||
ret = m_nra.check();
|
||||
m_stats.m_nra_calls++;
|
||||
}
|
||||
|
@ -1554,7 +1554,7 @@ lbool core::check(vector<lemma>& l_vec) {
|
|||
}
|
||||
|
||||
bool core::should_run_bounded_nlsat() {
|
||||
if (!m_nla_settings.run_nra())
|
||||
if (!m_nla_settings.run_nra)
|
||||
return false;
|
||||
if (m_nlsat_delay > m_nlsat_fails)
|
||||
++m_nlsat_fails;
|
||||
|
@ -1619,8 +1619,13 @@ std::ostream& core::print_terms(std::ostream& out) const {
|
|||
}
|
||||
|
||||
std::string core::var_str(lpvar j) const {
|
||||
return is_monic_var(j)?
|
||||
(product_indices_str(m_emons[j].vars()) + (check_monic(m_emons[j])? "": "_")) : (std::string("j") + lp::T_to_string(j));
|
||||
std::string result;
|
||||
if (is_monic_var(j))
|
||||
result += product_indices_str(m_emons[j].vars()) + (check_monic(m_emons[j])? "": "_");
|
||||
else
|
||||
result += std::string("j") + lp::T_to_string(j);
|
||||
// result += ":w" + lp::T_to_string(get_var_weight(j));
|
||||
return result;
|
||||
}
|
||||
|
||||
std::ostream& core::print_term( const lp::lar_term& t, std::ostream& out) const {
|
||||
|
@ -1632,7 +1637,7 @@ std::ostream& core::print_term( const lp::lar_term& t, std::ostream& out) const
|
|||
|
||||
|
||||
void core::run_grobner() {
|
||||
unsigned& quota = m_nla_settings.grobner_quota();
|
||||
unsigned& quota = m_nla_settings.grobner_quota;
|
||||
if (quota == 1) {
|
||||
return;
|
||||
}
|
||||
|
@ -1645,13 +1650,14 @@ void core::run_grobner() {
|
|||
bool conflict = false;
|
||||
unsigned n = m_pdd_grobner.number_of_conflicts_to_report();
|
||||
SASSERT(n > 0);
|
||||
for (auto eq : m_pdd_grobner.equations()) {
|
||||
for (auto eq : m_pdd_grobner.equations()) {
|
||||
if (check_pdd_eq(eq)) {
|
||||
conflict = true;
|
||||
if (--n == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
TRACE("grobner", m_pdd_grobner.display(tout));
|
||||
if (conflict) {
|
||||
IF_VERBOSE(2, verbose_stream() << "grobner conflict\n");
|
||||
return;
|
||||
|
@ -1694,14 +1700,32 @@ void core::configure_grobner() {
|
|||
m_pdd_grobner.reset();
|
||||
try {
|
||||
set_level2var_for_grobner();
|
||||
for (unsigned i : m_rows) {
|
||||
add_row_to_grobner(m_lar_solver.A_r().m_rows[i]);
|
||||
TRACE("grobner",
|
||||
tout << "base vars: ";
|
||||
for (lpvar j : active_var_set())
|
||||
if (m_lar_solver.is_base(j))
|
||||
tout << "j" << j << " ";
|
||||
tout << "\n");
|
||||
for (lpvar j : active_var_set()) {
|
||||
if (m_lar_solver.is_base(j))
|
||||
add_row_to_grobner(m_lar_solver.basic2row(j));
|
||||
|
||||
if (is_monic_var(j) && var_is_fixed(j)) {
|
||||
u_dependency* dep = nullptr;
|
||||
dd::pdd r = m_pdd_manager.mk_val(rational(1));
|
||||
for (lpvar k : emons()[j].vars())
|
||||
r *= pdd_expr(rational::one(), k, dep);
|
||||
r -= val_of_fixed_var_with_deps(j, dep);
|
||||
m_pdd_grobner.add(r, dep);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
IF_VERBOSE(2, verbose_stream() << "pdd throw\n");
|
||||
return;
|
||||
}
|
||||
TRACE("grobner", m_pdd_grobner.display(tout));
|
||||
|
||||
#if 0
|
||||
IF_VERBOSE(2, m_pdd_grobner.display(verbose_stream()));
|
||||
dd::pdd_eval eval(m_pdd_manager);
|
||||
|
@ -1717,11 +1741,11 @@ void core::configure_grobner() {
|
|||
|
||||
struct dd::solver::config cfg;
|
||||
cfg.m_max_steps = m_pdd_grobner.equations().size();
|
||||
cfg.m_max_simplified = m_nla_settings.grobner_max_simplified();
|
||||
cfg.m_eqs_growth = m_nla_settings.grobner_eqs_growth();
|
||||
cfg.m_expr_size_growth = m_nla_settings.grobner_expr_size_growth();
|
||||
cfg.m_expr_degree_growth = m_nla_settings.grobner_expr_degree_growth();
|
||||
cfg.m_number_of_conflicts_to_report = m_nla_settings.grobner_number_of_conflicts_to_report();
|
||||
cfg.m_max_simplified = m_nla_settings.grobner_max_simplified;
|
||||
cfg.m_eqs_growth = m_nla_settings.grobner_eqs_growth;
|
||||
cfg.m_expr_size_growth = m_nla_settings.grobner_expr_size_growth;
|
||||
cfg.m_expr_degree_growth = m_nla_settings.grobner_expr_degree_growth;
|
||||
cfg.m_number_of_conflicts_to_report = m_nla_settings.grobner_number_of_conflicts_to_report;
|
||||
m_pdd_grobner.set(cfg);
|
||||
m_pdd_grobner.adjust_cfg();
|
||||
m_pdd_manager.set_max_num_nodes(10000); // or something proportional to the number of initial nodes.
|
||||
|
@ -1762,49 +1786,66 @@ bool core::check_pdd_eq(const dd::solver::equation* e) {
|
|||
};
|
||||
scoped_dep_interval i(di), i_wd(di);
|
||||
eval.get_interval<dd::w_dep::without_deps>(e->poly(), i);
|
||||
if (!di.separated_from_zero(i))
|
||||
if (!di.separated_from_zero(i)) {
|
||||
TRACE("grobner", m_pdd_grobner.display(tout << "not separated from 0 ", *e) << "\n";
|
||||
eval.get_interval_distributed<dd::w_dep::without_deps>(e->poly(), i);
|
||||
tout << "separated from 0: " << di.separated_from_zero(i) << "\n";
|
||||
for (auto j : e->poly().free_vars()) {
|
||||
scoped_dep_interval a(di);
|
||||
m_intervals.set_var_interval<dd::w_dep::without_deps>(j, a);
|
||||
m_intervals.display(tout << "j" << j << " ", a); tout << " ";
|
||||
}
|
||||
tout << "\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
eval.get_interval<dd::w_dep::with_deps>(e->poly(), i_wd);
|
||||
std::function<void (const lp::explanation&)> f = [this](const lp::explanation& e) {
|
||||
new_lemma lemma(*this, "pdd");
|
||||
lemma &= e;
|
||||
};
|
||||
if (di.check_interval_for_conflict_on_zero(i_wd, e->dep(), f)) {
|
||||
TRACE("grobner", m_pdd_grobner.display(tout << "conflict ", *e) << "\n");
|
||||
lp_settings().stats().m_grobner_conflicts++;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
TRACE("grobner", m_pdd_grobner.display(tout << "no conflict ", *e) << "\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void core::add_var_and_its_factors_to_q_and_collect_new_rows(lpvar j, svector<lpvar> & q) {
|
||||
if (active_var_set_contains(j) || var_is_fixed(j)) return;
|
||||
TRACE("grobner", tout << "j = " << j << ", " << pp(j););
|
||||
const auto& matrix = m_lar_solver.A_r();
|
||||
if (active_var_set_contains(j))
|
||||
return;
|
||||
insert_to_active_var_set(j);
|
||||
for (auto & s : matrix.m_columns[j]) {
|
||||
unsigned row = s.var();
|
||||
if (m_rows.contains(row)) continue;
|
||||
if (matrix.m_rows[row].size() > m_nla_settings.grobner_row_length_limit()) {
|
||||
TRACE("grobner", tout << "ignore the row " << row << " with the size " << matrix.m_rows[row].size() << "\n";);
|
||||
continue;
|
||||
}
|
||||
m_rows.insert(row);
|
||||
for (auto& rc : matrix.m_rows[row]) {
|
||||
add_var_and_its_factors_to_q_and_collect_new_rows(rc.var(), q);
|
||||
}
|
||||
if (is_monic_var(j)) {
|
||||
const monic& m = emons()[j];
|
||||
for (auto fcn : factorization_factory_imp(m, *this))
|
||||
for (const factor& fc: fcn)
|
||||
q.push_back(var(fc));
|
||||
}
|
||||
|
||||
if (!is_monic_var(j))
|
||||
if (var_is_fixed(j))
|
||||
return;
|
||||
const auto& matrix = m_lar_solver.A_r();
|
||||
for (auto & s : matrix.m_columns[j]) {
|
||||
unsigned row = s.var();
|
||||
if (m_rows.contains(row))
|
||||
continue;
|
||||
m_rows.insert(row);
|
||||
unsigned k = m_lar_solver.get_base_column_in_row(row);
|
||||
if (m_lar_solver.column_is_free(k) && k != j)
|
||||
continue;
|
||||
CTRACE("grobner", matrix.m_rows[row].size() > m_nla_settings.grobner_row_length_limit,
|
||||
tout << "ignore the row " << row << " with the size " << matrix.m_rows[row].size() << "\n";);
|
||||
if (matrix.m_rows[row].size() > m_nla_settings.grobner_row_length_limit)
|
||||
continue;
|
||||
for (auto& rc : matrix.m_rows[row])
|
||||
add_var_and_its_factors_to_q_and_collect_new_rows(rc.var(), q);
|
||||
}
|
||||
|
||||
|
||||
const monic& m = emons()[j];
|
||||
for (auto fcn : factorization_factory_imp(m, *this)) {
|
||||
for (const factor& fc: fcn) {
|
||||
q.push_back(var(fc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const rational& core::val_of_fixed_var_with_deps(lpvar j, u_dependency*& dep) {
|
||||
|
@ -1816,41 +1857,36 @@ const rational& core::val_of_fixed_var_with_deps(lpvar j, u_dependency*& dep) {
|
|||
}
|
||||
|
||||
dd::pdd core::pdd_expr(const rational& c, lpvar j, u_dependency*& dep) {
|
||||
if (m_nla_settings.grobner_subs_fixed() == 1 && var_is_fixed(j)) {
|
||||
return m_pdd_manager.mk_val(c * val_of_fixed_var_with_deps(j, dep));
|
||||
}
|
||||
|
||||
if (m_nla_settings.grobner_subs_fixed() == 2 && var_is_fixed_to_zero(j)) {
|
||||
return m_pdd_manager.mk_val(val_of_fixed_var_with_deps(j, dep));
|
||||
}
|
||||
|
||||
if (!is_monic_var(j))
|
||||
return c * m_pdd_manager.mk_var(j);
|
||||
|
||||
u_dependency* zero_dep = dep;
|
||||
// j is a monic var
|
||||
dd::pdd r = m_pdd_manager.mk_val(c);
|
||||
const monic& m = emons()[j];
|
||||
for (lpvar k : m.vars()) {
|
||||
if (m_nla_settings.grobner_subs_fixed() && var_is_fixed(k)) {
|
||||
r *= m_pdd_manager.mk_val(val_of_fixed_var_with_deps(k, dep));
|
||||
} else if (m_nla_settings.grobner_subs_fixed() == 2 && var_is_fixed_to_zero(k)) {
|
||||
r = m_pdd_manager.mk_val(val_of_fixed_var_with_deps(k, zero_dep));
|
||||
sbuffer<lpvar> vars;
|
||||
vars.push_back(j);
|
||||
u_dependency* zero_dep = dep;
|
||||
while (!vars.empty()) {
|
||||
j = vars.back();
|
||||
vars.pop_back();
|
||||
if (m_nla_settings.grobner_subs_fixed > 0 && var_is_fixed_to_zero(j)) {
|
||||
r = m_pdd_manager.mk_val(val_of_fixed_var_with_deps(j, zero_dep));
|
||||
dep = zero_dep;
|
||||
return r;
|
||||
} else {
|
||||
r *= m_pdd_manager.mk_var(k);
|
||||
}
|
||||
if (m_nla_settings.grobner_subs_fixed == 1 && var_is_fixed(j))
|
||||
r *= val_of_fixed_var_with_deps(j, dep);
|
||||
else if (!is_monic_var(j))
|
||||
r *= m_pdd_manager.mk_var(j);
|
||||
else
|
||||
for (lpvar k : emons()[j].vars())
|
||||
vars.push_back(k);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void core::add_row_to_grobner(const vector<lp::row_cell<rational>> & row) {
|
||||
u_dependency *dep = nullptr;
|
||||
rational val;
|
||||
dd::pdd sum = m_pdd_manager.mk_val(rational(0));
|
||||
for (const auto &p : row) {
|
||||
sum += pdd_expr(p.coeff(), p.var(), dep);
|
||||
}
|
||||
for (const auto &p : row)
|
||||
sum += pdd_expr(p.coeff(), p.var(), dep);
|
||||
TRACE("grobner", print_row(row, tout) << " " << sum << "\n");
|
||||
m_pdd_grobner.add(sum, dep);
|
||||
}
|
||||
|
||||
|
@ -1858,17 +1894,21 @@ void core::add_row_to_grobner(const vector<lp::row_cell<rational>> & row) {
|
|||
void core::find_nl_cluster() {
|
||||
prepare_rows_and_active_vars();
|
||||
svector<lpvar> q;
|
||||
for (lpvar j : m_to_refine) {
|
||||
TRACE("grobner", print_monic(emons()[j], tout) << "\n";);
|
||||
TRACE("grobner", for (lpvar j : m_to_refine) print_monic(emons()[j], tout) << "\n";);
|
||||
|
||||
for (lpvar j : m_to_refine)
|
||||
q.push_back(j);
|
||||
}
|
||||
|
||||
while (!q.empty()) {
|
||||
lpvar j = q.back();
|
||||
q.pop_back();
|
||||
add_var_and_its_factors_to_q_and_collect_new_rows(j, q);
|
||||
}
|
||||
TRACE("grobner", display_matrix_of_m_rows(tout););
|
||||
TRACE("grobner", tout << "vars in cluster: ";
|
||||
for (lpvar j : active_var_set()) tout << "j" << j << " "; tout << "\n";
|
||||
display_matrix_of_m_rows(tout);
|
||||
/*emons().display(tout << "emons\n");*/
|
||||
);
|
||||
}
|
||||
|
||||
void core::prepare_rows_and_active_vars() {
|
||||
|
@ -1902,18 +1942,16 @@ std::unordered_set<lpvar> core::get_vars_of_expr_with_opening_terms(const nex *e
|
|||
|
||||
void core::display_matrix_of_m_rows(std::ostream & out) const {
|
||||
const auto& matrix = m_lar_solver.A_r();
|
||||
out << m_rows.size() << " rows" <<"\n";
|
||||
out << m_rows.size() << " rows" << "\n";
|
||||
out << "the matrix\n";
|
||||
for (const auto & r : matrix.m_rows) {
|
||||
for (const auto & r : matrix.m_rows)
|
||||
print_row(r, out) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void core::set_active_vars_weights(nex_creator& nc) {
|
||||
nc.set_number_of_vars(m_lar_solver.column_count());
|
||||
for (lpvar j : active_var_set()) {
|
||||
for (lpvar j : active_var_set())
|
||||
nc.set_var_weight(j, get_var_weight(j));
|
||||
}
|
||||
}
|
||||
|
||||
void core::set_level2var_for_grobner() {
|
||||
|
@ -1944,6 +1982,11 @@ void core::set_level2var_for_grobner() {
|
|||
l2v[j] = sorted_vars[j];
|
||||
|
||||
m_pdd_manager.reset(l2v);
|
||||
|
||||
TRACE("grobner",
|
||||
for (auto v : sorted_vars)
|
||||
tout << "j" << v << " w:" << weighted_vars[v] << " ";
|
||||
tout << "\n");
|
||||
}
|
||||
|
||||
unsigned core::get_var_weight(lpvar j) const {
|
||||
|
@ -1954,14 +1997,14 @@ unsigned core::get_var_weight(lpvar j) const {
|
|||
k = 0;
|
||||
break;
|
||||
case lp::column_type::boxed:
|
||||
k = 2;
|
||||
k = 3;
|
||||
break;
|
||||
case lp::column_type::lower_bound:
|
||||
case lp::column_type::upper_bound:
|
||||
k = 4;
|
||||
k = 6;
|
||||
break;
|
||||
case lp::column_type::free_column:
|
||||
k = 6;
|
||||
k = 9;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
@ -1969,9 +2012,8 @@ unsigned core::get_var_weight(lpvar j) const {
|
|||
}
|
||||
if (is_monic_var(j)) {
|
||||
k++;
|
||||
if (m_to_refine.contains(j)) {
|
||||
if (m_to_refine.contains(j))
|
||||
k++;
|
||||
}
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
|
|
@ -243,11 +243,11 @@ public:
|
|||
|
||||
// returns true if the combination of the Horner's schema and Grobner Basis should be called
|
||||
bool need_run_horner() const {
|
||||
return m_nla_settings.run_horner() && lp_settings().stats().m_nla_calls % m_nla_settings.horner_frequency() == 0;
|
||||
return m_nla_settings.run_horner && lp_settings().stats().m_nla_calls % m_nla_settings.horner_frequency == 0;
|
||||
}
|
||||
|
||||
bool need_run_grobner() const {
|
||||
return m_nla_settings.run_grobner() && lp_settings().stats().m_nla_calls % m_nla_settings.grobner_frequency() == 0;
|
||||
return m_nla_settings.run_grobner && lp_settings().stats().m_nla_calls % m_nla_settings.grobner_frequency == 0;
|
||||
}
|
||||
|
||||
void incremental_linearization(bool);
|
||||
|
@ -456,8 +456,7 @@ public:
|
|||
for (auto p : row) {
|
||||
v.push_back(std::make_pair(p.coeff(), p.var()));
|
||||
}
|
||||
return lp::print_linear_combination_customized(v, [this](lpvar j) { return var_str(j); },
|
||||
out);
|
||||
return lp::print_linear_combination_customized(v, [this](lpvar j) { return var_str(j); }, out);
|
||||
}
|
||||
void run_grobner();
|
||||
void find_nl_cluster();
|
||||
|
|
|
@ -19,7 +19,7 @@ typedef lp::lar_term term;
|
|||
// a > b && c > 0 => ac > bc
|
||||
void order::order_lemma() {
|
||||
TRACE("nla_solver", );
|
||||
if (!c().m_nla_settings.run_order()) {
|
||||
if (!c().m_nla_settings.run_order) {
|
||||
TRACE("nla_solver", tout << "not generating order lemmas\n";);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -9,94 +9,38 @@ Author:
|
|||
|
||||
#pragma once
|
||||
namespace nla {
|
||||
class nla_settings {
|
||||
bool m_run_order;
|
||||
bool m_run_tangents;
|
||||
bool m_run_horner;
|
||||
// how often to call the horner heuristic
|
||||
unsigned m_horner_frequency;
|
||||
unsigned m_horner_row_length_limit;
|
||||
unsigned m_horner_subs_fixed;
|
||||
// grobner fields
|
||||
bool m_run_grobner;
|
||||
unsigned m_grobner_row_length_limit;
|
||||
unsigned m_grobner_subs_fixed;
|
||||
unsigned m_grobner_eqs_growth;
|
||||
unsigned m_grobner_tree_size_growth;
|
||||
unsigned m_grobner_expr_size_growth;
|
||||
unsigned m_grobner_expr_degree_growth;
|
||||
unsigned m_grobner_max_simplified;
|
||||
unsigned m_grobner_number_of_conflicts_to_report;
|
||||
unsigned m_grobner_quota;
|
||||
unsigned m_grobner_frequency;
|
||||
bool m_run_nra;
|
||||
// expensive patching
|
||||
bool m_expensive_patching;
|
||||
public:
|
||||
nla_settings() : m_run_order(true),
|
||||
m_run_tangents(true),
|
||||
m_run_horner(true),
|
||||
m_horner_frequency(4),
|
||||
m_horner_row_length_limit(10),
|
||||
m_horner_subs_fixed(2),
|
||||
m_run_grobner(true),
|
||||
m_grobner_row_length_limit(50),
|
||||
m_grobner_subs_fixed(false),
|
||||
m_grobner_quota(0),
|
||||
m_grobner_frequency(4),
|
||||
m_run_nra(false),
|
||||
m_expensive_patching(false)
|
||||
{}
|
||||
unsigned grobner_eqs_growth() const { return m_grobner_eqs_growth;}
|
||||
unsigned& grobner_eqs_growth() { return m_grobner_eqs_growth;}
|
||||
bool run_order() const { return m_run_order; }
|
||||
bool& run_order() { return m_run_order; }
|
||||
struct nla_settings {
|
||||
bool run_order = true;
|
||||
bool run_tangents = true;
|
||||
|
||||
// horner fields
|
||||
bool run_horner = true;
|
||||
unsigned horner_frequency = 4;
|
||||
unsigned horner_row_length_limit = 10;
|
||||
unsigned horner_subs_fixed = 2;
|
||||
|
||||
bool run_tangents() const { return m_run_tangents; }
|
||||
bool& run_tangents() { return m_run_tangents; }
|
||||
|
||||
// grobner fields
|
||||
bool run_grobner = true;
|
||||
unsigned grobner_row_length_limit = 50;
|
||||
unsigned grobner_subs_fixed = 1;
|
||||
unsigned grobner_eqs_growth = 10;
|
||||
unsigned grobner_tree_size_growth = 2;
|
||||
unsigned grobner_expr_size_growth = 2;
|
||||
unsigned grobner_expr_degree_growth = 2;
|
||||
unsigned grobner_max_simplified = 10000;
|
||||
unsigned grobner_number_of_conflicts_to_report = 1;
|
||||
unsigned grobner_quota = 0;
|
||||
unsigned grobner_frequency = 4;
|
||||
|
||||
bool expensive_patching() const { return m_expensive_patching; }
|
||||
bool& expensive_patching() { return m_expensive_patching; }
|
||||
|
||||
bool run_horner() const { return m_run_horner; }
|
||||
bool& run_horner() { return m_run_horner; }
|
||||
|
||||
unsigned horner_frequency() const { return m_horner_frequency; }
|
||||
unsigned& horner_frequency() { return m_horner_frequency; }
|
||||
unsigned horner_row_length_limit() const { return m_horner_row_length_limit; }
|
||||
unsigned& horner_row_length_limit() { return m_horner_row_length_limit; }
|
||||
unsigned horner_subs_fixed() const { return m_horner_subs_fixed; }
|
||||
unsigned& horner_subs_fixed() { return m_horner_subs_fixed; }
|
||||
|
||||
bool run_grobner() const { return m_run_grobner; }
|
||||
bool& run_grobner() { return m_run_grobner; }
|
||||
unsigned grobner_frequency() const { return m_grobner_frequency; }
|
||||
unsigned& grobner_frequency() { return m_grobner_frequency; }
|
||||
|
||||
bool run_nra() const { return m_run_nra; }
|
||||
bool& run_nra() { return m_run_nra; }
|
||||
|
||||
unsigned grobner_row_length_limit() const { return m_grobner_row_length_limit; }
|
||||
unsigned& grobner_row_length_limit() { return m_grobner_row_length_limit; }
|
||||
unsigned grobner_subs_fixed() const { return m_grobner_subs_fixed; }
|
||||
unsigned& grobner_subs_fixed() { return m_grobner_subs_fixed; }
|
||||
|
||||
unsigned grobner_tree_size_growth() const { return m_grobner_tree_size_growth; }
|
||||
unsigned & grobner_tree_size_growth() { return m_grobner_tree_size_growth; }
|
||||
|
||||
unsigned grobner_expr_size_growth() const { return m_grobner_expr_size_growth; }
|
||||
unsigned & grobner_expr_size_growth() { return m_grobner_expr_size_growth; }
|
||||
|
||||
unsigned grobner_expr_degree_growth() const { return m_grobner_expr_degree_growth; }
|
||||
unsigned & grobner_expr_degree_growth() { return m_grobner_expr_degree_growth; }
|
||||
|
||||
unsigned grobner_max_simplified() const { return m_grobner_max_simplified; }
|
||||
unsigned & grobner_max_simplified() { return m_grobner_max_simplified; }
|
||||
|
||||
unsigned grobner_number_of_conflicts_to_report() const { return m_grobner_number_of_conflicts_to_report; }
|
||||
unsigned & grobner_number_of_conflicts_to_report() { return m_grobner_number_of_conflicts_to_report; }
|
||||
|
||||
unsigned& grobner_quota() { return m_grobner_quota; }
|
||||
// nra fields
|
||||
bool run_nra = false;
|
||||
|
||||
};
|
||||
// expensive patching
|
||||
bool expensive_patching = false;
|
||||
|
||||
nla_settings() {}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -186,7 +186,7 @@ tangents::tangents(core * c) : common(c) {}
|
|||
void tangents::tangent_lemma() {
|
||||
factorization bf(nullptr);
|
||||
const monic* m = nullptr;
|
||||
if (c().m_nla_settings.run_tangents() && c().find_bfc_to_refine(m, bf)) {
|
||||
if (c().m_nla_settings.run_tangents && c().find_bfc_to_refine(m, bf)) {
|
||||
lpvar j = m->var();
|
||||
tangent_imp tangent(point(val(bf[0]), val(bf[1])), c().val(j), *m, bf, *this);
|
||||
tangent();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue