diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index b31713094..561a94e99 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -16,6 +16,9 @@ namespace lp { lp_settings const& lar_solver::settings() const { return m_settings; } + statistics& lar_solver::stats() { return m_settings.stats(); } + + void lar_solver::updt_params(params_ref const& _p) { smt_params_helper p(_p); set_track_pivoted_rows(p.arith_bprop_on_pivoted_rows()); @@ -23,17 +26,9 @@ namespace lp { m_settings.updt_params(_p); } - - void clear() { - lp_assert(false); // not implemented - } - lar_solver::lar_solver() : - m_status(lp_status::UNKNOWN), m_crossed_bounds_column(-1), m_mpq_lar_core_solver(m_settings, *this), - m_int_solver(nullptr), - m_need_register_terms(false), m_var_register(false), m_term_register(true), m_constraints(*this) {} @@ -197,11 +192,11 @@ namespace lp { void lar_solver::set_status(lp_status s) { m_status = s; } lp_status lar_solver::find_feasible_solution() { - m_settings.stats().m_make_feasible++; - if (A_r().column_count() > m_settings.stats().m_max_cols) - m_settings.stats().m_max_cols = A_r().column_count(); - if (A_r().row_count() > m_settings.stats().m_max_rows) - m_settings.stats().m_max_rows = A_r().row_count(); + stats().m_make_feasible++; + if (A_r().column_count() > stats().m_max_cols) + stats().m_max_cols = A_r().column_count(); + if (A_r().row_count() > stats().m_max_rows) + stats().m_max_rows = A_r().row_count(); if (strategy_is_undecided()) decide_on_strategy_and_adjust_initial_state(); @@ -248,7 +243,7 @@ namespace lp { m_constraints.push(); m_usage_in_terms.push(); } - + void lar_solver::clean_popped_elements(unsigned n, u_set& set) { vector to_remove; for (unsigned j : set) @@ -269,9 +264,8 @@ namespace lp { m_crossed_bounds_column.pop(k); unsigned n = m_columns_to_ul_pairs.peek_size(k); m_var_register.shrink(n); - if (m_settings.use_tableau()) { + if (m_settings.use_tableau()) pop_tableau(); - } lp_assert(A_r().column_count() == n); TRACE("lar_solver_details", for (unsigned j = 0; j < n; j++) { @@ -285,6 +279,10 @@ namespace lp { clean_popped_elements(n, m_columns_with_changed_bounds); clean_popped_elements(n, m_incorrect_columns); + for (auto rid : m_row_bounds_to_replay) + insert_row_with_changed_bounds(rid); + m_row_bounds_to_replay.reset(); + unsigned m = A_r().row_count(); clean_popped_elements(m, m_rows_with_changed_bounds); clean_inf_set_of_r_solver_after_pop(); @@ -633,6 +631,9 @@ namespace lp { left_side.push_back(std::make_pair(p.second, p.first)); } + void lar_solver::insert_row_with_changed_bounds(unsigned rid) { + m_rows_with_changed_bounds.insert(rid); + } void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column(unsigned j) { if (A_r().row_count() != m_column_buffer.data_size()) @@ -643,14 +644,14 @@ namespace lp { m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); for (unsigned i : m_column_buffer.m_index) - m_rows_with_changed_bounds.insert(i); + insert_row_with_changed_bounds(i); } void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column_tableau(unsigned j) { for (auto& rc : m_mpq_lar_core_solver.m_r_A.m_columns[j]) - m_rows_with_changed_bounds.insert(rc.var()); + insert_row_with_changed_bounds(rc.var()); } bool lar_solver::use_tableau() const { return m_settings.use_tableau(); } @@ -743,7 +744,7 @@ namespace lp { void lar_solver::detect_rows_with_changed_bounds_for_column(unsigned j) { if (m_mpq_lar_core_solver.m_r_heading[j] >= 0) { - m_rows_with_changed_bounds.insert(m_mpq_lar_core_solver.m_r_heading[j]); + insert_row_with_changed_bounds(m_mpq_lar_core_solver.m_r_heading[j]); return; } @@ -793,7 +794,7 @@ namespace lp { update_x_and_inf_costs_for_columns_with_changed_bounds(); m_mpq_lar_core_solver.solve(); set_status(m_mpq_lar_core_solver.m_r_solver.get_status()); - lp_assert(((m_settings.stats().m_make_feasible% 100) != 0) || m_status != lp_status::OPTIMAL || all_constraints_hold()); + lp_assert(((stats().m_make_feasible% 100) != 0) || m_status != lp_status::OPTIMAL || all_constraints_hold()); } @@ -974,9 +975,7 @@ namespace lp { bool lar_solver::the_left_sides_sum_to_zero(const vector>& evidence) const { std::unordered_map coeff_map; - for (auto& it : evidence) { - mpq coeff = it.first; - constraint_index con_ind = it.second; + for (auto const & [coeff, con_ind] : evidence) { lp_assert(m_constraints.valid_index(con_ind)); register_in_map(coeff_map, m_constraints[con_ind], coeff); } @@ -1337,7 +1336,7 @@ namespace lp { void lar_solver::mark_rows_for_bound_prop(lpvar j) { auto& column = A_r().m_columns[j]; for (auto const& r : column) - m_rows_with_changed_bounds.insert(r.var()); + insert_row_with_changed_bounds(r.var()); } @@ -1659,7 +1658,7 @@ namespace lp { m_mpq_lar_core_solver.m_r_heading.push_back(m_mpq_lar_core_solver.m_r_basis.size()); m_mpq_lar_core_solver.m_r_basis.push_back(j); if (m_settings.bound_propagation()) - m_rows_with_changed_bounds.insert(A_r().row_count() - 1); + insert_row_with_changed_bounds(A_r().row_count() - 1); } else { m_mpq_lar_core_solver.m_r_heading.push_back(-static_cast(m_mpq_lar_core_solver.m_r_nbasis.size()) - 1); @@ -1755,7 +1754,7 @@ namespace lp { if (use_tableau() && !coeffs.empty()) { add_row_from_term_no_constraint(m_terms.back(), ret); if (m_settings.bound_propagation()) - m_rows_with_changed_bounds.insert(A_r().row_count() - 1); + insert_row_with_changed_bounds(A_r().row_count() - 1); } lp_assert(m_var_register.size() == A_r().column_count()); if (m_need_register_terms) { diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 6e61354ff..b4c69d783 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -76,13 +76,13 @@ class lar_solver : public column_namer { //////////////////// fields ////////////////////////// lp_settings m_settings; - lp_status m_status; + lp_status m_status = lp_status::UNKNOWN; stacked_value m_simplex_strategy; // such can be found at the initialization step: u < l stacked_value m_crossed_bounds_column; lar_core_solver m_mpq_lar_core_solver; - int_solver * m_int_solver; - bool m_need_register_terms; + int_solver * m_int_solver = nullptr; + bool m_need_register_terms = false; var_register m_var_register; var_register m_term_register; stacked_vector m_columns_to_ul_pairs; @@ -90,6 +90,8 @@ class lar_solver : public column_namer { // the set of column indices j such that bounds have changed for j u_set m_columns_with_changed_bounds; u_set m_rows_with_changed_bounds; + unsigned_vector m_row_bounds_to_replay; + u_set m_basic_columns_with_changed_cost; // these are basic columns with the value changed, so the the corresponding row in the tableau // does not sum to zero anymore @@ -164,7 +166,6 @@ class lar_solver : public column_namer { void adjust_initial_state_for_lu(); void adjust_initial_state_for_tableau_rows(); void fill_last_row_of_A_d(static_matrix & A, const lar_term* ls); - void clear(); bool use_lu() const; bool sizes_are_correct() const; bool implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const; @@ -219,6 +220,7 @@ class lar_solver : public column_namer { void change_basic_columns_dependend_on_a_given_nb_column(unsigned j, const numeric_pair & delta); void update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j); unsigned num_changed_bounds() const { return m_rows_with_changed_bounds.size(); } + void insert_row_with_changed_bounds(unsigned rid); void detect_rows_with_changed_bounds_for_column(unsigned j); void detect_rows_with_changed_bounds(); void set_value_for_nbasic_column(unsigned j, const impq & new_val); @@ -368,20 +370,19 @@ public: // these two loops should be run sequentially // since the first loop might change column bounds // and add fixed columns this way - if (settings().cheap_eqs()) { + if (settings().propagate_eqs()) { bp.clear_for_eq(); for (unsigned i : m_rows_with_changed_bounds) { - calculate_cheap_eqs_for_row(i, bp); + unsigned offset_eqs = stats().m_offset_eqs; + bp.cheap_eq_tree(i); if (settings().get_cancel_flag()) return; + if (stats().m_offset_eqs > offset_eqs) + m_row_bounds_to_replay.push_back(i); } } m_rows_with_changed_bounds.clear(); } - template - void calculate_cheap_eqs_for_row(unsigned i, lp_bound_propagator & bp) { - bp.cheap_eq_tree(i); - } bool is_fixed(column_index const& j) const { return column_is_fixed(j); } inline column_index to_column_index(unsigned v) const { return column_index(external_to_column_index(v)); } @@ -515,6 +516,8 @@ public: unsigned column_to_reported_index(unsigned j) const; lp_settings & settings(); lp_settings const & settings() const; + statistics& stats(); + void updt_params(params_ref const& p); column_type get_column_type(unsigned j) const { return m_mpq_lar_core_solver.m_column_types()[j]; } const impq & get_lower_bound(unsigned j) const { return m_mpq_lar_core_solver.m_r_lower_bounds()[j]; } diff --git a/src/math/lp/lar_term.h b/src/math/lp/lar_term.h index 8dcb16684..3ef424e24 100644 --- a/src/math/lp/lar_term.h +++ b/src/math/lp/lar_term.h @@ -155,7 +155,7 @@ public: }; class const_iterator { - u_map< mpq>::iterator m_it; + u_map::iterator m_it; public: ival operator*() const { return ival(m_it->m_key, m_it->m_value); } const_iterator operator++() { const_iterator i = *this; m_it++; return i; } diff --git a/src/math/lp/lp_bound_propagator.h b/src/math/lp/lp_bound_propagator.h index fec650293..1ea872517 100644 --- a/src/math/lp/lp_bound_propagator.h +++ b/src/math/lp/lp_bound_propagator.h @@ -72,14 +72,15 @@ class lp_bound_propagator { static int other(int x, int y, int z) { SASSERT(x == z || y == z); return x == z ? y : x; } std::ostream& print_vert(std::ostream & out, const vertex* v) const { out << "(c = " << v->column() << ", parent = {"; - if (v->parent()) { out << "(" << v->parent()->column() << ")";} - else { out << "null"; } + if (v->parent()) + out << "(" << v->parent()->column() << ")"; + else + out << "null"; out << "} , lvl = " << v->level(); - if (m_pol.contains(v->column())) { + if (m_pol.contains(v->column())) out << (pol(v) == -1? " -":" +"); - } else { + else out << " not in m_pol"; - } out << ')'; return out; } @@ -87,13 +88,13 @@ class lp_bound_propagator { hashtable m_visited_rows; hashtable m_visited_columns; u_map m_vertices; - vertex* m_root; + vertex* m_root = nullptr; // At some point we can find a row with a single vertex non fixed vertex // then we can fix the whole tree, // by adjusting the vertices offsets, so they become absolute. // If the tree is fixed then in addition to checking with the m_vals_to_verts // we are going to check with the m_fixed_var_tables. - const vertex* m_fixed_vertex; + const vertex* m_fixed_vertex = nullptr; explanation m_fixed_vertex_explanation; // a pair (o, j) belongs to m_vals_to_verts iff x[j] = x[m_root->column()] + o map, default_eq> m_vals_to_verts; @@ -111,19 +112,199 @@ class lp_bound_propagator { T& m_imp; vector m_ibounds; + + + + map, default_eq> m_val2fixed_row; + + void try_add_equation_with_internal_fixed_tables(unsigned r1, vertex const* v) { + SASSERT(m_fixed_vertex); + if (v != m_root) + return; + unsigned v1 = v->column(); + unsigned r2 = UINT_MAX; + if (!m_val2fixed_row.find(val(v1), r2) || r2 >= lp().row_count()) { + m_val2fixed_row.insert(val(v1), r1); + return; + } + unsigned v2, v3; + int polarity; + if (!is_tree_offset_row(r2, v2, v3, polarity) || !not_set(v3) || + is_int(v1) != is_int(v2) || val(v1) != val(v2)) { + m_val2fixed_row.insert(val(v1), r1); + return; + } + + explanation ex; + explain_fixed_in_row(r1, ex); + explain_fixed_in_row(r2, ex); + add_eq_on_columns(ex, v1, v2, true); + } + + void try_add_equation_with_lp_fixed_tables(unsigned row_index, const vertex *v) { + SASSERT(m_fixed_vertex); + unsigned v_j = v->column(); + unsigned j = null_lpvar; + if (!lp().find_in_fixed_tables(val(v_j), is_int(v_j), j)) { + // try_add_equation_with_internal_fixed_tables(row_index, v); + return; + } + + TRACE("cheap_eq", + tout << "v_j = "; lp().print_column_info(v_j, tout) << std::endl; + tout << "v = "; print_vert(tout, v) << std::endl; + tout << "found j " << j << std::endl; lp().print_column_info(j, tout)<< std::endl; + tout << "found j = " << j << std::endl;); + vector path = connect_in_tree(v, m_fixed_vertex); + explanation ex = get_explanation_from_path(path); + ex.add_expl(m_fixed_vertex_explanation); + explain_fixed_column(j, ex); + add_eq_on_columns(ex, j, v_j, true); + } + + void try_add_equation_with_val_table(const vertex *v) { + SASSERT(m_fixed_vertex); + unsigned v_j = v->column(); + const vertex *u = nullptr; + if (!m_vals_to_verts.find(val(v_j), u)) { + m_vals_to_verts.insert(val(v_j), v); + return; + } + unsigned j = u->column(); + if (j == v_j || is_int(j) != is_int(v_j)) + return; + + TRACE("cheap_eq", tout << "found j=" << j << " for v="; + print_vert(tout, v) << "\n in m_vals_to_verts\n";); + vector path = connect_in_tree(u, v); + explanation ex = get_explanation_from_path(path); + ex.add_expl(m_fixed_vertex_explanation); + add_eq_on_columns(ex, j, v_j, true); + } + + static bool not_set(unsigned j) { return j == UINT_MAX; } + static bool is_set(unsigned j) { return j != UINT_MAX; } + + void create_root(unsigned row_index) { + SASSERT(!m_root && !m_fixed_vertex); + unsigned x, y; + int polarity; + TRACE("cheap_eq_det", print_row(tout, row_index);); + if (!is_tree_offset_row(row_index, x, y, polarity)) { + TRACE("cheap_eq_det", tout << "not an offset row\n";); + return; + } + TRACE("cheap_eq", print_row(tout, row_index);); + m_root = alloc_v(x); + set_polarity(m_root, 1); // keep m_root in the positive table + if (not_set(y)) { + set_fixed_vertex(m_root); + explain_fixed_in_row(row_index, m_fixed_vertex_explanation); + } + else { + vertex *v = add_child_with_check(row_index, y, m_root, polarity); + if (v) + explore_under(v); + } + explore_under(m_root); + } + + void explore_under(vertex * v) { + check_for_eq_and_add_to_val_tables(v); + go_over_vertex_column(v); + } + + // In case of only one non fixed column, and the function returns true, + // this column would be represened by x. + bool is_tree_offset_row(unsigned row_index, unsigned & x, unsigned & y, int & polarity) const { + x = y = UINT_MAX; + const row_cell* x_cell = nullptr; + const row_cell* y_cell = nullptr; + const auto & row = lp().get_row(row_index); + for (unsigned k = 0; k < row.size(); k++) { + const auto& c = row[k]; + if (column_is_fixed(c.var())) + continue; + if (not_set(x)) { + if (c.coeff().is_one() || c.coeff().is_minus_one()) { + x = c.var(); + x_cell = & c; + } + else + return false; + } + else if (not_set(y)) { + if (c.coeff().is_one() || c.coeff().is_minus_one()) { + y = c.var(); + y_cell = & c; + } + else + return false; + } + else + return false; + } + if (is_set(x)) { + if (is_set(y)) + polarity = x_cell->coeff().is_pos() == y_cell->coeff().is_pos()? -1 : 1; + else + polarity = 1; + return true; + } + return false; + } + + void go_over_vertex_column(vertex * v) { + lpvar j = v->column(); + if (!check_insert(m_visited_columns, j)) + return; + + for (const auto & c : lp().get_column(j)) { + unsigned row_index = c.var(); + if (!check_insert(m_visited_rows, row_index)) + continue; + vertex* u = get_child_from_row(row_index, v); + if (u) + explore_under(u); + } + } + + void reset_cheap_eq_eh() { + if (!m_root) + return; + delete_tree(m_root); + m_root = nullptr; + set_fixed_vertex(nullptr); + m_fixed_vertex_explanation.clear(); + m_vals_to_verts.reset(); + m_vals_to_verts_neg.reset(); + m_pol.reset(); + m_vertices.reset(); + } + + struct reset_cheap_eq { + lp_bound_propagator& p; + reset_cheap_eq(lp_bound_propagator& p):p(p) {} + ~reset_cheap_eq() { p.reset_cheap_eq_eh(); } + }; + + public: + + lp_bound_propagator(T& imp): + m_imp(imp) {} + const vector& ibounds() const { return m_ibounds; } + void init() { m_improved_upper_bounds.clear(); m_improved_lower_bounds.clear(); m_ibounds.reset(); } - lp_bound_propagator(T& imp): m_root(nullptr), - m_fixed_vertex(nullptr), - m_imp(imp) {} - + const lar_solver& lp() const { return m_imp.lp(); } lar_solver& lp() { return m_imp.lp(); } + column_type get_column_type(unsigned j) const { return m_imp.lp().get_column_type(j); } @@ -133,9 +314,8 @@ public: } const mpq & get_lower_bound_rational(unsigned j) const { - return m_imp.lp().get_lower_bound(j).x; + return m_imp.lp().get_lower_bound(j).x; } - const impq & get_upper_bound(unsigned j) const { return m_imp.lp().get_upper_bound(j); @@ -167,19 +347,22 @@ public: found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict); TRACE("try_add_bound", m_imp.lp().print_implied_bound(found_bound, tout);); } - } else { + } + else { m_improved_lower_bounds[j] = m_ibounds.size(); m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict)); TRACE("try_add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout);); } - } else { // the upper bound case + } + else { // the upper bound case if (try_get_value(m_improved_upper_bounds, j, k)) { auto & found_bound = m_ibounds[k]; if (v < found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) { found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict); TRACE("try_add_bound", m_imp.lp().print_implied_bound(found_bound, tout);); } - } else { + } + else { m_improved_upper_bounds[j] = m_ibounds.size(); m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict)); TRACE("try_add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout);); @@ -199,54 +382,12 @@ public: return val(v->column()); } - void try_add_equation_with_lp_fixed_tables(const vertex *v) { - SASSERT(m_fixed_vertex); - unsigned v_j = v->column(); - unsigned j = null_lpvar; - if (!lp().find_in_fixed_tables(val(v_j), is_int(v_j), j)) - return; - - TRACE("cheap_eq", tout << "v_j = "; lp().print_column_info(v_j, tout) << std::endl;); - TRACE("cheap_eq", tout << "v = "; print_vert(tout, v) << std::endl;); - TRACE("cheap_eq", tout << "found j " << j << std::endl; - lp().print_column_info(j, tout)<< std::endl;); - TRACE("cheap_eq", tout << "found j = " << j << std::endl;); - vector path = connect_in_tree(v, m_fixed_vertex); - explanation ex = get_explanation_from_path(path); - ex.add_expl(m_fixed_vertex_explanation); - explain_fixed_column(j, ex); - add_eq_on_columns(ex, j, v->column()); - - } - - void try_add_equation_with_val_table(const vertex *v) { - SASSERT(m_fixed_vertex); - unsigned v_j = v->column(); - const vertex *u = nullptr; - if (!m_vals_to_verts.find(val(v_j), u)) { - m_vals_to_verts.insert(val(v_j), v); - return; - } - unsigned j = u->column(); - if (j == v_j || is_int(j) != is_int(v_j)) - return; - - TRACE("cheap_eq", tout << "found j=" << j << " for v="; - print_vert(tout, v) << "\n in m_vals_to_verts\n";); - vector path = connect_in_tree(u, v); - explanation ex = get_explanation_from_path(path); - ex.add_expl(m_fixed_vertex_explanation); - add_eq_on_columns(ex, j, v_j); - } - - bool tree_contains_r(vertex* root, vertex *v) const { if (*root == *v) return true; - for (auto e : root->edges()) { + for (auto e : root->edges()) if (tree_contains_r(e.target(), v)) return true; - } return false; } @@ -294,38 +435,12 @@ public: return v; } - static bool not_set(unsigned j) { return j == UINT_MAX; } - static bool is_set(unsigned j) { return j != UINT_MAX; } - - void create_root(unsigned row_index) { - SASSERT(!m_root && !m_fixed_vertex); - unsigned x, y; - int polarity; - TRACE("cheap_eq_det", print_row(tout, row_index);); - if (!is_tree_offset_row(row_index, x, y, polarity)) { - TRACE("cheap_eq_det", tout << "not an offset row\n";); - return; - } - TRACE("cheap_eq", print_row(tout, row_index);); - m_root = alloc_v(x); - set_polarity(m_root, 1); // keep m_root in the positive table - if (not_set(y)) { - set_fixed_vertex(m_root); - explain_fixed_in_row(row_index, m_fixed_vertex_explanation); - } else { - vertex *v = add_child_with_check(row_index, y, m_root, polarity); - if (v) - explore_under(v); - } - explore_under(m_root); - } unsigned column(unsigned row, unsigned index) { return lp().get_row(row)[index].var(); } bool fixed_phase() const { return m_fixed_vertex; } - // Returns the vertex to start exploration from, or nullptr. @@ -379,10 +494,12 @@ public: is_int(k->column()) == is_int(v->column()) && !is_equal(k->column(), v->column())) { report_eq(k, v); - } else { + } + else { TRACE("cheap_eq", tout << "no report\n";); } - } else { + } + else { TRACE("cheap_eq", tout << "registered: " << val(v) << " -> { "; print_vert(tout, v) << "} \n";); table.insert(val(v), v); } @@ -411,37 +528,31 @@ public: std::ostream& print_path(const vector& path, std::ostream& out) const { out << "path = \n"; - for (const edge& k : path) { + for (const edge& k : path) print_edge(k, out) << "\n"; - } return out; } - - - // we have v_i and v_j, indices of vertices at the same offsets void report_eq(const vertex* v_i, const vertex* v_j) { SASSERT(v_i != v_j); SASSERT(lp().get_column_value(v_i->column()) == lp().get_column_value(v_j->column())); TRACE("cheap_eq", tout << v_i->column() << " = " << v_j->column() << "\nu = "; - print_vert(tout, v_i) << "\nv = "; print_vert(tout, v_j) <<"\n"; - ); + print_vert(tout, v_i) << "\nv = "; print_vert(tout, v_j) <<"\n"); vector path = connect_in_tree(v_i, v_j); lp::explanation exp = get_explanation_from_path(path); - add_eq_on_columns(exp, v_i->column(), v_j->column()); + add_eq_on_columns(exp, v_i->column(), v_j->column(), false); } std::ostream& print_expl(std::ostream & out, const explanation& exp) const { - for (auto p : exp) { + for (auto p : exp) lp().constraints().display(out, [this](lpvar j) { return lp().get_variable_name(j);}, p.ci()); - } return out; } - void add_eq_on_columns(const explanation& exp, lpvar j, lpvar k) { + bool add_eq_on_columns(const explanation& exp, lpvar j, lpvar k, bool is_fixed) { SASSERT(j != k); unsigned je = lp().column_to_reported_index(j); unsigned ke = lp().column_to_reported_index(k); @@ -452,8 +563,10 @@ public: tout << "theory_vars v" << lp().local_to_external(je) << " == v" << lp().local_to_external(ke) << "\n"; ); - m_imp.add_eq(je, ke, exp); - lp().settings().stats().m_cheap_eqs++; + bool added = m_imp.add_eq(je, ke, exp, is_fixed); + if (added) + lp().stats().m_offset_eqs++; + return added; } // column to theory_var @@ -478,14 +591,10 @@ public: } void explain_fixed_in_row(unsigned row, explanation& ex) const { - TRACE("cheap_eq", - tout << lp().get_row(row) << std::endl; - ); - for (const auto & c : lp().get_row(row)) { - if (lp().is_fixed(c.var())) { + TRACE("cheap_eq", tout << lp().get_row(row) << std::endl); + for (const auto & c : lp().get_row(row)) + if (lp().is_fixed(c.var())) explain_fixed_column(c.var(), ex); - } - } } void explain_fixed_column(unsigned j, explanation & ex) const { @@ -536,10 +645,9 @@ public: if (visited_verts.find(v->column()) != visited_verts.end()) return false; visited_verts.insert(v->column()); - for (auto e : v->edges()) { + for (auto e : v->edges()) if (!tree_is_correct(e.target(), visited_verts)) return false; - } return true; } std::ostream& print_tree(std::ostream & out, vertex* v) const { @@ -553,43 +661,37 @@ public: return out; } - void try_add_equation_with_fixed_tables(const vertex* v) { - try_add_equation_with_lp_fixed_tables(v); + void try_add_equation_with_fixed_tables(unsigned row_index, const vertex* v) { + try_add_equation_with_lp_fixed_tables(row_index, v); try_add_equation_with_val_table(v); } - void create_fixed_eqs(const vertex* v) { - try_add_equation_with_fixed_tables(v); + void handle_fixed_phase(unsigned row_index) { + if (!fixed_phase()) + return; + const vertex* v = m_root; + try_add_equation_with_fixed_tables(row_index, v); for (auto e: v->edges()) - try_add_equation_with_fixed_tables(e.target()); + try_add_equation_with_fixed_tables(row_index, e.target()); } - void handle_fixed_phase() { - create_fixed_eqs(m_root); - } void cheap_eq_tree(unsigned row_index) { - TRACE("cheap_eq_det", tout << "row_index = " << row_index << "\n";); - if (!check_insert(m_visited_rows, row_index)) - return; // already explored - create_root(row_index); - if (m_root == nullptr) { + reset_cheap_eq _reset(*this); + TRACE("cheap_eq_det", tout << "row_index = " << row_index << "\n";); + if (!check_insert(m_visited_rows, row_index)) return; - } - TRACE("cheap_eq", tout << "tree = "; print_tree(tout, m_root) << "\n";); + create_root(row_index); + if (!m_root) + return; + + TRACE("cheap_eq", tout << "tree = "; print_tree(tout, m_root) << "\n";); SASSERT(tree_is_correct()); - if (fixed_phase()) - handle_fixed_phase(); - TRACE("cheap_eq", tout << "done for row_index " << row_index << "\n";); - TRACE("cheap_eq", tout << "tree size = " << verts_size();); - delete_tree(m_root); - m_root = nullptr; - set_fixed_vertex(nullptr); - m_fixed_vertex_explanation.clear(); - m_vals_to_verts.reset(); - m_vals_to_verts_neg.reset(); - m_pol.reset(); - m_vertices.reset(); + handle_fixed_phase(row_index); + + TRACE("cheap_eq", + tout << "done for row_index " << row_index << "\n"; + tout << "tree size = " << verts_size();); } std::ostream& print_row(std::ostream & out, unsigned row_index) const { @@ -643,71 +745,7 @@ public: return false; table.insert(j); return true; - } - - void go_over_vertex_column(vertex * v) { - lpvar j = v->column(); - if (!check_insert(m_visited_columns, j)) - return; - - for (const auto & c : lp().get_column(j)) { - unsigned row_index = c.var(); - if (!check_insert(m_visited_rows, row_index)) - continue; - vertex *u = get_child_from_row(row_index, v); - if (u) { - // debug - // if (verts_size() > 3) { - // std::cout << "big tree\n"; - // TRACE("cheap_eq", print_tree(tout, m_root);); - // exit(1); - // } // end debug - explore_under(u); - } - } - } - - void explore_under(vertex * v) { - check_for_eq_and_add_to_val_tables(v); - go_over_vertex_column(v); - } + } - // In case of only one non fixed column, and the function returns true, - // this column would be represened by x. - bool is_tree_offset_row( unsigned row_index, - unsigned & x, unsigned & y, int & polarity ) const { - x = y = UINT_MAX; - const row_cell* x_cell = nullptr; - const row_cell* y_cell = nullptr; - const auto & row = lp().get_row(row_index); - for (unsigned k = 0; k < row.size(); k++) { - const auto& c = row[k]; - if (column_is_fixed(c.var())) - continue; - if (not_set(x)) { - if (c.coeff().is_one() || c.coeff().is_minus_one()) { - x = c.var(); - x_cell = & c; - } else { - return false; - } - } else if (not_set(y)) { - if (c.coeff().is_one() || c.coeff().is_minus_one()) { - y = c.var(); - y_cell = & c; - } else - return false; - } else - return false; - } - if (is_set(x)) { - if (is_set(y)) - polarity = x_cell->coeff().is_pos() == y_cell->coeff().is_pos()? -1 : 1; - else - polarity = 1; - return true; - } - return false; - } }; } diff --git a/src/math/lp/lp_settings.cpp b/src/math/lp/lp_settings.cpp index ce6edcfd5..592a98983 100644 --- a/src/math/lp/lp_settings.cpp +++ b/src/math/lp/lp_settings.cpp @@ -27,7 +27,7 @@ template bool lp::vectors_are_equal(vector const&, vectorget_expr(); expr* e2 = n2->get_expr(); - if (m.is_ite(e1) || m.is_ite(e2)) - return; + if (!is_fixed && !a.is_numeral(e1) && !a.is_numeral(e2) && (m.is_ite(e1) || m.is_ite(e2))) + return false; if (e1->get_sort() != e2->get_sort()) - return; + return false; reset_evidence(); for (auto ev : e) set_evidence(ev.ci(), m_core, m_eqs); auto* jst = euf::th_explain::propagate(*this, m_core, m_eqs, n1, n2); ctx.propagate(n1, n2, jst->to_index()); + return true; } bool solver::bound_is_interesting(unsigned vi, lp::lconstraint_kind kind, const rational& bval) const { diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index b449e049e..759c85fae 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -450,7 +450,7 @@ namespace arith { lp::lar_solver& lp() { return *m_solver; } lp::lar_solver const& lp() const { return *m_solver; } bool is_equal(theory_var x, theory_var y) const; - void add_eq(lpvar u, lpvar v, lp::explanation const& e); + bool add_eq(lpvar u, lpvar v, lp::explanation const& e, bool is_fixed); void consume(rational const& v, lp::constraint_index j); bool bound_is_interesting(unsigned vi, lp::lconstraint_kind kind, const rational& bval) const; }; diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index a5a42ee7a..4499752e5 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -262,22 +262,30 @@ namespace smt { } void context::display_eqc(std::ostream & out) const { - bool first = true; - for (enode * x : m_enodes) { - expr * n = x->get_expr(); - expr * r = x->get_root()->get_expr(); - if (n != r) { - if (first) { - out << "equivalence classes:\n"; - first = false; - } - out << "#" << n->get_id() << " -> #" << r->get_id() << ": "; - out << mk_pp(n, m) << " -> " << mk_pp(r, m) << "\n"; + if (m_enodes.empty()) + return; + unsigned count = 0; + for (enode * r : m_enodes) + if (r->is_root()) + ++count; + + out << "equivalence classes: " << count << "\n"; + for (enode * r : m_enodes) { + if (!r->is_root()) + continue; + out << "#" << enode_pp(r, *this) << "\n"; + if (r->get_class_size() == 1) + continue; + for (enode* n : *r) { + if (n != r) + out << " #" << enode_pp(n, *this) << "\n"; } } } void context::display_app_enode_map(std::ostream & out) const { + return; + // mainly useless if (!m_e_internalized_stack.empty()) { out << "expression -> enode:\n"; unsigned sz = m_e_internalized_stack.size(); diff --git a/src/smt/smt_theory.h b/src/smt/smt_theory.h index c47a7bcf7..500c47f5e 100644 --- a/src/smt/smt_theory.h +++ b/src/smt/smt_theory.h @@ -453,9 +453,6 @@ namespace smt { std::ostream& display_flat_app(std::ostream & out, app * n) const; - std::ostream& display_var_def(std::ostream & out, theory_var v) const { return display_app(out, get_enode(v)->get_expr()); } - - std::ostream& display_var_flat_def(std::ostream & out, theory_var v) const { return display_flat_app(out, get_enode(v)->get_expr()); } protected: void log_axiom_instantiation(app * r, unsigned axiom_id = UINT_MAX, unsigned num_bindings = 0, diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index f152c2430..4b57f043e 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -2239,17 +2239,17 @@ namespace smt { ctx.push_trail(value_trail(m_assume_eq_head)); while (m_assume_eq_head < m_assume_eq_candidates.size()) { - std::pair const & p = m_assume_eq_candidates[m_assume_eq_head]; - theory_var v1 = p.first; - theory_var v2 = p.second; + auto const& [v1, v2] = m_assume_eq_candidates[m_assume_eq_head]; + enode* n1 = get_enode(v1); + enode* n2 = get_enode(v2); m_assume_eq_head++; CTRACE("func_interp_bug", get_value(v1) == get_value(v2) && - get_enode(v1)->get_root() != get_enode(v2)->get_root(), - tout << "assuming eq: #" << get_enode(v1)->get_owner_id() << " = #" << get_enode(v2)->get_owner_id() << "\n";); + n1->get_root() != n2->get_root(), + tout << "assuming eq: #" << n1->get_owner_id() << " = #" << n2->get_owner_id() << "\n";); if (get_value(v1) == get_value(v2) && - get_enode(v1)->get_root() != get_enode(v2)->get_root() && - assume_eq(get_enode(v1), get_enode(v2))) { + n1->get_root() != n2->get_root() && + assume_eq(n1, n2)) { ++m_stats.m_assume_eqs; return true; } diff --git a/src/smt/theory_arith_pp.h b/src/smt/theory_arith_pp.h index a4dba46d0..049528f79 100644 --- a/src/smt/theory_arith_pp.h +++ b/src/smt/theory_arith_pp.h @@ -82,18 +82,17 @@ namespace smt { template void theory_arith::display_row(std::ostream & out, row const & r, bool compact) const { - typename vector::const_iterator it = r.begin_entries(); - typename vector::const_iterator end = r.end_entries(); + out << "(v" << r.get_base_var() << ") : "; bool first = true; - for (; it != end; ++it) { - if (!it->is_dead()) { + for (auto const& e : r) { + if (!e.is_dead()) { if (first) first = false; else out << " + "; - theory_var s = it->m_var; - numeral const & c = it->m_coeff; + theory_var s = e.m_var; + numeral const & c = e.m_coeff; if (!c.is_one()) out << c << "*"; if (compact) { @@ -103,7 +102,7 @@ namespace smt { } } else - display_var_flat_def(out, s); + out << enode_pp(get_enode(s), ctx); } } out << "\n"; @@ -117,20 +116,16 @@ namespace smt { else out << "rows (expanded view):\n"; unsigned num = m_rows.size(); - for (unsigned r_id = 0; r_id < num; r_id++) { - if (m_rows[r_id].m_base_var != null_theory_var) { + for (unsigned r_id = 0; r_id < num; r_id++) + if (m_rows[r_id].m_base_var != null_theory_var) display_row(out, r_id, compact); - } - } } template void theory_arith::display_row_shape(std::ostream & out, row const & r) const { - typename vector::const_iterator it = r.begin_entries(); - typename vector::const_iterator end = r.end_entries(); - for (; it != end; ++it) { - if (!it->is_dead()) { - numeral const & c = it->m_coeff; + for (auto const& e : r) { + if (!e.is_dead()) { + numeral const & c = e.m_coeff; if (c.is_one()) out << "1"; else if (c.is_minus_one()) @@ -150,11 +145,9 @@ namespace smt { template bool theory_arith::is_one_minus_one_row(row const & r) const { - typename vector::const_iterator it = r.begin_entries(); - typename vector::const_iterator end = r.end_entries(); - for (; it != end; ++it) { - if (!it->is_dead()) { - numeral const & c = it->m_coeff; + for (auto const& e : r) { + if (!e.is_dead()) { + numeral const & c = e.m_coeff; if (!c.is_one() && !c.is_minus_one()) return false; } @@ -184,11 +177,9 @@ namespace smt { for (unsigned r_id = 0; r_id < num; r_id++) { row const & r = m_rows[r_id]; if (r.m_base_var != null_theory_var) { - typename vector::const_iterator it = r.begin_entries(); - typename vector::const_iterator end = r.end_entries(); - for (; it != end; ++it) { - if (!it->is_dead()) { - numeral const & c = it->m_coeff; + for (auto const& e : r) { + if (!e.is_dead()) { + numeral const & c = e.m_coeff; if (c.to_rational().is_big()) { std::string str = c.to_rational().to_string(); if (str.length() > 48) @@ -215,11 +206,9 @@ namespace smt { row const & r = m_rows[r_id]; if (r.m_base_var != null_theory_var) { num_rows++; - typename vector::const_iterator it = r.begin_entries(); - typename vector::const_iterator end = r.end_entries(); - for (; it != end; ++it) { - if (!it->is_dead()) { - numeral const & c = it->m_coeff; + for (auto const& e : r) { + if (!e.is_dead()) { + numeral const & c = e.m_coeff; num_non_zeros++; if (c.is_one()) num_ones++; @@ -284,11 +273,9 @@ namespace smt { template void theory_arith::display_row_info(std::ostream & out, row const & r) const { display_row(out, r, true); - typename vector::const_iterator it = r.begin_entries(); - typename vector::const_iterator end = r.end_entries(); - for (; it != end; ++it) - if (!it->is_dead()) - display_var(out, it->m_var); + for (auto const& e : r) + if (!e.is_dead()) + display_var(out, e.m_var); } /** @@ -298,15 +285,14 @@ namespace smt { void theory_arith::display_simplified_row(std::ostream & out, row const & r) const { bool has_rat_coeff = false; numeral k; - typename vector::const_iterator it = r.begin_entries(); - typename vector::const_iterator end = r.end_entries(); + out << "(v" << r.get_base_var() << ") : "; bool first = true; - for (; it != end; ++it) { - if (it->is_dead()) + for (auto const& e : r) { + if (e.is_dead()) continue; - theory_var v = it->m_var; - numeral const & c = it->m_coeff; + theory_var v = e.m_var; + numeral const & c = e.m_coeff; if (is_fixed(v)) { k += c * lower_bound(v).get_rational(); continue; @@ -328,11 +314,9 @@ namespace smt { } out << "\n"; if (has_rat_coeff) { - typename vector::const_iterator it = r.begin_entries(); - typename vector::const_iterator end = r.end_entries(); - for (; it != end; ++it) - if (!it->is_dead() && (is_base(it->m_var) || (!is_fixed(it->m_var) && (lower(it->m_var) || upper(it->m_var))))) - display_var(out, it->m_var); + for (auto const& e : r) + if (!e.is_dead() && (is_base(e.m_var) || (!is_fixed(e.m_var) && (lower(e.m_var) || upper(e.m_var))))) + display_var(out, e.m_var); } } @@ -385,8 +369,7 @@ namespace smt { out << ", shared: " << get_context().is_shared(get_enode(v)); out << ", unassigned: " << m_unassigned_atoms[v]; out << ", rel: " << get_context().is_relevant(get_enode(v)); - out << ", def: "; - display_var_flat_def(out, v); + out << ", def: " << enode_pp(get_enode(v), ctx); out << "\n"; } @@ -477,28 +460,17 @@ namespace smt { theory_var v = a->get_var(); inf_numeral const & k = a->get_k(); enode * e = get_enode(v); - if (show_sign) { - if (!a->is_true()) - out << "not "; - else - out << " "; - } + if (show_sign) + out << (a->is_true()?" ":"not "); out << "v"; out.width(3); out << std::left << v << " #"; out.width(3); out << e->get_owner_id(); out << std::right; - out << " "; - if (a->get_atom_kind() == A_LOWER) - out << ">="; - else - out << "<="; - out << " "; + out << " " << ((a->get_atom_kind() == A_LOWER)? ">=" : "<=") << " "; out.width(6); - out << k << " "; - display_var_flat_def(out, v); - out << "\n"; + out << k << " " << enode_pp(get_enode(v), ctx) << "\n"; } template diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 124461189..0abc2870d 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -173,8 +173,8 @@ class theory_lra::imp { unsigned_vector m_bounds_trail; unsigned m_asserted_qhead; - svector m_to_check; // rows that should be checked for theory propagation - + svector m_bv_to_propagate; // Boolean variables that can be propagated + svector > m_assume_eq_candidates; unsigned m_assume_eq_head; lp::u_set m_tmp_var_set; @@ -233,6 +233,7 @@ class theory_lra::imp { resource_limit m_resource_limit; lp_bounds m_new_bounds; symbol m_farkas; + vector m_bound_params; lp::lp_bound_propagator m_bp; context& ctx() const { return th.get_context(); } @@ -870,6 +871,10 @@ public: m_bound_terms(m), m_bound_predicate(m) { + m_bound_params.push_back(parameter(m_farkas)); + m_bound_params.push_back(parameter(rational(1))); + m_bound_params.push_back(parameter(rational(1))); + } ~imp() { @@ -1071,7 +1076,7 @@ public: lp().pop(num_scopes); // VERIFY(l_false != make_feasible()); m_new_bounds.reset(); - m_to_check.reset(); + m_bv_to_propagate.reset(); if (m_nla) m_nla->pop(num_scopes); TRACE("arith", tout << "num scopes: " << num_scopes << " new scope level: " << m_scopes.size() << "\n";); @@ -1493,29 +1498,24 @@ public: ctx().push_trail(value_trail(m_assume_eq_head)); while (m_assume_eq_head < m_assume_eq_candidates.size()) { - std::pair const & p = m_assume_eq_candidates[m_assume_eq_head]; - theory_var v1 = p.first; - theory_var v2 = p.second; + auto const [v1, v2] = m_assume_eq_candidates[m_assume_eq_head]; enode* n1 = get_enode(v1); enode* n2 = get_enode(v2); m_assume_eq_head++; CTRACE("arith", is_eq(v1, v2) && n1->get_root() != n2->get_root(), tout << "assuming eq: v" << v1 << " = v" << v2 << "\n";); - if (is_eq(v1, v2) && n1->get_root() != n2->get_root() && th.assume_eq(n1, n2)) { + if (is_eq(v1, v2) && n1->get_root() != n2->get_root() && th.assume_eq(n1, n2)) return true; - } } return false; } bool is_eq(theory_var v1, theory_var v2) { - if (use_nra_model()) { + if (use_nra_model()) return m_nla->am().eq(nl_value(v1, *m_a1), nl_value(v2, *m_a2)); - } - else { + else return get_ivalue(v1) == get_ivalue(v2); - } } bool has_delayed_constraints() const { @@ -1523,6 +1523,8 @@ public: } final_check_status final_check_eh() { + if (propagate_core()) + return FC_CONTINUE; m_model_is_initialized = false; IF_VERBOSE(12, verbose_stream() << "final-check " << lp().get_status() << "\n"); lbool is_sat = l_true; @@ -1534,9 +1536,7 @@ public: switch (is_sat) { case l_true: - TRACE("arith", display(tout); - /* ctx().display(tout);*/ - ); + TRACE("arith", display(tout)); switch (check_lia()) { case l_true: @@ -2048,41 +2048,59 @@ public: return false; } - bool m_new_def{ false }; + bool m_new_def = false ; + + bool adaptive() const { return ctx().get_fparams().m_arith_adaptive; } + double adaptive_assertion_threshold() const { return ctx().get_fparams().m_arith_adaptive_assertion_threshold; } + + bool process_atoms() const { + if (!adaptive()) + return true; + unsigned total_conflicts = ctx().get_num_conflicts(); + if (total_conflicts < 10) + return true; + double f = static_cast(m_num_conflicts)/static_cast(total_conflicts); + return f >= adaptive_assertion_threshold(); + } bool can_propagate() { + return process_atoms() && can_propagate_core(); + } + + bool can_propagate_core() { return m_asserted_atoms.size() > m_asserted_qhead || m_new_def; } - void propagate() { + bool propagate() { + return process_atoms() && propagate_core(); + } + + bool propagate_core() { m_model_is_initialized = false; flush_bound_axioms(); - if (!can_propagate()) { - return; - } - m_new_def = false; + if (!can_propagate_core()) + return false; + m_new_def = false; while (m_asserted_qhead < m_asserted_atoms.size() && !ctx().inconsistent() && m.inc()) { - bool_var bv = m_asserted_atoms[m_asserted_qhead].m_bv; - bool is_true = m_asserted_atoms[m_asserted_qhead].m_is_true; - m_to_check.push_back(bv); + auto [bv, is_true] = m_asserted_atoms[m_asserted_qhead]; + + m_bv_to_propagate.push_back(bv); + api_bound* b = nullptr; - TRACE("arith", tout << "propagate: " << literal(bv, !is_true) << "\n";); - if (m_bool_var2bound.find(bv, b)) { + TRACE("arith", tout << "propagate: " << literal(bv, !is_true) << "\n"; + if (!m_bool_var2bound.contains(bv)) tout << "not found\n"); + if (m_bool_var2bound.find(bv, b)) assert_bound(bv, is_true, *b); - } - else { - TRACE("arith", tout << "not found " << bv << "\n";); - } ++m_asserted_qhead; } if (ctx().inconsistent()) { - m_to_check.reset(); - return; + m_bv_to_propagate.reset(); + return true; } lbool lbl = make_feasible(); if (!m.inc()) - return; + return false; switch(lbl) { case l_false: @@ -2096,7 +2114,7 @@ public: case l_undef: break; } - + return true; } bool should_propagate() const { @@ -2246,26 +2264,28 @@ public: assign(bound, m_core, m_eqs, m_params); } - void add_eq(lpvar u, lpvar v, lp::explanation const& e) { + bool add_eq(lpvar u, lpvar v, lp::explanation const& e, bool is_fixed) { if (ctx().inconsistent()) - return; + return false; theory_var uv = lp().local_to_external(u); // variables that are returned should have external representations theory_var vv = lp().local_to_external(v); // so maybe better to have them already transformed to external form enode* n1 = get_enode(uv); enode* n2 = get_enode(vv); + TRACE("arith", tout << "add-eq " << mk_pp(n1->get_expr(), m) << " == " << mk_pp(n2->get_expr(), m) << " " << n1->get_expr_id() << " == " << n2->get_expr_id() << "\n";); if (n1->get_root() == n2->get_root()) - return; + return false; expr* e1 = n1->get_expr(); expr* e2 = n2->get_expr(); if (e1->get_sort() != e2->get_sort()) - return; - if (m.is_ite(e1) || m.is_ite(e2)) - return; + return false; + if (!is_fixed && !a.is_numeral(e1) && !a.is_numeral(e2) && (m.is_ite(e1) || m.is_ite(e2))) + return false; reset_evidence(); for (auto ev : e) set_evidence(ev.ci(), m_core, m_eqs); assign_eq(uv, vv); + return true; } literal_vector m_core2; @@ -2440,6 +2460,7 @@ public: typedef lp_bounds::iterator iterator; void flush_bound_axioms() { + CTRACE("arith", !m_new_bounds.empty(), tout << "flush bound axioms\n";); while (!m_new_bounds.empty()) { @@ -2458,7 +2479,7 @@ public: CTRACE("arith", atoms.size() > 1, for (auto* a : atoms) a->display(tout) << "\n";); lp_bounds occs(m_bounds[v]); - + std::sort(atoms.begin(), atoms.end(), compare_bounds()); std::sort(occs.begin(), occs.end(), compare_bounds()); @@ -2558,14 +2579,15 @@ public: } void propagate_basic_bounds() { - for (auto const& bv : m_to_check) { + for (auto const& bv : m_bv_to_propagate) { api_bound* b = nullptr; if (m_bool_var2bound.find(bv, b)) { propagate_bound(bv, ctx().get_assignment(bv) == l_true, *b); - if (ctx().inconsistent()) break; + if (ctx().inconsistent()) + break; } } - m_to_check.reset(); + m_bv_to_propagate.reset(); } // for glb lo': lo' < lo: @@ -2633,10 +2655,7 @@ public: ctx().display_literals_verbose(tout, m_core); ctx().display_literal_verbose(tout << " => ", lit2); tout << "\n";); - m_params.push_back(parameter(m_farkas)); - m_params.push_back(parameter(rational(1))); - m_params.push_back(parameter(rational(1))); - assign(lit2, m_core, m_eqs, m_params); + assign(lit2, m_core, m_eqs, m_bound_params); ++m_stats.m_bounds_propagations; } @@ -3194,7 +3213,7 @@ public: m_assume_eq_head = 0; m_scopes.reset(); m_stats.reset(); - m_to_check.reset(); + m_bv_to_propagate.reset(); m_model_is_initialized = false; } @@ -3661,7 +3680,7 @@ public: else if (can_get_value(v)) out << " = " << get_value(v); if (is_int(v)) out << ", int"; if (ctx().is_shared(get_enode(v))) out << ", shared"; - out << " := "; th.display_var_flat_def(out, v) << "\n"; + out << " := " << enode_pp(get_enode(v), ctx()) << "\n"; } }