Skip to content

Commit 4dd628d

Browse files
authored
Merge pull request #2525 from ERGO-Code/fix-force-highs-solution-basis-size
Fix `Highs::forceHighsSolutionBasisSize`
2 parents dc27d34 + 39d2afc commit 4dd628d

File tree

3 files changed

+70
-14
lines changed

3 files changed

+70
-14
lines changed

check/TestBasis.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,3 +315,43 @@ void testBasisRestart(Highs& highs, const std::string& basis_file,
315315

316316
REQUIRE(info.simplex_iteration_count == 0);
317317
}
318+
319+
TEST_CASE("Basis-read", "[highs_basis_data]") {
320+
// Duplicates test_read_basis in test_highspy.py
321+
const std::string test_name = Catch::getResultCapture().getCurrentTestName();
322+
323+
HighsLp lp;
324+
lp.num_col_ = 2;
325+
lp.num_row_ = 2;
326+
lp.col_cost_ = {0, 1};
327+
lp.col_lower_.assign(lp.num_col_, -kHighsInf);
328+
lp.col_upper_.assign(lp.num_col_, kHighsInf);
329+
lp.row_lower_ = {2, 0};
330+
lp.row_upper_.assign(lp.num_row_, kHighsInf);
331+
lp.a_matrix_.start_ = {0, 2, 4};
332+
lp.a_matrix_.index_ = {0, 1, 0, 1};
333+
lp.a_matrix_.value_ = {-1, 1, 1, 1};
334+
335+
HighsBasisStatus status_before = HighsBasisStatus::kNonbasic;
336+
HighsBasisStatus status_after = HighsBasisStatus::kBasic;
337+
Highs h1;
338+
const HighsBasis& basis1 = h1.getBasis();
339+
h1.passModel(lp);
340+
REQUIRE(basis1.col_status[0] == status_before);
341+
h1.run();
342+
REQUIRE(basis1.col_status[0] == status_after);
343+
344+
Highs h2;
345+
const HighsBasis& basis2 = h2.getBasis();
346+
h2.passModel(lp);
347+
REQUIRE(basis2.col_status[0] == status_before);
348+
349+
const std::string basis_file = test_name + ".bas";
350+
h1.writeBasis(basis_file);
351+
h2.readBasis(basis_file);
352+
REQUIRE(basis2.col_status[0] == status_after);
353+
354+
std::remove(basis_file.c_str());
355+
h1.resetGlobalScheduler(true);
356+
h2.resetGlobalScheduler(true);
357+
}

highs/lp_data/Highs.cpp

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4368,23 +4368,39 @@ void Highs::newHighsBasis() {
43684368
// model, and that the HiGHS basis is kept up-to-date with any solved
43694369
// basis
43704370
void Highs::forceHighsSolutionBasisSize() {
4371-
// Ensure that the HiGHS solution vectors are the right size
4372-
solution_.col_value.resize(model_.lp_.num_col_);
4373-
solution_.row_value.resize(model_.lp_.num_row_);
4374-
solution_.col_dual.resize(model_.lp_.num_col_);
4375-
solution_.row_dual.resize(model_.lp_.num_row_);
4376-
// Ensure that the HiGHS basis vectors are the right size,
4377-
// invalidating the basis if they aren't
4378-
if (basis_.col_status.size() != static_cast<size_t>(model_.lp_.num_col_)) {
4379-
basis_.col_status.resize(model_.lp_.num_col_);
4380-
basis_.valid = false;
4381-
basis_.useful = false;
4371+
// Ensure that the HiGHS solution and basis vectors are the right size
4372+
//
4373+
// If the column or row, values or duals, are increased in size,
4374+
// ensure that values are assigned to the new entries, and that
4375+
// validity and status values are over-written in HighsSolution,
4376+
// HighsBasis and HighsInfo
4377+
const HighsInt num_col = this->model_.lp_.num_col_;
4378+
const HighsInt num_row = this->model_.lp_.num_row_;
4379+
// Values
4380+
if (solution_.col_value.size() < static_cast<size_t>(num_col) ||
4381+
solution_.row_value.size() < static_cast<size_t>(num_row)) {
4382+
solution_.value_valid = false;
4383+
info_.primal_solution_status = kSolutionStatusNone;
4384+
}
4385+
solution_.col_value.resize(num_col, 0);
4386+
solution_.row_value.resize(num_row, 0);
4387+
// Duals
4388+
if (solution_.col_dual.size() < static_cast<size_t>(num_col) ||
4389+
solution_.row_dual.size() < static_cast<size_t>(num_row)) {
4390+
solution_.dual_valid = false;
4391+
info_.dual_solution_status = kSolutionStatusNone;
43824392
}
4383-
if (basis_.row_status.size() != static_cast<size_t>(model_.lp_.num_row_)) {
4384-
basis_.row_status.resize(model_.lp_.num_row_);
4393+
solution_.col_dual.resize(num_col, 0);
4394+
solution_.row_dual.resize(num_row, 0);
4395+
// Basis
4396+
if (basis_.col_status.size() != static_cast<size_t>(num_col) ||
4397+
basis_.row_status.size() != static_cast<size_t>(num_row)) {
43854398
basis_.valid = false;
43864399
basis_.useful = false;
4400+
info_.basis_validity = kBasisValidityInvalid;
43874401
}
4402+
basis_.col_status.resize(num_col, HighsBasisStatus::kNonbasic);
4403+
basis_.row_status.resize(num_row, HighsBasisStatus::kBasic);
43884404
}
43894405

43904406
void Highs::setHighsModelStatusAndClearSolutionAndBasis(

tests/test_highspy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1004,7 +1004,7 @@ def test_write_basis_after_running(self):
10041004
def test_read_basis(self):
10051005
if platform == "linux" or platform == "darwin":
10061006
# Read basis from one run model into an unrun model
1007-
expected_status_before = highspy.HighsBasisStatus.kLower
1007+
expected_status_before = highspy.HighsBasisStatus.kNonbasic
10081008
expected_status_after = highspy.HighsBasisStatus.kBasic
10091009

10101010
h1 = self.get_basic_model()

0 commit comments

Comments
 (0)