3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-22 16:45:31 +00:00

tangent lemma

Signed-off-by: Lev <levnach@hotmail.com>
This commit is contained in:
Lev 2019-01-22 16:36:48 -08:00 committed by Lev Nachmanson
parent d630b06933
commit 4886acfae5
2 changed files with 216 additions and 183 deletions

View file

@ -41,7 +41,7 @@ public:
}
}
void add_coeff_var(unsigned j) {
void add_var(unsigned j) {
rational c(1);
add_coeff_var(c, j);
}

View file

@ -74,9 +74,7 @@ struct solver::imp {
// m_var_to_its_monomial[m_monomials[i].var()] = i
std::unordered_map<lpvar, unsigned> m_var_to_its_monomial;
vector<lp::explanation> * m_expl_vec;
lp::explanation * m_expl;
vector<lemma> * m_lemma_vec;
lemma * m_lemma;
unsigned_vector m_to_refine;
std::unordered_map<unsigned_vector, unsigned, hash_svector> m_mkeys; // the key is the sorted vars of a monomial
@ -131,8 +129,8 @@ struct solver::imp {
return compare_holds(value(n.term()), n.cmp(), n.rs());
}
bool lemma_holds() const {
for(auto &i : *m_lemma) {
bool lemma_holds(const lemma& l) const {
for(auto &i : l) {
if (!ineq_holds(i))
return false;
}
@ -236,20 +234,20 @@ struct solver::imp {
return product_value(m) == m_lar_solver.get_column_value_rational(m.var());
}
void explain(const monomial& m) const {
m_vars_equivalence.explain(m, *m_expl);
void explain(const monomial& m, lp::explanation& exp) const {
m_vars_equivalence.explain(m, exp);
}
void explain(const rooted_mon& rm) const {
void explain(const rooted_mon& rm, lp::explanation& exp) const {
auto & m = m_monomials[rm.orig_index()];
explain(m);
explain(m, exp);
}
void explain(const factor& f) const {
void explain(const factor& f, lp::explanation& exp) const {
if (f.type() == factor_type::VAR) {
m_vars_equivalence.explain(f.index(), *m_expl);
m_vars_equivalence.explain(f.index(), exp);
} else {
m_vars_equivalence.explain(m_monomials[m_rm_table.vec()[f.index()].orig_index()], *m_expl);
m_vars_equivalence.explain(m_monomials[m_rm_table.vec()[f.index()].orig_index()], exp);
}
}
@ -350,53 +348,53 @@ struct solver::imp {
return out;
}
std::ostream& print_explanation(std::ostream& out) const {
for (auto &p : *m_expl) {
std::ostream& print_explanation(std::ostream& out, lp::explanation& exp) const {
for (auto &p : exp) {
m_lar_solver.print_constraint(p.second, out);
}
return out;
}
void mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, llc cmp, const rational& rs) {
void mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, llc cmp, const rational& rs, lemma& l) {
lp::lar_term t;
t.add_coeff_var(a, j);
t.add_coeff_var(b, k);
if (t.is_empty() && rs.is_zero() &&
(cmp == llc::LT || cmp == llc::GT || cmp == llc::NE))
return; // otherwise we get something like 0 < 0, which is always false and can be removed from the lemma
m_lemma->push_back(ineq(cmp, t, rs));
l.push_back(ineq(cmp, t, rs));
}
void mk_ineq(lpvar j, const rational& b, lpvar k, llc cmp, const rational& rs) {
mk_ineq(rational(1), j, b, k, cmp, rs);
void mk_ineq(lpvar j, const rational& b, lpvar k, llc cmp, const rational& rs, lemma& l) {
mk_ineq(rational(1), j, b, k, cmp, rs, l);
}
void mk_ineq(lpvar j, const rational& b, lpvar k, llc cmp) {
mk_ineq(j, b, k, cmp, rational::zero());
void mk_ineq(lpvar j, const rational& b, lpvar k, llc cmp, lemma& l) {
mk_ineq(j, b, k, cmp, rational::zero(), l);
}
void mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, llc cmp) {
mk_ineq(a, j, b, k, cmp, rational::zero());
void mk_ineq(const rational& a, lpvar j, const rational& b, lpvar k, llc cmp, lemma& l) {
mk_ineq(a, j, b, k, cmp, rational::zero(), l);
}
void mk_ineq(const rational& a ,lpvar j, lpvar k, llc cmp, const rational& rs) {
mk_ineq(a, j, rational(1), k, cmp, rs);
void mk_ineq(const rational& a ,lpvar j, lpvar k, llc cmp, const rational& rs, lemma& l) {
mk_ineq(a, j, rational(1), k, cmp, rs, l);
}
void mk_ineq(lpvar j, lpvar k, llc cmp, const rational& rs) {
mk_ineq(j, rational(1), k, cmp, rs);
void mk_ineq(lpvar j, lpvar k, llc cmp, const rational& rs, lemma& l) {
mk_ineq(j, rational(1), k, cmp, rs, l);
}
void mk_ineq(lpvar j, llc cmp, const rational& rs) {
void mk_ineq(lpvar j, llc cmp, const rational& rs, lemma& l) {
lp::lar_term t;
t.add_coeff_var(j);
m_lemma->push_back(ineq(cmp, t, rs));
t.add_var(j);
l.push_back(ineq(cmp, t, rs));
}
void mk_ineq(const rational& a, lpvar j, llc cmp, const rational& rs) {
void mk_ineq(const rational& a, lpvar j, llc cmp, const rational& rs, lemma& l) {
lp::lar_term t;
t.add_coeff_var(a, j);
m_lemma->push_back(ineq(cmp, t, rs));
l.push_back(ineq(cmp, t, rs));
}
llc negate(llc cmp) {
@ -423,41 +421,41 @@ struct solver::imp {
return cmp;
}
bool explain(const rational& a, lpvar j, llc cmp, const rational& rs) {
bool explain(const rational& a, lpvar j, llc cmp, const rational& rs, lp::explanation & exp) {
cmp = negate(cmp);
if (a == rational(1))
return explain(j, cmp, rs);
return explain(j, cmp, rs, exp);
if (a == -rational(1))
return explain(j, apply_minus(cmp), -rs);
return explain(j, apply_minus(cmp), -rs, exp);
return false;
}
bool explain(lpvar j, llc cmp, const rational& rs) {
bool explain(lpvar j, llc cmp, const rational& rs, lp::explanation & exp) {
unsigned lc, uc; // indices for the lower and upper bounds
m_lar_solver.get_bound_constraint_witnesses_for_column(j, lc, uc);
switch(cmp) {
case llc::LE: {
if (uc + 1 == 0 || m_lar_solver.column_upper_bound(j) > rs)
return false;
m_expl->add(uc);
exp.add(uc);
return true;
}
case llc::LT: {
if (uc + 1 == 0 || m_lar_solver.column_upper_bound(j) >= rs)
return false;
m_expl->add(uc);
exp.add(uc);
return true;
}
case llc::GE: {
if (lc + 1 == 0 || m_lar_solver.column_lower_bound(j) < rs)
return false;
m_expl->add(lc);
exp.add(lc);
return true;
}
case llc::GT: {
if (lc + 1 == 0 || m_lar_solver.column_lower_bound(j) <= rs)
return false;
m_expl->add(lc);
exp.add(lc);
return true;
}
case llc::EQ:
@ -466,17 +464,17 @@ struct solver::imp {
||
uc + 1 == 0 || m_lar_solver.column_upper_bound(j) > rs)
return false;
m_expl->add(lc);
m_expl->add(uc);
exp.add(lc);
exp.add(uc);
return true;
}
case llc::NE: {
if (uc + 1 && m_lar_solver.column_upper_bound(j) < rs) {
m_expl->add(uc);
exp.add(uc);
return true;
}
if (lc + 1 && m_lar_solver.column_lower_bound(j) > rs) {
m_expl->add(lc);
exp.add(lc);
return true;
}
return false;
@ -488,31 +486,31 @@ struct solver::imp {
return false;
}
void mk_ineq(const rational& a, lpvar j, llc cmp) {
mk_ineq(a, j, cmp, rational::zero());
void mk_ineq(const rational& a, lpvar j, llc cmp, lemma& l) {
mk_ineq(a, j, cmp, rational::zero(), l);
}
void mk_ineq(lpvar j, lpvar k, llc cmp) {
mk_ineq(rational(1), j, rational(1), k, cmp, rational::zero());
void mk_ineq(lpvar j, lpvar k, llc cmp, lemma& l) {
mk_ineq(rational(1), j, rational(1), k, cmp, rational::zero(), l);
}
void mk_ineq(lpvar j, llc cmp) {
mk_ineq(j, cmp, rational::zero());
void mk_ineq(lpvar j, llc cmp, lemma& l) {
mk_ineq(j, cmp, rational::zero(), l);
}
// the monomials should be equal by modulo sign but this is not so in the model
void fill_explanation_and_lemma_sign(const monomial& a, const monomial & b, rational const& sign) {
SASSERT(sign == 1 || sign == -1);
explain(a);
explain(b);
explain(a, m_expl_vec->back());
explain(b, m_expl_vec->back());
TRACE("nla_solver",
tout << "used constraints: ";
for (auto &p : *m_expl)
for (auto &p : m_expl_vec->back())
m_lar_solver.print_constraint(p.second, tout); tout << "\n";
);
SASSERT(m_lemma->size() == 0);
mk_ineq(rational(1), a.var(), -sign, b.var(), llc::EQ, rational::zero());
TRACE("nla_solver", print_lemma(tout););
SASSERT(m_lemma_vec->back().size() == 0);
mk_ineq(rational(1), a.var(), -sign, b.var(), llc::EQ, rational::zero(), m_lemma_vec->back());
TRACE("nla_solver", print_lemma(m_lemma_vec->back(), tout););
}
// Replaces each variable index by the root in the tree and flips the sign if the var comes with a minus.
@ -549,7 +547,7 @@ struct solver::imp {
// the value of the i-th monomial has to be equal to the value of the k-th monomial modulo sign
// but it is not the case in the model
void generate_sign_lemma(const vector<rational>& abs_vals, const monomial& m, const monomial& n, const rational& sign) {
SASSERT(m_lemma->empty());
SASSERT(m_lemma_vec->back().empty());
TRACE("nla_solver",
tout << "m = "; print_monomial_with_vars(m, tout);
tout << "n = "; print_monomial_with_vars(n, tout);
@ -590,15 +588,17 @@ struct solver::imp {
index_with_sign & ins = it->second.back();
if (j != ins.m_i) {
s *= ins.m_sign;
mk_ineq(j, -s, ins.m_i, llc::NE);
mk_ineq(j, -s, ins.m_i, llc::NE, m_lemma_vec->back());
}
it->second.pop_back();
}
mk_ineq(m.var(), -sign, n.var(), llc::EQ);
TRACE("nla_solver", print_lemma(tout););
mk_ineq(m.var(), -sign, n.var(), llc::EQ, current_lemma());
TRACE("nla_solver", print_lemma(current_lemma(), tout););
}
lemma& current_lemma() {return m_lemma_vec->back();}
lp::explanation& current_expl() {return m_expl_vec->back();}
static int rat_sign(const rational& r) {
return r.is_pos()? 1 : ( r.is_neg()? -1 : 0);
@ -623,8 +623,8 @@ struct solver::imp {
}
}
SASSERT(zero_j + 1);
mk_ineq(zero_j, llc::NE);
mk_ineq(m.var(), llc::EQ);
mk_ineq(zero_j, llc::NE, m_lemma_vec->back());
mk_ineq(m.var(), llc::EQ, m_lemma_vec->back());
}
// we know here that the value one of the vars of each monomial is zero
@ -761,8 +761,7 @@ struct solver::imp {
return out;
}
std::ostream & print_lemma(std::ostream & out) const {
auto &l = *m_lemma;
std::ostream & print_lemma(const lemma& l, std::ostream & out) const {
out << "lemma: ";
for (unsigned i = 0; i < l.size(); i++) {
print_ineq(l[i], out);
@ -831,15 +830,15 @@ struct solver::imp {
}
}
SASSERT(m_lemma->empty());
SASSERT(current_lemma().empty());
mk_ineq(var(rm), llc::NE);
mk_ineq(var(rm), llc::NE, current_lemma());
for (auto j : f) {
mk_ineq(var(j), llc::EQ);
mk_ineq(var(j), llc::EQ, current_lemma());
}
explain(rm);
TRACE("nla_solver", print_lemma(tout););
explain(rm, current_expl());
TRACE("nla_solver", print_lemma(current_lemma(), tout););
return true;
}
@ -870,11 +869,11 @@ struct solver::imp {
return false;
}
mk_ineq(zero_j, llc::NE);
mk_ineq(var(rm), llc::EQ);
mk_ineq(zero_j, llc::NE, current_lemma());
mk_ineq(var(rm), llc::EQ, current_lemma());
explain(rm);
TRACE("nla_solver", print_lemma(tout););
explain(rm, current_expl());
TRACE("nla_solver", print_lemma(current_lemma(), tout););
return true;
}
@ -917,21 +916,21 @@ struct solver::imp {
}
// mon_var = 0
mk_ineq(mon_var, llc::EQ);
mk_ineq(mon_var, llc::EQ, current_lemma());
// negate abs(jl) == abs()
if (vvr(jl) == - vvr(mon_var))
mk_ineq(jl, mon_var, llc::NE);
mk_ineq(jl, mon_var, llc::NE, current_lemma());
else // jl == mon_var
mk_ineq(jl, -rational(1), mon_var, llc::NE);
mk_ineq(jl, -rational(1), mon_var, llc::NE, current_lemma());
// not_one_j = 1
mk_ineq(not_one_j, llc::EQ, rational(1));
mk_ineq(not_one_j, llc::EQ, rational(1), current_lemma());
// not_one_j = -1
mk_ineq(not_one_j, llc::EQ, -rational(1));
explain(rm);
TRACE("nla_solver", print_lemma(tout); );
mk_ineq(not_one_j, llc::EQ, -rational(1), current_lemma());
explain(rm, current_expl());
TRACE("nla_solver", print_lemma(current_lemma(), tout); );
return true;
}
@ -963,22 +962,22 @@ struct solver::imp {
return false;
}
explain(rm);
explain(rm, current_expl());
for (auto j : f){
lpvar var_j = var(j);
if (not_one == var_j) continue;
mk_ineq(var_j, llc::NE, j.is_var()? vvr(j) : flip_sign(j) * vvr(j) );
mk_ineq(var_j, llc::NE, j.is_var()? vvr(j) : flip_sign(j) * vvr(j), current_lemma());
}
if (not_one == static_cast<lpvar>(-1)) {
mk_ineq(m_monomials[rm.orig_index()].var(), llc::EQ, sign);
mk_ineq(m_monomials[rm.orig_index()].var(), llc::EQ, sign, current_lemma());
} else {
mk_ineq(m_monomials[rm.orig_index()].var(), -sign, not_one, llc::EQ);
mk_ineq(m_monomials[rm.orig_index()].var(), -sign, not_one, llc::EQ, current_lemma());
}
TRACE("nla_solver",
tout << "rm = "; print_rooted_monomial_with_vars(rm, tout);
print_lemma(tout););
print_lemma(current_lemma(), tout););
return true;
}
@ -989,9 +988,9 @@ struct solver::imp {
return false;
}
void explain(const factorization& f) {
void explain(const factorization& f, lp::explanation& exp) {
for (const auto& fc : f) {
explain(fc);
explain(fc, exp);
}
}
@ -1008,7 +1007,7 @@ struct solver::imp {
int fi = 0;
for (factor f : fc) {
if (fi++ != factor_index) {
mk_ineq(var(f), llc::EQ);
mk_ineq(var(f), llc::EQ, current_lemma());
} else {
rational rmv = vvr(rm);
rational sm = rational(rat_sign(rmv));
@ -1018,13 +1017,13 @@ struct solver::imp {
rational sj = rational(rat_sign(jv));
SASSERT(sm*rmv < sj*jv);
TRACE("nla_solver", tout << "rmv = " << rmv << ", jv = " << jv << "\n";);
mk_ineq(sm, mon_var, llc::LT);
mk_ineq(sj, j, llc::LT);
mk_ineq(sm, mon_var, -sj, j, llc::GE);
mk_ineq(sm, mon_var, llc::LT, current_lemma());
mk_ineq(sj, j, llc::LT, current_lemma());
mk_ineq(sm, mon_var, -sj, j, llc::GE, current_lemma());
}
explain(f);
explain(f, current_expl());
}
TRACE("nla_solver", print_lemma(tout););
TRACE("nla_solver", print_lemma(current_lemma(), tout););
}
// x != 0 or y = 0 => |xy| >= |y|
@ -1054,7 +1053,7 @@ struct solver::imp {
continue;
if (basic_lemma_for_mon_zero(rm, factorization) ||
basic_lemma_for_mon_neutral(rm, factorization)) {
explain(factorization);
explain(factorization, current_expl());
return true;
}
}
@ -1065,7 +1064,7 @@ struct solver::imp {
if (basic_lemma_for_mon_non_zero(rm, factorization) ||
basic_lemma_for_mon_neutral(rm, factorization) ||
proportion_lemma(rm, factorization)) {
explain(factorization);
explain(factorization, current_expl());
return true;
}
}
@ -1273,8 +1272,8 @@ struct solver::imp {
m_vars_equivalence.clear();
m_rm_table.clear();
m_monomials_containing_var.clear();
m_expl->clear();
m_lemma->clear();
m_expl_vec->clear();
m_lemma_vec->clear();
}
void init_search() {
@ -1328,9 +1327,9 @@ struct solver::imp {
auto iv = vvr(i), jv = vvr(j);
SASSERT(abs(iv) == abs(jv));
if (iv == jv) {
mk_ineq(i, -rational(1), j, llc::NE);
mk_ineq(i, -rational(1), j, llc::NE, current_lemma());
} else { // iv == -jv
mk_ineq(i, j, llc::NE);
mk_ineq(i, j, llc::NE, current_lemma());
}
}
@ -1338,7 +1337,7 @@ struct solver::imp {
rational a_fs = flip_sign(a);
rational b_fs = flip_sign(b);
llc cmp = a_sign*vvr(a) < b_sign*vvr(b)? llc::GE : llc::LE;
mk_ineq(a_fs*a_sign, var(a), - b_fs*b_sign, var(b), cmp);
mk_ineq(a_fs*a_sign, var(a), - b_fs*b_sign, var(b), cmp, current_lemma());
}
// |c_sign| = |d_sign| = 1, and c*c_sign = d*d_sign > 0
@ -1353,17 +1352,17 @@ struct solver::imp {
int d_sign,
const factor& d,
llc ab_cmp) {
mk_ineq(rational(c_sign) * flip_sign(c), var(c), llc::LE);
mk_ineq(rational(c_sign) * flip_sign(c), var(c), llc::LE, current_lemma());
negate_factor_equality(c, d);
negate_factor_relation(rational(c_sign), a, rational(d_sign), b);
mk_ineq(flip_sign(ac), var(ac), -flip_sign(bd), var(bd), ab_cmp);
explain(ac);
explain(a);
explain(c);
explain(bd);
explain(b);
explain(d); // todo: double check that these explanations are enough!
TRACE("nla_solver", print_lemma(tout););
mk_ineq(flip_sign(ac), var(ac), -flip_sign(bd), var(bd), ab_cmp, current_lemma());
explain(ac, current_expl());
explain(a, current_expl());
explain(c, current_expl());
explain(bd, current_expl());
explain(b, current_expl());
explain(d, current_expl()); // todo: double check that these explanations are enough!
TRACE("nla_solver", print_lemma(current_lemma(), tout););
}
bool get_cd_signs_for_ol(const rational& c, const rational& d, int& c_sign, int & d_sign) const {
@ -1664,9 +1663,9 @@ struct solver::imp {
rational bs = rational(rat_sign(bv));
TRACE("nla_solver", tout << "av = " << av << ", bv = " << bv << "\n";);
SASSERT(as*av <= bs*bv);
mk_ineq(as, a, llc::LT); // |aj| < 0
mk_ineq(bs, b, llc::LT); // |bj| < 0
mk_ineq(as, a, -bs, b, llc::GT); // negate |aj| <= |bj|
mk_ineq(as, a, llc::LT, current_lemma()); // |aj| < 0
mk_ineq(bs, b, llc::LT, current_lemma()); // |bj| < 0
mk_ineq(as, a, -bs, b, llc::GT, current_lemma()); // negate |aj| <= |bj|
}
void negate_abs_a_lt_abs_b(lpvar a, lpvar b) {
@ -1676,9 +1675,9 @@ struct solver::imp {
rational bs = rational(rat_sign(bv));
TRACE("nla_solver", tout << "av = " << av << ", bv = " << bv << "\n";);
SASSERT(as*av < bs*bv);
mk_ineq(as, a, llc::LT); // |aj| < 0
mk_ineq(bs, b, llc::LT); // |bj| < 0
mk_ineq(as, a, -bs, b, llc::GE); // negate |aj| < |bj|
mk_ineq(as, a, llc::LT, current_lemma()); // |aj| < 0
mk_ineq(bs, b, llc::LT, current_lemma()); // |bj| < 0
mk_ineq(as, a, -bs, b, llc::GE, current_lemma()); // negate |aj| < |bj|
}
void assert_abs_val_a_le_abs_var_b(
@ -1692,9 +1691,9 @@ struct solver::imp {
rational bv = vvr(bj);
rational bs = rational(rat_sign(bv));
// TRACE("nla_solver", tout << "rmv = " << rmv << ", jv = " << jv << "\n";);
mk_ineq(as, aj, llc::LT); // |aj| < 0
mk_ineq(bs, bj, llc::LT); // |bj| < 0
mk_ineq(as, aj, -bs, bj, strict? llc::LT : llc::LE); // |aj| < |bj|
mk_ineq(as, aj, llc::LT, current_lemma()); // |aj| < 0
mk_ineq(bs, bj, llc::LT, current_lemma()); // |bj| < 0
mk_ineq(as, aj, -bs, bj, strict? llc::LT : llc::LE, current_lemma()); // |aj| < |bj|
}
// strict version
@ -1708,13 +1707,13 @@ struct solver::imp {
if (i != strict) {
negate_abs_a_le_abs_b(akey[i].second, bkey[i].second);
} else {
mk_ineq(b[i], llc::EQ);
mk_ineq(b[i], llc::EQ, current_lemma());
negate_abs_a_lt_abs_b(akey[i].second, bkey[i].second);
}
}
assert_abs_val_a_le_abs_var_b(a, b, true);
explain(a);
explain(b);
explain(a, current_expl());
explain(b, current_expl());
}
// not a strict version
@ -1727,8 +1726,8 @@ struct solver::imp {
negate_abs_a_le_abs_b(a[i], b[i]);
}
assert_abs_val_a_le_abs_var_b(a, b, false);
explain(a);
explain(b);
explain(a, current_expl());
explain(b, current_expl());
}
bool monotonicity_lemma_on_lex_sorted_rm_upper(const vector<std::pair<std::vector<rational>, unsigned>>& lex_sorted, unsigned i, const rooted_mon& rm) {
@ -1855,7 +1854,7 @@ struct solver::imp {
return false;
}
bool find_bfc_to_refine(bfc& bf, lpvar &j, rational& sign){
bool find_bfc_to_refine(bfc& bf, lpvar &j, rational& sign, const rooted_mon*& rm_found){
for (const auto& rm : m_rm_table.vec()) {
if (check_monomial(m_monomials[rm.orig_index()]))
continue;
@ -1865,7 +1864,7 @@ struct solver::imp {
TRACE("nla_solver", tout << "found bf"; print_bfc(bf, tout);
tout << " product = " << vvr(rm) << ", but should be =" << vvr(bf.m_x)*vvr(bf.m_y);
tout << ", j == "; print_var(j, tout) << "\n";);
rm_found = &rm;
return true;
}
}
@ -1876,19 +1875,27 @@ struct solver::imp {
bfc bf;
lpvar j;
rational sign;
if (!find_bfc_to_refine(bf, j, sign)) {
const rooted_mon* rm;
if (!find_bfc_to_refine(bf, j, sign, rm)) {
return false;
}
tangent_lemma_bf(bf, j, sign);
generate_explanations_of_tang_lemma();
tangent_lemma_bf(bf, j, sign, *rm);
return true;
}
void generate_explanations_of_tang_lemma() {
SASSERT(false);
void generate_explanations_of_tang_lemma(const rooted_mon& rm, const bfc& bf) {
// here we repeat the same explanation for each lemma
lp::explanation exp;
explain(rm, exp);
explain(bf.m_x, exp);
explain(bf.m_y, exp);
m_expl_vec->clear();
while (m_expl_vec->size() < m_lemma_vec->size()) {
m_expl_vec->push_back(exp);
}
}
void tangent_lemma_bf(const bfc& bf, lpvar j, const rational& sign){
void tangent_lemma_bf(const bfc& bf, lpvar j, const rational& sign, const rooted_mon& rm){
point a, b;
point xy (vvr(bf.m_x), vvr(bf.m_y));
rational correct_mult_val = xy.x * xy.y;
@ -1897,25 +1904,52 @@ struct solver::imp {
TRACE("nla_solver", tout << "below = " << below << std::endl;);
get_tang_points(a, b, below, val, xy);
TRACE("nla_solver", tout << "tang domain = "; print_tangent_domain(a, b, tout); tout << std::endl;);
generate_tang_lemma(bf, xy, sign, j);
}
void generate_tang_lemma(const bfc & bf, const point& xy, const rational& sign, lpvar j) {
generate_two_tang_lines(bf, xy, sign, j);
generate_two_tang_planes();
generate_tang_plane(a.x, a.y, var(bf.m_x), var(bf.m_y), below, j, sign);
generate_tang_plane(b.x, b.y, var(bf.m_x), var(bf.m_y), below, j, sign);
generate_explanations_of_tang_lemma(rm, bf);
}
void generate_two_tang_planes() {}
void generate_two_tang_lines(const bfc & bf, const point& xy, const rational& sign, lpvar j) {
void add_empty_lemma() {
m_lemma_vec->push_back(lemma());
m_lemma = &m_lemma_vec->back();
mk_ineq(var(bf.m_x), llc::NE, xy.x);
mk_ineq(j, llc::EQ, sign * xy.x * xy.y);
}
void generate_tang_plane(const rational & a, const rational& b, lpvar jx, lpvar jy, bool below, lpvar j, const rational& j_sign) {
add_empty_lemma();
lemma& l = m_lemma_vec->back();
negate_relation(jx, a, l);
negate_relation(jy, a, l);
// If "below" holds then ay + bx - ab < xy, otherwise ay + bx - ab > xy,
// j_sign*vvr(j) stands for xy. So, finally we have ay + bx - j_sign*j < ab ( or > )
lp::lar_term t;
t.add_coeff_var(a, jy);
t.add_coeff_var(b, jx);
t.add_coeff_var( -j_sign, j);
l.push_back(ineq(below? llc::LT : llc::GT, t, a*b));
TRACE("nla_solver", print_lemma(l, tout););
}
m_lemma_vec->push_back(lemma());
m_lemma = &m_lemma_vec->back();
mk_ineq(var(bf.m_y), llc::NE, xy.y);
mk_ineq(j, llc::EQ, sign * xy.x * xy.y);
void negate_relation(unsigned j, const rational& a, lemma& l) {
SASSERT(vvr(j) != a);
if (vvr(j) < a) {
mk_ineq(j, llc::GE, a, l);
}
else {
mk_ineq(j, llc::LE, a, l);
}
TRACE("nla_solver", print_ineq(l.back(), tout););
}
void generate_two_tang_lines(const bfc & bf, const point& xy, const rational& sign, lpvar j) {
auto rs = sign * xy.x * xy.y;
add_empty_lemma();
mk_ineq(var(bf.m_x), llc::NE, xy.x, m_lemma_vec->back());
mk_ineq(j, llc::EQ, rs, m_lemma_vec->back());
add_empty_lemma();
mk_ineq(var(bf.m_y), llc::NE, xy.y, m_lemma_vec->back());
mk_ineq(j, llc::EQ, rs, m_lemma_vec->back());
}
// There are two planes tangent to surface z = xy at points a and b
// One can show that these planes still create a cut
@ -1987,15 +2021,9 @@ struct solver::imp {
}
lbool check(vector<lp::explanation> & expl_vec, vector<lemma>& l_vec) {
TRACE("nla_solver", tout << "check of nla";);
m_expl_vec = &expl_vec;
m_lemma_vec = &l_vec;
m_expl_vec->push_back(lp::explanation());
m_expl = m_expl_vec->begin();
m_lemma_vec->push_back(lemma());
m_lemma = m_lemma_vec->begin();
if (!(m_lar_solver.get_status() == lp::lp_status::OPTIMAL || m_lar_solver.get_status() == lp::lp_status::FEASIBLE )) {
TRACE("nla_solver", tout << "unknown because of the m_lar_solver.m_status = " << lp_status_to_string(m_lar_solver.get_status()) << "\n";);
return l_undef;
@ -2026,15 +2054,20 @@ struct solver::imp {
IF_VERBOSE(2, if(ret == l_undef) {verbose_stream() << "Monomials\n"; print_monomials(verbose_stream());});
CTRACE("nla_solver", ret == l_undef, tout << "Monomials\n"; print_monomials(tout););
SASSERT(ret != l_false || ((!m_lemma->empty()) && (!lemma_holds())));
SASSERT(ret != l_false || !lemmas_hold());
return ret;
}
bool lemmas_hold() const {
for (auto & l : * m_lemma_vec) {
if (lemma_holds(l))
return true;
}
return false;
}
void test_factorization(unsigned mon_index, unsigned number_of_factorizations) {
vector<ineq> lemma;
m_lemma = & lemma;
lp::explanation exp;
m_expl = & exp;
init_search();
factorization_factory_imp fc(m_monomials[mon_index].vars(), // 0 is the index of "abcde"
@ -2224,15 +2257,15 @@ void solver::test_basic_lemma_for_mon_neutral_from_factors_to_monomial_0() {
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
nla.m_imp->print_lemma(std::cout << "expl & lemma: ");
nla.m_imp->print_lemma(lemma.back(), std::cout << "expl & lemma: ");
ineq i0(llc::NE, lp::lar_term(), rational(1));
i0.m_term.add_coeff_var(lp_ac);
i0.m_term.add_var(lp_ac);
ineq i1(llc::EQ, lp::lar_term(), rational(0));
i1.m_term.add_coeff_var(lp_bde);
i1.m_term.add_var(lp_bde);
i1.m_term.add_coeff_var(-rational(1), lp_abcde);
ineq i2(llc::EQ, lp::lar_term(), rational(0));
i2.m_term.add_coeff_var(lp_abcde);
i2.m_term.add_var(lp_abcde);
i2.m_term.add_coeff_var(-rational(1), lp_bde);
bool found0 = false;
bool found1 = false;
@ -2283,16 +2316,16 @@ void solver::test_basic_lemma_for_mon_neutral_from_factors_to_monomial_1() {
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
SASSERT(lemma[0].size() == 4);
nla.m_imp->print_lemma(std::cout << "expl & lemma: ");
nla.m_imp->print_lemma(lemma.back(), std::cout << "expl & lemma: ");
ineq i0(llc::NE, lp::lar_term(), rational(1));
i0.m_term.add_coeff_var(lp_b);
i0.m_term.add_var(lp_b);
ineq i1(llc::NE, lp::lar_term(), rational(1));
i1.m_term.add_coeff_var(lp_d);
i1.m_term.add_var(lp_d);
ineq i2(llc::NE, lp::lar_term(), rational(1));
i2.m_term.add_coeff_var(lp_e);
i2.m_term.add_var(lp_e);
ineq i3(llc::EQ, lp::lar_term(), rational(1));
i3.m_term.add_coeff_var(lp_bde);
i3.m_term.add_var(lp_bde);
bool found0 = false;
bool found1 = false;
bool found2 = false;
@ -2362,12 +2395,12 @@ void solver::test_basic_lemma_for_mon_zero_from_factors_to_monomial() {
s.set_column_value(lp_be, rational(1));
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
nla.m_imp->print_lemma(std::cout << "expl & lemma: ");
nla.m_imp->print_lemma(lemma.back(), std::cout << "expl & lemma: ");
SASSERT(lemma.size() == 1 && lemma[0].size() == 2);
ineq i0(llc::NE, lp::lar_term(), rational(0));
i0.m_term.add_coeff_var(lp_b);
i0.m_term.add_var(lp_b);
ineq i1(llc::EQ, lp::lar_term(), rational(0));
i1.m_term.add_coeff_var(lp_be);
i1.m_term.add_var(lp_be);
bool found0 = false;
bool found1 = false;
@ -2426,14 +2459,14 @@ void solver::test_basic_lemma_for_mon_zero_from_monomial_to_factors() {
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
nla.m_imp->print_lemma(std::cout << "expl & lemma: ");
nla.m_imp->print_lemma(lemma.back(), std::cout << "expl & lemma: ");
ineq i0(llc::EQ, lp::lar_term(), rational(0));
i0.m_term.add_coeff_var(lp_b);
i0.m_term.add_var(lp_b);
ineq i1(llc::EQ, lp::lar_term(), rational(0));
i1.m_term.add_coeff_var(lp_d);
i1.m_term.add_var(lp_d);
ineq i2(llc::EQ, lp::lar_term(), rational(0));
i2.m_term.add_coeff_var(lp_e);
i2.m_term.add_var(lp_e);
bool found0 = false;
bool found1 = false;
bool found2 = false;
@ -2504,11 +2537,11 @@ void solver::test_basic_lemma_for_mon_neutral_from_monomial_to_factors() {
// we have bde = -b, therefore d = +-1 and e = +-1
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
nla.m_imp->print_lemma(std::cout << "expl & lemma: ");
nla.m_imp->print_lemma(lemma.back(), std::cout << "expl & lemma: ");
ineq i0(llc::EQ, lp::lar_term(), rational(1));
i0.m_term.add_coeff_var(lp_b);
i0.m_term.add_var(lp_b);
ineq i1(llc::EQ, lp::lar_term(), -rational(1));
i1.m_term.add_coeff_var(lp_b);
i1.m_term.add_var(lp_b);
bool found0 = false;
bool found1 = false;
@ -2577,15 +2610,15 @@ void solver::test_basic_sign_lemma() {
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
lp::lar_term t;
t.add_coeff_var(lp_bde);
t.add_coeff_var(lp_acd);
t.add_var(lp_bde);
t.add_var(lp_acd);
ineq q(llc::EQ, t, rational(0));
nla.m_imp->print_lemma(std::cout << "expl & lemma: ");
nla.m_imp->print_lemma(lemma.back(), std::cout << "expl & lemma: ");
SASSERT(q == lemma[0].back());
ineq i0(llc::EQ, lp::lar_term(), rational(0));
i0.m_term.add_coeff_var(lp_bde);
i0.m_term.add_coeff_var(rational(1), lp_acd);
i0.m_term.add_var(lp_bde);
i0.m_term.add_var(lp_acd);
bool found = false;
for (const auto& k : lemma[0]){
if (k == i0) {
@ -2654,7 +2687,7 @@ void solver::test_order_lemma_params(bool var_equiv, int sign) {
if (var_equiv) { // make k equivalent to j
lp::lar_term t;
t.add_coeff_var(lp_k);
t.add_var(lp_k);
t.add_coeff_var(-rational(1), lp_j);
lpvar kj = s.add_term(t.coeffs_as_vector());
s.add_var_bound(kj, llc::LE, rational(0));
@ -2718,7 +2751,7 @@ void solver::test_order_lemma_params(bool var_equiv, int sign) {
// t.add_coeff_var(lp_acd);
// ineq q(llc::EQ, t, rational(0));
nla.m_imp->print_lemma(std::cout << "lemma: ");
nla.m_imp->print_lemma(lemma.back(), std::cout << "lemma: ");
// SASSERT(q == lemma.back());
// ineq i0(llc::EQ, lp::lar_term(), rational(0));
// i0.m_term.add_coeff_var(lp_bde);
@ -2796,7 +2829,7 @@ void solver::test_monotone_lemma() {
vector<lemma> lemma;
vector<lp::explanation> exp;
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
nla.m_imp->print_lemma(std::cout << "lemma: ");
nla.m_imp->print_lemma(lemma.back(), std::cout << "lemma: ");
}
void solver::test_tangent_lemma() {
@ -2833,7 +2866,7 @@ void solver::test_tangent_lemma() {
vector<lp::explanation> exp;
SASSERT(nla.m_imp->test_check(lemma, exp) == l_false);
nla.m_imp->print_lemma(std::cout << "lemma: ");
nla.m_imp->print_lemma(lemma.back(), std::cout << "lemma: ");
}
void solver::test_order_lemma() {