#include "lp_data/HighsLp.h"
#include <cassert>
#include "lp_data/HighsLpUtils.h"
#include "util/HighsMatrixUtils.h"
bool HighsLp::isMip() const {
size_t integrality_size = this->integrality_.size();
if (integrality_size) {
assert(static_cast<HighsInt>(integrality_size) == this->num_col_);
for (HighsInt iCol = 0; iCol < this->num_col_; iCol++)
if (this->integrality_[iCol] != HighsVarType::kContinuous) return true;
}
return false;
}
bool HighsLp::hasInfiniteCost(const double infinite_cost) const {
for (HighsInt iCol = 0; iCol < this->num_col_; iCol++) {
if (this->col_cost_[iCol] >= infinite_cost) return true;
if (this->col_cost_[iCol] <= -infinite_cost) return true;
}
return false;
}
bool HighsLp::hasSemiVariables() const {
size_t integrality_size = this->integrality_.size();
if (integrality_size) {
assert(static_cast<HighsInt>(integrality_size) == this->num_col_);
for (HighsInt iCol = 0; iCol < this->num_col_; iCol++)
if (this->integrality_[iCol] == HighsVarType::kSemiContinuous ||
this->integrality_[iCol] == HighsVarType::kSemiInteger)
return true;
}
return false;
}
bool HighsLp::hasMods() const {
return this->mods_.save_non_semi_variable_index.size() > 0 ||
this->mods_.save_inconsistent_semi_variable_index.size() > 0 ||
this->mods_.save_relaxed_semi_variable_lower_bound_index.size() > 0 ||
this->mods_.save_tightened_semi_variable_upper_bound_index.size() >
0 ||
this->mods_.save_inf_cost_variable_index.size() > 0;
}
bool HighsLp::needsMods(const double infinite_cost) const {
assert(this->has_infinite_cost_ == this->hasInfiniteCost(infinite_cost));
return this->has_infinite_cost_ || this->hasSemiVariables();
}
bool HighsLp::operator==(const HighsLp& lp) const {
bool equal = equalButForNames(lp);
equal = equalNames(lp) && equal;
return equal;
}
bool HighsLp::equalButForNames(const HighsLp& lp) const {
bool equal = equalButForScalingAndNames(lp);
equal = equalScaling(lp) && equal;
return equal;
}
bool HighsLp::equalButForScalingAndNames(const HighsLp& lp) const {
const bool equal_vectors = equalVectors(lp);
const bool equal_matrix = this->a_matrix_ == lp.a_matrix_;
#ifndef NDEBUG
if (!equal_matrix) printf("HighsLp::equalButForNames: Unequal matrix\n");
#endif
return equal_vectors && equal_matrix;
}
bool HighsLp::equalVectors(const HighsLp& lp) const {
bool equal_vectors = true;
equal_vectors = this->num_col_ == lp.num_col_ && equal_vectors;
equal_vectors = this->num_row_ == lp.num_row_ && equal_vectors;
equal_vectors = this->sense_ == lp.sense_ && equal_vectors;
equal_vectors = this->offset_ == lp.offset_ && equal_vectors;
equal_vectors = this->model_name_ == lp.model_name_ && equal_vectors;
equal_vectors = this->col_cost_ == lp.col_cost_ && equal_vectors;
equal_vectors = this->col_upper_ == lp.col_upper_ && equal_vectors;
equal_vectors = this->col_lower_ == lp.col_lower_ && equal_vectors;
equal_vectors = this->row_upper_ == lp.row_upper_ && equal_vectors;
equal_vectors = this->row_lower_ == lp.row_lower_ && equal_vectors;
#ifndef NDEBUG
if (!equal_vectors) printf("HighsLp::equalButForNames: Unequal vectors\n");
#endif
return equal_vectors;
}
bool HighsLp::equalNames(const HighsLp& lp) const {
bool equal = true;
equal = this->objective_name_ == lp.objective_name_ && equal;
equal = this->row_names_ == lp.row_names_ && equal;
equal = this->col_names_ == lp.col_names_ && equal;
return equal;
}
bool HighsLp::equalScaling(const HighsLp& lp) const {
bool equal = true;
equal = this->scale_.strategy == lp.scale_.strategy && equal;
equal = this->scale_.has_scaling == lp.scale_.has_scaling && equal;
equal = this->scale_.num_col == lp.scale_.num_col && equal;
equal = this->scale_.num_row == lp.scale_.num_row && equal;
equal = this->scale_.cost == lp.scale_.cost && equal;
equal = this->scale_.col == lp.scale_.col && equal;
equal = this->scale_.row == lp.scale_.row && equal;
#ifndef NDEBUG
if (!equal) printf("HighsLp::equalScaling: Unequal scaling\n");
#endif
return equal;
}
double HighsLp::objectiveValue(const std::vector<double>& solution) const {
assert((int)solution.size() >= this->num_col_);
double objective_function_value = this->offset_;
for (HighsInt iCol = 0; iCol < this->num_col_; iCol++)
objective_function_value += this->col_cost_[iCol] * solution[iCol];
return objective_function_value;
}
HighsCDouble HighsLp::objectiveCDoubleValue(
const std::vector<double>& solution) const {
assert((int)solution.size() >= this->num_col_);
HighsCDouble objective_function_value = this->offset_;
for (HighsInt iCol = 0; iCol < this->num_col_; iCol++)
objective_function_value += this->col_cost_[iCol] * solution[iCol];
return objective_function_value;
}
void HighsLp::setMatrixDimensions() {
this->a_matrix_.num_col_ = this->num_col_;
this->a_matrix_.num_row_ = this->num_row_;
}
void HighsLp::resetScale() {
this->clearScale();
}
void HighsLp::setFormat(const MatrixFormat format) {
this->a_matrix_.setFormat(format);
}
void HighsLp::exactResize() {
this->col_cost_.resize(this->num_col_);
this->col_lower_.resize(this->num_col_);
this->col_upper_.resize(this->num_col_);
this->row_lower_.resize(this->num_row_);
this->row_upper_.resize(this->num_row_);
this->a_matrix_.exactResize();
if ((int)this->col_names_.size()) this->col_names_.resize(this->num_col_);
if ((int)this->row_names_.size()) this->row_names_.resize(this->num_row_);
if ((int)this->integrality_.size()) this->integrality_.resize(this->num_col_);
}
bool HighsLp::okNames() const {
if (this->col_names_.size() != static_cast<size_t>(this->num_col_))
return false;
if (this->row_names_.size() != static_cast<size_t>(this->num_row_))
return false;
for (HighsInt iCol = 0; iCol < this->num_col_; iCol++) {
const std::string& name = this->col_names_[iCol];
if (HighsInt(name.length()) == 0) return false;
size_t space_pos = name.find(" ");
if (space_pos != std::string::npos) return false;
}
for (HighsInt iRow = 0; iRow < this->num_row_; iRow++) {
const std::string& name = this->row_names_[iRow];
if (HighsInt(name.length()) == 0) return false;
size_t space_pos = name.find(" ");
if (space_pos != std::string::npos) return false;
}
return true;
}
void HighsLp::clear() {
this->num_col_ = 0;
this->num_row_ = 0;
this->col_cost_.clear();
this->col_lower_.clear();
this->col_upper_.clear();
this->row_lower_.clear();
this->row_upper_.clear();
this->a_matrix_.clear();
this->sense_ = ObjSense::kMinimize;
this->offset_ = 0;
this->model_name_ = "";
this->origin_name_ = "";
this->objective_name_ = "";
this->col_name_prefix_ = "";
this->row_name_prefix_ = "";
this->col_name_suffix_ = 0;
this->row_name_suffix_ = 0;
this->col_names_.clear();
this->row_names_.clear();
this->integrality_.clear();
this->col_hash_.clear();
this->row_hash_.clear();
this->clearScale();
this->is_scaled_ = false;
this->is_moved_ = false;
this->cost_row_location_ = -1;
this->has_infinite_cost_ = false;
this->mods_.clear();
}
void HighsLp::clearScale() {
this->scale_.strategy = kSimplexScaleStrategyOff;
this->scale_.has_scaling = false;
this->scale_.num_col = 0;
this->scale_.num_row = 0;
this->scale_.cost = 0;
this->scale_.col.clear();
this->scale_.row.clear();
}
void HighsLp::clearScaling() {
this->unapplyScale();
this->clearScale();
}
void HighsLp::applyScale() {
const HighsScale& scale = this->scale_;
if (this->is_scaled_) {
assert(scale.has_scaling);
return;
}
this->is_scaled_ = false;
if (scale.has_scaling) {
for (HighsInt iCol = 0; iCol < this->num_col_; iCol++) {
this->col_lower_[iCol] /= scale.col[iCol];
this->col_upper_[iCol] /= scale.col[iCol];
this->col_cost_[iCol] *= scale.col[iCol];
}
for (HighsInt iRow = 0; iRow < this->num_row_; iRow++) {
this->row_lower_[iRow] *= scale.row[iRow];
this->row_upper_[iRow] *= scale.row[iRow];
}
this->a_matrix_.applyScale(scale);
this->is_scaled_ = true;
}
}
void HighsLp::unapplyScale() {
const HighsScale& scale = this->scale_;
if (!this->is_scaled_) {
return;
}
assert(scale.has_scaling);
for (HighsInt iCol = 0; iCol < this->num_col_; iCol++) {
this->col_lower_[iCol] *= scale.col[iCol];
this->col_upper_[iCol] *= scale.col[iCol];
this->col_cost_[iCol] /= scale.col[iCol];
}
for (HighsInt iRow = 0; iRow < this->num_row_; iRow++) {
this->row_lower_[iRow] /= scale.row[iRow];
this->row_upper_[iRow] /= scale.row[iRow];
}
this->a_matrix_.unapplyScale(scale);
this->is_scaled_ = false;
}
void HighsLp::moveBackLpAndUnapplyScaling(HighsLp& lp) {
assert(this->is_moved_ == true);
*this = std::move(lp);
this->unapplyScale();
assert(this->is_moved_ == false);
}
void HighsLp::addColNames(const std::string name, const HighsInt num_new_col) {
if (this->num_col_ == 0) return;
HighsInt col_names_size = this->col_names_.size();
if (col_names_size <= 0) return;
assert(col_names_size == this->num_col_ + num_new_col);
assert(name == "");
}
void HighsLp::addRowNames(const std::string name, const HighsInt num_new_row) {
if (this->num_row_ == 0) return;
HighsInt row_names_size = this->row_names_.size();
if (row_names_size <= 0) return;
assert(row_names_size == this->num_row_ + num_new_row);
assert(name == "");
}
void HighsLp::deleteColsFromVectors(
HighsInt& new_num_col, const HighsIndexCollection& index_collection) {
assert(ok(index_collection));
HighsInt from_k;
HighsInt to_k;
limits(index_collection, from_k, to_k);
new_num_col = this->num_col_;
if (from_k > to_k) return;
HighsInt delete_from_col;
HighsInt delete_to_col;
HighsInt keep_from_col;
HighsInt keep_to_col = -1;
HighsInt current_set_entry = 0;
HighsInt col_dim = this->num_col_;
new_num_col = 0;
bool have_names = (this->col_names_.size() != 0);
bool have_integrality = (this->integrality_.size() != 0);
for (HighsInt k = from_k; k <= to_k; k++) {
updateOutInIndex(index_collection, delete_from_col, delete_to_col,
keep_from_col, keep_to_col, current_set_entry);
if (k == from_k) new_num_col = delete_from_col;
if (delete_to_col >= col_dim - 1) break;
assert(delete_to_col < col_dim);
for (HighsInt col = keep_from_col; col <= keep_to_col; col++) {
this->col_cost_[new_num_col] = this->col_cost_[col];
this->col_lower_[new_num_col] = this->col_lower_[col];
this->col_upper_[new_num_col] = this->col_upper_[col];
if (have_names) this->col_names_[new_num_col] = this->col_names_[col];
if (have_integrality)
this->integrality_[new_num_col] = this->integrality_[col];
new_num_col++;
}
if (keep_to_col >= col_dim - 1) break;
}
this->col_cost_.resize(new_num_col);
this->col_lower_.resize(new_num_col);
this->col_upper_.resize(new_num_col);
if (have_integrality) this->integrality_.resize(new_num_col);
if (have_names) this->col_names_.resize(new_num_col);
}
void HighsLp::deleteRowsFromVectors(
HighsInt& new_num_row, const HighsIndexCollection& index_collection) {
assert(ok(index_collection));
HighsInt from_k;
HighsInt to_k;
limits(index_collection, from_k, to_k);
new_num_row = this->num_row_;
if (from_k > to_k) return;
HighsInt delete_from_row;
HighsInt delete_to_row;
HighsInt keep_from_row;
HighsInt keep_to_row = -1;
HighsInt current_set_entry = 0;
HighsInt row_dim = this->num_row_;
new_num_row = 0;
bool have_names = (HighsInt)this->row_names_.size() > 0;
for (HighsInt k = from_k; k <= to_k; k++) {
updateOutInIndex(index_collection, delete_from_row, delete_to_row,
keep_from_row, keep_to_row, current_set_entry);
if (k == from_k) {
new_num_row = delete_from_row;
}
if (delete_to_row >= row_dim - 1) break;
assert(delete_to_row < row_dim);
for (HighsInt row = keep_from_row; row <= keep_to_row; row++) {
this->row_lower_[new_num_row] = this->row_lower_[row];
this->row_upper_[new_num_row] = this->row_upper_[row];
if (have_names) this->row_names_[new_num_row] = this->row_names_[row];
new_num_row++;
}
if (keep_to_row >= row_dim - 1) break;
}
this->row_lower_.resize(new_num_row);
this->row_upper_.resize(new_num_row);
if (have_names) this->row_names_.resize(new_num_row);
}
void HighsLp::deleteCols(const HighsIndexCollection& index_collection) {
HighsInt new_num_col;
this->deleteColsFromVectors(new_num_col, index_collection);
this->a_matrix_.deleteCols(index_collection);
this->num_col_ = new_num_col;
}
void HighsLp::deleteRows(const HighsIndexCollection& index_collection) {
HighsInt new_num_row;
this->deleteRowsFromVectors(new_num_row, index_collection);
this->a_matrix_.deleteRows(index_collection);
this->num_row_ = new_num_row;
}
void HighsLp::unapplyMods() {
const HighsInt num_non_semi = this->mods_.save_non_semi_variable_index.size();
for (HighsInt k = 0; k < num_non_semi; k++) {
HighsInt iCol = this->mods_.save_non_semi_variable_index[k];
assert(this->integrality_[iCol] == HighsVarType::kContinuous ||
this->integrality_[iCol] == HighsVarType::kInteger);
if (this->integrality_[iCol] == HighsVarType::kContinuous) {
this->integrality_[iCol] = HighsVarType::kSemiContinuous;
} else {
this->integrality_[iCol] = HighsVarType::kSemiInteger;
}
}
const HighsInt num_inconsistent_semi =
this->mods_.save_inconsistent_semi_variable_index.size();
if (!num_inconsistent_semi) {
assert(
!this->mods_.save_inconsistent_semi_variable_lower_bound_value.size());
assert(
!this->mods_.save_inconsistent_semi_variable_upper_bound_value.size());
assert(!this->mods_.save_inconsistent_semi_variable_type.size());
}
for (HighsInt k = 0; k < num_inconsistent_semi; k++) {
HighsInt iCol = this->mods_.save_inconsistent_semi_variable_index[k];
this->col_lower_[iCol] =
this->mods_.save_inconsistent_semi_variable_lower_bound_value[k];
this->col_upper_[iCol] =
this->mods_.save_inconsistent_semi_variable_upper_bound_value[k];
this->integrality_[iCol] =
this->mods_.save_inconsistent_semi_variable_type[k];
}
std::vector<HighsInt>& relaxed_semi_variable_lower_index =
this->mods_.save_relaxed_semi_variable_lower_bound_index;
std::vector<double>& relaxed_semi_variable_lower_value =
this->mods_.save_relaxed_semi_variable_lower_bound_value;
const HighsInt num_lower_bound = relaxed_semi_variable_lower_index.size();
if (!num_lower_bound) {
assert(!relaxed_semi_variable_lower_value.size());
}
for (HighsInt k = 0; k < num_lower_bound; k++) {
HighsInt iCol = relaxed_semi_variable_lower_index[k];
assert(this->integrality_[iCol] == HighsVarType::kSemiContinuous ||
this->integrality_[iCol] == HighsVarType::kSemiInteger);
this->col_lower_[iCol] = relaxed_semi_variable_lower_value[k];
}
std::vector<HighsInt>& tightened_semi_variable_upper_bound_index =
this->mods_.save_tightened_semi_variable_upper_bound_index;
std::vector<double>& tightened_semi_variable_upper_bound_value =
this->mods_.save_tightened_semi_variable_upper_bound_value;
const HighsInt num_upper_bound =
tightened_semi_variable_upper_bound_index.size();
if (!num_upper_bound) {
assert(!tightened_semi_variable_upper_bound_value.size());
}
for (HighsInt k = 0; k < num_upper_bound; k++) {
HighsInt iCol = tightened_semi_variable_upper_bound_index[k];
assert(this->integrality_[iCol] == HighsVarType::kSemiContinuous ||
this->integrality_[iCol] == HighsVarType::kSemiInteger);
this->col_upper_[iCol] = tightened_semi_variable_upper_bound_value[k];
}
this->mods_.clear();
}
void HighsLpMods::clear() {
this->save_non_semi_variable_index.clear();
this->save_inconsistent_semi_variable_index.clear();
this->save_inconsistent_semi_variable_lower_bound_value.clear();
this->save_inconsistent_semi_variable_upper_bound_value.clear();
this->save_inconsistent_semi_variable_type.clear();
this->save_relaxed_semi_variable_lower_bound_index.clear();
this->save_relaxed_semi_variable_lower_bound_value.clear();
this->save_tightened_semi_variable_upper_bound_index.clear();
this->save_tightened_semi_variable_upper_bound_value.clear();
this->save_inf_cost_variable_index.clear();
this->save_inf_cost_variable_cost.clear();
this->save_inf_cost_variable_lower.clear();
this->save_inf_cost_variable_upper.clear();
}
bool HighsLpMods::isClear() {
if (this->save_non_semi_variable_index.size()) return false;
if (this->save_inconsistent_semi_variable_index.size()) return false;
if (this->save_inconsistent_semi_variable_lower_bound_value.size())
return false;
if (this->save_inconsistent_semi_variable_upper_bound_value.size())
return false;
if (this->save_inconsistent_semi_variable_type.size()) return false;
if (this->save_relaxed_semi_variable_lower_bound_value.size()) return false;
if (this->save_relaxed_semi_variable_lower_bound_value.size()) return false;
if (this->save_tightened_semi_variable_upper_bound_index.size()) return false;
if (this->save_tightened_semi_variable_upper_bound_value.size()) return false;
return true;
}
void HighsNameHash::form(const std::vector<std::string>& name) {
this->clear();
for (size_t index = 0; index < name.size(); index++) {
auto emplace_result =
this->name2index.emplace(name[index], static_cast<int>(index));
const bool duplicate = !emplace_result.second;
if (duplicate) {
auto& search = emplace_result.first;
assert(int(search->second) < int(this->name2index.size()));
search->second = kHashIsDuplicate;
}
}
}
bool HighsNameHash::hasDuplicate(const std::vector<std::string>& name) {
this->clear();
bool has_duplicate = false;
for (size_t index = 0; index < name.size(); index++) {
has_duplicate =
!this->name2index.emplace(name[index], static_cast<int>(index)).second;
if (has_duplicate) break;
}
this->clear();
return has_duplicate;
}
void HighsNameHash::update(int index, const std::string& old_name,
const std::string& new_name) {
this->name2index.erase(old_name);
auto emplace_result = this->name2index.emplace(new_name, index);
if (!emplace_result.second) {
auto& search = emplace_result.first;
assert(int(search->second) < int(this->name2index.size()));
search->second = kHashIsDuplicate;
}
}
void HighsNameHash::clear() { this->name2index.clear(); }