3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-22 22:03:39 +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:
Nikolaj Bjorner 2022-07-11 07:38:51 -07:00
parent 9d9414c111
commit b68af0c1e5
19 changed files with 357 additions and 282 deletions

View file

@ -398,6 +398,7 @@ namespace dd {
inline pdd operator-(rational const& r, pdd const& b) { return b.rev_sub(r); } 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-(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, 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; }
@ -405,6 +406,9 @@ namespace dd {
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); std::ostream& operator<<(std::ostream& out, pdd const& b);

View file

@ -28,6 +28,32 @@ class pdd_interval {
dep_intervals& m_dep_intervals; dep_intervals& m_dep_intervals;
std::function<void (unsigned, bool, scoped_dep_interval&)> m_var2interval; 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: public:
pdd_interval(dep_intervals& d): m_dep_intervals(d) {} 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);
}
}; };
} }

View file

@ -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()) { if (!m.m_coeff.is_one() || m.m_vars.empty()) {
out << m.m_coeff; out << m.m_coeff;
if (!m.m_vars.empty()) 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; bool first = true;
for (unsigned i = 0; i < num_monomials; i++) { for (unsigned i = 0; i < num_monomials; i++) {
monomial const * m = monomials[i]; monomial const * m = monomials[i];
@ -173,26 +173,26 @@ void grobner::display_monomials(std::ostream & out, unsigned num_monomials, mono
first = false; first = false;
else else
out << " + "; out << " + ";
display_monomial(out, *m); display_monomial(out, *m, display_var);
} }
} }
void grobner::display_equation(std::ostream & out, equation const & eq) const { 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_monomials(out, eq.m_monomials.size(), eq.m_monomials.data(), display_var);
out << " = 0\n"; out << " = 0\n";
} }
void grobner::display_equations(std::ostream & out, equation_set const & v, char const * header) const { 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()) { if (v.empty())
out << header << "\n"; return;
for (equation const* eq : v) out << header << "\n";
display_equation(out, *eq); for (equation const* eq : v)
} display_equation(out, *eq, display_var);
} }
void grobner::display(std::ostream & out) const { void grobner::display(std::ostream & out, std::function<void(std::ostream&, expr*)>& display_var) const {
display_equations(out, m_processed, "processed:"); display_equations(out, m_processed, "processed:", display_var);
display_equations(out, m_to_process, "to process:"); display_equations(out, m_to_process, "to process:", display_var);
} }
void grobner::set_weight(expr * n, int weight) { 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++) for (; i2 < sz2; i2++)
rest.push_back(m2->m_vars[i2]); rest.push_back(m2->m_vars[i2]);
TRACE("grobner", 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"; display_monomial(tout, *m2); tout << "\n";
tout << "rest: "; display_vars(tout, rest.size(), rest.data()); tout << "\n";); tout << "rest: "; display_vars(tout, rest.size(), rest.data()); tout << "\n";);
return true; return true;
@ -552,7 +552,7 @@ bool grobner::is_subset(monomial const * m1, monomial const * m2, ptr_vector<exp
} }
} }
// is not subset // 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";); display_monomial(tout, *m2); tout << "\n";);
return false; return false;
} }

View file

@ -120,9 +120,16 @@ protected:
void display_var(std::ostream & out, expr * var) const; 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); void del_equations(unsigned old_size);
@ -281,11 +288,26 @@ public:
void pop_scope(unsigned num_scopes); 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(std::ostream & out) const; void display_equation(std::ostream & out, equation const & eq, std::function<void(std::ostream&, expr*)>& display_var) 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;
}; };

View file

@ -11,9 +11,9 @@
--*/ --*/
#include "util/uint_set.h"
#include "math/grobner/pdd_solver.h" #include "math/grobner/pdd_solver.h"
#include "math/grobner/pdd_simplifier.h" #include "math/grobner/pdd_simplifier.h"
#include "util/uint_set.h"
#include <math.h> #include <math.h>

View file

@ -222,7 +222,6 @@ public:
template <enum with_deps_t wd> template <enum with_deps_t wd>
void mul(const rational& r, const interval& a, interval& b) const { void mul(const rational& r, const interval& a, interval& b) const {
if (r.is_zero()) return;
m_imanager.mul(r.to_mpq(), a, b); m_imanager.mul(r.to_mpq(), a, b);
if (wd == with_deps) { if (wd == with_deps) {
auto lower_dep = a.m_lower_dep; auto lower_dep = a.m_lower_dep;

View file

@ -40,7 +40,7 @@ bool horner::row_has_monomial_to_refine(const T& row) const {
template <typename T> template <typename T>
bool horner::row_is_interesting(const T& row) const { bool horner::row_is_interesting(const T& row) const {
TRACE("nla_solver_details", c().print_row(row, tout);); 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";); TRACE("nla_solver_details", tout << "disregard\n";);
return false; return false;
} }
@ -98,7 +98,7 @@ bool horner::lemmas_on_row(const T& row) {
} }
bool horner::horner_lemmas() { 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";); TRACE("nla_solver", tout << "not generating horner lemmas\n";);
return false; return false;
} }

View file

@ -275,9 +275,6 @@ class lar_solver : public column_namer {
return m_column_buffer; return m_column_buffer;
} }
bool bound_is_integer_for_integer_column(unsigned j, const mpq & right_side) const; 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; } inline lar_core_solver & get_core_solver() { return m_mpq_lar_core_solver; }
void catch_up_in_updating_int_solver(); void catch_up_in_updating_int_solver();
var_index to_column(unsigned ext_j) const; 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); 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)); } // lp_assert(implied_bound_is_correctly_explained(ib, explanation)); }
constraint_index mk_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side); 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(); 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> & 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]; } inline const column_strip & get_column(unsigned i) const { return A_r().m_columns[i]; }
bool row_is_correct(unsigned i) const; bool row_is_correct(unsigned i) const;
bool ax_is_correct() const; bool ax_is_correct() const;

View file

@ -71,11 +71,11 @@ void common::add_deps_of_fixed(lpvar j, u_dependency*& dep) {
// creates a nex expression for the coeff and var, // creates a nex expression for the coeff and var,
nex * common::nexvar(const rational & coeff, lpvar j, nex_creator& cn, u_dependency*& dep) { nex * common::nexvar(const rational & coeff, lpvar j, nex_creator& cn, u_dependency*& dep) {
SASSERT(!coeff.is_zero()); 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); add_deps_of_fixed(j, dep);
return cn.mk_scalar(coeff * c().m_lar_solver.column_lower_bound(j).x); 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); add_deps_of_fixed(j, dep);
return cn.mk_scalar(rational(0)); 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; mf *= coeff;
u_dependency * initial_dep = dep; u_dependency * initial_dep = dep;
for (lpvar k : m.vars()) { 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); add_deps_of_fixed(k, dep);
mf *= c().m_lar_solver.column_lower_bound(k).x; 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)) { c().var_is_fixed_to_zero(k)) {
dep = initial_dep; dep = initial_dep;
add_deps_of_fixed(k, dep); add_deps_of_fixed(k, dep);

View file

@ -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 { 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); 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; std::unordered_set<lpvar> vars;
auto insert_j = [&](lpvar j) { auto insert_j = [&](lpvar j) {
vars.insert(j); vars.insert(j);
if (m_emons.is_monic_var(j)) { if (is_monic_var(j)) {
for (lpvar k : m_emons[j].vars()) for (lpvar k : m_emons[j].vars())
vars.insert(k); vars.insert(k);
} }
@ -948,7 +948,7 @@ void core::maybe_add_a_factor(lpvar i,
std::unordered_set<unsigned>& found_rm, std::unordered_set<unsigned>& found_rm,
vector<factor> & r) const { vector<factor> & r) const {
SASSERT(abs(val(i)) == abs(val(c))); 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(); i = m_evars.find(i).var();
if (try_insert(i, found_vars)) { if (try_insert(i, found_vars)) {
r.push_back(factor(i, factor_type::VAR)); 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 { 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";); TRACE("nla_solver", tout << "j = " << j << ", m = "; print_monic(emons()[j], tout) << "\n";);
return true; // changing the value of a correct monic 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 { bool core::to_refine_is_correct() const {
for (unsigned j = 0; j < m_lar_solver.number_of_vars(); j++) { 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]); bool valid = check_monic(emons()[j]);
if (valid == m_to_refine.contains(j)) { if (valid == m_to_refine.contains(j)) {
TRACE("nla_solver", tout << "inconstency in m_to_refine : "; TRACE("nla_solver", tout << "inconstency in m_to_refine : ";
@ -1414,7 +1414,7 @@ void core::patch_monomials_on_to_refine() {
void core::patch_monomials() { void core::patch_monomials() {
m_cautious_patching = true; m_cautious_patching = true;
patch_monomials_on_to_refine(); 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; return;
} }
NOT_IMPLEMENTED_YET(); NOT_IMPLEMENTED_YET();
@ -1530,11 +1530,11 @@ lbool core::check(vector<lemma>& l_vec) {
check_weighted(3, checks); check_weighted(3, checks);
unsigned num_calls = lp_settings().stats().m_nla_calls; 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(); 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(); ret = m_nra.check();
m_stats.m_nra_calls++; m_stats.m_nra_calls++;
} }
@ -1554,7 +1554,7 @@ lbool core::check(vector<lemma>& l_vec) {
} }
bool core::should_run_bounded_nlsat() { bool core::should_run_bounded_nlsat() {
if (!m_nla_settings.run_nra()) if (!m_nla_settings.run_nra)
return false; return false;
if (m_nlsat_delay > m_nlsat_fails) if (m_nlsat_delay > m_nlsat_fails)
++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 { std::string core::var_str(lpvar j) const {
return is_monic_var(j)? std::string result;
(product_indices_str(m_emons[j].vars()) + (check_monic(m_emons[j])? "": "_")) : (std::string("j") + lp::T_to_string(j)); 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 { 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() { void core::run_grobner() {
unsigned& quota = m_nla_settings.grobner_quota(); unsigned& quota = m_nla_settings.grobner_quota;
if (quota == 1) { if (quota == 1) {
return; return;
} }
@ -1652,6 +1657,7 @@ void core::run_grobner() {
break; break;
} }
} }
TRACE("grobner", m_pdd_grobner.display(tout));
if (conflict) { if (conflict) {
IF_VERBOSE(2, verbose_stream() << "grobner conflict\n"); IF_VERBOSE(2, verbose_stream() << "grobner conflict\n");
return; return;
@ -1694,14 +1700,32 @@ void core::configure_grobner() {
m_pdd_grobner.reset(); m_pdd_grobner.reset();
try { try {
set_level2var_for_grobner(); set_level2var_for_grobner();
for (unsigned i : m_rows) { TRACE("grobner",
add_row_to_grobner(m_lar_solver.A_r().m_rows[i]); 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 (...) { catch (...) {
IF_VERBOSE(2, verbose_stream() << "pdd throw\n"); IF_VERBOSE(2, verbose_stream() << "pdd throw\n");
return; return;
} }
TRACE("grobner", m_pdd_grobner.display(tout));
#if 0 #if 0
IF_VERBOSE(2, m_pdd_grobner.display(verbose_stream())); IF_VERBOSE(2, m_pdd_grobner.display(verbose_stream()));
dd::pdd_eval eval(m_pdd_manager); dd::pdd_eval eval(m_pdd_manager);
@ -1717,11 +1741,11 @@ void core::configure_grobner() {
struct dd::solver::config cfg; struct dd::solver::config cfg;
cfg.m_max_steps = m_pdd_grobner.equations().size(); cfg.m_max_steps = m_pdd_grobner.equations().size();
cfg.m_max_simplified = m_nla_settings.grobner_max_simplified(); cfg.m_max_simplified = m_nla_settings.grobner_max_simplified;
cfg.m_eqs_growth = m_nla_settings.grobner_eqs_growth(); 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_size_growth = m_nla_settings.grobner_expr_size_growth;
cfg.m_expr_degree_growth = m_nla_settings.grobner_expr_degree_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_number_of_conflicts_to_report = m_nla_settings.grobner_number_of_conflicts_to_report;
m_pdd_grobner.set(cfg); m_pdd_grobner.set(cfg);
m_pdd_grobner.adjust_cfg(); m_pdd_grobner.adjust_cfg();
m_pdd_manager.set_max_num_nodes(10000); // or something proportional to the number of initial nodes. 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); scoped_dep_interval i(di), i_wd(di);
eval.get_interval<dd::w_dep::without_deps>(e->poly(), i); 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; return false;
}
eval.get_interval<dd::w_dep::with_deps>(e->poly(), i_wd); eval.get_interval<dd::w_dep::with_deps>(e->poly(), i_wd);
std::function<void (const lp::explanation&)> f = [this](const lp::explanation& e) { std::function<void (const lp::explanation&)> f = [this](const lp::explanation& e) {
new_lemma lemma(*this, "pdd"); new_lemma lemma(*this, "pdd");
lemma &= e; lemma &= e;
}; };
if (di.check_interval_for_conflict_on_zero(i_wd, e->dep(), f)) { 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++; lp_settings().stats().m_grobner_conflicts++;
return true; return true;
} }
else { else {
TRACE("grobner", m_pdd_grobner.display(tout << "no conflict ", *e) << "\n");
return false; return false;
} }
} }
void core::add_var_and_its_factors_to_q_and_collect_new_rows(lpvar j, svector<lpvar> & q) { 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; if (active_var_set_contains(j))
TRACE("grobner", tout << "j = " << j << ", " << pp(j);); return;
const auto& matrix = m_lar_solver.A_r();
insert_to_active_var_set(j); insert_to_active_var_set(j);
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 (var_is_fixed(j))
return;
const auto& matrix = m_lar_solver.A_r();
for (auto & s : matrix.m_columns[j]) { for (auto & s : matrix.m_columns[j]) {
unsigned row = s.var(); unsigned row = s.var();
if (m_rows.contains(row)) continue; if (m_rows.contains(row))
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; continue;
}
m_rows.insert(row); m_rows.insert(row);
for (auto& rc : matrix.m_rows[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); add_var_and_its_factors_to_q_and_collect_new_rows(rc.var(), q);
}
} }
if (!is_monic_var(j))
return;
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) { 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) { 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); dd::pdd r = m_pdd_manager.mk_val(c);
const monic& m = emons()[j]; sbuffer<lpvar> vars;
for (lpvar k : m.vars()) { vars.push_back(j);
if (m_nla_settings.grobner_subs_fixed() && var_is_fixed(k)) { u_dependency* zero_dep = dep;
r *= m_pdd_manager.mk_val(val_of_fixed_var_with_deps(k, dep)); while (!vars.empty()) {
} else if (m_nla_settings.grobner_subs_fixed() == 2 && var_is_fixed_to_zero(k)) { j = vars.back();
r = m_pdd_manager.mk_val(val_of_fixed_var_with_deps(k, zero_dep)); 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; dep = zero_dep;
return r; 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; return r;
} }
void core::add_row_to_grobner(const vector<lp::row_cell<rational>> & row) { void core::add_row_to_grobner(const vector<lp::row_cell<rational>> & row) {
u_dependency *dep = nullptr; u_dependency *dep = nullptr;
rational val;
dd::pdd sum = m_pdd_manager.mk_val(rational(0)); dd::pdd sum = m_pdd_manager.mk_val(rational(0));
for (const auto &p : row) { for (const auto &p : row)
sum += pdd_expr(p.coeff(), p.var(), dep); sum += pdd_expr(p.coeff(), p.var(), dep);
} TRACE("grobner", print_row(row, tout) << " " << sum << "\n");
m_pdd_grobner.add(sum, dep); 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() { void core::find_nl_cluster() {
prepare_rows_and_active_vars(); prepare_rows_and_active_vars();
svector<lpvar> q; svector<lpvar> q;
for (lpvar j : m_to_refine) { TRACE("grobner", for (lpvar j : m_to_refine) print_monic(emons()[j], tout) << "\n";);
TRACE("grobner", print_monic(emons()[j], tout) << "\n";);
for (lpvar j : m_to_refine)
q.push_back(j); q.push_back(j);
}
while (!q.empty()) { while (!q.empty()) {
lpvar j = q.back(); lpvar j = q.back();
q.pop_back(); q.pop_back();
add_var_and_its_factors_to_q_and_collect_new_rows(j, q); 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() { 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 { void core::display_matrix_of_m_rows(std::ostream & out) const {
const auto& matrix = m_lar_solver.A_r(); const auto& matrix = m_lar_solver.A_r();
out << m_rows.size() << " rows" <<"\n"; out << m_rows.size() << " rows" << "\n";
out << "the matrix\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; print_row(r, out) << std::endl;
}
} }
void core::set_active_vars_weights(nex_creator& nc) { void core::set_active_vars_weights(nex_creator& nc) {
nc.set_number_of_vars(m_lar_solver.column_count()); 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)); nc.set_var_weight(j, get_var_weight(j));
}
} }
void core::set_level2var_for_grobner() { void core::set_level2var_for_grobner() {
@ -1944,6 +1982,11 @@ void core::set_level2var_for_grobner() {
l2v[j] = sorted_vars[j]; l2v[j] = sorted_vars[j];
m_pdd_manager.reset(l2v); 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 { unsigned core::get_var_weight(lpvar j) const {
@ -1954,14 +1997,14 @@ unsigned core::get_var_weight(lpvar j) const {
k = 0; k = 0;
break; break;
case lp::column_type::boxed: case lp::column_type::boxed:
k = 2; k = 3;
break; break;
case lp::column_type::lower_bound: case lp::column_type::lower_bound:
case lp::column_type::upper_bound: case lp::column_type::upper_bound:
k = 4; k = 6;
break; break;
case lp::column_type::free_column: case lp::column_type::free_column:
k = 6; k = 9;
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
@ -1969,9 +2012,8 @@ unsigned core::get_var_weight(lpvar j) const {
} }
if (is_monic_var(j)) { if (is_monic_var(j)) {
k++; k++;
if (m_to_refine.contains(j)) { if (m_to_refine.contains(j))
k++; k++;
}
} }
return k; return k;
} }

View file

@ -243,11 +243,11 @@ public:
// returns true if the combination of the Horner's schema and Grobner Basis should be called // returns true if the combination of the Horner's schema and Grobner Basis should be called
bool need_run_horner() const { 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 { 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); void incremental_linearization(bool);
@ -456,8 +456,7 @@ public:
for (auto p : row) { for (auto p : row) {
v.push_back(std::make_pair(p.coeff(), p.var())); v.push_back(std::make_pair(p.coeff(), p.var()));
} }
return lp::print_linear_combination_customized(v, [this](lpvar j) { return var_str(j); }, return lp::print_linear_combination_customized(v, [this](lpvar j) { return var_str(j); }, out);
out);
} }
void run_grobner(); void run_grobner();
void find_nl_cluster(); void find_nl_cluster();

View file

@ -19,7 +19,7 @@ typedef lp::lar_term term;
// a > b && c > 0 => ac > bc // a > b && c > 0 => ac > bc
void order::order_lemma() { void order::order_lemma() {
TRACE("nla_solver", ); 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";); TRACE("nla_solver", tout << "not generating order lemmas\n";);
return; return;
} }

View file

@ -9,94 +9,38 @@ Author:
#pragma once #pragma once
namespace nla { namespace nla {
class nla_settings { struct nla_settings {
bool m_run_order; bool run_order = true;
bool m_run_tangents; bool run_tangents = true;
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; }
bool run_tangents() const { return m_run_tangents; } // horner fields
bool& run_tangents() { return m_run_tangents; } bool run_horner = true;
unsigned horner_frequency = 4;
unsigned horner_row_length_limit = 10;
unsigned horner_subs_fixed = 2;
bool expensive_patching() const { return m_expensive_patching; }
bool& expensive_patching() { return m_expensive_patching; }
bool run_horner() const { return m_run_horner; } // grobner fields
bool& run_horner() { return m_run_horner; } 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;
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; } // nra fields
bool& run_grobner() { return m_run_grobner; } bool run_nra = false;
unsigned grobner_frequency() const { return m_grobner_frequency; }
unsigned& grobner_frequency() { return m_grobner_frequency; }
bool run_nra() const { return m_run_nra; } // expensive patching
bool& run_nra() { return m_run_nra; } bool expensive_patching = false;
unsigned grobner_row_length_limit() const { return m_grobner_row_length_limit; } nla_settings() {}
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; }
};
} }

View file

@ -186,7 +186,7 @@ tangents::tangents(core * c) : common(c) {}
void tangents::tangent_lemma() { void tangents::tangent_lemma() {
factorization bf(nullptr); factorization bf(nullptr);
const monic* m = 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(); lpvar j = m->var();
tangent_imp tangent(point(val(bf[0]), val(bf[1])), c().val(j), *m, bf, *this); tangent_imp tangent(point(val(bf[0]), val(bf[1])), c().val(j), *m, bf, *this);
tangent(); tangent();

View file

@ -69,23 +69,23 @@ namespace arith {
m_nla->push(); m_nla->push();
} }
smt_params_helper prms(s().params()); smt_params_helper prms(s().params());
m_nla->settings().run_order() = prms.arith_nl_order(); m_nla->settings().run_order = prms.arith_nl_order();
m_nla->settings().run_tangents() = prms.arith_nl_tangents(); m_nla->settings().run_tangents = prms.arith_nl_tangents();
m_nla->settings().run_horner() = prms.arith_nl_horner(); m_nla->settings().run_horner = prms.arith_nl_horner();
m_nla->settings().horner_subs_fixed() = prms.arith_nl_horner_subs_fixed(); m_nla->settings().horner_subs_fixed = prms.arith_nl_horner_subs_fixed();
m_nla->settings().horner_frequency() = prms.arith_nl_horner_frequency(); m_nla->settings().horner_frequency = prms.arith_nl_horner_frequency();
m_nla->settings().horner_row_length_limit() = prms.arith_nl_horner_row_length_limit(); m_nla->settings().horner_row_length_limit = prms.arith_nl_horner_row_length_limit();
m_nla->settings().run_grobner() = prms.arith_nl_grobner(); m_nla->settings().run_grobner = prms.arith_nl_grobner();
m_nla->settings().run_nra() = prms.arith_nl_nra(); m_nla->settings().run_nra = prms.arith_nl_nra();
m_nla->settings().grobner_subs_fixed() = prms.arith_nl_grobner_subs_fixed(); m_nla->settings().grobner_subs_fixed = prms.arith_nl_grobner_subs_fixed();
m_nla->settings().grobner_eqs_growth() = prms.arith_nl_grobner_eqs_growth(); m_nla->settings().grobner_eqs_growth = prms.arith_nl_grobner_eqs_growth();
m_nla->settings().grobner_expr_size_growth() = prms.arith_nl_grobner_expr_size_growth(); m_nla->settings().grobner_expr_size_growth = prms.arith_nl_grobner_expr_size_growth();
m_nla->settings().grobner_expr_degree_growth() = prms.arith_nl_grobner_expr_degree_growth(); m_nla->settings().grobner_expr_degree_growth = prms.arith_nl_grobner_expr_degree_growth();
m_nla->settings().grobner_max_simplified() = prms.arith_nl_grobner_max_simplified(); m_nla->settings().grobner_max_simplified = prms.arith_nl_grobner_max_simplified();
m_nla->settings().grobner_number_of_conflicts_to_report() = prms.arith_nl_grobner_cnfl_to_report(); m_nla->settings().grobner_number_of_conflicts_to_report = prms.arith_nl_grobner_cnfl_to_report();
m_nla->settings().grobner_quota() = prms.arith_nl_gr_q(); m_nla->settings().grobner_quota = prms.arith_nl_gr_q();
m_nla->settings().grobner_frequency() = prms.arith_nl_grobner_frequency(); m_nla->settings().grobner_frequency = prms.arith_nl_grobner_frequency();
m_nla->settings().expensive_patching() = false; m_nla->settings().expensive_patching = false;
} }
} }

View file

@ -71,7 +71,7 @@ def_module_params(module_name='smt',
('arith.nl.grobner_max_simplified', UINT, 10000, 'grobner\'s maximum number of simplifications'), ('arith.nl.grobner_max_simplified', UINT, 10000, 'grobner\'s maximum number of simplifications'),
('arith.nl.grobner_cnfl_to_report', UINT, 1, 'grobner\'s maximum number of conflicts to report'), ('arith.nl.grobner_cnfl_to_report', UINT, 1, 'grobner\'s maximum number of conflicts to report'),
('arith.nl.gr_q', UINT, 10, 'grobner\'s quota'), ('arith.nl.gr_q', UINT, 10, 'grobner\'s quota'),
('arith.nl.grobner_subs_fixed', UINT, 2, '0 - no subs, 1 - substitute, 2 - substitute fixed zeros only'), ('arith.nl.grobner_subs_fixed', UINT, 1, '0 - no subs, 1 - substitute, 2 - substitute fixed zeros only'),
('arith.nl.delay', UINT, 500, 'number of calls to final check before invoking bounded nlsat check'), ('arith.nl.delay', UINT, 500, 'number of calls to final check before invoking bounded nlsat check'),
('arith.propagate_eqs', BOOL, True, 'propagate (cheap) equalities'), ('arith.propagate_eqs', BOOL, True, 'propagate (cheap) equalities'),
('arith.propagation_mode', UINT, 1, '0 - no propagation, 1 - propagate existing literals, 2 - refine finite bounds'), ('arith.propagation_mode', UINT, 1, '0 - no propagation, 1 - propagate existing literals, 2 - refine finite bounds'),

View file

@ -592,7 +592,7 @@ namespace smt {
// (or (= y 0) (<= (* y (div x y)) x)) // (or (= y 0) (<= (* y (div x y)) x))
else if (!m_util.is_numeral(divisor)) { else if (!m_util.is_numeral(divisor)) {
expr_ref div_ge(m), div_le(m), ge(m), le(m); expr_ref div_ge(m);
div_ge = m_util.mk_ge(m_util.mk_sub(dividend, m_util.mk_mul(divisor, div)), zero); div_ge = m_util.mk_ge(m_util.mk_sub(dividend, m_util.mk_mul(divisor, div)), zero);
s(div_ge); s(div_ge);
mk_axiom(eqz, div_ge, false); mk_axiom(eqz, div_ge, false);

View file

@ -80,14 +80,12 @@ void theory_arith<Ext>::mark_dependents(theory_var v, svector<theory_var> & vars
if (is_fixed(v)) if (is_fixed(v))
return; return;
column & c = m_columns[v]; column & c = m_columns[v];
typename svector<col_entry>::iterator it = c.begin_entries(); for (auto& ce : c) {
typename svector<col_entry>::iterator end = c.end_entries(); if (ce.is_dead() || already_visited_rows.contains(ce.m_row_id))
for (; it != end; ++it) {
if (it->is_dead() || already_visited_rows.contains(it->m_row_id))
continue; continue;
TRACE("non_linear_bug", tout << "visiting row: " << it->m_row_id << "\n";); TRACE("non_linear_bug", tout << "visiting row: " << ce.m_row_id << "\n";);
already_visited_rows.insert(it->m_row_id); already_visited_rows.insert(ce.m_row_id);
row & r = m_rows[it->m_row_id]; row & r = m_rows[ce.m_row_id];
theory_var s = r.get_base_var(); theory_var s = r.get_base_var();
// ignore quasi base vars... actually they should not be used if the problem is non linear... // ignore quasi base vars... actually they should not be used if the problem is non linear...
if (is_quasi_base(s)) if (is_quasi_base(s))
@ -97,14 +95,10 @@ void theory_arith<Ext>::mark_dependents(theory_var v, svector<theory_var> & vars
// was eliminated by substitution. // was eliminated by substitution.
if (s != null_theory_var && is_free(s) && s != v) if (s != null_theory_var && is_free(s) && s != v)
continue; continue;
typename vector<row_entry>::const_iterator it2 = r.begin_entries(); for (auto& re : r) {
typename vector<row_entry>::const_iterator end2 = r.end_entries(); if (!re.is_dead() && !is_fixed(re.m_var))
for (; it2 != end2; ++it2) { mark_var(re.m_var, vars, already_found);
if (!it2->is_dead() && !is_fixed(it2->m_var)) CTRACE("non_linear", !re.is_dead() && is_fixed(re.m_var), tout << "skipped fixed\n");
mark_var(it2->m_var, vars, already_found);
if (!it2->is_dead() && is_fixed(it2->m_var)) {
TRACE("non_linear", tout << "skipped fixed\n";);
}
} }
} }
} }
@ -119,6 +113,7 @@ void theory_arith<Ext>::get_non_linear_cluster(svector<theory_var> & vars) {
return; return;
var_set already_found; var_set already_found;
row_set already_visited_rows; row_set already_visited_rows;
for (theory_var v : m_nl_monomials) { for (theory_var v : m_nl_monomials) {
expr * n = var2expr(v); expr * n = var2expr(v);
if (ctx.is_relevant(n)) if (ctx.is_relevant(n))
@ -130,9 +125,9 @@ void theory_arith<Ext>::get_non_linear_cluster(svector<theory_var> & vars) {
TRACE("non_linear", tout << "marking dependents of: v" << v << "\n";); TRACE("non_linear", tout << "marking dependents of: v" << v << "\n";);
mark_dependents(v, vars, already_found, already_visited_rows); mark_dependents(v, vars, already_found, already_visited_rows);
} }
TRACE("non_linear", tout << "variables in non linear cluster:\n"; TRACE("non_linear", tout << "variables in non linear cluster: ";
for (theory_var v : vars) tout << "v" << v << " "; for (theory_var v : vars) tout << "v" << v << " "; tout << "\n";
tout << "\n";); for (theory_var v : m_nl_monomials) tout << "non-linear v" << v << " " << mk_pp(var2expr(v), m) << "\n";);
} }
@ -1740,22 +1735,21 @@ grobner::monomial * theory_arith<Ext>::mk_gb_monomial(rational const & _coeff, e
*/ */
template<typename Ext> template<typename Ext>
void theory_arith<Ext>::add_row_to_gb(row const & r, grobner & gb) { void theory_arith<Ext>::add_row_to_gb(row const & r, grobner & gb) {
TRACE("non_linear", tout << "adding row to gb\n"; display_row(tout, r);); TRACE("grobner", tout << "adding row to gb\n"; display_row(tout, r););
ptr_buffer<grobner::monomial> monomials; ptr_buffer<grobner::monomial> monomials;
v_dependency * dep = nullptr; v_dependency * dep = nullptr;
m_tmp_var_set.reset(); m_tmp_var_set.reset();
typename vector<row_entry>::const_iterator it = r.begin_entries(); for (auto& re : r) {
typename vector<row_entry>::const_iterator end = r.end_entries(); if (re.is_dead())
for (; it != end; ++it) { continue;
if (!it->is_dead()) { rational coeff = re.m_coeff.to_rational();
rational coeff = it->m_coeff.to_rational(); expr * m = var2expr(re.m_var);
expr * m = var2expr(it->m_var); grobner::monomial * new_m = mk_gb_monomial(coeff, m, gb, dep, m_tmp_var_set);
TRACE("non_linear", tout << "monomial: " << mk_pp(m, get_manager()) << "\n";); if (new_m)
grobner::monomial * new_m = mk_gb_monomial(coeff, m, gb, dep, m_tmp_var_set); monomials.push_back(new_m);
TRACE("non_linear", tout << "new monomial:\n"; if (new_m) gb.display_monomial(tout, *new_m); else tout << "null"; tout << "\n";); TRACE("grobner",
if (new_m) tout << "monomial: " << mk_pp(m, get_manager()) << "\n";
monomials.push_back(new_m); tout << "new monomial: "; if (new_m) gb.display_monomial(tout, *new_m); else tout << "null"; tout << "\n";);
}
} }
gb.assert_eq_0(monomials.size(), monomials.data(), dep); gb.assert_eq_0(monomials.size(), monomials.data(), dep);
} }
@ -2158,8 +2152,9 @@ bool theory_arith<Ext>::get_gb_eqs_and_look_for_conflict(ptr_vector<grobner::equ
eqs.reset(); eqs.reset();
gb.get_equations(eqs); gb.get_equations(eqs);
TRACE("grobner", tout << "after gb\n"; TRACE("grobner", tout << "after gb\n";
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { out << "v" << expr2var(v); };
for (grobner::equation* eq : eqs) for (grobner::equation* eq : eqs)
gb.display_equation(tout, *eq); gb.display_equation(tout, *eq, _fn);
); );
for (grobner::equation* eq : eqs) { for (grobner::equation* eq : eqs) {
if (is_inconsistent(eq, gb) || is_inconsistent2(eq, gb)) { if (is_inconsistent(eq, gb) || is_inconsistent2(eq, gb)) {
@ -2259,7 +2254,9 @@ typename theory_arith<Ext>::gb_result theory_arith<Ext>::compute_grobner(svector
ptr_vector<grobner::equation> eqs; ptr_vector<grobner::equation> eqs;
do { do {
TRACE("non_linear_gb", tout << "before:\n"; gb.display(tout);); TRACE("grobner", tout << "before grobner:\n";
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { out << "v" << expr2var(v); };
gb.display(tout, _fn));
compute_basis(gb, warn); compute_basis(gb, warn);
update_statistics(gb); update_statistics(gb);
TRACE("non_linear_gb", tout << "after:\n"; gb.display(tout);); TRACE("non_linear_gb", tout << "after:\n"; gb.display(tout););

View file

@ -276,23 +276,23 @@ class theory_lra::imp {
m_nla->push(); m_nla->push();
} }
smt_params_helper prms(ctx().get_params()); smt_params_helper prms(ctx().get_params());
m_nla->settings().run_order() = prms.arith_nl_order(); m_nla->settings().run_order = prms.arith_nl_order();
m_nla->settings().run_tangents() = prms.arith_nl_tangents(); m_nla->settings().run_tangents = prms.arith_nl_tangents();
m_nla->settings().run_horner() = prms.arith_nl_horner(); m_nla->settings().run_horner = prms.arith_nl_horner();
m_nla->settings().horner_subs_fixed() = prms.arith_nl_horner_subs_fixed(); m_nla->settings().horner_subs_fixed = prms.arith_nl_horner_subs_fixed();
m_nla->settings().horner_frequency() = prms.arith_nl_horner_frequency(); m_nla->settings().horner_frequency = prms.arith_nl_horner_frequency();
m_nla->settings().horner_row_length_limit() = prms.arith_nl_horner_row_length_limit(); m_nla->settings().horner_row_length_limit = prms.arith_nl_horner_row_length_limit();
m_nla->settings().run_grobner() = prms.arith_nl_grobner(); m_nla->settings().run_grobner = prms.arith_nl_grobner();
m_nla->settings().run_nra() = prms.arith_nl_nra(); m_nla->settings().run_nra = prms.arith_nl_nra();
m_nla->settings().grobner_subs_fixed() = prms.arith_nl_grobner_subs_fixed(); m_nla->settings().grobner_subs_fixed = prms.arith_nl_grobner_subs_fixed();
m_nla->settings().grobner_eqs_growth() = prms.arith_nl_grobner_eqs_growth(); m_nla->settings().grobner_eqs_growth = prms.arith_nl_grobner_eqs_growth();
m_nla->settings().grobner_expr_size_growth() = prms.arith_nl_grobner_expr_size_growth(); m_nla->settings().grobner_expr_size_growth = prms.arith_nl_grobner_expr_size_growth();
m_nla->settings().grobner_expr_degree_growth() = prms.arith_nl_grobner_expr_degree_growth(); m_nla->settings().grobner_expr_degree_growth = prms.arith_nl_grobner_expr_degree_growth();
m_nla->settings().grobner_max_simplified() = prms.arith_nl_grobner_max_simplified(); m_nla->settings().grobner_max_simplified = prms.arith_nl_grobner_max_simplified();
m_nla->settings().grobner_number_of_conflicts_to_report() = prms.arith_nl_grobner_cnfl_to_report(); m_nla->settings().grobner_number_of_conflicts_to_report = prms.arith_nl_grobner_cnfl_to_report();
m_nla->settings().grobner_quota() = prms.arith_nl_gr_q(); m_nla->settings().grobner_quota = prms.arith_nl_gr_q();
m_nla->settings().grobner_frequency() = prms.arith_nl_grobner_frequency(); m_nla->settings().grobner_frequency = prms.arith_nl_grobner_frequency();
m_nla->settings().expensive_patching() = false; m_nla->settings().expensive_patching = false;
} }
} }
@ -1224,7 +1224,7 @@ public:
return; return;
} }
expr_ref mod_r(a.mk_add(a.mk_mul(q, div), mod), m); expr_ref mod_r(a.mk_add(a.mk_mul(q, div), mod), m);
ctx().get_rewriter()(mod_r);
expr_ref eq_r(th.mk_eq_atom(mod_r, p), m); expr_ref eq_r(th.mk_eq_atom(mod_r, p), m);
ctx().internalize(eq_r, false); ctx().internalize(eq_r, false);
literal eq = ctx().get_literal(eq_r); literal eq = ctx().get_literal(eq_r);
@ -1256,6 +1256,38 @@ public:
} }
else { else {
expr_ref abs_q(m.mk_ite(a.mk_ge(q, zero), q, a.mk_uminus(q)), m);
expr_ref mone(a.mk_int(-1), m);
expr_ref modmq(a.mk_sub(mod, abs_q), m);
ctx().get_rewriter()(modmq);
literal eqz = mk_literal(m.mk_eq(q, zero));
literal mod_ge_0 = mk_literal(a.mk_ge(mod, zero));
literal mod_lt_q = mk_literal(a.mk_le(modmq, mone));
// q = 0 or p = (p mod q) + q * (p div q)
// q = 0 or (p mod q) >= 0
// q = 0 or (p mod q) < abs(q)
mk_axiom(eqz, eq);
mk_axiom(eqz, mod_ge_0);
mk_axiom(eqz, mod_lt_q);
if (a.is_zero(p)) {
mk_axiom(eqz, mk_literal(m.mk_eq(div, zero)));
mk_axiom(eqz, mk_literal(m.mk_eq(mod, zero)));
}
// (or (= y 0) (<= (* y (div x y)) x))
else if (!a.is_numeral(q)) {
expr_ref div_ge(m);
div_ge = a.mk_ge(a.mk_sub(p, a.mk_mul(q, div)), zero);
ctx().get_rewriter()(div_ge);
mk_axiom(eqz, mk_literal(div_ge));
TRACE("arith", tout << eqz << " " << div_ge << "\n");
}
#if 0
/*literal div_ge_0 = */ mk_literal(a.mk_ge(div, zero)); /*literal div_ge_0 = */ mk_literal(a.mk_ge(div, zero));
/*literal div_le_0 = */ mk_literal(a.mk_le(div, zero)); /*literal div_le_0 = */ mk_literal(a.mk_le(div, zero));
/*literal p_ge_0 = */ mk_literal(a.mk_ge(p, zero)); /*literal p_ge_0 = */ mk_literal(a.mk_ge(p, zero));
@ -1277,7 +1309,7 @@ public:
mk_axiom(q_le_0, mod_ge_0); mk_axiom(q_le_0, mod_ge_0);
mk_axiom(q_le_0, ~mk_literal(a.mk_ge(a.mk_sub(mod, q), zero))); mk_axiom(q_le_0, ~mk_literal(a.mk_ge(a.mk_sub(mod, q), zero)));
mk_axiom(q_ge_0, ~mk_literal(a.mk_ge(a.mk_add(mod, q), zero))); mk_axiom(q_ge_0, ~mk_literal(a.mk_ge(a.mk_add(mod, q), zero)));
#endif
#if 0 #if 0
// seem expensive // seem expensive
@ -1293,19 +1325,21 @@ public:
mk_axiom(q_ge_0, p_le_0, ~div_ge_0); mk_axiom(q_ge_0, p_le_0, ~div_ge_0);
#endif #endif
#if 0
std::function<void(void)> log = [&,this]() { std::function<void(void)> log = [&,this]() {
th.log_axiom_unit(m.mk_implies(m.mk_not(m.mk_eq(q, zero)), c.bool_var2expr(eq.var()))); th.log_axiom_unit(m.mk_implies(m.mk_not(m.mk_eq(q, zero)), c.bool_var2expr(eq.var())));
th.log_axiom_unit(m.mk_implies(m.mk_not(m.mk_eq(q, zero)), c.bool_var2expr(mod_ge_0.var()))); th.log_axiom_unit(m.mk_implies(m.mk_not(m.mk_eq(q, zero)), c.bool_var2expr(mod_ge_0.var())));
th.log_axiom_unit(m.mk_implies(a.mk_lt(q, zero), a.mk_lt(a.mk_sub(mod, q), zero))); th.log_axiom_unit(m.mk_implies(a.mk_lt(q, zero), a.mk_lt(a.mk_sub(mod, q), zero)));
th.log_axiom_unit(m.mk_implies(a.mk_lt(q, zero), a.mk_lt(a.mk_add(mod, q), zero))); th.log_axiom_unit(m.mk_implies(a.mk_lt(q, zero), a.mk_lt(a.mk_add(mod, q), zero)));
};
if_trace_stream _ts(m, log);
#endif
#if 0 #if 0
th.log_axiom_unit(m.mk_implies(m.mk_and(a.mk_gt(q, zero), c.bool_var2expr(p_ge_0.var())), c.bool_var2expr(div_ge_0.var()))); th.log_axiom_unit(m.mk_implies(m.mk_and(a.mk_gt(q, zero), c.bool_var2expr(p_ge_0.var())), c.bool_var2expr(div_ge_0.var())));
th.log_axiom_unit(m.mk_implies(m.mk_and(a.mk_gt(q, zero), c.bool_var2expr(p_le_0.var())), c.bool_var2expr(div_le_0.var()))); th.log_axiom_unit(m.mk_implies(m.mk_and(a.mk_gt(q, zero), c.bool_var2expr(p_le_0.var())), c.bool_var2expr(div_le_0.var())));
th.log_axiom_unit(m.mk_implies(m.mk_and(a.mk_lt(q, zero), c.bool_var2expr(p_ge_0.var())), c.bool_var2expr(div_le_0.var()))); th.log_axiom_unit(m.mk_implies(m.mk_and(a.mk_lt(q, zero), c.bool_var2expr(p_ge_0.var())), c.bool_var2expr(div_le_0.var())));
th.log_axiom_unit(m.mk_implies(m.mk_and(a.mk_lt(q, zero), c.bool_var2expr(p_le_0.var())), c.bool_var2expr(div_ge_0.var()))); th.log_axiom_unit(m.mk_implies(m.mk_and(a.mk_lt(q, zero), c.bool_var2expr(p_le_0.var())), c.bool_var2expr(div_ge_0.var())));
#endif #endif
};
if_trace_stream _ts(m, log);
} }
if (params().m_arith_enum_const_mod && k.is_pos() && k < rational(8)) { if (params().m_arith_enum_const_mod && k.is_pos() && k < rational(8)) {
unsigned _k = k.get_unsigned(); unsigned _k = k.get_unsigned();