3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-12 12:08:18 +00:00
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-05-10 20:28:35 -07:00
parent 179c9c2da2
commit 99043399ce
3 changed files with 69 additions and 80 deletions

View file

@ -207,11 +207,11 @@ void basics::negate_strict_sign(new_lemma& lemma, lpvar j) {
} }
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(lemma, j); lemma.explain_existing_lower_bound(j);
lemma |= ineq(j, llc::GT, 0); 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(lemma, j); lemma.explain_existing_upper_bound(j);
lemma |= ineq(j, llc::LT, 0); lemma |= ineq(j, llc::LT, 0);
} }
} }
@ -302,7 +302,7 @@ bool basics::basic_lemma_for_mon_non_zero_derived(const monic& rm, const factori
continue; continue;
new_lemma lemma(c(), "x = 0 or y = 0 -> xy = 0"); new_lemma lemma(c(), "x = 0 or y = 0 -> xy = 0");
lemma.explain_fixed(var(fc)); lemma.explain_fixed(var(fc));
c().explain_var_separated_from_zero(lemma, var(rm)); lemma.explain_var_separated_from_zero(var(rm));
lemma &= rm; lemma &= rm;
lemma &= f; lemma &= f;
return true; return true;
@ -328,7 +328,7 @@ bool basics::basic_lemma_for_mon_neutral_derived(const monic& rm, const factoriz
return false; return false;
} }
bool mon_var_is_sep_from_zero = c().var_is_separated_from_zero(mon_var); bool mon_var_is_sep_from_zero = c().var_is_separated_from_zero(mon_var);
lpvar jl = null_lpvar, not_one_j = null_lpvar; lpvar u = null_lpvar, v = null_lpvar;
bool all_int = true; bool all_int = true;
for (auto fc : f) { for (auto fc : f) {
lpvar j = var(fc); lpvar j = var(fc);
@ -336,31 +336,22 @@ bool basics::basic_lemma_for_mon_neutral_derived(const monic& rm, const factoriz
if (j == null_lpvar && abs(val(j)) == abs_mv && if (j == null_lpvar && abs(val(j)) == abs_mv &&
c().vars_are_equiv(j, mon_var) && c().vars_are_equiv(j, mon_var) &&
(mon_var_is_sep_from_zero || c().var_is_separated_from_zero(j))) (mon_var_is_sep_from_zero || c().var_is_separated_from_zero(j)))
jl = j; u = j;
else if (j == jl)
return false;
else if (abs(val(j)) != rational(1)) else if (abs(val(j)) != rational(1))
not_one_j = j; v = j;
} }
if (jl == null_lpvar || not_one_j == null_lpvar) if (u == null_lpvar || v == null_lpvar)
return false; return false;
if (!all_int && f.size() > 2) if (!all_int && f.size() > 2)
return false; return false;
// (mon_var != 0 || u != 0) & mon_var = +/- u =>
// v = 1 or v = -1
new_lemma lemma(c(), "|xa| = |x| & x != 0 -> |a| = 1"); new_lemma lemma(c(), "|xa| = |x| & x != 0 -> |a| = 1");
// mon_var = 0 lemma.explain_var_separated_from_zero(mon_var_is_sep_from_zero ? mon_var : u);
if (mon_var_is_sep_from_zero) lemma.explain_equiv(mon_var, u);
c().explain_var_separated_from_zero(lemma, mon_var); lemma |= ineq(v, llc::EQ, 1);
else lemma |= ineq(v, llc::EQ, -1);
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);
lemma &= rm; lemma &= rm;
lemma &= f; lemma &= f;
return true; return true;
@ -422,9 +413,6 @@ NSB review:
sign_m*m < 0 or f_j = 0 or \/_{i != j} sign_m*m >= sign_i*f_i sign_m*m < 0 or f_j = 0 or \/_{i != j} sign_m*m >= sign_i*f_i
- or even, without reference to factor index:
sign_m*m < 0 or \/_i sign_m*m >= sign_i*f_i
*/ */
void basics::generate_pl_on_mon(const monic& m, unsigned factor_index) { void basics::generate_pl_on_mon(const monic& m, unsigned factor_index) {
SASSERT(!mon_has_real(m)); SASSERT(!mon_has_real(m));
@ -529,7 +517,7 @@ 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(lemma, var(j)); lemma.explain_separation_from_zero(var(j));
} }
} }
lemma &= f; lemma &= f;
@ -601,8 +589,8 @@ bool basics::basic_lemma_for_mon_neutral_from_factors_to_monic_model_based_fm(co
new_lemma lemma(c(), __FUNCTION__); new_lemma lemma(c(), __FUNCTION__);
for (auto j : m.vars()) { for (auto j : m.vars()) {
if (not_one == j) continue; if (not_one != j)
lemma |= ineq(j, llc::NE, val(j)); lemma |= ineq(j, llc::NE, val(j));
} }
if (not_one == null_lpvar) if (not_one == null_lpvar)
@ -613,7 +601,7 @@ bool basics::basic_lemma_for_mon_neutral_from_factors_to_monic_model_based_fm(co
} }
// use the fact that // use the fact that
// |xabc| = |x| and x != 0 -> |a| = |b| = |c| = 1 // |uvw| = |u| and uvw != 0 -> |v| = 1
bool basics::basic_lemma_for_mon_neutral_monic_to_factor_model_based(const monic& rm, const factorization& f) { bool basics::basic_lemma_for_mon_neutral_monic_to_factor_model_based(const monic& rm, const factorization& f) {
lpvar mon_var = c().emons()[rm.var()].var(); lpvar mon_var = c().emons()[rm.var()].var();
TRACE("nla_solver_bl", c().trace_print_monic_and_factorization(rm, f, tout); tout << "\nmon_var = " << mon_var << "\n";); TRACE("nla_solver_bl", c().trace_print_monic_and_factorization(rm, f, tout); tout << "\nmon_var = " << mon_var << "\n";);
@ -624,36 +612,32 @@ bool basics::basic_lemma_for_mon_neutral_monic_to_factor_model_based(const monic
if (abs_mv == rational::zero()) { if (abs_mv == rational::zero()) {
return false; return false;
} }
lpvar jl = null_lpvar, not_one_j = null_lpvar; lpvar u = null_lpvar, v = null_lpvar;
bool all_int = true; bool all_int = true;
for (auto fc : f) { for (auto fc : f) {
lpvar j = var(fc); lpvar j = var(fc);
all_int &= c().var_is_int(j); all_int &= c().var_is_int(j);
if (j == null_lpvar && abs(val(fc)) == abs_mv) if (j == null_lpvar && abs(val(fc)) == abs_mv)
jl = j; u = j;
else if (j == jl)
return false;
else if (abs(val(fc)) != rational(1)) else if (abs(val(fc)) != rational(1))
not_one_j = j; v = j;
} }
if (jl == null_lpvar || not_one_j == null_lpvar) if (u == null_lpvar || v == null_lpvar)
return false; return false;
if (!all_int && f.size() > 2) if (!all_int && f.size() > 2)
return false; return false;
new_lemma lemma(c(), __FUNCTION__);
// mon_var = 0 // mon_var = 0
lemma |= ineq(mon_var, llc::EQ, 0); // abs(u) != abs(mon_var)
// v = 1
// negate abs(jl) == abs() // v = -1
lemma |= ineq(term(jl, rational(val(jl) == -val(mon_var) ? 1 : -1), mon_var), llc::NE, 0);
// not_one_j = 1 new_lemma lemma(c(), __FUNCTION__);
lemma |= ineq(not_one_j, llc::EQ, 1); lemma |= ineq(mon_var, llc::EQ, 0);
lemma |= ineq(term(u, rational(val(u) == -val(mon_var) ? 1 : -1), mon_var), llc::NE, 0);
// not_one_j = -1 lemma |= ineq(v, llc::EQ, 1);
lemma |= ineq(not_one_j, llc::EQ, -1); lemma |= ineq(v, llc::EQ, -1);
lemma &= rm; lemma &= rm; // NSB review: is this dependency required?
lemma &= f; lemma &= f;
return true; return true;
@ -695,7 +679,7 @@ bool basics::basic_lemma_for_mon_neutral_from_factors_to_monic_model_based(const
} }
if (v == -rational(1)) { if (v == -rational(1)) {
sign = - sign; sign = -sign;
continue; continue;
} }

View file

@ -625,24 +625,6 @@ bool core::is_canonical_monic(lpvar j) const {
} }
void core::explain_existing_lower_bound(new_lemma& lemma, lpvar j) {
SASSERT(has_lower_bound(j));
lemma &= m_lar_solver.get_column_lower_bound_witness(j);
}
void core::explain_existing_upper_bound(new_lemma& lemma, lpvar j) {
SASSERT(has_upper_bound(j));
lemma &= m_lar_solver.get_column_upper_bound_witness(j);
}
void core::explain_separation_from_zero(new_lemma& lemma, lpvar j) {
SASSERT(!val(j).is_zero());
if (val(j).is_pos())
explain_existing_lower_bound(lemma, j);
else
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) << "\n"; print_product(rm.rvars(), out) << "\n";
@ -651,14 +633,6 @@ void core::trace_print_monic_and_factorization(const monic& rm, const factorizat
print_factorization(f, out << "fact: ") << "\n"; print_factorization(f, out << "fact: ") << "\n";
} }
void core::explain_var_separated_from_zero(new_lemma& lemma, lpvar 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>()))
lemma &= m_lar_solver.get_column_upper_bound_witness(j);
else
lemma &= 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>();
@ -1187,6 +1161,38 @@ new_lemma& new_lemma::explain_equiv(lpvar a, lpvar b) {
return *this; return *this;
} }
new_lemma& new_lemma::explain_var_separated_from_zero(lpvar j) {
SASSERT(c.var_is_separated_from_zero(j));
if (c.m_lar_solver.column_has_upper_bound(j) &&
(c.m_lar_solver.get_upper_bound(j)< lp::zero_of_type<lp::impq>()))
*this &= c.m_lar_solver.get_column_upper_bound_witness(j);
else
*this &= c.m_lar_solver.get_column_lower_bound_witness(j);
return *this;
}
new_lemma& new_lemma::explain_existing_lower_bound(lpvar j) {
SASSERT(c.has_lower_bound(j));
*this &= c.m_lar_solver.get_column_lower_bound_witness(j);
return *this;
}
new_lemma& new_lemma::explain_existing_upper_bound(lpvar j) {
SASSERT(c.has_upper_bound(j));
*this &= c.m_lar_solver.get_column_upper_bound_witness(j);
return *this;
}
new_lemma& new_lemma::explain_separation_from_zero(lpvar j) {
SASSERT(!c.val(j).is_zero());
if (c.val(j).is_pos())
explain_existing_lower_bound(j);
else
explain_existing_upper_bound(j);
return *this;
}
std::ostream& new_lemma::display(std::ostream & out) const { std::ostream& new_lemma::display(std::ostream & out) const {
auto const& lemma = current(); auto const& lemma = current();

View file

@ -105,6 +105,11 @@ public:
new_lemma& operator|=(ineq const& i); new_lemma& operator|=(ineq const& i);
new_lemma& explain_fixed(lpvar j); new_lemma& explain_fixed(lpvar j);
new_lemma& explain_equiv(lpvar u, lpvar v); new_lemma& explain_equiv(lpvar u, lpvar v);
new_lemma& explain_var_separated_from_zero(lpvar j);
new_lemma& explain_existing_lower_bound(lpvar j);
new_lemma& explain_existing_upper_bound(lpvar j);
new_lemma& explain_separation_from_zero(lpvar j);
unsigned num_ineqs() const { return current().ineqs().size(); } unsigned num_ineqs() const { return current().ineqs().size(); }
}; };
@ -245,13 +250,7 @@ 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;
// NSB review: these should really be methods on new_lemma
void explain_existing_lower_bound(new_lemma& lemma, lpvar j);
void explain_existing_upper_bound(new_lemma& lemma, lpvar j);
void explain_separation_from_zero(new_lemma& lemma, lpvar j);
void explain_var_separated_from_zero(new_lemma& lemma, lpvar j);
std::ostream & print_ineq(const ineq & in, std::ostream & out) const; std::ostream & print_ineq(const ineq & in, std::ostream & out) const;
std::ostream & print_var(lpvar j, std::ostream & out) const; std::ostream & print_var(lpvar j, std::ostream & out) const;