mirror of
https://github.com/Z3Prover/z3
synced 2025-04-27 19:05:51 +00:00
Merge branch 'master' into polysat
This commit is contained in:
commit
e168d8a2eb
109 changed files with 4372 additions and 2743 deletions
|
@ -1741,6 +1741,87 @@ namespace dd {
|
|||
return (*this) * rational::power_of_two(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief substitute variable v by r.
|
||||
* This base line implementation is simplistic and does not use operator caching.
|
||||
*/
|
||||
pdd pdd::subst_pdd(unsigned v, pdd const& r) const {
|
||||
if (is_val())
|
||||
return *this;
|
||||
if (m.m_var2level[var()] < m.m_var2level[v])
|
||||
return *this;
|
||||
pdd l = lo().subst_pdd(v, r);
|
||||
pdd h = hi().subst_pdd(v, r);
|
||||
if (var() == v)
|
||||
return r*h + l;
|
||||
else if (l == lo() && h == hi())
|
||||
return *this;
|
||||
else
|
||||
return m.mk_var(var())*h + l;
|
||||
}
|
||||
|
||||
std::pair<unsigned_vector, pdd> pdd::var_factors() const {
|
||||
if (is_val())
|
||||
return { unsigned_vector(), *this };
|
||||
unsigned v = var();
|
||||
if (lo().is_val()) {
|
||||
if (!lo().is_zero())
|
||||
return { unsigned_vector(), *this };
|
||||
auto [vars, p] = hi().var_factors();
|
||||
vars.push_back(v);
|
||||
return {vars, p};
|
||||
}
|
||||
auto [lo_vars, q] = lo().var_factors();
|
||||
if (lo_vars.empty())
|
||||
return { unsigned_vector(), *this };
|
||||
|
||||
unsigned_vector lo_and_hi;
|
||||
auto merge = [&](unsigned_vector& lo_vars, unsigned_vector& hi_vars) {
|
||||
unsigned ir = 0, jr = 0;
|
||||
for (unsigned i = 0, j = 0; i < lo_vars.size() || j < hi_vars.size(); ) {
|
||||
if (i == lo_vars.size())
|
||||
hi_vars[jr++] = hi_vars[j++];
|
||||
else if (j == hi_vars.size())
|
||||
lo_vars[ir++] = lo_vars[i++];
|
||||
else if (lo_vars[i] == hi_vars[j]) {
|
||||
lo_and_hi.push_back(lo_vars[i]);
|
||||
++i;
|
||||
++j;
|
||||
}
|
||||
else if (m.m_var2level[lo_vars[i]] > m.m_var2level[hi_vars[j]])
|
||||
hi_vars[jr++] = hi_vars[j++];
|
||||
else
|
||||
lo_vars[ir++] = lo_vars[i++];
|
||||
}
|
||||
lo_vars.shrink(ir);
|
||||
hi_vars.shrink(jr);
|
||||
};
|
||||
|
||||
auto mul = [&](unsigned_vector const& vars, pdd p) {
|
||||
for (auto v : vars)
|
||||
p *= m.mk_var(v);
|
||||
return p;
|
||||
};
|
||||
|
||||
auto [hi_vars, p] = hi().var_factors();
|
||||
if (lo_vars.back() == v) {
|
||||
lo_vars.pop_back();
|
||||
merge(lo_vars, hi_vars);
|
||||
lo_and_hi.push_back(v);
|
||||
return { lo_and_hi, mul(lo_vars, q) + mul(hi_vars, p) };
|
||||
}
|
||||
if (hi_vars.empty())
|
||||
return { unsigned_vector(), *this };
|
||||
|
||||
merge(lo_vars, hi_vars);
|
||||
hi_vars.push_back(v);
|
||||
if (lo_and_hi.empty())
|
||||
return { unsigned_vector(), *this };
|
||||
else
|
||||
return { lo_and_hi, mul(lo_vars, q) + mul(hi_vars, p) };
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, pdd const& b) { return b.display(out); }
|
||||
|
||||
void pdd_iterator::next() {
|
||||
|
|
|
@ -447,11 +447,22 @@ namespace dd {
|
|||
bool resolve(unsigned v, pdd const& other, pdd& result) { return m.resolve(v, *this, other, result); }
|
||||
pdd reduce(unsigned v, pdd const& other) const { return m.reduce(v, *this, other); }
|
||||
|
||||
/**
|
||||
* \brief factor out variables
|
||||
*/
|
||||
std::pair<unsigned_vector, pdd> var_factors() const;
|
||||
|
||||
pdd subst_val0(vector<std::pair<unsigned, rational>> const& s) const { return m.subst_val0(*this, s); }
|
||||
pdd subst_val(pdd const& s) const { return m.subst_val(*this, s); }
|
||||
pdd subst_val(vector<std::pair<unsigned, rational>> const& s) const { return m.subst_val0(*this, s); }
|
||||
pdd subst_val(unsigned v, rational const& val) const { return m.subst_val(*this, v, val); }
|
||||
pdd subst_add(unsigned var, rational const& val) { return m.subst_add(*this, var, val); }
|
||||
|
||||
/**
|
||||
* \brief substitute variable v by r.
|
||||
*/
|
||||
pdd subst_pdd(unsigned v, pdd const& r) const;
|
||||
|
||||
std::ostream& display(std::ostream& out) const { return m.display(out, *this); }
|
||||
bool operator==(pdd const& other) const { return root == other.root; }
|
||||
bool operator!=(pdd const& other) const { return root != other.root; }
|
||||
|
|
|
@ -27,7 +27,33 @@ typedef dep_intervals::with_deps_t w_dep;
|
|||
class pdd_interval {
|
||||
dep_intervals& m_dep_intervals;
|
||||
std::function<void (unsigned, bool, scoped_dep_interval&)> m_var2interval;
|
||||
|
||||
|
||||
// retrieve intervals after distributing multiplication over addition.
|
||||
template <w_dep wd>
|
||||
void get_interval_distributed(pdd const& p, scoped_dep_interval& i, scoped_dep_interval& ret) {
|
||||
bool deps = wd == w_dep::with_deps;
|
||||
if (p.is_val()) {
|
||||
if (deps)
|
||||
m_dep_intervals.mul<dep_intervals::with_deps>(p.val(), i, ret);
|
||||
else
|
||||
m_dep_intervals.mul<dep_intervals::without_deps>(p.val(), i, ret);
|
||||
return;
|
||||
}
|
||||
scoped_dep_interval hi(m()), lo(m()), t(m()), a(m());
|
||||
get_interval_distributed<wd>(p.lo(), i, lo);
|
||||
m_var2interval(p.var(), deps, a);
|
||||
if (deps) {
|
||||
m_dep_intervals.mul<dep_intervals::with_deps>(a, i, t);
|
||||
get_interval_distributed<wd>(p.hi(), t, hi);
|
||||
m_dep_intervals.add<dep_intervals::with_deps>(hi, lo, ret);
|
||||
}
|
||||
else {
|
||||
m_dep_intervals.mul<dep_intervals::without_deps>(a, i, t);
|
||||
get_interval_distributed<wd>(p.hi(), t, hi);
|
||||
m_dep_intervals.add<dep_intervals::without_deps>(hi, lo, ret);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
pdd_interval(dep_intervals& d): m_dep_intervals(d) {}
|
||||
|
@ -57,5 +83,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
template <w_dep wd>
|
||||
void get_interval_distributed(pdd const& p, scoped_dep_interval& ret) {
|
||||
scoped_dep_interval i(m());
|
||||
m_dep_intervals.set_interval_for_scalar(i, rational::one());
|
||||
get_interval_distributed<wd>(p, i, ret);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ void grobner::display_vars(std::ostream & out, unsigned num_vars, expr * const *
|
|||
}
|
||||
}
|
||||
|
||||
void grobner::display_monomial(std::ostream & out, monomial const & m) const {
|
||||
void grobner::display_monomial(std::ostream & out, monomial const & m, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
if (!m.m_coeff.is_one() || m.m_vars.empty()) {
|
||||
out << m.m_coeff;
|
||||
if (!m.m_vars.empty())
|
||||
|
@ -165,7 +165,7 @@ void grobner::display_monomial(std::ostream & out, monomial const & m) const {
|
|||
}
|
||||
}
|
||||
|
||||
void grobner::display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials) const {
|
||||
void grobner::display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
bool first = true;
|
||||
for (unsigned i = 0; i < num_monomials; i++) {
|
||||
monomial const * m = monomials[i];
|
||||
|
@ -173,26 +173,26 @@ void grobner::display_monomials(std::ostream & out, unsigned num_monomials, mono
|
|||
first = false;
|
||||
else
|
||||
out << " + ";
|
||||
display_monomial(out, *m);
|
||||
display_monomial(out, *m, display_var);
|
||||
}
|
||||
}
|
||||
|
||||
void grobner::display_equation(std::ostream & out, equation const & eq) const {
|
||||
display_monomials(out, eq.m_monomials.size(), eq.m_monomials.data());
|
||||
void grobner::display_equation(std::ostream & out, equation const & eq, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
display_monomials(out, eq.m_monomials.size(), eq.m_monomials.data(), display_var);
|
||||
out << " = 0\n";
|
||||
}
|
||||
|
||||
void grobner::display_equations(std::ostream & out, equation_set const & v, char const * header) const {
|
||||
if (!v.empty()) {
|
||||
out << header << "\n";
|
||||
for (equation const* eq : v)
|
||||
display_equation(out, *eq);
|
||||
}
|
||||
void grobner::display_equations(std::ostream & out, equation_set const & v, char const * header, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
if (v.empty())
|
||||
return;
|
||||
out << header << "\n";
|
||||
for (equation const* eq : v)
|
||||
display_equation(out, *eq, display_var);
|
||||
}
|
||||
|
||||
void grobner::display(std::ostream & out) const {
|
||||
display_equations(out, m_processed, "processed:");
|
||||
display_equations(out, m_to_process, "to process:");
|
||||
void grobner::display(std::ostream & out, std::function<void(std::ostream&, expr*)>& display_var) const {
|
||||
display_equations(out, m_processed, "processed:", display_var);
|
||||
display_equations(out, m_to_process, "to process:", display_var);
|
||||
}
|
||||
|
||||
void grobner::set_weight(expr * n, int weight) {
|
||||
|
@ -528,7 +528,7 @@ bool grobner::is_subset(monomial const * m1, monomial const * m2, ptr_vector<exp
|
|||
for (; i2 < sz2; i2++)
|
||||
rest.push_back(m2->m_vars[i2]);
|
||||
TRACE("grobner",
|
||||
tout << "monomail: "; display_monomial(tout, *m1); tout << " is a subset of ";
|
||||
tout << "monomial: "; display_monomial(tout, *m1); tout << " is a subset of ";
|
||||
display_monomial(tout, *m2); tout << "\n";
|
||||
tout << "rest: "; display_vars(tout, rest.size(), rest.data()); tout << "\n";);
|
||||
return true;
|
||||
|
@ -552,7 +552,7 @@ bool grobner::is_subset(monomial const * m1, monomial const * m2, ptr_vector<exp
|
|||
}
|
||||
}
|
||||
// is not subset
|
||||
TRACE("grobner", tout << "monomail: "; display_monomial(tout, *m1); tout << " is not a subset of ";
|
||||
TRACE("grobner", tout << "monomial: "; display_monomial(tout, *m1); tout << " is not a subset of ";
|
||||
display_monomial(tout, *m2); tout << "\n";);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -120,9 +120,16 @@ protected:
|
|||
|
||||
void display_var(std::ostream & out, expr * var) const;
|
||||
|
||||
void display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials) const;
|
||||
void display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
|
||||
void display_equations(std::ostream & out, equation_set const & v, char const * header) const;
|
||||
|
||||
void display_monomials(std::ostream & out, unsigned num_monomials, monomial * const * monomials) const {
|
||||
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { display_var(out, v); };
|
||||
display_monomials(out, num_monomials, monomials, _fn);
|
||||
}
|
||||
|
||||
|
||||
void display_equations(std::ostream & out, equation_set const & v, char const * header, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
|
||||
void del_equations(unsigned old_size);
|
||||
|
||||
|
@ -281,11 +288,26 @@ public:
|
|||
|
||||
void pop_scope(unsigned num_scopes);
|
||||
|
||||
void display_equation(std::ostream & out, equation const & eq) const;
|
||||
void display_equation(std::ostream & out, equation const & eq) const {
|
||||
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { display_var(out, v); };
|
||||
display_equation(out, eq, _fn);
|
||||
}
|
||||
|
||||
void display_monomial(std::ostream & out, monomial const & m) const;
|
||||
void display_monomial(std::ostream & out, monomial const & m) const {
|
||||
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { display_var(out, v); };
|
||||
display_monomial(out, m, _fn);
|
||||
}
|
||||
|
||||
void display_equation(std::ostream & out, equation const & eq, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
|
||||
void display(std::ostream & out) const;
|
||||
void display_monomial(std::ostream & out, monomial const & m, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
|
||||
void display(std::ostream & out) const {
|
||||
std::function<void(std::ostream& out, expr* v)> _fn = [&](std::ostream& out, expr* v) { display_var(out, v); };
|
||||
display(out, _fn);
|
||||
}
|
||||
|
||||
void display(std::ostream & out, std::function<void(std::ostream&, expr*)>& display_var) const;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -223,6 +223,8 @@ namespace dd {
|
|||
for (unsigned i = 0; i < s.m_to_simplify.size(); ++i) {
|
||||
equation* e = s.m_to_simplify[i];
|
||||
pdd p = e->poly();
|
||||
if (p.is_val())
|
||||
continue;
|
||||
if (!p.hi().is_val()) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
||||
|
@ -169,7 +169,7 @@ namespace dd {
|
|||
/*
|
||||
Use the given equation to simplify equations in set
|
||||
*/
|
||||
void solver::simplify_using(equation_vector& set, equation const& eq) {
|
||||
void solver::simplify_using(equation_vector& set, std::function<bool(equation&, bool&)>& simplifier) {
|
||||
struct scoped_update {
|
||||
equation_vector& set;
|
||||
unsigned i, j, sz;
|
||||
|
@ -191,7 +191,7 @@ namespace dd {
|
|||
equation& target = *set[sr.i];
|
||||
bool changed_leading_term = false;
|
||||
bool simplified = true;
|
||||
simplified = !done() && try_simplify_using(target, eq, changed_leading_term);
|
||||
simplified = !done() && simplifier(target, changed_leading_term);
|
||||
|
||||
if (simplified && is_trivial(target)) {
|
||||
retire(&target);
|
||||
|
@ -200,7 +200,6 @@ namespace dd {
|
|||
// pushed to solved
|
||||
}
|
||||
else if (simplified && changed_leading_term) {
|
||||
SASSERT(target.state() == processed);
|
||||
push_equation(to_simplify, target);
|
||||
if (!m_var2level.empty()) {
|
||||
m_levelp1 = std::max(m_var2level[target.poly().var()]+1, m_levelp1);
|
||||
|
@ -210,6 +209,13 @@ namespace dd {
|
|||
sr.nextj();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void solver::simplify_using(equation_vector& set, equation const& eq) {
|
||||
std::function<bool(equation&, bool&)> simplifier = [&](equation& target, bool& changed_leading_term) {
|
||||
return try_simplify_using(target, eq, changed_leading_term);
|
||||
};
|
||||
simplify_using(set, simplifier);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -342,6 +348,7 @@ namespace dd {
|
|||
for (equation* e : m_solved) dealloc(e);
|
||||
for (equation* e : m_to_simplify) dealloc(e);
|
||||
for (equation* e : m_processed) dealloc(e);
|
||||
m_subst.reset();
|
||||
m_solved.reset();
|
||||
m_processed.reset();
|
||||
m_to_simplify.reset();
|
||||
|
@ -352,18 +359,54 @@ namespace dd {
|
|||
}
|
||||
|
||||
void solver::add(pdd const& p, u_dependency * dep) {
|
||||
if (p.is_zero()) return;
|
||||
equation * eq = alloc(equation, p, dep);
|
||||
if (check_conflict(*eq)) {
|
||||
if (p.is_zero())
|
||||
return;
|
||||
equation * eq = alloc(equation, p, dep);
|
||||
if (check_conflict(*eq))
|
||||
return;
|
||||
}
|
||||
push_equation(to_simplify, eq);
|
||||
|
||||
if (!m_var2level.empty()) {
|
||||
if (!m_var2level.empty())
|
||||
m_levelp1 = std::max(m_var2level[p.var()]+1, m_levelp1);
|
||||
}
|
||||
update_stats_max_degree_and_size(*eq);
|
||||
}
|
||||
}
|
||||
|
||||
void solver::add_subst(unsigned v, pdd const& p, u_dependency* dep) {
|
||||
m_subst.push_back({v, p, dep});
|
||||
if (!m_var2level.empty())
|
||||
m_levelp1 = std::max(m_var2level[v]+1, std::max(m_var2level[p.var()]+1, m_levelp1));
|
||||
|
||||
std::function<bool(equation&, bool&)> simplifier = [&](equation& dst, bool& changed_leading_term) {
|
||||
auto r = dst.poly().subst_pdd(v, p);
|
||||
if (r == dst.poly())
|
||||
return false;
|
||||
if (is_too_complex(r)) {
|
||||
m_too_complex = true;
|
||||
return false;
|
||||
}
|
||||
changed_leading_term = m.different_leading_term(r, dst.poly());
|
||||
dst = r;
|
||||
dst = m_dep_manager.mk_join(dst.dep(), dep);
|
||||
update_stats_max_degree_and_size(dst);
|
||||
return true;
|
||||
};
|
||||
if (!done())
|
||||
simplify_using(m_processed, simplifier);
|
||||
if (!done())
|
||||
simplify_using(m_to_simplify, simplifier);
|
||||
if (!done())
|
||||
simplify_using(m_solved, simplifier);
|
||||
}
|
||||
|
||||
void solver::simplify(pdd& p, u_dependency*& d) {
|
||||
for (auto const& [v, q, d2] : m_subst) {
|
||||
pdd r = p.subst_pdd(v, q);
|
||||
if (r != p) {
|
||||
p = r;
|
||||
d = m_dep_manager.mk_join(d, d2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool solver::canceled() {
|
||||
return m_limit.is_canceled();
|
||||
|
@ -446,9 +489,24 @@ namespace dd {
|
|||
}
|
||||
|
||||
std::ostream& solver::display(std::ostream& out) const {
|
||||
out << "solved\n"; for (auto e : m_solved) display(out, *e);
|
||||
out << "processed\n"; for (auto e : m_processed) display(out, *e);
|
||||
out << "to_simplify\n"; for (auto e : m_to_simplify) display(out, *e);
|
||||
if (!m_solved.empty()) {
|
||||
out << "solved\n"; for (auto e : m_solved) display(out, *e);
|
||||
}
|
||||
if (!m_processed.empty()) {
|
||||
out << "processed\n"; for (auto e : m_processed) display(out, *e);
|
||||
}
|
||||
if (!m_to_simplify.empty()) {
|
||||
out << "to_simplify\n"; for (auto e : m_to_simplify) display(out, *e);
|
||||
}
|
||||
if (!m_subst.empty()) {
|
||||
out << "subst\n";
|
||||
for (auto const& [v, p, d] : m_subst) {
|
||||
out << "v" << v << " := " << p;
|
||||
if (m_print_dep)
|
||||
m_print_dep(d, out);
|
||||
out << "\n";
|
||||
}
|
||||
}
|
||||
return display_statistics(out);
|
||||
}
|
||||
|
||||
|
|
|
@ -118,6 +118,7 @@ private:
|
|||
equation_vector m_solved; // equations with solved variables, triangular
|
||||
equation_vector m_processed;
|
||||
equation_vector m_to_simplify;
|
||||
vector<std::tuple<unsigned, pdd, u_dependency*>> m_subst;
|
||||
mutable u_dependency_manager m_dep_manager;
|
||||
equation_vector m_all_eqs;
|
||||
equation* m_conflict;
|
||||
|
@ -136,6 +137,9 @@ public:
|
|||
void add(pdd const& p) { add(p, nullptr); }
|
||||
void add(pdd const& p, u_dependency * dep);
|
||||
|
||||
void simplify(pdd& p, u_dependency*& dep);
|
||||
void add_subst(unsigned v, pdd const& p, u_dependency* dep);
|
||||
|
||||
void simplify();
|
||||
void saturate();
|
||||
|
||||
|
@ -160,6 +164,7 @@ private:
|
|||
void simplify_using(equation& eq, equation_vector const& eqs);
|
||||
void simplify_using(equation_vector& set, equation const& eq);
|
||||
void simplify_using(equation & dst, equation const& src, bool& changed_leading_term);
|
||||
void simplify_using(equation_vector& set, std::function<bool(equation&, bool&)>& simplifier);
|
||||
bool try_simplify_using(equation& target, equation const& source, bool& changed_leading_term);
|
||||
|
||||
bool is_trivial(equation const& eq) const { return eq.poly().is_zero(); }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -34,6 +34,7 @@ z3_add_component(lp
|
|||
nla_basics_lemmas.cpp
|
||||
nla_common.cpp
|
||||
nla_core.cpp
|
||||
nla_grobner.cpp
|
||||
nla_intervals.cpp
|
||||
nla_monotone_lemmas.cpp
|
||||
nla_order_lemmas.cpp
|
||||
|
|
|
@ -40,7 +40,7 @@ bool horner::row_has_monomial_to_refine(const T& row) const {
|
|||
template <typename T>
|
||||
bool horner::row_is_interesting(const T& row) const {
|
||||
TRACE("nla_solver_details", c().print_row(row, tout););
|
||||
if (row.size() > c().m_nla_settings.horner_row_length_limit()) {
|
||||
if (row.size() > c().m_nla_settings.horner_row_length_limit) {
|
||||
TRACE("nla_solver_details", tout << "disregard\n";);
|
||||
return false;
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ bool horner::lemmas_on_row(const T& row) {
|
|||
}
|
||||
|
||||
bool horner::horner_lemmas() {
|
||||
if (!c().m_nla_settings.run_horner()) {
|
||||
if (!c().m_nla_settings.run_horner) {
|
||||
TRACE("nla_solver", tout << "not generating horner lemmas\n";);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -275,9 +275,6 @@ class lar_solver : public column_namer {
|
|||
return m_column_buffer;
|
||||
}
|
||||
bool bound_is_integer_for_integer_column(unsigned j, const mpq & right_side) const;
|
||||
inline unsigned get_base_column_in_row(unsigned row_index) const {
|
||||
return m_mpq_lar_core_solver.m_r_solver.get_base_column_in_row(row_index);
|
||||
}
|
||||
inline lar_core_solver & get_core_solver() { return m_mpq_lar_core_solver; }
|
||||
void catch_up_in_updating_int_solver();
|
||||
var_index to_column(unsigned ext_j) const;
|
||||
|
@ -357,6 +354,10 @@ public:
|
|||
}
|
||||
|
||||
void set_value_for_nbasic_column(unsigned j, const impq& new_val);
|
||||
inline unsigned get_base_column_in_row(unsigned row_index) const {
|
||||
return m_mpq_lar_core_solver.m_r_solver.get_base_column_in_row(row_index);
|
||||
}
|
||||
|
||||
|
||||
// lp_assert(implied_bound_is_correctly_explained(ib, explanation)); }
|
||||
constraint_index mk_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side);
|
||||
|
@ -630,6 +631,7 @@ public:
|
|||
}
|
||||
void round_to_integer_solution();
|
||||
inline const row_strip<mpq> & get_row(unsigned i) const { return A_r().m_rows[i]; }
|
||||
inline const row_strip<mpq> & basic2row(unsigned i) const { return A_r().m_rows[row_of_basic_column(i)]; }
|
||||
inline const column_strip & get_column(unsigned i) const { return A_r().m_columns[i]; }
|
||||
bool row_is_correct(unsigned i) const;
|
||||
bool ax_is_correct() const;
|
||||
|
|
|
@ -71,11 +71,11 @@ void common::add_deps_of_fixed(lpvar j, u_dependency*& dep) {
|
|||
// creates a nex expression for the coeff and var,
|
||||
nex * common::nexvar(const rational & coeff, lpvar j, nex_creator& cn, u_dependency*& dep) {
|
||||
SASSERT(!coeff.is_zero());
|
||||
if (c().m_nla_settings.horner_subs_fixed() == 1 && c().var_is_fixed(j)) {
|
||||
if (c().m_nla_settings.horner_subs_fixed == 1 && c().var_is_fixed(j)) {
|
||||
add_deps_of_fixed(j, dep);
|
||||
return cn.mk_scalar(coeff * c().m_lar_solver.column_lower_bound(j).x);
|
||||
}
|
||||
if (c().m_nla_settings.horner_subs_fixed() == 2 && c().var_is_fixed_to_zero(j)) {
|
||||
if (c().m_nla_settings.horner_subs_fixed == 2 && c().var_is_fixed_to_zero(j)) {
|
||||
add_deps_of_fixed(j, dep);
|
||||
return cn.mk_scalar(rational(0));
|
||||
}
|
||||
|
@ -89,10 +89,10 @@ nex * common::nexvar(const rational & coeff, lpvar j, nex_creator& cn, u_depende
|
|||
mf *= coeff;
|
||||
u_dependency * initial_dep = dep;
|
||||
for (lpvar k : m.vars()) {
|
||||
if (c().m_nla_settings.horner_subs_fixed() && c().var_is_fixed(k)) {
|
||||
if (c().m_nla_settings.horner_subs_fixed == 1 && c().var_is_fixed(k)) {
|
||||
add_deps_of_fixed(k, dep);
|
||||
mf *= c().m_lar_solver.column_lower_bound(k).x;
|
||||
} else if (c().m_nla_settings.horner_subs_fixed() == 2 &&
|
||||
} else if (c().m_nla_settings.horner_subs_fixed == 2 &&
|
||||
c().var_is_fixed_to_zero(k)) {
|
||||
dep = initial_dep;
|
||||
add_deps_of_fixed(k, dep);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -18,15 +18,18 @@
|
|||
#include "math/lp/nla_basics_lemmas.h"
|
||||
#include "math/lp/nla_order_lemmas.h"
|
||||
#include "math/lp/nla_monotone_lemmas.h"
|
||||
#include "math/lp/nla_grobner.h"
|
||||
#include "math/lp/emonics.h"
|
||||
#include "math/lp/nla_settings.h"
|
||||
#include "math/lp/nex.h"
|
||||
#include "math/lp/horner.h"
|
||||
#include "math/lp/monomial_bounds.h"
|
||||
#include "math/lp/nla_intervals.h"
|
||||
#include "math/grobner/pdd_solver.h"
|
||||
#include "nlsat/nlsat_solver.h"
|
||||
|
||||
namespace nra {
|
||||
class solver;
|
||||
}
|
||||
|
||||
namespace nla {
|
||||
|
||||
|
@ -139,6 +142,20 @@ struct pp_factorization {
|
|||
};
|
||||
|
||||
class core {
|
||||
friend struct common;
|
||||
friend class new_lemma;
|
||||
friend class grobner;
|
||||
friend class order;
|
||||
friend struct basics;
|
||||
friend struct tangents;
|
||||
friend class monotone;
|
||||
friend struct nla_settings;
|
||||
friend class intervals;
|
||||
friend class horner;
|
||||
friend class solver;
|
||||
friend class monomial_bounds;
|
||||
friend class nra::solver;
|
||||
|
||||
struct stats {
|
||||
unsigned m_nla_explanations;
|
||||
unsigned m_nla_lemmas;
|
||||
|
@ -148,16 +165,18 @@ class core {
|
|||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
};
|
||||
stats m_stats;
|
||||
friend class new_lemma;
|
||||
|
||||
unsigned m_nlsat_delay { 50 };
|
||||
unsigned m_nlsat_fails { 0 };
|
||||
stats m_stats;
|
||||
unsigned m_nlsat_delay = 50;
|
||||
unsigned m_nlsat_fails = 0;
|
||||
|
||||
bool should_run_bounded_nlsat();
|
||||
lbool bounded_nlsat();
|
||||
public:
|
||||
|
||||
var_eqs<emonics> m_evars;
|
||||
|
||||
lp::lar_solver& m_lar_solver;
|
||||
reslimit& m_reslim;
|
||||
vector<lemma> * m_lemma_vec;
|
||||
lp::u_set m_to_refine;
|
||||
tangents m_tangents;
|
||||
|
@ -166,24 +185,21 @@ public:
|
|||
monotone m_monotone;
|
||||
intervals m_intervals;
|
||||
monomial_bounds m_monomial_bounds;
|
||||
nla_settings m_nla_settings;
|
||||
|
||||
horner m_horner;
|
||||
nla_settings m_nla_settings;
|
||||
dd::pdd_manager m_pdd_manager;
|
||||
dd::solver m_pdd_grobner;
|
||||
private:
|
||||
grobner m_grobner;
|
||||
emonics m_emons;
|
||||
svector<lpvar> m_add_buffer;
|
||||
mutable lp::u_set m_active_var_set;
|
||||
lp::u_set m_rows;
|
||||
|
||||
reslimit m_nra_lim;
|
||||
public:
|
||||
reslimit& m_reslim;
|
||||
bool m_use_nra_model;
|
||||
|
||||
bool m_use_nra_model = false;
|
||||
nra::solver m_nra;
|
||||
private:
|
||||
bool m_cautious_patching;
|
||||
lpvar m_patched_var;
|
||||
monic const* m_patched_monic;
|
||||
bool m_cautious_patching = true;
|
||||
lpvar m_patched_var = 0;
|
||||
monic const* m_patched_monic = nullptr;
|
||||
|
||||
void check_weighted(unsigned sz, std::pair<unsigned, std::function<void(void)>>* checks);
|
||||
|
||||
|
@ -205,6 +221,8 @@ public:
|
|||
m_active_var_set.resize(m_lar_solver.number_of_vars());
|
||||
}
|
||||
|
||||
unsigned get_var_weight(lpvar) const;
|
||||
|
||||
reslimit& reslim() { return m_reslim; }
|
||||
emonics& emons() { return m_emons; }
|
||||
const emonics& emons() const { return m_emons; }
|
||||
|
@ -243,12 +261,15 @@ 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 set_active_vars_weights(nex_creator&);
|
||||
std::unordered_set<lpvar> get_vars_of_expr_with_opening_terms(const nex* e);
|
||||
|
||||
void incremental_linearization(bool);
|
||||
|
||||
|
@ -450,31 +471,19 @@ public:
|
|||
lpvar map_to_root(lpvar) const;
|
||||
std::ostream& print_terms(std::ostream&) const;
|
||||
std::ostream& print_term(const lp::lar_term&, std::ostream&) const;
|
||||
|
||||
template <typename T>
|
||||
std::ostream& print_row(const T & row , std::ostream& out) const {
|
||||
std::ostream& print_row(const T& row, std::ostream& out) const {
|
||||
vector<std::pair<rational, lpvar>> v;
|
||||
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();
|
||||
void prepare_rows_and_active_vars();
|
||||
void add_var_and_its_factors_to_q_and_collect_new_rows(lpvar j, svector<lpvar>& q);
|
||||
std::unordered_set<lpvar> get_vars_of_expr_with_opening_terms(const nex* e);
|
||||
void display_matrix_of_m_rows(std::ostream & out) const;
|
||||
void set_active_vars_weights(nex_creator&);
|
||||
unsigned get_var_weight(lpvar) const;
|
||||
void add_row_to_grobner(const vector<lp::row_cell<rational>> & row);
|
||||
bool check_pdd_eq(const dd::solver::equation*);
|
||||
const rational& val_of_fixed_var_with_deps(lpvar j, u_dependency*& dep);
|
||||
dd::pdd pdd_expr(const rational& c, lpvar j, u_dependency*&);
|
||||
void set_level2var_for_grobner();
|
||||
void configure_grobner();
|
||||
|
||||
bool influences_nl_var(lpvar) const;
|
||||
bool is_nl_var(lpvar) const;
|
||||
|
||||
bool is_used_in_monic(lpvar) const;
|
||||
void patch_monomials();
|
||||
void patch_monomials_on_to_refine();
|
||||
|
|
545
src/math/lp/nla_grobner.cpp
Normal file
545
src/math/lp/nla_grobner.cpp
Normal file
|
@ -0,0 +1,545 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
nla_grobner.cpp
|
||||
|
||||
Author:
|
||||
Lev Nachmanson (levnach)
|
||||
Nikolaj Bjorner (nbjorner)
|
||||
|
||||
--*/
|
||||
#include "util/uint_set.h"
|
||||
#include "math/lp/nla_core.h"
|
||||
#include "math/lp/factorization_factory_imp.h"
|
||||
#include "math/lp/nex.h"
|
||||
#include "math/grobner/pdd_solver.h"
|
||||
#include "math/dd/pdd_interval.h"
|
||||
#include "math/dd/pdd_eval.h"
|
||||
|
||||
namespace nla {
|
||||
|
||||
grobner::grobner(core* c):
|
||||
common(c),
|
||||
m_pdd_manager(m_core.m_lar_solver.number_of_vars()),
|
||||
m_solver(m_core.m_reslim, m_pdd_manager),
|
||||
m_lar_solver(m_core.m_lar_solver)
|
||||
|
||||
{}
|
||||
|
||||
lp::lp_settings& grobner::lp_settings() {
|
||||
return c().lp_settings();
|
||||
}
|
||||
|
||||
void grobner::operator()() {
|
||||
unsigned& quota = c().m_nla_settings.grobner_quota;
|
||||
if (quota == 1)
|
||||
return;
|
||||
|
||||
lp_settings().stats().m_grobner_calls++;
|
||||
find_nl_cluster();
|
||||
configure();
|
||||
m_solver.saturate();
|
||||
|
||||
if (is_conflicting())
|
||||
return;
|
||||
|
||||
if (propagate_bounds())
|
||||
return;
|
||||
|
||||
if (propagate_eqs())
|
||||
return;
|
||||
|
||||
if (propagate_factorization())
|
||||
return;
|
||||
|
||||
if (quota > 1)
|
||||
quota--;
|
||||
|
||||
IF_VERBOSE(2, verbose_stream() << "grobner miss, quota " << quota << "\n");
|
||||
IF_VERBOSE(4, diagnose_pdd_miss(verbose_stream()));
|
||||
|
||||
#if 0
|
||||
// diagnostics: did we miss something
|
||||
vector<dd::pdd> eqs;
|
||||
for (auto eq : m_solver.equations())
|
||||
eqs.push_back(eq->poly());
|
||||
c().m_nra.check(eqs);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool grobner::is_conflicting() {
|
||||
unsigned conflicts = 0;
|
||||
for (auto eq : m_solver.equations())
|
||||
if (is_conflicting(*eq) && ++conflicts >= m_solver.number_of_conflicts_to_report())
|
||||
break;
|
||||
|
||||
if (conflicts > 0)
|
||||
lp_settings().stats().m_grobner_conflicts++;
|
||||
|
||||
TRACE("grobner", m_solver.display(tout));
|
||||
IF_VERBOSE(2, if (conflicts > 0) verbose_stream() << "grobner conflict\n");
|
||||
|
||||
return conflicts > 0;
|
||||
}
|
||||
|
||||
bool grobner::propagate_bounds() {
|
||||
unsigned changed = 0;
|
||||
for (auto eq : m_solver.equations())
|
||||
if (propagate_bounds(*eq) && ++changed >= m_solver.number_of_conflicts_to_report())
|
||||
return true;
|
||||
return changed > 0;
|
||||
}
|
||||
|
||||
bool grobner::propagate_eqs() {
|
||||
unsigned changed = 0;
|
||||
for (auto eq : m_solver.equations())
|
||||
if (propagate_fixed(*eq) && ++changed >= m_solver.number_of_conflicts_to_report())
|
||||
return true;
|
||||
return changed > 0;
|
||||
}
|
||||
|
||||
bool grobner::propagate_factorization() {
|
||||
unsigned changed = 0;
|
||||
for (auto eq : m_solver.equations())
|
||||
if (propagate_factorization(*eq) && ++changed >= m_solver.number_of_conflicts_to_report())
|
||||
return true;
|
||||
return changed > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief detect equalities
|
||||
- k*x = 0, that is x = 0
|
||||
- ax + b = 0
|
||||
*/
|
||||
typedef lp::lar_term term;
|
||||
bool grobner::propagate_fixed(const dd::solver::equation& eq) {
|
||||
dd::pdd const& p = eq.poly();
|
||||
//IF_VERBOSE(0, verbose_stream() << p << "\n");
|
||||
if (p.is_unary()) {
|
||||
unsigned v = p.var();
|
||||
if (c().var_is_fixed(v))
|
||||
return false;
|
||||
ineq new_eq(v, llc::EQ, rational::zero());
|
||||
if (c().ineq_holds(new_eq))
|
||||
return false;
|
||||
new_lemma lemma(c(), "pdd-eq");
|
||||
add_dependencies(lemma, eq);
|
||||
lemma |= new_eq;
|
||||
return true;
|
||||
}
|
||||
if (p.is_offset()) {
|
||||
unsigned v = p.var();
|
||||
if (c().var_is_fixed(v))
|
||||
return false;
|
||||
rational a = p.hi().val();
|
||||
rational b = -p.lo().val();
|
||||
rational d = lcm(denominator(a), denominator(b));
|
||||
a *= d;
|
||||
b *= d;
|
||||
ineq new_eq(term(a, v), llc::EQ, b);
|
||||
if (c().ineq_holds(new_eq))
|
||||
return false;
|
||||
new_lemma lemma(c(), "pdd-eq");
|
||||
add_dependencies(lemma, eq);
|
||||
lemma |= new_eq;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief detect simple factors
|
||||
x*q = 0 => x = 0 or q = 0
|
||||
*/
|
||||
|
||||
bool grobner::propagate_factorization(const dd::solver::equation& eq) {
|
||||
dd::pdd const& p = eq.poly();
|
||||
auto [vars, q] = p.var_factors();
|
||||
if (vars.empty() || !q.is_linear())
|
||||
return false;
|
||||
|
||||
// IF_VERBOSE(0, verbose_stream() << "factored " << q << " : " << vars << "\n");
|
||||
|
||||
term t;
|
||||
while (!q.is_val()) {
|
||||
t.add_monomial(q.hi().val(), q.var());
|
||||
q = q.lo();
|
||||
}
|
||||
vector<ineq> ineqs;
|
||||
for (auto v : vars)
|
||||
ineqs.push_back(ineq(v, llc::EQ, rational::zero()));
|
||||
ineqs.push_back(ineq(t, llc::EQ, -q.val()));
|
||||
for (auto const& i : ineqs)
|
||||
if (c().ineq_holds(i))
|
||||
return false;
|
||||
|
||||
new_lemma lemma(c(), "pdd-factored");
|
||||
add_dependencies(lemma, eq);
|
||||
for (auto const& i : ineqs)
|
||||
lemma |= i;
|
||||
//lemma.display(verbose_stream());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void grobner::add_dependencies(new_lemma& lemma, const dd::solver::equation& eq) {
|
||||
lp::explanation ex;
|
||||
u_dependency_manager dm;
|
||||
vector<unsigned, false> lv;
|
||||
dm.linearize(eq.dep(), lv);
|
||||
for (unsigned ci : lv)
|
||||
ex.push_back(ci);
|
||||
lemma &= ex;
|
||||
}
|
||||
|
||||
void grobner::configure() {
|
||||
m_solver.reset();
|
||||
try {
|
||||
set_level2var();
|
||||
TRACE("grobner",
|
||||
tout << "base vars: ";
|
||||
for (lpvar j : c().active_var_set())
|
||||
if (m_lar_solver.is_base(j))
|
||||
tout << "j" << j << " ";
|
||||
tout << "\n");
|
||||
for (lpvar j : c().active_var_set()) {
|
||||
if (m_lar_solver.is_base(j))
|
||||
add_row(m_lar_solver.basic2row(j));
|
||||
|
||||
if (c().is_monic_var(j) && c().var_is_fixed(j))
|
||||
add_fixed_monic(j);
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
IF_VERBOSE(2, verbose_stream() << "pdd throw\n");
|
||||
return;
|
||||
}
|
||||
TRACE("grobner", m_solver.display(tout));
|
||||
|
||||
#if 0
|
||||
IF_VERBOSE(2, m_pdd_grobner.display(verbose_stream()));
|
||||
dd::pdd_eval eval(m_pdd_manager);
|
||||
eval.var2val() = [&](unsigned j){ return val(j); };
|
||||
for (auto* e : m_pdd_grobner.equations()) {
|
||||
dd::pdd p = e->poly();
|
||||
rational v = eval(p);
|
||||
if (p.is_linear() && !eval(p).is_zero()) {
|
||||
IF_VERBOSE(0, verbose_stream() << "violated linear constraint " << p << "\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
struct dd::solver::config cfg;
|
||||
cfg.m_max_steps = m_solver.equations().size();
|
||||
cfg.m_max_simplified = c().m_nla_settings.grobner_max_simplified;
|
||||
cfg.m_eqs_growth = c().m_nla_settings.grobner_eqs_growth;
|
||||
cfg.m_expr_size_growth = c().m_nla_settings.grobner_expr_size_growth;
|
||||
cfg.m_expr_degree_growth = c().m_nla_settings.grobner_expr_degree_growth;
|
||||
cfg.m_number_of_conflicts_to_report = c().m_nla_settings.grobner_number_of_conflicts_to_report;
|
||||
m_solver.set(cfg);
|
||||
m_solver.adjust_cfg();
|
||||
m_pdd_manager.set_max_num_nodes(10000); // or something proportional to the number of initial nodes.
|
||||
}
|
||||
|
||||
std::ostream& grobner::diagnose_pdd_miss(std::ostream& out) {
|
||||
|
||||
// m_pdd_grobner.display(out);
|
||||
|
||||
dd::pdd_eval eval;
|
||||
eval.var2val() = [&](unsigned j){ return val(j); };
|
||||
for (auto* e : m_solver.equations()) {
|
||||
dd::pdd p = e->poly();
|
||||
rational v = eval(p);
|
||||
if (!v.is_zero()) {
|
||||
out << p << " := " << v << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < m_lar_solver.number_of_vars(); ++j) {
|
||||
if (m_lar_solver.column_has_lower_bound(j) || m_lar_solver.column_has_upper_bound(j)) {
|
||||
out << j << ": [";
|
||||
if (m_lar_solver.column_has_lower_bound(j)) out << m_lar_solver.get_lower_bound(j);
|
||||
out << "..";
|
||||
if (m_lar_solver.column_has_upper_bound(j)) out << m_lar_solver.get_upper_bound(j);
|
||||
out << "]\n";
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool grobner::is_conflicting(const dd::solver::equation& e) {
|
||||
auto& di = c().m_intervals.get_dep_intervals();
|
||||
dd::pdd_interval eval(di);
|
||||
eval.var2interval() = [this](lpvar j, bool deps, scoped_dep_interval& a) {
|
||||
if (deps) c().m_intervals.set_var_interval<dd::w_dep::with_deps>(j, a);
|
||||
else c().m_intervals.set_var_interval<dd::w_dep::without_deps>(j, a);
|
||||
};
|
||||
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)) {
|
||||
TRACE("grobner", m_solver.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);
|
||||
c().m_intervals.set_var_interval<dd::w_dep::without_deps>(j, a);
|
||||
c().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(m_core, "pdd");
|
||||
lemma &= e;
|
||||
};
|
||||
if (di.check_interval_for_conflict_on_zero(i_wd, e.dep(), f)) {
|
||||
TRACE("grobner", m_solver.display(tout << "conflict ", e) << "\n");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
TRACE("grobner", m_solver.display(tout << "no conflict ", e) << "\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool grobner::propagate_bounds(const dd::solver::equation& e) {
|
||||
return false;
|
||||
// TODO
|
||||
auto& di = c().m_intervals.get_dep_intervals();
|
||||
dd::pdd_interval eval(di);
|
||||
eval.var2interval() = [this](lpvar j, bool deps, scoped_dep_interval& a) {
|
||||
if (deps) c().m_intervals.set_var_interval<dd::w_dep::with_deps>(j, a);
|
||||
else c().m_intervals.set_var_interval<dd::w_dep::without_deps>(j, a);
|
||||
};
|
||||
scoped_dep_interval i(di), i_wd(di);
|
||||
eval.get_interval<dd::w_dep::without_deps>(e.poly(), i);
|
||||
return false;
|
||||
}
|
||||
|
||||
void grobner::add_var_and_its_factors_to_q_and_collect_new_rows(lpvar j, svector<lpvar> & q) {
|
||||
if (c().active_var_set_contains(j))
|
||||
return;
|
||||
c().insert_to_active_var_set(j);
|
||||
if (c().is_monic_var(j)) {
|
||||
const monic& m = c().emons()[j];
|
||||
for (auto fcn : factorization_factory_imp(m, m_core))
|
||||
for (const factor& fc: fcn)
|
||||
q.push_back(var(fc));
|
||||
}
|
||||
|
||||
if (c().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() > c().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() > c().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 rational& grobner::val_of_fixed_var_with_deps(lpvar j, u_dependency*& dep) {
|
||||
unsigned lc, uc;
|
||||
m_lar_solver.get_bound_constraint_witnesses_for_column(j, lc, uc);
|
||||
dep = c().m_intervals.mk_join(dep, c().m_intervals.mk_leaf(lc));
|
||||
dep = c().m_intervals.mk_join(dep, c().m_intervals.mk_leaf(uc));
|
||||
return m_lar_solver.column_lower_bound(j).x;
|
||||
}
|
||||
|
||||
dd::pdd grobner::pdd_expr(const rational& coeff, lpvar j, u_dependency*& dep) {
|
||||
dd::pdd r = m_pdd_manager.mk_val(coeff);
|
||||
sbuffer<lpvar> vars;
|
||||
vars.push_back(j);
|
||||
u_dependency* zero_dep = dep;
|
||||
while (!vars.empty()) {
|
||||
j = vars.back();
|
||||
vars.pop_back();
|
||||
if (c().m_nla_settings.grobner_subs_fixed > 0 && c().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;
|
||||
}
|
||||
if (c().m_nla_settings.grobner_subs_fixed == 1 && c().var_is_fixed(j))
|
||||
r *= val_of_fixed_var_with_deps(j, dep);
|
||||
else if (!c().is_monic_var(j))
|
||||
r *= m_pdd_manager.mk_var(j);
|
||||
else
|
||||
for (lpvar k : c().emons()[j].vars())
|
||||
vars.push_back(k);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief convert p == 0 into a solved form v == r, such that
|
||||
v has bounds [lo, oo) iff r has bounds [lo', oo)
|
||||
v has bounds (oo,hi] iff r has bounds (oo,hi']
|
||||
|
||||
The solved form allows the Grobner solver identify more bounds conflicts.
|
||||
A bad leading term can miss bounds conflicts.
|
||||
For example for x + y + z == 0 where x, y : [0, oo) and z : (oo,0]
|
||||
we prefer to solve z == -x - y instead of x == -z - y
|
||||
because the solution -z - y has neither an upper, nor a lower bound.
|
||||
*/
|
||||
bool grobner::is_solved(dd::pdd const& p, unsigned& v, dd::pdd& r) {
|
||||
if (!p.is_linear())
|
||||
return false;
|
||||
r = p;
|
||||
unsigned num_lo = 0, num_hi = 0;
|
||||
unsigned lo = 0, hi = 0;
|
||||
rational lc, hc, c;
|
||||
while (!r.is_val()) {
|
||||
SASSERT(r.hi().is_val());
|
||||
v = r.var();
|
||||
rational val = r.hi().val();
|
||||
switch (m_lar_solver.get_column_type(v)) {
|
||||
case lp::column_type::lower_bound:
|
||||
if (val > 0) num_lo++, lo = v, lc = val; else num_hi++, hi = v, hc = val;
|
||||
break;
|
||||
case lp::column_type::upper_bound:
|
||||
if (val < 0) num_lo++, lo = v, lc = val; else num_hi++, hi = v, hc = val;
|
||||
break;
|
||||
case lp::column_type::fixed:
|
||||
case lp::column_type::boxed:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (num_lo > 1 && num_hi > 1)
|
||||
return false;
|
||||
r = r.lo();
|
||||
}
|
||||
if (num_lo == 1 && num_hi > 1) {
|
||||
v = lo;
|
||||
c = lc;
|
||||
}
|
||||
else if (num_hi == 1 && num_lo > 1) {
|
||||
v = hi;
|
||||
c = hc;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
r = c*m_pdd_manager.mk_var(v) - p;
|
||||
if (c != 1)
|
||||
r = r * (1/c);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief add an equality to grobner solver, convert it to solved form if available.
|
||||
*/
|
||||
void grobner::add_eq(dd::pdd& p, u_dependency* dep) {
|
||||
unsigned v;
|
||||
dd::pdd q(m_pdd_manager);
|
||||
m_solver.simplify(p, dep);
|
||||
if (is_solved(p, v, q))
|
||||
m_solver.add_subst(v, q, dep);
|
||||
else
|
||||
m_solver.add(p, dep);
|
||||
}
|
||||
|
||||
void grobner::add_fixed_monic(unsigned j) {
|
||||
u_dependency* dep = nullptr;
|
||||
dd::pdd r = m_pdd_manager.mk_val(rational(1));
|
||||
for (lpvar k : c().emons()[j].vars())
|
||||
r *= pdd_expr(rational::one(), k, dep);
|
||||
r -= val_of_fixed_var_with_deps(j, dep);
|
||||
add_eq(r, dep);
|
||||
}
|
||||
|
||||
void grobner::add_row(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);
|
||||
TRACE("grobner", c().print_row(row, tout) << " " << sum << "\n");
|
||||
add_eq(sum, dep);
|
||||
}
|
||||
|
||||
|
||||
void grobner::find_nl_cluster() {
|
||||
prepare_rows_and_active_vars();
|
||||
svector<lpvar> q;
|
||||
TRACE("grobner", for (lpvar j : c().m_to_refine) print_monic(c().emons()[j], tout) << "\n";);
|
||||
|
||||
for (lpvar j : c().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", tout << "vars in cluster: ";
|
||||
for (lpvar j : c().active_var_set()) tout << "j" << j << " "; tout << "\n";
|
||||
display_matrix_of_m_rows(tout);
|
||||
);
|
||||
}
|
||||
|
||||
void grobner::prepare_rows_and_active_vars() {
|
||||
m_rows.clear();
|
||||
m_rows.resize(m_lar_solver.row_count());
|
||||
c().clear_and_resize_active_var_set();
|
||||
}
|
||||
|
||||
|
||||
void grobner::display_matrix_of_m_rows(std::ostream & out) const {
|
||||
const auto& matrix = m_lar_solver.A_r();
|
||||
out << m_rows.size() << " rows" << "\n";
|
||||
out << "the matrix\n";
|
||||
for (const auto & r : matrix.m_rows)
|
||||
c().print_row(r, out) << std::endl;
|
||||
}
|
||||
|
||||
void grobner::set_level2var() {
|
||||
unsigned n = m_lar_solver.column_count();
|
||||
unsigned_vector sorted_vars(n), weighted_vars(n);
|
||||
for (unsigned j = 0; j < n; j++) {
|
||||
sorted_vars[j] = j;
|
||||
weighted_vars[j] = c().get_var_weight(j);
|
||||
}
|
||||
#if 1
|
||||
// potential update to weights
|
||||
for (unsigned j = 0; j < n; j++) {
|
||||
if (c().is_monic_var(j) && c().m_to_refine.contains(j)) {
|
||||
for (lpvar k : c().m_emons[j].vars()) {
|
||||
weighted_vars[k] += 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::sort(sorted_vars.begin(), sorted_vars.end(), [&](unsigned a, unsigned b) {
|
||||
unsigned wa = weighted_vars[a];
|
||||
unsigned wb = weighted_vars[b];
|
||||
return wa < wb || (wa == wb && a < b); });
|
||||
|
||||
unsigned_vector l2v(n);
|
||||
for (unsigned j = 0; j < n; j++)
|
||||
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");
|
||||
}
|
||||
|
||||
}
|
64
src/math/lp/nla_grobner.h
Normal file
64
src/math/lp/nla_grobner.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Author:
|
||||
Nikolaj Bjorner (nbjorner)
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "math/lp/nla_common.h"
|
||||
#include "math/lp/nla_intervals.h"
|
||||
#include "math/lp/nex.h"
|
||||
#include "math/lp/cross_nested.h"
|
||||
#include "math/lp/u_set.h"
|
||||
#include "math/grobner/pdd_solver.h"
|
||||
|
||||
namespace nla {
|
||||
class core;
|
||||
|
||||
class grobner : common {
|
||||
dd::pdd_manager m_pdd_manager;
|
||||
dd::solver m_solver;
|
||||
lp::lar_solver& m_lar_solver;
|
||||
lp::u_set m_rows;
|
||||
|
||||
lp::lp_settings& lp_settings();
|
||||
|
||||
// solving
|
||||
bool is_conflicting();
|
||||
bool is_conflicting(const dd::solver::equation& eq);
|
||||
|
||||
bool propagate_bounds();
|
||||
bool propagate_bounds(const dd::solver::equation& eq);
|
||||
|
||||
bool propagate_eqs();
|
||||
bool propagate_fixed(const dd::solver::equation& eq);
|
||||
|
||||
bool propagate_factorization();
|
||||
bool propagate_factorization(const dd::solver::equation& eq);
|
||||
|
||||
void add_dependencies(new_lemma& lemma, const dd::solver::equation& eq);
|
||||
|
||||
// setup
|
||||
void configure();
|
||||
void set_level2var();
|
||||
void find_nl_cluster();
|
||||
void prepare_rows_and_active_vars();
|
||||
void add_var_and_its_factors_to_q_and_collect_new_rows(lpvar j, svector<lpvar>& q);
|
||||
void add_row(const vector<lp::row_cell<rational>>& row);
|
||||
void add_fixed_monic(unsigned j);
|
||||
bool is_solved(dd::pdd const& p, unsigned& v, dd::pdd& r);
|
||||
void add_eq(dd::pdd& p, u_dependency* dep);
|
||||
const rational& val_of_fixed_var_with_deps(lpvar j, u_dependency*& dep);
|
||||
dd::pdd pdd_expr(const rational& c, lpvar j, u_dependency*& dep);
|
||||
|
||||
void display_matrix_of_m_rows(std::ostream& out) const;
|
||||
std::ostream& diagnose_pdd_miss(std::ostream& out);
|
||||
|
||||
public:
|
||||
grobner(core *core);
|
||||
void operator()();
|
||||
};
|
||||
}
|
|
@ -19,7 +19,7 @@ typedef lp::lar_term term;
|
|||
// a > b && c > 0 => ac > bc
|
||||
void order::order_lemma() {
|
||||
TRACE("nla_solver", );
|
||||
if (!c().m_nla_settings.run_order()) {
|
||||
if (!c().m_nla_settings.run_order) {
|
||||
TRACE("nla_solver", tout << "not generating order lemmas\n";);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -9,94 +9,38 @@ Author:
|
|||
|
||||
#pragma once
|
||||
namespace nla {
|
||||
class nla_settings {
|
||||
bool m_run_order;
|
||||
bool m_run_tangents;
|
||||
bool m_run_horner;
|
||||
// how often to call the horner heuristic
|
||||
unsigned m_horner_frequency;
|
||||
unsigned m_horner_row_length_limit;
|
||||
unsigned m_horner_subs_fixed;
|
||||
// grobner fields
|
||||
bool m_run_grobner;
|
||||
unsigned m_grobner_row_length_limit;
|
||||
unsigned m_grobner_subs_fixed;
|
||||
unsigned m_grobner_eqs_growth;
|
||||
unsigned m_grobner_tree_size_growth;
|
||||
unsigned m_grobner_expr_size_growth;
|
||||
unsigned m_grobner_expr_degree_growth;
|
||||
unsigned m_grobner_max_simplified;
|
||||
unsigned m_grobner_number_of_conflicts_to_report;
|
||||
unsigned m_grobner_quota;
|
||||
unsigned m_grobner_frequency;
|
||||
bool m_run_nra;
|
||||
// expensive patching
|
||||
bool m_expensive_patching;
|
||||
public:
|
||||
nla_settings() : m_run_order(true),
|
||||
m_run_tangents(true),
|
||||
m_run_horner(true),
|
||||
m_horner_frequency(4),
|
||||
m_horner_row_length_limit(10),
|
||||
m_horner_subs_fixed(2),
|
||||
m_run_grobner(true),
|
||||
m_grobner_row_length_limit(50),
|
||||
m_grobner_subs_fixed(false),
|
||||
m_grobner_quota(0),
|
||||
m_grobner_frequency(4),
|
||||
m_run_nra(false),
|
||||
m_expensive_patching(false)
|
||||
{}
|
||||
unsigned grobner_eqs_growth() const { return m_grobner_eqs_growth;}
|
||||
unsigned& grobner_eqs_growth() { return m_grobner_eqs_growth;}
|
||||
bool run_order() const { return m_run_order; }
|
||||
bool& run_order() { return m_run_order; }
|
||||
struct nla_settings {
|
||||
bool run_order = true;
|
||||
bool run_tangents = true;
|
||||
|
||||
// horner fields
|
||||
bool run_horner = true;
|
||||
unsigned horner_frequency = 4;
|
||||
unsigned horner_row_length_limit = 10;
|
||||
unsigned horner_subs_fixed = 2;
|
||||
|
||||
bool run_tangents() const { return m_run_tangents; }
|
||||
bool& run_tangents() { return m_run_tangents; }
|
||||
|
||||
// grobner fields
|
||||
bool run_grobner = true;
|
||||
unsigned grobner_row_length_limit = 50;
|
||||
unsigned grobner_subs_fixed = 1;
|
||||
unsigned grobner_eqs_growth = 10;
|
||||
unsigned grobner_tree_size_growth = 2;
|
||||
unsigned grobner_expr_size_growth = 2;
|
||||
unsigned grobner_expr_degree_growth = 2;
|
||||
unsigned grobner_max_simplified = 10000;
|
||||
unsigned grobner_number_of_conflicts_to_report = 1;
|
||||
unsigned grobner_quota = 0;
|
||||
unsigned grobner_frequency = 4;
|
||||
|
||||
bool expensive_patching() const { return m_expensive_patching; }
|
||||
bool& expensive_patching() { return m_expensive_patching; }
|
||||
|
||||
bool run_horner() const { return m_run_horner; }
|
||||
bool& run_horner() { return m_run_horner; }
|
||||
|
||||
unsigned horner_frequency() const { return m_horner_frequency; }
|
||||
unsigned& horner_frequency() { return m_horner_frequency; }
|
||||
unsigned horner_row_length_limit() const { return m_horner_row_length_limit; }
|
||||
unsigned& horner_row_length_limit() { return m_horner_row_length_limit; }
|
||||
unsigned horner_subs_fixed() const { return m_horner_subs_fixed; }
|
||||
unsigned& horner_subs_fixed() { return m_horner_subs_fixed; }
|
||||
|
||||
bool run_grobner() const { return m_run_grobner; }
|
||||
bool& run_grobner() { return m_run_grobner; }
|
||||
unsigned grobner_frequency() const { return m_grobner_frequency; }
|
||||
unsigned& grobner_frequency() { return m_grobner_frequency; }
|
||||
|
||||
bool run_nra() const { return m_run_nra; }
|
||||
bool& run_nra() { return m_run_nra; }
|
||||
|
||||
unsigned grobner_row_length_limit() const { return m_grobner_row_length_limit; }
|
||||
unsigned& grobner_row_length_limit() { return m_grobner_row_length_limit; }
|
||||
unsigned grobner_subs_fixed() const { return m_grobner_subs_fixed; }
|
||||
unsigned& grobner_subs_fixed() { return m_grobner_subs_fixed; }
|
||||
|
||||
unsigned grobner_tree_size_growth() const { return m_grobner_tree_size_growth; }
|
||||
unsigned & grobner_tree_size_growth() { return m_grobner_tree_size_growth; }
|
||||
|
||||
unsigned grobner_expr_size_growth() const { return m_grobner_expr_size_growth; }
|
||||
unsigned & grobner_expr_size_growth() { return m_grobner_expr_size_growth; }
|
||||
|
||||
unsigned grobner_expr_degree_growth() const { return m_grobner_expr_degree_growth; }
|
||||
unsigned & grobner_expr_degree_growth() { return m_grobner_expr_degree_growth; }
|
||||
|
||||
unsigned grobner_max_simplified() const { return m_grobner_max_simplified; }
|
||||
unsigned & grobner_max_simplified() { return m_grobner_max_simplified; }
|
||||
|
||||
unsigned grobner_number_of_conflicts_to_report() const { return m_grobner_number_of_conflicts_to_report; }
|
||||
unsigned & grobner_number_of_conflicts_to_report() { return m_grobner_number_of_conflicts_to_report; }
|
||||
|
||||
unsigned& grobner_quota() { return m_grobner_quota; }
|
||||
// nra fields
|
||||
bool run_nra = false;
|
||||
|
||||
};
|
||||
// expensive patching
|
||||
bool expensive_patching = false;
|
||||
|
||||
nla_settings() {}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -186,7 +186,7 @@ tangents::tangents(core * c) : common(c) {}
|
|||
void tangents::tangent_lemma() {
|
||||
factorization bf(nullptr);
|
||||
const monic* m = nullptr;
|
||||
if (c().m_nla_settings.run_tangents() && c().find_bfc_to_refine(m, bf)) {
|
||||
if (c().m_nla_settings.run_tangents && c().find_bfc_to_refine(m, bf)) {
|
||||
lpvar j = m->var();
|
||||
tangent_imp tangent(point(val(bf[0]), val(bf[1])), c().val(j), *m, bf, *this);
|
||||
tangent();
|
||||
|
|
|
@ -65,12 +65,10 @@ struct solver::imp {
|
|||
}
|
||||
|
||||
// add polynomial definitions.
|
||||
for (auto const& m : m_nla_core.emons()) {
|
||||
for (auto const& m : m_nla_core.emons())
|
||||
add_monic_eq(m);
|
||||
}
|
||||
for (unsigned i : m_term_set) {
|
||||
for (unsigned i : m_term_set)
|
||||
add_term(i);
|
||||
}
|
||||
// TBD: add variable bounds?
|
||||
|
||||
lbool r = l_undef;
|
||||
|
@ -176,7 +174,103 @@ struct solver::imp {
|
|||
lp_assert(false); // unreachable
|
||||
}
|
||||
m_nlsat->mk_clause(1, &lit, a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lbool check(vector<dd::pdd> const& eqs) {
|
||||
m_zero = nullptr;
|
||||
m_nlsat = alloc(nlsat::solver, m_limit, m_params, false);
|
||||
m_zero = alloc(scoped_anum, am());
|
||||
m_lp2nl.reset();
|
||||
m_term_set.clear();
|
||||
for (auto const& eq : eqs)
|
||||
add_eq(eq);
|
||||
for (auto const& [v, w] : m_lp2nl) {
|
||||
auto& ls = m_nla_core.m_lar_solver;
|
||||
if (ls.column_has_lower_bound(v))
|
||||
add_lb(ls.get_lower_bound(v), w);
|
||||
if (ls.column_has_upper_bound(v))
|
||||
add_ub(ls.get_upper_bound(v), w);
|
||||
}
|
||||
|
||||
lbool r = l_undef;
|
||||
try {
|
||||
r = m_nlsat->check();
|
||||
}
|
||||
catch (z3_exception&) {
|
||||
if (m_limit.is_canceled()) {
|
||||
r = l_undef;
|
||||
}
|
||||
else {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
IF_VERBOSE(0, verbose_stream() << "check-nra " << r << "\n";
|
||||
m_nlsat->display(verbose_stream());
|
||||
for (auto const& [v, w] : m_lp2nl) {
|
||||
auto& ls = m_nla_core.m_lar_solver;
|
||||
if (ls.column_has_lower_bound(v))
|
||||
verbose_stream() << w << " >= " << ls.get_lower_bound(v) << "\n";
|
||||
if (ls.column_has_upper_bound(v))
|
||||
verbose_stream() << w << " <= " << ls.get_upper_bound(v) << "\n";
|
||||
});
|
||||
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void add_eq(dd::pdd const& eq) {
|
||||
dd::pdd normeq = eq;
|
||||
rational lc(1);
|
||||
for (auto const& [c, m] : eq)
|
||||
lc = lcm(denominator(c), lc);
|
||||
if (lc != 1)
|
||||
normeq *= lc;
|
||||
polynomial::manager& pm = m_nlsat->pm();
|
||||
polynomial::polynomial_ref p(pdd2polynomial(normeq), pm);
|
||||
bool is_even[1] = { false };
|
||||
polynomial::polynomial* ps[1] = { p };
|
||||
nlsat::literal lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, is_even);
|
||||
m_nlsat->mk_clause(1, &lit, nullptr);
|
||||
}
|
||||
|
||||
void add_lb(lp::impq const& b, unsigned w) {
|
||||
add_bound(b.x, w, b.y <= 0, b.y > 0 ? nlsat::atom::kind::GT : nlsat::atom::kind::LT);
|
||||
}
|
||||
void add_ub(lp::impq const& b, unsigned w) {
|
||||
add_bound(b.x, w, b.y >= 0, b.y < 0 ? nlsat::atom::kind::LT : nlsat::atom::kind::GT);
|
||||
}
|
||||
|
||||
// w - bound < 0
|
||||
// w - bound > 0
|
||||
void add_bound(lp::mpq const& bound, unsigned w, bool neg, nlsat::atom::kind k) {
|
||||
polynomial::manager& pm = m_nlsat->pm();
|
||||
polynomial::polynomial_ref p1(pm.mk_polynomial(w), pm);
|
||||
polynomial::polynomial_ref p2(pm.mk_const(bound), pm);
|
||||
polynomial::polynomial_ref p(pm.sub(p1, p2), pm);
|
||||
polynomial::polynomial* ps[1] = { p };
|
||||
bool is_even[1] = { false };
|
||||
nlsat::literal lit = m_nlsat->mk_ineq_literal(k, 1, ps, is_even);
|
||||
if (neg)
|
||||
lit.neg();
|
||||
m_nlsat->mk_clause(1, &lit, nullptr);
|
||||
}
|
||||
|
||||
polynomial::polynomial* pdd2polynomial(dd::pdd const& p) {
|
||||
polynomial::manager& pm = m_nlsat->pm();
|
||||
if (p.is_val())
|
||||
return pm.mk_const(p.val());
|
||||
polynomial::polynomial_ref lo(pdd2polynomial(p.lo()), pm);
|
||||
polynomial::polynomial_ref hi(pdd2polynomial(p.hi()), pm);
|
||||
unsigned w, v = p.var();
|
||||
if (!m_lp2nl.find(v, w)) {
|
||||
w = m_nlsat->mk_var(false);
|
||||
m_lp2nl.insert(v, w);
|
||||
}
|
||||
polynomial::polynomial_ref vp(pm.mk_polynomial(w, 1), pm);
|
||||
return pm.add(lo, pm.mul(vp, hi));
|
||||
}
|
||||
|
||||
bool is_int(lp::var_index v) {
|
||||
return s.var_is_int(v);
|
||||
|
@ -265,6 +359,10 @@ lbool solver::check() {
|
|||
return m_imp->check();
|
||||
}
|
||||
|
||||
lbool solver::check(vector<dd::pdd> const& eqs) {
|
||||
return m_imp->check(eqs);
|
||||
}
|
||||
|
||||
bool solver::need_check() {
|
||||
return m_imp->need_check();
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "util/rlimit.h"
|
||||
#include "util/params.h"
|
||||
#include "nlsat/nlsat_solver.h"
|
||||
#include "math/dd/dd_pdd.h"
|
||||
|
||||
namespace lp {
|
||||
class lar_solver;
|
||||
|
@ -36,6 +37,11 @@ namespace nra {
|
|||
*/
|
||||
lbool check();
|
||||
|
||||
/**
|
||||
\breif Check feasibility of equalities modulo bounds constraints on their variables.
|
||||
*/
|
||||
lbool check(vector<dd::pdd> const& eqs);
|
||||
|
||||
/*
|
||||
\brief determine whether nra check is needed.
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue