3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-28 11:25:51 +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 {
new_lemma lemma(c(), __FUNCTION__);
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);
}
@ -155,8 +155,8 @@ void basics::generate_sign_lemma(const monic& m, const monic& n, const rational&
tout << "n = " << pp_mon_with_vars(_(), n);
);
lemma |= ineq(term(m.var(), -sign, n.var()), llc::EQ, 0);
explain(m);
explain(n);
lemma &= m;
lemma &= n;
}
// try to find a variable j such that val(j) = 0
// 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);
for (unsigned j : m.vars()) {
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) {
new_lemma lemma(c(), "fixed zero");
c().explain_fixed_var(j);
lemma.explain_fixed(j);
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";);
if (!val(j).is_zero()) {
int sign = nla::rat_sign(val(j));
c().mk_ineq(j, (sign == 1? llc::LE : llc::GE));
} else { // val(j).is_zero()
lemma |= ineq(j, (sign == 1? llc::LE : llc::GE), 0);
}
else { // val(j).is_zero()
if (c().has_lower_bound(j) && c().get_lower_bound(j) >= rational(0)) {
c().explain_existing_lower_bound(j);
c().mk_ineq(j, llc::GT);
c().explain_existing_lower_bound(lemma, j);
lemma |= ineq(j, llc::GT, 0);
} else {
SASSERT(c().has_upper_bound(j) && c().get_upper_bound(j) <= rational(0));
c().explain_existing_upper_bound(j);
c().mk_ineq(j, llc::LT);
c().explain_existing_upper_bound(lemma, j);
lemma |= ineq(j, llc::LT, 0);
}
}
}
@ -219,21 +220,24 @@ void basics::negate_strict_sign(lpvar j) {
// here we use the fact
// xy = 0 -> x = 0 or y = 0
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();
return true;
#if 0
TRACE("nla_solver", c().trace_print_monic_and_factorization(rm, f, tout););
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;
for (auto j : f) {
if (try_insert(var(j), processed))
lemma |= ineq(var(j), llc::EQ, 0);
}
explain(rm);
lemma &= rm;
lemma &= f;
return true;
#endif
}
// use basic multiplication properties to create a lemma
bool basics::basic_lemma(bool derived) {
if (basic_sign_lemma(derived))
@ -266,48 +270,44 @@ bool basics::basic_lemma_for_mon_derived(const monic& rm) {
if (c().var_is_fixed_to_zero(var(rm))) {
for (auto factorization : factorization_factory_imp(rm, c())) {
if (factorization.is_empty())
continue;
if (basic_lemma_for_mon_zero(rm, factorization) ||
basic_lemma_for_mon_neutral_derived(rm, factorization)) {
explain(factorization);
continue;
if (basic_lemma_for_mon_zero(rm, factorization))
return true;
if (basic_lemma_for_mon_neutral_derived(rm, factorization))
return true;
}
}
} else {
}
else {
for (auto factorization : factorization_factory_imp(rm, c())) {
if (factorization.is_empty())
continue;
if (basic_lemma_for_mon_non_zero_derived(rm, factorization) ||
basic_lemma_for_mon_neutral_derived(rm, factorization) ||
proportion_lemma_derived(rm, factorization)) {
explain(factorization);
if (basic_lemma_for_mon_non_zero_derived(rm, factorization))
return true;
if (basic_lemma_for_mon_neutral_derived(rm, factorization))
return true;
if (proportion_lemma_derived(rm, factorization))
return true;
}
}
}
return false;
}
// x = 0 or y = 0 -> xy = 0
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););
if (!c().var_is_separated_from_zero(var(rm)))
return false;
lpvar zero_j = null_lpvar;
for (auto j : f) {
if (c().var_is_fixed_to_zero(var(j))) {
zero_j = var(j);
break;
}
for (auto fc : f) {
if (!c().var_is_fixed_to_zero(var(fc)))
continue;
new_lemma lemma(c(), "x = 0 or y = 0 -> xy = 0");
lemma.explain_fixed(var(fc));
c().explain_var_separated_from_zero(lemma, var(rm));
lemma &= rm;
lemma &= f;
return true;
}
if (zero_j == null_lpvar) {
return false;
}
new_lemma lemma(c(), "x = 0 or y = 0 -> xy = 0");
c().explain_fixed_var(zero_j);
c().explain_var_separated_from_zero(var(rm));
explain(rm);
return true;
return false;
}
// use the fact that
@ -315,7 +315,7 @@ bool basics::basic_lemma_for_mon_non_zero_derived(const monic& rm, const factori
// it holds for integers, and for reals for a pair of factors
// |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););
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");
// mon_var = 0
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
c().explain_var_separated_from_zero(jl);
c().explain_equiv_vars(mon_var, jl);
c().explain_var_separated_from_zero(lemma, jl);
lemma.explain_equiv(mon_var, jl);
// not_one_j = 1
lemma |= ineq(not_one_j, llc::EQ, 1);
// not_one_j = -1
lemma |= ineq(not_one_j, llc::EQ, -1);
explain(rm);
lemma &= rm;
lemma &= f;
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|
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,
@ -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) {
// NSB review: why return false?
return false;
if (factorization_has_real(factorization))
return false;
rational rmv = abs(var_val(rm));
if (rmv.is_zero()) {
SASSERT(c().has_zero_factor(factorization));
@ -429,13 +427,12 @@ NSB review:
*/
void basics::generate_pl_on_mon(const monic& m, unsigned factor_index) {
if (mon_has_real(m))
return;
SASSERT(!mon_has_real(m));
new_lemma lemma(c(), "generate_pl_on_mon");
unsigned mon_var = m.var();
rational mv = val(mon_var);
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 ++) {
lpvar j = m.vars()[fi];
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 &= 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
*/
void basics::generate_pl(const monic& m, const factorization& fc, int factor_index) {
if (factorization_has_real(fc))
return;
SASSERT(!factorization_has_real(fc));
TRACE("nla_solver", tout << "factor_index = " << factor_index << ", m = "
<< pp_mon(c(), m);
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);
}
}
explain(fc);
explain(m);
lemma &= fc;
lemma &= m;
}
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 {
lemma |= ineq(var(rm), llc::NE, 0);
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) {
@ -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
@ -615,6 +567,10 @@ bool basics::basic_lemma_for_mon_neutral_monic_to_factor_model_based_fm(const mo
or
- /\_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) {
lpvar not_one = null_lpvar;
rational sign(1);
@ -689,26 +645,23 @@ bool basics::basic_lemma_for_mon_neutral_monic_to_factor_model_based(const monic
// 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);
// negate abs(jl) == abs()
lemma |= ineq(term(jl, rational(val(jl) == -val(mon_var) ? 1 : -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);
explain(rm);
explain(f);
lemma &= rm;
lemma &= f;
return true;
}
void basics::basic_lemma_for_mon_neutral_model_based(const monic& rm, const factorization& f) {
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());
}
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);
else
lemma |= ineq(term(m.var(), -sign, not_one), llc::EQ, 0);
explain(m);
explain(f);
lemma &= m;
lemma &= f;
TRACE("nla_solver", tout << "m = " << pp_mon_with_vars(c(), m););
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
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););
// NSB code review:
// the two branches are the same
if (f.is_mon())
basic_lemma_for_mon_non_zero_model_based_mf(f);
else
basic_lemma_for_mon_non_zero_model_based_mf(f);
for (auto j : f) {
if (val(j).is_zero()) {
new_lemma lemma(c(), "x = 0 => x*... = 0");
lemma |= ineq(var(j), llc::NE, 0);
lemma |= ineq(f.mon().var(), llc::EQ, 0);
lemma &= f;
return;
}
}
}