3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-07-19 10:52:02 +00:00

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-21 21:09:51 -07:00
parent 64e542bd70
commit bd4fb22665
9 changed files with 66 additions and 32 deletions

View file

@ -21,7 +21,6 @@ void int_solver::fix_non_base_columns() {
return; return;
if (m_lar_solver->find_feasible_solution() == lp_status::INFEASIBLE) if (m_lar_solver->find_feasible_solution() == lp_status::INFEASIBLE)
failed(); failed();
init_inf_int_set();
lp_assert(is_feasible() && inf_int_set_is_correct()); lp_assert(is_feasible() && inf_int_set_is_correct());
} }
@ -61,14 +60,22 @@ void int_solver::trace_inf_rows() const {
); );
} }
int_set& int_solver::inf_int_set() {
return m_lar_solver->m_inf_int_set;
}
const int_set& int_solver::inf_int_set() const {
return m_lar_solver->m_inf_int_set;
}
int int_solver::find_inf_int_base_column() { int int_solver::find_inf_int_base_column() {
if (m_inf_int_set.is_empty()) if (inf_int_set().is_empty())
return -1; return -1;
int j = find_inf_int_boxed_base_column_with_smallest_range(); int j = find_inf_int_boxed_base_column_with_smallest_range();
if (j != -1) if (j != -1)
return j; return j;
unsigned k = settings().random_next() % m_inf_int_set.m_index.size(); unsigned k = settings().random_next() % inf_int_set().m_index.size();
return m_inf_int_set.m_index[k]; return inf_int_set().m_index[k];
} }
int int_solver::find_inf_int_boxed_base_column_with_smallest_range() { int int_solver::find_inf_int_boxed_base_column_with_smallest_range() {
@ -79,7 +86,7 @@ int int_solver::find_inf_int_boxed_base_column_with_smallest_range() {
unsigned n = 0; unsigned n = 0;
lar_core_solver & lcs = m_lar_solver->m_mpq_lar_core_solver; lar_core_solver & lcs = m_lar_solver->m_mpq_lar_core_solver;
for (int j : m_inf_int_set.m_index) { for (int j : inf_int_set().m_index) {
lp_assert(is_base(j) && column_is_int_inf(j)); lp_assert(is_base(j) && column_is_int_inf(j));
if (!is_boxed(j)) if (!is_boxed(j))
continue; continue;
@ -331,7 +338,6 @@ lia_move int_solver::mk_gomory_cut(lar_term& t, mpq& k, explanation & expl) {
} }
void int_solver::init_check_data() { void int_solver::init_check_data() {
init_inf_int_set();
unsigned n = m_lar_solver->A_r().column_count(); unsigned n = m_lar_solver->A_r().column_count();
m_old_values_set.resize(n); m_old_values_set.resize(n);
m_old_values_data.resize(n); m_old_values_data.resize(n);
@ -402,12 +408,13 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) {
if ((++m_branch_cut_counter) % settings().m_int_branch_cut_threshold == 0) { if ((++m_branch_cut_counter) % settings().m_int_branch_cut_threshold == 0) {
move_non_base_vars_to_bounds(); move_non_base_vars_to_bounds(); // todo track changed variables
lp_status st = m_lar_solver->find_feasible_solution(); lp_status st = m_lar_solver->find_feasible_solution();
if (st != lp_status::FEASIBLE && st != lp_status::OPTIMAL) { if (st != lp_status::FEASIBLE && st != lp_status::OPTIMAL) {
return lia_move::give_up; return lia_move::give_up;
} }
init_inf_int_set(); // todo - can we avoid this call? lp_assert(inf_int_set_is_correct());
// init_inf_int_set(); // todo - can we avoid this call?
int j = find_inf_int_base_column(); int j = find_inf_int_base_column();
if (j != -1) { if (j != -1) {
// setup the call for gomory cut // setup the call for gomory cut
@ -862,7 +869,7 @@ void int_solver::display_column(std::ostream & out, unsigned j) const {
bool int_solver::inf_int_set_is_correct() const { bool int_solver::inf_int_set_is_correct() const {
for (unsigned j = 0; j < m_lar_solver->A_r().column_count(); j++) { for (unsigned j = 0; j < m_lar_solver->A_r().column_count(); j++) {
if (m_inf_int_set.contains(j) != (is_int(j) && (!value_is_int(j)))) if (inf_int_set().contains(j) != (is_int(j) && (!value_is_int(j))))
return false; return false;
} }
return true; return true;
@ -872,20 +879,11 @@ bool int_solver::column_is_int_inf(unsigned j) const {
return is_int(j) && (!value_is_int(j)); return is_int(j) && (!value_is_int(j));
} }
void int_solver::init_inf_int_set() {
m_inf_int_set.clear();
m_inf_int_set.resize(m_lar_solver->A_r().column_count());
for (unsigned j = 0; j < m_lar_solver->A_r().column_count(); j++) {
if (column_is_int_inf(j))
m_inf_int_set.insert(j);
}
}
void int_solver::update_column_in_int_inf_set(unsigned j) { void int_solver::update_column_in_int_inf_set(unsigned j) {
if (is_int(j) && (!value_is_int(j))) if (is_int(j) && (!value_is_int(j)))
m_inf_int_set.insert(j); inf_int_set().insert(j);
else else
m_inf_int_set.erase(j); inf_int_set().erase(j);
} }
bool int_solver::is_base(unsigned j) const { bool int_solver::is_base(unsigned j) const {

View file

@ -34,13 +34,15 @@ public:
lar_solver *m_lar_solver; lar_solver *m_lar_solver;
int_set m_old_values_set; int_set m_old_values_set;
vector<impq> m_old_values_data; vector<impq> m_old_values_data;
int_set m_inf_int_set;
unsigned m_branch_cut_counter; unsigned m_branch_cut_counter;
linear_combination_iterator<mpq>* m_iter_on_gomory_row; linear_combination_iterator<mpq>* m_iter_on_gomory_row;
unsigned m_gomory_cut_inf_column; unsigned m_gomory_cut_inf_column;
bool m_found_free_var_in_gomory_row; bool m_found_free_var_in_gomory_row;
// methods // methods
int_solver(lar_solver* lp); int_solver(lar_solver* lp);
int_set& inf_int_set();
const int_set& inf_int_set() const;
// main function to check that solution provided by lar_solver is valid for integral values, // main function to check that solution provided by lar_solver is valid for integral values,
// or provide a way of how it can be adjusted. // or provide a way of how it can be adjusted.
lia_move check(lar_term& t, mpq& k, explanation& ex); lia_move check(lar_term& t, mpq& k, explanation& ex);
@ -96,7 +98,6 @@ private:
const impq & get_value(unsigned j) const; const impq & get_value(unsigned j) const;
void display_column(std::ostream & out, unsigned j) const; void display_column(std::ostream & out, unsigned j) const;
bool inf_int_set_is_correct() const; bool inf_int_set_is_correct() const;
void init_inf_int_set();
void update_column_in_int_inf_set(unsigned j); void update_column_in_int_inf_set(unsigned j);
bool column_is_int_inf(unsigned j) const; bool column_is_int_inf(unsigned j) const;
void trace_inf_rows() const; void trace_inf_rows() const;

View file

@ -30,7 +30,17 @@ void clear() {lp_assert(false); // not implemented
lar_solver::lar_solver() : m_status(lp_status::OPTIMAL), lar_solver::lar_solver() : m_status(lp_status::OPTIMAL),
m_infeasible_column_index(-1), m_infeasible_column_index(-1),
m_terms_start_index(1000000), 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);
})
{ {
} }
@ -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;} 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() { lp_status lar_solver::find_feasible_solution() {
m_settings.st().m_make_feasible++; m_settings.st().m_make_feasible++;
if (A_r().column_count() > m_settings.st().m_max_cols) if (A_r().column_count() > m_settings.st().m_max_cols)
@ -288,6 +302,10 @@ lp_status lar_solver::find_feasible_solution() {
if (strategy_is_undecided()) if (strategy_is_undecided())
decide_on_strategy_and_adjust_initial_state(); 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; m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = true;
return solve(); return solve();
} }
@ -1474,6 +1492,9 @@ var_index lar_solver::add_var(unsigned ext_j, bool is_int) {
m_columns_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); add_non_basic_var_to_core_fields(ext_j, is_int);
lp_assert(sizes_are_correct()); 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; return i;
} }

View file

@ -68,7 +68,8 @@ public:
lar_core_solver m_mpq_lar_core_solver; lar_core_solver m_mpq_lar_core_solver;
unsigned constraint_count() const; unsigned constraint_count() const;
const lar_base_constraint& get_constraint(unsigned ci) const; const lar_base_constraint& get_constraint(unsigned ci) const;
std::function<void (unsigned, const impq&)> m_tracker_of_x_change;
int_set m_inf_int_set;
////////////////// methods //////////////////////////////// ////////////////// methods ////////////////////////////////
static_matrix<mpq, numeric_pair<mpq>> & A_r(); static_matrix<mpq, numeric_pair<mpq>> & A_r();
static_matrix<mpq, numeric_pair<mpq>> const & A_r() const; static_matrix<mpq, numeric_pair<mpq>> const & A_r() const;
@ -473,5 +474,7 @@ public:
t.clear(); t.clear();
t = lar_term(pol_after_subs, v); t = lar_term(pol_after_subs, v);
} }
bool has_int_var() const;
}; };
} }

View file

@ -69,6 +69,12 @@ public:
bool m_tracing_basis_changes; bool m_tracing_basis_changes;
int_set* m_pivoted_rows; int_set* m_pivoted_rows;
bool m_look_for_feasible_solution_only; bool m_look_for_feasible_solution_only;
std::function<void (unsigned, const X &)> * m_tracker_of_x_change;
void set_tracker_of_x(std::function<void (unsigned, const X&)>* tracker) {
m_tracker_of_x_change = tracker;
}
void start_tracing_basis_changes() { void start_tracing_basis_changes() {
m_trace_of_basis_change_vector.resize(0); m_trace_of_basis_change_vector.resize(0);
m_tracing_basis_changes = true; m_tracing_basis_changes = true;
@ -670,16 +676,20 @@ public:
void update_column_in_inf_set(unsigned j) { void update_column_in_inf_set(unsigned j) {
if (column_is_feasible(j)) { if (column_is_feasible(j)) {
m_inf_set.erase(j); remove_column_from_inf_set(j);
} else { } else {
m_inf_set.insert(j); insert_column_into_inf_set(j);
} }
} }
void insert_column_into_inf_set(unsigned j) { void insert_column_into_inf_set(unsigned j) {
if (m_tracker_of_x_change != nullptr)
(*m_tracker_of_x_change)(j, m_x[j]);
m_inf_set.insert(j); m_inf_set.insert(j);
lp_assert(!column_is_feasible(j)); lp_assert(!column_is_feasible(j));
} }
void remove_column_from_inf_set(unsigned j) { void remove_column_from_inf_set(unsigned j) {
if (m_tracker_of_x_change != nullptr)
(*m_tracker_of_x_change)(j, m_x[j]);
m_inf_set.erase(j); m_inf_set.erase(j);
lp_assert(column_is_feasible(j)); lp_assert(column_is_feasible(j));
} }

View file

@ -52,7 +52,8 @@ lp_core_solver_base(static_matrix<T, X> & A,
m_steepest_edge_coefficients(A.column_count()), m_steepest_edge_coefficients(A.column_count()),
m_tracing_basis_changes(false), m_tracing_basis_changes(false),
m_pivoted_rows(nullptr), m_pivoted_rows(nullptr),
m_look_for_feasible_solution_only(false) { m_look_for_feasible_solution_only(false),
m_tracker_of_x_change(nullptr) {
lp_assert(bounds_for_boxed_are_set_correctly()); lp_assert(bounds_for_boxed_are_set_correctly());
init(); init();
init_basis_heading_and_non_basic_columns_vector(); init_basis_heading_and_non_basic_columns_vector();

View file

@ -779,7 +779,7 @@ public:
if (this->m_basis_heading[j] < 0) if (this->m_basis_heading[j] < 0)
continue; continue;
if (!this->column_is_feasible(j)) if (!this->column_is_feasible(j))
this->m_inf_set.insert(j); this->insert_column_into_inf_set(j);
} }
} }

View file

@ -1197,9 +1197,9 @@ lp_primal_core_solver<T, X>::init_infeasibility_cost_for_column(unsigned j) {
} }
if (numeric_traits<T>::is_zero(this->m_costs[j])) { if (numeric_traits<T>::is_zero(this->m_costs[j])) {
this->m_inf_set.erase(j); this->remove_column_from_inf_set(j);
} else { } else {
this->m_inf_set.insert(j); this->insert_column_into_inf_set(j);
} }
if (!this->m_settings.use_breakpoints_in_feasibility_search) { if (!this->m_settings.use_breakpoints_in_feasibility_search) {
this->m_costs[j] = - this->m_costs[j]; this->m_costs[j] = - this->m_costs[j];

View file

@ -349,9 +349,9 @@ update_x_tableau(unsigned entering, const X& delta) {
this->m_x[j] -= delta * this->m_A.get_val(c); this->m_x[j] -= delta * this->m_A.get_val(c);
update_inf_cost_for_column_tableau(j); update_inf_cost_for_column_tableau(j);
if (is_zero(this->m_costs[j])) if (is_zero(this->m_costs[j]))
this->m_inf_set.erase(j); this->remove_column_from_inf_set(j);
else else
this->m_inf_set.insert(j); this->insert_column_into_inf_set(j);
} }
} }
lp_assert(this->A_mult_x_is_off() == false); lp_assert(this->A_mult_x_is_off() == false);