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

consolidate methods that add lemma specific information to under "new_lemma"

This commit is contained in:
Nikolaj Bjorner 2020-05-10 18:31:57 -07:00
parent caee936af5
commit 179c9c2da2
12 changed files with 314 additions and 560 deletions

View file

@ -85,7 +85,7 @@ void basics::basic_sign_lemma_model_based_one_mon(const monic& m, int product_si
} else { } else {
new_lemma lemma(c(), __FUNCTION__); new_lemma lemma(c(), __FUNCTION__);
for (lpvar j: m.vars()) { for (lpvar j: m.vars()) {
negate_strict_sign(j); negate_strict_sign(lemma, j);
} }
lemma |= ineq(m.var(), product_sign == 1? llc::GT : llc::LT, 0); lemma |= ineq(m.var(), product_sign == 1? llc::GT : llc::LT, 0);
} }
@ -155,8 +155,8 @@ void basics::generate_sign_lemma(const monic& m, const monic& n, const rational&
tout << "n = " << pp_mon_with_vars(_(), n); tout << "n = " << pp_mon_with_vars(_(), n);
); );
lemma |= ineq(term(m.var(), -sign, n.var()), llc::EQ, 0); lemma |= ineq(term(m.var(), -sign, n.var()), llc::EQ, 0);
explain(m); lemma &= m;
explain(n); lemma &= n;
} }
// try to find a variable j such that val(j) = 0 // try to find a variable j such that val(j) = 0
// and the bounds on j contain 0 as an inner point // and the bounds on j contain 0 as an inner point
@ -187,31 +187,32 @@ void basics::generate_strict_case_zero_lemma(const monic& m, unsigned zero_j, in
lemma |= ineq(zero_j, sign_of_zj == 1? llc::GT : llc::LT, 0); lemma |= ineq(zero_j, sign_of_zj == 1? llc::GT : llc::LT, 0);
for (unsigned j : m.vars()) { for (unsigned j : m.vars()) {
if (j != zero_j) { if (j != zero_j) {
negate_strict_sign(j); negate_strict_sign(lemma, j);
} }
} }
negate_strict_sign(m.var()); negate_strict_sign(lemma, m.var());
} }
void basics::add_fixed_zero_lemma(const monic& m, lpvar j) { void basics::add_fixed_zero_lemma(const monic& m, lpvar j) {
new_lemma lemma(c(), "fixed zero"); new_lemma lemma(c(), "fixed zero");
c().explain_fixed_var(j); lemma.explain_fixed(j);
lemma |= ineq(m.var(), llc::EQ, 0); lemma |= ineq(m.var(), llc::EQ, 0);
} }
void basics::negate_strict_sign(lpvar j) { void basics::negate_strict_sign(new_lemma& lemma, lpvar j) {
TRACE("nla_solver_details", tout << pp_var(c(), j) << "\n";); TRACE("nla_solver_details", tout << pp_var(c(), j) << "\n";);
if (!val(j).is_zero()) { if (!val(j).is_zero()) {
int sign = nla::rat_sign(val(j)); int sign = nla::rat_sign(val(j));
c().mk_ineq(j, (sign == 1? llc::LE : llc::GE)); lemma |= ineq(j, (sign == 1? llc::LE : llc::GE), 0);
} else { // val(j).is_zero() }
else { // val(j).is_zero()
if (c().has_lower_bound(j) && c().get_lower_bound(j) >= rational(0)) { if (c().has_lower_bound(j) && c().get_lower_bound(j) >= rational(0)) {
c().explain_existing_lower_bound(j); c().explain_existing_lower_bound(lemma, j);
c().mk_ineq(j, llc::GT); lemma |= ineq(j, llc::GT, 0);
} else { } else {
SASSERT(c().has_upper_bound(j) && c().get_upper_bound(j) <= rational(0)); SASSERT(c().has_upper_bound(j) && c().get_upper_bound(j) <= rational(0));
c().explain_existing_upper_bound(j); c().explain_existing_upper_bound(lemma, j);
c().mk_ineq(j, llc::LT); lemma |= ineq(j, llc::LT, 0);
} }
} }
} }
@ -219,21 +220,24 @@ void basics::negate_strict_sign(lpvar j) {
// here we use the fact // here we use the fact
// xy = 0 -> x = 0 or y = 0 // xy = 0 -> x = 0 or y = 0
bool basics::basic_lemma_for_mon_zero(const monic& rm, const factorization& f) { bool basics::basic_lemma_for_mon_zero(const monic& rm, const factorization& f) {
// NSB review: how is the code-path calling this function disabled?
NOT_IMPLEMENTED_YET(); NOT_IMPLEMENTED_YET();
return true; return true;
#if 0 #if 0
TRACE("nla_solver", c().trace_print_monic_and_factorization(rm, f, tout);); TRACE("nla_solver", c().trace_print_monic_and_factorization(rm, f, tout););
new_lemma lemma(c(), "xy = 0 -> x = 0 or y = 0"); new_lemma lemma(c(), "xy = 0 -> x = 0 or y = 0");
c().explain_fixed_var(var(rm)); lemma.explain_fixed(var(rm));
std::unordered_set<lpvar> processed; std::unordered_set<lpvar> processed;
for (auto j : f) { for (auto j : f) {
if (try_insert(var(j), processed)) if (try_insert(var(j), processed))
lemma |= ineq(var(j), llc::EQ, 0); lemma |= ineq(var(j), llc::EQ, 0);
} }
explain(rm); lemma &= rm;
lemma &= f;
return true; return true;
#endif #endif
} }
// use basic multiplication properties to create a lemma // use basic multiplication properties to create a lemma
bool basics::basic_lemma(bool derived) { bool basics::basic_lemma(bool derived) {
if (basic_sign_lemma(derived)) if (basic_sign_lemma(derived))
@ -267,55 +271,51 @@ bool basics::basic_lemma_for_mon_derived(const monic& rm) {
for (auto factorization : factorization_factory_imp(rm, c())) { for (auto factorization : factorization_factory_imp(rm, c())) {
if (factorization.is_empty()) if (factorization.is_empty())
continue; continue;
if (basic_lemma_for_mon_zero(rm, factorization) || if (basic_lemma_for_mon_zero(rm, factorization))
basic_lemma_for_mon_neutral_derived(rm, factorization)) { return true;
explain(factorization); if (basic_lemma_for_mon_neutral_derived(rm, factorization))
return true; return true;
} }
} }
} else { else {
for (auto factorization : factorization_factory_imp(rm, c())) { for (auto factorization : factorization_factory_imp(rm, c())) {
if (factorization.is_empty()) if (factorization.is_empty())
continue; continue;
if (basic_lemma_for_mon_non_zero_derived(rm, factorization) || if (basic_lemma_for_mon_non_zero_derived(rm, factorization))
basic_lemma_for_mon_neutral_derived(rm, factorization) || return true;
proportion_lemma_derived(rm, factorization)) { if (basic_lemma_for_mon_neutral_derived(rm, factorization))
explain(factorization); return true;
if (proportion_lemma_derived(rm, factorization))
return true; return true;
}
} }
} }
return false; return false;
} }
// x = 0 or y = 0 -> xy = 0 // x = 0 or y = 0 -> xy = 0
bool basics::basic_lemma_for_mon_non_zero_derived(const monic& rm, const factorization& f) { bool basics::basic_lemma_for_mon_non_zero_derived(const monic& rm, const factorization& f) {
TRACE("nla_solver", c().trace_print_monic_and_factorization(rm, f, tout);); TRACE("nla_solver", c().trace_print_monic_and_factorization(rm, f, tout););
if (!c().var_is_separated_from_zero(var(rm))) if (!c().var_is_separated_from_zero(var(rm)))
return false; return false;
lpvar zero_j = null_lpvar; for (auto fc : f) {
for (auto j : f) { if (!c().var_is_fixed_to_zero(var(fc)))
if (c().var_is_fixed_to_zero(var(j))) { continue;
zero_j = var(j);
break;
}
}
if (zero_j == null_lpvar) {
return false;
}
new_lemma lemma(c(), "x = 0 or y = 0 -> xy = 0"); new_lemma lemma(c(), "x = 0 or y = 0 -> xy = 0");
c().explain_fixed_var(zero_j); lemma.explain_fixed(var(fc));
c().explain_var_separated_from_zero(var(rm)); c().explain_var_separated_from_zero(lemma, var(rm));
explain(rm); lemma &= rm;
lemma &= f;
return true; return true;
} }
return false;
}
// use the fact that // use the fact that
// |xabc| = |x| and x != 0 -> |a| = |b| = |c| = 1 // |xabc| = |x| and x != 0 -> |a| = |b| = |c| = 1
// it holds for integers, and for reals for a pair of factors // it holds for integers, and for reals for a pair of factors
// |x*a| = |x| & x != 0 -> |a| = 1 // |x*a| = |x| & x != 0 -> |a| = 1
bool basics::basic_lemma_for_mon_neutral_monic_to_factor_derived(const monic& rm, const factorization& f) { bool basics::basic_lemma_for_mon_neutral_derived(const monic& rm, const factorization& f) {
TRACE("nla_solver", c().trace_print_monic_and_factorization(rm, f, tout);); TRACE("nla_solver", c().trace_print_monic_and_factorization(rm, f, tout););
lpvar mon_var = c().emons()[rm.var()].var(); lpvar mon_var = c().emons()[rm.var()].var();
@ -350,26 +350,22 @@ bool basics::basic_lemma_for_mon_neutral_monic_to_factor_derived(const monic& rm
new_lemma lemma(c(), "|xa| = |x| & x != 0 -> |a| = 1"); new_lemma lemma(c(), "|xa| = |x| & x != 0 -> |a| = 1");
// mon_var = 0 // mon_var = 0
if (mon_var_is_sep_from_zero) if (mon_var_is_sep_from_zero)
c().explain_var_separated_from_zero(mon_var); c().explain_var_separated_from_zero(lemma, mon_var);
else else
c().explain_var_separated_from_zero(jl); c().explain_var_separated_from_zero(lemma, jl);
c().explain_equiv_vars(mon_var, jl); lemma.explain_equiv(mon_var, jl);
// not_one_j = 1 // not_one_j = 1
lemma |= ineq(not_one_j, llc::EQ, 1); lemma |= ineq(not_one_j, llc::EQ, 1);
// not_one_j = -1 // not_one_j = -1
lemma |= ineq(not_one_j, llc::EQ, -1); lemma |= ineq(not_one_j, llc::EQ, -1);
explain(rm); lemma &= rm;
lemma &= f;
return true; return true;
} }
bool basics::basic_lemma_for_mon_neutral_derived(const monic& rm, const factorization& factorization) {
return
basic_lemma_for_mon_neutral_monic_to_factor_derived(rm, factorization);
}
// x != 0 or y = 0 => |xy| >= |y| // x != 0 or y = 0 => |xy| >= |y|
void basics::proportion_lemma_model_based(const monic& rm, const factorization& factorization) { void basics::proportion_lemma_model_based(const monic& rm, const factorization& factorization) {
if (factorization_has_real(factorization)) // todo: handle the situaiton when all factors are greater than 1, if (factorization_has_real(factorization)) // todo: handle the situaiton when all factors are greater than 1,
@ -392,6 +388,8 @@ void basics::proportion_lemma_model_based(const monic& rm, const factorization&
bool basics::proportion_lemma_derived(const monic& rm, const factorization& factorization) { bool basics::proportion_lemma_derived(const monic& rm, const factorization& factorization) {
// NSB review: why return false? // NSB review: why return false?
return false; return false;
if (factorization_has_real(factorization))
return false;
rational rmv = abs(var_val(rm)); rational rmv = abs(var_val(rm));
if (rmv.is_zero()) { if (rmv.is_zero()) {
SASSERT(c().has_zero_factor(factorization)); SASSERT(c().has_zero_factor(factorization));
@ -429,13 +427,12 @@ NSB review:
*/ */
void basics::generate_pl_on_mon(const monic& m, unsigned factor_index) { void basics::generate_pl_on_mon(const monic& m, unsigned factor_index) {
if (mon_has_real(m)) SASSERT(!mon_has_real(m));
return;
new_lemma lemma(c(), "generate_pl_on_mon"); new_lemma lemma(c(), "generate_pl_on_mon");
unsigned mon_var = m.var(); unsigned mon_var = m.var();
rational mv = val(mon_var); rational mv = val(mon_var);
rational sm = rational(nla::rat_sign(mv)); rational sm = rational(nla::rat_sign(mv));
c().mk_ineq(sm, mon_var, llc::LT); lemma |= ineq(term(sm, mon_var), llc::LT, 0);
for (unsigned fi = 0; fi < m.size(); fi ++) { for (unsigned fi = 0; fi < m.size(); fi ++) {
lpvar j = m.vars()[fi]; lpvar j = m.vars()[fi];
if (fi != factor_index) { if (fi != factor_index) {
@ -448,6 +445,7 @@ void basics::generate_pl_on_mon(const monic& m, unsigned factor_index) {
lemma |= ineq(term(sm, mon_var, -sj, j), llc::GE, 0); lemma |= ineq(term(sm, mon_var, -sj, j), llc::GE, 0);
} }
} }
lemma &= m;
} }
/** /**
@ -459,8 +457,7 @@ void basics::generate_pl_on_mon(const monic& m, unsigned factor_index) {
sign_m*m < 0 or f_i = 0 or \/_{j != i} sign_m*m >= sign_j*f_j sign_m*m < 0 or f_i = 0 or \/_{j != i} sign_m*m >= sign_j*f_j
*/ */
void basics::generate_pl(const monic& m, const factorization& fc, int factor_index) { void basics::generate_pl(const monic& m, const factorization& fc, int factor_index) {
if (factorization_has_real(fc)) SASSERT(!factorization_has_real(fc));
return;
TRACE("nla_solver", tout << "factor_index = " << factor_index << ", m = " TRACE("nla_solver", tout << "factor_index = " << factor_index << ", m = "
<< pp_mon(c(), m); << pp_mon(c(), m);
tout << ", fc = " << c().pp(fc); tout << ", fc = " << c().pp(fc);
@ -487,8 +484,8 @@ void basics::generate_pl(const monic& m, const factorization& fc, int factor_ind
lemma |= ineq(term(sm, mon_var, -sj, j), llc::GE, 0); lemma |= ineq(term(sm, mon_var, -sj, j), llc::GE, 0);
} }
} }
explain(fc); lemma &= fc;
explain(m); lemma &= m;
} }
bool basics::is_separated_from_zero(const factorization& f) const { bool basics::is_separated_from_zero(const factorization& f) const {
@ -532,10 +529,10 @@ void basics::basic_lemma_for_mon_zero_model_based(const monic& rm, const factori
} else { } else {
lemma |= ineq(var(rm), llc::NE, 0); lemma |= ineq(var(rm), llc::NE, 0);
for (auto j : f) { for (auto j : f) {
c().explain_separation_from_zero(var(j)); c().explain_separation_from_zero(lemma, var(j));
} }
} }
explain(f); lemma &= f;
} }
void basics::basic_lemma_for_mon_model_based(const monic& rm) { void basics::basic_lemma_for_mon_model_based(const monic& rm) {
@ -558,51 +555,6 @@ void basics::basic_lemma_for_mon_model_based(const monic& rm) {
} }
} }
// use the fact that
// |xabc| = |x| and x != 0 -> |a| = |b| = |c| = 1
bool basics::basic_lemma_for_mon_neutral_monic_to_factor_model_based_fm(const monic& m) {
TRACE("nla_solver_bl", c().print_monic(m, tout););
lpvar mon_var = m.var();
const auto mv = var_val(m);
const auto abs_mv = abs(mv);
if (abs_mv == rational::zero()) {
return false;
}
lpvar jl = null_lpvar, not_one_j = null_lpvar;
bool all_int = true;
for (auto j : m.vars()) {
all_int &= c().var_is_int(j);
if (jl == null_lpvar && abs(val(j)) == abs_mv)
jl = j;
else if (jl == j)
return false;
else if (abs(val(j)) != rational(1))
not_one_j = j;
}
if (jl == null_lpvar || not_one_j == null_lpvar)
return false;
if (!all_int && m.size() > 2)
return false;
new_lemma lemma(c(), __FUNCTION__);
// mon_var = 0
lemma |= ineq(mon_var, llc::EQ, 0);
// negate abs(jl) == abs()
if (val(jl) == - val(mon_var))
lemma |= ineq(term(jl, mon_var), llc::NE, 0);
else // jl == mon_var
lemma |= ineq(term(jl, -rational(1), mon_var), llc::NE, 0);
// not_one_j = 1
lemma |= ineq(not_one_j, llc::EQ, 1);
// not_one_j = -1
lemma |= ineq(not_one_j, llc::EQ, -1);
return true;
}
/** /**
m = f1 * f2 * .. * fn m = f1 * f2 * .. * fn
@ -615,6 +567,10 @@ bool basics::basic_lemma_for_mon_neutral_monic_to_factor_model_based_fm(const mo
or or
- /\_j f_j = val(f_j) => m = sign - /\_j f_j = val(f_j) => m = sign
*/ */
// NSB code review: can't we just use basic_lemma_for_mon_neutral_from_factors_to_model_based?
// then the factorization is the same as the monomial.
// then the only difference is to omit adding some explanations.
bool basics::basic_lemma_for_mon_neutral_from_factors_to_monic_model_based_fm(const monic& m) { bool basics::basic_lemma_for_mon_neutral_from_factors_to_monic_model_based_fm(const monic& m) {
lpvar not_one = null_lpvar; lpvar not_one = null_lpvar;
rational sign(1); rational sign(1);
@ -690,25 +646,22 @@ bool basics::basic_lemma_for_mon_neutral_monic_to_factor_model_based(const monic
lemma |= ineq(mon_var, llc::EQ, 0); lemma |= ineq(mon_var, llc::EQ, 0);
// negate abs(jl) == abs() // negate abs(jl) == abs()
if (val(jl) == - val(mon_var)) lemma |= ineq(term(jl, rational(val(jl) == -val(mon_var) ? 1 : -1), mon_var), llc::NE, 0);
lemma |= ineq(term(jl, mon_var), llc::NE, 0);
else // jl == mon_var
lemma |= ineq(term(jl, -rational(1), mon_var), llc::NE, 0);
// not_one_j = 1 // not_one_j = 1
lemma |= ineq(not_one_j, llc::EQ, 1); lemma |= ineq(not_one_j, llc::EQ, 1);
// not_one_j = -1 // not_one_j = -1
lemma |= ineq(not_one_j, llc::EQ, -1); lemma |= ineq(not_one_j, llc::EQ, -1);
explain(rm); lemma &= rm;
explain(f); lemma &= f;
return true; return true;
} }
void basics::basic_lemma_for_mon_neutral_model_based(const monic& rm, const factorization& f) { void basics::basic_lemma_for_mon_neutral_model_based(const monic& rm, const factorization& f) {
if (f.is_mon()) { if (f.is_mon()) {
basic_lemma_for_mon_neutral_monic_to_factor_model_based_fm(f.mon()); basic_lemma_for_mon_neutral_monic_to_factor_model_based(rm, f);
basic_lemma_for_mon_neutral_from_factors_to_monic_model_based_fm(f.mon()); basic_lemma_for_mon_neutral_from_factors_to_monic_model_based_fm(f.mon());
} }
else { else {
@ -779,35 +732,24 @@ bool basics::basic_lemma_for_mon_neutral_from_factors_to_monic_model_based(const
lemma |= ineq(m.var(), llc::EQ, sign); lemma |= ineq(m.var(), llc::EQ, sign);
else else
lemma |= ineq(term(m.var(), -sign, not_one), llc::EQ, 0); lemma |= ineq(term(m.var(), -sign, not_one), llc::EQ, 0);
explain(m); lemma &= m;
explain(f); lemma &= f;
TRACE("nla_solver", tout << "m = " << pp_mon_with_vars(c(), m);); TRACE("nla_solver", tout << "m = " << pp_mon_with_vars(c(), m););
return true; return true;
} }
void basics::basic_lemma_for_mon_non_zero_model_based_mf(const factorization& f) {
TRACE("nla_solver_bl", tout << c().pp(f););
for (auto j : f) {
if (val(j).is_zero()) {
lpvar zero_j = var(j);
new_lemma lemma(c(), "x = 0 => x*... = 0");
lemma |= ineq(zero_j, llc::NE, 0);
lemma |= ineq(f.mon().var(), llc::EQ, 0);
return;
}
}
}
// x = 0 or y = 0 -> xy = 0 // x = 0 or y = 0 -> xy = 0
void basics::basic_lemma_for_mon_non_zero_model_based(const monic& rm, const factorization& f) { void basics::basic_lemma_for_mon_non_zero_model_based(const monic& rm, const factorization& f) {
TRACE("nla_solver_bl", c().trace_print_monic_and_factorization(rm, f, tout);); TRACE("nla_solver_bl", c().trace_print_monic_and_factorization(rm, f, tout););
// NSB code review: for (auto j : f) {
// the two branches are the same if (val(j).is_zero()) {
if (f.is_mon()) new_lemma lemma(c(), "x = 0 => x*... = 0");
basic_lemma_for_mon_non_zero_model_based_mf(f); lemma |= ineq(var(j), llc::NE, 0);
else lemma |= ineq(f.mon().var(), llc::EQ, 0);
basic_lemma_for_mon_non_zero_model_based_mf(f); lemma &= f;
return;
}
}
} }

View file

@ -14,6 +14,7 @@
namespace nla { namespace nla {
class core; class core;
class new_lemma;
struct basics: common { struct basics: common {
basics(core *core); basics(core *core);
bool basic_sign_lemma_on_two_monics(const monic& m, const monic& n); bool basic_sign_lemma_on_two_monics(const monic& m, const monic& n);
@ -36,7 +37,6 @@ struct basics: common {
// x = 0 or y = 0 -> xy = 0 // x = 0 or y = 0 -> xy = 0
void basic_lemma_for_mon_non_zero_model_based_rm(const monic& rm, const factorization& f); void basic_lemma_for_mon_non_zero_model_based_rm(const monic& rm, const factorization& f);
void basic_lemma_for_mon_non_zero_model_based_mf(const factorization& f);
// x = 0 or y = 0 -> xy = 0 // x = 0 or y = 0 -> xy = 0
bool basic_lemma_for_mon_non_zero_derived(const monic& rm, const factorization& f); bool basic_lemma_for_mon_non_zero_derived(const monic& rm, const factorization& f);
@ -45,7 +45,7 @@ struct basics: common {
bool basic_lemma_for_mon_neutral_monic_to_factor_model_based(const monic& rm, const factorization& f); bool basic_lemma_for_mon_neutral_monic_to_factor_model_based(const monic& rm, const factorization& f);
// use the fact that // use the fact that
// |xabc| = |x| and x != 0 -> |a| = |b| = |c| = 1 // |xabc| = |x| and x != 0 -> |a| = |b| = |c| = 1
bool basic_lemma_for_mon_neutral_monic_to_factor_model_based_fm(const monic& m); // bool basic_lemma_for_mon_neutral_monic_to_factor_model_based_fm(const monic& m);
bool basic_lemma_for_mon_neutral_monic_to_factor_derived(const monic& rm, const factorization& f); bool basic_lemma_for_mon_neutral_monic_to_factor_derived(const monic& rm, const factorization& f);
// use the fact // use the fact
@ -80,7 +80,7 @@ struct basics: common {
void generate_strict_case_zero_lemma(const monic& m, unsigned zero_j, int sign_of_zj); void generate_strict_case_zero_lemma(const monic& m, unsigned zero_j, int sign_of_zj);
void add_fixed_zero_lemma(const monic& m, lpvar j); void add_fixed_zero_lemma(const monic& m, lpvar j);
void negate_strict_sign(lpvar j); void negate_strict_sign(new_lemma& lemma, lpvar j);
// x != 0 or y = 0 => |xy| >= |y| // x != 0 or y = 0 => |xy| >= |y|
void proportion_lemma_model_based(const monic& rm, const factorization& factorization); void proportion_lemma_model_based(const monic& rm, const factorization& factorization);
// x != 0 or y = 0 => |xy| >= |y| // x != 0 or y = 0 => |xy| >= |y|

View file

@ -12,14 +12,6 @@
namespace nla { namespace nla {
bool common::done() const { return c().done(); } bool common::done() const { return c().done(); }
template <typename T> void common::explain(const T& t) {
c().explain(t, c().current_expl());
}
template void common::explain<monic>(const monic& t);
template void common::explain<factor>(const factor& t);
template void common::explain<factorization>(const factorization& t);
void common::explain(lpvar j) { c().explain(j, c().current_expl()); }
template <typename T> rational common::val(T const& t) const { return c().val(t); } template <typename T> rational common::val(T const& t) const { return c().val(t); }
template rational common::val<factor>(factor const& t) const; template rational common::val<factor>(factor const& t) const;
@ -39,52 +31,7 @@ template bool common::canonize_sign<factor>(const factor&) const;
template bool common::canonize_sign<lpvar>(const lpvar&) const; template bool common::canonize_sign<lpvar>(const lpvar&) const;
template bool common::canonize_sign<factorization>(const factorization&) 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);
}
void common::mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, llc cmp, const rational& rs){
c().mk_ineq(a, j, b, j, cmp, rs);
}
void common::mk_ineq(lpvar j, const rational& b, lpvar k, llc cmp, const rational& rs){
c().mk_ineq(j, b, k, cmp, rs);
}
void common::mk_ineq(lpvar j, const rational& b, lpvar k, llc cmp){
c().mk_ineq(j, b, k, cmp);
}
void common::mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, llc cmp) {
c().mk_ineq(a, j, b, k, cmp);
}
void common::mk_ineq(bool a, lpvar j, bool b, lpvar k, llc cmp) {
c().mk_ineq(sign_to_rat(a), j, sign_to_rat(b), k, cmp);
}
void common::mk_ineq(const rational& a ,lpvar j, lpvar k, llc cmp, const rational& rs) {
c().mk_ineq(a, j, k, cmp, rs);
}
void common::mk_ineq(lpvar j, lpvar k, llc cmp, const rational& rs) {
c().mk_ineq(j, k, cmp, rs);}
void common::mk_ineq(lpvar j, llc cmp, const rational& rs){
c().mk_ineq(j, cmp, rs);}
void common::mk_ineq(const rational& a, lpvar j, llc cmp, const rational& rs) {
c().mk_ineq(a, j, cmp, rs);
}
void common::mk_ineq(const rational& a, lpvar j, llc cmp){
c().mk_ineq(a, j, cmp);
}
void common::mk_ineq(lpvar j, llc cmp){
c().mk_ineq(j, cmp);
}
std::ostream& common::print_lemma(std::ostream& out) const {
return c().print_lemma(out);
}
template <typename T> template <typename T>
std::ostream& common::print_product(const T & m, std::ostream& out) const { std::ostream& common::print_product(const T & m, std::ostream& out) const {
return c().print_product(m, out); return c().print_product(m, out);

View file

@ -50,31 +50,7 @@ struct common {
rational mul_val(monic const& m) const; // value obtained from multiplying variables of monomial rational mul_val(monic const& m) const; // value obtained from multiplying variables of monomial
template <typename T> lpvar var(T const& t) const; template <typename T> lpvar var(T const& t) const;
bool done() const; bool done() const;
template <typename T> void explain(const T&);
void explain(lpvar);
template <typename T> bool canonize_sign(const T&) const; template <typename T> bool canonize_sign(const T&) const;
void mk_ineq(lp::lar_term& t, llc cmp, const rational& rs);
void mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, llc cmp, const rational& rs);
void mk_ineq(lpvar j, const rational& b, lpvar k, llc cmp, const rational& rs);
void mk_ineq(lpvar j, const rational& b, lpvar k, llc cmp);
void mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, llc cmp);
void mk_ineq(bool a, lpvar j, bool b, lpvar k, llc cmp);
void mk_ineq(const rational& a ,lpvar j, lpvar k, llc cmp, const rational& rs);
void mk_ineq(lpvar j, lpvar k, llc cmp, const rational& rs);
void mk_ineq(lpvar j, llc cmp, const rational& rs);
void mk_ineq(const rational& a, lpvar j, llc cmp, const rational& rs);
void mk_ineq(const rational& a, lpvar j, llc cmp);
void mk_ineq(lpvar j, llc cmp);
std::ostream& print_lemma(std::ostream&) const;
template <typename T> template <typename T>
std::ostream& print_product(const T & m, std::ostream& out) const; std::ostream& print_product(const T & m, std::ostream& out) const;

View file

@ -18,6 +18,8 @@ Author:
#include "math/dd/pdd_eval.h" #include "math/dd/pdd_eval.h"
namespace nla { namespace nla {
typedef lp::lar_term term;
core::core(lp::lar_solver& s, reslimit & lim) : core::core(lp::lar_solver& s, reslimit & lim) :
m_evars(), m_evars(),
m_lar_solver(s), m_lar_solver(s),
@ -160,22 +162,6 @@ bool core::check_monic(const monic& m) const {
return ret; return ret;
} }
void core::explain(const monic& m, lp::explanation& exp) const {
for (lpvar j : m.vars())
explain(j, exp);
}
void core::explain(const factor& f, lp::explanation& exp) const {
if (f.type() == factor_type::VAR) {
explain(f.var(), exp);
} else {
explain(m_emons[f.var()], exp);
}
}
void core::explain(lpvar j, lp::explanation& exp) const {
m_evars.explain(j, exp);
}
template <typename T> template <typename T>
std::ostream& core::print_product(const T & m, std::ostream& out) const { std::ostream& core::print_product(const T & m, std::ostream& out) const {
@ -358,7 +344,7 @@ bool core::explain_coeff_upper_bound(const lp::lar_term::ival& p, rational& boun
} }
// return true iff the negation of the ineq can be derived from the constraints // return true iff the negation of the ineq can be derived from the constraints
bool core::explain_ineq(const lp::lar_term& t, llc cmp, const rational& rs) { bool core::explain_ineq(new_lemma& lemma, const lp::lar_term& t, llc cmp, const rational& rs) {
// check that we have something like 0 < 0, which is always false and can be safely // check that we have something like 0 < 0, which is always false and can be safely
// removed from the lemma // removed from the lemma
@ -393,7 +379,7 @@ bool core::explain_ineq(const lp::lar_term& t, llc cmp, const rational& rs) {
return false; return false;
} }
if (r) { if (r) {
current_expl().add(exp); lemma &= exp;
return true; return true;
} }
@ -419,58 +405,13 @@ bool core::explain_by_equiv(const lp::lar_term& t, lp::explanation& e) const {
} }
void core::mk_ineq(lp::lar_term& t, llc cmp, const rational& rs) {
void core::mk_ineq_no_expl_check(new_lemma& lemma, lp::lar_term& t, llc cmp, const rational& rs) {
TRACE("nla_solver_details", m_lar_solver.print_term_as_indices(t, tout << "t = ");); TRACE("nla_solver_details", m_lar_solver.print_term_as_indices(t, tout << "t = "););
if (!explain_ineq(t, cmp, rs)) { lemma |= ineq(cmp, t, rs);
current_lemma().push_back(ineq(cmp, t, rs));
CTRACE("nla_solver", ineq_holds(ineq(cmp, t, rs)), print_ineq(ineq(cmp, t, rs), tout) << "\n";); CTRACE("nla_solver", ineq_holds(ineq(cmp, t, rs)), print_ineq(ineq(cmp, t, rs), tout) << "\n";);
SASSERT(!ineq_holds(ineq(cmp, t, rs))); SASSERT(!ineq_holds(ineq(cmp, t, rs)));
} }
}
void core::mk_ineq_no_expl_check(lp::lar_term& t, llc cmp, const rational& rs) {
TRACE("nla_solver_details", m_lar_solver.print_term_as_indices(t, tout << "t = "););
current_lemma().push_back(ineq(cmp, t, rs));
CTRACE("nla_solver", ineq_holds(ineq(cmp, t, rs)), print_ineq(ineq(cmp, t, rs), tout) << "\n";);
SASSERT(!ineq_holds(ineq(cmp, t, rs)));
}
void core::mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, llc cmp, const rational& rs) {
lp::lar_term t;
t.add_monomial(a, j);
t.add_monomial(b, k);
mk_ineq(t, cmp, rs);
}
void core::mk_ineq(lpvar j, const rational& b, lpvar k, llc cmp, const rational& rs) {
mk_ineq(rational(1), j, b, k, cmp, rs);
}
void core::mk_ineq(lpvar j, const rational& b, lpvar k, llc cmp) {
mk_ineq(j, b, k, cmp, rational::zero());
}
void core::mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, llc cmp) {
mk_ineq(a, j, b, k, cmp, rational::zero());
}
void core::mk_ineq(const rational& a ,lpvar j, lpvar k, llc cmp, const rational& rs) {
mk_ineq(a, j, rational(1), k, cmp, rs);
}
void core::mk_ineq(lpvar j, lpvar k, llc cmp, const rational& rs) {
mk_ineq(j, rational(1), k, cmp, rs);
}
void core::mk_ineq(lpvar j, llc cmp, const rational& rs) {
mk_ineq(rational(1), j, cmp, rs);
}
void core::mk_ineq(const rational& a, lpvar j, llc cmp, const rational& rs) {
lp::lar_term t;
t.add_monomial(a, j);
mk_ineq(t, cmp, rs);
}
llc apply_minus(llc cmp) { llc apply_minus(llc cmp) {
switch(cmp) { switch(cmp) {
@ -483,28 +424,15 @@ llc apply_minus(llc cmp) {
return cmp; return cmp;
} }
void core::mk_ineq(const rational& a, lpvar j, llc cmp) {
mk_ineq(a, j, cmp, rational::zero());
}
void core::mk_ineq(lpvar j, llc cmp) {
mk_ineq(j, cmp, rational::zero());
}
// the monics should be equal by modulo sign but this is not so in the model // the monics should be equal by modulo sign but this is not so in the model
void core::fill_explanation_and_lemma_sign(const monic& a, const monic & b, rational const& sign) { void core::fill_explanation_and_lemma_sign(new_lemma& lemma, const monic& a, const monic & b, rational const& sign) {
SASSERT(sign == 1 || sign == -1); SASSERT(sign == 1 || sign == -1);
explain(a, current_expl()); lemma &= a;
explain(b, current_expl()); lemma &= b;
TRACE("nla_solver", TRACE("nla_solver", tout << "used constraints: " << lemma;);
tout << "used constraints: "; SASSERT(lemma.num_ineqs() == 0);
for (auto &p : current_expl()) lemma |= ineq(term(rational(1), a.var(), -sign, b.var()), llc::EQ, 0);
m_lar_solver.constraints().display(tout, p.second); tout << "\n";
);
SASSERT(current_ineqs().size() == 0);
mk_ineq(rational(1), a.var(), -sign, b.var(), llc::EQ, rational::zero());
TRACE("nla_solver", print_lemma(tout););
} }
// Replaces each variable index by the root in the tree and flips the sign if the var comes with a minus. // Replaces each variable index by the root in the tree and flips the sign if the var comes with a minus.
@ -536,13 +464,6 @@ monic_coeff core::canonize_monic(monic const& m) const {
return monic_coeff(vars, sign); return monic_coeff(vars, sign);
} }
lemma& core::current_lemma() { return m_lemma_vec->back(); }
const lemma& core::current_lemma() const { return m_lemma_vec->back(); }
vector<ineq>& core::current_ineqs() { return current_lemma().ineqs(); }
lp::explanation& core::current_expl() { return current_lemma().expl(); }
const lp::explanation& core::current_expl() const { return current_lemma().expl(); }
int core::vars_sign(const svector<lpvar>& v) { int core::vars_sign(const svector<lpvar>& v) {
int sign = 1; int sign = 1;
for (lpvar j : v) { for (lpvar j : v) {
@ -704,47 +625,40 @@ bool core::is_canonical_monic(lpvar j) const {
} }
void core::explain_existing_lower_bound(lpvar j) { void core::explain_existing_lower_bound(new_lemma& lemma, lpvar j) {
SASSERT(has_lower_bound(j)); SASSERT(has_lower_bound(j));
current_expl().add(m_lar_solver.get_column_lower_bound_witness(j)); lemma &= m_lar_solver.get_column_lower_bound_witness(j);
} }
void core::explain_existing_upper_bound(lpvar j) { void core::explain_existing_upper_bound(new_lemma& lemma, lpvar j) {
SASSERT(has_upper_bound(j)); SASSERT(has_upper_bound(j));
current_expl().add(m_lar_solver.get_column_upper_bound_witness(j)); lemma &= m_lar_solver.get_column_upper_bound_witness(j);
} }
void core::explain_separation_from_zero(lpvar j) { void core::explain_separation_from_zero(new_lemma& lemma, lpvar j) {
SASSERT(!val(j).is_zero()); SASSERT(!val(j).is_zero());
if (val(j).is_pos()) if (val(j).is_pos())
explain_existing_lower_bound(j); explain_existing_lower_bound(lemma, j);
else else
explain_existing_upper_bound(j); explain_existing_upper_bound(lemma, j);
} }
void core::trace_print_monic_and_factorization(const monic& rm, const factorization& f, std::ostream& out) const { void core::trace_print_monic_and_factorization(const monic& rm, const factorization& f, std::ostream& out) const {
out << "rooted vars: "; out << "rooted vars: ";
print_product(rm.rvars(), out); print_product(rm.rvars(), out) << "\n";
out << "\n";
out << "mon: " << pp_mon(*this, rm.var()) << "\n"; out << "mon: " << pp_mon(*this, rm.var()) << "\n";
out << "value: " << var_val(rm) << "\n"; out << "value: " << var_val(rm) << "\n";
print_factorization(f, out << "fact: ") << "\n"; print_factorization(f, out << "fact: ") << "\n";
} }
void core::explain_var_separated_from_zero(lpvar j) { void core::explain_var_separated_from_zero(new_lemma& lemma, lpvar j) {
SASSERT(var_is_separated_from_zero(j)); SASSERT(var_is_separated_from_zero(j));
if (m_lar_solver.column_has_upper_bound(j) && (m_lar_solver.get_upper_bound(j)< lp::zero_of_type<lp::impq>())) if (m_lar_solver.column_has_upper_bound(j) && (m_lar_solver.get_upper_bound(j)< lp::zero_of_type<lp::impq>()))
current_expl().add(m_lar_solver.get_column_upper_bound_witness(j)); lemma &= m_lar_solver.get_column_upper_bound_witness(j);
else else
current_expl().add(m_lar_solver.get_column_lower_bound_witness(j)); lemma &= m_lar_solver.get_column_lower_bound_witness(j);
} }
void core::explain_fixed_var(lpvar j) {
SASSERT(var_is_fixed(j));
current_expl().add(m_lar_solver.get_column_upper_bound_witness(j));
current_expl().add(m_lar_solver.get_column_lower_bound_witness(j));
}
bool core::var_has_positive_lower_bound(lpvar j) const { bool core::var_has_positive_lower_bound(lpvar j) const {
return m_lar_solver.column_has_lower_bound(j) && m_lar_solver.get_lower_bound(j) > lp::zero_of_type<lp::impq>(); return m_lar_solver.column_has_lower_bound(j) && m_lar_solver.get_lower_bound(j) > lp::zero_of_type<lp::impq>();
@ -766,25 +680,6 @@ bool core::vars_are_equiv(lpvar a, lpvar b) const {
return m_evars.vars_are_equiv(a, b); return m_evars.vars_are_equiv(a, b);
} }
void core::explain_equiv_vars(lpvar a, lpvar b) {
SASSERT(abs(val(a)) == abs(val(b)));
if (m_evars.vars_are_equiv(a, b)) {
explain(a, current_expl());
explain(b, current_expl());
} else {
explain_fixed_var(a);
explain_fixed_var(b);
}
}
void core::explain(const factorization& f, lp::explanation& exp) {
SASSERT(!f.is_mon());
for (const auto& fc : f) {
explain(fc, exp);
}
}
bool core::has_zero_factor(const factorization& factorization) const { bool core::has_zero_factor(const factorization& factorization) const {
for (factor f : factorization) { for (factor f : factorization) {
if (val(f).is_zero()) if (val(f).is_zero())
@ -983,12 +878,12 @@ std::unordered_set<lpvar> core::collect_vars(const lemma& l) const {
} }
}; };
for (const auto& i : current_lemma().ineqs()) { for (const auto& i : l.ineqs()) {
for (const auto& p : i.term()) { for (const auto& p : i.term()) {
insert_j(p.column()); insert_j(p.column());
} }
} }
for (const auto& p : current_expl()) { for (const auto& p : l.expl()) {
const auto& c = m_lar_solver.constraints()[p.second]; const auto& c = m_lar_solver.constraints()[p.second];
for (const auto& r : c.coeffs()) { for (const auto& r : c.coeffs()) {
insert_j(r.second); insert_j(r.second);
@ -1026,16 +921,12 @@ bool core::divide(const monic& bc, const factor& c, factor & b) const {
return true; return true;
} }
void core::negate_var_relation_strictly(lpvar a, lpvar b) { void core::negate_var_relation_strictly(new_lemma& lemma, lpvar a, lpvar b) {
SASSERT(val(a) != val(b)); SASSERT(val(a) != val(b));
if (val(a) < val(b)) { lemma |= ineq(term(a, -rational(1), b), val(a) < val(b) ? llc::GT : llc::LT, 0);
mk_ineq(a, -rational(1), b, llc::GT);
} else {
mk_ineq(a, -rational(1), b, llc::LT);
}
} }
void core::negate_factor_equality(const factor& c, void core::negate_factor_equality(new_lemma& lemma, const factor& c,
const factor& d) { const factor& d) {
if (c == d) if (c == d)
return; return;
@ -1043,30 +934,22 @@ void core::negate_factor_equality(const factor& c,
lpvar j = var(d); lpvar j = var(d);
auto iv = val(i), jv = val(j); auto iv = val(i), jv = val(j);
SASSERT(abs(iv) == abs(jv)); SASSERT(abs(iv) == abs(jv));
if (iv == jv) { lemma |= ineq(term(i, rational(iv == jv ? -1 : 1), j), llc::NE, 0);
mk_ineq(i, -rational(1), j, llc::NE);
} else { // iv == -jv
mk_ineq(i, j, llc::NE, rational::zero());
}
} }
void core::negate_factor_relation(const rational& a_sign, const factor& a, const rational& b_sign, const factor& b) { void core::negate_factor_relation(new_lemma& lemma, const rational& a_sign, const factor& a, const rational& b_sign, const factor& b) {
rational a_fs = sign_to_rat(canonize_sign(a)); rational a_fs = sign_to_rat(canonize_sign(a));
rational b_fs = sign_to_rat(canonize_sign(b)); rational b_fs = sign_to_rat(canonize_sign(b));
llc cmp = a_sign*val(a) < b_sign*val(b)? llc::GE : llc::LE; llc cmp = a_sign*val(a) < b_sign*val(b)? llc::GE : llc::LE;
mk_ineq(a_fs*a_sign, var(a), - b_fs*b_sign, var(b), cmp); lemma |= ineq(term(a_fs*a_sign, var(a), - b_fs*b_sign, var(b)), cmp, 0);
} }
std::ostream& core::print_lemma(std::ostream& out) const { std::ostream& core::print_lemma(const lemma& l, std::ostream& out) const {
return print_specific_lemma(current_lemma(), out);
}
std::ostream& core::print_specific_lemma(const lemma& l, std::ostream& out) const {
static int n = 0; static int n = 0;
out << "lemma:" << ++n << " "; out << "lemma:" << ++n << " ";
print_ineqs(l, out); print_ineqs(l, out);
print_explanation(l.expl(), out); print_explanation(l.expl(), out);
for (lpvar j : collect_vars(current_lemma())) { for (lpvar j : collect_vars(l)) {
print_var(j, out); print_var(j, out);
} }
return out; return out;
@ -1146,11 +1029,11 @@ bool core::rm_check(const monic& rm) const {
*/ */
void core::add_abs_bound(lpvar v, llc cmp) { void core::add_abs_bound(new_lemma& lemma, lpvar v, llc cmp) {
add_abs_bound(v, cmp, val(v)); add_abs_bound(lemma, v, cmp, val(v));
} }
void core::add_abs_bound(lpvar v, llc cmp, rational const& bound) { void core::add_abs_bound(new_lemma& lemma, lpvar v, llc cmp, rational const& bound) {
SASSERT(!val(v).is_zero()); SASSERT(!val(v).is_zero());
lp::lar_term t; // t = abs(v) lp::lar_term t; // t = abs(v)
t.add_monomial(rrat_sign(val(v)), v); t.add_monomial(rrat_sign(val(v)), v);
@ -1158,7 +1041,7 @@ void core::add_abs_bound(lpvar v, llc cmp, rational const& bound) {
switch (cmp) { switch (cmp) {
case llc::GT: case llc::GT:
case llc::GE: // negate abs(v) >= 0 case llc::GE: // negate abs(v) >= 0
mk_ineq(t, llc::LT, rational(0)); lemma |= ineq(t, llc::LT, 0);
break; break;
case llc::LT: case llc::LT:
case llc::LE: case llc::LE:
@ -1167,7 +1050,7 @@ void core::add_abs_bound(lpvar v, llc cmp, rational const& bound) {
UNREACHABLE(); UNREACHABLE();
break; break;
} }
mk_ineq(t, cmp, abs(bound)); lemma |= ineq(t, cmp, abs(bound));
} }
// NB - move this comment to monotonicity or appropriate. // NB - move this comment to monotonicity or appropriate.
@ -1234,11 +1117,11 @@ new_lemma::new_lemma(core& c, char const* name):name(name), c(c) {
c.m_lemma_vec->push_back(lemma()); c.m_lemma_vec->push_back(lemma());
} }
new_lemma& new_lemma::add(ineq const& ineq) { new_lemma& new_lemma::operator|=(ineq const& ineq) {
if (!c.explain_ineq(ineq.term(), ineq.cmp(), ineq.rs())) { if (!c.explain_ineq(*this, ineq.term(), ineq.cmp(), ineq.rs())) {
c.current_lemma().push_back(ineq);
CTRACE("nla_solver", c.ineq_holds(ineq), c.print_ineq(ineq, tout) << "\n";); CTRACE("nla_solver", c.ineq_holds(ineq), c.print_ineq(ineq, tout) << "\n";);
SASSERT(!c.ineq_holds(ineq)); SASSERT(!c.ineq_holds(ineq));
current().push_back(ineq);
} }
return *this; return *this;
} }
@ -1248,12 +1131,65 @@ new_lemma::~new_lemma() {
TRACE("nla_solver", tout << name << "\n" << *this; ); TRACE("nla_solver", tout << name << "\n" << *this; );
} }
lemma& new_lemma::operator()() { lemma& new_lemma::current() const {
return c.current_lemma(); return c.m_lemma_vec->back();
} }
new_lemma& new_lemma::operator&=(lp::explanation const& e) {
expl().add(e);
return *this;
}
new_lemma& new_lemma::operator&=(const monic& m) {
for (lpvar j : m.vars())
*this &= j;
return *this;
}
new_lemma& new_lemma::operator&=(const factor& f) {
if (f.type() == factor_type::VAR)
*this &= f.var();
else
*this &= c.m_emons[f.var()];
return *this;
}
new_lemma& new_lemma::operator&=(const factorization& f) {
if (f.is_mon())
return *this;
for (const auto& fc : f) {
*this &= fc;
}
return *this;
}
new_lemma& new_lemma::operator&=(lpvar j) {
c.m_evars.explain(j, expl());
return *this;
}
new_lemma& new_lemma::explain_fixed(lpvar j) {
SASSERT(c.var_is_fixed(j));
*this &= c.m_lar_solver.get_column_upper_bound_witness(j);
*this &= c.m_lar_solver.get_column_lower_bound_witness(j);
return *this;
}
new_lemma& new_lemma::explain_equiv(lpvar a, lpvar b) {
SASSERT(abs(c.val(a)) == abs(c.val(b)));
if (c.vars_are_equiv(a, b)) {
*this &= a;
*this &= b;
} else {
explain_fixed(a);
explain_fixed(b);
}
return *this;
}
std::ostream& new_lemma::display(std::ostream & out) const { std::ostream& new_lemma::display(std::ostream & out) const {
auto const& lemma = c.current_lemma(); auto const& lemma = current();
for (auto &p : lemma.expl()) { for (auto &p : lemma.expl()) {
out << "(" << p.second << ") "; out << "(" << p.second << ") ";
@ -1278,14 +1214,10 @@ std::ostream& new_lemma::display(std::ostream & out) const {
return out; return out;
} }
void core::negate_relation(unsigned j, const rational& a) {
void core::negate_relation(new_lemma& lemma, unsigned j, const rational& a) {
SASSERT(val(j) != a); SASSERT(val(j) != a);
if (val(j) < a) { lemma |= ineq(j, val(j) < a ? llc::GE : llc::LE, a);
mk_ineq(j, llc::GE, a);
}
else {
mk_ineq(j, llc::LE, a);
}
} }
bool core::conflict_found() const { bool core::conflict_found() const {
@ -1555,7 +1487,7 @@ lbool core::check(vector<lemma>& l_vec) {
bool core::no_lemmas_hold() const { bool core::no_lemmas_hold() const {
for (auto & l : * m_lemma_vec) { for (auto & l : * m_lemma_vec) {
if (lemma_holds(l)) { if (lemma_holds(l)) {
TRACE("nla_solver", print_specific_lemma(l, tout);); TRACE("nla_solver", print_lemma(l, tout););
return false; return false;
} }
} }
@ -1703,7 +1635,7 @@ bool core::check_pdd_eq(const dd::solver::equation* e) {
eval.get_interval<dd::w_dep::with_deps>(e->poly(), i_wd); eval.get_interval<dd::w_dep::with_deps>(e->poly(), i_wd);
std::function<void (const lp::explanation&)> f = [this](const lp::explanation& e) { std::function<void (const lp::explanation&)> f = [this](const lp::explanation& e) {
new_lemma lemma(*this, "pdd"); new_lemma lemma(*this, "pdd");
current_expl().add(e); lemma &= e;
}; };
if (di.check_interval_for_conflict_on_zero(i_wd, e->dep(), f)) { if (di.check_interval_for_conflict_on_zero(i_wd, e->dep(), f)) {
lp_settings().stats().m_grobner_conflicts++; lp_settings().stats().m_grobner_conflicts++;

View file

@ -89,17 +89,25 @@ class core;
class new_lemma { class new_lemma {
char const* name; char const* name;
core& c; core& c;
lemma& current() const;
lp::explanation& expl() { return current().expl(); }
public: public:
new_lemma(core& c, char const* name); new_lemma(core& c, char const* name);
~new_lemma(); ~new_lemma();
new_lemma& add(ineq const& ineq); lemma& operator()() { return current(); }
lemma& operator()();
std::ostream& display(std::ostream& out) const; std::ostream& display(std::ostream& out) const;
new_lemma& operator&=(lp::explanation const& e);
new_lemma& operator&=(const monic& m);
new_lemma& operator&=(const factor& f);
new_lemma& operator&=(const factorization& f);
new_lemma& operator&=(lpvar j);
new_lemma& operator|=(ineq const& i);
new_lemma& explain_fixed(lpvar j);
new_lemma& explain_equiv(lpvar u, lpvar v);
unsigned num_ineqs() const { return current().ineqs().size(); }
}; };
inline new_lemma& operator|=(new_lemma& lemma, ineq const& i) {
return lemma.add(i);
}
inline std::ostream& operator<<(std::ostream& out, new_lemma const& l) { inline std::ostream& operator<<(std::ostream& out, new_lemma const& l) {
return l.display(out); return l.display(out);
@ -238,14 +246,11 @@ public:
// return true iff the monic value is equal to the product of the values of the factors // return true iff the monic value is equal to the product of the values of the factors
bool check_monic(const monic& m) const; bool check_monic(const monic& m) const;
void explain(const monic& m, lp::explanation& exp) const; // NSB review: these should really be methods on new_lemma
void explain(const factor& f, lp::explanation& exp) const; void explain_existing_lower_bound(new_lemma& lemma, lpvar j);
void explain(lpvar j, lp::explanation& exp) const; void explain_existing_upper_bound(new_lemma& lemma, lpvar j);
void explain_existing_lower_bound(lpvar j); void explain_separation_from_zero(new_lemma& lemma, lpvar j);
void explain_existing_upper_bound(lpvar j); void explain_var_separated_from_zero(new_lemma& lemma, lpvar j);
void explain_separation_from_zero(lpvar j);
void explain_var_separated_from_zero(lpvar j);
void explain_fixed_var(lpvar j);
std::ostream & print_ineq(const ineq & in, std::ostream & out) const; std::ostream & print_ineq(const ineq & in, std::ostream & out) const;
@ -274,13 +279,12 @@ public:
void trace_print_monic_and_factorization(const monic& rm, const factorization& f, std::ostream& out) const; void trace_print_monic_and_factorization(const monic& rm, const factorization& f, std::ostream& out) const;
void print_monic_stats(const monic& m, std::ostream& out); void print_monic_stats(const monic& m, std::ostream& out);
void print_stats(std::ostream& out); void print_stats(std::ostream& out);
std::ostream& print_lemma(std::ostream& out) const;
pp_var pp(lpvar j) const { return pp_var(*this, j); } pp_var pp(lpvar j) const { return pp_var(*this, j); }
pp_fac pp(factor const& f) const { return pp_fac(*this, f); } pp_fac pp(factor const& f) const { return pp_fac(*this, f); }
pp_factorization pp(factorization const& f) const { return pp_factorization(*this, f); } pp_factorization pp(factorization const& f) const { return pp_factorization(*this, f); }
std::ostream& print_specific_lemma(const lemma& l, std::ostream& out) const; std::ostream& print_lemma(const lemma& l, std::ostream& out) const;
void trace_print_ol(const monic& ac, void trace_print_ol(const monic& ac,
@ -291,22 +295,7 @@ public:
std::ostream& out); std::ostream& out);
void mk_ineq_no_expl_check(new_lemma& lemma, lp::lar_term& t, llc cmp, const rational& rs);
void mk_ineq(lp::lar_term& t, llc cmp, const rational& rs);
void mk_ineq_no_expl_check(lp::lar_term& t, llc cmp, const rational& rs);
void mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, llc cmp, const rational& rs);
void mk_ineq(bool a, lpvar j, bool b, lpvar k, llc cmp, const rational& rs);
void mk_ineq(bool a, lpvar j, bool b, lpvar k, llc cmp);
void mk_ineq(lpvar j, const rational& b, lpvar k, llc cmp, const rational& rs);
void mk_ineq(lpvar j, const rational& b, lpvar k, llc cmp);
void mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, llc cmp);
void mk_ineq(const rational& a ,lpvar j, lpvar k, llc cmp, const rational& rs);
void mk_ineq(lpvar j, lpvar k, llc cmp, const rational& rs);
void mk_ineq(lpvar j, llc cmp, const rational& rs);
void mk_ineq(const rational& a, lpvar j, llc cmp, const rational& rs);
void mk_ineq(const rational& a, lpvar j, llc cmp);
void mk_ineq(lpvar j, llc cmp);
void maybe_add_a_factor(lpvar i, void maybe_add_a_factor(lpvar i,
const factor& c, const factor& c,
@ -316,18 +305,12 @@ public:
llc apply_minus(llc cmp); llc apply_minus(llc cmp);
void fill_explanation_and_lemma_sign(const monic& a, const monic & b, rational const& sign); void fill_explanation_and_lemma_sign(new_lemma& lemma, const monic& a, const monic & b, rational const& sign);
svector<lpvar> reduce_monic_to_rooted(const svector<lpvar> & vars, rational & sign) const; svector<lpvar> reduce_monic_to_rooted(const svector<lpvar> & vars, rational & sign) const;
monic_coeff canonize_monic(monic const& m) const; monic_coeff canonize_monic(monic const& m) const;
lemma& current_lemma();
const lemma& current_lemma() const;
vector<ineq>& current_ineqs();
lp::explanation& current_expl();
const lp::explanation& current_expl() const;
int vars_sign(const svector<lpvar>& v); int vars_sign(const svector<lpvar>& v);
bool has_upper_bound(lpvar j) const; bool has_upper_bound(lpvar j) const;
bool has_lower_bound(lpvar j) const; bool has_lower_bound(lpvar j) const;
@ -361,20 +344,12 @@ public:
bool var_is_separated_from_zero(lpvar j) const; bool var_is_separated_from_zero(lpvar j) const;
bool vars_are_equiv(lpvar a, lpvar b) const; bool vars_are_equiv(lpvar a, lpvar b) const;
void explain_equiv_vars(lpvar a, lpvar b); bool explain_ineq(new_lemma& lemma, const lp::lar_term& t, llc cmp, const rational& rs);
void explain(const factorization& f, lp::explanation& exp);
bool explain_upper_bound(const lp::lar_term& t, const rational& rs, lp::explanation& e) const; bool explain_upper_bound(const lp::lar_term& t, const rational& rs, lp::explanation& e) const;
bool explain_lower_bound(const lp::lar_term& t, const rational& rs, lp::explanation& e) const; bool explain_lower_bound(const lp::lar_term& t, const rational& rs, lp::explanation& e) const;
bool explain_coeff_lower_bound(const lp::lar_term::ival& p, rational& bound, lp::explanation& e) const; bool explain_coeff_lower_bound(const lp::lar_term::ival& p, rational& bound, lp::explanation& e) const;
bool explain_coeff_upper_bound(const lp::lar_term::ival& p, rational& bound, lp::explanation& e) const; bool explain_coeff_upper_bound(const lp::lar_term::ival& p, rational& bound, lp::explanation& e) const;
bool explain_ineq(const lp::lar_term& t, llc cmp, const rational& rs);
bool explain_by_equiv(const lp::lar_term& t, lp::explanation& e) const; bool explain_by_equiv(const lp::lar_term& t, lp::explanation& e) const;
bool has_zero_factor(const factorization& factorization) const; bool has_zero_factor(const factorization& factorization) const;
template <typename T> template <typename T>
@ -415,25 +390,23 @@ public:
bool divide(const monic& bc, const factor& c, factor & b) const; bool divide(const monic& bc, const factor& c, factor & b) const;
void negate_factor_equality(const factor& c, const factor& d);
void negate_factor_relation(const rational& a_sign, const factor& a, const rational& b_sign, const factor& b);
void negate_var_relation_strictly(lpvar a, lpvar b);
std::unordered_set<lpvar> collect_vars(const lemma& l) const; std::unordered_set<lpvar> collect_vars(const lemma& l) const;
bool rm_check(const monic&) const; bool rm_check(const monic&) const;
std::unordered_map<unsigned, unsigned_vector> get_rm_by_arity(); std::unordered_map<unsigned, unsigned_vector> get_rm_by_arity();
void add_abs_bound(lpvar v, llc cmp); // NSB code review: these could be methods on new_lemma
void add_abs_bound(lpvar v, llc cmp, rational const& bound); void add_abs_bound(new_lemma& lemma, lpvar v, llc cmp);
void add_abs_bound(new_lemma& lemma, lpvar v, llc cmp, rational const& bound);
void negate_relation(new_lemma& lemma, unsigned j, const rational& a);
void negate_factor_equality(new_lemma& lemma, const factor& c, const factor& d);
void negate_factor_relation(new_lemma& lemma, const rational& a_sign, const factor& a, const rational& b_sign, const factor& b);
void negate_var_relation_strictly(new_lemma& lemma, lpvar a, lpvar b);
bool find_bfc_to_refine_on_monic(const monic&, factorization & bf); bool find_bfc_to_refine_on_monic(const monic&, factorization & bf);
bool find_bfc_to_refine(const monic* & m, factorization& bf); bool find_bfc_to_refine(const monic* & m, factorization& bf);
void negate_relation(unsigned j, const rational& a);
bool conflict_found() const; bool conflict_found() const;
lbool inner_check(bool derived); lbool inner_check(bool derived);

View file

@ -85,7 +85,7 @@ bool intervals::check_nex(const nex* n, u_dependency* initial_deps) {
scoped_dep_interval i(get_dep_intervals()); scoped_dep_interval i(get_dep_intervals());
std::function<void (const lp::explanation&)> f = [this](const lp::explanation& e) { std::function<void (const lp::explanation&)> f = [this](const lp::explanation& e) {
new_lemma lemma(*m_core, "check_nex"); new_lemma lemma(*m_core, "check_nex");
m_core->current_expl().add(e); lemma &= e;
}; };
if (!interval_of_expr<e_with_deps::without_deps>(n, 1, i, f)) { if (!interval_of_expr<e_with_deps::without_deps>(n, 1, i, f)) {
// found a conflict during the interval calculation // found a conflict during the interval calculation

View file

@ -40,11 +40,10 @@ void monotone::monotonicity_lemma_gt(const monic& m, const rational& prod_val) {
tout << "m = "; c().print_monic_with_vars(m, tout);); tout << "m = "; c().print_monic_with_vars(m, tout););
new_lemma lemma(c(), __FUNCTION__); new_lemma lemma(c(), __FUNCTION__);
for (lpvar j : m.vars()) { for (lpvar j : m.vars()) {
c().add_abs_bound(j, llc::GT); c().add_abs_bound(lemma, j, llc::GT);
} }
lpvar m_j = m.var(); lpvar m_j = m.var();
c().add_abs_bound(m_j, llc::LE, prod_val); c().add_abs_bound(lemma, m_j, llc::LE, prod_val);
TRACE("nla_solver", print_lemma(tout););
} }
/** \brief enforce the inequality |m| >= product |m[i]| . /** \brief enforce the inequality |m| >= product |m[i]| .
@ -56,11 +55,10 @@ void monotone::monotonicity_lemma_gt(const monic& m, const rational& prod_val) {
void monotone::monotonicity_lemma_lt(const monic& m, const rational& prod_val) { void monotone::monotonicity_lemma_lt(const monic& m, const rational& prod_val) {
new_lemma lemma(c(), __FUNCTION__); new_lemma lemma(c(), __FUNCTION__);
for (lpvar j : m.vars()) { for (lpvar j : m.vars()) {
c().add_abs_bound(j, llc::LT); c().add_abs_bound(lemma, j, llc::LT);
} }
lpvar m_j = m.var(); lpvar m_j = m.var();
c().add_abs_bound(m_j, llc::GE, prod_val); c().add_abs_bound(lemma, m_j, llc::GE, prod_val);
TRACE("nla_solver", print_lemma(tout););
} }

View file

@ -13,6 +13,8 @@
namespace nla { namespace nla {
typedef lp::lar_term term;
// The order lemma is // The order lemma is
// a > b && c > 0 => ac > bc // a > b && c > 0 => ac > bc
void order::order_lemma() { void order::order_lemma() {
@ -82,9 +84,9 @@ void order::order_lemma_on_binomial_sign(const monic& xy, lpvar x, lpvar y, int
SASSERT(!_().mon_has_zero(xy.vars())); SASSERT(!_().mon_has_zero(xy.vars()));
int sy = rat_sign(val(y)); int sy = rat_sign(val(y));
new_lemma lemma(c(), __FUNCTION__); new_lemma lemma(c(), __FUNCTION__);
mk_ineq(y, sy == 1 ? llc::LE : llc::GE); // negate sy lemma |= ineq(y, sy == 1 ? llc::LE : llc::GE, 0); // negate sy
mk_ineq(x, sy*sign == 1 ? llc::GT : llc::LT , val(x)); lemma |= ineq(x, sy*sign == 1 ? llc::GT : llc::LT , val(x));
mk_ineq(xy.var(), - val(x), y, sign == 1 ? llc::LE : llc::GE); lemma |= ineq(term(xy.var(), - val(x), y), sign == 1 ? llc::LE : llc::GE, 0);
} }
// We look for monics e = m.rvars()[k]*d and see if we can create an order lemma for m and e // We look for monics e = m.rvars()[k]*d and see if we can create an order lemma for m and e
@ -165,13 +167,13 @@ void order::generate_mon_ol(const monic& ac,
SASSERT(ab_cmp != llc::GT || (var_val(ac) <= var_val(bd) && val(a)*c_sign > val(b)*d_sign)); SASSERT(ab_cmp != llc::GT || (var_val(ac) <= var_val(bd) && val(a)*c_sign > val(b)*d_sign));
new_lemma lemma(_(), __FUNCTION__); new_lemma lemma(_(), __FUNCTION__);
mk_ineq(c_sign, c, llc::LE); lemma |= ineq(term(c_sign, c), llc::LE, 0);
explain(c); // this explains c == +- d lemma &= c; // this explains c == +- d
mk_ineq(c_sign, a, -d_sign * b.rat_sign(), b.var(), negate(ab_cmp)); lemma |= ineq(term(c_sign, a, -d_sign * b.rat_sign(), b.var()), negate(ab_cmp), 0);
mk_ineq(ac.var(), rational(-1), var(bd), ab_cmp); lemma |= ineq(term(ac.var(), rational(-1), var(bd)), ab_cmp, 0);
explain(bd); lemma &= bd;
explain(b); lemma &= b;
explain(d); lemma &= d;
} }
@ -215,8 +217,8 @@ void order::order_lemma_on_factorization(const monic& m, const factorization& ab
for (unsigned j = 0, k = 1; j < 2; j++, k--) { for (unsigned j = 0, k = 1; j < 2; j++, k--) {
new_lemma lemma(_(), __FUNCTION__); new_lemma lemma(_(), __FUNCTION__);
order_lemma_on_ab(lemma, m, rsign, var(ab[k]), var(ab[j]), gt); order_lemma_on_ab(lemma, m, rsign, var(ab[k]), var(ab[j]), gt);
explain(ab); lemma &= ab;
explain(m); lemma &= m;
} }
} }
for (unsigned j = 0, k = 1; j < 2; j++, k--) { for (unsigned j = 0, k = 1; j < 2; j++, k--) {
@ -260,15 +262,14 @@ void order::generate_ol_eq(const monic& ac,
<< " b " << "*v" << var(b) << " " << val(b) << "\n" << " b " << "*v" << var(b) << " " << val(b) << "\n"
<< " c " << "*v" << var(c) << " " << val(c) << "\n"); << " c " << "*v" << var(c) << " " << val(c) << "\n");
// ac == bc // ac == bc
mk_ineq(c.var(),llc::EQ); // c is not equal to zero lemma |= ineq(c.var(), llc::EQ, 0); // c is not equal to zero
mk_ineq(ac.var(), -rational(1), bc.var(), llc::NE); lemma |= ineq(term(ac.var(), -rational(1), bc.var()), llc::NE, 0);
mk_ineq(canonize_sign(a), a.var(), !canonize_sign(b), b.var(), llc::EQ); lemma |= ineq(term(rational(canonize_sign(a)), a.var(), rational(!canonize_sign(b)), b.var()), llc::EQ, 0);
explain(ac); lemma &= ac;
explain(a); lemma &= a;
explain(bc); lemma &= bc;
explain(b); lemma &= b;
explain(c); lemma &= c;
TRACE("nla_solver", _().print_lemma(tout););
} }
void order::generate_ol(const monic& ac, void order::generate_ol(const monic& ac,
@ -284,15 +285,14 @@ void order::generate_ol(const monic& ac,
<< " b " << "*v" << var(b) << " " << val(b) << "\n" << " b " << "*v" << var(b) << " " << val(b) << "\n"
<< " c " << "*v" << var(c) << " " << val(c) << "\n"); << " c " << "*v" << var(c) << " " << val(c) << "\n");
// fix the sign of c // fix the sign of c
_().negate_relation(c.var(), rational(0)); lemma |= ineq(c.var(), val(c.var()).is_neg() ? llc::GE : llc::LE, 0);
_().negate_var_relation_strictly(ac.var(), bc.var()); _().negate_var_relation_strictly(lemma, ac.var(), bc.var());
_().negate_var_relation_strictly(a.var(), b.var()); _().negate_var_relation_strictly(lemma, a.var(), b.var());
explain(ac); lemma &= ac;
explain(a); lemma &= a;
explain(bc); lemma &= bc;
explain(b); lemma &= b;
explain(c); lemma &= c;
TRACE("nla_solver", _().print_lemma(tout););
} }
// We have ac = a*c and bc = b*c. // We have ac = a*c and bc = b*c.
@ -327,9 +327,9 @@ bool order::order_lemma_on_ac_and_bc_and_factors(const monic& ac,
void order::order_lemma_on_ab_gt(new_lemma& lemma, const monic& m, const rational& sign, lpvar a, lpvar b) { void order::order_lemma_on_ab_gt(new_lemma& lemma, const monic& m, const rational& sign, lpvar a, lpvar b) {
SASSERT(sign * var_val(m) > val(a) * val(b)); SASSERT(sign * var_val(m) > val(a) * val(b));
// negate b == val(b) // negate b == val(b)
mk_ineq(b, llc::NE, val(b)); lemma |= ineq(b, llc::NE, val(b));
// ab <= val(b)a // ab <= val(b)a
mk_ineq(sign, m.var(), -val(b), a, llc::LE); lemma |= ineq(term(sign, m.var(), -val(b), a), llc::LE, 0);
} }
/* /*
given: sign * m = ab given: sign * m = ab
@ -340,9 +340,9 @@ void order::order_lemma_on_ab_lt(new_lemma& lemma, const monic& m, const rationa
", b = "; c().print_var(b, tout) << "\n";); ", b = "; c().print_var(b, tout) << "\n";);
SASSERT(sign * var_val(m) < val(a) * val(b)); SASSERT(sign * var_val(m) < val(a) * val(b));
// negate b == val(b) // negate b == val(b)
mk_ineq(b, llc::NE, val(b)); lemma |= ineq(b, llc::NE, val(b));
// ab >= val(b)a // ab >= val(b)a
mk_ineq(sign, m.var(), -val(b), a, llc::GE); lemma |= ineq(term(sign, m.var(), -val(b), a), llc::GE, 0);
} }
void order::order_lemma_on_ab(new_lemma& lemma, const monic& m, const rational& sign, lpvar a, lpvar b, bool gt) { void order::order_lemma_on_ab(new_lemma& lemma, const monic& m, const rational& sign, lpvar a, lpvar b, bool gt) {

View file

@ -11,7 +11,7 @@
namespace nla { namespace nla {
struct imp { struct tangent_imp {
point m_a; point m_a;
point m_b; point m_b;
point m_xy; point m_xy;
@ -26,33 +26,30 @@ struct imp {
lpvar m_jx; lpvar m_jx;
lpvar m_jy; lpvar m_jy;
tangents& m_tang; tangents& m_tang;
imp(point xy, bool m_is_mon;
tangent_imp(point xy,
const rational& v, const rational& v,
lpvar j, // the monic variable lpvar j, // the monic variable
const monic& m, const monic& m,
const factor& x, const factorization& f,
const factor& y,
tangents& tang) : m_xy(xy), tangents& tang) : m_xy(xy),
m_correct_v(xy.x * xy.y), m_correct_v(xy.x * xy.y),
m_below(v < m_correct_v), m_below(v < m_correct_v),
m_v(v), m_v(v),
m_j(tang.var(m)), m_j(tang.var(m)),
m_m(m), m_m(m),
m_x(x), m_x(f[0]),
m_y(y), m_y(f[1]),
m_jx(tang.var(x)), m_jx(tang.var(m_x)),
m_jy(tang.var(y)), m_jy(tang.var(m_y)),
m_tang(tang) {} m_tang(tang),
m_is_mon(f.is_mon()) {
SASSERT(f.size() == 2);
}
core & c() { return m_tang.c(); } core & c() { return m_tang.c(); }
void generate_explanations_of_tang_lemma(lp::explanation& exp) {
// here we repeat the same explanation for each lemma
c().explain(m_m, exp);
c().explain(m_x, exp);
c().explain(m_y, exp);
}
void tangent_lemma_on_bf() { void tangent_lemma_on_bf() {
get_tang_points(); get_tang_points();
TRACE("nla_solver", tout << "tang domain = "; print_tangent_domain(tout) << std::endl;); TRACE("nla_solver", tout << "tang domain = "; print_tangent_domain(tout) << std::endl;);
@ -61,11 +58,18 @@ struct imp {
generate_tang_plane(m_b); generate_tang_plane(m_b);
} }
void explain(new_lemma& lemma) {
if (!m_is_mon) {
lemma &= m_m;
lemma &= m_x;
lemma &= m_y;
}
}
void generate_tang_plane(const point & pl) { void generate_tang_plane(const point & pl) {
new_lemma lemma(c(), "generate tangent plane"); new_lemma lemma(c(), "generate tangent plane");
c().negate_relation(m_jx, m_x.rat_sign()*pl.x); c().negate_relation(lemma, m_jx, m_x.rat_sign()*pl.x);
c().negate_relation(m_jy, m_y.rat_sign()*pl.y); c().negate_relation(lemma, m_jy, m_y.rat_sign()*pl.y);
#if Z3DEBUG #if Z3DEBUG
SASSERT(c().val(m_x) == m_xy.x && c().val(m_y) == m_xy.y); SASSERT(c().val(m_x) == m_xy.x && c().val(m_y) == m_xy.y);
int mult_sign = nla::rat_sign(pl.x - m_xy.x)*nla::rat_sign(pl.y - m_xy.y); int mult_sign = nla::rat_sign(pl.x - m_xy.x)*nla::rat_sign(pl.y - m_xy.y);
@ -79,20 +83,23 @@ struct imp {
t.add_monomial(- m_y.rat_sign()*pl.x, m_jy); t.add_monomial(- m_y.rat_sign()*pl.x, m_jy);
t.add_monomial(- m_x.rat_sign()*pl.y, m_jx); t.add_monomial(- m_x.rat_sign()*pl.y, m_jx);
t.add_var(m_j); t.add_var(m_j);
c().mk_ineq(t, m_below? llc::GT : llc::LT, - pl.x*pl.y); lemma |= ineq(t, m_below? llc::GT : llc::LT, - pl.x*pl.y);
explain(lemma);
} }
void generate_two_tang_lines() { void generate_two_tang_lines() {
{ {
new_lemma lemma(c(), "two tangent planes 1"); new_lemma lemma(c(), "two tangent planes 1");
// Should be v = val(m_x)*val(m_y), and val(factor) = factor.rat_sign()*var(factor.var()) // Should be v = val(m_x)*val(m_y), and val(factor) = factor.rat_sign()*var(factor.var())
c().mk_ineq(m_jx, llc::NE, c().val(m_jx)); lemma |= ineq(m_jx, llc::NE, c().val(m_jx));
c().mk_ineq(m_j, - m_y.rat_sign() * m_xy.x, m_jy, llc::EQ); lemma |= ineq(lp::lar_term(m_j, - m_y.rat_sign() * m_xy.x, m_jy), llc::EQ, 0);
explain(lemma);
} }
{ {
new_lemma lemma(c(), "two tangent planes 2"); new_lemma lemma(c(), "two tangent planes 2");
c().mk_ineq(m_jy, llc::NE, c().val(m_jy)); lemma |= ineq(m_jy, llc::NE, c().val(m_jy));
c().mk_ineq(m_j, - m_x.rat_sign() * m_xy.y, m_jx, llc::EQ); lemma |= ineq(lp::lar_term(m_j, - m_x.rat_sign() * m_xy.y, m_jx), llc::EQ, 0);
explain(lemma);
} }
} }
// Get two planes tangent to surface z = xy, one at point a, and another at point b, creating a cut // Get two planes tangent to surface z = xy, one at point a, and another at point b, creating a cut
@ -182,36 +189,16 @@ void tangents::tangent_lemma() {
factorization bf(nullptr); factorization bf(nullptr);
const monic* m; const monic* m;
if (c().find_bfc_to_refine(m, bf)) { if (c().find_bfc_to_refine(m, bf)) {
unsigned lemmas_size_was = c().m_lemma_vec->size();
unsigned j = m->var(); unsigned j = m->var();
imp i(point(val(bf[0]), val(bf[1])), tangent_imp i(point(val(bf[0]), val(bf[1])),
c().val(j), c().val(j),
j, j,
*m, *m,
bf[0], bf,
bf[1],
*this); *this);
i.tangent_lemma_on_bf(); i.tangent_lemma_on_bf();
if (!bf.is_mon()) {
lp::explanation 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);
}
}
TRACE("nla_solver",
for (unsigned i = lemmas_size_was; i < c().m_lemma_vec->size(); i++)
c().print_specific_lemma((*c().m_lemma_vec)[i], tout); );
} }
} }
void tangents::generate_explanations_of_tang_lemma(const monic& rm, const factorization& bf, lp::explanation& exp) {
// here we repeat the same explanation for each lemma
c().explain(rm, exp);
c().explain(bf[0], exp);
c().explain(bf[1], exp);
}
} }

View file

@ -43,6 +43,5 @@ inline std::ostream& operator<<(std::ostream& out, point const& a) { return out
struct tangents : common { struct tangents : common {
tangents(core *core); tangents(core *core);
void tangent_lemma(); void tangent_lemma();
void generate_explanations_of_tang_lemma(const monic& rm, const factorization& bf, lp::explanation& exp);
}; // end of tangents }; // end of tangents
} // end of namespace } // end of namespace

View file

@ -193,9 +193,9 @@ void test_basic_lemma_for_mon_neutral_from_factors_to_monomial_0() {
s.set_column_value_test(lp_bde, lp::impq(rational(16))); s.set_column_value_test(lp_bde, lp::impq(rational(16)));
SASSERT(nla.get_core().test_check(lv) == l_false); VERIFY(nla.get_core().test_check(lv) == l_false);
nla.get_core().print_lemma(std::cout); nla.get_core().print_lemma(lv.back(), std::cout);
ineq i0(lp_ac, llc::NE, 1); ineq i0(lp_ac, llc::NE, 1);
lp::lar_term t1, t2; lp::lar_term t1, t2;
@ -259,9 +259,9 @@ void test_basic_lemma_for_mon_neutral_from_factors_to_monomial_1() {
s_set_column_value_test(s, lp_e, rational(1)); s_set_column_value_test(s, lp_e, rational(1));
s_set_column_value_test(s, lp_bde, rational(3)); s_set_column_value_test(s, lp_bde, rational(3));
SASSERT(nla.get_core().test_check(lemma) == l_false); VERIFY(nla.get_core().test_check(lemma) == l_false);
SASSERT(lemma[0].size() == 4); SASSERT(lemma[0].size() == 4);
nla.get_core().print_lemma(std::cout); nla.get_core().print_lemma(lemma.back(), std::cout);
lp::lar_term t0, t1, t2, t3; lp::lar_term t0, t1, t2, t3;
t0.add_var(lp_b); t0.add_var(lp_b);
@ -344,8 +344,8 @@ void test_basic_lemma_for_mon_zero_from_factors_to_monomial() {
s_set_column_value_test(s, lp_acd, rational(1)); s_set_column_value_test(s, lp_acd, rational(1));
s_set_column_value_test(s, lp_be, rational(1)); s_set_column_value_test(s, lp_be, rational(1));
SASSERT(nla.get_core().test_check(lemma) == l_false); VERIFY(nla.get_core().test_check(lemma) == l_false);
nla.get_core().print_lemma(std::cout); nla.get_core().print_lemma(lemma.back(), std::cout);
SASSERT(lemma.size() == 1 && lemma[0].size() == 2); SASSERT(lemma.size() == 1 && lemma[0].size() == 2);
lp::lar_term t0, t1; lp::lar_term t0, t1;
t0.add_var(lp_b); t0.add_var(lp_b);
@ -395,9 +395,9 @@ void test_basic_lemma_for_mon_zero_from_monomial_to_factors() {
s_set_column_value_test(s, lp_d, rational(1)); s_set_column_value_test(s, lp_d, rational(1));
s_set_column_value_test(s, lp_acd, rational(0)); s_set_column_value_test(s, lp_acd, rational(0));
SASSERT(nla.get_core().test_check(lemma) == l_false); VERIFY(nla.get_core().test_check(lemma) == l_false);
nla.get_core().print_lemma(std::cout); nla.get_core().print_lemma(lemma.back(), std::cout);
ineq i0(lp_a, llc::EQ, 0); ineq i0(lp_a, llc::EQ, 0);
ineq i1(lp_c, llc::EQ, 0); ineq i1(lp_c, llc::EQ, 0);
@ -471,10 +471,10 @@ void test_basic_lemma_for_mon_neutral_from_monomial_to_factors() {
s_set_column_value_test(s, lp_b, - rational(2)); s_set_column_value_test(s, lp_b, - rational(2));
// we have bde = -b, therefore d = +-1 and e = +-1 // we have bde = -b, therefore d = +-1 and e = +-1
s_set_column_value_test(s, lp_d, rational(3)); s_set_column_value_test(s, lp_d, rational(3));
SASSERT(nla.get_core().test_check(lemma) == l_false); VERIFY(nla.get_core().test_check(lemma) == l_false);
nla.get_core().print_lemma(std::cout); nla.get_core().print_lemma(lemma.back(), std::cout);
ineq i0(lp_d, llc::EQ, 1); ineq i0(lp_d, llc::EQ, 1);
ineq i1(lp_d, llc::EQ, -1); ineq i1(lp_d, llc::EQ, -1);
bool found0 = false; bool found0 = false;
@ -585,14 +585,14 @@ void test_basic_sign_lemma() {
s_set_column_value_test(s, lp_acd, rational(3)); s_set_column_value_test(s, lp_acd, rational(3));
vector<lemma> lemmas; vector<lemma> lemmas;
SASSERT(nla.get_core().test_check(lemmas) == l_false); VERIFY(nla.get_core().test_check(lemmas) == l_false);
lp::lar_term t; lp::lar_term t;
t.add_var(lp_bde); t.add_var(lp_bde);
t.add_var(lp_acd); t.add_var(lp_acd);
ineq q(llc::EQ, t, rational(0)); ineq q(llc::EQ, t, rational(0));
nla.get_core().print_lemma(std::cout); nla.get_core().print_lemma(lemmas.back(), std::cout);
} }
void test_order_lemma_params(bool var_equiv, int sign) { void test_order_lemma_params(bool var_equiv, int sign) {
@ -709,13 +709,13 @@ void test_order_lemma_params(bool var_equiv, int sign) {
} }
vector<lemma> lemma; vector<lemma> lemma;
SASSERT(nla.get_core().test_check(lemma) == l_false); VERIFY(nla.get_core().test_check(lemma) == l_false);
// lp::lar_term t; // lp::lar_term t;
// t.add_monomial(lp_bde); // t.add_monomial(lp_bde);
// t.add_monomial(lp_acd); // t.add_monomial(lp_acd);
// ineq q(llc::EQ, t, rational(0)); // ineq q(llc::EQ, t, rational(0));
nla.get_core().print_lemma(std::cout); nla.get_core().print_lemma(lemma.back(), std::cout);
// SASSERT(q == lemma.back()); // SASSERT(q == lemma.back());
// ineq i0(llc::EQ, lp::lar_term(), rational(0)); // ineq i0(llc::EQ, lp::lar_term(), rational(0));
// i0.m_term.add_monomial(lp_bde); // i0.m_term.add_monomial(lp_bde);
@ -793,8 +793,8 @@ void test_monotone_lemma() {
s_set_column_value_test(s, lp_ef, s.get_column_value(lp_ij)); s_set_column_value_test(s, lp_ef, s.get_column_value(lp_ij));
vector<lemma> lemma; vector<lemma> lemma;
SASSERT(nla.get_core().test_check(lemma) == l_false); VERIFY(nla.get_core().test_check(lemma) == l_false);
nla.get_core().print_lemma(std::cout); nla.get_core().print_lemma(lemma.back(), std::cout);
*/ */
} }
@ -822,8 +822,8 @@ void test_tangent_lemma_rat() {
nla.add_monic(lp_ab, vec.size(), vec.begin()); nla.add_monic(lp_ab, vec.size(), vec.begin());
vector<lemma> lemma; vector<lemma> lemma;
SASSERT(nla.get_core().test_check(lemma) == l_false); VERIFY(nla.get_core().test_check(lemma) == l_false);
nla.get_core().print_lemma(std::cout); nla.get_core().print_lemma(lemma.back(), std::cout);
} }
void test_tangent_lemma_reg() { void test_tangent_lemma_reg() {
@ -849,8 +849,8 @@ void test_tangent_lemma_reg() {
nla.add_monic(lp_ab, vec.size(), vec.begin()); nla.add_monic(lp_ab, vec.size(), vec.begin());
vector<lemma> lemma; vector<lemma> lemma;
SASSERT(nla.get_core().test_check(lemma) == l_false); VERIFY(nla.get_core().test_check(lemma) == l_false);
nla.get_core().print_lemma(std::cout); nla.get_core().print_lemma(lemma.back(), std::cout);
} }
void test_tangent_lemma_equiv() { void test_tangent_lemma_equiv() {
@ -895,8 +895,8 @@ void test_tangent_lemma_equiv() {
s_set_column_value_test(s, lp_ab, nla.get_core().mon_value_by_vars(mon_ab) + rational(10)); // greater by ten than the correct value s_set_column_value_test(s, lp_ab, nla.get_core().mon_value_by_vars(mon_ab) + rational(10)); // greater by ten than the correct value
vector<lemma> lemma; vector<lemma> lemma;
SASSERT(nla.get_core().test_check(lemma) == l_false); VERIFY(nla.get_core().test_check(lemma) == l_false);
nla.get_core().print_lemma(std::cout); nla.get_core().print_lemma(lemma.back(), std::cout);
*/ */
} }