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

cleanup in hnf.h

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

fixex in maximize_term

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

prepare for LIRA (#76)

* merge

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* simple mixed integer example

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

Nikolaj's fixes in theory_lra.cpp

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

fixes in maximize_term, disable find_cube for mixed case

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

fix cube heuristic for the mixed case

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

fix the build

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

fix in find cube delta's calculation

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

remove a printout

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

remove a blank line

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

test credentials

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

avoid double checks to add terms in hnf_cutter

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

fixes in add terms to hnf_cutter

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

remove a variable used for debug only

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

remove a field

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

remove a warning and hide m_A_orig under debug

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

use var_register to deal with mapping between external and local variables

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

tighten the loop in explain_implied_bound

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

fixes in theory_lra and relaxing debug checks in pop(), for the case when push() has been done from not fully initialized state

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

suppress hnf cutter when the numbers become too large

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

remove some debug code

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

adjusting hnf

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
Lev Nachmanson 2018-06-08 15:05:08 -07:00
parent 9ba4026bc6
commit eeaca949e0
13 changed files with 424 additions and 260 deletions

View file

@ -31,8 +31,7 @@ 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_int_solver(nullptr),
m_has_int_var(false)
m_int_solver(nullptr)
{}
void lar_solver::set_track_pivoted_rows(bool v) {
@ -199,7 +198,7 @@ void lar_solver::calculate_implied_bounds_for_row(unsigned i, bound_propagator &
}
unsigned lar_solver::adjust_column_index_to_term_index(unsigned j) const {
unsigned ext_var_or_term = m_columns_to_ext_vars_or_term_indices[j];
unsigned ext_var_or_term = m_var_register.local_to_external(j);
return ext_var_or_term < m_terms_start_index ? j : ext_var_or_term;
}
@ -212,21 +211,14 @@ void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp
unsigned i = ib.m_row_or_term_index;
int bound_sign = ib.m_is_lower_bound? 1: -1;
int j_sign = (ib.m_coeff_before_j_is_pos ? 1 :-1) * bound_sign;
unsigned m_j = ib.m_j;
if (is_term(m_j)) {
auto it = m_ext_vars_to_columns.find(m_j);
lp_assert(it != m_ext_vars_to_columns.end());
m_j = it->second.internal_j();
unsigned bound_j = ib.m_j;
if (is_term(bound_j)) {
bound_j = m_var_register.external_to_local(bound_j);
}
for (auto const& r : A_r().m_rows[i]) {
unsigned j = r.m_j;
mpq const& a = r.get_val();
if (j == m_j) continue;
if (is_term(j)) {
auto it = m_ext_vars_to_columns.find(j);
lp_assert(it != m_ext_vars_to_columns.end());
j = it->second.internal_j();
}
mpq const& a = r.get_val();
int a_sign = is_pos(a)? 1: -1;
int sign = j_sign * a_sign;
const ul_pair & ul = m_columns_to_ul_pairs[j];
@ -240,7 +232,7 @@ void lar_solver::explain_implied_bound(implied_bound & ib, bound_propagator & bp
bool lar_solver::term_is_used_as_row(unsigned term) const {
lp_assert(is_term(term));
return contains(m_ext_vars_to_columns, term);
return m_var_register.external_is_used(term);
}
void lar_solver::propagate_bounds_on_terms(bound_propagator & bp) {
@ -273,10 +265,6 @@ 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_has_int_var;
}
lp_status lar_solver::find_feasible_solution() {
m_settings.st().m_make_feasible++;
if (A_r().column_count() > m_settings.st().m_max_cols)
@ -352,12 +340,9 @@ void lar_solver::pop(unsigned k) {
TRACE("arith_int", tout << "pop" << std::endl;);
TRACE("lar_solver", tout << "k = " << k << std::endl;);
int n_was = static_cast<int>(m_ext_vars_to_columns.size());
m_infeasible_column_index.pop(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);
m_var_register.shrink(n);
TRACE("arith_int", tout << "pop" << std::endl;);
if (m_settings.use_tableau()) {
pop_tableau();
@ -375,7 +360,6 @@ void lar_solver::pop(unsigned k) {
lp_assert(ax_is_correct());
lp_assert(m_mpq_lar_core_solver.m_r_solver.inf_set_is_correct());
m_constraint_count.pop(k);
for (unsigned i = m_constraint_count; i < m_constraints.size(); i++)
delete m_constraints[i];
@ -404,18 +388,17 @@ vector<constraint_index> lar_solver::get_all_constraint_indices() const {
return ret;
}
bool lar_solver::maximize_term_on_tableau(const vector<std::pair<mpq, var_index>> & term,
bool lar_solver::maximize_term_on_tableau(const lar_term & term,
impq &term_max) {
if (settings().simplex_strategy() == simplex_strategy_enum::undecided)
decide_on_strategy_and_adjust_initial_state();
m_mpq_lar_core_solver.m_r_solver.set_status(lp_status::FEASIBLE);
m_mpq_lar_core_solver.solve();
if (m_mpq_lar_core_solver.m_r_solver.get_status() == lp_status::UNBOUNDED)
return false;
term_max = 0;
for (auto & p : term)
term_max += p.first * m_mpq_lar_core_solver.m_r_x[p.second];
term_max = term.apply(m_mpq_lar_core_solver.m_r_x);
return true;
}
@ -433,13 +416,13 @@ bool lar_solver::reduced_costs_are_zeroes_for_r_solver() const {
return true;
}
void lar_solver::set_costs_to_zero(const vector<std::pair<mpq, var_index>> & term) {
void lar_solver::set_costs_to_zero(const lar_term& term) {
auto & rslv = m_mpq_lar_core_solver.m_r_solver;
auto & jset = m_mpq_lar_core_solver.m_r_solver.m_inf_set; // hijack this set that should be empty right now
lp_assert(jset.m_index.size()==0);
for (auto & p : term) {
unsigned j = p.second;
for (const auto & p : term) {
unsigned j = p.var();
rslv.m_costs[j] = zero_of_type<mpq>();
int i = rslv.m_basis_heading[j];
if (i < 0)
@ -459,25 +442,25 @@ void lar_solver::set_costs_to_zero(const vector<std::pair<mpq, var_index>> & ter
lp_assert(costs_are_zeros_for_r_solver());
}
void lar_solver::prepare_costs_for_r_solver(const vector<std::pair<mpq, var_index>> & term) {
void lar_solver::prepare_costs_for_r_solver(const lar_term & term) {
auto & rslv = m_mpq_lar_core_solver.m_r_solver;
rslv.m_using_infeas_costs = false;
lp_assert(costs_are_zeros_for_r_solver());
lp_assert(reduced_costs_are_zeroes_for_r_solver());
rslv.m_costs.resize(A_r().column_count(), zero_of_type<mpq>());
for (auto & p : term) {
unsigned j = p.second;
rslv.m_costs[j] = p.first;
for (const auto & p : term) {
unsigned j = p.var();
rslv.m_costs[j] = p.coeff();
if (rslv.m_basis_heading[j] < 0)
rslv.m_d[j] += p.first;
rslv.m_d[j] += p.coeff();
else
rslv.update_reduced_cost_for_basic_column_cost_change(- p.first, j);
rslv.update_reduced_cost_for_basic_column_cost_change(- p.coeff(), j);
}
lp_assert(rslv.reduced_costs_are_correct_tableau());
}
bool lar_solver::maximize_term_on_corrected_r_solver(const vector<std::pair<mpq, var_index>> & term,
bool lar_solver::maximize_term_on_corrected_r_solver(lar_term & term,
impq &term_max) {
settings().backup_costs = false;
switch (settings().simplex_strategy()) {
@ -514,16 +497,35 @@ bool lar_solver::remove_from_basis(unsigned j) {
return m_mpq_lar_core_solver.m_r_solver.remove_from_basis(j);
}
lar_term lar_solver::get_term_to_maximize(unsigned ext_j) const {
unsigned local_j;
if (m_var_register.external_is_used(ext_j, local_j)) {
lar_term r;
r. add_monomial(one_of_type<mpq>(), local_j);
return r;
}
return get_term(ext_j);
}
// starting from a given feasible state look for the maximum of the term
// return true if found and false if unbounded
lp_status lar_solver::maximize_term(const vector<std::pair<mpq, var_index>> & term,
lp_status lar_solver::maximize_term(unsigned ext_j,
impq &term_max) {
lp_assert(m_mpq_lar_core_solver.m_r_solver.current_x_is_feasible());
bool was_feasible = m_mpq_lar_core_solver.m_r_solver.calc_current_x_is_feasible_include_non_basis();
impq prev_value;
lar_term term = get_term_to_maximize(ext_j);
auto backup = m_mpq_lar_core_solver.m_r_x;
if (was_feasible) {
prev_value = term.apply(m_mpq_lar_core_solver.m_r_x);
}
m_mpq_lar_core_solver.m_r_solver.m_look_for_feasible_solution_only = false;
if (!maximize_term_on_corrected_r_solver(term, term_max))
if (!maximize_term_on_corrected_r_solver(term, term_max)) {
m_mpq_lar_core_solver.m_r_x = backup;
return lp_status::UNBOUNDED;
}
impq opt_val = term_max;
bool change = false;
for (unsigned j = 0; j < m_mpq_lar_core_solver.m_r_x.size(); j++) {
if (!column_is_int(j))
@ -534,18 +536,19 @@ lp_status lar_solver::maximize_term(const vector<std::pair<mpq, var_index>> & te
if (!remove_from_basis(j)) // consider a special version of remove_from_basis that would not remove inf_int columns
return lp_status::FEASIBLE; // it should not happen
}
m_int_solver->patch_nbasic_column(j);
m_int_solver->patch_nbasic_column(j, false);
if (!column_value_is_integer(j))
return lp_status::FEASIBLE;
change = true;
}
if (change) {
term_max = zero_of_type<impq>();
for (const auto& p : term) {
term_max += p.first * m_mpq_lar_core_solver.m_r_x[p.second];
}
term_max = term.apply(m_mpq_lar_core_solver.m_r_x);
}
return lp_status::OPTIMAL;
if (was_feasible && term_max < prev_value) {
term_max = prev_value;
m_mpq_lar_core_solver.m_r_x = backup;
}
return term_max == opt_val? lp_status::OPTIMAL :lp_status::FEASIBLE;
}
@ -907,10 +910,10 @@ column_type lar_solver::get_column_type(const column_info<mpq> & ci) {
std::string lar_solver::get_column_name(unsigned j) const {
if (j >= m_terms_start_index)
return std::string("_t") + T_to_string(j);
if (j >= m_columns_to_ext_vars_or_term_indices.size())
if (j >= m_var_register.size())
return std::string("_s") + T_to_string(j);
return std::string("v") + T_to_string(m_columns_to_ext_vars_or_term_indices[j]);
return std::string("v") + T_to_string(m_var_register.local_to_external(j));
}
bool lar_solver::all_constrained_variables_are_registered(const vector<std::pair<mpq, var_index>>& left_side) {
@ -1392,7 +1395,8 @@ void lar_solver::pop_tableau() {
lp_assert(m_mpq_lar_core_solver.m_r_solver.basis_heading_is_correct());
// We remove last variables starting from m_column_names.size() to m_vec_of_canonic_left_sides.size().
// At this moment m_column_names is already popped
while (A_r().column_count() > m_columns_to_ext_vars_or_term_indices.size())
unsigned size = m_var_register.size();
while (A_r().column_count() > size)
remove_last_column_from_tableau();
lp_assert(m_mpq_lar_core_solver.m_r_solver.m_costs.size() == A_r().column_count());
lp_assert(m_mpq_lar_core_solver.m_r_solver.m_basis.size() == A_r().row_count());
@ -1469,9 +1473,7 @@ bool lar_solver::var_is_int(var_index v) const {
}
bool lar_solver::column_is_int(unsigned j) const {
unsigned ext_var = m_columns_to_ext_vars_or_term_indices[j];
lp_assert(contains(m_ext_vars_to_columns, ext_var));
return m_ext_vars_to_columns.find(ext_var)->second.is_integer();
return m_var_register.local_is_int(j);
}
bool lar_solver::column_is_fixed(unsigned j) const {
@ -1480,9 +1482,7 @@ bool lar_solver::column_is_fixed(unsigned j) const {
bool lar_solver::ext_var_is_int(var_index ext_var) const {
auto it = m_ext_vars_to_columns.find(ext_var);
lp_assert(it != m_ext_vars_to_columns.end());
return it->second.is_integer();
return m_var_register.external_is_int(ext_var);
}
// below is the initialization functionality of lar_solver
@ -1492,30 +1492,22 @@ bool lar_solver::strategy_is_undecided() const {
}
var_index lar_solver::add_var(unsigned ext_j, bool is_int) {
if (is_int)
m_has_int_var = true;
TRACE("add_var", tout << "adding var " << ext_j << (is_int? " int" : " nonint") << std::endl;);
var_index i;
var_index local_j;
lp_assert(ext_j < m_terms_start_index);
auto it = m_ext_vars_to_columns.find(ext_j);
if (it != m_ext_vars_to_columns.end()) {
return it->second.internal_j();
}
if (m_var_register.external_is_used(ext_j, local_j))
return local_j;
lp_assert(m_columns_to_ul_pairs.size() == A_r().column_count());
i = A_r().column_count();
local_j = A_r().column_count();
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());
return i;
return local_j;
}
void lar_solver::register_new_ext_var_index(unsigned ext_v, bool is_int) {
lp_assert(!contains(m_ext_vars_to_columns, ext_v));
unsigned j = static_cast<unsigned>(m_ext_vars_to_columns.size());
m_ext_vars_to_columns.insert(std::make_pair(ext_v, ext_var_info(j, is_int)));
lp_assert(m_columns_to_ext_vars_or_term_indices.size() == j);
m_columns_to_ext_vars_or_term_indices.push_back(ext_v);
lp_assert(!m_var_register.external_is_used(ext_v));
m_var_register.add_var(ext_v, is_int);
}
void lar_solver::add_non_basic_var_to_core_fields(unsigned ext_j, bool is_int) {
@ -1631,7 +1623,7 @@ var_index lar_solver::add_term(const vector<std::pair<mpq, var_index>> & coeffs,
if (m_settings.bound_propagation())
m_rows_with_changed_bounds.insert(A_r().row_count() - 1);
}
lp_assert(m_ext_vars_to_columns.size() == A_r().column_count());
lp_assert(m_var_register.size() == A_r().column_count());
return ret;
}
@ -1716,9 +1708,8 @@ void lar_solver::add_var_bound_on_constraint_for_term(var_index j, lconstraint_k
lp_assert(is_term(j));
unsigned adjusted_term_index = adjust_term_index(j);
// lp_assert(!term_is_int(m_terms[adjusted_term_index]) || right_side.is_int());
auto it = m_ext_vars_to_columns.find(j);
if (it != m_ext_vars_to_columns.end()) {
unsigned term_j = it->second.internal_j();
unsigned term_j;
if (m_var_register.external_is_used(j, term_j)) {
mpq rs = right_side - m_terms[adjusted_term_index]->m_v;
m_constraints.push_back(new lar_term_constraint(m_terms[adjusted_term_index], kind, right_side));
update_column_type_and_bound(term_j, kind, rs, ci);
@ -1804,10 +1795,10 @@ void lar_solver::adjust_initial_state_for_lu() {
}
void lar_solver::adjust_initial_state_for_tableau_rows() {
for (unsigned j = 0; j < m_terms.size(); j++) {
if (contains(m_ext_vars_to_columns, j + m_terms_start_index))
for (unsigned i = 0; i < m_terms.size(); i++) {
if (m_var_register.external_is_used(i + m_terms_start_index))
continue;
add_row_from_term_no_constraint(m_terms[j], j + m_terms_start_index);
add_row_from_term_no_constraint(m_terms[i], i + m_terms_start_index);
}
}
@ -2122,21 +2113,18 @@ void lar_solver::update_fixed_column_type_and_bound(var_index j, lconstraint_kin
}
bool lar_solver::column_corresponds_to_term(unsigned j) const {
return m_columns_to_ext_vars_or_term_indices[j] >= m_terms_start_index;
return m_var_register.local_to_external(j) >= m_terms_start_index;
}
var_index lar_solver:: to_var_index(unsigned ext_j) const {
auto it = m_ext_vars_to_columns.find(ext_j);
lp_assert(it != m_ext_vars_to_columns.end());
return it->second.internal_j();
var_index lar_solver::to_column(unsigned ext_j) const {
return m_var_register.external_to_local(ext_j);
}
bool lar_solver::tighten_term_bounds_by_delta(unsigned term_index, const impq& delta) {
unsigned tj = term_index + m_terms_start_index;
auto it = m_ext_vars_to_columns.find(tj);
if (it == m_ext_vars_to_columns.end())
return true;
unsigned j = it->second.internal_j();
unsigned j;
if (m_var_register.external_is_used(tj, j) == false)
return true; // the term is not a column so it has no bounds
auto & slv = m_mpq_lar_core_solver.m_r_solver;
TRACE("cube", tout << "delta = " << delta << std::endl;
m_int_solver->display_column(tout, j); );
@ -2166,7 +2154,7 @@ void lar_solver::update_delta_for_terms(const impq & delta, unsigned j, const ve
for (unsigned i : terms_of_var) {
lar_term & t = *m_terms[i];
auto it = t.m_coeffs.find(j);
unsigned tj = to_var_index(i + m_terms_start_index);
unsigned tj = to_column(i + m_terms_start_index);
TRACE("cube",
tout << "t.apply = " << t.apply(m_mpq_lar_core_solver.m_r_x) << ", m_mpq_lar_core_solver.m_r_x[tj]= " << m_mpq_lar_core_solver.m_r_x[tj];);
TRACE("cube", print_term_as_indices(t, tout);
@ -2199,6 +2187,7 @@ void lar_solver::round_to_integer_solution() {
fill_vars_to_terms(vars_to_terms);
for (unsigned j = 0; j < column_count(); j++) {
if (column_is_int(j)) continue;
if (column_corresponds_to_term(j)) continue;
TRACE("cube", m_int_solver->display_column(tout, j););
impq& v = m_mpq_lar_core_solver.m_r_x[j];
@ -2219,16 +2208,17 @@ void lar_solver::round_to_integer_solution() {
bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term_index, mpq & rs, constraint_index& ci) const {
unsigned tj = term_index + m_terms_start_index;
auto it = m_ext_vars_to_columns.find(tj);
if (it == m_ext_vars_to_columns.end())
unsigned j;
bool is_int;
if (m_var_register.external_is_used(tj, j, is_int) == false)
return false; // the term does not have bound because it does not correspond to a column
if (!is_int) // todo - allow for the next version of hnf
return false;
unsigned j = it->second.internal_j();
impq term_val;
bool term_val_ready = false;
mpq b;
bool is_strict;
if (has_upper_bound(j, ci, b, is_strict)) {
lp_assert(!is_strict);
if (has_upper_bound(j, ci, b, is_strict) && !is_strict) {
lp_assert(b.is_int());
term_val = terms()[term_index]->apply(m_mpq_lar_core_solver.m_r_x);
term_val_ready = true;
@ -2237,8 +2227,7 @@ bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term
return true;
}
}
if (has_lower_bound(j, ci, b, is_strict)) {
lp_assert(!is_strict);
if (has_lower_bound(j, ci, b, is_strict) && !is_strict) {
if (!term_val_ready)
term_val = terms()[term_index]->apply(m_mpq_lar_core_solver.m_r_x);
lp_assert(b.is_int());