Skip to content

Commit

Permalink
Now handles multi-case LP
Browse files Browse the repository at this point in the history
  • Loading branch information
jajhall committed Oct 25, 2024
1 parent bcadf18 commit b625ac0
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 29 deletions.
32 changes: 27 additions & 5 deletions check/TestLpSolvers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -475,11 +475,30 @@ TEST_CASE("standard-form-lp", "[highs_lp_solver]") {
std::string model;
std::string model_file;
Highs highs;
highs.setOptionValue("output_flag", dev_run);
model = "avgas";
model_file = std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps";
highs.readModel(model_file);
// highs.setOptionValue("output_flag", dev_run);
const bool test_mps = false;
if (test_mps) {
model = "avgas";
model_file = std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps";
highs.readModel(model_file);
} else {
HighsLp lp;
lp.offset_ = 0.5;
lp.num_col_ = 4;
lp.num_row_ = 3;
lp.col_cost_ = {1, 1, 1, -1};
lp.col_lower_ = {1, -kHighsInf, -kHighsInf, -1};
lp.col_upper_ = {kHighsInf, kHighsInf, 2, 3};
lp.row_lower_ = {0, 1, -kHighsInf};
lp.row_upper_ = {4, kHighsInf, 4};
lp.a_matrix_.start_ = {0, 2, 4, 6, 8};
lp.a_matrix_.index_ = {0, 2, 0, 1, 1, 2, 0, 2};
lp.a_matrix_.value_ = {1, 1, 1, 1, 1, 1, 1, 1};
highs.passModel(lp);
highs.writeModel("");
}
highs.run();
highs.writeSolution("", kSolutionStylePretty);
double required_objective_function_value =
highs.getInfo().objective_function_value;
//
Expand All @@ -502,6 +521,7 @@ TEST_CASE("standard-form-lp", "[highs_lp_solver]") {
HighsLp standard_form_lp;
standard_form_lp.num_col_ = num_col;
standard_form_lp.num_row_ = num_row;
standard_form_lp.offset_ = offset;
standard_form_lp.col_cost_ = cost;
standard_form_lp.col_lower_.assign(num_col, 0);
standard_form_lp.col_upper_.assign(num_col, kHighsInf);
Expand All @@ -511,9 +531,11 @@ TEST_CASE("standard-form-lp", "[highs_lp_solver]") {
standard_form_lp.a_matrix_.index_ = index;
standard_form_lp.a_matrix_.value_ = value;
REQUIRE(highs.passModel(standard_form_lp) == HighsStatus::kOk);
if (dev_run) highs.writeModel("");
// if (dev_run)
highs.writeModel("");
REQUIRE(highs.run() == HighsStatus::kOk);
REQUIRE(highs.getModelStatus() == HighsModelStatus::kOptimal);
highs.writeSolution("", kSolutionStylePretty);
double objective_function_value = highs.getInfo().objective_function_value;
double objective_difference =
std::fabs(objective_function_value - required_objective_function_value) /
Expand Down
2 changes: 1 addition & 1 deletion src/Highs.h
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ class Highs {
* HiGHS
*/
HighsStatus getStandardFormLp(HighsInt& num_col, HighsInt& num_row,
HighsInt& num_nz, double offset,
HighsInt& num_nz, double& offset,
double* cost = nullptr, double* rhs = nullptr,
HighsInt* start = nullptr,
HighsInt* index = nullptr,
Expand Down
4 changes: 2 additions & 2 deletions src/lp_data/Highs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1639,12 +1639,12 @@ HighsStatus Highs::run() {
}

HighsStatus Highs::getStandardFormLp(HighsInt& num_col, HighsInt& num_row,
HighsInt& num_nz, double offset,
HighsInt& num_nz, double& offset,
double* cost, double* rhs, HighsInt* start,
HighsInt* index, double* value) {
if (!this->standard_form_valid_) {
HighsStatus status = formStandardFormLp();
if (status != HighsStatus::kOk) return status;
assert(status == HighsStatus::kOk);
}
num_col = this->standard_form_cost_.size();
num_row = this->standard_form_rhs_.size();
Expand Down
74 changes: 53 additions & 21 deletions src/lp_data/HighsInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,18 @@ HighsStatus Highs::formStandardFormLp() {
local_row.start_.resize(2);
HighsInt& num_nz = local_row.start_[1];
local_row.start_[0] = 0;
HighsInt num_fixed_row = 0;
HighsInt num_boxed_row = 0;
HighsInt num_lower_row = 0;
HighsInt num_upper_row = 0;
HighsInt num_free_row = 0;
HighsInt num_fixed_col = 0;
HighsInt num_boxed_col = 0;
HighsInt num_lower_col = 0;
HighsInt num_upper_col = 0;
HighsInt num_free_col = 0;
std::vector<HighsInt> slack_ix;
HighsInt slack_k = 1;
HighsInt slack_k = 0;
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
double lower = lp.row_lower_[iRow];
double upper = lp.row_upper_[iRow];
Expand All @@ -65,41 +74,42 @@ HighsStatus Highs::formStandardFormLp() {
continue;
}
if (lower == upper) {
assert(0 == 2);
// Equality
// Equality row
num_fixed_row++;
matrix.getRow(iRow, num_nz, local_row.index_.data(),
local_row.value_.data());
standard_form_matrix.addRows(local_row);
standard_form_rhs.push_back(upper);
continue;
} else if (lower <= -kHighsInf) {
assert(0 == 3);
// Upper bounded, so record the slack
// Upper bounded row, so record the slack
num_upper_row++;
assert(upper < kHighsInf);
slack_ix.push_back(++slack_k);
matrix.getRow(iRow, num_nz, local_row.index_.data(),
local_row.value_.data());
standard_form_matrix.addRows(local_row);
standard_form_rhs.push_back(upper);
} else if (upper >= kHighsInf) {
// Lower bounded, so record the slack
// Lower bounded row, so record the slack
num_lower_row++;
assert(lower > -kHighsInf);
slack_ix.push_back(-(++slack_k));
matrix.getRow(iRow, num_nz, local_row.index_.data(),
local_row.value_.data());
standard_form_matrix.addRows(local_row);
standard_form_rhs.push_back(lower);
} else {
assert(0 == 5);
// Boxed, so record the lower slack
// Boxed row, so record the lower slack
assert(lower > -kHighsInf);
assert(upper < kHighsInf);
num_boxed_row++;
slack_ix.push_back(-(++slack_k));
matrix.getRow(iRow, num_nz, local_row.index_.data(),
local_row.value_.data());
standard_form_matrix.addRows(local_row);
standard_form_rhs.push_back(lower);
// .. and upper slack
// .. and upper slack, adding a copy of the row
slack_ix.push_back(++slack_k);
standard_form_matrix.addRows(local_row);
standard_form_rhs.push_back(upper);
Expand All @@ -114,9 +124,9 @@ HighsStatus Highs::formStandardFormLp() {
//
// x will be replaced by x = l + X (below) with X >= 0
//
// Introduce variable s >= 0 so that
// Introduce variable s >= 0 so that (with x >= l still)
//
// l + X = u - s => X + s = u - l
// x = u - s => x + s = u
standard_form_cost.push_back(0);
standard_form_matrix.num_col_++;
local_row.num_col_++;
Expand All @@ -126,7 +136,7 @@ HighsStatus Highs::formStandardFormLp() {
local_row.value_[1] = 1;
local_row.start_[1] = 2;
standard_form_matrix.addRows(local_row);
standard_form_rhs.push_back(upper - lower);
standard_form_rhs.push_back(upper);
}
}
// Finished with both matrices, row-wise, so ensure that the
Expand All @@ -145,8 +155,19 @@ HighsStatus Highs::formStandardFormLp() {
double upper = lp.col_upper_[iCol];
if (lower > -kHighsInf) {
// Finite lower bound
if (upper < kHighsInf) {
if (lower == upper) {
// Fixed column
num_fixed_col++;
} else {
// Boxed column
num_boxed_col++;
}
} else {
// Lower column
num_lower_col++;
}
if (lower != 0) {
assert(1 == 2);
// x >= l, so shift x-l = X >= 0, giving x = X + l
//
// Cost contribution c(X+l) = cX + cl
Expand All @@ -158,28 +179,30 @@ HighsStatus Highs::formStandardFormLp() {
standard_form_matrix.value_[iEl] * lower;
}
} else if (upper < kHighsInf) {
// Finite upper bound
//
// Upper column
num_upper_col++;
// Have to operate even if u=0, since cost and column values are negated
//
// x <= u, so shift u-x = X >= 0, giving x = u - X
//
// Cost contribution c(u-X) = cu - cX
standard_form_offset += cost * upper;
standard_form_cost[iCol] = -cost;
// Constraint contribution a(u-X) = au - aX
// Constraint contribution a(u-X) = -aX + au
for (HighsInt iEl = standard_form_matrix.start_[iCol];
iEl < standard_form_matrix.start_[iCol + 1]; iEl++) {
standard_form_rhs[standard_form_matrix.index_[iEl]] +=
standard_form_rhs[standard_form_matrix.index_[iEl]] -=
standard_form_matrix.value_[iEl] * upper;
standard_form_matrix.value_[iEl] = -standard_form_matrix.value_[iEl];
}
} else {
assert(1 == 4);
// Free variable
// Free column
num_free_col++;
// Represent as x = x+ - x-
//
// where original column is now x+ >= 0
//
// Represent as x = x+ - x-, where original column is now x+ >=
// 0 and x- >= 0 has negation of its cost and matrix column
// and x- >= 0 has negation of its cost and matrix column
standard_form_cost.push_back(-cost);
for (HighsInt iEl = standard_form_matrix.start_[iCol];
iEl < standard_form_matrix.start_[iCol + 1]; iEl++) {
Expand Down Expand Up @@ -210,6 +233,15 @@ HighsStatus Highs::formStandardFormLp() {
this->standard_form_cost_ = standard_form_cost;
this->standard_form_rhs_ = standard_form_rhs;
this->standard_form_matrix_ = standard_form_matrix;
highsLogUser(options_.log_options, HighsLogType::kInfo,
"Standard form LP obtained for LP with (free / lower / upper / "
"boxed / fixed) variables"
" (%d / %d / %d / %d / %d) and constraints"
" (%d / %d / %d / %d / %d) \n",
int(num_free_col), int(num_lower_col), int(num_upper_col),
int(num_boxed_col), int(num_fixed_col), int(num_free_row),
int(num_lower_row), int(num_upper_row), int(num_boxed_row),
int(num_fixed_row));
return HighsStatus::kOk;
}

Expand Down

0 comments on commit b625ac0

Please sign in to comment.