3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-15 05:18:44 +00:00

fix the factorization sign to be equal to the monomial sign

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
Lev Nachmanson 2019-05-10 12:08:56 -07:00
parent df5f3f9722
commit 375027d195
13 changed files with 185 additions and 151 deletions

View file

@ -27,7 +27,7 @@ bool const_iterator_mon::get_factors(factor& k, factor& j, rational& sign) const
k.set(k_vars[0], factor_type::VAR);
} else {
unsigned i;
if (!m_ff->find_rm_monomial_of_vars(k_vars, i)) {
if (!m_ff->find_canonical_monomial_of_vars(k_vars, i)) {
return false;
}
k.set(i, factor_type::MON);
@ -37,7 +37,7 @@ bool const_iterator_mon::get_factors(factor& k, factor& j, rational& sign) const
j.set(j_vars[0], factor_type::VAR);
} else {
unsigned i;
if (!m_ff->find_rm_monomial_of_vars(j_vars, i)) {
if (!m_ff->find_canonical_monomial_of_vars(j_vars, i)) {
return false;
}
j.set(i, factor_type::MON);
@ -92,7 +92,14 @@ bool const_iterator_mon::operator!=(const const_iterator_mon::self_type &other)
factorization const_iterator_mon::create_binary_factorization(factor j, factor k) const {
factorization f(nullptr);
f.push_back(j);
f.push_back(k);
f.push_back(k);
// Let m by *m_ff->m_monomial, the monomial we factorize
// We have canonize_sign(m)*m.vars() = m.rvars()
// Let s = canonize_sign(f). Then we have f[0]*f[1] = s*m.rvars()
// s*canonize_sign(m)*val(m).
// Therefore val(m) = sign*val((f[0])*val(f[1]), where sign = canonize_sign(f)*canonize_sign(m).
// We apply this sign to the first factor.
f[0].sign() ^= (m_ff->canonize_sign(f)^m_ff->canonize_sign(*m_ff->m_monomial));
return f;
}

View file

@ -54,26 +54,30 @@ public:
class factorization {
svector<factor> m_vars;
svector<factor> m_factors;
const monomial* m_mon;
public:
factorization(const monomial* m): m_mon(m) {
if (m != nullptr) {
for (lpvar j : m->vars())
m_vars.push_back(factor(j, factor_type::VAR));
m_factors.push_back(factor(j, factor_type::VAR));
}
}
bool is_mon() const { return m_mon != nullptr;}
bool is_empty() const { return m_vars.empty(); }
factor operator[](unsigned k) const { return m_vars[k]; }
size_t size() const { return m_vars.size(); }
const factor* begin() const { return m_vars.begin(); }
const factor* end() const { return m_vars.end(); }
void push_back(factor const& v) {
SASSERT(!is_mon());
m_vars.push_back(v);
bool is_mon() const {
return m_mon != nullptr;
}
const monomial* mon() const { return m_mon; }
bool is_empty() const { return m_factors.empty(); }
const factor& operator[](unsigned k) const { return m_factors[k]; }
factor& operator[](unsigned k) { return m_factors[k]; }
size_t size() const { return m_factors.size(); }
const factor* begin() const { return m_factors.begin(); }
const factor* end() const { return m_factors.end(); }
void push_back(factor const& v) {
m_factors.push_back(v);
}
const monomial& mon() const { return *m_mon; }
void set_mon(const monomial* m) { m_mon = m; }
};
struct const_iterator_mon {
@ -112,9 +116,9 @@ struct factorization_factory {
const svector<lpvar>& m_vars;
const monomial* m_monomial;
// returns true if found
virtual bool find_rm_monomial_of_vars(const svector<lpvar>& vars, unsigned& i) const = 0;
virtual const monomial* find_monomial_of_vars(const svector<lpvar>& vars) const = 0;
virtual bool find_canonical_monomial_of_vars(const svector<lpvar>& vars, unsigned& i) const = 0;
virtual bool canonize_sign(const monomial& m) const = 0;
virtual bool canonize_sign(const factorization& m) const = 0;
factorization_factory(const svector<lpvar>& vars, const monomial* m) :
m_vars(vars), m_monomial(m) {
@ -140,8 +144,7 @@ struct factorization_factory {
auto it = const_iterator_mon(mask, this);
it.m_full_factorization_returned = true;
return it;
}
}
};
}

View file

@ -25,10 +25,14 @@ factorization_factory_imp::factorization_factory_imp(const monomial& rm, const c
factorization_factory(rm.rvars(), &s.m_emons[rm.var()]),
m_core(s), m_mon(s.m_emons[rm.var()]), m_rm(rm) { }
bool factorization_factory_imp::find_rm_monomial_of_vars(const svector<lpvar>& vars, unsigned & i) const {
return m_core.find_rm_monomial_of_vars(vars, i);
bool factorization_factory_imp::find_canonical_monomial_of_vars(const svector<lpvar>& vars, unsigned & i) const {
return m_core.find_canonical_monomial_of_vars(vars, i);
}
const monomial* factorization_factory_imp::find_monomial_of_vars(const svector<lpvar>& vars) const {
return m_core.find_monomial_of_vars(vars);
bool factorization_factory_imp::canonize_sign(const monomial& m) const {
return m_core.canonize_sign(m);
}
bool factorization_factory_imp::canonize_sign(const factorization& f) const {
return m_core.canonize_sign(f);
}
}

View file

@ -28,7 +28,8 @@ namespace nla {
const monomial& m_rm;
factorization_factory_imp(const monomial& rm, const core& s);
bool find_rm_monomial_of_vars(const svector<lpvar>& vars, unsigned & i) const;
const monomial* find_monomial_of_vars(const svector<lpvar>& vars) const;
};
bool find_canonical_monomial_of_vars(const svector<lpvar>& vars, unsigned & i) const;
virtual bool canonize_sign(const monomial& m) const;
virtual bool canonize_sign(const factorization& m) const;
};
}

View file

@ -70,7 +70,7 @@ public:
};
inline std::ostream& operator<<(std::ostream& out, monomial const& m) {
return out << m.var() << " := " << m.vars() << " r " << m.rsign() << " * " << m.rvars();
return out << m.var() << " := " << m.vars() << " r ( " << sign_to_rat(m.rsign()) << " * " << m.rvars() << ")";
}

View file

@ -446,20 +446,20 @@ void basics::generate_pl_on_mon(const monomial& m, unsigned factor_index) {
// none of the factors is zero and the product is not zero
// -> |fc[factor_index]| <= |rm|
void basics::generate_pl(const monomial& rm, const factorization& fc, int factor_index) {
TRACE("nla_solver", tout << "factor_index = " << factor_index << ", rm = "
<< pp_mon(c(), rm);
void basics::generate_pl(const monomial& m, const factorization& fc, int factor_index) {
TRACE("nla_solver", tout << "factor_index = " << factor_index << ", m = "
<< pp_mon(c(), m);
tout << ", fc = "; c().print_factorization(fc, tout);
tout << "orig mon = "; c().print_monomial(c().m_emons[rm.var()], tout););
tout << "orig mon = "; c().print_monomial(c().emons()[m.var()], tout););
if (fc.is_mon()) {
generate_pl_on_mon(*fc.mon(), factor_index);
generate_pl_on_mon(m, factor_index);
return;
}
add_empty_lemma();
int fi = 0;
rational rmv = val(rm);
rational sm = rational(nla::rat_sign(rmv));
unsigned mon_var = var(rm);
rational mv = val(m);
rational sm = rational(nla::rat_sign(mv));
unsigned mon_var = var(m);
c().mk_ineq(sm, mon_var, llc::LT);
for (factor f : fc) {
if (fi++ != factor_index) {
@ -468,14 +468,14 @@ void basics::generate_pl(const monomial& rm, const factorization& fc, int factor
lpvar j = var(f);
rational jv = val(j);
rational sj = rational(nla::rat_sign(jv));
SASSERT(sm*rmv < sj*jv);
SASSERT(sm*mv < sj*jv);
c().mk_ineq(sj, j, llc::LT);
c().mk_ineq(sm, mon_var, -sj, j, llc::GE );
}
}
if (!fc.is_mon()) {
explain(fc);
explain(rm);
explain(m);
}
TRACE("nla_solver", c().print_lemma(tout); );
}
@ -691,8 +691,8 @@ bool basics::basic_lemma_for_mon_neutral_monomial_to_factor_model_based(const mo
void basics::basic_lemma_for_mon_neutral_model_based(const monomial& rm, const factorization& f) {
if (f.is_mon()) {
basic_lemma_for_mon_neutral_monomial_to_factor_model_based_fm(*f.mon());
basic_lemma_for_mon_neutral_from_factors_to_monomial_model_based_fm(*f.mon());
basic_lemma_for_mon_neutral_monomial_to_factor_model_based_fm(f.mon());
basic_lemma_for_mon_neutral_from_factors_to_monomial_model_based_fm(f.mon());
}
else {
basic_lemma_for_mon_neutral_monomial_to_factor_model_based(rm, f);
@ -701,9 +701,10 @@ void basics::basic_lemma_for_mon_neutral_model_based(const monomial& rm, const f
}
// use the fact
// 1 * 1 ... * 1 * x * 1 ... * 1 = x
bool basics::basic_lemma_for_mon_neutral_from_factors_to_monomial_model_based(const monomial& rm, const factorization& f) {
rational sign = sign_to_rat(rm.rsign());
TRACE("nla_solver_bl", tout << pp_rmon(_(), rm) <<"\nf = "; c().print_factorization(f, tout); tout << "sign = " << sign << '\n'; );
bool basics::basic_lemma_for_mon_neutral_from_factors_to_monomial_model_based(const monomial& m, const factorization& f) {
rational sign = sign_to_rat(m.rsign());
SASSERT(m.rsign() == canonize_sign(f));
TRACE("nla_solver_bl", tout << pp_rmon(_(), m) <<"\nf = "; c().print_factorization(f, tout); tout << "sign = " << sign << '\n'; );
lpvar not_one = -1;
for (auto j : f){
TRACE("nla_solver_bl", tout << "j = "; c().print_factor_with_vars(j, tout););
@ -728,13 +729,13 @@ bool basics::basic_lemma_for_mon_neutral_from_factors_to_monomial_model_based(co
if (not_one + 1) {
// we found the only not_one
if (val(rm) == val(not_one) * sign) {
if (val(m) == val(not_one) * sign) {
TRACE("nla_solver", tout << "the whole is equal to the factor" << std::endl;);
return false;
}
} else {
// we have +-ones only in the factorization
if (val(rm) == sign) {
if (val(m) == sign) {
return false;
}
}
@ -746,19 +747,20 @@ bool basics::basic_lemma_for_mon_neutral_from_factors_to_monomial_model_based(co
for (auto j : f){
lpvar var_j = var(j);
if (not_one == var_j) continue;
c().mk_ineq(var_j, llc::NE, j.is_var()? val(j) : sign_to_rat(c().canonize_sign(j)) * val(j));
TRACE("nla_solver_bl", tout << "j = "; c().print_factor_with_vars(j, tout););
c().mk_ineq(var_j, llc::NE, val(var_j));
}
if (not_one == static_cast<lpvar>(-1)) {
c().mk_ineq(rm.var(), llc::EQ, sign);
c().mk_ineq(m.var(), llc::EQ, sign);
} else {
c().mk_ineq(rm.var(), -sign, not_one, llc::EQ);
c().mk_ineq(m.var(), -sign, not_one, llc::EQ);
}
explain(rm);
explain(m);
explain(f);
TRACE("nla_solver",
c().print_lemma(tout);
tout << "rm = " << pp_rmon(c(), rm);
tout << "m = " << pp_rmon(c(), m);
);
return true;
}
@ -777,7 +779,7 @@ void basics::basic_lemma_for_mon_non_zero_model_based_mf(const factorization& f)
if (zero_j == -1) { return; }
add_empty_lemma();
c().mk_ineq(zero_j, llc::NE);
c().mk_ineq(f.mon()->var(), llc::EQ);
c().mk_ineq(f.mon().var(), llc::EQ);
TRACE("nla_solver", c().print_lemma(tout););
}

View file

@ -47,6 +47,7 @@ template <typename T> bool common::canonize_sign(const T& t) const {
template bool common::canonize_sign<monomial>(const monomial&) const;
template bool common::canonize_sign<factor>(const factor&) const;
template bool common::canonize_sign<lpvar>(const lpvar&) const;
template bool common::canonize_sign<factorization>(const factorization&) const;
void common::mk_ineq(lp::lar_term& t, llc cmp, const rational& rs){
c().mk_ineq(t, cmp, rs);

View file

@ -93,7 +93,7 @@ svector<lpvar> core::sorted_rvars(const factor& f) const {
// the value of the factor is equal to the value of the variable multiplied
// by the canonize_sign
bool core::canonize_sign(const factor& f) const {
return f.sign() ^ (f.is_var()? canonize_sign(f.var()) : m_emons[f.var()].rsign());
return f.sign() ^ (f.is_var()? canonize_sign(f.var()) : canonize_sign(m_emons[f.var()]));
}
bool core::canonize_sign(lpvar j) const {
@ -113,6 +113,14 @@ bool core::canonize_sign(const monomial& m) const {
return m.rsign();
}
bool core::canonize_sign(const factorization& f) const {
bool r = false;
for (const factor & a : f) {
r ^= canonize_sign(a);
}
return r;
}
void core::add(lpvar v, unsigned sz, lpvar const* vs) {
m_emons.add(v, sz, vs);
}
@ -180,7 +188,7 @@ std::ostream & core::print_factor(const factor& f, std::ostream& out) const {
out << "VAR, ";
print_var(f.var(), out);
} else {
out << "MON, ";
out << "MON, v" << m_emons[f.var()] << " = ";
print_product(m_emons[f.var()].rvars(), out);
}
out << "\n";
@ -192,7 +200,7 @@ std::ostream & core::print_factor_with_vars(const factor& f, std::ostream& out)
print_var(f.var(), out);
}
else {
out << " RM = " << pp_rmon(*this, m_emons[f.var()]);
out << " MON = " << pp_rmon(*this, m_emons[f.var()]);
}
return out;
}
@ -216,11 +224,12 @@ std::ostream& core::print_tangent_domain(const point &a, const point &b, std::os
return out;
}
std::ostream& core::print_bfc(const bfc& m, std::ostream& out) const {
std::ostream& core::print_bfc(const factorization& m, std::ostream& out) const {
SASSERT(m.size() == 2);
out << "( x = ";
print_factor(m.m_x, out);
out << ", y = ";
print_factor(m.m_y, out); out << ")";
print_factor(m[0], out);
out << "* y = ";
print_factor(m[1], out); out << ")";
return out;
}
@ -748,7 +757,8 @@ std::ostream & core::print_var(lpvar j, std::ostream & out) const {
}
m_lar_solver.print_column_info(j, out);
out << "root=" << m_evars.find(j) << "\n";
signed_var jr = m_evars.find(j);
out << "root=" << (jr.sign()? "-v":"v") << jr.var() << "\n";
return out;
}
@ -783,7 +793,7 @@ std::ostream & core::print_ineqs(const lemma& l, std::ostream & out) const {
std::ostream & core::print_factorization(const factorization& f, std::ostream& out) const {
if (f.is_mon()){
out << "is_mon " << pp_mon(*this, *f.mon());
out << "is_mon " << pp_mon(*this, f.mon());
}
else {
for (unsigned k = 0; k < f.size(); k++ ) {
@ -795,18 +805,12 @@ std::ostream & core::print_factorization(const factorization& f, std::ostream& o
return out;
}
bool core:: find_rm_monomial_of_vars(const svector<lpvar>& vars, unsigned & i) const {
bool core::find_canonical_monomial_of_vars(const svector<lpvar>& vars, unsigned & i) const {
SASSERT(vars_are_roots(vars));
monomial const* sv = m_emons.find_canonical(vars);
return sv && (i = sv->var(), true);
}
const monomial* core::find_monomial_of_vars(const svector<lpvar>& vars) const {
monomial const* sv = m_emons.find_canonical(vars);
return sv ? &m_emons[sv->var()] : nullptr;
}
void core::explain_existing_lower_bound(lpvar j) {
SASSERT(has_lower_bound(j));
current_expl().add(m_lar_solver.get_column_lower_bound_witness(j));
@ -1571,13 +1575,17 @@ void core::add_abs_bound(lpvar v, llc cmp, rational const& bound) {
*/
bool core::find_bfc_to_refine_on_rmonomial(const monomial& rm, bfc & bf) {
for (auto factorization : factorization_factory_imp(rm, *this)) {
if (factorization.size() == 2) {
auto a = factorization[0];
auto b = factorization[1];
if (val(rm) != val(a) * val(b)) {
bf = bfc(a, b);
bool core::find_bfc_to_refine_on_monomial(const monomial& m, factorization & bf) {
for (auto f : factorization_factory_imp(m, *this)) {
if (f.size() == 2) {
auto a = f[0];
auto b = f[1];
if (val(m) != val(a) * val(b)) {
bf = f;
TRACE("nla_solver", tout << "found bf";
tout << ":m:" << pp_rmon(*this, m) << "\n";
tout << "bf:"; print_bfc(bf, tout););
return true;
}
}
@ -1585,30 +1593,23 @@ bool core::find_bfc_to_refine_on_rmonomial(const monomial& rm, bfc & bf) {
return false;
}
bool core::find_bfc_to_refine(bfc& bf, lpvar &j, rational& sign, const monomial*& rm_found){
rm_found = nullptr;
bool core::find_bfc_to_refine(const monomial* & m, factorization & bf){
m = nullptr;
// todo: randomise loop
for (unsigned i: m_to_refine) {
const auto& rm = m_emons[i];
SASSERT (!check_monomial(m_emons[rm.var()]));
if (rm.size() == 2) {
sign = rational(1);
const monomial & m = m_emons[rm.var()];
j = m.var();
rm_found = nullptr;
bf.m_x = factor(m.vars()[0], factor_type::VAR);
bf.m_y = factor(m.vars()[1], factor_type::VAR);
m = &m_emons[i];
SASSERT (!check_monomial(*m));
if (m->size() == 2) {
bf.set_mon(m);
bf.push_back(factor(m->vars()[0], factor_type::VAR));
bf.push_back(factor(m->vars()[1], factor_type::VAR));
return true;
}
rm_found = &rm;
if (find_bfc_to_refine_on_rmonomial(rm, bf)) {
j = rm.var();
sign = sign_to_rat(rm.rsign());
TRACE("nla_solver", tout << "found bf";
tout << ":rm:" << pp_rmon(*this, rm) << "\n";
tout << "bf:"; print_bfc(bf, tout);
tout << ", product = " << val(rm) << ", but should be =" << val(bf.m_x)*val(bf.m_y);
tout << ", j == "; print_var(j, tout) << "\n";);
if (find_bfc_to_refine_on_monomial(*m, bf)) {
TRACE("nla_solver",
tout << "bf = "; print_factorization(bf, tout);
tout << "\nval(*m) = " << val(*m) << ", should be = (val(bf[0])=" << val(bf[0]) << ")*(val(bf[1]) = " << val(bf[1]) << ") = " << val(bf[0])*val(bf[1]) << "\n";);
return true;
}
}

View file

@ -117,6 +117,7 @@ public:
// the value of the factor is equal to the value of the variable multiplied
// by the canonize_sign
bool canonize_sign(const factor& f) const;
bool canonize_sign(const factorization& f) const;
bool canonize_sign(lpvar j) const;
@ -159,7 +160,7 @@ public:
std::ostream & print_factor(const factor& f, std::ostream& out) const;
std::ostream & print_factor_with_vars(const factor& f, std::ostream& out) const;
std::ostream& print_monomial(const monomial& m, std::ostream& out) const;
std::ostream& print_bfc(const bfc& m, std::ostream& out) const;
std::ostream& print_bfc(const factorization& m, std::ostream& out) const;
std::ostream& print_monomial_with_vars(unsigned i, std::ostream& out) const;
template <typename T>
std::ostream& print_product_with_vars(const T& m, std::ostream& out) const;
@ -238,9 +239,7 @@ public:
bool var_is_fixed(lpvar j) const;
bool find_rm_monomial_of_vars(const svector<lpvar>& vars, unsigned & i) const;
const monomial* find_monomial_of_vars(const svector<lpvar>& vars) const;
bool find_canonical_monomial_of_vars(const svector<lpvar>& vars, unsigned & i) const;
bool var_has_positive_lower_bound(lpvar j) const;
@ -320,9 +319,9 @@ public:
void add_abs_bound(lpvar v, llc cmp);
void add_abs_bound(lpvar v, llc cmp, rational const& bound);
bool find_bfc_to_refine_on_rmonomial(const monomial& rm, bfc & bf);
bool find_bfc_to_refine_on_monomial(const monomial&, factorization & bf);
bool find_bfc_to_refine(bfc& bf, lpvar &j, rational& sign, const monomial*& rm_found );
bool find_bfc_to_refine(const monomial* & m, factorization& bf);
void generate_simple_sign_lemma(const rational& sign, const monomial& m);
void negate_relation(unsigned j, const rational& a);
@ -349,7 +348,6 @@ struct pp_rmon {
pp_rmon(core const& c, monomial const& m): c(c), m(m) {}
pp_rmon(core const& c, lpvar v): c(c), m(c.m_emons[v]) {}
};
inline rational sign_to_rat(bool s) { return rational(s? -1 : 1); }
inline std::ostream& operator<<(std::ostream& out, pp_mon const& p) { return p.c.print_monomial(p.m, out); }
inline std::ostream& operator<<(std::ostream& out, pp_rmon const& p) { return p.c.print_monomial_with_vars(p.m, out); }

View file

@ -99,5 +99,5 @@ bool uniform_le(const T& a, const T& b, unsigned & strict_i) {
if (z_b) {strict_i = -1;}
return true;
}
inline rational sign_to_rat(bool s) { return rational(s? -1 : 1); }
}

View file

@ -49,7 +49,7 @@ void order::order_lemma_on_rmonomial(const monomial& m) {
if (ac.size() != 2)
continue;
if (ac.is_mon())
order_lemma_on_binomial(*ac.mon());
order_lemma_on_binomial(ac.mon());
else
order_lemma_on_factorization(m, ac);
if (done())

View file

@ -29,10 +29,22 @@ tangents::tangents(core * c) : common(c) {}
std::ostream& tangents::print_tangent_domain(const point &a, const point &b, std::ostream& out) const {
return out << "(" << a << ", " << b << ")";
}
unsigned tangents::find_binomial_to_refine() {
unsigned start = c().random();
unsigned sz = c().m_to_refine.size();
for (unsigned k = 0; k < sz; k++) {
lpvar j = c().m_to_refine[(k + start) % sz];
if (c().emons()[j].size() == 2)
return j;
}
return -1;
}
void tangents::generate_simple_tangent_lemma(const monomial& m) {
if (m.size() != 2)
return;
void tangents::generate_simple_tangent_lemma() {
lpvar j = find_binomial_to_refine();
if (!is_set(j)) return;
const monomial& m = c().emons()[j];
SASSERT(m.size() != 2);
TRACE("nla_solver", tout << "m:" << pp_mon(c(), m) << std::endl;);
c().add_empty_lemma();
const rational v = c().product_value(m.vars());
@ -66,65 +78,70 @@ void tangents::generate_simple_tangent_lemma(const monomial& m) {
}
void tangents::tangent_lemma() {
bfc bf;
lpvar j;
rational sign;
const monomial* rm = nullptr;
if (c().find_bfc_to_refine(bf, j, sign, rm)) {
tangent_lemma_bf(bf, j, sign, rm);
} else {
TRACE("nla_solver", tout << "cannot find a bfc to refine\n"; );
if (rm != nullptr)
generate_simple_tangent_lemma(*rm);
if (!c().m_settings.run_tangents()) {
TRACE("nla_solver", tout << "not generating tangent lemmas\n";);
return;
}
factorization bf(nullptr);
const monomial* m;
if (c().find_bfc_to_refine(m, bf)) {
tangent_lemma_bf(*m, bf);
}
}
void tangents::generate_explanations_of_tang_lemma(const monomial& rm, const bfc& bf, lp::explanation& exp) {
void tangents::generate_explanations_of_tang_lemma(const monomial& rm, const factorization& bf, lp::explanation& exp) {
// here we repeat the same explanation for each lemma
c().explain(rm, exp);
c().explain(bf.m_x, exp);
c().explain(bf.m_y, exp);
c().explain(bf[0], exp);
c().explain(bf[1], exp);
}
void tangents::generate_tang_plane(const rational & a, const rational& b, const factor& x, const factor& y, bool below, lpvar j, const rational& j_sign) {
void tangents::generate_tang_plane(const rational & a, const rational& b, const factor& x, const factor& y, bool below, lpvar j) {
lpvar jx = var(x);
lpvar jy = var(y);
add_empty_lemma();
c().negate_relation(jx, a);
c().negate_relation(jy, b);
bool sbelow = j_sign.is_pos()? below: !below;
#if Z3DEBUG
int mult_sign = nla::rat_sign(a - val(jx))*nla::rat_sign(b - val(jy));
SASSERT((mult_sign == 1) == sbelow);
SASSERT((mult_sign == 1) == below);
// If "mult_sign is 1" then (a - x)(b-y) > 0 and ab - bx - ay + xy > 0
// or -ab + bx + ay < xy or -ay - bx + xy > -ab
// j_sign*val(j) stands for xy. So, finally we have -ay - bx + j_sign*j > - ab
// val(j) stands for xy. So, finally we have -ay - bx + j > - ab
#endif
lp::lar_term t;
t.add_coeff_var(-a, jy);
t.add_coeff_var(-b, jx);
t.add_coeff_var( j_sign, j);
c().mk_ineq(t, sbelow? llc::GT : llc::LT, - a*b);
}
void tangents::tangent_lemma_bf(const bfc& bf, lpvar j, const rational& sign, const monomial* rm){
t.add_var(j);
c().mk_ineq(t, below? llc::GT : llc::LT, - a*b);
}
void tangents::tangent_lemma_bf(const monomial& m, const factorization& bf){
point a, b;
point xy (val(bf.m_x), val(bf.m_y));
point xy (val(bf[0]), val(bf[1]));
rational correct_mult_val = xy.x * xy.y;
rational v = val(j) * sign;
lpvar j =m.var();
// We have canonize_sign(m)*m.vars() = m.rvars()
// Let s = canonize_sign(bf). Then we have bf[1]*bf[1] = s*m.rvars()
// s*canonize_sign(m)*val(m).
// Therefore sign*val(m) = val((bf[0])*val(bf[1]), where sign = canonize_sign(bf)*canonize_sign(m)
SASSERT(canonize_sign(bf) == canonize_sign(m));
rational v = val(j);
bool below = v < correct_mult_val;
TRACE("nla_solver", tout << "rm = " << rm << ", below = " << below << std::endl; );
TRACE("nla_solver", tout << "below = " << below << std::endl; );
get_tang_points(a, b, below, v, xy);
TRACE("nla_solver", tout << "sign = " << sign << ", tang domain = "; print_tangent_domain(a, b, tout); tout << std::endl;);
TRACE("nla_solver", tout << "tang domain = "; print_tangent_domain(a, b, tout); tout << std::endl;);
unsigned lemmas_size_was = c().m_lemma_vec->size();
generate_two_tang_lines(bf, xy, sign, j);
generate_tang_plane(a.x, a.y, bf.m_x, bf.m_y, below, j, sign);
generate_tang_plane(b.x, b.y, bf.m_x, bf.m_y, below, j, sign);
// if rm == nullptr there is no need to explain equivs since we work on a monomial and not on a rooted monomial
if (rm != nullptr) {
rational sign(1);
generate_two_tang_lines(bf, xy, j);
generate_tang_plane(a.x, a.y, bf[0], bf[1], below, j);
generate_tang_plane(b.x, b.y, bf[0], bf[1], below, j);
if (!bf.is_mon()) {
lp::explanation expl;
generate_explanations_of_tang_lemma(*rm, bf, expl);
generate_explanations_of_tang_lemma(m, bf, expl);
for (unsigned i = lemmas_size_was; i < c().m_lemma_vec->size(); i++) {
auto &l = ((*c().m_lemma_vec)[i]);
l.expl().add(expl);
@ -135,14 +152,14 @@ void tangents::tangent_lemma_bf(const bfc& bf, lpvar j, const rational& sign, co
c().print_specific_lemma((*c().m_lemma_vec)[i], tout); );
}
void tangents::generate_two_tang_lines(const bfc & bf, const point& xy, const rational& sign, lpvar j) {
void tangents::generate_two_tang_lines(const factorization & bf, const point& xy, lpvar j) {
add_empty_lemma();
c().mk_ineq(var(bf.m_x), llc::NE, xy.x);
c().mk_ineq(sign, j, - xy.x, var(bf.m_y), llc::EQ);
c().mk_ineq(var(bf[0]), llc::NE, xy.x);
c().mk_ineq(j, - xy.x, var(bf[1]), llc::EQ);
add_empty_lemma();
c().mk_ineq(var(bf.m_y), llc::NE, xy.y);
c().mk_ineq(sign, j, - xy.y, var(bf.m_x), llc::EQ);
c().mk_ineq(var(bf[1]), llc::NE, xy.y);
c().mk_ineq(j, - xy.y, var(bf[0]), llc::EQ);
}
// Get two planes tangent to surface z = xy, one at point a, and another at point b.
@ -168,7 +185,7 @@ void tangents::push_tang_point(point &a, const point& xy, bool below, const rati
while (steps--) {
del *= rational(2);
point na = xy + del;
TRACE("nla_solver", tout << "del = " << del << std::endl;);
TRACE("nla_solver_tp", tout << "del = " << del << std::endl;);
if (!plane_is_correct_cut(na, xy, correct_val, val, below)) {
TRACE("nla_solver_tp", tout << "exit";tout << std::endl;);
return;

View file

@ -52,16 +52,16 @@ class tangents : common {
public:
tangents(core *core);
void tangent_lemma();
private:
private:
lpvar find_binomial_to_refine();
void generate_simple_tangent_lemma();
void generate_simple_tangent_lemma(const monomial&);
void generate_explanations_of_tang_lemma(const monomial& rm, const bfc& bf, lp::explanation& exp);
void generate_explanations_of_tang_lemma(const monomial& m, const factorization& bf, lp::explanation& exp);
void tangent_lemma_bf(const bfc& bf, lpvar j, const rational& sign, const monomial* rm);
void generate_tang_plane(const rational & a, const rational& b, const factor& x, const factor& y, bool below, lpvar j, const rational& j_sign);
void tangent_lemma_bf(const monomial& m,const factorization& bf);
void generate_tang_plane(const rational & a, const rational& b, const factor& x, const factor& y, bool below, lpvar j);
void generate_two_tang_lines(const bfc & bf, const point& xy, const rational& sign, lpvar j);
void generate_two_tang_lines(const factorization & bf, const point& xy, lpvar j);
// Get two planes tangent to surface z = xy, one at point a, and another at point b.
// One can show that these planes still create a cut.
void get_initial_tang_points(point &a, point &b, const point& xy, bool below) const;