Skip to content

Commit 0c3ddc5

Browse files
committed
Deleted MIP race code
1 parent d77e739 commit 0c3ddc5

File tree

8 files changed

+30
-662
lines changed

8 files changed

+30
-662
lines changed

check/TestMipSolver.cpp

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,33 +1035,3 @@ TEST_CASE("issue-2432", "[highs_test_mip_solver]") {
10351035
"found\n");
10361036
solve(highs, kHighsOffString, require_model_status, optimal_objective);
10371037
}
1038-
1039-
TEST_CASE("mip-race", "[highs_test_mip_solver]") {
1040-
const bool ci_test = true;
1041-
const std::string test_build_model = "fiball"; //"neos-3381206-awhea"; //
1042-
const std::string model = ci_test ? "flugpl" : test_build_model;
1043-
// "neos-3381206-awhea";
1044-
const std::string model_file =
1045-
ci_test ? std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps"
1046-
: "/srv/miplib2017/" + model + ".mps.gz";
1047-
Highs h;
1048-
if (ci_test) h.setOptionValue("output_flag", dev_run);
1049-
const HighsInt mip_race_concurrency = ci_test ? 2 : 4;
1050-
h.setOptionValue("mip_race_concurrency", mip_race_concurrency);
1051-
h.setOptionValue("mip_race_read_solutions", true);
1052-
for (HighsInt k = 0; k < 2; 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-
}
1059-
1060-
if (ci_test) {
1061-
h.clearSolver();
1062-
h.setOptionValue("mip_race_read_solutions", false);
1063-
REQUIRE(h.run() == HighsStatus::kOk);
1064-
REQUIRE(h.getModelStatus() == HighsModelStatus::kOptimal);
1065-
}
1066-
h.resetGlobalScheduler(true);
1067-
}

highs/Highs.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,9 +1503,8 @@ class Highs {
15031503
HighsStatus callSolveLp(HighsLp& lp, const string message);
15041504
HighsStatus callSolveQp();
15051505
HighsStatus callSolveMip();
1506-
HighsStatus callRunPostsolve(
1507-
const HighsSolution& solution, const HighsBasis& basis,
1508-
const bool suppress_mip_model_status_warning = false);
1506+
HighsStatus callRunPostsolve(const HighsSolution& solution,
1507+
const HighsBasis& basis);
15091508

15101509
PresolveComponent presolve_;
15111510
HighsPresolveStatus runPresolve(const bool force_lp_presolve,
@@ -1715,11 +1714,6 @@ class Highs {
17151714
bool optionsHasHighsFiles() const;
17161715
void saveHighsFiles();
17171716
void getHighsFiles();
1718-
HighsStatus mipRaceResults(bool use_mip_race_single_presolve,
1719-
HighsMipSolverInfo& mip_solver_info,
1720-
const std::vector<HighsMipSolverInfo>& worker_info,
1721-
const std::vector<double>& mip_time,
1722-
double mip_race_time);
17231717
};
17241718

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

highs/lp_data/Highs.cpp

Lines changed: 10 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -4030,127 +4030,11 @@ HighsStatus Highs::callSolveMip() {
40304030
use_lp = withoutSemiVariables(model_.lp_, solution_,
40314031
options_.primal_feasibility_tolerance);
40324032
}
4033-
// Start timing any MIP race before its presolve and parallel MIP
4034-
// solver calls. This timer is stopped in Highs::mipRaceResults
4035-
// after any postsolve is performed
4036-
double mip_race_time = -this->timer_.read();
4037-
HighsLp presolved_lp;
4038-
const HighsInt mip_race_concurrency = this->options_.mip_race_concurrency;
4039-
const bool run_mip_race = mip_race_concurrency > 1;
4040-
// Determine whether to do a single presolve before any MIP race
4041-
//
4042-
// Doesn't work when there are semi-variables since they have to be
4043-
// converted into the use_lp instance, and this->presolve(); works
4044-
// on the incumbent model
4045-
const bool use_mip_race_single_presolve =
4046-
run_mip_race && options_.mip_race_single_presolve &&
4047-
options_.presolve != kHighsOffString && !has_semi_variables;
4048-
// Take a copy of the presolve option in case it's switched off for
4049-
// a single presolve MIP race
4050-
const std::string presolve = this->options_.presolve;
4051-
if (use_mip_race_single_presolve) {
4052-
// Perform presolve before the MIP race
4053-
//
4054-
// NB Highs::presolve() 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-
HighsStatus call_status = 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-
if (call_status != HighsStatus::kOk) return call_status;
4066-
presolved_lp = this->getPresolvedLp();
4067-
this->options_.presolve = kHighsOffString;
4068-
}
4069-
// Create the master MIP solver instance that will exist beyond any
4070-
// MIP race
4071-
HighsLp& lp =
4072-
has_semi_variables
4073-
? use_lp
4074-
: (use_mip_race_single_presolve ? presolved_lp : model_.lp_);
4033+
HighsLp& lp = has_semi_variables ? use_lp : model_.lp_;
40754034
HighsMipSolver solver(callback_, options_, lp, solution_);
40764035
HighsMipSolverInfo mip_solver_info;
4077-
if (run_mip_race) {
4078-
// Set up the shared memory for the MIP solver race
4079-
MipRaceRecord mip_race_record;
4080-
mip_race_record.initialise(mip_race_concurrency, lp.num_col_);
4081-
// Set up the shared memory for the concurrent MIP terminator
4082-
auto terminator_record =
4083-
solver.initialiseTerminatorRecord(mip_race_concurrency);
4084-
// Don't allow callbacks for workers
4085-
HighsCallback worker_callback = callback_;
4086-
worker_callback.clear();
4087-
// Race the MIP solver!
4088-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4089-
"\nStarting MIP race with %d instances: behaviour is "
4090-
"non-deterministic!\n\n",
4091-
int(mip_race_concurrency));
4092-
// Define the HighsMipSolverInfo record for each worker
4093-
std::vector<HighsMipSolverInfo> worker_info(mip_race_concurrency);
4094-
// Set up the vector of options settings for workers
4095-
std::vector<HighsOptions> worker_options;
4096-
// std::vector<HighsMipSolver*> worker;
4097-
std::vector<double> mip_time(mip_race_concurrency);
4098-
for (HighsInt instance = 0; instance < mip_race_concurrency; instance++) {
4099-
HighsOptions instance_options = options_;
4100-
// No workers log to console
4101-
instance_options.log_to_console = false;
4102-
instance_options.setLogOptions();
4103-
// Use the instance ID as an offset to the random seed
4104-
instance_options.random_seed = options_.random_seed + instance;
4105-
std::string worker_log_file =
4106-
"mip_worker" + std::to_string(instance) + ".log";
4107-
if (options_.output_flag)
4108-
highsOpenLogFile(instance_options, worker_log_file);
4109-
worker_options.push_back(instance_options);
4110-
}
4111-
highs::parallel::for_each(
4112-
0, mip_race_concurrency, [&](HighsInt start, HighsInt end) {
4113-
for (HighsInt instance = start; instance < end; instance++) {
4114-
if (instance == 0) {
4115-
solver.initialiseTerminator(mip_race_concurrency, instance,
4116-
terminator_record.data());
4117-
solver.initialiseMipRace(mip_race_concurrency, instance,
4118-
&mip_race_record);
4119-
mip_time[instance] = -timer_.read();
4120-
solver.run();
4121-
mip_time[instance] += timer_.read();
4122-
mip_solver_info = getMipSolverInfo(solver);
4123-
} else {
4124-
HighsMipSolver worker(worker_callback, worker_options[instance],
4125-
lp, solution_);
4126-
worker.initialiseTerminator(mip_race_concurrency, instance,
4127-
terminator_record.data());
4128-
worker.initialiseMipRace(mip_race_concurrency, instance,
4129-
&mip_race_record);
4130-
mip_time[instance] = -timer_.read();
4131-
worker.run();
4132-
mip_time[instance] += timer_.read();
4133-
worker_info[instance] = getMipSolverInfo(worker);
4134-
}
4135-
}
4136-
});
4137-
// Determine the winner and report on the solution
4138-
HighsStatus call_status =
4139-
this->mipRaceResults(use_mip_race_single_presolve, mip_solver_info,
4140-
worker_info, mip_time, mip_race_time);
4141-
// Restore the presolve option - that will have been set to
4142-
// kHighsOffString for a single presolve MIP race
4143-
this->options_.presolve = presolve;
4144-
4145-
if (call_status == HighsStatus::kError) {
4146-
const bool undo_mods = true;
4147-
return returnFromOptimizeModel(HighsStatus::kError, undo_mods);
4148-
}
4149-
} else {
4150-
// Run a single MIP solver
4151-
solver.run();
4152-
mip_solver_info = getMipSolverInfo(solver);
4153-
}
4036+
solver.run();
4037+
mip_solver_info = getMipSolverInfo(solver);
41544038
options_.log_dev_level = log_dev_level;
41554039
// Set the return_status, model status and, for completeness, scaled
41564040
// model status
@@ -4160,14 +4044,7 @@ HighsStatus Highs::callSolveMip() {
41604044
// Extract the solution
41614045
if (mip_solver_info.solution_objective != kHighsInf) {
41624046
// There is a primal solution
4163-
HighsInt solver_solution_size = mip_solver_info.solution.size();
4164-
const bool solver_solution_size_ok = solver_solution_size >= lp.num_col_;
4165-
if (!solver_solution_size)
4166-
highsLogUser(
4167-
options_.log_options, HighsLogType::kError,
4168-
"After MIP race, size of solution is %d < %d = lp.num_col_\n",
4169-
int(solver_solution_size), int(lp.num_col_));
4170-
assert(solver_solution_size >= lp.num_col_);
4047+
//
41714048
// If the original model has semi-variables, its solution is
41724049
// (still) given by the first model_.lp_.num_col_ entries of the
41734050
// solution from the MIP solver
@@ -4240,10 +4117,9 @@ HighsStatus Highs::callSolveMip() {
42404117
return return_status;
42414118
}
42424119

4243-
// Only called from Highs::postsolve and Highs::mipRaceResults
4244-
HighsStatus Highs::callRunPostsolve(
4245-
const HighsSolution& solution, const HighsBasis& basis,
4246-
const bool suppress_mip_model_status_warning) {
4120+
// Only called from Highs::postsolve
4121+
HighsStatus Highs::callRunPostsolve(const HighsSolution& solution,
4122+
const HighsBasis& basis) {
42474123
HighsStatus return_status = HighsStatus::kOk;
42484124
HighsStatus call_status;
42494125
const HighsLp& presolved_lp = presolve_.getReducedProblem();
@@ -4308,12 +4184,9 @@ HighsStatus Highs::callRunPostsolve(
43084184
max_integrality_violation);
43094185
}
43104186
}
4311-
// When calling postsolve after MIP race on presolved model,
4312-
// model status can be trusted so suppress the warning message
4313-
if (!suppress_mip_model_status_warning)
4314-
highsLogUser(
4315-
options_.log_options, HighsLogType::kWarning,
4316-
"Postsolve performed for MIP, but model status cannot be known\n");
4187+
highsLogUser(
4188+
options_.log_options, HighsLogType::kWarning,
4189+
"Postsolve performed for MIP, but model status cannot be known\n");
43174190
} else {
43184191
highsLogUser(options_.log_options, HighsLogType::kError,
43194192
"Postsolve return status is %d\n", (int)postsolve_status);

highs/lp_data/HighsInterface.cpp

Lines changed: 0 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -4260,143 +4260,3 @@ void HighsMipSolverInfo::clear() {
42604260
this->total_lp_iterations = -kHighsSize_tInf;
42614261
this->primal_dual_integral = -kHighsInf;
42624262
}
4263-
4264-
HighsStatus Highs::mipRaceResults(
4265-
bool use_mip_race_single_presolve, HighsMipSolverInfo& mip_solver_info,
4266-
const std::vector<HighsMipSolverInfo>& worker_info,
4267-
const std::vector<double>& mip_time, double mip_race_time) {
4268-
const HighsInt mip_race_concurrency = this->options_.mip_race_concurrency;
4269-
HighsInt winning_instance = -1;
4270-
HighsModelStatus winning_model_status = HighsModelStatus::kNotset;
4271-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4272-
"\nMIP race results\n");
4273-
for (HighsInt instance = 0; instance < mip_race_concurrency; instance++) {
4274-
const HighsMipSolverInfo& solver_info =
4275-
instance == 0 ? mip_solver_info : worker_info[instance];
4276-
HighsModelStatus instance_model_status = solver_info.modelstatus;
4277-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4278-
" Solver %2d has best objective %15.8g, gap %6.2f%% (time "
4279-
"= %6.2f), and status %s\n",
4280-
int(instance), solver_info.solution_objective,
4281-
1e2 * solver_info.gap, mip_time[instance],
4282-
modelStatusToString(instance_model_status).c_str());
4283-
if (instance_model_status != HighsModelStatus::kHighsInterrupt) {
4284-
// Definitive status for this instance, so check compatibility
4285-
// with any current winning model status
4286-
if (winning_model_status != HighsModelStatus::kNotset) {
4287-
if (winning_model_status != instance_model_status) {
4288-
highsLogUser(options_.log_options, HighsLogType::kError,
4289-
"MIP race: conflict between status \"%s\" for "
4290-
"instance %d and status \"%s\" for instance %d\n",
4291-
modelStatusToString(winning_model_status).c_str(),
4292-
int(winning_instance),
4293-
modelStatusToString(instance_model_status).c_str(),
4294-
int(instance));
4295-
return HighsStatus::kError;
4296-
}
4297-
} else {
4298-
winning_model_status = instance_model_status;
4299-
winning_instance = instance;
4300-
}
4301-
}
4302-
}
4303-
if (winning_instance > 0) mip_solver_info = worker_info[winning_instance];
4304-
4305-
const bool havesolution = mip_solver_info.solution_objective != kHighsInf;
4306-
4307-
if (use_mip_race_single_presolve && havesolution) {
4308-
HighsSolution solution;
4309-
solution.col_value = mip_solver_info.solution;
4310-
// Perform postsolve after the MIP race
4311-
//
4312-
// Set up an empty basis so that callRunPostsolve can be used
4313-
HighsBasis basis;
4314-
// Need to suppress the warning about the HighsModelStatus for
4315-
// MIPs that (in general) can't be set after postsolve
4316-
const bool suppress_mip_model_status_warning = true;
4317-
HighsStatus call_status = this->callRunPostsolve(
4318-
solution, basis, suppress_mip_model_status_warning);
4319-
// call_status will be HighsStatus::kWarning, since model_status_
4320-
// is typically HighsModelStatus::kUnknown due to the lack of
4321-
// optimality test for a MIP. However, since this postsolve was
4322-
// run for a solution that was optimal for the presolved problem
4323-
// (and that status is in mip_solver_info) the warning can be
4324-
// ignored.
4325-
if (call_status == HighsStatus::kError) return call_status;
4326-
// Now update the MipSolverInfo with the postsolved solution
4327-
mip_solver_info.solution = this->solution_.col_value;
4328-
}
4329-
const HighsInt mip_solver_info_solution_size =
4330-
mip_solver_info.solution.size();
4331-
if (0 < mip_solver_info_solution_size &&
4332-
mip_solver_info_solution_size < this->model_.lp_.num_col_) {
4333-
printf(
4334-
"Highs::mipRaceResults MipSolverInfo solution size = %d < %d = "
4335-
"num_col\n",
4336-
int(mip_solver_info_solution_size), int(this->model_.lp_.num_col_));
4337-
assert(11 == 33);
4338-
}
4339-
4340-
mip_race_time += this->timer_.read();
4341-
4342-
std::array<char, 128> gapString = getGapString(
4343-
mip_solver_info.gap, mip_solver_info.primal_bound, &options_);
4344-
4345-
bool feasible;
4346-
std::string solutionstatus = "-";
4347-
if (havesolution) {
4348-
feasible =
4349-
mip_solver_info.bound_violation <= options_.mip_feasibility_tolerance &&
4350-
mip_solver_info.integrality_violation <=
4351-
options_.mip_feasibility_tolerance &&
4352-
mip_solver_info.row_violation <= options_.mip_feasibility_tolerance;
4353-
} else {
4354-
feasible = false;
4355-
}
4356-
solutionstatus = feasible ? "feasible" : "infeasible";
4357-
4358-
highsLogUser(options_.log_options, HighsLogType::kInfo, "Solving report\n");
4359-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4360-
" Model %s\n",
4361-
this->model_.lp_.model_name_.c_str());
4362-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4363-
" Status %s\n",
4364-
modelStatusToString(mip_solver_info.modelstatus).c_str());
4365-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4366-
" Primal bound %.12g\n", mip_solver_info.primal_bound);
4367-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4368-
" Dual bound %.12g\n", mip_solver_info.dual_bound);
4369-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4370-
" Gap %s\n", gapString.data());
4371-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4372-
" P-D integral %.12g\n",
4373-
mip_solver_info.primal_dual_integral);
4374-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4375-
" Solution status %s\n", solutionstatus.c_str());
4376-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4377-
" %.12g\n",
4378-
mip_solver_info.solution_objective);
4379-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4380-
" %.12g (bound viol.)\n",
4381-
mip_solver_info.bound_violation);
4382-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4383-
" %.12g (int. viol.)\n",
4384-
mip_solver_info.integrality_violation);
4385-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4386-
" %.12g (row viol.)\n",
4387-
mip_solver_info.row_violation);
4388-
// Report the solution time for the whole concurrent loop, as that's
4389-
// "real" time
4390-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4391-
" Timing %.2f\n", mip_race_time);
4392-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4393-
" Max sub-MIP depth %d\n",
4394-
int(mip_solver_info.max_submip_level));
4395-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4396-
" Nodes %llu\n",
4397-
(long long unsigned)(mip_solver_info.node_count));
4398-
highsLogUser(options_.log_options, HighsLogType::kInfo,
4399-
" LP iterations %llu\n",
4400-
(long long unsigned)(mip_solver_info.total_lp_iterations));
4401-
return HighsStatus::kOk;
4402-
}

0 commit comments

Comments
 (0)