mirror of
https://github.com/Z3Prover/z3
synced 2025-07-20 11:22:04 +00:00
toward bound prop
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
parent
a3d9803fa5
commit
aa57ee7b62
1 changed files with 95 additions and 92 deletions
|
@ -461,6 +461,9 @@ namespace lp {
|
||||||
m_data.clear();
|
m_data.clear();
|
||||||
SASSERT(invariant());
|
SASSERT(invariant());
|
||||||
}
|
}
|
||||||
|
auto begin() const { return m_data.begin();}
|
||||||
|
auto end() const { return m_data.end(); }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// m_lspace is for operations on l_terms - m_e_matrix rows
|
// m_lspace is for operations on l_terms - m_e_matrix rows
|
||||||
|
@ -902,7 +905,7 @@ namespace lp {
|
||||||
TRACE("dioph_eq", print_entry(ei, tout) << std::endl;);
|
TRACE("dioph_eq", print_entry(ei, tout) << std::endl;);
|
||||||
mpq& c = m_sum_of_fixed[ei];
|
mpq& c = m_sum_of_fixed[ei];
|
||||||
c = mpq(0);
|
c = mpq(0);
|
||||||
open_l_term_to_work_vector(ei, c);
|
open_l_term_to_espace(ei, c);
|
||||||
clear_e_row(ei);
|
clear_e_row(ei);
|
||||||
mpq denom(1);
|
mpq denom(1);
|
||||||
for (const auto& p : m_espace.m_data) {
|
for (const auto& p : m_espace.m_data) {
|
||||||
|
@ -1202,7 +1205,7 @@ namespace lp {
|
||||||
void subs_qfront_by_fresh(unsigned k, protected_queue& q) {
|
void subs_qfront_by_fresh(unsigned k, protected_queue& q) {
|
||||||
const lar_term& e = m_fresh_k2xt_terms.get_by_key(k).first;
|
const lar_term& e = m_fresh_k2xt_terms.get_by_key(k).first;
|
||||||
TRACE("dioph_eq", tout << "k:" << k << ", in ";
|
TRACE("dioph_eq", tout << "k:" << k << ", in ";
|
||||||
print_term_o(create_term_from_subst_space(), tout) << std::endl;
|
print_term_o(create_term_from_espace(), tout) << std::endl;
|
||||||
tout << "subs with e:";
|
tout << "subs with e:";
|
||||||
print_lar_term_L(e, tout) << std::endl;);
|
print_lar_term_L(e, tout) << std::endl;);
|
||||||
mpq coeff = -m_espace[k]; // need to copy since it will be zeroed
|
mpq coeff = -m_espace[k]; // need to copy since it will be zeroed
|
||||||
|
@ -1221,7 +1224,7 @@ namespace lp {
|
||||||
}
|
}
|
||||||
// there is no change in m_l_matrix
|
// there is no change in m_l_matrix
|
||||||
TRACE("dioph_eq", tout << "after subs k:" << k << "\n";
|
TRACE("dioph_eq", tout << "after subs k:" << k << "\n";
|
||||||
print_term_o(create_term_from_subst_space(), tout) << std::endl;
|
print_term_o(create_term_from_espace(), tout) << std::endl;
|
||||||
tout << "m_term_with_index:{"; print_lar_term_L(m_lspace.m_data, tout);
|
tout << "m_term_with_index:{"; print_lar_term_L(m_lspace.m_data, tout);
|
||||||
tout << "}, opened:"; print_ml(m_lspace.to_term(), tout) << std::endl;);
|
tout << "}, opened:"; print_ml(m_lspace.to_term(), tout) << std::endl;);
|
||||||
}
|
}
|
||||||
|
@ -1235,7 +1238,7 @@ namespace lp {
|
||||||
void subs_qfront_by_S(unsigned k, protected_queue& q) {
|
void subs_qfront_by_S(unsigned k, protected_queue& q) {
|
||||||
const mpq& e = m_sum_of_fixed[m_k2s[k]];
|
const mpq& e = m_sum_of_fixed[m_k2s[k]];
|
||||||
TRACE("dioph_eq", tout << "k:" << k << ", in ";
|
TRACE("dioph_eq", tout << "k:" << k << ", in ";
|
||||||
print_term_o(create_term_from_subst_space(), tout) << std::endl;
|
print_term_o(create_term_from_espace(), tout) << std::endl;
|
||||||
tout << "subs with e:";
|
tout << "subs with e:";
|
||||||
print_entry(m_k2s[k], tout) << std::endl;);
|
print_entry(m_k2s[k], tout) << std::endl;);
|
||||||
mpq coeff = m_espace[k]; // need to copy since it will be zeroed
|
mpq coeff = m_espace[k]; // need to copy since it will be zeroed
|
||||||
|
@ -1264,7 +1267,7 @@ namespace lp {
|
||||||
m_c += coeff * e;
|
m_c += coeff * e;
|
||||||
add_l_row_to_term_with_index(coeff, sub_index(k));
|
add_l_row_to_term_with_index(coeff, sub_index(k));
|
||||||
TRACE("dioph_eq", tout << "after subs k:" << k << "\n";
|
TRACE("dioph_eq", tout << "after subs k:" << k << "\n";
|
||||||
print_term_o(create_term_from_subst_space(), tout) << std::endl;
|
print_term_o(create_term_from_espace(), tout) << std::endl;
|
||||||
tout << "m_term_with_index:{"; print_lar_term_L(m_lspace.to_term(), tout);
|
tout << "m_term_with_index:{"; print_lar_term_L(m_lspace.to_term(), tout);
|
||||||
tout << "}, opened:"; print_ml(m_lspace.to_term(), tout) << std::endl;);
|
tout << "}, opened:"; print_ml(m_lspace.to_term(), tout) << std::endl;);
|
||||||
}
|
}
|
||||||
|
@ -1339,6 +1342,14 @@ namespace lp {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool subs_invariant(const lar_term &term_to_tighten) const {
|
||||||
|
auto ls = term_to_lar_solver(remove_fresh_vars(create_term_from_espace()));
|
||||||
|
lar_term t0 = m_lspace.to_term();
|
||||||
|
lar_term t1 = open_ml(t0);
|
||||||
|
auto rs = fix_vars(term_to_tighten + t1);
|
||||||
|
return ls == rs;
|
||||||
|
}
|
||||||
|
|
||||||
void subs_with_S_and_fresh(protected_queue& q) {
|
void subs_with_S_and_fresh(protected_queue& q) {
|
||||||
while (!q.empty())
|
while (!q.empty())
|
||||||
subs_front_with_S_and_fresh(q);
|
subs_front_with_S_and_fresh(q);
|
||||||
|
@ -1421,7 +1432,7 @@ namespace lp {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
term_o create_term_from_subst_space() {
|
term_o create_term_from_espace() const {
|
||||||
term_o t;
|
term_o t;
|
||||||
for (const auto& p : m_espace.m_data) {
|
for (const auto& p : m_espace.m_data) {
|
||||||
t.add_monomial(p.coeff(), p.var());
|
t.add_monomial(p.coeff(), p.var());
|
||||||
|
@ -1451,31 +1462,71 @@ namespace lp {
|
||||||
return m_var_register.external_to_local(j);
|
return m_var_register.external_to_local(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we have m_espace and m_lspace filled with an lra_term and the variables are substituted by S and fresh
|
||||||
|
lia_move tighten_bounds_for_term_column_bp() {
|
||||||
|
return lia_move::undef;
|
||||||
|
std::cout << "tighten_bounds_for_term_column_bp\n";
|
||||||
|
remove_fresh_from_espace();
|
||||||
|
for (auto & p: m_espace.m_data) p.m_j = local_to_lar_solver(p.var()); // have to restore it for the cleanup to work
|
||||||
|
|
||||||
|
TRACE("dio",
|
||||||
|
tout << "m_espace:\n"; print_lar_term_L(m_espace.m_data, tout) << "+" << m_c << std::endl;
|
||||||
|
tout << "m_lspace:\n"; print_lar_term_L(m_lspace.m_data, tout) << std::endl;
|
||||||
|
for (const auto &p : m_espace.m_data) {
|
||||||
|
lra.print_column_info(p.var(), tout);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
m_prop_bounds.clear();
|
||||||
|
bound_analyzer_on_row<std_vector<iv>, dioph_eq::imp>::analyze_row(m_espace.m_data, impq(- m_c), *this);
|
||||||
|
lia_move r = lia_move::undef;
|
||||||
|
bool change = false;
|
||||||
|
u_dependency * fixed_dep = explain_fixed_in_meta_term(m_lspace.m_data); // not efficient : todo
|
||||||
|
for (auto& pb: m_prop_bounds) {
|
||||||
|
pb.m_dep = lra.join_deps(pb.m_dep, fixed_dep);
|
||||||
|
if (update_bound(pb)) {
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (change) {
|
||||||
|
auto st = lra.find_feasible_solution();
|
||||||
|
if (st == lp_status::INFEASIBLE) {
|
||||||
|
lra.get_infeasibility_explanation(m_infeas_explanation);
|
||||||
|
r = lia_move::conflict;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto & p: m_espace.m_data) p.m_j = lar_solver_to_local(p.var());
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
lia_move tighten_bounds_for_term_column(unsigned j) {
|
||||||
|
auto r = tighten_bounds_for_term_column_gcd(j);
|
||||||
|
if (r == lia_move::undef)
|
||||||
|
r = tighten_bounds_for_term_column_bp();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
// j is the index of the column representing a term
|
// j is the index of the column representing a term
|
||||||
// return true if a conflict was found
|
// return true if a conflict was found
|
||||||
lia_move tighten_bounds_for_term_column(unsigned j) {
|
lia_move tighten_bounds_for_term_column_gcd(unsigned j) {
|
||||||
term_o term_to_tighten = lra.get_term(j); // copy the term aside
|
term_o term_to_tighten = lra.get_term(j); // copy the term aside
|
||||||
|
|
||||||
SASSERT(get_extended_term_value(term_to_tighten).is_zero() && all_vars_are_int(term_to_tighten));
|
SASSERT(get_extended_term_value(term_to_tighten).is_zero() && all_vars_are_int(term_to_tighten));
|
||||||
// q is the queue of variables that can be substituted in term_to_tighten
|
// q is the queue of variables that can be substituted in term_to_tighten
|
||||||
protected_queue q;
|
protected_queue q;
|
||||||
TRACE("dio", tout << "j:" << j << ", t: "; print_lar_term_L(term_to_tighten, tout) << std::endl;);
|
TRACE("dio", tout << "j:" << j << " , intitial term t: "; print_lar_term_L(term_to_tighten, tout) << std::endl;);
|
||||||
init_substitutions(term_to_tighten, q);
|
init_substitutions(term_to_tighten, q);
|
||||||
if (q.empty())
|
if (q.empty()) // todo: maybe still go ahead and process it?
|
||||||
return lia_move::undef;
|
return lia_move::undef;
|
||||||
|
|
||||||
TRACE("dio", tout << "t:";
|
TRACE("dio", tout << "t:";
|
||||||
tout << "m_espace:";
|
tout << "m_espace:";
|
||||||
print_term_o(create_term_from_subst_space(), tout) << std::endl;
|
print_term_o(create_term_from_espace(), tout) << std::endl;
|
||||||
tout << "m_lspace:";
|
tout << "m_lspace:";
|
||||||
print_lar_term_L(m_lspace.to_term(), tout) << std::endl;);
|
print_lar_term_L(m_lspace.to_term(), tout) << std::endl;);
|
||||||
subs_with_S_and_fresh(q);
|
subs_with_S_and_fresh(q);
|
||||||
|
SASSERT(subs_invariant(term_to_tighten));
|
||||||
SASSERT(fix_vars(term_to_tighten + open_ml(m_lspace.to_term())) ==
|
|
||||||
term_to_lar_solver(remove_fresh_vars(create_term_from_subst_space())));
|
|
||||||
|
|
||||||
mpq g = gcd_of_coeffs(m_espace.m_data, true);
|
mpq g = gcd_of_coeffs(m_espace.m_data, true);
|
||||||
TRACE("dioph_eq", tout << "after process_q_with_S\nt:"; print_term_o(create_term_from_subst_space(), tout) << std::endl; tout << "g:" << g << std::endl;);
|
TRACE("dioph_eq", tout << "after process_q_with_S\nt:"; print_term_o(create_term_from_espace(), tout) << std::endl; tout << "g:" << g << std::endl;);
|
||||||
|
|
||||||
if (g.is_one())
|
if (g.is_one())
|
||||||
return lia_move::undef;
|
return lia_move::undef;
|
||||||
|
@ -1682,19 +1733,13 @@ namespace lp {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return true iff lar_solvre is feasible or cancelled
|
// return true iff the column bound has been changed
|
||||||
bool create_cut(const prop_bound& pb) {
|
bool update_bound(const prop_bound& pb) {
|
||||||
lra.update_column_type_and_bound(pb.m_j, get_bound_kind(pb), pb.m_bound, pb.m_dep);
|
lra.update_column_type_and_bound(pb.m_j, get_bound_kind(pb), pb.m_bound, pb.m_dep);
|
||||||
auto st = lra.find_feasible_solution();
|
if (lra.column_is_fixed(pb.m_j)) std::cout << "new fixed " << pb.m_j << "\n";
|
||||||
if ((int)st >= (int)(lp_status::FEASIBLE) || !lia.settings().get_cancel_flag())
|
return lra.columns_with_changed_bounds().contains(pb.m_j);
|
||||||
return true;
|
|
||||||
if (st == lp_status::INFEASIBLE) {
|
|
||||||
lra.get_infeasibility_explanation(m_infeas_explanation);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool row_has_int_inf(unsigned ei) {
|
bool row_has_int_inf(unsigned ei) {
|
||||||
for (const auto& p: m_e_matrix.m_rows[ei]) {
|
for (const auto& p: m_e_matrix.m_rows[ei]) {
|
||||||
unsigned j = local_to_lar_solver(p.var());
|
unsigned j = local_to_lar_solver(p.var());
|
||||||
|
@ -1703,55 +1748,8 @@ namespace lp {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int prop_calls = 0;
|
|
||||||
lia_move tighten_S_row(unsigned ei) {
|
|
||||||
if (!row_has_int_inf(ei)) return lia_move::undef;
|
|
||||||
// SASSERT(entry_invariant(ei));
|
|
||||||
m_espace.clear();
|
|
||||||
for (const auto& p: m_e_matrix.m_rows[ei]) {
|
|
||||||
m_espace.add(p.coeff(), p.var());
|
|
||||||
}
|
|
||||||
remove_fresh_from_espace();
|
|
||||||
std_vector<iv> row_in_lar_solver_indices;
|
|
||||||
for (const auto & p: m_espace.m_data) {
|
|
||||||
row_in_lar_solver_indices.push_back({p.coeff(), local_to_lar_solver(p.var())});
|
|
||||||
}
|
|
||||||
m_prop_bounds.clear();
|
|
||||||
bound_analyzer_on_row<std_vector<iv>, dioph_eq::imp>::analyze_row(row_in_lar_solver_indices, impq(- m_sum_of_fixed[ei]), *this);
|
|
||||||
for (auto& pb: m_prop_bounds) {
|
|
||||||
if (lra.settings().get_cancel_flag())
|
|
||||||
return lia_move::undef;
|
|
||||||
|
|
||||||
if (cut(pb) && lia.column_is_int_inf(pb.m_j)) {
|
|
||||||
pb.m_dep = lra.join_deps(pb.m_dep, explain_fixed_in_meta_term(m_l_matrix.m_rows[ei])); // todo; not efficient
|
|
||||||
TRACE("dio", tout << "cut on variable x" << pb.m_j << ", with " << (pb.m_is_low? "lower": "upper") << " bound:" << pb.m_bound << "\n"; tout << "row " << ei << " in lar indices:\n";
|
|
||||||
print_lar_term_L(row_in_lar_solver_indices, tout) << " + " << m_sum_of_fixed[ei] << "\n";
|
|
||||||
tout << "bounds:\n";
|
|
||||||
for (const auto& p: row_in_lar_solver_indices)
|
|
||||||
lra.print_column_info(p.var(), tout););
|
|
||||||
if (!create_cut(pb))
|
|
||||||
return lia_move::conflict;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lia_move::undef;
|
|
||||||
}
|
|
||||||
|
|
||||||
lia_move propagate_bounds_on_tightened_columns() {
|
|
||||||
TRACE("dio", print_int_inf_vars(tout); print_S(tout););
|
|
||||||
std::unordered_set<unsigned> rows;
|
|
||||||
for (unsigned tcol : m_tightened_columns) {
|
|
||||||
for (const auto& p: m_e_matrix.m_columns[lar_solver_to_local(tcol)] ) {
|
|
||||||
if (lra.settings().get_cancel_flag())
|
|
||||||
return lia_move::undef;
|
|
||||||
if (contains(rows, p.var())) continue;
|
|
||||||
rows.insert(p.var());
|
|
||||||
lia_move r = tighten_S_row(p.var());
|
|
||||||
if (r == lia_move::conflict)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lia_move::undef;
|
|
||||||
}
|
|
||||||
// m_espace contains the coefficients of the term
|
// m_espace contains the coefficients of the term
|
||||||
// m_c contains the fixed part of the term
|
// m_c contains the fixed part of the term
|
||||||
// m_tmp_l is the linear combination of the equations that removes the
|
// m_tmp_l is the linear combination of the equations that removes the
|
||||||
|
@ -1818,15 +1816,15 @@ namespace lp {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
u_dependency* explain_fixed_in_meta_term(const T& t) {
|
u_dependency* explain_fixed_in_meta_term(const T& t) {
|
||||||
return explain_fixed(open_ml(t));
|
return explain_fixed(open_fixed_from_ml(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
u_dependency* explain_fixed(const lar_term& t) {
|
template <typename T>
|
||||||
|
u_dependency* explain_fixed(const T& t) {
|
||||||
u_dependency* dep = nullptr;
|
u_dependency* dep = nullptr;
|
||||||
for (const auto& p : t) {
|
for (const auto& p : t) {
|
||||||
if (is_fixed(p.j())) {
|
if (is_fixed(p.var())) {
|
||||||
u_dependency* bound_dep =
|
u_dependency* bound_dep = lra.get_bound_constraint_witnesses_for_column(p.var());
|
||||||
lra.get_bound_constraint_witnesses_for_column(p.j());
|
|
||||||
dep = lra.join_deps(dep, bound_dep);
|
dep = lra.join_deps(dep, bound_dep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1875,17 +1873,8 @@ namespace lp {
|
||||||
return ret;
|
return ret;
|
||||||
TRACE("dio", print_S(tout););
|
TRACE("dio", print_S(tout););
|
||||||
ret = tighten_terms_with_S();
|
ret = tighten_terms_with_S();
|
||||||
if (ret == lia_move::conflict) {
|
if (ret == lia_move::conflict)
|
||||||
lra.stats().m_dio_tighten_conflicts++;
|
lra.stats().m_dio_tighten_conflicts++;
|
||||||
return lia_move::conflict;
|
|
||||||
}
|
|
||||||
if (ret == lia_move::undef) {
|
|
||||||
TRACE("dio", print_int_inf_vars(tout); print_S(tout););
|
|
||||||
ret = propagate_bounds_on_tightened_columns();
|
|
||||||
if (ret == lia_move::conflict)
|
|
||||||
lra.stats().m_dio_bound_propagation_conflicts++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2392,7 +2381,7 @@ namespace lp {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
term_o term_to_lar_solver(const term_o& eterm) const {
|
term_o term_to_lar_solver(const term_o& eterm) const {
|
||||||
term_o ret;
|
term_o ret;
|
||||||
for (const auto& p : eterm) {
|
for (const auto& p : eterm) {
|
||||||
|
@ -2470,6 +2459,20 @@ namespace lp {
|
||||||
return print_lar_term_L(opened_ml, out);
|
return print_lar_term_L(opened_ml, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// collect only fixed variables
|
||||||
|
template <typename T>
|
||||||
|
term_with_index open_fixed_from_ml(const T& ml) {
|
||||||
|
term_with_index r;
|
||||||
|
for (const auto& v : ml) {
|
||||||
|
for (const auto & p : lra.get_term(v.var()).ext_coeffs()) {
|
||||||
|
if (lra.column_is_fixed(p.var()))
|
||||||
|
r.add(p.coeff(), p.var());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
term_o open_ml(const T& ml) const {
|
term_o open_ml(const T& ml) const {
|
||||||
term_o r;
|
term_o r;
|
||||||
|
@ -2479,7 +2482,7 @@ namespace lp {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_l_term_to_work_vector(unsigned ei, mpq& c) {
|
void open_l_term_to_espace(unsigned ei, mpq& c) {
|
||||||
m_espace.clear();
|
m_espace.clear();
|
||||||
for (const auto& p : m_l_matrix.m_rows[ei]) {
|
for (const auto& p : m_l_matrix.m_rows[ei]) {
|
||||||
const lar_term& t = lra.get_term(p.var());
|
const lar_term& t = lra.get_term(p.var());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue