Skip to content

Commit

Permalink
Added inward integer rounding of bounds to Highs::infeasibleBoundsOk,…
Browse files Browse the repository at this point in the history
… but temporarily switched off so that bin/unit_tests MIP-unbounded still propagates to FJ
  • Loading branch information
jajhall committed Dec 4, 2024
1 parent 23e5283 commit 9707618
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 29 deletions.
39 changes: 15 additions & 24 deletions check/TestMipSolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,34 +371,25 @@ TEST_CASE("MIP-unbounded", "[highs_test_mip_solver]") {

// Now as a MIP - infeasible
lp.integrality_ = {HighsVarType::kContinuous, HighsVarType::kInteger};
use_presolve = false;
for (HighsInt k = 0; k < 2; k++) {
if (use_presolve) {
// With use_presolve = true, MIP solver returns
// HighsModelStatus::kUnboundedOrInfeasible from presolve
highs.setOptionValue("presolve", kHighsOnString);
require_model_status = HighsModelStatus::kUnboundedOrInfeasible;
highs.setOptionValue("output_flag", dev_run);
} else {
// With use_presolve = false, MIP solver returns
// HighsModelStatus::kUnboundedOrInfeasible
highs.setOptionValue("presolve", kHighsOffString);
require_model_status = HighsModelStatus::kUnboundedOrInfeasible;
highs.setOptionValue("output_flag", true);
}
// With(out) presolve, Highs::infeasibleBoundsOk() performs inwardd
// integer rounding of [0.25, 0.75] to [1, 0] so identifes
// infeasiblility. Hence MIP solver returns
// HighsModelStatus::kInfeasible

return_status = highs.passModel(lp);
REQUIRE(return_status == HighsStatus::kOk);
// Run with presolve off so that this example still propagates to FJ
highs.setOptionValue("output_flag", true);
highs.setOptionValue("presolve", kHighsOffString);

return_status = highs.run();
REQUIRE(return_status == HighsStatus::kOk);
return_status = highs.passModel(lp);
REQUIRE(return_status == HighsStatus::kOk);

model_status = highs.getModelStatus();
REQUIRE(model_status == require_model_status);
return_status = highs.run();
REQUIRE(return_status == HighsStatus::kOk);

model_status = highs.getModelStatus();
REQUIRE(model_status == HighsModelStatus::kUnboundedOrInfeasible);
// REQUIRE(model_status == HighsModelStatus::kInfeasible);

// Second time through loop is with presolve
use_presolve = true;
}
}

TEST_CASE("MIP-od", "[highs_test_mip_solver]") {
Expand Down
22 changes: 18 additions & 4 deletions src/lp_data/HighsInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3557,16 +3557,30 @@ bool Highs::infeasibleBoundsOk() {
return false;
};

const bool perform_inward_integer_rounding = false;
if (!perform_inward_integer_rounding)
printf("Highs::infeasibleBoundsOk() Not performing inward integer rounding of bounds\n");
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
double lower = lp.col_lower_[iCol];
double upper = lp.col_upper_[iCol];
if (has_integrality) {
// Semi-variables can have inconsistent bounds
// Semi-variables cannot have inconsistent bounds
if (lp.integrality_[iCol] == HighsVarType::kSemiContinuous ||
lp.integrality_[iCol] == HighsVarType::kSemiInteger)
continue;
if (perform_inward_integer_rounding &&
lp.integrality_[iCol] == HighsVarType::kInteger) {
// Assess bounds after inward integer rounding
double integer_lower = std::ceil(lower);
double integer_upper = std::floor(lower);
assert(integer_lower >= lower);
assert(integer_upper <= upper);
lower = integer_lower;
upper = integer_upper;
}
}
if (lp.col_lower_[iCol] > lp.col_upper_[iCol])
assessInfeasibleBound("Column", iCol, lp.col_lower_[iCol],
lp.col_upper_[iCol]);
if (lower > upper)
assessInfeasibleBound("Column", iCol, lower, upper);
}
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
if (lp.row_lower_[iRow] > lp.row_upper_[iRow])
Expand Down
2 changes: 1 addition & 1 deletion src/mip/feasibilityjump.hh
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ namespace external_feasibilityjump {
double weightUpdateDecay;
double weightUpdateIncrement = 1.0;

size_t nBumps;
size_t nBumps = 0;

// The probability of choosing a random positive-score variable.
const double randomVarProbability = 0.001;
Expand Down

0 comments on commit 9707618

Please sign in to comment.