3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-10 03:07:07 +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,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);

View file

@ -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);
}
};
}

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()) {
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;
}

View file

@ -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;
};

View file

@ -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>

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

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,
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);

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 {
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;
}

View file

@ -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();

View file

@ -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;
}

View file

@ -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() {}
};
}

View file

@ -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();

View file

@ -69,23 +69,23 @@ namespace arith {
m_nla->push();
}
smt_params_helper prms(s().params());
m_nla->settings().run_order() = prms.arith_nl_order();
m_nla->settings().run_tangents() = prms.arith_nl_tangents();
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_frequency() = prms.arith_nl_horner_frequency();
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_nra() = prms.arith_nl_nra();
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_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_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_quota() = prms.arith_nl_gr_q();
m_nla->settings().grobner_frequency() = prms.arith_nl_grobner_frequency();
m_nla->settings().expensive_patching() = false;
m_nla->settings().run_order = prms.arith_nl_order();
m_nla->settings().run_tangents = prms.arith_nl_tangents();
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_frequency = prms.arith_nl_horner_frequency();
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_nra = prms.arith_nl_nra();
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_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_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_quota = prms.arith_nl_gr_q();
m_nla->settings().grobner_frequency = prms.arith_nl_grobner_frequency();
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_cnfl_to_report', UINT, 1, 'grobner\'s maximum number of conflicts to report'),
('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.propagate_eqs', BOOL, True, 'propagate (cheap) equalities'),
('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))
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);
s(div_ge);
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))
return;
column & c = m_columns[v];
typename svector<col_entry>::iterator it = c.begin_entries();
typename svector<col_entry>::iterator end = c.end_entries();
for (; it != end; ++it) {
if (it->is_dead() || already_visited_rows.contains(it->m_row_id))
for (auto& ce : c) {
if (ce.is_dead() || already_visited_rows.contains(ce.m_row_id))
continue;
TRACE("non_linear_bug", tout << "visiting row: " << it->m_row_id << "\n";);
already_visited_rows.insert(it->m_row_id);
row & r = m_rows[it->m_row_id];
TRACE("non_linear_bug", tout << "visiting row: " << ce.m_row_id << "\n";);
already_visited_rows.insert(ce.m_row_id);
row & r = m_rows[ce.m_row_id];
theory_var s = r.get_base_var();
// ignore quasi base vars... actually they should not be used if the problem is non linear...
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.
if (s != null_theory_var && is_free(s) && s != v)
continue;
typename vector<row_entry>::const_iterator it2 = r.begin_entries();
typename vector<row_entry>::const_iterator end2 = r.end_entries();
for (; it2 != end2; ++it2) {
if (!it2->is_dead() && !is_fixed(it2->m_var))
mark_var(it2->m_var, vars, already_found);
if (!it2->is_dead() && is_fixed(it2->m_var)) {
TRACE("non_linear", tout << "skipped fixed\n";);
}
for (auto& re : r) {
if (!re.is_dead() && !is_fixed(re.m_var))
mark_var(re.m_var, vars, already_found);
CTRACE("non_linear", !re.is_dead() && is_fixed(re.m_var), tout << "skipped fixed\n");
}
}
}
@ -119,6 +113,7 @@ void theory_arith<Ext>::get_non_linear_cluster(svector<theory_var> & vars) {
return;
var_set already_found;
row_set already_visited_rows;
for (theory_var v : m_nl_monomials) {
expr * n = var2expr(v);
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";);
mark_dependents(v, vars, already_found, already_visited_rows);
}
TRACE("non_linear", tout << "variables in non linear cluster:\n";
for (theory_var v : vars) tout << "v" << v << " ";
tout << "\n";);
TRACE("non_linear", tout << "variables in non linear cluster: ";
for (theory_var v : vars) tout << "v" << v << " "; 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>
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;
v_dependency * dep = nullptr;
m_tmp_var_set.reset();
typename vector<row_entry>::const_iterator it = r.begin_entries();
typename vector<row_entry>::const_iterator end = r.end_entries();
for (; it != end; ++it) {
if (!it->is_dead()) {
rational coeff = it->m_coeff.to_rational();
expr * m = var2expr(it->m_var);
TRACE("non_linear", tout << "monomial: " << mk_pp(m, get_manager()) << "\n";);
grobner::monomial * new_m = mk_gb_monomial(coeff, m, gb, dep, m_tmp_var_set);
TRACE("non_linear", tout << "new monomial:\n"; if (new_m) gb.display_monomial(tout, *new_m); else tout << "null"; tout << "\n";);
if (new_m)
monomials.push_back(new_m);
}
for (auto& re : r) {
if (re.is_dead())
continue;
rational coeff = re.m_coeff.to_rational();
expr * m = var2expr(re.m_var);
grobner::monomial * new_m = mk_gb_monomial(coeff, m, gb, dep, m_tmp_var_set);
if (new_m)
monomials.push_back(new_m);
TRACE("grobner",
tout << "monomial: " << mk_pp(m, get_manager()) << "\n";
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);
}
@ -2158,8 +2152,9 @@ bool theory_arith<Ext>::get_gb_eqs_and_look_for_conflict(ptr_vector<grobner::equ
eqs.reset();
gb.get_equations(eqs);
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)
gb.display_equation(tout, *eq);
gb.display_equation(tout, *eq, _fn);
);
for (grobner::equation* eq : eqs) {
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;
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);
update_statistics(gb);
TRACE("non_linear_gb", tout << "after:\n"; gb.display(tout););

View file

@ -276,23 +276,23 @@ class theory_lra::imp {
m_nla->push();
}
smt_params_helper prms(ctx().get_params());
m_nla->settings().run_order() = prms.arith_nl_order();
m_nla->settings().run_tangents() = prms.arith_nl_tangents();
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_frequency() = prms.arith_nl_horner_frequency();
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_nra() = prms.arith_nl_nra();
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_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_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_quota() = prms.arith_nl_gr_q();
m_nla->settings().grobner_frequency() = prms.arith_nl_grobner_frequency();
m_nla->settings().expensive_patching() = false;
m_nla->settings().run_order = prms.arith_nl_order();
m_nla->settings().run_tangents = prms.arith_nl_tangents();
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_frequency = prms.arith_nl_horner_frequency();
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_nra = prms.arith_nl_nra();
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_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_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_quota = prms.arith_nl_gr_q();
m_nla->settings().grobner_frequency = prms.arith_nl_grobner_frequency();
m_nla->settings().expensive_patching = false;
}
}
@ -1224,9 +1224,9 @@ public:
return;
}
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);
ctx().internalize(eq_r, false);
ctx().internalize(eq_r, false);
literal eq = ctx().get_literal(eq_r);
rational k(0);
@ -1256,6 +1256,38 @@ public:
}
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_le_0 = */ mk_literal(a.mk_le(div, zero));
/*literal p_ge_0 = */ mk_literal(a.mk_ge(p, zero));
@ -1266,7 +1298,7 @@ public:
// q >= 0 or (p mod q) >= 0
// q <= 0 or (p mod q) >= 0
// q <= 0 or (p mod q) < q
// q >= 0 or (p mod q) < -q
// q >= 0 or (p mod q) < -q
literal q_ge_0 = mk_literal(a.mk_ge(q, zero));
literal q_le_0 = mk_literal(a.mk_le(q, zero));
literal mod_ge_0 = mk_literal(a.mk_ge(mod, zero));
@ -1277,11 +1309,11 @@ public:
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_ge_0, ~mk_literal(a.mk_ge(a.mk_add(mod, q), zero)));
#endif
#if 0
// seem expensive
mk_axiom(q_le_0, ~p_ge_0, div_ge_0);
mk_axiom(q_le_0, ~p_le_0, div_le_0);
mk_axiom(q_ge_0, ~p_ge_0, div_le_0);
@ -1293,19 +1325,21 @@ public:
mk_axiom(q_ge_0, p_le_0, ~div_ge_0);
#endif
#if 0
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(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_add(mod, q), zero)));
};
if_trace_stream _ts(m, log);
#endif
#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_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_le_0.var())), c.bool_var2expr(div_ge_0.var())));
#endif
};
if_trace_stream _ts(m, log);
}
if (params().m_arith_enum_const_mod && k.is_pos() && k < rational(8)) {
unsigned _k = k.get_unsigned();