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

stronger lemmas to avoid branching

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
Lev Nachmanson 2019-02-14 15:44:02 -08:00
parent 580ebead79
commit 63e62ec1bb
8 changed files with 156 additions and 62 deletions

View file

@ -1974,7 +1974,7 @@ public:
expr_ref fml(m);
expr_ref_vector ts(m);
rational rhs = c.m_right_side;
for (auto cv : c.get_left_side_coefficients()) {
for (auto cv : c.coeffs()) {
ts.push_back(multerm(cv.first, var2expr(cv.second)));
}
switch (c.m_kind) {

View file

@ -48,7 +48,7 @@ inline std::string lconstraint_kind_string(lconstraint_kind t) {
struct lar_base_constraint {
lconstraint_kind m_kind;
mpq m_right_side;
virtual vector<std::pair<mpq, var_index>> get_left_side_coefficients() const = 0;
virtual vector<std::pair<mpq, var_index>> coeffs() const = 0;
lar_base_constraint() {}
lar_base_constraint(lconstraint_kind kind, const mpq& right_side) :m_kind(kind), m_right_side(right_side) {}
@ -59,7 +59,7 @@ struct lar_base_constraint {
struct lar_var_constraint: public lar_base_constraint {
unsigned m_j;
vector<std::pair<mpq, var_index>> get_left_side_coefficients() const override {
vector<std::pair<mpq, var_index>> coeffs() const override {
vector<std::pair<mpq, var_index>> ret;
ret.push_back(std::make_pair(one_of_type<mpq>(), m_j));
return ret;
@ -71,7 +71,7 @@ struct lar_var_constraint: public lar_base_constraint {
struct lar_term_constraint: public lar_base_constraint {
const lar_term * m_term;
vector<std::pair<mpq, var_index>> get_left_side_coefficients() const override {
vector<std::pair<mpq, var_index>> coeffs() const override {
return m_term->coeffs_as_vector();
}
unsigned size() const override { return m_term->size();}
@ -95,6 +95,6 @@ public:
return static_cast<unsigned>(m_coeffs.size());
}
vector<std::pair<mpq, var_index>> get_left_side_coefficients() const override { return m_coeffs; }
vector<std::pair<mpq, var_index>> coeffs() const override { return m_coeffs; }
};
}

View file

@ -1067,7 +1067,7 @@ bool lar_solver::the_relations_are_of_same_type(const vector<std::pair<mpq, unsi
}
void lar_solver::register_in_map(std::unordered_map<var_index, mpq> & coeffs, const lar_base_constraint & cn, const mpq & a) {
for (auto & it : cn.get_left_side_coefficients()) {
for (auto & it : cn.coeffs()) {
unsigned j = it.second;
auto p = coeffs.find(j);
if (p == coeffs.end())
@ -1332,7 +1332,7 @@ std::ostream& lar_solver::print_terms(std::ostream& out) const {
}
std::ostream& lar_solver::print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) const {
print_linear_combination_of_column_indices(c->get_left_side_coefficients(), out);
print_linear_combination_of_column_indices(c->coeffs(), out);
mpq free_coeff = c->get_free_coeff_of_left_side();
if (!is_zero(free_coeff))
out << " + " << free_coeff;
@ -1371,7 +1371,7 @@ std::ostream& lar_solver::print_term_as_indices(lar_term const& term, std::ostre
mpq lar_solver::get_left_side_val(const lar_base_constraint & cns, const std::unordered_map<var_index, mpq> & var_map) const {
mpq ret = cns.get_free_coeff_of_left_side();
for (auto & it : cns.get_left_side_coefficients()) {
for (auto & it : cns.coeffs()) {
var_index j = it.second;
auto vi = var_map.find(j);
lp_assert(vi != var_map.end());

View file

@ -598,6 +598,10 @@ public:
}
}
std::ostream& print_column_info(unsigned j, std::ostream& out) const {
return m_mpq_lar_core_solver.m_r_solver.print_column_info(j, out);
}
bool has_int_var() const;
bool has_inf_int() const {
for (unsigned j = 0; j < column_count(); j++) {

View file

@ -108,6 +108,7 @@ struct stats {
unsigned m_patches_success;
unsigned m_hnf_cutter_calls;
unsigned m_hnf_cuts;
unsigned m_nla_calls;
stats() { reset(); }
void reset() { memset(this, 0, sizeof(*this)); }
};

View file

@ -396,7 +396,7 @@ struct solver::imp {
for (const auto& p : t) {
rational pb;
if (explain_coeff_upper_bound(p, pb, e)) {
b += pb;
b += pb;
} else {
e.clear();
return false;
@ -413,7 +413,7 @@ struct solver::imp {
for (const auto& p : t) {
rational pb;
if (explain_coeff_lower_bound(p, pb, e)) {
b += pb;
b += pb;
} else {
e.clear();
return false;
@ -438,7 +438,7 @@ struct solver::imp {
e.add(c);
return true;
}
// a.is_neg()
// a.is_neg()
c = m_lar_solver.get_column_upper_bound_witness(p.var());
if (c + 1 == 0)
return false;
@ -459,7 +459,7 @@ struct solver::imp {
e.add(c);
return true;
}
// a.is_pos()
// a.is_pos()
c = m_lar_solver.get_column_upper_bound_witness(p.var());
if (c + 1 == 0)
return false;
@ -495,6 +495,7 @@ struct solver::imp {
break;
case llc::NE:
r = explain_lower_bound(t, rs + rational(1), exp) || explain_upper_bound(t, rs - rational(1), exp);
CTRACE("nla_solver", r, tout << "ineq:"; print_ineq(ineq(cmp, t, rs), tout); print_explanation(exp, tout << ", "););
break;
default:
SASSERT(false);
@ -510,7 +511,6 @@ struct solver::imp {
void mk_ineq(lp::lar_term& t, llc cmp, const rational& rs, lemma& l) {
TRACE("nla_solver", m_lar_solver.print_term(t, tout << "t = "););
if (explain_ineq(t, cmp, rs)) {
TRACE("nla_solver", tout << "explained\n";);
return;
}
m_lar_solver.subs_term_columns(t);
@ -710,6 +710,7 @@ struct solver::imp {
// abs_vars_key is formed by m_vars_equivalence.get_abs_root_for_var(k), where
// 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
@ -776,29 +777,50 @@ struct solver::imp {
return sign;
}
void generate_zero_lemma(const monomial& m) {
unsigned zero_j = -1;
for (unsigned j : m.vars()){
if (vvr(j).is_zero()){
zero_j = j;
break;
}
}
SASSERT(zero_j + 1);
mk_ineq(zero_j, llc::NE, m_lemma_vec->back());
mk_ineq(m.var(), llc::EQ, m_lemma_vec->back());
void negate_strict_sign(lpvar j) {
SASSERT(!vvr(j).is_zero());
mk_ineq(j, (rat_sign(vvr(j)) == 1? llc::LE : llc::GE), current_lemma());
}
// we know here that the value one of the vars of each monomial is zero
// so the value of each monomial has to be zero
bool sign_lemma_for_zero_on_list(const unsigned_vector& mon_list) {
for (unsigned i : mon_list) {
if (!vvr(m_monomials[i]).is_zero()) {
generate_zero_lemma(m_monomials[i]);
return true;
void generate_strict_case_zero_lemma(const monomial& m, unsigned zero_j, int sign_of_zj) {
// we know all the signs
for (unsigned j : m){
if (j == zero_j) {
mk_ineq(j, (sign_of_zj == 1? llc::GT : llc::LT), current_lemma());
}
else {
negate_strict_sign(j);
}
}
return false;
negate_strict_sign(m.var());
}
void generate_zero_lemma(const monomial& m) {
SASSERT(!vvr(m).is_zero());
int sign = rat_sign(vvr(m));
unsigned zero_j = -1;
for (unsigned j : m){
const rational & v = vvr(j);
if (v.is_zero()){
if (zero_j + 1 == 0) {
zero_j = j;
} else {
sign = 0;
break;
}
} else {
sign *= rat_sign(v);
}
}
TRACE("nla_solver", tout << "sign = " << sign << "\n";);
SASSERT(zero_j + 1);
if (sign == 0) {
mk_ineq(zero_j, llc::NE, current_lemma());
mk_ineq(m.var(), llc::EQ, current_lemma());
} else {
generate_strict_case_zero_lemma(m, zero_j, sign);
}
}
rational rat_sign(const monomial& m) const {
@ -967,19 +989,14 @@ struct solver::imp {
}
std::ostream & print_var(lpvar j, std::ostream & out) const {
bool is_monomial = false;
out << "[" << j << "] = ";
for (const monomial & m : m_monomials) {
if (j == m.var()) {
is_monomial = true;
print_monomial(m, out);
out << " = " << vvr(j);;
break;
}
auto it = m_var_to_its_monomial.find(j);
if (it != m_var_to_its_monomial.end()) {
print_monomial(m_monomials[it->second], out);
out << " = " << vvr(j);;
}
if (!is_monomial)
out << m_lar_solver.get_variable_name(j) << " = " << vvr(j);
out <<";";
m_lar_solver.print_column_info(j, out) <<";";
return out;
}
@ -1060,7 +1077,7 @@ struct solver::imp {
add_empty_lemma();
if (derived)
mk_ineq(var(rm), llc::NE, current_lemma());
mk_ineq(var(rm), llc::NE, current_lemma());
for (auto j : f) {
mk_ineq(var(j), llc::EQ, current_lemma());
}
@ -1585,7 +1602,11 @@ struct solver::imp {
m_rm_table.init_to_refine(ref);
}
unsigned random() {return m_lar_solver.settings().random_next();}
lp::lp_settings& settings() {
return m_lar_solver.settings();
}
unsigned random() {return settings().random_next();}
// use basic multiplication properties to create a lemma
bool basic_lemma(bool derived) {
@ -1683,7 +1704,7 @@ struct solver::imp {
m_vars_equivalence.create_tree();
TRACE("nla_solver", tout << "number of equivs = " << m_vars_equivalence.size(););
SASSERT((m_lar_solver.settings().random_next() % 100) || tables_are_ok());
SASSERT((settings().random_next() % 100) || tables_are_ok());
}
bool vars_table_is_ok() const {
@ -1755,6 +1776,27 @@ struct solver::imp {
}
out << "\n}";
}
void print_monomial_stats(const monomial& m, std::ostream& out) {
if (m.size() == 2) return;
monomial_coeff mc = canonize_monomial(m);
for(unsigned i = 0; i < mc.vars().size(); i++){
if (abs(vvr(mc.vars()[i])) == rational(1)) {
auto vv = mc.vars();
vv.erase(vv.begin()+i);
auto it = m_rm_table.map().find(vv);
if (it == m_rm_table.map().end()) {
out << "nf length" << vv.size() << "\n"; ;
}
}
}
}
void print_stats(std::ostream& out) {
// for (const auto& m : m_monomials)
// print_monomial_stats(m, out);
m_rm_table.print_stats(out);
}
void register_monomials_in_tables() {
for (unsigned i = 0; i < m_monomials.size(); i++)
@ -1762,6 +1804,7 @@ struct solver::imp {
m_rm_table.fill_rooted_monomials_containing_var();
m_rm_table.fill_proper_factors();
TRACE("nla_solver", print_stats(tout););
}
void clear() {
@ -1866,9 +1909,42 @@ struct solver::imp {
TRACE("nla_solver", print_lemma(tout););
}
std::unordered_set<lpvar> collect_vars( const lemma& l) {
std::unordered_set<lpvar> vars;
for (const auto& i : current_lemma().ineqs()) {
for (const auto& p : i.term()) {
lpvar j = p.var();
vars.insert(j);
auto it = m_var_to_its_monomial.find(j);
if (it != m_var_to_its_monomial.end()) {
for (lpvar k : m_monomials[it->second])
vars.insert(k);
}
}
}
for (const auto& p : current_expl()) {
const auto& c = m_lar_solver.get_constraint(p.second);
for (const auto& r : c.coeffs()) {
lpvar j = r.second;
vars.insert(j);
auto it = m_var_to_its_monomial.find(j);
if (it != m_var_to_its_monomial.end()) {
for (lpvar k : m_monomials[it->second])
vars.insert(k);
}
}
}
return vars;
}
void print_lemma(std::ostream& out) {
print_ineqs(current_lemma(), out);
print_explanation(current_expl(), out);
std::unordered_set<lpvar> vars = collect_vars(current_lemma());
for (lpvar j : vars) {
print_var(j, out);
}
}
bool get_cd_signs_for_ol(const rational& c, const rational& d, int& c_sign, int & d_sign) const {
@ -2147,8 +2223,8 @@ struct solver::imp {
bool uniform_le(const std::vector<rational>& a,
const std::vector<rational>& b,
unsigned & strict_i) const {
const std::vector<rational>& b,
unsigned & strict_i) const {
SASSERT(a.size() == b.size());
strict_i = -1;
bool z_b = false;
@ -2176,11 +2252,11 @@ struct solver::imp {
}
std::sort(r.begin(), r.end(), [](const std::pair<rational, lpvar>& a,
const std::pair<rational, lpvar>& b) {
return
a.first < b.first ||
(a.first == b.first &&
a.second < b.second);
});
return
a.first < b.first ||
(a.first == b.first &&
a.second < b.second);
});
return r;
}
@ -2503,7 +2579,7 @@ struct solver::imp {
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();
lemma& l = current_lemma();
negate_relation(jx, a, l);
negate_relation(jy, b, l);
// If "below" holds then ay + bx - ab < xy, otherwise ay + bx - ab > xy,
@ -2634,7 +2710,8 @@ struct solver::imp {
lbool check(vector<lemma>& l_vec) {
TRACE("nla_solver", tout << "check of nla";);
settings().st().m_nla_calls++;
TRACE("nla_solver", tout << "calls = " << settings().st().m_nla_calls << "\n";);
m_lemma_vec = &l_vec;
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";);
@ -2646,13 +2723,13 @@ struct solver::imp {
return l_true;
}
init_search();
lbool ret = inner_check(false);
// if (ret == l_undef)
// ret = inner_check(false);
lbool ret = inner_check(true);
if (ret == l_undef)
ret = inner_check(false);
TRACE("nla_solver", tout << "ret = " << ret;);
TRACE("nla_solver_c", tout << "ret = " << ret;);
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););
CTRACE("nla_solver_c", ret == l_undef, tout << "Monomials\n"; print_monomials(tout););
SASSERT(ret != l_false || no_lemmas_hold());
return ret;
}

View file

@ -157,7 +157,7 @@ typedef nla::variable_map_type variable_map_type;
auto& pm = m_nlsat->pm();
auto k = c.m_kind;
auto rhs = c.m_right_side;
auto lhs = c.get_left_side_coefficients();
auto lhs = c.coeffs();
auto sz = lhs.size();
svector<polynomial::var> vars;
rational den = denominator(rhs);

View file

@ -73,7 +73,19 @@ struct rooted_mon_table {
svector<unsigned> m_to_refine;
// maps the indices of the regular monomials to the rooted monomial indices
std::unordered_map<unsigned, index_with_sign> m_reg_to_rm;
void print_stats(std::ostream& out) const {
static double ratio = 1;
double s = 0;
for (const auto& p : m_map) {
s += m_vector[p.second].m_mons.size();
}
double r = s /m_map.size();
if (r > ratio) {
ratio = r;
out << "rooted mons " << m_map.size() << ", ratio = " << r << "\n";
}
}
const svector<unsigned>& to_refine() { return m_to_refine; }