From fc6a876845a414e8591919ea18ad81304703ab2c Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 11 Jul 2017 13:38:59 -0700 Subject: [PATCH] start gomory cut Signed-off-by: Lev Nachmanson --- src/smt/theory_lra.cpp | 5 +++ src/util/lp/int_solver.cpp | 79 ++++++++++++++++++++++++-------------- src/util/lp/int_solver.h | 9 ++++- 3 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index e2b4ea944..b0404e126 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -1252,6 +1252,11 @@ namespace smt { // SAT core assigns a value to return l_false; } + case lp::lia_move::bound: { + // todo nikolaj + // Need to set a bound >= k on the only var from the term + return l_false; + } case lp::lia_move::cut: { // m_explanation implies term <= k app_ref b = mk_bound(term, k); diff --git a/src/util/lp/int_solver.cpp b/src/util/lp/int_solver.cpp index 176d67733..c4c477dfb 100644 --- a/src/util/lp/int_solver.cpp +++ b/src/util/lp/int_solver.cpp @@ -110,26 +110,21 @@ int int_solver::find_inf_int_boxed_base_column_with_smallest_range() { } -bool int_solver::mk_gomory_cut(unsigned row_index, explanation & ex) { + /** + \brief Create bounds for (non base) free vars in the given row. + Return true if at least one variable was constrained. + This method is used to enable the application of gomory cuts. + */ - auto row_it = m_lar_solver->get_iterator_on_row(row_index); + + +lia_move int_solver::mk_gomory_cut(explanation & ex) { + + lp_assert(column_is_int_inf(m_gomory_cut_inf_column)); + + return lia_move::give_up; - unsigned x_i = m_lar_solver->get_base_column_in_row(row_index); - - lp_assert(column_is_int_inf(x_i)); /* - SASSERT(is_int(x_i)); - // The following assertion is wrong. It may be violated in mixed-real-interger problems. - // The check is_gomory_cut_target will discard rows where any variable contains infinitesimals. - // SASSERT(m_value[x_i].is_rational()); // infinitesimals are not used for integer variables - SASSERT(!m_value[x_i].is_int()); // the base variable is not assigned to an integer value. - - if (constrain_free_vars(r) || !is_gomory_cut_target(r)) { - TRACE("gomory_cut", tout << "failed to apply gomory cut:\n"; - tout << "constrain_free_vars(r): " << constrain_free_vars(r) << "\n";); - return false; - } - TRACE("gomory_cut", tout << "applying cut at:\n"; display_row_info(tout, r);); antecedents ante(*this); @@ -287,9 +282,6 @@ bool int_solver::mk_gomory_cut(unsigned row_index, explanation & ex) { ante.eqs().size(), ante.eqs().c_ptr(), ante, l))); return true; */ - delete row_it; - return true; - } void int_solver::init_check_data() { @@ -299,9 +291,35 @@ void int_solver::init_check_data() { m_old_values_data.resize(n); } +int int_solver::find_next_free_var_in_gomory_row() { + lp_assert(m_iter_on_gomory_row != nullptr); + unsigned j; + while(m_iter_on_gomory_row->next(j)) { + if (is_free(j)) + return static_cast(j); + } + return -1; +} + +lia_move int_solver::proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex) { + int j = find_next_free_var_in_gomory_row(); + if (j != -1) { + lp_assert(t.is_empty()); + t.add_to_map(j, mpq(1)); + k = zero_of_type(); + return lia_move::bound; + } + delete m_iter_on_gomory_row; + m_iter_on_gomory_row = nullptr; + return mk_gomory_cut(ex); + } + + lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { - lp_assert(m_lar_solver->m_mpq_lar_core_solver.r_basis_is_OK()); - lp_assert(is_feasible()); + if (m_iter_on_gomory_row != nullptr) { + return proceed_with_gomory_cut(t, k, ex); + } + init_check_data(); lp_assert(inf_int_set_is_correct()); // currently it is a reimplementation of @@ -333,13 +351,12 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) { } int j = find_inf_int_base_column(); if (j != -1) { + // setup the call for gomory cut TRACE("arith_int", tout << "j = " << j << " does not have an integer assignment: " << get_value(j) << "\n";); unsigned row_index = m_lar_solver->m_mpq_lar_core_solver.m_r_heading[j]; - if (!mk_gomory_cut(row_index, ex)) { - return lia_move::give_up; - // silent failure - } - return lia_move::cut; + m_iter_on_gomory_row = m_lar_solver->get_iterator_on_row(row_index); + m_gomory_cut_inf_column = j; + return check(t, k, ex); } } else { @@ -623,7 +640,8 @@ linear_combination_iterator * int_solver::get_column_iterator(unsigned j) { int_solver::int_solver(lar_solver* lar_slv) : m_lar_solver(lar_slv), - m_branch_cut_counter(0) { + m_branch_cut_counter(0), + m_iter_on_gomory_row(nullptr) { lp_assert(m_old_values_set.size() == 0); m_old_values_set.resize(lar_slv->A_r().column_count()); m_old_values_data.resize(lar_slv->A_r().column_count(), zero_of_type()); @@ -810,6 +828,11 @@ bool int_solver::is_boxed(unsigned j) const { return m_lar_solver->m_mpq_lar_core_solver.m_column_types[j] == column_type::boxed; } +bool int_solver::is_free(unsigned j) const { + return m_lar_solver->m_mpq_lar_core_solver.m_column_types[j] == column_type::free_column; +} + + lp_settings& int_solver::settings() { return m_lar_solver->settings(); } diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h index 1d1a1dc69..1ae0ecbd8 100644 --- a/src/util/lp/int_solver.h +++ b/src/util/lp/int_solver.h @@ -18,6 +18,7 @@ enum class lia_move { branch, cut, conflict, + bound, give_up }; @@ -33,6 +34,8 @@ public: vector m_old_values_data; int_set m_inf_int_set; unsigned m_branch_cut_counter; + linear_combination_iterator* m_iter_on_gomory_row; + unsigned m_gomory_cut_inf_column; // methods int_solver(lar_solver* lp); // main function to check that solution provided by lar_solver is valid for integral values, @@ -80,6 +83,7 @@ private: bool is_int(unsigned j) const; bool is_base(unsigned j) const; bool is_boxed(unsigned j) const; + bool is_free(unsigned j) const; bool value_is_int(unsigned j) const; void set_value_for_nbasic_column(unsigned j, const impq & new_val); void fix_non_base_columns(); @@ -97,7 +101,10 @@ private: lp_settings& settings(); void move_non_base_vars_to_bounds(); void branch_infeasible_int_var(unsigned); - bool mk_gomory_cut(unsigned row_index, explanation & ex); + lia_move mk_gomory_cut(explanation & ex); void init_check_data(); + bool constrain_free_vars(linear_combination_iterator * r); + lia_move proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex); + int find_next_free_var_in_gomory_row(); }; }