dev(lp): simplify the design of lar_solver

Signed-off-by: Lev Nachmanson <levnach@microsoft.com>
This commit is contained in:
Lev Nachmanson 2016-05-19 14:59:32 -07:00 committed by Leonardo de Moura
parent 1d3c46e712
commit 0bb21914e6
8 changed files with 229 additions and 178 deletions

View file

@ -12,8 +12,7 @@
#include <utility> #include <utility>
#include "util/lp/column_info.h" #include "util/lp/column_info.h"
namespace lean { namespace lean {
typedef unsigned var_index;
typedef unsigned constraint_index;
enum lconstraint_kind { enum lconstraint_kind {
LE = -2, LT = -1 , GE = 2, GT = 1, EQ = 0 LE = -2, LT = -1 , GE = 2, GT = 1, EQ = 0
}; };
@ -25,10 +24,10 @@ inline bool compare(const std::pair<mpq, var_index> & a, const std::pair<mpq,
class canonic_left_side { class canonic_left_side {
public: public:
int m_row_index = -1; // this index is exposed to the user, this is not the index that points to the row
int m_column_index = -1; // this is the column of the left side variable in the matrix unsigned m_row_index = static_cast<unsigned>(-1);
var_index m_additional_var_index = static_cast<var_index>(-1); // this is the index of the additional variable created for this constraint
std::vector<std::pair<mpq, var_index>> m_coeffs; std::vector<std::pair<mpq, var_index>> m_coeffs;
column_info<mpq> m_column_info;
lar_normalized_constraint * m_low_bound_witness = nullptr; lar_normalized_constraint * m_low_bound_witness = nullptr;
lar_normalized_constraint * m_upper_bound_witness = nullptr; lar_normalized_constraint * m_upper_bound_witness = nullptr;
@ -42,10 +41,6 @@ public:
normalize(); normalize();
} }
void set_name(std::string name) {
m_column_info.set_name(name);
}
unsigned size() const { return static_cast<unsigned>(m_coeffs.size()); } unsigned size() const { return static_cast<unsigned>(m_coeffs.size()); }
void normalize() { void normalize() {

View file

@ -12,6 +12,10 @@
#include <algorithm> #include <algorithm>
#include "util/lp/lp_settings.h" #include "util/lp/lp_settings.h"
namespace lean { namespace lean {
inline bool is_valid(unsigned j) { return static_cast<int>(j) >= 0;}
typedef unsigned var_index;
typedef unsigned constraint_index;
template <typename T> template <typename T>
class column_info { class column_info {
std::string m_name; std::string m_name;
@ -24,8 +28,35 @@ class column_info {
T m_cost = numeric_traits<T>::zero(); T m_cost = numeric_traits<T>::zero();
T m_fixed_value; T m_fixed_value;
bool m_is_fixed = false; bool m_is_fixed = false;
unsigned m_column_index;
public: public:
void set_column_index(unsigned j) {
m_column_index = j;
}
// the default constructor
column_info() {}
column_info(unsigned column_index) : m_column_index(column_index) {
}
column_info(const column_info & ci) {
m_name = ci.m_name;
m_low_bound_is_set = ci.m_low_bound_is_set;
m_low_bound_is_strict = ci.m_low_bound_is_strict;
m_upper_bound_is_set = ci.m_upper_bound_is_set;
m_upper_bound_is_strict = ci.m_upper_bound_is_strict;
m_low_bound = ci.m_low_bound;
m_upper_bound = ci.m_upper_bound;
m_cost = ci.m_cost;
m_fixed_value = ci.m_fixed_value;
m_is_fixed = ci.m_is_fixed;
m_column_index = ci.m_column_index;
}
unsigned get_column_index() const {
return m_column_index;
}
column_type get_column_type() const { column_type get_column_type() const {
return m_is_fixed? fixed : (m_low_bound_is_set? (m_upper_bound_is_set? boxed : low_bound) : (m_upper_bound_is_set? upper_bound: free_column)); return m_is_fixed? fixed : (m_low_bound_is_set? (m_upper_bound_is_set? boxed : low_bound) : (m_upper_bound_is_set? upper_bound: free_column));
} }

View file

@ -33,9 +33,15 @@ double conversion_helper <double>::get_upper_bound(const column_info<mpq> & ci)
canonic_left_side * lar_solver::create_or_fetch_existing_left_side(const buffer<std::pair<mpq, var_index>>& left_side_par) { canonic_left_side * lar_solver::create_or_fetch_existing_left_side(const buffer<std::pair<mpq, var_index>>& left_side_par) {
auto left_side = new canonic_left_side(left_side_par); auto left_side = new canonic_left_side(left_side_par);
lean_assert(left_side->size() > 0); lean_assert(left_side->size() > 0);
auto it = m_canonic_left_sides.find(left_side); auto it = m_set_of_canonic_left_sides.find(left_side);
if (it == m_canonic_left_sides.end()) { if (it == m_set_of_canonic_left_sides.end()) {
m_canonic_left_sides.insert(left_side); m_set_of_canonic_left_sides.insert(left_side);
lean_assert(m_map_from_var_index_to_column_info_with_cls.find(m_available_var_index) == m_map_from_var_index_to_column_info_with_cls.end());
unsigned vj = m_available_var_index;
m_map_from_var_index_to_column_info_with_cls[vj] = column_info_with_cls(left_side);
m_map_from_var_index_to_column_info_with_cls[vj].m_column_info.set_name("_s" + T_to_string(vj));
left_side->m_additional_var_index = vj;
m_available_var_index++;
} else { } else {
delete left_side; delete left_side;
left_side = *it; left_side = *it;
@ -43,14 +49,7 @@ canonic_left_side * lar_solver::create_or_fetch_existing_left_side(const buffer<
return left_side; return left_side;
} }
mpq lar_solver::find_ratio_of_original_constraint_to_normalized(canonic_left_side * ls, const lar_constraint & constraint) {
bool lar_solver::var_is_fixed(unsigned j) {
auto it = m_map_from_var_index_to_left_side.find(j);
lean_assert(it != m_map_from_var_index_to_left_side.end());
return it->second->m_column_info.is_fixed();
}
mpq lar_solver::find_ratio(canonic_left_side * ls, const lar_constraint & constraint) {
lean_assert(ls->m_coeffs.size() > 0); lean_assert(ls->m_coeffs.size() > 0);
auto first_pair = ls->m_coeffs[0]; auto first_pair = ls->m_coeffs[0];
lean_assert(first_pair.first == numeric_traits<mpq>::one()); lean_assert(first_pair.first == numeric_traits<mpq>::one());
@ -60,81 +59,68 @@ mpq lar_solver::find_ratio(canonic_left_side * ls, const lar_constraint & constr
return it->second; return it->second;
} }
void lar_solver::add_canonic_left_side_for_var(var_index i, std::string var_name) { void lar_solver::map_left_side_to_A_of_core_solver(canonic_left_side* left_side, unsigned j) {
buffer<std::pair<mpq, var_index>> b; var_index additional_var = left_side->m_additional_var_index;
b.push_back(std::make_pair(numeric_traits<mpq>::one(), i)); lean_assert(valid_index(additional_var));
auto can_ls = new canonic_left_side(b); auto it = m_map_from_var_index_to_column_info_with_cls.find(additional_var);
can_ls->set_name(var_name); lean_assert(it != m_map_from_var_index_to_column_info_with_cls.end());
column_info<mpq> & ci = it->second.m_column_info;
lean_assert(m_canonic_left_sides.find(can_ls) == m_canonic_left_sides.end()); lean_assert(!is_valid(ci.get_column_index()));
m_canonic_left_sides.insert(can_ls); lean_assert(left_side->size() > 0); // if size is zero we have an empty row
m_map_from_var_index_to_left_side[i] = can_ls; left_side->m_row_index = m_basis.size();
}
void lar_solver::map_left_side_to_column_of_A(canonic_left_side* left_side, unsigned & j) {
lean_assert(m_column_indices_to_canonic_left_sides.find(j) == m_column_indices_to_canonic_left_sides.end());
left_side->m_column_index = j; // assigning this index does not change the hash of canonic_left_side
if (left_side->size() > 1) { // if size is one we will not create a row for this left side
left_side->m_row_index = static_cast<int>(m_basis.size());
m_basis.push_back(j); // j will be a basis column, so we put it into the basis as well m_basis.push_back(j); // j will be a basis column, so we put it into the basis as well
} lean_assert(m_map_from_column_indices_to_var_index.find(j) == m_map_from_column_indices_to_var_index.end());
m_column_indices_to_canonic_left_sides[j++] = left_side; // pointing from the column to the left side ci.set_column_index(j);
m_map_from_column_indices_to_var_index[j] = additional_var;
} }
void lar_solver::map_left_sides_to_columns_of_A() { void lar_solver::map_left_sides_to_A_of_core_solver() {
unsigned j = 0; unsigned j = m_map_from_column_indices_to_var_index.size();
for (auto it : m_canonic_left_sides) for (auto it : m_set_of_canonic_left_sides)
map_left_side_to_column_of_A(it, j); map_left_side_to_A_of_core_solver(it, j++);
} }
bool valid_index(unsigned j) { return static_cast<int>(j) >= 0;}
// this adds a row to A // this adds a row to A
template <typename U, typename V> template <typename U, typename V>
void lar_solver::add_row_to_A(static_matrix<U, V> & A, unsigned i, canonic_left_side * ls) { void lar_solver::fill_row_of_A(static_matrix<U, V> & A, unsigned i, canonic_left_side * ls) {
for (auto & t : ls->m_coeffs) { for (auto & t : ls->m_coeffs) {
var_index vi = t.second; var_index vi = t.second;
canonic_left_side *var_left_side = m_map_from_var_index_to_left_side[vi]; unsigned column = get_column_index_from_var_index(vi);
unsigned column = var_left_side->m_column_index; lean_assert(is_valid(column));
lean_assert(valid_index(column));
A.set(i, column, convert_struct<U, mpq>::convert(t.first)); A.set(i, column, convert_struct<U, mpq>::convert(t.first));
} }
A.set(i, ls->m_column_index, - one_of_type<U>()); unsigned additional_column = get_column_index_from_var_index(ls->m_additional_var_index);
lean_assert(is_valid(additional_column));
A.set(i, additional_column, - one_of_type<U>());
}
void lar_solver::fill_set_of_active_var_indices() {
for (auto & t : m_set_of_canonic_left_sides)
for (auto & a : t->m_coeffs)
m_set_of_active_var_indices.insert(a.second);
} }
template <typename U, typename V> template <typename U, typename V>
void lar_solver::create_matrix_A(static_matrix<U, V> & A) { void lar_solver::create_matrix_A(static_matrix<U, V> & A) {
unsigned n = static_cast<unsigned>(m_column_indices_to_canonic_left_sides.size()); unsigned m = m_set_of_canonic_left_sides.size();
unsigned m = static_cast<unsigned>(m_basis.size()); fill_set_of_active_var_indices();
unsigned n = m_set_of_active_var_indices.size() + m;
A.init_empty_matrix(m, n); A.init_empty_matrix(m, n);
unsigned i = 0; unsigned i = 0;
for (auto & t : m_column_indices_to_canonic_left_sides) for (auto t : m_set_of_canonic_left_sides) {
if (valid_index(t.second->m_row_index)) lean_assert(t->size() > 0);
add_row_to_A(A, i++, t.second); if (is_valid(t->m_row_index))
#ifdef LEAN_DEBUG fill_row_of_A(A, i++, t);
// print_matrix(m_A); }
#endif
} }
// void lar_solver::fill_column_info_names() {
// for (unsigned j = 0; j < m_A.column_count(); j++) {
// column_info<mpq> t;
// m_column_infos.push_back(t);
// if (j < m_map_from_var_index_to_name_left_side_pair.size()) {
// m_column_infos.back().set_name(m_map_from_var_index_to_name_left_side_pair[j]);
// } else {
// string pref("_s_");
// m_column_infos.back().set_name(pref + T_to_string(j));
// }
// m_column_names
// }
// }
void lar_solver::set_upper_bound_for_column_info(lar_normalized_constraint * norm_constr) { void lar_solver::set_upper_bound_for_column_info(lar_normalized_constraint * norm_constr) {
const mpq & v = norm_constr->m_right_side; const mpq & v = norm_constr->m_right_side;
canonic_left_side * ls = norm_constr->m_canonic_left_side; canonic_left_side * ls = norm_constr->m_canonic_left_side;
column_info<mpq> & ci = ls->m_column_info; var_index additional_var_index = ls->m_additional_var_index;
lean_assert(is_valid(additional_var_index));
column_info<mpq> & ci = get_column_info_from_var_index(additional_var_index);
lean_assert(norm_constr->m_kind == LE || norm_constr->m_kind == LT || norm_constr->m_kind == EQ); lean_assert(norm_constr->m_kind == LE || norm_constr->m_kind == LT || norm_constr->m_kind == EQ);
bool strict = norm_constr->m_kind == LT; bool strict = norm_constr->m_kind == LT;
if (!ci.upper_bound_is_set()) { if (!ci.upper_bound_is_set()) {
@ -165,7 +151,7 @@ bool lar_solver::try_to_set_fixed(column_info<mpq> & ci) {
void lar_solver::set_low_bound_for_column_info(lar_normalized_constraint * norm_constr) { void lar_solver::set_low_bound_for_column_info(lar_normalized_constraint * norm_constr) {
const mpq & v = norm_constr->m_right_side; const mpq & v = norm_constr->m_right_side;
canonic_left_side * ls = norm_constr->m_canonic_left_side; canonic_left_side * ls = norm_constr->m_canonic_left_side;
column_info<mpq> & ci = ls->m_column_info; column_info<mpq> & ci = get_column_info_from_var_index(ls->m_additional_var_index);
lean_assert(norm_constr->m_kind == GE || norm_constr->m_kind == GT || norm_constr->m_kind == EQ); lean_assert(norm_constr->m_kind == GE || norm_constr->m_kind == GT || norm_constr->m_kind == EQ);
bool strict = norm_constr->m_kind == GT; bool strict = norm_constr->m_kind == GT;
if (!ci.low_bound_is_set()) { if (!ci.low_bound_is_set()) {
@ -221,10 +207,10 @@ column_type lar_solver::get_column_type(column_info<mpq> & ci) {
void lar_solver::fill_column_names() { void lar_solver::fill_column_names() {
m_column_names.clear(); m_column_names.clear();
for (auto t : m_canonic_left_sides) { for (auto & t : m_map_from_var_index_to_column_info_with_cls) {
auto & ci = t->m_column_info; column_info<mpq> & ci = t.second.m_column_info;
unsigned j = t->m_column_index; unsigned j = ci.get_column_index();
lean_assert(valid_index(j)); lean_assert(is_valid(j));
std::string name = ci.get_name(); std::string name = ci.get_name();
if (name.size() == 0) if (name.size() == 0)
name = std::string("_s") + T_to_string(j); name = std::string("_s") + T_to_string(j);
@ -234,24 +220,25 @@ void lar_solver::fill_column_names() {
void lar_solver::fill_column_types() { void lar_solver::fill_column_types() {
m_column_types.clear(); m_column_types.clear();
m_column_types.resize(m_canonic_left_sides.size(), free_column); m_column_types.resize(m_map_from_var_index_to_column_info_with_cls.size(), free_column);
for (auto t : m_canonic_left_sides) { for (auto t : m_set_of_canonic_left_sides) {
auto & ci = t->m_column_info; var_index additional_vj = t->m_additional_var_index;
unsigned j = t->m_column_index; unsigned j = get_column_index_from_var_index(additional_vj);
lean_assert(valid_index(j)); lean_assert(is_valid(j));
m_column_types[j] = get_column_type(ci); m_column_types[j] = get_column_type(get_column_info_from_var_index(additional_vj));
} }
} }
template <typename V> template <typename V>
void lar_solver::fill_bounds_for_core_solver(std::vector<V> & lb, std::vector<V> & ub) { void lar_solver::fill_bounds_for_core_solver(std::vector<V> & lb, std::vector<V> & ub) {
unsigned n = static_cast<unsigned>(m_canonic_left_sides.size()); // this is the number of columns unsigned n = static_cast<unsigned>(m_map_from_var_index_to_column_info_with_cls.size()); // this is the number of columns
lb.resize(n); lb.resize(n);
ub.resize(n); ub.resize(n);
for (auto t : m_canonic_left_sides) { for (auto t : m_set_of_canonic_left_sides) {
auto & ci = t->m_column_info; auto & ci = get_column_info_from_var_index(t->m_additional_var_index);
unsigned j = t->m_column_index; unsigned j = ci.get_column_index();
lean_assert(valid_index(j)); lean_assert(is_valid(j));
lean_assert(j < n);
if (ci.low_bound_is_set()) if (ci.low_bound_is_set())
lb[j] = conversion_helper<V>::get_low_bound(ci); lb[j] = conversion_helper<V>::get_low_bound(ci);
if (ci.upper_bound_is_set()) if (ci.upper_bound_is_set())
@ -290,31 +277,32 @@ template <typename V> V lar_solver::get_column_val(std::vector<V> & low_bound, s
lar_solver::~lar_solver() { lar_solver::~lar_solver() {
std::vector<canonic_left_side*> to_delete; std::vector<canonic_left_side*> to_delete;
for (auto it : m_canonic_left_sides) for (auto it : m_set_of_canonic_left_sides)
to_delete.push_back(it); to_delete.push_back(it);
for (auto t : to_delete) for (auto t : to_delete)
delete t; delete t;
} }
var_index lar_solver::add_var(std::string s) { var_index lar_solver::add_var(std::string s) {
auto got = m_var_names_to_var_index.find(s); auto it = m_var_names_to_var_index.find(s);
if (got != m_var_names_to_var_index.end()) return got->second; if (it != m_var_names_to_var_index.end())
return it->second;
var_index i = m_available_var_index++; var_index i = m_available_var_index++;
lean_assert(m_map_from_var_index_to_column_info_with_cls.find(i) == m_map_from_var_index_to_column_info_with_cls.end());
auto ci_with_cls = column_info_with_cls();
ci_with_cls.m_column_info.set_name(s);
m_map_from_var_index_to_column_info_with_cls[i] = ci_with_cls;
m_var_names_to_var_index[s] = i; m_var_names_to_var_index[s] = i;
add_canonic_left_side_for_var(i, s);
return i; return i;
} }
constraint_index lar_solver::add_constraint(const buffer<std::pair<mpq, var_index>>& left_side, lconstraint_kind kind_par, mpq right_side_par) { constraint_index lar_solver::add_constraint(const buffer<std::pair<mpq, var_index>>& left_side, lconstraint_kind kind_par, mpq right_side_par) {
lean_assert(left_side.size() > 0); lean_assert(left_side.size() > 0);
constraint_index i = m_available_constr_index++; constraint_index i = m_available_constr_index++;
lean_assert(m_normalized_constraints.find(i) == m_normalized_constraints.end());
lar_constraint original_constr(left_side, kind_par, right_side_par, i); lar_constraint original_constr(left_side, kind_par, right_side_par, i);
canonic_left_side * ls = create_or_fetch_existing_left_side(left_side); canonic_left_side * ls = create_or_fetch_existing_left_side(left_side);
mpq ratio = find_ratio(ls, original_constr); mpq ratio = find_ratio_of_original_constraint_to_normalized(ls, original_constr);
auto kind = ratio.is_neg()? flip_kind(kind_par): kind_par; auto kind = ratio.is_neg()? flip_kind(kind_par): kind_par;
mpq right_side = right_side_par / ratio; mpq right_side = right_side_par / ratio;
lar_normalized_constraint normalized_constraint(ls, ratio, kind, right_side, original_constr); lar_normalized_constraint normalized_constraint(ls, ratio, kind, right_side, original_constr);
@ -455,9 +443,21 @@ mpq lar_solver::sum_of_right_sides_of_evidence(const buffer<std::pair<mpq, unsig
} }
return ret; return ret;
} }
// do not touch additional vars here
void lar_solver::map_var_indices_to_columns_of_A() {
int i = 0;
for (auto & it : m_map_from_var_index_to_column_info_with_cls) {
if (it.second.m_canonic_left_side != nullptr) continue;
lean_assert(m_map_from_column_indices_to_var_index.find(i) == m_map_from_column_indices_to_var_index.end());
it.second.m_column_info.set_column_index(i);
m_map_from_column_indices_to_var_index[i] = it.first;
i++;
}
}
void lar_solver::prepare_independently_of_numeric_type() { void lar_solver::prepare_independently_of_numeric_type() {
update_column_info_of_normalized_constraints(); update_column_info_of_normalized_constraints();
map_left_sides_to_columns_of_A(); map_var_indices_to_columns_of_A();
map_left_sides_to_A_of_core_solver();
fill_column_names(); fill_column_names();
fill_column_types(); fill_column_types();
} }
@ -565,7 +565,12 @@ void lar_solver::get_infeasibility_evidence_for_inf_sign(buffer<std::pair<mpq, c
for (auto & it : inf_row) { for (auto & it : inf_row) {
mpq coeff = it.first; mpq coeff = it.first;
unsigned j = it.second; unsigned j = it.second;
canonic_left_side * ls = m_column_indices_to_canonic_left_sides[j]; auto it1 = m_map_from_column_indices_to_var_index.find(j);
lean_assert(it1 != m_map_from_column_indices_to_var_index.end());
unsigned var_j = it1->second;
auto it2 = m_map_from_var_index_to_column_info_with_cls.find(var_j);
lean_assert(it2 != m_map_from_var_index_to_column_info_with_cls.end());
canonic_left_side * ls = it2->second.m_canonic_left_side;
int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign; int adj_sign = coeff.is_pos() ? inf_sign : -inf_sign;
lar_normalized_constraint * bound_constr = adj_sign < 0? ls->m_upper_bound_witness : ls->m_low_bound_witness; lar_normalized_constraint * bound_constr = adj_sign < 0? ls->m_upper_bound_witness : ls->m_low_bound_witness;
@ -577,10 +582,10 @@ void lar_solver::get_infeasibility_evidence_for_inf_sign(buffer<std::pair<mpq, c
mpq lar_solver::find_delta_for_strict_bounds() { mpq lar_solver::find_delta_for_strict_bounds() {
mpq delta = numeric_traits<mpq>::one(); mpq delta = numeric_traits<mpq>::one();
for (auto t : m_canonic_left_sides) { for (auto t : m_set_of_canonic_left_sides) {
auto & ci = t->m_column_info; auto & ci = get_column_info_from_var_index(t->m_additional_var_index);
unsigned j = t->m_column_index; unsigned j = ci.get_column_index();
lean_assert (valid_index(j)); lean_assert (is_valid(j));
if (ci.low_bound_is_set()) if (ci.low_bound_is_set())
restrict_delta_on_low_bound_column(delta, j); restrict_delta_on_low_bound_column(delta, j);
if (ci.upper_bound_is_set()) if (ci.upper_bound_is_set())
@ -623,18 +628,21 @@ void lar_solver::restrict_delta_on_upper_bound(mpq& delta, unsigned j) {
void lar_solver::get_model(std::unordered_map<var_index, mpq> & variable_values){ void lar_solver::get_model(std::unordered_map<var_index, mpq> & variable_values){
lean_assert(m_status == OPTIMAL); lean_assert(m_status == OPTIMAL);
mpq delta = find_delta_for_strict_bounds(); mpq delta = find_delta_for_strict_bounds();
for (auto & it : m_map_from_var_index_to_left_side) { for (auto & it : m_map_from_var_index_to_column_info_with_cls) {
numeric_pair<mpq> & rp = m_x[it.second->m_column_index]; column_info<mpq> & ci = it.second.m_column_info;
unsigned j = ci.get_column_index();
numeric_pair<mpq> & rp = m_x[j];
variable_values[it.first] = rp.x + delta * rp.y; variable_values[it.first] = rp.x + delta * rp.y;
} }
} }
std::string lar_solver::get_variable_name(var_index vi) { std::string lar_solver::get_variable_name(var_index vi) const {
if (m_map_from_var_index_to_left_side.size() <= vi) { auto it = m_map_from_var_index_to_column_info_with_cls.find(vi);
if (it == m_map_from_var_index_to_column_info_with_cls.end()) {
std::string s = "variable " + T_to_string(vi) + " is not found"; std::string s = "variable " + T_to_string(vi) + " is not found";
return s; return s;
} }
return m_map_from_var_index_to_left_side[vi]->m_column_info.get_name(); return it->second.m_column_info.get_name();
} }
// ********** print region start // ********** print region start
@ -650,7 +658,7 @@ void lar_solver::print_constraint(constraint_index ci, std::ostream & out) {
void lar_solver::print_canonic_left_side(const canonic_left_side & c, std::ostream & out) { void lar_solver::print_canonic_left_side(const canonic_left_side & c, std::ostream & out) {
bool first = true; bool first = true;
for (auto it : c.m_coeffs) { for (auto & it : c.m_coeffs) {
auto val = it.first; auto val = it.first;
if (first) { if (first) {
first = false; first = false;
@ -664,13 +672,13 @@ void lar_solver::print_canonic_left_side(const canonic_left_side & c, std::ostre
} }
if (val != numeric_traits<mpq>::one()) if (val != numeric_traits<mpq>::one())
out << T_to_string(val); out << T_to_string(val);
out << m_map_from_var_index_to_left_side[it.second]->m_column_info.get_name(); out << get_variable_name(it.second);
} }
} }
void lar_solver::print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) { void lar_solver::print_left_side_of_constraint(const lar_base_constraint * c, std::ostream & out) {
bool first = true; bool first = true;
for (auto it : c->get_left_side_coefficients()) { for (auto & it : c->get_left_side_coefficients()) {
auto val = it.first; auto val = it.first;
if (numeric_traits<mpq>::is_zero(val)) continue; if (numeric_traits<mpq>::is_zero(val)) continue;
if (first) { if (first) {
@ -686,29 +694,29 @@ void lar_solver::print_left_side_of_constraint(const lar_base_constraint * c, st
if (val != numeric_traits<mpq>::one()) if (val != numeric_traits<mpq>::one())
out << val; out << val;
out << m_map_from_var_index_to_left_side[it.second]->m_column_info.get_name(); out << get_variable_name(it.second);
} }
} }
void lar_solver::print_info_on_column(unsigned j, std::ostream & out) { // void lar_solver::print_info_on_column(unsigned j, std::ostream & out) {
for (auto ls : m_canonic_left_sides) { // for (auto ls : m_set_of_canonic_left_sides) {
if (static_cast<unsigned>(ls->m_column_index) == j) { // if (static_cast<unsigned>(ls->get_ci()) == j) {
auto & ci = ls->m_column_info; // auto & ci = ls->m_column_info;
if (ci.low_bound_is_set()) { // if (ci.low_bound_is_set()) {
out << "l = " << ci.get_low_bound(); // out << "l = " << ci.get_low_bound();
} // }
if (ci.upper_bound_is_set()) { // if (ci.upper_bound_is_set()) {
out << "u = " << ci.get_upper_bound(); // out << "u = " << ci.get_upper_bound();
} // }
out << std::endl; // out << std::endl;
m_mpq_core_solver.print_column_info(j, out); // m_mpq_core_solver.print_column_info(j, out);
} // }
} // }
} // }
mpq lar_solver::get_infeasibility_of_solution(std::unordered_map<std::string, mpq> & solution) { mpq lar_solver::get_infeasibility_of_solution(std::unordered_map<std::string, mpq> & solution) {
mpq ret = numeric_traits<mpq>::zero(); mpq ret = numeric_traits<mpq>::zero();
for (auto it : m_normalized_constraints) { for (auto & it : m_normalized_constraints) {
ret += get_infeasibility_of_constraint(it.second, solution); ret += get_infeasibility_of_constraint(it.second, solution);
} }
return ret; return ret;
@ -735,12 +743,9 @@ mpq lar_solver::get_infeasibility_of_constraint(const lar_normalized_constraint
mpq lar_solver::get_canonic_left_side_val(canonic_left_side * ls, std::unordered_map<std::string, mpq> & solution) { mpq lar_solver::get_canonic_left_side_val(canonic_left_side * ls, std::unordered_map<std::string, mpq> & solution) {
mpq ret = numeric_traits<mpq>::zero(); mpq ret = numeric_traits<mpq>::zero();
for (auto it : ls->m_coeffs) { for (auto & it : ls->m_coeffs) {
var_index j = it.second; var_index vi = it.second;
auto vi = m_map_from_var_index_to_left_side.find(j); std::string s = get_variable_name(vi);
lean_assert(vi != m_map_from_var_index_to_left_side.end());
canonic_left_side * var_ls = vi->second;
std::string s = var_ls->m_column_info.get_name();
auto t = solution.find(s); auto t = solution.find(s);
lean_assert(t != solution.end()); lean_assert(t != solution.end());
ret += it.first * (t->second); ret += it.first * (t->second);
@ -750,7 +755,7 @@ mpq lar_solver::get_canonic_left_side_val(canonic_left_side * ls, std::unordered
mpq lar_solver::get_left_side_val(const lar_constraint & cns, const std::unordered_map<var_index, mpq> & var_map) { mpq lar_solver::get_left_side_val(const lar_constraint & cns, const std::unordered_map<var_index, mpq> & var_map) {
mpq ret = numeric_traits<mpq>::zero(); mpq ret = numeric_traits<mpq>::zero();
for (auto it : cns.m_left_side) { for (auto & it : cns.m_left_side) {
var_index j = it.first; var_index j = it.first;
auto vi = var_map.find(j); auto vi = var_map.find(j);
lean_assert(vi != var_map.end()); lean_assert(vi != var_map.end());
@ -763,5 +768,21 @@ void lar_solver::print_constraint(const lar_base_constraint * c, std::ostream &
print_left_side_of_constraint(c, out); print_left_side_of_constraint(c, out);
out <<" " << lconstraint_kind_string(c->m_kind) << " " << c->m_right_side; out <<" " << lconstraint_kind_string(c->m_kind) << " " << c->m_right_side;
} }
unsigned lar_solver::get_column_index_from_var_index(var_index vi) const{
auto it = m_map_from_var_index_to_column_info_with_cls.find(vi);
if (it == m_map_from_var_index_to_column_info_with_cls.end())
return static_cast<unsigned>(-1);
return it->second.m_column_info.get_column_index();
}
column_info<mpq> & lar_solver::get_column_info_from_var_index(var_index vi) {
auto it = m_map_from_var_index_to_column_info_with_cls.find(vi);
if (it == m_map_from_var_index_to_column_info_with_cls.end()) {
lean_assert(false);
throw 0;
}
return it->second.m_column_info;
}
} }

View file

@ -33,6 +33,14 @@ struct conversion_helper {
} }
}; };
struct column_info_with_cls { // column_info_with canonic_left_side
canonic_left_side * m_canonic_left_side;
column_info<mpq> m_column_info;
column_info_with_cls(): m_canonic_left_side(nullptr), m_column_info(static_cast<unsigned>(-1)) {}
column_info_with_cls(canonic_left_side * cls) : m_canonic_left_side(cls), m_column_info(static_cast<unsigned>(-1)) {}
};
template<> template<>
struct conversion_helper <double> { struct conversion_helper <double> {
static double get_low_bound(const column_info<mpq> & ci); static double get_low_bound(const column_info<mpq> & ci);
@ -43,11 +51,12 @@ class lar_solver {
unsigned m_available_var_index = 0; unsigned m_available_var_index = 0;
unsigned m_available_constr_index = 0; unsigned m_available_constr_index = 0;
lp_status m_status = UNKNOWN; lp_status m_status = UNKNOWN;
std::unordered_set<var_index> m_set_of_active_var_indices; // a variable is active if it is referenced in a left side
std::unordered_map<std::string, var_index> m_var_names_to_var_index; std::unordered_map<std::string, var_index> m_var_names_to_var_index;
std::unordered_map<var_index, canonic_left_side*> m_map_from_var_index_to_left_side; std::unordered_set<canonic_left_side*, hash_and_equal_of_canonic_left_side_struct, hash_and_equal_of_canonic_left_side_struct> m_set_of_canonic_left_sides;
std::unordered_set<canonic_left_side*, hash_and_equal_of_canonic_left_side_struct, hash_and_equal_of_canonic_left_side_struct> m_canonic_left_sides; std::unordered_map<unsigned, var_index> m_map_from_column_indices_to_var_index;
std::unordered_map<unsigned, canonic_left_side*> m_column_indices_to_canonic_left_sides;
std::unordered_map<constraint_index, lar_normalized_constraint> m_normalized_constraints; std::unordered_map<constraint_index, lar_normalized_constraint> m_normalized_constraints;
std::unordered_map<var_index, column_info_with_cls> m_map_from_var_index_to_column_info_with_cls;
static_matrix<mpq, numeric_pair<mpq>> m_A; static_matrix<mpq, numeric_pair<mpq>> m_A;
lar_core_solver<mpq, numeric_pair<mpq>> m_mpq_core_solver; lar_core_solver<mpq, numeric_pair<mpq>> m_mpq_core_solver;
lp_settings m_settings; lp_settings m_settings;
@ -62,24 +71,20 @@ class lar_solver {
canonic_left_side * m_infeasible_canonic_left_side = nullptr; // such can be found at the initialization step canonic_left_side * m_infeasible_canonic_left_side = nullptr; // such can be found at the initialization step
canonic_left_side * create_or_fetch_existing_left_side(const buffer<std::pair<mpq, var_index>>& left_side_par); canonic_left_side * create_or_fetch_existing_left_side(const buffer<std::pair<mpq, var_index>>& left_side_par);
mpq find_ratio_of_original_constraint_to_normalized(canonic_left_side * ls, const lar_constraint & constraint);
bool var_is_fixed(unsigned j);
mpq find_ratio(canonic_left_side * ls, const lar_constraint & constraint);
void add_canonic_left_side_for_var(var_index i, std::string var_name); void add_canonic_left_side_for_var(var_index i, std::string var_name);
void map_left_side_to_column_of_A(canonic_left_side* left_side, unsigned & j); void map_left_side_to_A_of_core_solver(canonic_left_side* left_side, var_index vj);
void map_left_sides_to_A_of_core_solver();
void map_left_sides_to_columns_of_A();
bool valid_index(unsigned j) { return static_cast<int>(j) >= 0;} bool valid_index(unsigned j) { return static_cast<int>(j) >= 0;}
// this adds a row to A // this adds a row to A
template <typename U, typename V> template <typename U, typename V>
void add_row_to_A(static_matrix<U, V> & A, unsigned i, canonic_left_side * ls); void fill_row_of_A(static_matrix<U, V> & A, unsigned i, canonic_left_side * ls);
template <typename U, typename V> template <typename U, typename V>
void create_matrix_A(static_matrix<U, V> & A); void create_matrix_A(static_matrix<U, V> & A);
@ -123,6 +128,12 @@ class lar_solver {
std::vector<V> & upper_bound, const lar_solution_signature & signature); std::vector<V> & upper_bound, const lar_solution_signature & signature);
template <typename V> V get_column_val(std::vector<V> & low_bound, std::vector<V> & upper_bound, non_basic_column_value_position pos_type, unsigned j); template <typename V> V get_column_val(std::vector<V> & low_bound, std::vector<V> & upper_bound, non_basic_column_value_position pos_type, unsigned j);
void map_var_indices_to_columns_of_A();
void register_in_map(std::unordered_map<var_index, mpq> & coeffs, lar_constraint & cn, const mpq & a);
unsigned get_column_index_from_var_index(var_index vi) const;
column_info<mpq> & get_column_info_from_var_index(var_index vi);
void fill_set_of_active_var_indices();
public: public:
~lar_solver(); ~lar_solver();
@ -149,10 +160,6 @@ public:
constraint_index add_constraint(const buffer<std::pair<mpq, var_index>>& left_side, lconstraint_kind kind_par, mpq right_side_par); constraint_index add_constraint(const buffer<std::pair<mpq, var_index>>& left_side, lconstraint_kind kind_par, mpq right_side_par);
bool is_infeasible(const column_info<mpq> & ci) {
return ci.low_bound_is_set() && ci.upper_bound_is_set() && ci.get_low_bound() > ci.get_upper_bound();
}
bool all_constraints_hold(); bool all_constraints_hold();
bool constraint_holds(const lar_constraint & constr, std::unordered_map<var_index, mpq> & var_map); bool constraint_holds(const lar_constraint & constr, std::unordered_map<var_index, mpq> & var_map);
@ -163,7 +170,6 @@ public:
bool the_relations_are_of_same_type(const buffer<std::pair<mpq, unsigned>> & evidence, lconstraint_kind & the_kind_of_sum); bool the_relations_are_of_same_type(const buffer<std::pair<mpq, unsigned>> & evidence, lconstraint_kind & the_kind_of_sum);
void register_in_map(std::unordered_map<var_index, mpq> & coeffs, lar_constraint & cn, const mpq & a);
bool the_left_sides_sum_to_zero(const buffer<std::pair<mpq, unsigned>> & evidence); bool the_left_sides_sum_to_zero(const buffer<std::pair<mpq, unsigned>> & evidence);
bool the_righ_sides_do_not_sum_to_zero(const buffer<std::pair<mpq, unsigned>> & evidence); bool the_righ_sides_do_not_sum_to_zero(const buffer<std::pair<mpq, unsigned>> & evidence);
@ -214,7 +220,7 @@ public:
void get_model(std::unordered_map<var_index, mpq> & variable_values); void get_model(std::unordered_map<var_index, mpq> & variable_values);
std::string get_variable_name(var_index vi); std::string get_variable_name(var_index vi) const;
void print_constraint(constraint_index ci, std::ostream & out); void print_constraint(constraint_index ci, std::ostream & out);
@ -224,7 +230,7 @@ public:
numeric_pair<mpq> get_infeasibility_from_core_solver(std::unordered_map<std::string, mpq> & solution); numeric_pair<mpq> get_infeasibility_from_core_solver(std::unordered_map<std::string, mpq> & solution);
void print_info_on_column(unsigned j, std::ostream & out); // void print_info_on_column(unsigned j, std::ostream & out);
mpq get_infeasibility_of_solution(std::unordered_map<std::string, mpq> & solution); mpq get_infeasibility_of_solution(std::unordered_map<std::string, mpq> & solution);

View file

@ -145,9 +145,9 @@ template <typename T, typename X> void lp_primal_simplex<T, X>::set_core_solver_
this->m_upper_bounds.resize(total_vars); this->m_upper_bounds.resize(total_vars);
for (auto cit : this->m_columns) { for (auto cit : this->m_columns) {
column_info<T> * ci = cit.second; column_info<T> * ci = cit.second;
auto p = this->m_external_columns_to_core_solver_columns.find(cit.first); unsigned j = ci->get_column_index();
if (p == this->m_external_columns_to_core_solver_columns.end()) continue; if (!is_valid(j))
unsigned j = p->second; continue; // the variable is not mapped to a column
switch (this->m_column_types[j] = ci->get_column_type()){ switch (this->m_column_types[j] = ci->get_column_type()){
case fixed: case fixed:
this->m_upper_bounds[j] = numeric_traits<T>::zero(); this->m_upper_bounds[j] = numeric_traits<T>::zero();

View file

@ -401,9 +401,9 @@ template <typename T, typename X> void lp_solver<T, X>::map_external_columns_to_
throw_exception("found fixed column"); throw_exception("found fixed column");
} }
unsigned j = col.first; unsigned j = col.first;
auto j_place = m_external_columns_to_core_solver_columns.find(j); auto j_column = m_columns[j]->get_column_index();
if (j_place == m_external_columns_to_core_solver_columns.end()) { // j is a newcomer if (!is_valid(j_column)) { // j is a newcomer
m_external_columns_to_core_solver_columns[j] = size; m_columns[j]->set_column_index(size);
m_core_solver_columns_to_external_columns[size++] = j; m_core_solver_columns_to_external_columns[size++] = j;
} }
} }
@ -412,10 +412,9 @@ template <typename T, typename X> void lp_solver<T, X>::map_external_columns_to_
template <typename T, typename X> void lp_solver<T, X>::fill_column_names_for_core_solver() { template <typename T, typename X> void lp_solver<T, X>::fill_column_names_for_core_solver() {
for (auto it : this->m_columns) { for (auto it : this->m_columns) {
auto p = this->m_external_columns_to_core_solver_columns.find(it.first); unsigned j = it.second->get_column_index();
if (p != this->m_external_columns_to_core_solver_columns.end()) { if (is_valid(j))
this->m_name_map[p->second] = it.second->get_name(); this->m_name_map[j] = it.second->get_name();
}
} }
} }
@ -434,10 +433,9 @@ template <typename T, typename X> void lp_solver<T, X>::fill_A_from_A_values() {
lean_assert(m_external_rows_to_core_solver_rows.find(t.first) != m_external_rows_to_core_solver_rows.end()); lean_assert(m_external_rows_to_core_solver_rows.find(t.first) != m_external_rows_to_core_solver_rows.end());
unsigned row = m_external_rows_to_core_solver_rows[t.first]; unsigned row = m_external_rows_to_core_solver_rows[t.first];
for (auto k : t.second) { for (auto k : t.second) {
lean_assert(m_external_columns_to_core_solver_columns.find(k.first) != m_external_columns_to_core_solver_columns.end()); unsigned col = m_columns[k.first]->get_column_index();
unsigned col = m_external_columns_to_core_solver_columns[k.first]; lean_assert(is_valid(col));
bool col_is_flipped = m_columns[k.first]->is_flipped(); bool col_is_flipped = m_columns[k.first]->is_flipped();
if (!col_is_flipped) { if (!col_is_flipped) {
(*m_A)(row, col) = k.second; (*m_A)(row, col) = k.second;
} else { } else {
@ -517,9 +515,8 @@ template <typename T, typename X> T lp_solver<T, X>::get_column_value_with_co
return ci->get_fixed_value(); return ci->get_fixed_value();
} }
auto t = this->m_external_columns_to_core_solver_columns.find(column); unsigned cj = ci->get_column_index();
if (t != this->m_external_columns_to_core_solver_columns.end()){ if (cj != static_cast<unsigned>(-1)) {
unsigned cj = t->second;
T v = core_solver->get_var_value(cj) * this->m_column_scale[cj]; T v = core_solver->get_var_value(cj) * this->m_column_scale[cj];
if (ci->is_free()) { if (ci->is_free()) {
return v; return v;

View file

@ -43,12 +43,11 @@ public:
unsigned m_first_stage_iterations = 0; unsigned m_first_stage_iterations = 0;
unsigned m_second_stage_iterations = 0; unsigned m_second_stage_iterations = 0;
std::unordered_map<unsigned, lp_constraint<T, X>> m_constraints; std::unordered_map<unsigned, lp_constraint<T, X>> m_constraints;
std::unordered_map<unsigned, column_info<T>*> m_columns; std::unordered_map<var_index, column_info<T>*> m_columns;
std::unordered_map<unsigned, std::unordered_map<unsigned, T> > m_A_values; std::unordered_map<unsigned, std::unordered_map<unsigned, T> > m_A_values;
std::unordered_map<std::string, unsigned> m_names_to_columns; // don't have to use it std::unordered_map<std::string, unsigned> m_names_to_columns; // don't have to use it
std::unordered_map<unsigned, unsigned> m_external_rows_to_core_solver_rows; std::unordered_map<unsigned, unsigned> m_external_rows_to_core_solver_rows;
std::unordered_map<unsigned, unsigned> m_core_solver_rows_to_external_rows; std::unordered_map<unsigned, unsigned> m_core_solver_rows_to_external_rows;
std::unordered_map<unsigned, unsigned> m_external_columns_to_core_solver_columns;
std::unordered_map<unsigned, unsigned> m_core_solver_columns_to_external_columns; std::unordered_map<unsigned, unsigned> m_core_solver_columns_to_external_columns;
std::vector<T> m_column_scale; std::vector<T> m_column_scale;
std::unordered_map<unsigned, std::string> m_name_map; std::unordered_map<unsigned, std::string> m_name_map;
@ -197,7 +196,9 @@ protected:
void fill_column_names_for_core_solver(); void fill_column_names_for_core_solver();
unsigned number_of_core_structurals() { return static_cast<unsigned>(m_external_columns_to_core_solver_columns.size()); } unsigned number_of_core_structurals() {
return static_cast<unsigned>(m_core_solver_columns_to_external_columns.size());
}
void restore_column_scales_to_one() { void restore_column_scales_to_one() {

View file

@ -18,7 +18,7 @@ namespace lean {
inline void lean_assert(bool b) {} inline void lean_assert(bool b) {}
#else #else
#define lean_assert(_x_) {} #define lean_assert(_x_) {}
#endif #endif
inline void lean_unreachable() { lean_assert(false); } inline void lean_unreachable() { lean_assert(false); }
template <typename X> inline X zero_of_type() { return numeric_traits<X>::zero(); } template <typename X> inline X zero_of_type() { return numeric_traits<X>::zero(); }
template <typename X> inline X one_of_type() { return numeric_traits<X>::one(); } template <typename X> inline X one_of_type() { return numeric_traits<X>::one(); }
@ -75,7 +75,7 @@ template <typename X> inline bool is_zero(const X & v) { return numeric_traits<X
template <typename X> inline double get_double(const X & v) { return numeric_traits<X>::get_double(v); } template <typename X> inline double get_double(const X & v) { return numeric_traits<X>::get_double(v); }
template <typename T> inline T zero_of_type() {return numeric_traits<T>::zero();} template <typename T> inline T zero_of_type() {return numeric_traits<T>::zero();}
inline void throw_exception(std::string str) { throw exception(str); } inline void throw_exception(std::string str) { throw exception(str); }
template <typename T> inline T from_string(std::string const & str) { lean_unreachable();} template <typename T> inline T from_string(std::string const & ) { lean_unreachable();}
template <> double inline from_string<double>(std::string const & str) { return atof(str.c_str());} template <> double inline from_string<double>(std::string const & str) { return atof(str.c_str());}
template <> mpq inline from_string<mpq>(std::string const & str) { template <> mpq inline from_string<mpq>(std::string const & str) {
return mpq(atof(str.c_str())); return mpq(atof(str.c_str()));