3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-15 13:28:47 +00:00

a stronger zero lemma when the signs are known

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
Lev Nachmanson 2019-03-04 15:42:12 +14:00
parent 6637747fd9
commit e6d134b9fa
2 changed files with 48 additions and 42 deletions

View file

@ -356,7 +356,7 @@ struct solver::imp {
}
std::ostream& print_monomial_with_vars(const monomial& m, std::ostream& out) const {
out << "( [" << m.var() << "] = " << m_lar_solver.get_variable_name(m.var()) << " = " << vvr(m.var()) << " = ";
out << "["; print_var(m.var(), out) << "]\n";
print_product_with_vars(m.vars(), out);
out << ")\n";
return out;
@ -654,7 +654,6 @@ struct solver::imp {
// k runs over m.
void generate_sign_lemma_model_based(const monomial& m, const monomial& n, const rational& sign) {
TRACE("nla_solver",);
add_empty_lemma();
if (sign.is_zero()) {
// either m or n has to be equal zero, but it is not the case
SASSERT(!vvr(m).is_zero() || !vvr(n).is_zero());
@ -664,6 +663,7 @@ struct solver::imp {
generate_zero_lemmas(n);
return;
}
add_empty_lemma();
unsigned_vector mvars(m.vars());
unsigned_vector nvars(n.vars());
divide_by_common_factor(mvars, nvars);
@ -720,25 +720,29 @@ struct solver::imp {
}
void negate_strict_sign(lpvar j) {
int sign;
if (!vvr(j).is_zero()){
sign = rat_sign(vvr(j));
TRACE("nla_solver", print_var(j, tout););
if (!vvr(j).is_zero()) {
int sign = rat_sign(vvr(j));
mk_ineq(j, (sign == 1? llc::LE : llc::GE), current_lemma());
} else {
sign = 1;
try_get_non_strict_sign_from_bounds(j, sign);
mk_ineq(j, (sign == 1? llc::LT : llc::GT), current_lemma());
SASSERT(sign);
} else { // vvr(j).is_zero()
if (has_lower_bound(j) && get_lower_bound(j) >= rational(0)) {
explain_existing_lower_bound(j);
mk_ineq(j, llc::GT, current_lemma());
} else {
SASSERT(has_upper_bound(j) && get_upper_bound(j) <= rational(0));
explain_existing_upper_bound(j);
mk_ineq(j, llc::LT, current_lemma());
}
}
}
}
void generate_strict_case_zero_lemma(const monomial& m, unsigned zero_j, int sign_of_zj) {
TRACE("nla_solver", tout << "sign_of_zj = " << sign_of_zj << "\n";);
// we know all the signs
add_empty_lemma();
mk_ineq(zero_j, (sign_of_zj == 1? llc::GT : llc::LT), current_lemma());
for (unsigned j : m){
if (j == zero_j) {
mk_ineq(j, (sign_of_zj == 1? llc::GT : llc::LT), current_lemma());
}
else {
if (j != zero_j) {
negate_strict_sign(j);
}
}
@ -815,10 +819,10 @@ struct solver::imp {
}
void generate_zero_lemmas(const monomial& m) {
SASSERT(!vvr(m).is_zero());
SASSERT(!vvr(m).is_zero() && product_value(m).is_zero());
int sign = rat_sign(vvr(m));
unsigned_vector fixed_zeros;
unsigned zero_j = find_best_zero(m, fixed_zeros);
lpvar zero_j = find_best_zero(m, fixed_zeros);
SASSERT(is_set(zero_j));
unsigned zero_power = 0;
for (unsigned j : m){
@ -834,6 +838,7 @@ struct solver::imp {
sign = 0;
TRACE("nla_solver", tout << "zero_j = " << zero_j << ", sign = " << sign << "\n";);
if (sign == 0) {
add_empty_lemma();
mk_ineq(zero_j, llc::NE, current_lemma());
mk_ineq(m.var(), llc::EQ, current_lemma());
} else {
@ -868,8 +873,8 @@ struct solver::imp {
return rational(sign);
}
// Monomials m and n vars have the same absolute values,
// the function tests that the abs values of m.var() and n.var() are the same
// Monomials m and n vars have the same values, up to "sign"
// the function tests that the values of m.var() and n.var() are the same up to sign
bool sign_contradiction(const monomial& m, const monomial& n, rational & sign) const {
sign = rat_sign(m) * rat_sign(n);
return vvr(m) != sign * vvr(n) ;
@ -882,15 +887,15 @@ struct solver::imp {
});
return m_vars_equivalence.eq_vars(j);
}
// Monomials m and n vars have the same values, up to "sign"
// Generate a lemma if values of m.var() and n.var() are not the same up to sign
bool basic_sign_lemma_on_two_monomials(const monomial& m, const monomial& n, const rational& sign) {
TRACE("nla_solver", tout << "m = "; print_monomial_with_vars(m, tout); tout << "n= "; print_monomial_with_vars(n, tout); );
rational contr_sign;
if (sign_contradiction(m, n, contr_sign)) {
generate_sign_lemma(m, n, sign);
return true;
}
return false;
if (vvr(m) == vvr(n) *sign)
return false;
TRACE("nla_solver", tout << "sign contradiction:\nm = "; print_monomial_with_vars(m, tout); tout << "n= "; print_monomial_with_vars(n, tout); tout << "sign: " << sign << "\n";);
generate_sign_lemma(m, n, sign);
return true;
}
void init_abs_val_table() {
@ -929,9 +934,9 @@ struct solver::imp {
}
bool basic_sign_lemma_on_two_mons_model_based(const monomial& m, const monomial& n) {
TRACE("nla_solver", tout << "m = "; print_monomial_with_vars(m, tout); tout << "n= "; print_monomial_with_vars(n, tout); );
rational sign;
if (sign_contradiction(m, n, sign)) {
TRACE("nla_solver", tout << "m = "; print_monomial_with_vars(m, tout); tout << "n= "; print_monomial_with_vars(n, tout); tout << "sign: " << sign<< "\n"; );
generate_sign_lemma_model_based(m, n, sign);
return true;
}
@ -955,7 +960,7 @@ struct solver::imp {
bool basic_sign_lemma_on_mon(unsigned i, std::unordered_set<unsigned> & explored){
const monomial& m = m_monomials[i];
TRACE("nla_solver", tout << "i = " << i << ", mon = "; print_monomial_with_vars(m, tout););
TRACE("nla_solver_details", tout << "i = " << i << ", mon = "; print_monomial_with_vars(m, tout););
const index_with_sign& rm_i_s = m_rm_table.get_rooted_mon(i);
unsigned k = rm_i_s.index();
if (!try_insert(k, explored))
@ -968,9 +973,9 @@ struct solver::imp {
if (n == i) continue;
if (basic_sign_lemma_on_two_monomials(m, m_monomials[n], rm_i_s.sign()*i_s.sign()))
if(done())
return true;
return true;
}
TRACE("nla_solver",);
TRACE("nla_solver_details", tout << "return false\n";);
return false;
}
@ -1018,7 +1023,6 @@ struct solver::imp {
}
std::ostream & print_var(lpvar j, std::ostream & out) const {
out << "[" << j << "] = ";
auto it = m_var_to_its_monomial.find(j);
if (it != m_var_to_its_monomial.end()) {
print_monomial(m_monomials[it->second], out);
@ -1109,10 +1113,12 @@ struct solver::imp {
}
void explain_existing_lower_bound(lpvar j) {
SASSERT(has_lower_bound(j));
current_expl().add(m_lar_solver.get_column_lower_bound_witness(j));
}
void explain_existing_upper_bound(lpvar j) {
SASSERT(has_upper_bound(j));
current_expl().add(m_lar_solver.get_column_upper_bound_witness(j));
}
@ -1714,7 +1720,7 @@ struct solver::imp {
continue;
lpvar j = s.external_to_local(ti);
if (var_is_fixed_to_zero(j)) {
TRACE("nla_solver", tout << "term = "; s.print_term(*s.terms()[i], tout););
TRACE("nla_solver_eq", tout << "term = "; s.print_term(*s.terms()[i], tout););
add_equivalence_maybe(s.terms()[i], s.get_column_upper_bound_witness(j), s.get_column_lower_bound_witness(j));
}
}
@ -1806,7 +1812,7 @@ struct solver::imp {
void register_monomial_in_tables(unsigned i_mon) {
const monomial& m = m_monomials[i_mon];
monomial_coeff mc = canonize_monomial(m);
TRACE("nla_solver", tout << "i_mon = " << i_mon << ", mon = ";
TRACE("nla_solver_rm", tout << "i_mon = " << i_mon << ", mon = ";
print_monomial(m_monomials[i_mon], tout);
tout << "\nmc = ";
print_product(mc.vars(), tout);
@ -1852,7 +1858,7 @@ struct solver::imp {
m_rm_table.fill_rooted_monomials_containing_var();
m_rm_table.fill_proper_factors();
TRACE("nla_solver", print_stats(tout););
TRACE("nla_solver_rm", print_stats(tout););
}
void clear() {
@ -1877,7 +1883,7 @@ struct solver::imp {
m_to_refine.push_back(i);
}
TRACE("nla_solver",
tout << "to refine: ";
tout << m_to_refine.size() << " mons to refine: ";
for (unsigned i: m_to_refine) {
print_monomial_with_vars(m_monomials[i], tout);
}
@ -2199,7 +2205,7 @@ struct solver::imp {
// a > b && c > 0 => ac > bc
bool order_lemma_on_monomial(const rooted_mon& rm, bool derived) {
TRACE("nla_solver",
TRACE("nla_solver_details",
tout << "rm = "; print_product(rm, tout);
tout << ", orig = "; print_monomial(m_monomials[rm.orig_index()], tout);
);
@ -2763,11 +2769,11 @@ struct solver::imp {
lbool inner_check(bool derived) {
for (int search_level = 0; search_level < 3 && !done(); search_level++) {
TRACE("nla_solver", tout << "search_level = " << search_level << "\n";);
TRACE("nla_solver", tout << "derived = " << derived << ", search_level = " << search_level << "\n";);
if (search_level == 0) {
basic_lemma(derived);
if (!m_lemma_vec->empty())
return l_false;
return l_false;
} else if (search_level == 1) {
order_lemma(derived);
} else { // search_level == 2

View file

@ -112,7 +112,7 @@ struct rooted_mon_table {
if (list_contains_to_refine_reg(vec()[i].m_mons, to_refine_reg))
m_to_refine.push_back(i);
}
TRACE("nla_solver", tout << "m_to_refine = "; print_vector(m_to_refine, tout) << std::endl;);
TRACE("nla_solver", tout << "rooted m_to_refine =["; print_vector(m_to_refine, tout) << "]\n";);
}
void clear() {
@ -219,14 +219,14 @@ struct rooted_mon_table {
SASSERT(abs(mc.coeff()) == rational(1));
auto it = map().find(mc.vars());
if (it == map().end()) {
TRACE("nla_solver", tout << "size = " << vec().size(););
TRACE("nla_solver_rm", tout << "size = " << vec().size(););
map().emplace(mc.vars(), vec().size());
m_reg_to_rm.emplace(i_mon, index_with_sign(vec().size(), mc.coeff()));
vec().push_back(rooted_mon(mc.vars(), i_mon, mc.coeff()));
}
else {
vec()[it->second].push_back(ms);
TRACE("nla_solver", tout << "add ms.m_i = " << ms.m_i;);
TRACE("nla_solver_rm", tout << "add ms.m_i = " << ms.m_i;);
m_reg_to_rm.emplace(i_mon, index_with_sign(it->second, mc.coeff()));
}
}