3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-05-08 08:15:47 +00:00

fix a bug in the lar_solver::m_status update during push/pop

Signed-off-by: Lev Nachmanson <levnach@microsoft.com>

progress in gomory cut

Signed-off-by: Lev Nachmanson <levnach@microsoft.com>

the first version of Gomory cut, probably broken

Signed-off-by: Lev Nachmanson <levnach@microsoft.com>

rename a function

Signed-off-by: Lev Nachmanson <levnach@microsoft.com>

gomory cut worked on a toy example

Signed-off-by: Lev Nachmanson <levnach@microsoft.com>

track the set of integer variables that are not set to integer values

Signed-off-by: Lev Nachmanson <levnach@microsoft.com>
This commit is contained in:
Lev Nachmanson 2017-07-10 16:34:23 -07:00 committed by Lev Nachmanson
parent 0164ea9abb
commit aba7dcab3e
21 changed files with 682 additions and 455 deletions

View file

@ -27,10 +27,20 @@ void clear() {lp_assert(false); // not implemented
}
lar_solver::lar_solver() : m_status(OPTIMAL),
lar_solver::lar_solver() : m_status(lp_status::OPTIMAL),
m_infeasible_column_index(-1),
m_terms_start_index(1000000),
m_mpq_lar_core_solver(m_settings, *this)
m_mpq_lar_core_solver(m_settings, *this),
m_tracker_of_x_change([&](unsigned j, const impq & x){
if (!var_is_int(j)) {
lp_assert(m_inf_int_set.contains(j) == false);
return;
}
if (m_mpq_lar_core_solver.m_r_x[j].is_int())
m_inf_int_set.erase(j);
else
m_inf_int_set.insert(j);
})
{
}
@ -237,7 +247,7 @@ void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp
}
int a_sign = is_pos(a)? 1: -1;
int sign = j_sign * a_sign;
const ul_pair & ul = m_vars_to_ul_pairs[j];
const ul_pair & ul = m_columns_to_ul_pairs[j];
auto witness = sign > 0? ul.upper_bound_witness(): ul.low_bound_witness();
lp_assert(is_valid(witness));
bp.consume(a, witness);
@ -279,6 +289,10 @@ lp_status lar_solver::get_status() const { return m_status;}
void lar_solver::set_status(lp_status s) {m_status = s;}
bool lar_solver::has_int_var() const {
return m_mpq_lar_core_solver.m_r_solver.m_tracker_of_x_change != nullptr;
}
lp_status lar_solver::find_feasible_solution() {
m_settings.st().m_make_feasible++;
if (A_r().column_count() > m_settings.st().m_max_cols)
@ -288,16 +302,20 @@ lp_status lar_solver::find_feasible_solution() {
if (strategy_is_undecided())
decide_on_strategy_and_adjust_initial_state();
if (has_int_var()) {
m_inf_int_set.resize(A_r().column_count());
}
m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = true;
return solve();
}
lp_status lar_solver::solve() {
if (m_status == INFEASIBLE) {
if (m_status == lp_status::INFEASIBLE) {
return m_status;
}
solve_with_core_solver();
if (m_status != INFEASIBLE) {
if (m_status != lp_status::INFEASIBLE) {
if (m_settings.bound_propagation())
detect_rows_with_changed_bounds();
}
@ -309,7 +327,7 @@ lp_status lar_solver::solve() {
void lar_solver::fill_explanation_from_infeasible_column(vector<std::pair<mpq, constraint_index>> & evidence) const{
// this is the case when the lower bound is in conflict with the upper one
const ul_pair & ul = m_vars_to_ul_pairs[m_infeasible_column_index];
const ul_pair & ul = m_columns_to_ul_pairs[m_infeasible_column_index];
evidence.push_back(std::make_pair(numeric_traits<mpq>::one(), ul.upper_bound_witness()));
evidence.push_back(std::make_pair(-numeric_traits<mpq>::one(), ul.low_bound_witness()));
}
@ -325,8 +343,7 @@ vector<unsigned> lar_solver::get_list_of_all_var_indices() const {
void lar_solver::push() {
m_simplex_strategy = m_settings.simplex_strategy();
m_simplex_strategy.push();
m_status.push();
m_vars_to_ul_pairs.push();
m_columns_to_ul_pairs.push();
m_infeasible_column_index.push();
m_mpq_lar_core_solver.push();
m_term_count = m_terms.size();
@ -335,7 +352,7 @@ void lar_solver::push() {
m_constraint_count.push();
}
void lar_solver::clean_large_elements_after_pop(unsigned n, int_set& set) {
void lar_solver::clean_popped_elements(unsigned n, int_set& set) {
vector<int> to_remove;
for (unsigned j: set.m_index)
if (j >= n)
@ -345,29 +362,31 @@ void lar_solver::clean_large_elements_after_pop(unsigned n, int_set& set) {
}
void lar_solver::shrink_inf_set_after_pop(unsigned n, int_set & set) {
clean_large_elements_after_pop(n, set);
clean_popped_elements(n, set);
set.resize(n);
}
void lar_solver::pop(unsigned k) {
TRACE("lar_solver", tout << "k = " << k << std::endl;);
int n_was = static_cast<int>(m_ext_vars_to_columns.size());
m_status.pop(k);
m_infeasible_column_index.pop(k);
unsigned n = m_vars_to_ul_pairs.peek_size(k);
unsigned n = m_columns_to_ul_pairs.peek_size(k);
for (unsigned j = n_was; j-- > n;)
m_ext_vars_to_columns.erase(m_columns_to_ext_vars_or_term_indices[j]);
m_columns_to_ext_vars_or_term_indices.resize(n);
if (m_settings.use_tableau()) {
pop_tableau();
}
m_vars_to_ul_pairs.pop(k);
m_columns_to_ul_pairs.pop(k);
m_mpq_lar_core_solver.pop(k);
clean_large_elements_after_pop(n, m_columns_with_changed_bound);
clean_popped_elements(n, m_columns_with_changed_bound);
unsigned m = A_r().row_count();
clean_large_elements_after_pop(m, m_rows_with_changed_bounds);
clean_popped_elements(m, m_rows_with_changed_bounds);
clean_inf_set_of_r_solver_after_pop();
m_status = m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible()? lp_status::OPTIMAL: lp_status::UNKNOWN;
lp_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided ||
(!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau());
@ -404,7 +423,7 @@ bool lar_solver::maximize_term_on_tableau(const vector<std::pair<mpq, var_index>
decide_on_strategy_and_adjust_initial_state();
m_mpq_lar_core_solver.solve();
if (m_mpq_lar_core_solver.m_r_solver.get_status() == UNBOUNDED)
if (m_mpq_lar_core_solver.m_r_solver.get_status() == lp_status::UNBOUNDED)
return false;
term_max = 0;
@ -482,7 +501,7 @@ bool lar_solver::maximize_term_on_corrected_r_solver(const vector<std::pair<mpq,
bool ret = maximize_term_on_tableau(term, term_max);
settings().simplex_strategy() = simplex_strategy_enum::tableau_rows;
set_costs_to_zero(term);
m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL);
m_mpq_lar_core_solver.m_r_solver.set_status(lp_status::OPTIMAL);
return ret;
}
case simplex_strategy_enum::tableau_costs:
@ -490,7 +509,7 @@ bool lar_solver::maximize_term_on_corrected_r_solver(const vector<std::pair<mpq,
{
bool ret = maximize_term_on_tableau(term, term_max);
set_costs_to_zero(term);
m_mpq_lar_core_solver.m_r_solver.set_status(OPTIMAL);
m_mpq_lar_core_solver.m_r_solver.set_status(lp_status::OPTIMAL);
return ret;
}
@ -529,18 +548,18 @@ void lar_solver::pop_core_solver_params(unsigned k) {
void lar_solver::set_upper_bound_witness(var_index j, constraint_index ci) {
ul_pair ul = m_vars_to_ul_pairs[j];
ul_pair ul = m_columns_to_ul_pairs[j];
ul.upper_bound_witness() = ci;
m_vars_to_ul_pairs[j] = ul;
m_columns_to_ul_pairs[j] = ul;
}
void lar_solver::set_low_bound_witness(var_index j, constraint_index ci) {
ul_pair ul = m_vars_to_ul_pairs[j];
ul_pair ul = m_columns_to_ul_pairs[j];
ul.low_bound_witness() = ci;
m_vars_to_ul_pairs[j] = ul;
m_columns_to_ul_pairs[j] = ul;
}
void lar_solver::register_one_coeff_in_map(std::unordered_map<var_index, mpq> & coeffs, const mpq & a, unsigned j) {
void lar_solver::register_monoid_in_map(std::unordered_map<var_index, mpq> & coeffs, const mpq & a, unsigned j) {
auto it = coeffs.find(j);
if (it == coeffs.end()) {
coeffs[j] = a;
@ -551,18 +570,18 @@ void lar_solver::register_one_coeff_in_map(std::unordered_map<var_index, mpq> &
void lar_solver::substitute_terms_in_linear_expression(const vector<std::pair<mpq, var_index>>& left_side_with_terms,
vector<std::pair<mpq, var_index>> &left_side, mpq & right_side) const {
vector<std::pair<mpq, var_index>> &left_side, mpq & free_coeff) const {
std::unordered_map<var_index, mpq> coeffs;
for (auto & t : left_side_with_terms) {
unsigned j = t.second;
if (!is_term(j)) {
register_one_coeff_in_map(coeffs, t.first, j);
register_monoid_in_map(coeffs, t.first, j);
} else {
const lar_term & term = * m_terms[adjust_term_index(t.second)];
for (auto & p : term.coeffs()){
register_one_coeff_in_map(coeffs, t.first * p.second , p.first);
register_monoid_in_map(coeffs, t.first * p.second , p.first);
}
right_side += t.first * term.m_v;
free_coeff += t.first * term.m_v;
}
}
@ -732,7 +751,7 @@ void lar_solver::solve_with_core_solver() {
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_status != OPTIMAL || all_constraints_hold());
lp_assert(m_status != lp_status::OPTIMAL || all_constraints_hold());
}
@ -1039,11 +1058,11 @@ mpq lar_solver::sum_of_right_sides_of_explanation(const vector<std::pair<mpq, un
bool lar_solver::has_lower_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) {
if (var >= m_vars_to_ul_pairs.size()) {
if (var >= m_columns_to_ul_pairs.size()) {
// TBD: bounds on terms could also be used, caller may have to track these.
return false;
}
const ul_pair & ul = m_vars_to_ul_pairs[var];
const ul_pair & ul = m_columns_to_ul_pairs[var];
ci = ul.low_bound_witness();
if (ci != static_cast<constraint_index>(-1)) {
auto& p = m_mpq_lar_core_solver.m_r_low_bounds()[var];
@ -1058,11 +1077,11 @@ bool lar_solver::has_lower_bound(var_index var, constraint_index& ci, mpq& value
bool lar_solver::has_upper_bound(var_index var, constraint_index& ci, mpq& value, bool& is_strict) {
if (var >= m_vars_to_ul_pairs.size()) {
if (var >= m_columns_to_ul_pairs.size()) {
// TBD: bounds on terms could also be used, caller may have to track these.
return false;
}
const ul_pair & ul = m_vars_to_ul_pairs[var];
const ul_pair & ul = m_columns_to_ul_pairs[var];
ci = ul.upper_bound_witness();
if (ci != static_cast<constraint_index>(-1)) {
auto& p = m_mpq_lar_core_solver.m_r_upper_bounds()[var];
@ -1103,7 +1122,7 @@ void lar_solver::get_infeasibility_explanation_for_inf_sign(
unsigned j = it.second;
int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign;
const ul_pair & ul = m_vars_to_ul_pairs[j];
const ul_pair & ul = m_columns_to_ul_pairs[j];
constraint_index bound_constr_i = adj_sign < 0 ? ul.upper_bound_witness() : ul.low_bound_witness();
lp_assert(bound_constr_i < m_constraints.size());
@ -1113,7 +1132,7 @@ void lar_solver::get_infeasibility_explanation_for_inf_sign(
void lar_solver::get_model(std::unordered_map<var_index, mpq> & variable_values) const {
mpq delta = mpq(1, 2); // start from 0.5 to have less clashes
lp_assert(m_status == OPTIMAL);
lp_assert(m_status == lp_status::OPTIMAL);
unsigned i;
do {
@ -1188,6 +1207,13 @@ void lar_solver::print_term(lar_term const& term, std::ostream & out) const {
print_linear_combination_of_column_indices(term.coeffs_as_vector(), out);
}
void lar_solver::print_term_as_indices(lar_term const& term, std::ostream & out) const {
if (!numeric_traits<mpq>::is_zero(term.m_v)) {
out << term.m_v << " + ";
}
print_linear_combination_of_column_indices_only(term.coeffs_as_vector(), out);
}
mpq lar_solver::get_left_side_val(const lar_base_constraint & cns, const std::unordered_map<var_index, mpq> & var_map) const {
mpq ret = cns.get_free_coeff_of_left_side();
for (auto & it : cns.get_left_side_coefficients()) {
@ -1234,7 +1260,7 @@ void lar_solver::pop() {
}
bool lar_solver::column_represents_row_in_tableau(unsigned j) {
return m_vars_to_ul_pairs()[j].m_i != static_cast<row_index>(-1);
return m_columns_to_ul_pairs()[j].m_i != static_cast<row_index>(-1);
}
void lar_solver::make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j) {
@ -1353,7 +1379,7 @@ void lar_solver::pop_tableau() {
void lar_solver::clean_inf_set_of_r_solver_after_pop() {
vector<unsigned> became_feas;
clean_large_elements_after_pop(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set);
clean_popped_elements(A_r().column_count(), m_mpq_lar_core_solver.m_r_solver.m_inf_set);
std::unordered_set<unsigned> basic_columns_with_changed_cost;
auto inf_index_copy = m_mpq_lar_core_solver.m_r_solver.m_inf_set.m_index;
for (auto j: inf_index_copy) {
@ -1458,11 +1484,14 @@ var_index lar_solver::add_var(unsigned ext_j, bool is_int) {
if (it != m_ext_vars_to_columns.end()) {
return it->second.ext_j();
}
lp_assert(m_vars_to_ul_pairs.size() == A_r().column_count());
lp_assert(m_columns_to_ul_pairs.size() == A_r().column_count());
i = A_r().column_count();
m_vars_to_ul_pairs.push_back(ul_pair(static_cast<unsigned>(-1)));
m_columns_to_ul_pairs.push_back(ul_pair(static_cast<unsigned>(-1)));
add_non_basic_var_to_core_fields(ext_j, is_int);
lp_assert(sizes_are_correct());
if (is_int) {
m_mpq_lar_core_solver.m_r_solver.set_tracker_of_x(& m_tracker_of_x_change);
}
return i;
}
@ -1564,7 +1593,7 @@ void lar_solver::add_row_from_term_no_constraint(const lar_term * term, unsigned
// j will be a new variable
unsigned j = A_r().column_count();
ul_pair ul(j);
m_vars_to_ul_pairs.push_back(ul);
m_columns_to_ul_pairs.push_back(ul);
add_basic_var_to_core_fields();
if (use_tableau()) {
auto it = iterator_on_term_with_basis_var(*term, j);
@ -1598,6 +1627,7 @@ bool lar_solver::bound_is_integer_if_needed(unsigned j, const mpq & right_side)
}
constraint_index lar_solver::add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) {
TRACE("lar_solver", tout << "j = " << j << std::endl;);
constraint_index ci = m_constraints.size();
if (!is_term(j)) { // j is a var
lp_assert(bound_is_integer_if_needed(j, right_side));
@ -1672,7 +1702,7 @@ void lar_solver::add_constraint_from_term_and_create_new_column_row(unsigned ter
void lar_solver::decide_on_strategy_and_adjust_initial_state() {
lp_assert(strategy_is_undecided());
if (m_vars_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) {
if (m_columns_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) {
m_settings.simplex_strategy() = simplex_strategy_enum::lu;
}
else {
@ -1816,7 +1846,7 @@ void lar_solver::update_upper_bound_column_type_and_bound(var_index j, lconstrai
set_low_bound_witness(j, ci);
m_columns_with_changed_bound.insert(j);
if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_status = lp_status::INFEASIBLE;
m_infeasible_column_index = j;
}
else {
@ -1828,7 +1858,7 @@ void lar_solver::update_upper_bound_column_type_and_bound(var_index j, lconstrai
{
auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_status = lp_status::INFEASIBLE;
set_low_bound_witness(j, ci);
m_infeasible_column_index = j;
}
@ -1850,7 +1880,7 @@ void lar_solver::update_upper_bound_column_type_and_bound(var_index j, lconstrai
}
void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
lp_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]));
lp_assert(m_status == lp_status::INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]));
mpq y_of_bound(0);
switch (kind) {
case LT:
@ -1865,7 +1895,7 @@ void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kin
}
if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_status = lp_status::INFEASIBLE;
lp_assert(false);
m_infeasible_column_index = j;
}
@ -1886,7 +1916,7 @@ void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kin
set_low_bound_witness(j, ci);
}
if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_status = lp_status::INFEASIBLE;
m_infeasible_column_index = j;
}
else if (low == m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
@ -1898,12 +1928,12 @@ void lar_solver::update_boxed_column_type_and_bound(var_index j, lconstraint_kin
{
auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_status = lp_status::INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
}
else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_status = lp_status::INFEASIBLE;
m_infeasible_column_index = j;
set_low_bound_witness(j, ci);
}
@ -1937,7 +1967,7 @@ void lar_solver::update_low_bound_column_type_and_bound(var_index j, lconstraint
m_columns_with_changed_bound.insert(j);
if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_status = lp_status::INFEASIBLE;
m_infeasible_column_index = j;
}
else {
@ -1961,7 +1991,7 @@ void lar_solver::update_low_bound_column_type_and_bound(var_index j, lconstraint
{
auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_status = lp_status::INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
}
@ -1982,15 +2012,15 @@ void lar_solver::update_low_bound_column_type_and_bound(var_index j, lconstraint
}
void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
lp_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j]));
lp_assert(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero()));
lp_assert(m_status == lp_status::INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j]));
lp_assert(m_status == lp_status::INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero()));
auto v = numeric_pair<mpq>(right_side, mpq(0));
mpq y_of_bound(0);
switch (kind) {
case LT:
if (v <= m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_status = lp_status::INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
}
@ -1998,7 +2028,7 @@ void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kin
case LE:
{
if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_status = lp_status::INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
}
@ -2007,7 +2037,7 @@ void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kin
case GT:
{
if (v >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_status = lp_status::INFEASIBLE;
m_infeasible_column_index = j;
set_low_bound_witness(j, ci);
}
@ -2016,7 +2046,7 @@ void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kin
case GE:
{
if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_status = lp_status::INFEASIBLE;
m_infeasible_column_index = j;
set_low_bound_witness(j, ci);
}
@ -2025,12 +2055,12 @@ void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kin
case EQ:
{
if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
m_status = INFEASIBLE;
m_status = lp_status::INFEASIBLE;
m_infeasible_column_index = j;
set_upper_bound_witness(j, ci);
}
else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
m_status = INFEASIBLE;
m_status = lp_status::INFEASIBLE;
m_infeasible_column_index = j;
set_low_bound_witness(j, ci);
}