Skip to content

Commit 9bf49e1

Browse files
authored
Merge pull request #2533 from ERGO-Code/bc/issue-2487
Minor feasibility jump enhancements (fix #2487)
2 parents 683aa0f + 93cff15 commit 9bf49e1

File tree

3 files changed

+24
-16
lines changed

3 files changed

+24
-16
lines changed

FEATURES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ The irreducible infeasibility system (IIS) facility now detects infeasibility du
1212

1313
Prompted by [#2463](https://github.com/ERGO-Code/HiGHS/issues/2463), the HiGHS solution and basis files now match data to any column and row names in the model, only assuming that the data are aligned with column and row indices if there are no names in the model. This requires a new version (v2) of the HiGHS basis file. Basis files from v1 are still read, but deprecated. Now, when writing out a model, basis or solution, column and row names are added to the model - previously they were created temporarily and inconsistentyly on the fly. If the model has existing names, then distinctive names are created to replace any blank names, but names with spaces or duplicate names yield an error status return.
1414

15+
As per [#2487](https://github.com/ERGO-Code/HiGHS/issues/2487), trivial heuristics now run before feasibility jump (FJ), and FJ will use any existing incumbent. FJ will clip any finite variable values in the incumbent to lower and upper bounds, and falls back to the existing logic (lower bound if finite, else upper bound if finite, else 0) for any infinite values in the incumbent.

highs/mip/HighsFeasibilityJump.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ HighsModelStatus HighsMipSolverData::feasibilityJump() {
2727
std::vector<double> col_value(model->num_col_, 0.0);
2828
double objective_function_value;
2929

30+
const bool use_incumbent = !incumbent.empty();
31+
3032
// Configure Feasibility Jump and pass it the problem
3133
auto solver = external_feasibilityjump::FeasibilityJumpSolver(
3234
log_options,
@@ -66,10 +68,14 @@ HighsModelStatus HighsMipSolverData::feasibilityJump() {
6668
sense_multiplier * model->col_cost_[col]);
6769

6870
double initial_assignment = 0.0;
69-
if (std::isfinite(lower)) {
70-
initial_assignment = lower;
71-
} else if (std::isfinite(upper)) {
72-
initial_assignment = upper;
71+
if (use_incumbent && std::isfinite(incumbent[col])) {
72+
initial_assignment = std::max(lower, std::min(upper, incumbent[col]));
73+
} else {
74+
if (std::isfinite(lower)) {
75+
initial_assignment = lower;
76+
} else if (std::isfinite(upper)) {
77+
initial_assignment = upper;
78+
}
7379
}
7480
col_value[col] = initial_assignment;
7581
}

highs/mip/HighsMipSolver.cpp

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,19 @@ void HighsMipSolver::run() {
148148
mipdata_->queryExternalSolution(
149149
solution_objective_, kExternalMipSolutionQueryOriginAfterSetup);
150150

151+
// Apply the trivial heuristics
152+
analysis_.mipTimerStart(kMipClockTrivialHeuristics);
153+
HighsModelStatus returned_model_status = mipdata_->trivialHeuristics();
154+
analysis_.mipTimerStop(kMipClockTrivialHeuristics);
155+
if (modelstatus_ == HighsModelStatus::kNotset &&
156+
returned_model_status == HighsModelStatus::kInfeasible) {
157+
// trivialHeuristics can spot trivial infeasibility, so act on it
158+
modelstatus_ = returned_model_status;
159+
cleanupSolve();
160+
return;
161+
}
162+
// Apply the feasibility jump heuristic (if enabled)
151163
if (options_mip_->mip_heuristic_run_feasibility_jump) {
152-
// Apply the feasibility jump before evaluating the root node
153164
analysis_.mipTimerStart(kMipClockFeasibilityJump);
154165
HighsModelStatus returned_model_status = mipdata_->feasibilityJump();
155166
analysis_.mipTimerStop(kMipClockFeasibilityJump);
@@ -161,17 +172,7 @@ void HighsMipSolver::run() {
161172
return;
162173
}
163174
}
164-
// Apply the trivial heuristics
165-
analysis_.mipTimerStart(kMipClockTrivialHeuristics);
166-
HighsModelStatus returned_model_status = mipdata_->trivialHeuristics();
167-
analysis_.mipTimerStop(kMipClockTrivialHeuristics);
168-
if (modelstatus_ == HighsModelStatus::kNotset &&
169-
returned_model_status == HighsModelStatus::kInfeasible) {
170-
// trivialHeuristics can spot trivial infeasibility, so act on it
171-
modelstatus_ = returned_model_status;
172-
cleanupSolve();
173-
return;
174-
}
175+
// End of pre-root-node heuristics
175176
if (analysis_.analyse_mip_time && !submip)
176177
if (analysis_.analyse_mip_time & !submip)
177178
highsLogUser(options_mip_->log_options, HighsLogType::kInfo,

0 commit comments

Comments
 (0)