3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-02 12:21:21 +00:00

remove the fresh definition when removing its column

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
Lev Nachmanson 2025-02-06 16:50:24 -10:00 committed by Lev Nachmanson
parent 17d68c18aa
commit dcd5783232

View file

@ -46,7 +46,8 @@
the i-th entry.
*/
namespace lp {
template <typename T, typename K> bool contains(const T& t, K j) {
template <typename T, typename K>
bool contains(const T& t, K j) {
return t.find(j) != t.end();
}
@ -54,8 +55,8 @@ namespace lp {
mpq m_coeff;
unsigned m_j;
lpvar var() const { return m_j; }
const mpq & coeff() const { return m_coeff; }
mpq & coeff() { return m_coeff; }
const mpq& coeff() const { return m_coeff; }
mpq& coeff() { return m_coeff; }
iv() {}
iv(const mpq& v, unsigned j) : m_coeff(v), m_j(j) {}
};
@ -75,7 +76,7 @@ namespace lp {
return m_rev_map.find(b)->second;
}
unsigned size() const {return static_cast<unsigned>(m_map.size());}
unsigned size() const { return static_cast<unsigned>(m_map.size()); }
void erase_val(unsigned b) {
VERIFY(contains(m_rev_map, b) && contains(m_map, m_rev_map[b]));
@ -132,14 +133,12 @@ namespace lp {
}
};
template<typename T>
class bij_map {
template <typename T>
struct bij_map {
// We store T indexed by 'b' in an std::unordered_map, and use bijection to map from 'a' to 'b'.
bijection m_bij;
std::unordered_map<unsigned, T> m_data;
public:
// Adds a->b in m_bij, associates val with b.
void add(unsigned a, unsigned b, const T& val) {
// You might have some method in bijection such as 'insert(a, b)'
@ -155,7 +154,7 @@ namespace lp {
}
void erase_by_second_key(unsigned b) {
VERIFY(m_bij.has_val(b));
SASSERT(m_bij.has_val(b));
m_bij.erase_val(b);
auto it = m_data.find(b);
VERIFY(it != m_data.end());
@ -163,7 +162,7 @@ namespace lp {
}
bool has_key(unsigned j) const { return m_bij.has_key(j); }
bool has_second_key(unsigned j) const { return m_bij.has_val(j);}
bool has_second_key(unsigned j) const { return m_bij.has_val(j); }
// Get the data by 'a', look up b in m_bij, then read from m_data
const T& get_by_key(unsigned a) const {
unsigned b = m_bij[a]; // relies on operator[](unsigned) from bijection
@ -246,7 +245,7 @@ namespace lp {
std::ostream& print_S(std::ostream& out) {
out << "S:\n";
for (const auto & p: m_k2s.m_map) {
for (const auto& p : m_k2s.m_map) {
print_entry(p.second, out);
}
return out;
@ -258,11 +257,10 @@ namespace lp {
[](int j) -> std::string { return "x" + std::to_string(j); }, out);
}
// used for debug only
std::ostream& print_lar_term_L(const std_vector<iv>& t, std::ostream& out) const {
vector<std::pair<mpq, unsigned>> tp;
for (const auto & p : t) {
for (const auto& p : t) {
tp.push_back(std::make_pair(p.coeff(), p.var()));
}
return print_linear_combination_customized(
@ -343,7 +341,7 @@ namespace lp {
// used for debug only
lar_term to_term() const {
lar_term r;
for (const auto& p: m_data) {
for (const auto& p : m_data) {
r.add_monomial(p.coeff(), p.var());
}
return r;
@ -384,7 +382,7 @@ namespace lp {
int idx = m_index[j];
if (idx == -1) {
// Insert a new monomial { a, j } into m_data
m_data.push_back({ a, j });
m_data.push_back({a, j});
m_index[j] = static_cast<int>(m_data.size() - 1);
} else {
// Accumulate the coefficient
@ -417,8 +415,7 @@ namespace lp {
return false;
}
}
}
else {
} else {
// Check that var() in m_data[idx] matches j
if (idx < 0 || static_cast<unsigned>(idx) >= m_data.size()) {
return false;
@ -446,20 +443,19 @@ namespace lp {
return true;
}
void clear() {
for (const auto& p: m_data) {
for (const auto& p : m_data) {
m_index[p.var()] = -1;
}
m_data.clear();
SASSERT(invariant());
}
};
term_with_index m_l_terms_workspace;
term_with_index m_substitution_workspace;
bijection m_k2s;
bij_map<lar_term> m_fresh_k2xt_terms;
bij_map<std::pair<lar_term, unsigned>> m_fresh_k2xt_terms;
// m_row2fresh_defs[i] is the set of all fresh variables xt
// such that pairs (xt, m_fresh_k2xt_terms[xt]) is a fresh definition introduced for row i
// When row i is changed all entries depending on m_fresh_k2xt_terms[xt] should be recalculated,
@ -472,7 +468,6 @@ namespace lp {
// m_column_to_terms[j] is the set of all k such lra.get_term(k) depends on j
std::unordered_map<unsigned, std::unordered_set<unsigned>> m_columns_to_terms;
unsigned m_conflict_index = -1; // the row index of the conflict
unsigned m_max_of_branching_iterations = 0;
unsigned m_number_of_branching_calls;
@ -513,13 +508,13 @@ namespace lp {
}
};
void undo_add_term_method(const lar_term *t) {
TRACE("d_undo", tout << "t:"<< t<<", t->j():"<< t->j() << std::endl;);
void undo_add_term_method(const lar_term* t) {
TRACE("d_undo", tout << "t:" << t << ", t->j():" << t->j() << std::endl;);
TRACE("dioph_eq", lra.print_term(*t, tout); tout << ", t->j() =" << t->j() << std::endl;);
if (!contains(m_active_terms, t)) {
for (int i = static_cast<int>(m_added_terms.size() - 1); i >= 0; --i) {
if (m_added_terms[i] != t) continue;
if ((unsigned)i != m_added_terms.size() -1)
if ((unsigned)i != m_added_terms.size() - 1)
m_added_terms[i] = m_added_terms.back();
m_added_terms.pop_back();
break; // all is done since the term has not made it to m_active_terms
@ -527,8 +522,8 @@ namespace lp {
return;
}
// deregister the term that has been activated
for (const auto & p: t->ext_coeffs()) {
TRACE("dio_reg", tout << "derigister p.var():" << p.var() <<"->" << t->j() << std::endl; );
for (const auto& p : t->ext_coeffs()) {
TRACE("dio_reg", tout << "derigister p.var():" << p.var() << "->" << t->j() << std::endl;);
auto it = m_columns_to_terms.find(p.var());
SASSERT(it != m_columns_to_terms.end());
it->second.erase(t->j());
@ -539,22 +534,14 @@ namespace lp {
SASSERT(std::find(m_added_terms.begin(), m_added_terms.end(), t) == m_added_terms.end());
SASSERT(contains(m_active_terms, t));
m_active_terms.erase(t);
TRACE("dioph_eq",
tout << "the deleted term column in m_l_matrix" << std::endl;
for (auto p: m_l_matrix.column(t->j())) {
tout << "p.coeff():" << p.coeff()<< ", row " << p.var() << std::endl;
}
tout << "m_l_matrix has " << m_l_matrix.column_count() << " columns"<< std::endl;
tout << "and " << m_l_matrix.row_count() << " rows" << std::endl;
print_lar_term_L(*t, tout); tout << "; t->j()=" << t->j() << std::endl;
);
TRACE("dioph_eq", tout << "the deleted term column in m_l_matrix" << std::endl; for (auto p : m_l_matrix.column(t->j())) { tout << "p.coeff():" << p.coeff() << ", row " << p.var() << std::endl; } tout << "m_l_matrix has " << m_l_matrix.column_count() << " columns" << std::endl; tout << "and " << m_l_matrix.row_count() << " rows" << std::endl; print_lar_term_L(*t, tout); tout << "; t->j()=" << t->j() << std::endl;);
shrink_matrices();
}
struct undo_add_term : public trail {
imp& m_s;
const lar_term* m_t;
undo_add_term(imp& s, const lar_term *t): m_s(s), m_t(t) {}
undo_add_term(imp& s, const lar_term* t) : m_s(s), m_t(t) {}
void undo() {
m_s.undo_add_term_method(m_t);
@ -569,7 +556,7 @@ namespace lp {
}
unsigned size() const {
return m_q.size();
return (unsigned)m_q.size();
}
void push(unsigned j) {
@ -591,7 +578,7 @@ namespace lp {
imp& m_imp;
unsigned m_j; // the column that has been added
const mpq m_fixed_val;
undo_fixed_column(imp& s, unsigned j) : m_imp(s), m_j(j) , m_fixed_val(s.lra.get_lower_bound(j).x) {
undo_fixed_column(imp& s, unsigned j) : m_imp(s), m_j(j), m_fixed_val(s.lra.get_lower_bound(j).x) {
SASSERT(s.lra.column_is_fixed(j));
}
@ -613,18 +600,18 @@ namespace lp {
// change only the rows in m_l_matrix, and update m_e_matrix lazily
unsigned j = m_l_matrix.column_count() - 1;
make_sure_j_is_in_the_last_row_of_l_matrix();
const auto &last_e_row = m_l_matrix.m_rows.back();
const auto& last_e_row = m_l_matrix.m_rows.back();
mpq alpha;
for (const auto& p: last_e_row) {
for (const auto& p : last_e_row) {
if (p.var() == j) {
alpha = p.coeff();
break;
}
}
unsigned last_row_index= m_l_matrix.row_count() - 1;
unsigned last_row_index = m_l_matrix.row_count() - 1;
m_l_matrix.divide_row(last_row_index, alpha); // divide the last row by alpha
auto &column = m_l_matrix.m_columns[j];
auto& column = m_l_matrix.m_columns[j];
int pivot_col_cell_index = -1;
for (unsigned k = 0; k < column.size(); k++) {
if (column[k].var() == last_row_index) {
@ -645,7 +632,7 @@ namespace lp {
m_l_matrix.m_rows[c.var()][c.offset()].offset() = pivot_col_cell_index;
}
while (column.size() > 1) {
auto & c = column.back();
auto& c = column.back();
SASSERT(c.var() != last_row_index);
m_l_matrix.pivot_row_to_row_given_cell(last_row_index, c, j);
m_changed_rows.insert(c.var());
@ -654,9 +641,9 @@ namespace lp {
void make_sure_j_is_in_the_last_row_of_l_matrix() {
unsigned j = m_l_matrix.column_count() - 1;
const auto &last_e_row = m_l_matrix.m_rows.back();
const auto& last_e_row = m_l_matrix.m_rows.back();
mpq alpha;
for (const auto& p: last_e_row) {
for (const auto& p : last_e_row) {
if (p.var() == j) {
return;
}
@ -671,10 +658,10 @@ namespace lp {
eliminate_last_term_column();
remove_last_row_in_matrix(m_l_matrix);
remove_last_row_in_matrix(m_e_matrix);
while(m_l_matrix.column_count() && m_l_matrix.m_columns.back().size() == 0) {
while (m_l_matrix.column_count() && m_l_matrix.m_columns.back().size() == 0) {
m_l_matrix.m_columns.pop_back();
}
while(m_e_matrix.column_count() && m_e_matrix.m_columns.back().size() == 0) {
while (m_e_matrix.column_count() && m_e_matrix.m_columns.back().size() == 0) {
m_e_matrix.m_columns.pop_back();
}
m_var_register.shrink(m_e_matrix.column_count());
@ -688,16 +675,15 @@ namespace lp {
m_sum_of_fixed.pop_back();
}
void remove_last_row_in_matrix(static_matrix<mpq, mpq>& m) {
auto & last_row = m.m_rows.back();
auto& last_row = m.m_rows.back();
for (unsigned k = static_cast<unsigned>(last_row.size()); k-- > 0;) {
m.remove_element(last_row, last_row[k]);
}
m.m_rows.pop_back();
}
void remove_entry_index(std::list<unsigned> & l, unsigned ei) {
void remove_entry_index(std::list<unsigned>& l, unsigned ei) {
auto it = std::find(l.begin(), l.end(), ei);
if (it != l.end())
l.erase(it);
@ -714,7 +700,7 @@ namespace lp {
std_vector<constraint_index> m_explanation_of_branches;
void add_term_callback(const lar_term* t) {
unsigned j = t->j();
TRACE("dioph_eq", tout << "term column t->j():" << j << std::endl; lra.print_term(*t, tout) << std::endl; );
TRACE("dioph_eq", tout << "term column t->j():" << j << std::endl; lra.print_term(*t, tout) << std::endl;);
if (!lra.column_is_int(j)) {
TRACE("dioph_eq", tout << "ignored a non-integral column" << std::endl;);
return;
@ -737,13 +723,13 @@ namespace lp {
return;
m_changed_columns.insert(j);
auto undo = undo_fixed_column(*this, j);
lra.trail().push(undo) ;
lra.trail().push(undo);
}
public:
imp(int_solver& lia, lar_solver& lra) : lia(lia), lra(lra) {
lra.m_add_term_callback=[this](const lar_term*t){add_term_callback(t);};
lra.m_update_column_bound_callback = [this](unsigned j){update_column_bound_callback(j);};
lra.m_add_term_callback = [this](const lar_term* t) { add_term_callback(t); };
lra.m_update_column_bound_callback = [this](unsigned j) { update_column_bound_callback(j); };
}
term_o get_term_from_entry(unsigned i) const {
term_o t;
@ -765,14 +751,13 @@ namespace lp {
void register_columns_to_term(const lar_term& t) {
TRACE("dioph_eq", tout << "register term:"; lra.print_term(t, tout); tout << ", t.j()=" << t.j() << std::endl;);
for (const auto &p: t.ext_coeffs()) {
for (const auto& p : t.ext_coeffs()) {
auto it = m_columns_to_terms.find(p.var());
TRACE("dio_reg", tout << "register p.var():" << p.var() <<"->" << t.j() << std::endl; );
TRACE("dio_reg", tout << "register p.var():" << p.var() << "->" << t.j() << std::endl;);
if (it != m_columns_to_terms.end()) {
it->second.insert(t.j());
}
else {
} else {
std::unordered_set<unsigned> s;
s.insert(t.j());
m_columns_to_terms[p.var()] = s;
@ -782,16 +767,16 @@ namespace lp {
// the term has form sum(a_i*x_i) - t.j() = 0,
void fill_entry(const lar_term& t) {
TRACE("dioph_eq", print_lar_term_L(t, tout) << std::endl;);
unsigned entry_index = (unsigned) m_e_matrix.row_count();
unsigned entry_index = (unsigned)m_e_matrix.row_count();
m_sum_of_fixed.push_back(mpq(0));
mpq & e = m_sum_of_fixed.back();
mpq& e = m_sum_of_fixed.back();
SASSERT(m_l_matrix.row_count() == m_e_matrix.row_count());
// fill m_l_matrix row
// fill m_l_matrix row
m_l_matrix.add_row();
// todo: consider to compress variables t.j() by using a devoted var_register for term columns
m_l_matrix.add_columns_up_to(t.j());
m_l_matrix.add_new_element(entry_index, t.j(), mpq(1));
// fill E-entry
// fill E-entry
m_e_matrix.add_row();
SASSERT(m_e_matrix.row_count() == m_e_matrix.row_count());
@ -814,7 +799,7 @@ namespace lp {
if (ei >= m_e_matrix.row_count()) return;
// q is the queue of variables that can be substituted in ei
protected_queue q;
for (const auto& p: m_e_matrix.m_rows[ei]) {
for (const auto& p : m_e_matrix.m_rows[ei]) {
if (can_substitute(p.var()))
q.push(p.var());
}
@ -823,23 +808,24 @@ namespace lp {
SASSERT(entry_invariant(ei));
}
void substitute_on_q_with_entry_in_S(protected_queue& q, unsigned ei, unsigned j, const mpq & alpha) {
void substitute_on_q_with_entry_in_S(protected_queue& q, unsigned ei, unsigned j, const mpq& alpha) {
unsigned ei_to_sub = m_k2s[j];
int sign_j = get_sign_in_e_row(ei_to_sub, j);
// we need to eliminate alpha*j in ei's row
add_two_entries(-mpq(sign_j)*alpha, ei_to_sub, ei);
for (const auto& p: m_e_matrix.m_rows[ei]) {
add_two_entries(-mpq(sign_j) * alpha, ei_to_sub, ei);
for (const auto& p : m_e_matrix.m_rows[ei]) {
unsigned jj = p.var();
if (can_substitute(jj))
q.push(jj);
}
}
void substitute_with_fresh_def(protected_queue& q, unsigned ei, unsigned j, const mpq & alpha) {
const lar_term& sub_term = m_fresh_k2xt_terms.get_by_key(j);
void substitute_with_fresh_def(protected_queue& q, unsigned ei, unsigned j, const mpq& alpha) {
const lar_term& sub_term = m_fresh_k2xt_terms.get_by_key(j).first;
TRACE("dioph_eq", print_lar_term_L(sub_term, tout) << std::endl;);
SASSERT(sub_term.get_coeff(j).is_one());
// we need to eliminate alpha*j in ei's row
add_term_to_entry(- alpha, sub_term, ei);
for (const auto& p: m_e_matrix.m_rows[ei]) {
add_term_to_entry(-alpha, sub_term, ei);
for (const auto& p : m_e_matrix.m_rows[ei]) {
unsigned jj = p.var();
if (can_substitute(jj))
q.push(jj);
@ -847,7 +833,7 @@ namespace lp {
}
// q is the queue of variables that can be substituted in ei
void substitute_on_q(protected_queue & q, unsigned ei) {
void substitute_on_q(protected_queue& q, unsigned ei) {
while (!q.empty()) {
unsigned j = q.pop_front();
mpq alpha = get_coeff_in_e_row(ei, j);
@ -860,23 +846,23 @@ namespace lp {
}
}
bool term_is_in_range(const lar_term& t) const {
for (const auto & p: t) {
for (const auto& p : t) {
if (p.var() >= m_e_matrix.column_count())
return false;
}
return true;
}
// adds the term multiplied by coeff to m_e_matrix row i
void add_term_to_entry(const mpq& coeff, const lar_term& t, unsigned i ) {
void add_term_to_entry(const mpq& coeff, const lar_term& t, unsigned i) {
SASSERT(term_is_in_range(t));
m_e_matrix.add_term_to_row(coeff, t, i);
}
// adds entry i0 multiplied by coeff to entry i1
void add_two_entries(const mpq& coeff, unsigned i0, unsigned i1 ) {
void add_two_entries(const mpq& coeff, unsigned i0, unsigned i1) {
m_e_matrix.add_rows(coeff, i0, i1);
m_l_matrix.add_rows(coeff, i0, i1);
m_sum_of_fixed[i1] += coeff* m_sum_of_fixed[i0];
m_sum_of_fixed[i1] += coeff * m_sum_of_fixed[i0];
}
bool all_vars_are_int(const lar_term& term) const {
@ -885,26 +871,24 @@ namespace lp {
return false;
}
return lia.column_is_int(term.j());
}
void clear_e_row(unsigned ei) {
auto & row = m_e_matrix.m_rows[ei];
auto& row = m_e_matrix.m_rows[ei];
while (row.size() > 0) {
auto& c = row.back();
m_e_matrix.remove_element(row, c);
}
}
void recalculate_entry(unsigned ei) {
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);
open_l_term_to_work_vector(ei, c);
clear_e_row(ei);
mpq denom(1);
for (const auto & p: m_substitution_workspace.m_data) {
for (const auto& p : m_substitution_workspace.m_data) {
unsigned lj = add_var(p.var());
m_e_matrix.add_columns_up_to(lj);
m_e_matrix.add_new_element(ei, lj, p.coeff());
@ -935,31 +919,48 @@ namespace lp {
for (const auto& p : m_e_matrix.column(this->lar_solver_to_local(j))) {
m_changed_rows.insert(p.var()); // TODO: is it necessary?
}
}
}
void remove_irrelevant_fresh_defs_for_row(unsigned ei) {
auto it = m_row2fresh_defs.find(ei);
if (it == m_row2fresh_defs.end()) return;
for (unsigned xt: it->second) {
for (unsigned xt : it->second) {
if (m_fresh_k2xt_terms.has_second_key(xt))
m_fresh_k2xt_terms.erase_by_second_key(xt);
}
m_row2fresh_defs.erase(it);
}
void remove_irrelevant_fresh_defs() {
std_vector<unsigned> xt_to_remove;
std_vector<unsigned> rows_to_remove_the_defs_from;
for (const auto& p : m_fresh_k2xt_terms.m_bij.m_rev_map) {
unsigned xt = p.first;
if (xt >= m_e_matrix.column_count()) {
xt_to_remove.push_back(xt);
rows_to_remove_the_defs_from.push_back(m_fresh_k2xt_terms.get_by_val(xt).second);
}
}
for (unsigned xt : xt_to_remove) {
m_fresh_k2xt_terms.erase_by_second_key(xt);
}
for (unsigned ei : m_changed_rows) {
remove_irrelevant_fresh_defs_for_row(ei);
}
for (unsigned ei : rows_to_remove_the_defs_from) {
remove_irrelevant_fresh_defs_for_row(ei);
}
}
void process_changed_columns() {
find_changed_terms_and_more_changed_rows();
for (unsigned j : m_changed_terms) {
if (j >= m_l_matrix.column_count()) continue;
for (const auto & cs: m_l_matrix.column(j)) {
for (const auto& cs : m_l_matrix.column(j)) {
m_changed_rows.insert(cs.var());
}
}
@ -971,7 +972,7 @@ namespace lp {
if (it == m_row2fresh_defs.end()) continue;
for (unsigned xt : it->second) {
SASSERT(var_is_fresh(xt));
for (const auto &p :m_e_matrix.m_columns[xt]) {
for (const auto& p : m_e_matrix.m_columns[xt]) {
more_changed_rows.push_back(p.var());
}
}
@ -981,12 +982,9 @@ namespace lp {
m_changed_rows.insert(ei);
}
remove_irrelevant_fresh_defs();
for(unsigned ei : m_changed_rows) {
for (unsigned ei : m_changed_rows) {
if (ei >= m_e_matrix.row_count())
continue;;
continue;
recalculate_entry(ei);
if (m_e_matrix.m_columns.back().size() == 0) {
m_e_matrix.m_columns.pop_back();
@ -997,6 +995,8 @@ namespace lp {
}
}
remove_irrelevant_fresh_defs();
eliminate_substituted_in_changed_rows();
m_changed_columns.reset();
SASSERT(m_changed_columns.size() == 0);
@ -1006,20 +1006,20 @@ namespace lp {
int get_sign_in_e_row(unsigned ei, unsigned j) const {
const auto& row = m_e_matrix.m_rows[ei];
auto it = std::find_if (row.begin(), row.end(), [j](const auto& p) {return p.var() == j;} );
auto it = std::find_if(row.begin(), row.end(), [j](const auto& p) { return p.var() == j; });
SASSERT(it != row.end() && abs(it->coeff()) == mpq(1));
return it->coeff().is_pos()? 1:-1;
return it->coeff().is_pos() ? 1 : -1;
}
mpq get_coeff_in_e_row (unsigned ei, unsigned j) {
mpq get_coeff_in_e_row(unsigned ei, unsigned j) {
const auto& row = m_e_matrix.m_rows[ei];
auto it = std::find_if (row.begin(), row.end(), [j](const auto& p) {return p.var() == j;} );
auto it = std::find_if(row.begin(), row.end(), [j](const auto& p) { return p.var() == j; });
if (it == row.end()) return mpq(0);
return it->coeff();
}
void eliminate_substituted_in_changed_rows() {
for (unsigned ei: m_changed_rows)
for (unsigned ei : m_changed_rows)
subs_entry(ei);
}
@ -1058,7 +1058,7 @@ namespace lp {
}
if (belongs_to_f(ei)) {
// see that all vars are substituted
const auto & row = m_e_matrix.m_rows[ei];
const auto& row = m_e_matrix.m_rows[ei];
for (const auto& p : row) {
if (m_k2s.has_key(p.var())) {
/*
@ -1078,7 +1078,6 @@ namespace lp {
}
}
}
}
return true;
}
@ -1093,7 +1092,7 @@ namespace lp {
m_lra_level = 0;
process_changed_columns();
for (const lar_term* t: m_added_terms) {
for (const lar_term* t : m_added_terms) {
m_active_terms.insert(t);
fill_entry(*t);
register_columns_to_term(*t);
@ -1161,7 +1160,7 @@ namespace lp {
// The function returns true if and only if there is no conflict. In the case of a conflict a branch
// can be returned as well.
bool normalize_e_by_gcd(unsigned ei, mpq& g) {
mpq & e = m_sum_of_fixed[ei];
mpq& e = m_sum_of_fixed[ei];
TRACE("dioph_eq", print_entry(ei, tout) << std::endl;);
g = gcd_of_coeffs(m_e_matrix.m_rows[ei], false);
if (g.is_zero() || g.is_one()) {
@ -1196,14 +1195,13 @@ namespace lp {
t.c() = -c.rhs();
}
void subs_front_in_indexed_vector_by_fresh(unsigned k, protected_queue &q) {
const lar_term& e = m_fresh_k2xt_terms.get_by_key(k);
void subs_front_in_indexed_vector_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_ind_c(), tout) << std::endl;
tout << "subs with e:";
print_lar_term_L(e, tout) << std::endl;);
mpq coeff = - m_substitution_workspace[k]; // need to copy since it will be zeroed
mpq coeff = -m_substitution_workspace[k]; // need to copy since it will be zeroed
m_substitution_workspace.erase(k); // m_work_vector_1[k] = 0;
SASSERT(e.get_coeff(k).is_one());
@ -1212,7 +1210,7 @@ namespace lp {
unsigned j = p.var();
if (j == k)
continue;
m_substitution_workspace.add(p.coeff()*coeff, j);
m_substitution_workspace.add(p.coeff() * coeff, j);
// do we need to add j to the queue?
if (!var_is_fresh(j) && m_substitution_workspace.has(j) && can_substitute(j))
q.push(j);
@ -1225,7 +1223,7 @@ namespace lp {
}
void add_l_row_to_term_with_index(const mpq& coeff, unsigned ei) {
for (const auto & p: m_l_matrix.m_rows[ei]) {
for (const auto& p : m_l_matrix.m_rows[ei]) {
m_l_terms_workspace.add(coeff * p.coeff(), p.var());
}
}
@ -1290,7 +1288,7 @@ namespace lp {
lar_term l_term_from_row(unsigned k) const {
lar_term ret;
for (const auto & p: m_l_matrix.m_rows[k])
for (const auto& p : m_l_matrix.m_rows[k])
ret.add_monomial(p.coeff(), p.var());
return ret;
@ -1357,7 +1355,7 @@ namespace lp {
break;
}
}
for (unsigned j: cleanup) {
for (unsigned j : cleanup) {
m_changed_terms.remove(j);
}
return ret;
@ -1428,25 +1426,8 @@ namespace lp {
// term_to_lar_solver(remove_fresh_vars(create_term_from_ind_c())))
// enable_trace("dioph_eq");
TRACE("dioph_eq_deb_subs", tout << "after subs\n";
print_term_o(create_term_from_ind_c(), tout) << std::endl;
tout << "term_to_tighten:";
print_lar_term_L(term_to_tighten, tout) << std::endl;
tout << "m_tmp_l:"; print_lar_term_L(m_l_terms_workspace.to_term(), tout) << std::endl;
tout << "open_ml:";
print_lar_term_L(open_ml(m_l_terms_workspace.to_term()), tout) << std::endl;
tout << "term_to_tighten + open_ml:";
print_term_o(term_to_tighten + open_ml(m_l_terms_workspace.to_term()), tout)
<< std::endl;
term_o ls = fix_vars(term_to_tighten + open_ml(m_l_terms_workspace.to_term()));
tout << "ls:"; print_term_o(ls,tout) << std::endl;
term_o rs = term_to_lar_solver(remove_fresh_vars(create_term_from_ind_c()));
tout << "rs:"; print_term_o(rs, tout ) << std::endl;
term_o diff = ls - rs;
if (!diff.is_empty()) {
tout << "diff:"; print_term_o(diff, tout ) << std::endl;
}
);
TRACE("dioph_eq_deb_subs", tout << "after subs\n"; print_term_o(create_term_from_ind_c(), tout) << std::endl; tout << "term_to_tighten:"; print_lar_term_L(term_to_tighten, tout) << std::endl; tout << "m_tmp_l:"; print_lar_term_L(m_l_terms_workspace.to_term(), tout) << std::endl; tout << "open_ml:"; print_lar_term_L(open_ml(m_l_terms_workspace.to_term()), tout) << std::endl; tout << "term_to_tighten + open_ml:"; print_term_o(term_to_tighten + open_ml(m_l_terms_workspace.to_term()), tout) << std::endl; term_o ls = fix_vars(term_to_tighten + open_ml(m_l_terms_workspace.to_term())); tout << "ls:"; print_term_o(ls, tout) << std::endl; term_o rs = term_to_lar_solver(remove_fresh_vars(create_term_from_ind_c())); tout << "rs:"; print_term_o(rs, tout) << std::endl; term_o diff = ls - rs; if (!diff.is_empty()) {
tout << "diff:"; print_term_o(diff, tout ) << std::endl; });
SASSERT(
fix_vars(term_to_tighten + open_ml(m_l_terms_workspace.to_term())) ==
@ -1574,7 +1555,8 @@ namespace lp {
return true;
}
template <typename T> u_dependency* explain_fixed_in_meta_term (const T& t) {
template <typename T>
u_dependency* explain_fixed_in_meta_term(const T& t) {
return explain_fixed(open_ml(t));
}
@ -1591,7 +1573,8 @@ namespace lp {
}
lia_move process_f() {
while (rewrite_eqs()) {}
while (rewrite_eqs()) {
}
if (m_conflict_index != UINT_MAX) {
lra.stats().m_dio_rewrite_conflicts++;
return lia_move::conflict;
@ -1636,10 +1619,10 @@ namespace lp {
mpq c = m_sum_of_fixed[ei];
for (const auto& p : m_e_matrix.m_rows[m_k2s[j]]) {
if (p.var() == j) {
const mpq & j_coeff = p.coeff();
const mpq& j_coeff = p.coeff();
SASSERT(j_coeff.is_one() || j_coeff.is_minus_one());
c += j_coeff * lra.get_lower_bound(local_to_lar_solver(j)).x;
TRACE("dio_br", tout << "the value of the vixed var is:" << lra.get_lower_bound(local_to_lar_solver(j)).x<<", m_sum_of_fixed[" << ei << "]:" << m_sum_of_fixed[ei] << ", new free coeff c:" << c << std::endl;);
TRACE("dio_br", tout << "the value of the vixed var is:" << lra.get_lower_bound(local_to_lar_solver(j)).x << ", m_sum_of_fixed[" << ei << "]:" << m_sum_of_fixed[ei] << ", new free coeff c:" << c << std::endl;);
continue;
}
if (g.is_zero()) {
@ -1649,7 +1632,7 @@ namespace lp {
}
if (g.is_one()) return lia_move::undef;
}
if (!(c/g).is_int()) {
if (!(c / g).is_int()) {
return lia_move::conflict;
}
return lia_move::undef;
@ -1662,7 +1645,8 @@ namespace lp {
*/
if (m_k2s.has_key(j)) { // j is substituted but using an entry
TRACE("dio_br",
tout << "fixed j:" << j <<", was substited by "; print_entry(m_k2s[j], tout););
tout << "fixed j:" << j << ", was substited by ";
print_entry(m_k2s[j], tout););
if (check_fixing(j) == lia_move::conflict) {
for (auto ci : lra.flatten(explain_fixed_in_meta_term(m_l_matrix.m_rows[m_k2s[j]]))) {
m_explanation_of_branches.push_back(ci);
@ -1674,7 +1658,7 @@ namespace lp {
}
void undo_branching() {
while (m_lra_level --) {
while (m_lra_level--) {
lra.pop();
}
lra.find_feasible_solution();
@ -1697,14 +1681,14 @@ namespace lp {
} else {
lra.add_var_bound(b.m_j, lconstraint_kind::GE, b.m_rs + mpq(1));
}
TRACE("dio_br", lra.print_column_info(b.m_j, tout) <<"add bound" << std::endl;);
TRACE("dio_br", lra.print_column_info(b.m_j, tout) << "add bound" << std::endl;);
if (lra.column_is_fixed(b.m_j)) {
unsigned local_bj;
if (! m_var_register.external_is_used(b.m_j, local_bj))
if (!m_var_register.external_is_used(b.m_j, local_bj))
return lia_move::undef;
if (fix_var(local_bj) == lia_move::conflict) {
TRACE("dio_br", tout << "conflict in fix_var" << std::endl;) ;
TRACE("dio_br", tout << "conflict in fix_var" << std::endl;);
return lia_move::conflict;
}
}
@ -1731,7 +1715,6 @@ namespace lp {
if (this->lra.constraints().valid_index(ci))
m_infeas_explanation.push_back(ci);
}
}
lia_move branching_on_undef() {
@ -1800,7 +1783,7 @@ namespace lp {
}
unsigned get_number_of_int_inf() const {
return (unsigned) std::count_if(
return (unsigned)std::count_if(
lra.r_basis().begin(), lra.r_basis().end(),
[this](unsigned j) {
return lia.column_is_int_inf(j);
@ -1826,7 +1809,6 @@ namespace lp {
}
}
branch create_branch() {
unsigned bj = UINT_MAX;
double score = std::numeric_limits<double>::infinity();
@ -1868,11 +1850,11 @@ namespace lp {
bool columns_to_terms_is_correct() const {
std::unordered_map<unsigned, std::unordered_set<unsigned>> c2t;
for (unsigned k = 0; k < lra.terms().size(); k ++ ) {
for (unsigned k = 0; k < lra.terms().size(); k++) {
const lar_term* t = lra.terms()[k];
if (!all_vars_are_int(*t)) continue;
SASSERT(t->j() != UINT_MAX);
for (const auto& p: (*t).ext_coeffs()) {
for (const auto& p : (*t).ext_coeffs()) {
unsigned j = p.var();
auto it = c2t.find(j);
if (it == c2t.end()) {
@ -1882,42 +1864,25 @@ namespace lp {
} else {
it->second.insert(t->j());
}
}
}
for (const auto & p : c2t) {
for (const auto& p : c2t) {
unsigned j = p.first;
const auto it = m_columns_to_terms.find(j);
if (it == m_columns_to_terms.end()) {
TRACE("dioph_eq", tout << "column j" << j << " is not registered" << std::endl;
tout << "the column belongs to the the following terms:";
for (unsigned tj : p.second) {
tout << " " << tj;
}
tout << std::endl;
);
TRACE("dioph_eq", tout << "column j" << j << " is not registered" << std::endl; tout << "the column belongs to the the following terms:"; for (unsigned tj : p.second) { tout << " " << tj; } tout << std::endl;);
return false;
}
if (it->second != p.second) {
TRACE("dioph_eq_deb", tout << "m_columns_to_terms[" << j << "] has to be ";
tout << "{";
for(unsigned lll : p.second) {
tout << lll << ", ";
}
tout << "}, \nbut it is {";
for (unsigned lll : it->second) {
tout << lll << ", ";
};
tout << "}" << std::endl;
TRACE("dioph_eq_deb", tout << "m_columns_to_terms[" << j << "] has to be "; tout << "{"; for (unsigned lll : p.second) { tout << lll << ", "; } tout << "}, \nbut it is {"; for (unsigned lll : it->second) { tout << lll << ", "; }; tout << "}" << std::endl;
);
return false;
}
}
// reverse inclusion
for (const auto & p : m_columns_to_terms) {
for (const auto& p : m_columns_to_terms) {
unsigned j = p.first;
const auto it = c2t.find(j);
if (it == c2t.end()) {
@ -1941,10 +1906,10 @@ namespace lp {
}
}
for (unsigned ei = 0; ei < m_e_matrix.row_count(); ei++ ) {
for (unsigned ei = 0; ei < m_e_matrix.row_count(); ei++) {
auto it = m_row2fresh_defs.find(ei);
if (it != m_row2fresh_defs.end()) {
for (unsigned xt: it->second) {
for (unsigned xt : it->second) {
if (!m_fresh_k2xt_terms.has_second_key(xt))
return false;
}
@ -1970,7 +1935,7 @@ namespace lp {
return ret;
}
SASSERT(ret == lia_move::undef);
m_max_of_branching_iterations = (unsigned)m_max_of_branching_iterations/2;
m_max_of_branching_iterations = (unsigned)m_max_of_branching_iterations / 2;
return lia_move::undef;
}
@ -2021,7 +1986,7 @@ namespace lp {
}
bool j_sign_is_correct(unsigned ei, unsigned j, int j_sign) {
const auto& row = m_e_matrix.m_rows[ei];
auto it = std::find_if (row.begin(), row.end(), [j](const auto& p) {return p.var() == j;} );
auto it = std::find_if(row.begin(), row.end(), [j](const auto& p) { return p.var() == j; });
if (it == row.end()) return false;
return (it->coeff() == mpq(1) && j_sign == 1) ||
(it->coeff() == mpq(-1) && j_sign == -1);
@ -2030,7 +1995,7 @@ namespace lp {
// a coefficient equal to j_sign which is +-1
void eliminate_var_in_f(unsigned ei, unsigned j, int j_sign) {
SASSERT(belongs_to_s(ei));
const auto & e = m_sum_of_fixed[ei];
const auto& e = m_sum_of_fixed[ei];
SASSERT(j_sign_is_correct(ei, j, j_sign));
TRACE("dioph_eq", tout << "eliminate var:" << j << " by using:";
print_entry(ei, tout) << std::endl;);
@ -2040,7 +2005,7 @@ namespace lp {
[ei](const auto& cell) {
return cell.var() == ei;
});
unsigned pivot_col_cell_index = (unsigned) std::distance(column.begin(), it);
unsigned pivot_col_cell_index = (unsigned)std::distance(column.begin(), it);
if (pivot_col_cell_index != 0) {
// swap the pivot column cell with the head cell
auto c = column[0];
@ -2067,8 +2032,8 @@ namespace lp {
print_entry(i, tout) << std::endl;);
m_sum_of_fixed[i] -= j_sign * coeff * e;
m_e_matrix.pivot_row_to_row_given_cell_with_sign(ei, c, j, j_sign);
//m_sum_of_fixed[i].m_l -= j_sign * coeff * e.m_l;
m_l_matrix.add_rows( -j_sign*coeff, ei, i);
// m_sum_of_fixed[i].m_l -= j_sign * coeff * e.m_l;
m_l_matrix.add_rows(-j_sign * coeff, ei, i);
TRACE("dioph_eq", tout << "after pivoting c_row:";
print_entry(i, tout););
CTRACE(
@ -2114,7 +2079,7 @@ namespace lp {
bool is_eliminated_from_f(unsigned j) const {
for (unsigned ei = 0; ei < m_e_matrix.row_count(); ei++) {
if (!belongs_to_f(ei)) continue;
const auto &row = m_e_matrix.m_rows[ei];
const auto& row = m_e_matrix.m_rows[ei];
for (const auto& p : row) {
if (p.var() == j) {
return false;
@ -2145,7 +2110,7 @@ namespace lp {
get_sign_in_e_row(ei, j);
}
for (const auto &p: m_e_matrix.m_rows[ei]) {
for (const auto& p : m_e_matrix.m_rows[ei]) {
if (!p.coeff().is_int()) {
return false;
}
@ -2155,20 +2120,20 @@ namespace lp {
term_to_lar_solver(remove_fresh_vars(get_term_from_entry(ei))) ==
fix_vars(open_ml(m_l_matrix.m_rows[ei]));
CTRACE( "dioph_deb_eq", !ret,
CTRACE("dioph_deb_eq", !ret,
{
tout << "get_term_from_entry(" << ei << "):";
print_term_o(get_term_from_entry(ei), tout) << std::endl;
tout << "ls:";
print_term_o(remove_fresh_vars(get_term_from_entry(ei)), tout)
<< std::endl;
tout << "e.m_l:"; print_lar_term_L(l_term_from_row(ei), tout) << std::endl;
tout << "e.m_l:";
print_lar_term_L(l_term_from_row(ei), tout) << std::endl;
tout << "open_ml(e.m_l):";
print_lar_term_L(open_ml(l_term_from_row(ei)), tout) << std::endl;
tout << "rs:";
print_term_o(fix_vars(open_ml(m_l_matrix.m_rows[ei])), tout) << std::endl;
}
);
});
return ret;
}
@ -2183,7 +2148,7 @@ namespace lp {
}
while (!q.empty()) {
unsigned xt = q.pop_front(); // xt is a fresh var
const lar_term& fresh_t = m_fresh_k2xt_terms.get_by_val(xt);
const lar_term& fresh_t = m_fresh_k2xt_terms.get_by_val(xt).first;
TRACE("dioph_eq", print_lar_term_L(fresh_t, tout););
SASSERT(fresh_t.get_coeff(xt).is_minus_one());
if (!t.contains(xt))
@ -2196,7 +2161,6 @@ namespace lp {
q.push(p.j());
}
}
}
return t;
}
@ -2206,7 +2170,8 @@ namespace lp {
return print_lar_term_L(opened_ml, out);
}
template <typename T> term_o open_ml(const T& ml) const {
template <typename T>
term_o open_ml(const T& ml) const {
term_o r;
for (const auto& p : ml) {
r += p.coeff() * (lra.get_term(p.var()) - lar_term(p.var()));
@ -2216,11 +2181,11 @@ namespace lp {
void open_l_term_to_work_vector(unsigned ei, mpq& c) {
m_substitution_workspace.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());
for (const auto & q: t.ext_coeffs()) {
for (const auto& q : t.ext_coeffs()) {
if (is_fixed(q.var())) {
c += p.coeff()*q.coeff()*lia.lower_bound(q.var()).x;
c += p.coeff() * q.coeff() * lia.lower_bound(q.var()).x;
} else {
m_substitution_workspace.add(p.coeff() * q.coeff(), q.var());
}
@ -2268,7 +2233,7 @@ namespace lp {
fresh_t.add_monomial(-mpq(1), xt);
fresh_t.add_monomial(mpq(1), k);
for (const auto& i : m_e_matrix.m_rows[h]) {
const mpq &ai = i.coeff();
const mpq& ai = i.coeff();
if (i.var() == k)
continue;
q = machine_div_rem(ai, ahk, r);
@ -2276,7 +2241,7 @@ namespace lp {
fresh_t.add_monomial(q, i.var());
}
m_fresh_k2xt_terms.add(k, xt, fresh_t);
m_fresh_k2xt_terms.add(k, xt, std::make_pair(fresh_t, h));
SASSERT(var_is_fresh(xt));
register_var_in_fresh_defs(h, xt);
eliminate_var_in_f_with_term(fresh_t, k, 1);
@ -2297,8 +2262,9 @@ namespace lp {
print_deps(out, explain_fixed_in_meta_term(l_term));
out << "}\n";
}
if (belongs_to_f(i)) { out << "in F\n"; }
else {
if (belongs_to_f(i)) {
out << "in F\n";
} else {
unsigned j = m_k2s.get_key(i);
if (local_to_lar_solver(j) == UINT_MAX) {
out << "FRESH\n";
@ -2332,7 +2298,7 @@ namespace lp {
mpq the_smallest_ahk;
unsigned kh;
int kh_sign;
for (unsigned ei=0; ei < m_e_matrix.row_count(); ei++) {
for (unsigned ei = 0; ei < m_e_matrix.row_count(); ei++) {
if (belongs_to_s(ei)) continue;
if (m_e_matrix.m_rows[ei].size() == 0) {
if (m_sum_of_fixed[ei].is_zero()) {
@ -2355,7 +2321,7 @@ namespace lp {
m_conflict_index = ei;
return false;
}
if (!gcd.is_one()){
if (!gcd.is_one()) {
ahk /= gcd;
if (ahk.is_one()) {
TRACE("dioph_eq", tout << "push to S:\n"; print_entry(ei, tout););
@ -2408,7 +2374,6 @@ namespace lp {
SASSERT(!ret || m_var_register.local_to_external(j) == UINT_MAX);
return ret;
}
};
// Constructor definition
dioph_eq::dioph_eq(int_solver& lia) {
@ -2427,4 +2392,3 @@ namespace lp {
}
} // namespace lp