Skip to content

Commit 6011753

Browse files
committed
Still passes bin/unit_tests mip-race
1 parent 84f4bb5 commit 6011753

File tree

5 files changed

+67
-24
lines changed

5 files changed

+67
-24
lines changed

check/TestMipSolver.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,9 +1049,13 @@ TEST_CASE("mip-race", "[highs_test_mip_solver]") {
10491049
const HighsInt mip_race_concurrency = ci_test ? 2 : 4;
10501050
h.setOptionValue("mip_race_concurrency", mip_race_concurrency);
10511051
h.setOptionValue("mip_race_read_solutions", true);
1052-
REQUIRE(h.readModel(model_file) == HighsStatus::kOk);
1053-
REQUIRE(h.run() == HighsStatus::kOk);
1054-
REQUIRE(h.getModelStatus() == HighsModelStatus::kOptimal);
1052+
for (HighsInt k = 0; k < 1; k++) {
1053+
bool mip_race_single_presolve = k == 0 ? false : true;
1054+
h.setOptionValue("mip_race_single_presolve", mip_race_single_presolve);
1055+
REQUIRE(h.readModel(model_file) == HighsStatus::kOk);
1056+
REQUIRE(h.run() == HighsStatus::kOk);
1057+
REQUIRE(h.getModelStatus() == HighsModelStatus::kOptimal);
1058+
}
10551059

10561060
if (ci_test) {
10571061
h.clearSolver();

highs/Highs.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1714,10 +1714,11 @@ class Highs {
17141714
bool optionsHasHighsFiles() const;
17151715
void saveHighsFiles();
17161716
void getHighsFiles();
1717-
HighsStatus mipRaceResults(HighsMipSolverInfo& mip_solver_info,
1717+
HighsStatus mipRaceResults(bool use_mip_race_single_presolve,
1718+
HighsMipSolverInfo& mip_solver_info,
17181719
const std::vector<HighsMipSolverInfo>& worker_info,
17191720
const std::vector<double>& mip_time,
1720-
const double& report_mip_time);
1721+
double mip_race_time);
17211722
};
17221723

17231724
// Start of deprecated methods not in the Highs class

highs/lp_data/Highs.cpp

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4031,13 +4031,45 @@ HighsStatus Highs::callSolveMip() {
40314031
options_.primal_feasibility_tolerance);
40324032
}
40334033
HighsLp& lp = has_semi_variables ? use_lp : model_.lp_;
4034-
4034+
// Start timing any MIP race before its presolve and parallel MIP
4035+
// solver calls. This timer is stopped in Highs::mipRaceResults
4036+
// after any postsolve is performed
4037+
double mip_race_time = -this->timer_.read();
4038+
HighsLp presolved_lp;
4039+
const HighsInt mip_race_concurrency = this->options_.mip_race_concurrency;
4040+
const bool run_mip_race = mip_race_concurrency > 1;
4041+
// Determine whether to do a single presolve before any MIP race
4042+
//
4043+
// Doesn't work when there are semi-variables since they have to be
4044+
// converted into the use_lp instance, and this->presolve(); works
4045+
// on the incumbent model
4046+
const bool use_mip_race_single_presolve =
4047+
run_mip_race &&
4048+
options_.mip_race_single_presolve &&
4049+
options_.presolve != kHighsOffString &&
4050+
!has_semi_variables;
4051+
if (use_mip_race_single_presolve) {
4052+
// Perform presolve before the MIP race
4053+
//
4054+
// NB This is normally called externally, so calls
4055+
// returnFromHighs(). This will stop the run clock, and check that
4056+
// called_return_from_optimize_model is true - when it isn't. So,
4057+
// add a hack to set called_return_from_optimize_model true before
4058+
// the call to presolve...
4059+
assert(!this->called_return_from_optimize_model);
4060+
this->called_return_from_optimize_model = true;
4061+
this->presolve();
4062+
// ... then set it back to false and restart the run clock
4063+
this->called_return_from_optimize_model = false;
4064+
this->timer_.start();
4065+
presolved_lp = this->getPresolvedLp();
4066+
lp = presolved_lp;
4067+
}
40354068
// Create the master MIP solver instance that will exist beyond any
4036-
// race
4069+
// MIP race
40374070
HighsMipSolver solver(callback_, options_, lp, solution_);
40384071
HighsMipSolverInfo mip_solver_info;
4039-
const HighsInt mip_race_concurrency = this->options_.mip_race_concurrency;
4040-
if (mip_race_concurrency > 1) {
4072+
if (run_mip_race) {
40414073
// Set up the shared memory for the MIP solver race
40424074
MipRaceRecord mip_race_record;
40434075
mip_race_record.initialise(mip_race_concurrency, lp.num_col_);
@@ -4070,14 +4102,7 @@ HighsStatus Highs::callSolveMip() {
40704102
if (options_.output_flag)
40714103
highsOpenLogFile(instance_options, worker_log_file);
40724104
worker_options.push_back(instance_options);
4073-
/*
4074-
HighsMipSolver worker_instance(worker_callback, worker_options[instance],
4075-
lp, solution_); worker.push_back(&worker_instance);
4076-
*/
40774105
}
4078-
// Time the master outside the parallel loop so that this "real"
4079-
// time is reported
4080-
double loop_mip_time = -timer_.read();
40814106
highs::parallel::for_each(
40824107
0, mip_race_concurrency, [&](HighsInt start, HighsInt end) {
40834108
for (HighsInt instance = start; instance < end; instance++) {
@@ -4104,10 +4129,10 @@ HighsStatus Highs::callSolveMip() {
41044129
}
41054130
}
41064131
});
4107-
loop_mip_time += timer_.read();
41084132
// Determine the winner and report on the solution
4109-
HighsStatus call_status = this->mipRaceResults(mip_solver_info, worker_info,
4110-
mip_time, loop_mip_time);
4133+
HighsStatus call_status = this->mipRaceResults(use_mip_race_single_presolve,
4134+
mip_solver_info, worker_info,
4135+
mip_time, mip_race_time);
41114136
if (call_status == HighsStatus::kError) {
41124137
const bool undo_mods = true;
41134138
return returnFromOptimizeModel(HighsStatus::kError, undo_mods);

highs/lp_data/HighsInterface.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4261,10 +4261,11 @@ void HighsMipSolverInfo::clear() {
42614261
this->primal_dual_integral = -kHighsInf;
42624262
}
42634263

4264-
HighsStatus Highs::mipRaceResults(
4265-
HighsMipSolverInfo& mip_solver_info,
4266-
const std::vector<HighsMipSolverInfo>& worker_info,
4267-
const std::vector<double>& mip_time, const double& report_mip_time) {
4264+
HighsStatus Highs::mipRaceResults(bool use_mip_race_single_presolve,
4265+
HighsMipSolverInfo& mip_solver_info,
4266+
const std::vector<HighsMipSolverInfo>& worker_info,
4267+
const std::vector<double>& mip_time,
4268+
double mip_race_time) {
42684269
const HighsInt mip_race_concurrency = this->options_.mip_race_concurrency;
42694270
HighsInt winning_instance = -1;
42704271
HighsModelStatus winning_model_status = HighsModelStatus::kNotset;
@@ -4301,6 +4302,10 @@ HighsStatus Highs::mipRaceResults(
43014302
}
43024303
}
43034304
if (winning_instance > 0) mip_solver_info = worker_info[winning_instance];
4305+
4306+
if (use_mip_race_single_presolve) assert(111==444);
4307+
mip_race_time += this->timer_.read();
4308+
43044309
std::array<char, 128> gapString = getGapString(
43054310
mip_solver_info.gap, mip_solver_info.primal_bound, &options_);
43064311

@@ -4351,7 +4356,7 @@ HighsStatus Highs::mipRaceResults(
43514356
// Report the solution time for the whole concurrent loop, as that's
43524357
// "real" time
43534358
highsLogUser(options_.log_options, HighsLogType::kInfo,
4354-
" Timing %.2f\n", report_mip_time);
4359+
" Timing %.2f\n", mip_race_time);
43554360
highsLogUser(options_.log_options, HighsLogType::kInfo,
43564361
" Max sub-MIP depth %d\n",
43574362
int(mip_solver_info.max_submip_level));

highs/lp_data/HighsOptions.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ struct HighsOptionsStruct {
426426
bool mip_allow_restart;
427427
HighsInt mip_race_concurrency;
428428
bool mip_race_read_solutions;
429+
bool mip_race_single_presolve;
429430
HighsInt mip_max_nodes;
430431
HighsInt mip_max_stall_nodes;
431432
HighsInt mip_max_start_nodes;
@@ -579,6 +580,7 @@ struct HighsOptionsStruct {
579580
mip_allow_restart(false),
580581
mip_race_concurrency(0),
581582
mip_race_read_solutions(false),
583+
mip_race_single_presolve(false),
582584
mip_max_nodes(0),
583585
mip_max_stall_nodes(0),
584586
mip_max_start_nodes(0),
@@ -1032,6 +1034,12 @@ class HighsOptions : public HighsOptionsStruct {
10321034
&mip_race_read_solutions, true);
10331035
records.push_back(record_bool);
10341036

1037+
record_bool = new OptionRecordBool(
1038+
"mip_race_single_presolve",
1039+
"Whether the MIP races should follow a single presolve", advanced,
1040+
&mip_race_single_presolve, true);
1041+
records.push_back(record_bool);
1042+
10351043
record_int = new OptionRecordInt("mip_max_nodes",
10361044
"MIP solver max number of nodes", advanced,
10371045
&mip_max_nodes, 0, kHighsIInf, kHighsIInf);

0 commit comments

Comments
 (0)