@@ -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);
0 commit comments