Skip to content

Commit a1ced62

Browse files
committed
Refactored feasibleWrtBounds
1 parent 346a7a8 commit a1ced62

File tree

4 files changed

+33
-59
lines changed

4 files changed

+33
-59
lines changed

check/TestMipSolver.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,11 +1075,16 @@ TEST_CASE("get-fixed-lp", "[highs_test_mip_solver]") {
10751075
REQUIRE(h.run() == HighsStatus::kOk);
10761076

10771077
REQUIRE(h.getInfo().objective_function_value == mip_optimal_objective);
1078-
// In calling changeColsBounds, the incumbent solution is cleared,
1079-
// so there is no information from which to construct an advanced
1080-
// basis. Hence simplex starts from a logical basis and requires a
1081-
// positive number of iterations (#2556)
1082-
REQUIRE(h.getInfo().simplex_iteration_count > 0);
1078+
// In calling changeColsBounds, the incumbent solution was always
1079+
// cleared, so there was no information from which to construct an
1080+
// advanced basis. Hence simplex starts from a logical basis and
1081+
// requires a positive number of iterations (#2556)
1082+
//
1083+
// Before code to retain solution if changing the bounds and
1084+
// solution remains feasible
1085+
//
1086+
// REQUIRE(h.getInfo().simplex_iteration_count > 0);
1087+
REQUIRE(h.getInfo().simplex_iteration_count == 0);
10831088

10841089
// Now, passing the MIP solution, there is information from which to
10851090
// construct an advanced basis. In the case of flugpl, this is

highs/Highs.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,9 @@ class Highs {
15681568
// Invalidates the model status, solution_ and info_
15691569
void invalidateModelStatusSolutionAndInfo();
15701570
//
1571+
// Invalidates the model status and info_
1572+
void invalidateModelStatusAndInfo();
1573+
//
15711574
// Sets model status to HighsModelStatus::kNotset
15721575
void invalidateModelStatus();
15731576
//
@@ -1637,10 +1640,7 @@ class Highs {
16371640
HighsStatus changeCostsInterface(HighsIndexCollection& index_collection,
16381641
const double* usr_col_cost);
16391642

1640-
bool feasibleWrtBounds(const bool columns,
1641-
const HighsIndexCollection& index_collection,
1642-
const std::vector<double>& lower,
1643-
const std::vector<double>& upper) const;
1643+
bool feasibleWrtBounds(const bool columns = true) const;
16441644
HighsStatus changeColBoundsInterface(HighsIndexCollection& index_collection,
16451645
const double* usr_col_lower,
16461646
const double* usr_col_upper);

highs/lp_data/Highs.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3723,8 +3723,12 @@ void Highs::invalidateSolverDualData() {
37233723
}
37243724

37253725
void Highs::invalidateModelStatusSolutionAndInfo() {
3726-
invalidateModelStatus();
3726+
invalidateModelStatusAndInfo();
37273727
invalidateSolution();
3728+
}
3729+
3730+
void Highs::invalidateModelStatusAndInfo() {
3731+
invalidateModelStatus();
37283732
invalidateRanging();
37293733
invalidateInfo();
37303734
invalidateIis();

highs/lp_data/HighsInterface.cpp

Lines changed: 14 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -985,51 +985,21 @@ HighsStatus Highs::changeCostsInterface(HighsIndexCollection& index_collection,
985985
return HighsStatus::kOk;
986986
}
987987

988-
bool Highs::feasibleWrtBounds(const bool columns,
989-
const HighsIndexCollection& index_collection,
990-
const std::vector<double>& lower,
991-
const std::vector<double>& upper) const {
988+
bool Highs::feasibleWrtBounds(const bool columns) const {
992989
if (this->info_.primal_solution_status != kSolutionStatusFeasible)
993990
return false;
994991
const HighsLp& lp = model_.lp_;
995992
const double primal_feasibility_tolerance =
996993
this->options_.primal_feasibility_tolerance;
997-
assert(ok(index_collection));
998-
HighsInt from_k;
999-
HighsInt to_k;
1000-
limits(index_collection, from_k, to_k);
1001-
if (from_k > to_k) return true;
1002-
1003-
const bool& interval = index_collection.is_interval_;
1004-
const bool& mask = index_collection.is_mask_;
1005-
const vector<HighsInt>& ix_set = index_collection.set_;
1006-
const vector<HighsInt>& ix_mask = index_collection.mask_;
1007-
1008994
std::vector<double> value = columns ?
1009995
this->solution_.col_value :
1010996
this->solution_.row_value;
1011-
1012-
HighsInt lp_ix;
1013-
HighsInt usr_ix = -1;
1014-
HighsInt ix_dim = value.size();
1015-
// Surely this is checked elsewhere
1016-
assert(0 <= from_k && to_k < ix_dim);
1017-
assert(from_k <= to_k);
1018-
for (HighsInt k = from_k; k < to_k + 1; k++) {
1019-
if (interval || mask) {
1020-
lp_ix = k;
1021-
} else {
1022-
lp_ix = ix_set[k];
1023-
}
1024-
HighsInt ix = lp_ix;
1025-
if (interval) {
1026-
usr_ix++;
1027-
} else {
1028-
usr_ix = k;
1029-
}
1030-
if (mask && !ix_mask[ix]) continue;
1031-
if (value[ix] < lower[usr_ix] - primal_feasibility_tolerance) return false;
1032-
if (value[ix] > upper[usr_ix] + primal_feasibility_tolerance) return false;
997+
std::vector<double> lower = columns ? lp.col_lower_ : lp.row_lower_;
998+
std::vector<double> upper = columns ? lp.col_upper_ : lp.row_upper_;
999+
HighsInt dim = columns ? lp.num_col_ : lp.num_row_;
1000+
for (HighsInt iX = 0; iX < dim; iX++) {
1001+
if (value[iX] < lower[iX] - primal_feasibility_tolerance) return false;
1002+
if (value[iX] > upper[iX] + primal_feasibility_tolerance) return false;
10331003
}
10341004
return true;
10351005
}
@@ -1086,19 +1056,14 @@ HighsStatus Highs::changeColBoundsInterface(
10861056
// nonbasic variables whose bounds have changed
10871057
setNonbasicStatusInterface(index_collection, true);
10881058
// Deduce the consequences of new col bounds
1089-
if (!this->basis_.useful) {
1090-
const bool columns = true;
1091-
const bool feasible = feasibleWrtBounds(columns, index_collection,
1092-
local_colLower, local_colUpper);
1093-
// highsLogUser(options_.log_options, HighsLogType::kInfo,
1094-
printf(
1095-
"feasibleWrtBounds is %s\n", feasible ? "True" : "False");
1096-
if (feasible) {
1097-
feasibleWrtBounds(columns, index_collection,
1098-
local_colLower, local_colUpper);
1099-
}
1059+
if (!this->basis_.useful && feasibleWrtBounds()) {
1060+
// Retain the solution if there's no basis, and the solution is
1061+
// feasible
1062+
invalidateModelStatusAndInfo();
1063+
} else {
1064+
// Invalidate the solution
1065+
invalidateModelStatusSolutionAndInfo();
11001066
}
1101-
invalidateModelStatusSolutionAndInfo();
11021067
// Determine any implications for simplex data
11031068
ekk_instance_.updateStatus(LpAction::kNewBounds);
11041069
return HighsStatus::kOk;

0 commit comments

Comments
 (0)