Skip to content

Commit

Permalink
toward bound prop
Browse files Browse the repository at this point in the history
Signed-off-by: Lev Nachmanson <[email protected]>
  • Loading branch information
levnach committed Mar 1, 2025
1 parent a3d9803 commit aa57ee7
Showing 1 changed file with 95 additions and 92 deletions.
187 changes: 95 additions & 92 deletions src/math/lp/dioph_eq.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,9 @@ namespace lp {
m_data.clear();
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
Expand Down Expand Up @@ -902,7 +905,7 @@ namespace lp {
TRACE("dioph_eq", print_entry(ei, tout) << std::endl;);
mpq& c = m_sum_of_fixed[ei];
c = mpq(0);
open_l_term_to_work_vector(ei, c);
open_l_term_to_espace(ei, c);
clear_e_row(ei);
mpq denom(1);
for (const auto& p : m_espace.m_data) {
Expand Down Expand Up @@ -1202,7 +1205,7 @@ namespace lp {
void subs_qfront_by_fresh(unsigned k, protected_queue& q) {
const lar_term& e = m_fresh_k2xt_terms.get_by_key(k).first;
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:";
print_lar_term_L(e, tout) << std::endl;);
mpq coeff = -m_espace[k]; // need to copy since it will be zeroed
Expand All @@ -1221,7 +1224,7 @@ namespace lp {
}
// there is no change in m_l_matrix
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 << "}, opened:"; print_ml(m_lspace.to_term(), tout) << std::endl;);
}
Expand All @@ -1235,7 +1238,7 @@ namespace lp {
void subs_qfront_by_S(unsigned k, protected_queue& q) {
const mpq& e = m_sum_of_fixed[m_k2s[k]];
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:";
print_entry(m_k2s[k], tout) << std::endl;);
mpq coeff = m_espace[k]; // need to copy since it will be zeroed
Expand Down Expand Up @@ -1264,7 +1267,7 @@ namespace lp {
m_c += coeff * e;
add_l_row_to_term_with_index(coeff, sub_index(k));
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 << "}, opened:"; print_ml(m_lspace.to_term(), tout) << std::endl;);
}
Expand Down Expand Up @@ -1339,6 +1342,14 @@ namespace lp {
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) {
while (!q.empty())
subs_front_with_S_and_fresh(q);
Expand Down Expand Up @@ -1421,7 +1432,7 @@ namespace lp {
}
#endif

term_o create_term_from_subst_space() {
term_o create_term_from_espace() const {
term_o t;
for (const auto& p : m_espace.m_data) {
t.add_monomial(p.coeff(), p.var());
Expand Down Expand Up @@ -1451,31 +1462,71 @@ namespace lp {
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
// 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

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
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);
if (q.empty())
if (q.empty()) // todo: maybe still go ahead and process it?
return lia_move::undef;

TRACE("dio", tout << "t:";
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:";
print_lar_term_L(m_lspace.to_term(), tout) << std::endl;);
subs_with_S_and_fresh(q);

SASSERT(fix_vars(term_to_tighten + open_ml(m_lspace.to_term())) ==
term_to_lar_solver(remove_fresh_vars(create_term_from_subst_space())));

subs_with_S_and_fresh(q);
SASSERT(subs_invariant(term_to_tighten));
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())
return lia_move::undef;
Expand Down Expand Up @@ -1682,19 +1733,13 @@ namespace lp {
return out;
}

// return true iff lar_solvre is feasible or cancelled
bool create_cut(const prop_bound& pb) {
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 ((int)st >= (int)(lp_status::FEASIBLE) || !lia.settings().get_cancel_flag())
return true;
if (st == lp_status::INFEASIBLE) {
lra.get_infeasibility_explanation(m_infeas_explanation);
return false;
}
return true;
// return true iff the column bound has been changed
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);
if (lra.column_is_fixed(pb.m_j)) std::cout << "new fixed " << pb.m_j << "\n";
return lra.columns_with_changed_bounds().contains(pb.m_j);
}

bool row_has_int_inf(unsigned ei) {
for (const auto& p: m_e_matrix.m_rows[ei]) {
unsigned j = local_to_lar_solver(p.var());
Expand All @@ -1703,55 +1748,8 @@ namespace lp {
}
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_c contains the fixed part of the term
// m_tmp_l is the linear combination of the equations that removes the
Expand Down Expand Up @@ -1818,15 +1816,15 @@ namespace lp {

template <typename 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;
for (const auto& p : t) {
if (is_fixed(p.j())) {
u_dependency* bound_dep =
lra.get_bound_constraint_witnesses_for_column(p.j());
if (is_fixed(p.var())) {
u_dependency* bound_dep = lra.get_bound_constraint_witnesses_for_column(p.var());
dep = lra.join_deps(dep, bound_dep);
}
}
Expand Down Expand Up @@ -1875,17 +1873,8 @@ namespace lp {
return ret;
TRACE("dio", print_S(tout););
ret = tighten_terms_with_S();
if (ret == lia_move::conflict) {
if (ret == lia_move::conflict)
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;
}

Expand Down Expand Up @@ -2392,7 +2381,7 @@ namespace lp {
}
return true;
}

term_o term_to_lar_solver(const term_o& eterm) const {
term_o ret;
for (const auto& p : eterm) {
Expand Down Expand Up @@ -2470,6 +2459,20 @@ namespace lp {
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>
term_o open_ml(const T& ml) const {
term_o r;
Expand All @@ -2479,7 +2482,7 @@ namespace lp {
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();
for (const auto& p : m_l_matrix.m_rows[ei]) {
const lar_term& t = lra.get_term(p.var());
Expand Down

0 comments on commit aa57ee7

Please sign in to comment.