mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +00:00
Dev (#56)
* introduce int_solver.h Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * add int_solver class Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * track which var is an integer Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * add queries for integrality of vars Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * resurrect lp_tst in its own director lp Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * add file Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * add_constraint has got a body Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * fix add_constraint and substitute_terms_in_linear_expression Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * after merge with Z3Prover Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * adding stub check_int_feasibility() Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Dev (#50) * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * small fix in lar_solver.cpp Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * adding some content to the new check_int_feasibility() Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Dev (#51) * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding more nlsat Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * nlsat integration Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding constraints Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * add missing initialization Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * test Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * Dev (#53) * change in a comment Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Disabled debug output * removing FOCI2 interface from interp * remove foci reference from cmakelist.txt Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding more nlsat Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * nlsat integration Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding constraints Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * add missing initialization Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * debugging nra Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * updates to nra_solver integration to call it directly from theory_lra instead of over lar_solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * n/a Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * integrate nlsat Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * tidy Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * preserve is_int flag Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * remove a debug printout Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Dev (#54) * change in a comment Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * Disabled debug output * removing FOCI2 interface from interp * remove foci reference from cmakelist.txt Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * initial skeletons for nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding more nlsat Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * nlsat integration Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding constraints Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * add missing initialization Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * adding nra Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * debugging nra Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * updates to nra_solver integration to call it directly from theory_lra instead of over lar_solver Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * n/a Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * integrate nlsat Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * tidy Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * use integer test from lra solver, updated it to work on term variables Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix equality check in assume-eq Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * fix model_is_int_feasible Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * untested gcd_test() Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * call fill_explanation_from_fixed_columns() Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * add the call to pivot_fixed_vars_from_basis() to int_solver.cpp::check() Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * port more of theory_arith_int.h Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * use statistics of lar_solver by theory_lra.cpp Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * port more code to int_solver.cpp Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * add an assert Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * more int porting Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * fix a bug in pivot_fixed_vars_from_basis Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * small change Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * implement find_inf_int_base_column() Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * catch unregistered vars in add_var_bound Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * add a file Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * compile for vs2012 Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * fix asserts in add_var_bound Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * fix the lp_solver init when workig on an mps file Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * towards int_solver::check() Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * change in int_solver::check() signature Signed-off-by: Lev Nachmanson <levnach@microsoft.com> * add handlers for lia moves Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com> * spacing Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
4d0fda81df
commit
a28a8304b7
47 changed files with 3926 additions and 2191 deletions
|
@ -8,6 +8,8 @@ z3_add_component(lp
|
|||
dense_matrix_instances.cpp
|
||||
eta_matrix_instances.cpp
|
||||
indexed_vector_instances.cpp
|
||||
int_solver.cpp
|
||||
lar_solver_instances.cpp
|
||||
lar_core_solver_instances.cpp
|
||||
lp_core_solver_base_instances.cpp
|
||||
lp_dual_core_solver_instances.cpp
|
||||
|
@ -18,8 +20,9 @@ z3_add_component(lp
|
|||
lp_solver_instances.cpp
|
||||
lu_instances.cpp
|
||||
matrix_instances.cpp
|
||||
nra_solver.cpp
|
||||
permutation_matrix_instances.cpp
|
||||
quick_xplain.cpp
|
||||
quick_xplain.cpp
|
||||
row_eta_matrix_instances.cpp
|
||||
scaler_instances.cpp
|
||||
sparse_matrix_instances.cpp
|
||||
|
@ -28,6 +31,8 @@ z3_add_component(lp
|
|||
random_updater_instances.cpp
|
||||
COMPONENT_DEPENDENCIES
|
||||
util
|
||||
polynomial
|
||||
nlsat
|
||||
PYG_FILES
|
||||
lp_params.pyg
|
||||
)
|
||||
|
|
|
@ -15,7 +15,7 @@ public:
|
|||
T a;
|
||||
unsigned i;
|
||||
while (it->next(a, i)) {
|
||||
coeff.emplace_back(a, i);
|
||||
coeff.push_back(std::make_pair(a, i));
|
||||
}
|
||||
print_linear_combination_of_column_indices(coeff, out);
|
||||
}
|
||||
|
|
|
@ -75,16 +75,7 @@ public:
|
|||
}
|
||||
|
||||
void set_value(const T& value, unsigned index);
|
||||
void set_value_as_in_dictionary(unsigned index) {
|
||||
lean_assert(index < m_data.size());
|
||||
T & loc = m_data[index];
|
||||
if (is_zero(loc)) {
|
||||
m_index.push_back(index);
|
||||
loc = one_of_type<T>(); // use as a characteristic function
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void clear();
|
||||
void clear_all();
|
||||
const T& operator[] (unsigned i) const {
|
||||
|
|
|
@ -1,576 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
Author: Lev Nachmanson
|
||||
*/
|
||||
|
||||
// here we are inside lean::lar_solver class
|
||||
|
||||
bool strategy_is_undecided() const {
|
||||
return m_settings.simplex_strategy() == simplex_strategy_enum::undecided;
|
||||
}
|
||||
|
||||
var_index add_var(unsigned ext_j) {
|
||||
var_index i;
|
||||
lean_assert (ext_j < m_terms_start_index);
|
||||
|
||||
if (ext_j >= m_terms_start_index)
|
||||
throw 0; // todo : what is the right way to exit?
|
||||
|
||||
if (try_get_val(m_ext_vars_to_columns, ext_j, i)) {
|
||||
return i;
|
||||
}
|
||||
lean_assert(m_vars_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)));
|
||||
add_non_basic_var_to_core_fields(ext_j);
|
||||
lean_assert(sizes_are_correct());
|
||||
return i;
|
||||
}
|
||||
|
||||
void register_new_ext_var_index(unsigned ext_v) {
|
||||
lean_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[ext_v] = j;
|
||||
lean_assert(m_columns_to_ext_vars_or_term_indices.size() == j);
|
||||
m_columns_to_ext_vars_or_term_indices.push_back(ext_v);
|
||||
}
|
||||
|
||||
void add_non_basic_var_to_core_fields(unsigned ext_j) {
|
||||
register_new_ext_var_index(ext_j);
|
||||
m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column);
|
||||
m_columns_with_changed_bound.increase_size_by_one();
|
||||
add_new_var_to_core_fields_for_mpq(false);
|
||||
if (use_lu())
|
||||
add_new_var_to_core_fields_for_doubles(false);
|
||||
}
|
||||
|
||||
void add_new_var_to_core_fields_for_doubles(bool register_in_basis) {
|
||||
unsigned j = A_d().column_count();
|
||||
A_d().add_column();
|
||||
lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j);
|
||||
// lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later
|
||||
m_mpq_lar_core_solver.m_d_x.resize(j + 1 );
|
||||
m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1);
|
||||
m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1);
|
||||
lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method
|
||||
if (register_in_basis) {
|
||||
A_d().add_row();
|
||||
m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size());
|
||||
m_mpq_lar_core_solver.m_d_basis.push_back(j);
|
||||
}else {
|
||||
m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast<int>(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1);
|
||||
m_mpq_lar_core_solver.m_d_nbasis.push_back(j);
|
||||
}
|
||||
}
|
||||
|
||||
void add_new_var_to_core_fields_for_mpq(bool register_in_basis) {
|
||||
unsigned j = A_r().column_count();
|
||||
A_r().add_column();
|
||||
lean_assert(m_mpq_lar_core_solver.m_r_x.size() == j);
|
||||
// lean_assert(m_mpq_lar_core_solver.m_r_low_bounds.size() == j && m_mpq_lar_core_solver.m_r_upper_bounds.size() == j); // restore later
|
||||
m_mpq_lar_core_solver.m_r_x.resize(j + 1);
|
||||
m_mpq_lar_core_solver.m_r_low_bounds.increase_size_by_one();
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds.increase_size_by_one();
|
||||
m_mpq_lar_core_solver.m_r_solver.m_inf_set.increase_size_by_one();
|
||||
m_mpq_lar_core_solver.m_r_solver.m_costs.resize(j + 1);
|
||||
m_mpq_lar_core_solver.m_r_solver.m_d.resize(j + 1);
|
||||
lean_assert(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method
|
||||
if (register_in_basis) {
|
||||
A_r().add_row();
|
||||
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);
|
||||
} else {
|
||||
m_mpq_lar_core_solver.m_r_heading.push_back(- static_cast<int>(m_mpq_lar_core_solver.m_r_nbasis.size()) - 1);
|
||||
m_mpq_lar_core_solver.m_r_nbasis.push_back(j);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var_index add_term_undecided(const vector<std::pair<mpq, var_index>> & coeffs,
|
||||
const mpq &m_v) {
|
||||
m_terms.push_back(new lar_term(coeffs, m_v));
|
||||
m_orig_terms.push_back(new lar_term(coeffs, m_v));
|
||||
return m_terms_start_index + m_terms.size() - 1;
|
||||
}
|
||||
|
||||
// terms
|
||||
var_index add_term(const vector<std::pair<mpq, var_index>> & coeffs,
|
||||
const mpq &m_v) {
|
||||
if (strategy_is_undecided())
|
||||
return add_term_undecided(coeffs, m_v);
|
||||
|
||||
m_terms.push_back(new lar_term(coeffs, m_v));
|
||||
m_orig_terms.push_back(new lar_term(coeffs, m_v));
|
||||
unsigned adjusted_term_index = m_terms.size() - 1;
|
||||
var_index ret = m_terms_start_index + adjusted_term_index;
|
||||
if (use_tableau() && !coeffs.empty()) {
|
||||
add_row_for_term(m_orig_terms.back(), ret);
|
||||
if (m_settings.bound_propagation())
|
||||
m_rows_with_changed_bounds.insert(A_r().row_count() - 1);
|
||||
}
|
||||
lean_assert(m_ext_vars_to_columns.size() == A_r().column_count());
|
||||
return ret;
|
||||
}
|
||||
|
||||
void add_row_for_term(const lar_term * term, unsigned term_ext_index) {
|
||||
lean_assert(sizes_are_correct());
|
||||
add_row_from_term_no_constraint(term, term_ext_index);
|
||||
lean_assert(sizes_are_correct());
|
||||
}
|
||||
|
||||
void add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index) {
|
||||
register_new_ext_var_index(term_ext_index);
|
||||
// j will be a new variable
|
||||
unsigned j = A_r().column_count();
|
||||
ul_pair ul(j);
|
||||
m_vars_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);
|
||||
A_r().fill_last_row_with_pivoting(it,
|
||||
m_mpq_lar_core_solver.m_r_solver.m_basis_heading);
|
||||
m_mpq_lar_core_solver.m_r_solver.m_b.resize(A_r().column_count(), zero_of_type<mpq>());
|
||||
} else {
|
||||
fill_last_row_of_A_r(A_r(), term);
|
||||
}
|
||||
m_mpq_lar_core_solver.m_r_x[j] = get_basic_var_value_from_row_directly(A_r().row_count() - 1);
|
||||
if (use_lu())
|
||||
fill_last_row_of_A_d(A_d(), term);
|
||||
}
|
||||
|
||||
void add_basic_var_to_core_fields() {
|
||||
bool use_lu = m_mpq_lar_core_solver.need_to_presolve_with_double_solver();
|
||||
lean_assert(!use_lu || A_r().column_count() == A_d().column_count());
|
||||
m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column);
|
||||
m_columns_with_changed_bound.increase_size_by_one();
|
||||
m_rows_with_changed_bounds.increase_size_by_one();
|
||||
add_new_var_to_core_fields_for_mpq(true);
|
||||
if (use_lu)
|
||||
add_new_var_to_core_fields_for_doubles(true);
|
||||
}
|
||||
|
||||
constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side) {
|
||||
constraint_index ci = m_constraints.size();
|
||||
if (!is_term(j)) { // j is a var
|
||||
auto vc = new lar_var_constraint(j, kind, right_side);
|
||||
m_constraints.push_back(vc);
|
||||
update_column_type_and_bound(j, kind, right_side, ci);
|
||||
} else {
|
||||
add_var_bound_on_constraint_for_term(j, kind, right_side, ci);
|
||||
}
|
||||
lean_assert(sizes_are_correct());
|
||||
return ci;
|
||||
}
|
||||
|
||||
void update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index) {
|
||||
switch(m_mpq_lar_core_solver.m_column_types[j]) {
|
||||
case column_type::free_column:
|
||||
update_free_column_type_and_bound(j, kind, right_side, constr_index);
|
||||
break;
|
||||
case column_type::boxed:
|
||||
update_boxed_column_type_and_bound(j, kind, right_side, constr_index);
|
||||
break;
|
||||
case column_type::low_bound:
|
||||
update_low_bound_column_type_and_bound(j, kind, right_side, constr_index);
|
||||
break;
|
||||
case column_type::upper_bound:
|
||||
update_upper_bound_column_type_and_bound(j, kind, right_side, constr_index);
|
||||
break;
|
||||
case column_type::fixed:
|
||||
update_fixed_column_type_and_bound(j, kind, right_side, constr_index);
|
||||
break;
|
||||
default:
|
||||
lean_assert(false); // cannot be here
|
||||
}
|
||||
}
|
||||
|
||||
void add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
|
||||
lean_assert(is_term(j));
|
||||
unsigned adjusted_term_index = adjust_term_index(j);
|
||||
unsigned term_j;
|
||||
if (try_get_val(m_ext_vars_to_columns, j, term_j)) {
|
||||
mpq rs = right_side - m_orig_terms[adjusted_term_index]->m_v;
|
||||
m_constraints.push_back(new lar_term_constraint(m_orig_terms[adjusted_term_index], kind, right_side));
|
||||
update_column_type_and_bound(term_j, kind, rs, ci);
|
||||
}
|
||||
else {
|
||||
add_constraint_from_term_and_create_new_column_row(j, m_orig_terms[adjusted_term_index], kind, right_side);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term,
|
||||
lconstraint_kind kind, const mpq & right_side) {
|
||||
|
||||
add_row_from_term_no_constraint(term, term_j);
|
||||
unsigned j = A_r().column_count() - 1;
|
||||
update_column_type_and_bound(j, kind, right_side - term->m_v, m_constraints.size());
|
||||
m_constraints.push_back(new lar_term_constraint(term, kind, right_side));
|
||||
lean_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size());
|
||||
}
|
||||
|
||||
void decide_on_strategy_and_adjust_initial_state() {
|
||||
lean_assert(strategy_is_undecided());
|
||||
if (m_vars_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) {
|
||||
m_settings.simplex_strategy() = simplex_strategy_enum::lu;
|
||||
} else {
|
||||
m_settings.simplex_strategy() = simplex_strategy_enum::tableau_rows; // todo: when to switch to tableau_costs?
|
||||
}
|
||||
adjust_initial_state();
|
||||
}
|
||||
|
||||
void adjust_initial_state() {
|
||||
switch (m_settings.simplex_strategy()) {
|
||||
case simplex_strategy_enum::lu:
|
||||
adjust_initial_state_for_lu();
|
||||
break;
|
||||
case simplex_strategy_enum::tableau_rows:
|
||||
adjust_initial_state_for_tableau_rows();
|
||||
break;
|
||||
case simplex_strategy_enum::tableau_costs:
|
||||
lean_assert(false); // not implemented
|
||||
case simplex_strategy_enum::undecided:
|
||||
adjust_initial_state_for_tableau_rows();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void adjust_initial_state_for_lu() {
|
||||
copy_from_mpq_matrix(A_d());
|
||||
unsigned n = A_d().column_count();
|
||||
m_mpq_lar_core_solver.m_d_x.resize(n);
|
||||
m_mpq_lar_core_solver.m_d_low_bounds.resize(n);
|
||||
m_mpq_lar_core_solver.m_d_upper_bounds.resize(n);
|
||||
m_mpq_lar_core_solver.m_d_heading = m_mpq_lar_core_solver.m_r_heading;
|
||||
m_mpq_lar_core_solver.m_d_basis = m_mpq_lar_core_solver.m_r_basis;
|
||||
|
||||
/*
|
||||
unsigned j = A_d().column_count();
|
||||
A_d().add_column();
|
||||
lean_assert(m_mpq_lar_core_solver.m_d_x.size() == j);
|
||||
// lean_assert(m_mpq_lar_core_solver.m_d_low_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later
|
||||
m_mpq_lar_core_solver.m_d_x.resize(j + 1 );
|
||||
m_mpq_lar_core_solver.m_d_low_bounds.resize(j + 1);
|
||||
m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1);
|
||||
lean_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method
|
||||
if (register_in_basis) {
|
||||
A_d().add_row();
|
||||
m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size());
|
||||
m_mpq_lar_core_solver.m_d_basis.push_back(j);
|
||||
}else {
|
||||
m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast<int>(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1);
|
||||
m_mpq_lar_core_solver.m_d_nbasis.push_back(j);
|
||||
}*/
|
||||
}
|
||||
|
||||
void 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))
|
||||
continue;
|
||||
add_row_from_term_no_constraint(m_terms[j], j + m_terms_start_index);
|
||||
}
|
||||
}
|
||||
|
||||
// this fills the last row of A_d and sets the basis column: -1 in the last column of the row
|
||||
void fill_last_row_of_A_d(static_matrix<double, double> & A, const lar_term* ls) {
|
||||
lean_assert(A.row_count() > 0);
|
||||
lean_assert(A.column_count() > 0);
|
||||
unsigned last_row = A.row_count() - 1;
|
||||
lean_assert(A.m_rows[last_row].empty());
|
||||
|
||||
for (auto & t : ls->m_coeffs) {
|
||||
lean_assert(!is_zero(t.second));
|
||||
var_index j = t.first;
|
||||
A.set(last_row, j, - t.second.get_double());
|
||||
}
|
||||
|
||||
unsigned basis_j = A.column_count() - 1;
|
||||
A.set(last_row, basis_j, - 1 );
|
||||
}
|
||||
|
||||
void update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind) {
|
||||
mpq y_of_bound(0);
|
||||
switch (kind) {
|
||||
case LT:
|
||||
y_of_bound = -1;
|
||||
case LE:
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound;
|
||||
lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound);
|
||||
lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j);
|
||||
{
|
||||
auto up = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
|
||||
}
|
||||
set_upper_bound_witness(j, constr_ind);
|
||||
break;
|
||||
case GT:
|
||||
y_of_bound = 1;
|
||||
case GE:
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::low_bound;
|
||||
lean_assert(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j);
|
||||
{
|
||||
auto low = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
|
||||
}
|
||||
set_low_bound_witness(j, constr_ind);
|
||||
break;
|
||||
case EQ:
|
||||
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] = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
|
||||
set_upper_bound_witness(j, constr_ind);
|
||||
set_low_bound_witness(j, constr_ind);
|
||||
break;
|
||||
|
||||
default:
|
||||
lean_unreachable();
|
||||
|
||||
}
|
||||
m_columns_with_changed_bound.insert(j);
|
||||
}
|
||||
|
||||
void update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
|
||||
lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound);
|
||||
mpq y_of_bound(0);
|
||||
switch (kind) {
|
||||
case LT:
|
||||
y_of_bound = -1;
|
||||
case LE:
|
||||
{
|
||||
auto up = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
if (up < m_mpq_lar_core_solver.m_r_upper_bounds()[j]) {
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
|
||||
set_upper_bound_witness(j, ci);
|
||||
m_columns_with_changed_bound.insert(j);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GT:
|
||||
y_of_bound = 1;
|
||||
case GE:
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::boxed;
|
||||
{
|
||||
auto low = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
|
||||
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_infeasible_column_index = j;
|
||||
} else {
|
||||
m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]? column_type::boxed : column_type::fixed;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EQ:
|
||||
{
|
||||
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;
|
||||
set_low_bound_witness(j, ci);
|
||||
m_infeasible_column_index = j;
|
||||
} else {
|
||||
m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v;
|
||||
m_columns_with_changed_bound.insert(j);
|
||||
set_low_bound_witness(j, ci);
|
||||
set_upper_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
lean_unreachable();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
|
||||
lean_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]));
|
||||
mpq y_of_bound(0);
|
||||
switch (kind) {
|
||||
case LT:
|
||||
y_of_bound = -1;
|
||||
case LE:
|
||||
{
|
||||
auto up = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
if (up < m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
|
||||
set_upper_bound_witness(j, ci);
|
||||
m_columns_with_changed_bound.insert(j);
|
||||
}
|
||||
|
||||
if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
|
||||
m_status = INFEASIBLE;
|
||||
lean_assert(false);
|
||||
m_infeasible_column_index = j;
|
||||
} else {
|
||||
if (m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GT:
|
||||
y_of_bound = 1;
|
||||
case GE:
|
||||
{
|
||||
auto low = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) {
|
||||
m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
|
||||
m_columns_with_changed_bound.insert(j);
|
||||
set_low_bound_witness(j, ci);
|
||||
}
|
||||
if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
|
||||
m_status = INFEASIBLE;
|
||||
m_infeasible_column_index = j;
|
||||
} else if ( low == m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EQ:
|
||||
{
|
||||
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_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_infeasible_column_index = j;
|
||||
set_low_bound_witness(j, ci);
|
||||
} else {
|
||||
m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v;
|
||||
set_low_bound_witness(j, ci);
|
||||
set_upper_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
|
||||
m_columns_with_changed_bound.insert(j);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
lean_unreachable();
|
||||
|
||||
}
|
||||
}
|
||||
void update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
|
||||
lean_assert(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_bound);
|
||||
mpq y_of_bound(0);
|
||||
switch (kind) {
|
||||
case LT:
|
||||
y_of_bound = -1;
|
||||
case LE:
|
||||
{
|
||||
auto up = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
|
||||
set_upper_bound_witness(j, ci);
|
||||
m_columns_with_changed_bound.insert(j);
|
||||
|
||||
if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
|
||||
m_status = INFEASIBLE;
|
||||
m_infeasible_column_index = j;
|
||||
} else {
|
||||
m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]? column_type::boxed : column_type::fixed;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GT:
|
||||
y_of_bound = 1;
|
||||
case GE:
|
||||
{
|
||||
auto low = numeric_pair<mpq>(right_side, y_of_bound);
|
||||
if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) {
|
||||
m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
|
||||
m_columns_with_changed_bound.insert(j);
|
||||
set_low_bound_witness(j, ci);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EQ:
|
||||
{
|
||||
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_infeasible_column_index = j;
|
||||
set_upper_bound_witness(j, ci);
|
||||
} else {
|
||||
m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v;
|
||||
set_low_bound_witness(j, ci);
|
||||
set_upper_bound_witness(j, ci);
|
||||
m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
|
||||
}
|
||||
m_columns_with_changed_bound.insert(j);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
lean_unreachable();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
|
||||
lean_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]));
|
||||
lean_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()));
|
||||
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_infeasible_column_index = j;
|
||||
set_upper_bound_witness(j, ci);
|
||||
}
|
||||
break;
|
||||
case LE:
|
||||
{
|
||||
if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
|
||||
m_status = INFEASIBLE;
|
||||
m_infeasible_column_index = j;
|
||||
set_upper_bound_witness(j, ci);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GT:
|
||||
{
|
||||
if (v >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
|
||||
m_status = INFEASIBLE;
|
||||
m_infeasible_column_index =j;
|
||||
set_low_bound_witness(j, ci);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GE:
|
||||
{
|
||||
if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
|
||||
m_status = INFEASIBLE;
|
||||
m_infeasible_column_index = j;
|
||||
set_low_bound_witness(j, ci);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EQ:
|
||||
{
|
||||
if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
|
||||
m_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_infeasible_column_index = j;
|
||||
set_low_bound_witness(j, ci);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
lean_unreachable();
|
||||
|
||||
}
|
||||
}
|
||||
|
606
src/util/lp/int_solver.cpp
Normal file
606
src/util/lp/int_solver.cpp
Normal file
|
@ -0,0 +1,606 @@
|
|||
/*
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
Author: Lev Nachmanson
|
||||
*/
|
||||
|
||||
#include "util/lp/int_solver.h"
|
||||
#include "util/lp/lar_solver.h"
|
||||
namespace lean {
|
||||
|
||||
void int_solver::fix_non_base_columns() {
|
||||
auto & lcs = m_lar_solver->m_mpq_lar_core_solver;
|
||||
for (unsigned j : lcs.m_r_nbasis) {
|
||||
if (column_is_int_inf(j)) {
|
||||
set_value(j, floor(lcs.m_r_x[j].x));
|
||||
}
|
||||
}
|
||||
if (m_lar_solver->find_feasible_solution() == INFEASIBLE)
|
||||
failed();
|
||||
}
|
||||
|
||||
void int_solver::failed() {
|
||||
auto & lcs = m_lar_solver->m_mpq_lar_core_solver;
|
||||
|
||||
for (unsigned j : m_old_values_set.m_index) {
|
||||
lcs.m_r_x[j] = m_old_values_data[j];
|
||||
lean_assert(lcs.m_r_solver.column_is_feasible(j));
|
||||
lcs.m_r_solver.remove_column_from_inf_set(j);
|
||||
}
|
||||
lean_assert(lcs.m_r_solver.calc_current_x_is_feasible_include_non_basis());
|
||||
lean_assert(lcs.m_r_solver.current_x_is_feasible());
|
||||
m_old_values_set.clear();
|
||||
}
|
||||
|
||||
void int_solver::trace_inf_rows() const {
|
||||
unsigned num = m_lar_solver->A_r().column_count();
|
||||
for (unsigned v = 0; v < num; v++) {
|
||||
if (is_int(v) && !get_value(v).is_int()) {
|
||||
display_column(tout, v);
|
||||
}
|
||||
}
|
||||
|
||||
num = 0;
|
||||
for (unsigned i = 0; i < m_lar_solver->A_r().row_count(); i++) {
|
||||
unsigned j = m_lar_solver->m_mpq_lar_core_solver.m_r_basis[i];
|
||||
if (column_is_int_inf(j)) {
|
||||
num++;
|
||||
iterator_on_row<mpq> it(m_lar_solver->A_r().m_rows[i]);
|
||||
m_lar_solver->print_linear_iterator(&it, tout);
|
||||
tout << "\n";
|
||||
}
|
||||
}
|
||||
tout << "num of int infeasible: " << num << "\n";
|
||||
}
|
||||
|
||||
int int_solver::find_inf_int_base_column() {
|
||||
if (m_inf_int_set.is_empty())
|
||||
return -1;
|
||||
int j = find_inf_int_boxed_base_column_with_smallest_range();
|
||||
if (j != -1)
|
||||
return j;
|
||||
unsigned k = settings().random_next() % m_inf_int_set.m_index.size();
|
||||
return m_inf_int_set.m_index[k];
|
||||
}
|
||||
|
||||
int int_solver::find_inf_int_boxed_base_column_with_smallest_range() {
|
||||
int result = -1;
|
||||
mpq range;
|
||||
mpq new_range;
|
||||
mpq small_range_thresold(1024);
|
||||
unsigned n = 0;
|
||||
lar_core_solver & lcs = m_lar_solver->m_mpq_lar_core_solver;
|
||||
|
||||
for (int j : m_inf_int_set.m_index) {
|
||||
lean_assert(is_base(j) && column_is_int_inf(j));
|
||||
if (!is_boxed(j))
|
||||
continue;
|
||||
new_range = lcs.m_r_upper_bounds()[j].x - lcs.m_r_low_bounds()[j].x;
|
||||
if (new_range > small_range_thresold)
|
||||
continue;
|
||||
if (result == -1) {
|
||||
result = j;
|
||||
range = new_range;
|
||||
n = 1;
|
||||
continue;
|
||||
}
|
||||
if (new_range < range) {
|
||||
n = 1;
|
||||
result = j;
|
||||
range = new_range;
|
||||
continue;
|
||||
}
|
||||
if (new_range == range) {
|
||||
n++;
|
||||
if (settings().random_next() % n == 0) {
|
||||
result = j;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) {
|
||||
lean_assert(is_feasible());
|
||||
init_inf_int_set();
|
||||
lean_assert(inf_int_set_is_correct());
|
||||
// currently it is a reimplementation of
|
||||
// final_check_status theory_arith<Ext>::check_int_feasibility()
|
||||
// from theory_arith_int.h
|
||||
if (m_lar_solver->model_is_int_feasible())
|
||||
return lia_move::ok;
|
||||
if (!gcd_test(ex))
|
||||
return lia_move::conflict;
|
||||
/*
|
||||
if (m_params.m_arith_euclidean_solver)
|
||||
apply_euclidean_solver();
|
||||
|
||||
*/
|
||||
m_lar_solver->pivot_fixed_vars_from_basis();
|
||||
patch_int_infeasible_columns();
|
||||
fix_non_base_columns();
|
||||
lean_assert(is_feasible());
|
||||
TRACE("arith_int_rows", trace_inf_rows(););
|
||||
|
||||
if (find_inf_int_base_column() == -1)
|
||||
return lia_move::ok;
|
||||
|
||||
|
||||
if ((++m_branch_cut_counter) % settings().m_int_branch_cut_threshold == 0) {
|
||||
move_non_base_vars_to_bounds();
|
||||
/*
|
||||
if (!make_feasible()) {
|
||||
TRACE("arith_int", tout << "failed to move variables to bounds.\n";);
|
||||
failed();
|
||||
return FC_CONTINUE;
|
||||
}
|
||||
int int_var = find_inf_int_base_var();
|
||||
if (int_var != null_int) {
|
||||
TRACE("arith_int", tout << "v" << int_var << " does not have an integer assignment: " << get_value(int_var) << "\n";);
|
||||
SASSERT(is_base(int_var));
|
||||
row const & r = m_rows[get_var_row(int_var)];
|
||||
if (!mk_gomory_cut(r)) {
|
||||
// silent failure
|
||||
}
|
||||
return FC_CONTINUE;
|
||||
}*/
|
||||
}
|
||||
else {
|
||||
int j = find_inf_int_base_column();
|
||||
/*
|
||||
if (j != -1) {
|
||||
TRACE("arith_int", tout << "v" << j << " does not have an integer assignment: " << get_value(j) << "\n";);
|
||||
// apply branching
|
||||
branch_infeasible_int_var(int_var);
|
||||
return false;
|
||||
}*/
|
||||
}
|
||||
// return true;
|
||||
return lia_move::give_up;
|
||||
}
|
||||
|
||||
void int_solver::move_non_base_vars_to_bounds() {
|
||||
auto & lcs = m_lar_solver->m_mpq_lar_core_solver;
|
||||
for (unsigned j : lcs.m_r_nbasis) {
|
||||
auto & val = lcs.m_r_x[j];
|
||||
switch (lcs.m_column_types()[j]) {
|
||||
case column_type::boxed:
|
||||
if (val != lcs.m_r_low_bounds()[j] && val != lcs.m_r_upper_bounds()[j])
|
||||
set_value(j, lcs.m_r_low_bounds()[j]);
|
||||
break;
|
||||
case column_type::low_bound:
|
||||
if (val != lcs.m_r_low_bounds()[j])
|
||||
set_value(j, lcs.m_r_low_bounds()[j]);
|
||||
break;
|
||||
case column_type::upper_bound:
|
||||
if (val != lcs.m_r_upper_bounds()[j])
|
||||
set_value(j, lcs.m_r_upper_bounds()[j]);
|
||||
break;
|
||||
default:
|
||||
if (is_int(j) && !val.is_int()) {
|
||||
set_value(j, impq(floor(val)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void int_solver::set_value(unsigned j, const impq & new_val) {
|
||||
auto & x = m_lar_solver->m_mpq_lar_core_solver.m_r_x[j];
|
||||
if (!m_old_values_set.contains(j)) {
|
||||
m_old_values_set.insert(j);
|
||||
m_old_values_data[j] = x;
|
||||
}
|
||||
auto delta = new_val - x;
|
||||
x = new_val;
|
||||
m_lar_solver->change_basic_x_by_delta_on_column(j, delta);
|
||||
update_column_in_inf_set_set(j);
|
||||
}
|
||||
|
||||
void int_solver::patch_int_infeasible_columns() {
|
||||
bool inf_l, inf_u;
|
||||
impq l, u;
|
||||
mpq m;
|
||||
auto & lcs = m_lar_solver->m_mpq_lar_core_solver;
|
||||
for (unsigned j : lcs.m_r_nbasis) {
|
||||
if (!is_int(j))
|
||||
continue;
|
||||
get_freedom_interval_for_column(j, inf_l, l, inf_u, u, m);
|
||||
impq & val = lcs.m_r_x[j];
|
||||
bool val_is_int = val.is_int();
|
||||
bool m_is_one = m.is_one();
|
||||
if (m.is_one() && val_is_int)
|
||||
continue;
|
||||
// check whether value of j is already a multiple of m.
|
||||
if (val_is_int && (val.x / m).is_int())
|
||||
continue;
|
||||
TRACE("patch_int",
|
||||
tout << "TARGET j" << j << " -> [";
|
||||
if (inf_l) tout << "-oo"; else tout << l;
|
||||
tout << ", ";
|
||||
if (inf_u) tout << "oo"; else tout << u;
|
||||
tout << "]";
|
||||
tout << ", m: " << m << ", val: " << val << ", is_int: " << m_lar_solver->column_is_int(j) << "\n";);
|
||||
if (!inf_l) {
|
||||
l = m_is_one? ceil(l) : m * ceil(l / m);
|
||||
if (inf_u || l <= u) {
|
||||
TRACE("patch_int",
|
||||
tout << "patching with l: " << l << '\n';);
|
||||
|
||||
set_value(j, l);
|
||||
} else {
|
||||
TRACE("patch_int",
|
||||
tout << "not patching " << l << "\n";);
|
||||
}
|
||||
} else if (!inf_u) {
|
||||
u = m_is_one? floor(u) : m * floor(u / m);
|
||||
set_value(j, u);
|
||||
TRACE("patch_int",
|
||||
tout << "patching with u: " << u << '\n';);
|
||||
} else {
|
||||
set_value(j, impq(0));
|
||||
TRACE("patch_int",
|
||||
tout << "patching with 0\n";);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mpq get_denominators_lcm(iterator_on_row<mpq> &it) {
|
||||
mpq r(1);
|
||||
mpq a;
|
||||
unsigned j;
|
||||
while (it.next(a, j)) {
|
||||
r = lcm(r, denominator(a));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool int_solver::gcd_test_for_row(static_matrix<mpq, numeric_pair<mpq>> & A, unsigned i, explanation & ex) {
|
||||
iterator_on_row<mpq> it(A.m_rows[i]);
|
||||
std::cout << "gcd_test_for_row(" << i << ")\n";
|
||||
mpq lcm_den = get_denominators_lcm(it);
|
||||
mpq consts(0);
|
||||
mpq gcds(0);
|
||||
mpq least_coeff(0);
|
||||
bool least_coeff_is_bounded = false;
|
||||
mpq a;
|
||||
unsigned j;
|
||||
while (it.next(a, j)) {
|
||||
if (m_lar_solver->column_is_fixed(j)) {
|
||||
mpq aux = lcm_den * a;
|
||||
consts += aux * m_lar_solver->column_low_bound(j).x;
|
||||
}
|
||||
else if (m_lar_solver->column_is_real(j)) {
|
||||
return true;
|
||||
}
|
||||
else if (gcds.is_zero()) {
|
||||
gcds = abs(lcm_den * a);
|
||||
least_coeff = gcds;
|
||||
least_coeff_is_bounded = m_lar_solver->column_is_bounded(j);
|
||||
}
|
||||
else {
|
||||
mpq aux = abs(lcm_den * a);
|
||||
gcds = gcd(gcds, aux);
|
||||
if (aux < least_coeff) {
|
||||
least_coeff = aux;
|
||||
least_coeff_is_bounded = m_lar_solver->column_is_bounded(j);
|
||||
}
|
||||
else if (least_coeff_is_bounded && aux == least_coeff) {
|
||||
least_coeff_is_bounded = m_lar_solver->column_is_bounded(j);
|
||||
}
|
||||
}
|
||||
SASSERT(gcds.is_int());
|
||||
SASSERT(least_coeff.is_int());
|
||||
TRACE("gcd_test_bug", tout << "coeff: " << a << ", gcds: " << gcds
|
||||
<< " least_coeff: " << least_coeff << " consts: " << consts << "\n";);
|
||||
|
||||
}
|
||||
|
||||
if (gcds.is_zero()) {
|
||||
// All variables are fixed.
|
||||
// This theory guarantees that the assignment satisfies each row, and
|
||||
// fixed integer variables are assigned to integer values.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(consts / gcds).is_int())
|
||||
fill_explanation_from_fixed_columns(it, ex);
|
||||
|
||||
if (least_coeff.is_one() && !least_coeff_is_bounded) {
|
||||
SASSERT(gcds.is_one());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (least_coeff_is_bounded) {
|
||||
return ext_gcd_test(it, least_coeff, lcm_den, consts, ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void int_solver::add_to_explanation_from_fixed_or_boxed_column(unsigned j, explanation & ex) {
|
||||
constraint_index lc, uc;
|
||||
m_lar_solver->get_bound_constraint_witnesses_for_column(j, lc, uc);
|
||||
ex.m_explanation.push_back(std::make_pair(mpq(1), lc));
|
||||
ex.m_explanation.push_back(std::make_pair(mpq(1), uc));
|
||||
}
|
||||
void int_solver::fill_explanation_from_fixed_columns(iterator_on_row<mpq> & it, explanation & ex) {
|
||||
it.reset();
|
||||
unsigned j;
|
||||
while (it.next(j)) {
|
||||
if (!m_lar_solver->column_is_fixed(j))
|
||||
continue;
|
||||
add_to_explanation_from_fixed_or_boxed_column(j, ex);
|
||||
}
|
||||
}
|
||||
|
||||
bool int_solver::gcd_test(explanation & ex) {
|
||||
auto & A = m_lar_solver->A_r(); // getting the matrix
|
||||
for (unsigned i = 0; i < A.row_count(); i++)
|
||||
if (!gcd_test_for_row(A, i, ex)) {
|
||||
std::cout << "false from gcd_test\n" ;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool int_solver::ext_gcd_test(iterator_on_row<mpq> & it,
|
||||
mpq const & least_coeff,
|
||||
mpq const & lcm_den,
|
||||
mpq const & consts, explanation& ex) {
|
||||
|
||||
std::cout << "calling ext_gcd_test" << std::endl;
|
||||
mpq gcds(0);
|
||||
mpq l(consts);
|
||||
mpq u(consts);
|
||||
|
||||
it.reset();
|
||||
mpq a;
|
||||
unsigned j;
|
||||
while (it.next(a, j)) {
|
||||
if (m_lar_solver->column_is_fixed(j))
|
||||
continue;
|
||||
SASSERT(!m_lar_solver->column_is_real(j));
|
||||
mpq ncoeff = lcm_den * a;
|
||||
SASSERT(ncoeff.is_int());
|
||||
mpq abs_ncoeff = abs(ncoeff);
|
||||
if (abs_ncoeff == least_coeff) {
|
||||
SASSERT(m_lar_solver->column_is_bounded(j));
|
||||
if (ncoeff.is_pos()) {
|
||||
// l += ncoeff * m_lar_solver->column_low_bound(j).x;
|
||||
l.addmul(ncoeff, m_lar_solver->column_low_bound(j).x);
|
||||
// u += ncoeff * m_lar_solver->column_upper_bound(j).x;
|
||||
u.addmul(ncoeff, m_lar_solver->column_upper_bound(j).x);
|
||||
}
|
||||
else {
|
||||
// l += ncoeff * upper_bound(j).get_rational();
|
||||
l.addmul(ncoeff, m_lar_solver->column_upper_bound(j).x);
|
||||
// u += ncoeff * lower_bound(j).get_rational();
|
||||
u.addmul(ncoeff, m_lar_solver->column_low_bound(j).x);
|
||||
}
|
||||
add_to_explanation_from_fixed_or_boxed_column(j, ex);
|
||||
}
|
||||
else if (gcds.is_zero()) {
|
||||
gcds = abs_ncoeff;
|
||||
}
|
||||
else {
|
||||
gcds = gcd(gcds, abs_ncoeff);
|
||||
}
|
||||
SASSERT(gcds.is_int());
|
||||
}
|
||||
|
||||
if (gcds.is_zero()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
mpq l1 = ceil(l/gcds);
|
||||
mpq u1 = floor(u/gcds);
|
||||
|
||||
if (u1 < l1) {
|
||||
fill_explanation_from_fixed_columns(it, ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
linear_combination_iterator<mpq> * int_solver::get_column_iterator(unsigned j) {
|
||||
if (m_lar_solver->use_tableau())
|
||||
return new iterator_on_column<mpq, impq>(m_lar_solver->A_r().m_columns[j], m_lar_solver->A_r());
|
||||
return new iterator_on_indexed_vector<mpq>(m_lar_solver->get_column_in_lu_mode(j));
|
||||
}
|
||||
|
||||
|
||||
int_solver::int_solver(lar_solver* lar_slv) :
|
||||
m_lar_solver(lar_slv),
|
||||
m_branch_cut_counter(0) {
|
||||
lean_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<impq>());
|
||||
}
|
||||
|
||||
bool int_solver::lower(unsigned j) const {
|
||||
switch (m_lar_solver->m_mpq_lar_core_solver.m_column_types()[j]) {
|
||||
case column_type::fixed:
|
||||
case column_type::boxed:
|
||||
case column_type::low_bound:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool int_solver::upper(unsigned j) const {
|
||||
switch (m_lar_solver->m_mpq_lar_core_solver.m_column_types()[j]) {
|
||||
case column_type::fixed:
|
||||
case column_type::boxed:
|
||||
case column_type::upper_bound:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const impq& int_solver::lower_bound(unsigned j) const {
|
||||
return m_lar_solver->m_mpq_lar_core_solver.m_r_low_bounds()[j];
|
||||
}
|
||||
|
||||
const impq& int_solver::upper_bound(unsigned j) const {
|
||||
return m_lar_solver->m_mpq_lar_core_solver.m_r_upper_bounds()[j];
|
||||
}
|
||||
|
||||
|
||||
void set_lower(impq & l,
|
||||
bool & inf_l,
|
||||
impq const & v ) {
|
||||
if (inf_l || v > l) {
|
||||
l = v;
|
||||
inf_l = false;
|
||||
}
|
||||
}
|
||||
|
||||
void set_upper(impq & u,
|
||||
bool & inf_u,
|
||||
impq const & v) {
|
||||
if (inf_u || v < u) {
|
||||
u = v;
|
||||
inf_u = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool int_solver::get_freedom_interval_for_column(unsigned x_j, bool & inf_l, impq & l, bool & inf_u, impq & u, mpq & m) {
|
||||
auto & lcs = m_lar_solver->m_mpq_lar_core_solver;
|
||||
if (lcs.m_r_heading[x_j] >= 0) // the basic var
|
||||
return false;
|
||||
|
||||
impq const & x_j_val = lcs.m_r_x[x_j];
|
||||
linear_combination_iterator<mpq> *it = get_column_iterator(x_j);
|
||||
|
||||
inf_l = true;
|
||||
inf_u = true;
|
||||
l = u = zero_of_type<impq>();
|
||||
m = mpq(1);
|
||||
|
||||
if (lower(x_j)) {
|
||||
set_lower(l, inf_l, lower_bound(x_j));
|
||||
}
|
||||
if (upper(x_j)) {
|
||||
set_upper(u, inf_u, upper_bound(x_j));
|
||||
}
|
||||
|
||||
mpq a_ij; unsigned i;
|
||||
while (it->next(a_ij, i)) {
|
||||
unsigned x_i = lcs.m_r_basis[i];
|
||||
impq const & x_i_val = lcs.m_r_x[x_i];
|
||||
if (is_int(x_i) && is_int(x_j) && !a_ij.is_int())
|
||||
m = lcm(m, denominator(a_ij));
|
||||
bool x_i_lower = lower(x_i);
|
||||
bool x_i_upper = upper(x_i);
|
||||
if (a_ij.is_neg()) {
|
||||
if (x_i_lower) {
|
||||
impq new_l = x_j_val + ((x_i_val - lcs.m_r_low_bounds()[x_i]) / a_ij);
|
||||
set_lower(l, inf_l, new_l);
|
||||
if (!inf_l && !inf_u && l == u) break;;
|
||||
}
|
||||
if (x_i_upper) {
|
||||
impq new_u = x_j_val + ((x_i_val - lcs.m_r_upper_bounds()[x_i]) / a_ij);
|
||||
set_upper(u, inf_u, new_u);
|
||||
if (!inf_l && !inf_u && l == u) break;;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (x_i_upper) {
|
||||
impq new_l = x_j_val + ((x_i_val - lcs.m_r_upper_bounds()[x_i]) / a_ij);
|
||||
set_lower(l, inf_u, new_l);
|
||||
if (!inf_l && !inf_u && l == u) break;;
|
||||
}
|
||||
if (x_i_lower) {
|
||||
impq new_u = x_j_val + ((x_i_val - lcs.m_r_low_bounds()[x_i]) / a_ij);
|
||||
set_upper(u, inf_u, new_u);
|
||||
if (!inf_l && !inf_u && l == u) break;;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete it;
|
||||
TRACE("freedom_interval",
|
||||
tout << "freedom variable for:\n";
|
||||
tout << m_lar_solver->get_column_name(x_j);
|
||||
tout << "[";
|
||||
if (inf_l) tout << "-oo"; else tout << l;
|
||||
tout << "; ";
|
||||
if (inf_u) tout << "oo"; else tout << u;
|
||||
tout << "]\n";);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool int_solver::is_int(unsigned j) const {
|
||||
return m_lar_solver->column_is_int(j);
|
||||
}
|
||||
|
||||
bool int_solver::value_is_int(unsigned j) const {
|
||||
return m_lar_solver->m_mpq_lar_core_solver.m_r_x[j].is_int();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool int_solver::is_feasible() const {
|
||||
auto & lcs = m_lar_solver->m_mpq_lar_core_solver;
|
||||
lean_assert(
|
||||
lcs.m_r_solver.calc_current_x_is_feasible_include_non_basis() ==
|
||||
lcs.m_r_solver.current_x_is_feasible());
|
||||
return lcs.m_r_solver.current_x_is_feasible();
|
||||
}
|
||||
const impq & int_solver::get_value(unsigned j) const {
|
||||
return m_lar_solver->m_mpq_lar_core_solver.m_r_x[j];
|
||||
}
|
||||
|
||||
void int_solver::display_column(std::ostream & out, unsigned j) const {
|
||||
m_lar_solver->m_mpq_lar_core_solver.m_r_solver.print_column_info(j, out);
|
||||
}
|
||||
|
||||
bool int_solver::inf_int_set_is_correct() const {
|
||||
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)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool int_solver::column_is_int_inf(unsigned j) const {
|
||||
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 : m_lar_solver->m_mpq_lar_core_solver.m_r_basis) {
|
||||
if (column_is_int_inf(j))
|
||||
m_inf_int_set.insert(j);
|
||||
}
|
||||
}
|
||||
|
||||
void int_solver::update_column_in_inf_set_set(unsigned j) {
|
||||
if (is_int(j) && (!value_is_int(j)))
|
||||
m_inf_int_set.insert(j);
|
||||
else
|
||||
m_inf_int_set.erase(j);
|
||||
}
|
||||
|
||||
bool int_solver::is_base(unsigned j) const {
|
||||
return m_lar_solver->m_mpq_lar_core_solver.m_r_heading[j] >= 0;
|
||||
}
|
||||
|
||||
bool int_solver::is_boxed(unsigned j) const {
|
||||
return m_lar_solver->m_mpq_lar_core_solver.m_column_types[j] == column_type::boxed;
|
||||
}
|
||||
|
||||
lp_settings& int_solver::settings() {
|
||||
return m_lar_solver->settings();
|
||||
}
|
||||
|
||||
}
|
100
src/util/lp/int_solver.h
Normal file
100
src/util/lp/int_solver.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
Author: Lev Nachmanson
|
||||
*/
|
||||
#pragma once
|
||||
#include "util/lp/lp_settings.h"
|
||||
#include "util/lp/static_matrix.h"
|
||||
#include "util/lp/iterator_on_row.h"
|
||||
#include "util/lp/int_set.h"
|
||||
#include "util/lp/lar_term.h"
|
||||
|
||||
namespace lean {
|
||||
class lar_solver;
|
||||
template <typename T, typename X>
|
||||
struct lp_constraint;
|
||||
enum class lia_move {
|
||||
ok,
|
||||
branch,
|
||||
cut,
|
||||
conflict,
|
||||
give_up
|
||||
};
|
||||
|
||||
struct explanation {
|
||||
vector<std::pair<mpq, constraint_index>> m_explanation;
|
||||
};
|
||||
|
||||
class int_solver {
|
||||
public:
|
||||
// fields
|
||||
lar_solver *m_lar_solver;
|
||||
int_set m_old_values_set;
|
||||
vector<impq> m_old_values_data;
|
||||
int_set m_inf_int_set;
|
||||
unsigned m_branch_cut_counter;
|
||||
// methods
|
||||
int_solver(lar_solver* lp);
|
||||
// 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.
|
||||
lia_move check(lar_term& t, mpq& k, explanation& ex);
|
||||
private:
|
||||
|
||||
// how to tighten bounds for integer variables.
|
||||
|
||||
bool gcd_test_for_row(static_matrix<mpq, numeric_pair<mpq>> & A, unsigned i, explanation &);
|
||||
|
||||
// gcd test
|
||||
// 5*x + 3*y + 6*z = 5
|
||||
// suppose x is fixed at 2.
|
||||
// so we have 10 + 3(y + 2z) = 5
|
||||
// 5 = -3(y + 2z)
|
||||
// this is unsolvable because 5/3 is not an integer.
|
||||
// so we create a lemma that rules out this condition.
|
||||
//
|
||||
bool gcd_test(explanation & ); // returns false in case of failure. Creates a theory lemma in case of failure.
|
||||
|
||||
// create goromy cuts
|
||||
// either creates a conflict or a bound.
|
||||
|
||||
// branch and bound:
|
||||
// decide what to branch and bound on
|
||||
// creates a fresh inequality.
|
||||
|
||||
bool branch(const lp_constraint<mpq, mpq> & new_inequality);
|
||||
bool ext_gcd_test(iterator_on_row<mpq> & it,
|
||||
mpq const & least_coeff,
|
||||
mpq const & lcm_den,
|
||||
mpq const & consts,
|
||||
explanation & ex);
|
||||
void fill_explanation_from_fixed_columns(iterator_on_row<mpq> & it, explanation &);
|
||||
void add_to_explanation_from_fixed_or_boxed_column(unsigned j, explanation &);
|
||||
void remove_fixed_vars_from_base();
|
||||
void patch_int_infeasible_columns();
|
||||
bool get_freedom_interval_for_column(unsigned j, bool & inf_l, impq & l, bool & inf_u, impq & u, mpq & m);
|
||||
linear_combination_iterator<mpq> * get_column_iterator(unsigned j);
|
||||
bool lower(unsigned j) const;
|
||||
bool upper(unsigned j) const;
|
||||
const impq & lower_bound(unsigned j) const;
|
||||
const impq & upper_bound(unsigned j) const;
|
||||
bool is_int(unsigned j) const;
|
||||
bool is_base(unsigned j) const;
|
||||
bool is_boxed(unsigned j) const;
|
||||
bool value_is_int(unsigned j) const;
|
||||
void set_value(unsigned j, const impq & new_val);
|
||||
void fix_non_base_columns();
|
||||
void failed();
|
||||
bool is_feasible() const;
|
||||
const impq & get_value(unsigned j) const;
|
||||
void display_column(std::ostream & out, unsigned j) const;
|
||||
bool inf_int_set_is_correct() const;
|
||||
void init_inf_int_set();
|
||||
void update_column_in_inf_set_set(unsigned j);
|
||||
bool column_is_int_inf(unsigned j) const;
|
||||
void trace_inf_rows() const;
|
||||
int find_inf_int_base_column();
|
||||
int find_inf_int_boxed_base_column_with_smallest_range();
|
||||
lp_settings& settings();
|
||||
void move_non_base_vars_to_bounds();
|
||||
};
|
||||
}
|
|
@ -796,6 +796,37 @@ public:
|
|||
return new iterator_on_indexed_vector<mpq>(m_r_solver.m_ed);
|
||||
}
|
||||
}
|
||||
|
||||
bool column_is_fixed(unsigned j) const {
|
||||
return m_column_types()[j] == column_type::fixed ||
|
||||
( m_column_types()[j] == column_type::boxed &&
|
||||
m_r_solver.m_low_bounds[j] == m_r_solver.m_upper_bounds[j]);
|
||||
}
|
||||
|
||||
const impq & low_bound(unsigned j) const {
|
||||
lean_assert(m_column_types()[j] == column_type::fixed ||
|
||||
m_column_types()[j] == column_type::boxed ||
|
||||
m_column_types()[j] == column_type::low_bound);
|
||||
return m_r_low_bounds[j];
|
||||
}
|
||||
|
||||
const impq & upper_bound(unsigned j) const {
|
||||
lean_assert(m_column_types()[j] == column_type::fixed ||
|
||||
m_column_types()[j] == column_type::boxed ||
|
||||
m_column_types()[j] == column_type::upper_bound);
|
||||
return m_r_upper_bounds[j];
|
||||
}
|
||||
|
||||
|
||||
const bool column_is_bounded(unsigned j) const {
|
||||
switch(m_column_types()[j]) {
|
||||
case column_type::fixed:
|
||||
case column_type::boxed:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
2040
src/util/lp/lar_solver.cpp
Normal file
2040
src/util/lp/lar_solver.cpp
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
13
src/util/lp/lar_solver_instances.cpp
Normal file
13
src/util/lp/lar_solver_instances.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
Author: Lev Nachmanson
|
||||
*/
|
||||
|
||||
#include "util/lp/lar_solver.cpp"
|
||||
|
||||
template void lean::lar_solver::copy_from_mpq_matrix<double,double>(class lean::static_matrix<double,double> &);
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -429,6 +429,7 @@ public:
|
|||
void init_lu();
|
||||
int pivots_in_column_and_row_are_different(int entering, int leaving) const;
|
||||
void pivot_fixed_vars_from_basis();
|
||||
bool pivot_column_general(unsigned j, unsigned j_basic, indexed_vector<T> & w);
|
||||
bool pivot_for_tableau_on_basis();
|
||||
bool pivot_row_for_tableau_on_basis(unsigned row);
|
||||
void init_basic_part_of_basis_heading() {
|
||||
|
@ -568,8 +569,8 @@ public:
|
|||
default:
|
||||
lean_assert(false);
|
||||
}
|
||||
std::cout << "basis heading = " << m_basis_heading[j] << std::endl;
|
||||
std::cout << "x = " << m_x[j] << std::endl;
|
||||
out << "basis heading = " << m_basis_heading[j] << std::endl;
|
||||
out << "x = " << m_x[j] << std::endl;
|
||||
/*
|
||||
std::cout << "cost = " << m_costs[j] << std::endl;
|
||||
std:: cout << "m_d = " << m_d[j] << std::endl;*/
|
||||
|
|
|
@ -923,7 +923,27 @@ template <typename T, typename X> void lp_core_solver_base<T, X>::transpose_row
|
|||
transpose_basis(i, j);
|
||||
m_A.transpose_rows(i, j);
|
||||
}
|
||||
|
||||
// j is the new basic column, j_basic - the leaving column
|
||||
template <typename T, typename X> bool lp_core_solver_base<T, X>::pivot_column_general(unsigned j, unsigned j_basic, indexed_vector<T> & w) {
|
||||
unsigned row_index = m_basis_heading[j_basic];
|
||||
change_basis(j, j_basic);
|
||||
if (m_settings.m_simplex_strategy == simplex_strategy_enum::lu) {
|
||||
if (m_factorization->need_to_refactor()) {
|
||||
init_lu();
|
||||
} else {
|
||||
m_factorization->prepare_entering(j, w); // to init vector w
|
||||
m_factorization->replace_column(zero_of_type<T>(), w, row_index);
|
||||
}
|
||||
if (m_factorization->get_status() != LU_status::OK) {
|
||||
change_basis(j_basic, j);
|
||||
init_lu();
|
||||
return false;
|
||||
}
|
||||
} else { // the tableau case
|
||||
pivot_column_tableau(j, row_index);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <typename T, typename X> void lp_core_solver_base<T, X>::pivot_fixed_vars_from_basis() {
|
||||
// run over basis and non-basis at the same time
|
||||
indexed_vector<T> w(m_basis.size()); // the buffer
|
||||
|
@ -943,22 +963,9 @@ template <typename T, typename X> void lp_core_solver_base<T, X>::pivot_fixed_v
|
|||
if (j >= m_nbasis.size())
|
||||
break;
|
||||
j++;
|
||||
if (m_factorization->need_to_refactor()) {
|
||||
change_basis(jj, ii);
|
||||
init_lu();
|
||||
} else {
|
||||
m_factorization->prepare_entering(jj, w); // to init vector w
|
||||
m_factorization->replace_column(zero_of_type<T>(), w, m_basis_heading[ii]);
|
||||
change_basis(jj, ii);
|
||||
}
|
||||
if (m_factorization->get_status() != LU_status::OK) {
|
||||
change_basis(ii, jj);
|
||||
init_lu();
|
||||
} else {
|
||||
if (!pivot_column_general(jj, ii, w))
|
||||
break;
|
||||
}
|
||||
}
|
||||
lean_assert(m_factorization->get_status()== LU_status::OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,13 +16,16 @@ namespace lean {
|
|||
typedef unsigned var_index;
|
||||
typedef unsigned constraint_index;
|
||||
typedef unsigned row_index;
|
||||
|
||||
typedef vector<std::pair<mpq, constraint_index>> explanation_t;
|
||||
|
||||
enum class column_type {
|
||||
free_column = 0,
|
||||
low_bound = 1,
|
||||
upper_bound = 2,
|
||||
boxed = 3,
|
||||
fixed = 4
|
||||
};
|
||||
low_bound = 1,
|
||||
upper_bound = 2,
|
||||
boxed = 3,
|
||||
fixed = 4
|
||||
};
|
||||
|
||||
enum class simplex_strategy_enum {
|
||||
undecided = 3,
|
||||
|
@ -75,11 +78,14 @@ public:
|
|||
};
|
||||
|
||||
struct stats {
|
||||
unsigned m_make_feasible;
|
||||
unsigned m_total_iterations;
|
||||
unsigned m_iters_with_no_cost_growing;
|
||||
unsigned m_num_factorizations;
|
||||
unsigned m_num_of_implied_bounds;
|
||||
unsigned m_need_to_solve_inf;
|
||||
unsigned m_max_cols;
|
||||
unsigned m_max_rows;
|
||||
stats() { reset(); }
|
||||
void reset() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
@ -198,7 +204,8 @@ public:
|
|||
use_breakpoints_in_feasibility_search(false),
|
||||
max_row_length_for_bound_propagation(300),
|
||||
backup_costs(true),
|
||||
column_number_threshold_for_using_lu_in_lar_solver(4000)
|
||||
column_number_threshold_for_using_lu_in_lar_solver(4000),
|
||||
m_int_branch_cut_threshold(10000000)
|
||||
{}
|
||||
|
||||
void set_resource_limit(lp_resource_limit& lim) { m_resource_limit = &lim; }
|
||||
|
@ -278,13 +285,13 @@ public:
|
|||
return m_simplex_strategy;
|
||||
}
|
||||
|
||||
bool use_lu() const {
|
||||
return m_simplex_strategy == simplex_strategy_enum::lu;
|
||||
}
|
||||
bool use_lu() const {
|
||||
return m_simplex_strategy == simplex_strategy_enum::lu;
|
||||
}
|
||||
|
||||
bool use_tableau() const {
|
||||
return m_simplex_strategy == simplex_strategy_enum::tableau_rows ||
|
||||
m_simplex_strategy == simplex_strategy_enum::tableau_costs;
|
||||
return m_simplex_strategy == simplex_strategy_enum::tableau_rows ||
|
||||
m_simplex_strategy == simplex_strategy_enum::tableau_costs;
|
||||
}
|
||||
|
||||
bool use_tableau_rows() const {
|
||||
|
@ -305,6 +312,7 @@ public:
|
|||
unsigned max_row_length_for_bound_propagation;
|
||||
bool backup_costs;
|
||||
unsigned column_number_threshold_for_using_lu_in_lar_solver;
|
||||
unsigned m_int_branch_cut_threshold;
|
||||
}; // end of lp_settings class
|
||||
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
Copyright (c) 2017 Microsoft Corporation
|
||||
Author: Lev Nachmanson
|
||||
*/
|
||||
#include "util/vector.h"
|
||||
#include <memory>
|
||||
#include "util/vector.h"
|
||||
#include "util/lp/lp_settings.hpp"
|
||||
template bool lean::vectors_are_equal<double>(vector<double> const&, vector<double> const&);
|
||||
template bool lean::vectors_are_equal<lean::mpq>(vector<lean::mpq > const&, vector<lean::mpq> const&);
|
||||
|
|
|
@ -810,7 +810,7 @@ public:
|
|||
auto kind = get_lar_relation_from_row(row->m_type);
|
||||
vector<std::pair<mpq, var_index>> ls;
|
||||
for (auto s : row->m_row_columns) {
|
||||
var_index i = solver->add_var(get_var_index(s.first));
|
||||
var_index i = solver->add_var(get_var_index(s.first), false);
|
||||
ls.push_back(std::make_pair(s.second, i));
|
||||
}
|
||||
solver->add_constraint(ls, kind, row->m_right_side);
|
||||
|
@ -828,20 +828,20 @@ public:
|
|||
|
||||
void create_low_constraint_for_var(column* col, bound * b, lar_solver *solver) {
|
||||
vector<std::pair<mpq, var_index>> ls;
|
||||
var_index i = solver->add_var(col->m_index);
|
||||
var_index i = solver->add_var(col->m_index, false);
|
||||
ls.push_back(std::make_pair(numeric_traits<T>::one(), i));
|
||||
solver->add_constraint(ls, GE, b->m_low);
|
||||
}
|
||||
|
||||
void create_upper_constraint_for_var(column* col, bound * b, lar_solver *solver) {
|
||||
var_index i = solver->add_var(col->m_index);
|
||||
var_index i = solver->add_var(col->m_index, false);
|
||||
vector<std::pair<mpq, var_index>> ls;
|
||||
ls.push_back(std::make_pair(numeric_traits<T>::one(), i));
|
||||
solver->add_constraint(ls, LE, b->m_upper);
|
||||
}
|
||||
|
||||
void create_equality_contraint_for_var(column* col, bound * b, lar_solver *solver) {
|
||||
var_index i = solver->add_var(col->m_index);
|
||||
var_index i = solver->add_var(col->m_index, false);
|
||||
vector<std::pair<mpq, var_index>> ls;
|
||||
ls.push_back(std::make_pair(numeric_traits<T>::one(), i));
|
||||
solver->add_constraint(ls, EQ, b->m_fixed_value);
|
||||
|
@ -850,7 +850,7 @@ public:
|
|||
void fill_lar_solver_on_columns(lar_solver * solver) {
|
||||
for (auto s : m_columns) {
|
||||
mps_reader::column * col = s.second;
|
||||
solver->add_var(col->m_index);
|
||||
solver->add_var(col->m_index, false);
|
||||
auto b = col->m_bound;
|
||||
if (b == nullptr) return;
|
||||
|
||||
|
|
264
src/util/lp/nra_solver.cpp
Normal file
264
src/util/lp/nra_solver.cpp
Normal file
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
Author: Lev Nachmanson
|
||||
*/
|
||||
|
||||
#include "util/lp/lar_solver.h"
|
||||
#include "util/lp/nra_solver.h"
|
||||
#include "nlsat/nlsat_solver.h"
|
||||
#include "math/polynomial/polynomial.h"
|
||||
#include "math/polynomial/algebraic_numbers.h"
|
||||
#include "util/map.h"
|
||||
|
||||
|
||||
namespace nra {
|
||||
|
||||
struct mon_eq {
|
||||
mon_eq(lean::var_index v, unsigned sz, lean::var_index const* vs):
|
||||
m_v(v), m_vs(sz, vs) {}
|
||||
lean::var_index m_v;
|
||||
svector<lean::var_index> m_vs;
|
||||
};
|
||||
|
||||
struct solver::imp {
|
||||
lean::lar_solver& s;
|
||||
reslimit& m_limit;
|
||||
params_ref m_params;
|
||||
u_map<polynomial::var> m_lp2nl; // map from lar_solver variables to nlsat::solver variables
|
||||
scoped_ptr<nlsat::solver> m_nlsat;
|
||||
vector<mon_eq> m_monomials;
|
||||
unsigned_vector m_monomials_lim;
|
||||
mutable std::unordered_map<lean::var_index, rational> m_variable_values; // current model
|
||||
|
||||
imp(lean::lar_solver& s, reslimit& lim, params_ref const& p):
|
||||
s(s),
|
||||
m_limit(lim),
|
||||
m_params(p) {
|
||||
}
|
||||
|
||||
bool need_check() {
|
||||
return !m_monomials.empty() && !check_assignments();
|
||||
}
|
||||
|
||||
void add(lean::var_index v, unsigned sz, lean::var_index const* vs) {
|
||||
m_monomials.push_back(mon_eq(v, sz, vs));
|
||||
}
|
||||
|
||||
void push() {
|
||||
m_monomials_lim.push_back(m_monomials.size());
|
||||
}
|
||||
|
||||
void pop(unsigned n) {
|
||||
if (n == 0) return;
|
||||
m_monomials.shrink(m_monomials_lim[m_monomials_lim.size() - n]);
|
||||
m_monomials_lim.shrink(m_monomials_lim.size() - n);
|
||||
}
|
||||
|
||||
/*
|
||||
\brief Check if polynomials are well defined.
|
||||
multiply values for vs and check if they are equal to value for v.
|
||||
epsilon has been computed.
|
||||
*/
|
||||
bool check_assignment(mon_eq const& m) const {
|
||||
rational r1 = m_variable_values[m.m_v];
|
||||
rational r2(1);
|
||||
for (auto w : m.m_vs) {
|
||||
r2 *= m_variable_values[w];
|
||||
}
|
||||
return r1 == r2;
|
||||
}
|
||||
|
||||
bool check_assignments() const {
|
||||
s.get_model(m_variable_values);
|
||||
for (auto const& m : m_monomials) {
|
||||
if (!check_assignment(m)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief one-shot nlsat check.
|
||||
A one shot checker is the least functionality that can
|
||||
enable non-linear reasoning.
|
||||
In addition to checking satisfiability we would also need
|
||||
to identify equalities in the model that should be assumed
|
||||
with the remaining solver.
|
||||
|
||||
TBD: use partial model from lra_solver to prime the state of nlsat_solver.
|
||||
TBD: explore more incremental ways of applying nlsat (using assumptions)
|
||||
*/
|
||||
lbool check(lean::explanation_t& ex) {
|
||||
SASSERT(need_check());
|
||||
m_nlsat = alloc(nlsat::solver, m_limit, m_params);
|
||||
m_lp2nl.reset();
|
||||
vector<nlsat::assumption, false> core;
|
||||
|
||||
// add linear inequalities from lra_solver
|
||||
for (unsigned i = 0; i < s.constraint_count(); ++i) {
|
||||
add_constraint(i);
|
||||
}
|
||||
|
||||
// add polynomial definitions.
|
||||
for (auto const& m : m_monomials) {
|
||||
add_monomial_eq(m);
|
||||
}
|
||||
// TBD: add variable bounds?
|
||||
|
||||
lbool r = m_nlsat->check();
|
||||
TRACE("arith", m_nlsat->display(tout << r << "\n"););
|
||||
switch (r) {
|
||||
case l_true:
|
||||
break;
|
||||
case l_false:
|
||||
ex.reset();
|
||||
m_nlsat->get_core(core);
|
||||
for (auto c : core) {
|
||||
unsigned idx = static_cast<unsigned>(static_cast<imp*>(c) - this);
|
||||
ex.push_back(std::pair<rational, unsigned>(rational(1), idx));
|
||||
TRACE("arith", tout << "ex: " << idx << "\n";);
|
||||
}
|
||||
break;
|
||||
|
||||
case l_undef:
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void add_monomial_eq(mon_eq const& m) {
|
||||
polynomial::manager& pm = m_nlsat->pm();
|
||||
svector<polynomial::var> vars;
|
||||
for (auto v : m.m_vs) {
|
||||
vars.push_back(lp2nl(v));
|
||||
}
|
||||
polynomial::monomial_ref m1(pm.mk_monomial(vars.size(), vars.c_ptr()), pm);
|
||||
polynomial::monomial_ref m2(pm.mk_monomial(lp2nl(m.m_v), 1), pm);
|
||||
polynomial::monomial* mls[2] = { m1, m2 };
|
||||
polynomial::scoped_numeral_vector coeffs(pm.m());
|
||||
coeffs.push_back(mpz(1));
|
||||
coeffs.push_back(mpz(-1));
|
||||
polynomial::polynomial_ref p(pm.mk_polynomial(2, coeffs.c_ptr(), mls), pm);
|
||||
polynomial::polynomial* ps[1] = { p };
|
||||
bool even[1] = { false };
|
||||
nlsat::literal lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, even);
|
||||
m_nlsat->mk_clause(1, &lit, 0);
|
||||
}
|
||||
|
||||
void add_constraint(unsigned idx) {
|
||||
auto& c = s.get_constraint(idx);
|
||||
auto& pm = m_nlsat->pm();
|
||||
auto k = c.m_kind;
|
||||
auto rhs = c.m_right_side;
|
||||
auto lhs = c.get_left_side_coefficients();
|
||||
auto sz = lhs.size();
|
||||
svector<polynomial::var> vars;
|
||||
rational den = denominator(rhs);
|
||||
for (auto kv : lhs) {
|
||||
vars.push_back(lp2nl(kv.second));
|
||||
den = lcm(den, denominator(kv.first));
|
||||
}
|
||||
vector<rational> coeffs;
|
||||
for (auto kv : lhs) {
|
||||
coeffs.push_back(den * kv.first);
|
||||
}
|
||||
rhs *= den;
|
||||
polynomial::polynomial_ref p(pm.mk_linear(sz, coeffs.c_ptr(), vars.c_ptr(), -rhs), pm);
|
||||
polynomial::polynomial* ps[1] = { p };
|
||||
bool is_even[1] = { false };
|
||||
nlsat::literal lit;
|
||||
nlsat::assumption a = this + idx;
|
||||
switch (k) {
|
||||
case lean::lconstraint_kind::LE:
|
||||
lit = ~m_nlsat->mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even);
|
||||
break;
|
||||
case lean::lconstraint_kind::GE:
|
||||
lit = ~m_nlsat->mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even);
|
||||
break;
|
||||
case lean::lconstraint_kind::LT:
|
||||
lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even);
|
||||
break;
|
||||
case lean::lconstraint_kind::GT:
|
||||
lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even);
|
||||
break;
|
||||
case lean::lconstraint_kind::EQ:
|
||||
lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, is_even);
|
||||
break;
|
||||
}
|
||||
m_nlsat->mk_clause(1, &lit, a);
|
||||
}
|
||||
|
||||
bool is_int(lean::var_index v) {
|
||||
return s.var_is_int(v);
|
||||
}
|
||||
|
||||
|
||||
polynomial::var lp2nl(lean::var_index v) {
|
||||
polynomial::var r;
|
||||
if (!m_lp2nl.find(v, r)) {
|
||||
r = m_nlsat->mk_var(is_int(v));
|
||||
m_lp2nl.insert(v, r);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
nlsat::anum const& value(lean::var_index v) const {
|
||||
return m_nlsat->value(m_lp2nl.find(v));
|
||||
}
|
||||
|
||||
nlsat::anum_manager& am() {
|
||||
return m_nlsat->am();
|
||||
}
|
||||
|
||||
std::ostream& display(std::ostream& out) const {
|
||||
for (auto m : m_monomials) {
|
||||
out << "v" << m.m_v << " = ";
|
||||
for (auto v : m.m_vs) {
|
||||
out << "v" << v << " ";
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
solver::solver(lean::lar_solver& s, reslimit& lim, params_ref const& p) {
|
||||
m_imp = alloc(imp, s, lim, p);
|
||||
}
|
||||
|
||||
solver::~solver() {
|
||||
dealloc(m_imp);
|
||||
}
|
||||
|
||||
void solver::add_monomial(lean::var_index v, unsigned sz, lean::var_index const* vs) {
|
||||
m_imp->add(v, sz, vs);
|
||||
}
|
||||
|
||||
lbool solver::check(lean::explanation_t& ex) {
|
||||
return m_imp->check(ex);
|
||||
}
|
||||
|
||||
bool solver::need_check() {
|
||||
return m_imp->need_check();
|
||||
}
|
||||
|
||||
void solver::push() {
|
||||
m_imp->push();
|
||||
}
|
||||
|
||||
void solver::pop(unsigned n) {
|
||||
m_imp->pop(n);
|
||||
}
|
||||
|
||||
std::ostream& solver::display(std::ostream& out) const {
|
||||
return m_imp->display(out);
|
||||
}
|
||||
|
||||
nlsat::anum const& solver::value(lean::var_index v) const {
|
||||
return m_imp->value(v);
|
||||
}
|
||||
|
||||
nlsat::anum_manager& solver::am() {
|
||||
return m_imp->am();
|
||||
}
|
||||
|
||||
}
|
70
src/util/lp/nra_solver.h
Normal file
70
src/util/lp/nra_solver.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
Author: Lev Nachmanson
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "util/vector.h"
|
||||
#include "util/lp/lp_settings.h"
|
||||
#include "util/rlimit.h"
|
||||
#include "util/params.h"
|
||||
#include "nlsat/nlsat_solver.h"
|
||||
|
||||
namespace lean {
|
||||
class lar_solver;
|
||||
}
|
||||
|
||||
|
||||
namespace nra {
|
||||
|
||||
|
||||
|
||||
class solver {
|
||||
struct imp;
|
||||
imp* m_imp;
|
||||
|
||||
public:
|
||||
|
||||
solver(lean::lar_solver& s, reslimit& lim, params_ref const& p = params_ref());
|
||||
|
||||
~solver();
|
||||
|
||||
/*
|
||||
\brief Add a definition v = vs[0]*vs[1]*...*vs[sz-1]
|
||||
The variable v is equal to the product of variables vs.
|
||||
*/
|
||||
void add_monomial(lean::var_index v, unsigned sz, lean::var_index const* vs);
|
||||
|
||||
/*
|
||||
\brief Check feasiblity of linear constraints augmented by polynomial definitions
|
||||
that are added.
|
||||
*/
|
||||
lbool check(lean::explanation_t& ex);
|
||||
|
||||
/*
|
||||
\brief determine whether nra check is needed.
|
||||
*/
|
||||
bool need_check();
|
||||
|
||||
/*
|
||||
\brief Access model.
|
||||
*/
|
||||
nlsat::anum const& value(lean::var_index v) const;
|
||||
|
||||
nlsat::anum_manager& am();
|
||||
|
||||
/*
|
||||
\brief push and pop scope.
|
||||
Monomial definitions are retraced when popping scope.
|
||||
*/
|
||||
void push();
|
||||
|
||||
void pop(unsigned n);
|
||||
|
||||
/*
|
||||
\brief display state
|
||||
*/
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
|
||||
};
|
||||
}
|
|
@ -199,6 +199,11 @@ struct numeric_pair {
|
|||
std::string to_string() const {
|
||||
return std::string("(") + T_to_string(x) + ", " + T_to_string(y) + ")";
|
||||
}
|
||||
|
||||
bool is_int() const {
|
||||
return x.is_int() && y.is_zero();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -324,4 +329,26 @@ struct convert_struct<double, double> {
|
|||
template <typename X> bool is_epsilon_small(const X & v, const double &eps) { return convert_struct<X, double>::is_epsilon_small(v, eps);}
|
||||
template <typename X> bool below_bound_numeric(const X & x, const X & bound, const double& eps) { return convert_struct<X, double>::below_bound_numeric(x, bound, eps);}
|
||||
template <typename X> bool above_bound_numeric(const X & x, const X & bound, const double& eps) { return convert_struct<X, double>::above_bound_numeric(x, bound, eps);}
|
||||
template <typename T> T floor(const numeric_pair<T> & r) {
|
||||
if (r.x.is_int()) {
|
||||
if (r.y.is_nonneg()) {
|
||||
return r.x;
|
||||
}
|
||||
return r.x - mpq::one();
|
||||
}
|
||||
|
||||
return floor(r.x);
|
||||
}
|
||||
|
||||
template <typename T> T ceil(const numeric_pair<T> & r) {
|
||||
if (r.x.is_int()) {
|
||||
if (r.y.is_nonpos()) {
|
||||
return r.x;
|
||||
}
|
||||
return r.x + mpq::one();
|
||||
}
|
||||
|
||||
return ceil(r.x);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ void quick_xplain::copy_constraint_and_add_constraint_vars(const lar_constraint&
|
|||
vector < std::pair<mpq, unsigned>> ls;
|
||||
for (auto & p : lar_c.get_left_side_coefficients()) {
|
||||
unsigned j = p.second;
|
||||
unsigned lj = m_qsol.add_var(j);
|
||||
unsigned lj = m_qsol.add_var(j, false);
|
||||
ls.push_back(std::make_pair(p.first, lj));
|
||||
}
|
||||
m_constraints_in_local_vars.push_back(lar_constraint(ls, lar_c.m_kind, lar_c.m_right_side));
|
||||
|
@ -94,7 +94,7 @@ bool quick_xplain::is_feasible(const vector<unsigned> & x, unsigned k) const {
|
|||
vector < std::pair<mpq, unsigned>> ls;
|
||||
const lar_constraint & c = m_constraints_in_local_vars[i];
|
||||
for (auto & p : c.get_left_side_coefficients()) {
|
||||
unsigned lj = l.add_var(p.second);
|
||||
unsigned lj = l.add_var(p.second, false);
|
||||
ls.push_back(std::make_pair(p.first, lj));
|
||||
}
|
||||
l.add_constraint(ls, c.m_kind, c.m_right_side);
|
||||
|
|
|
@ -32,7 +32,10 @@ public:
|
|||
operator const B&() const {
|
||||
return m_vec.m_vector[m_i];
|
||||
}
|
||||
|
||||
|
||||
bool operator==(B const& other) const {
|
||||
return m_vec.m_vector[m_i] == other;
|
||||
}
|
||||
};
|
||||
|
||||
class ref_const {
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
Copyright (c) 2017 Microsoft Corporation
|
||||
Author: Lev Nachmanson
|
||||
*/
|
||||
#include "util/vector.h"
|
||||
#include <memory>
|
||||
#include "util/vector.h"
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include "util/lp/static_matrix.hpp"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue