Skip to content

Commit 6cb49c3

Browse files
committed
Formatted
1 parent acd2cfc commit 6cb49c3

File tree

6 files changed

+85
-59
lines changed

6 files changed

+85
-59
lines changed

check/TestMipSolver.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,19 +1038,19 @@ TEST_CASE("issue-2432", "[highs_test_mip_solver]") {
10381038

10391039
TEST_CASE("mip-race", "[highs_test_mip_solver]") {
10401040
const bool ci_test = true;
1041-
const std::string test_build_model = "fiball";//"neos-3381206-awhea"; //
1041+
const std::string test_build_model = "fiball"; //"neos-3381206-awhea"; //
10421042
const std::string model = ci_test ? "flugpl" : test_build_model;
10431043
// "neos-3381206-awhea";
10441044
const std::string model_file =
10451045
ci_test ? std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps"
10461046
: "/srv/miplib2017/" + model + ".mps.gz";
10471047
Highs h;
1048-
// if (ci_test) h.setOptionValue("output_flag", dev_run);
1048+
if (ci_test) h.setOptionValue("output_flag", dev_run);
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-
for (HighsInt k = 0; k < 1; k++) {
1053-
bool mip_race_single_presolve = k == 1 ? false : true;
1052+
for (HighsInt k = 0; k < 2; k++) {
1053+
bool mip_race_single_presolve = k == 0 ? false : true;
10541054
h.setOptionValue("mip_race_single_presolve", mip_race_single_presolve);
10551055
REQUIRE(h.readModel(model_file) == HighsStatus::kOk);
10561056
REQUIRE(h.run() == HighsStatus::kOk);

highs/Highs.h

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

15091510
PresolveComponent presolve_;
15101511
HighsPresolveStatus runPresolve(const bool force_lp_presolve,
@@ -1715,7 +1716,7 @@ class Highs {
17151716
void saveHighsFiles();
17161717
void getHighsFiles();
17171718
HighsStatus mipRaceResults(bool use_mip_race_single_presolve,
1718-
HighsMipSolverInfo& mip_solver_info,
1719+
HighsMipSolverInfo& mip_solver_info,
17191720
const std::vector<HighsMipSolverInfo>& worker_info,
17201721
const std::vector<double>& mip_time,
17211722
double mip_race_time);

highs/lp_data/Highs.cpp

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4043,10 +4043,8 @@ HighsStatus Highs::callSolveMip() {
40434043
// converted into the use_lp instance, and this->presolve(); works
40444044
// on the incumbent model
40454045
const bool use_mip_race_single_presolve =
4046-
run_mip_race &&
4047-
options_.mip_race_single_presolve &&
4048-
options_.presolve != kHighsOffString &&
4049-
!has_semi_variables;
4046+
run_mip_race && options_.mip_race_single_presolve &&
4047+
options_.presolve != kHighsOffString && !has_semi_variables;
40504048
// Take a copy of the presolve option in case it's switched off for
40514049
// a single presolve MIP race
40524050
const std::string presolve = this->options_.presolve;
@@ -4060,16 +4058,20 @@ HighsStatus Highs::callSolveMip() {
40604058
// the call to presolve...
40614059
assert(!this->called_return_from_optimize_model);
40624060
this->called_return_from_optimize_model = true;
4063-
this->presolve();
4061+
HighsStatus call_status = this->presolve();
40644062
// ... then set it back to false and restart the run clock
40654063
this->called_return_from_optimize_model = false;
40664064
this->timer_.start();
4065+
if (call_status != HighsStatus::kOk) return call_status;
40674066
presolved_lp = this->getPresolvedLp();
40684067
this->options_.presolve = kHighsOffString;
40694068
}
40704069
// Create the master MIP solver instance that will exist beyond any
40714070
// MIP race
4072-
HighsLp& lp = has_semi_variables ? use_lp : (use_mip_race_single_presolve ? presolved_lp : model_.lp_);
4071+
HighsLp& lp =
4072+
has_semi_variables
4073+
? use_lp
4074+
: (use_mip_race_single_presolve ? presolved_lp : model_.lp_);
40734075
HighsMipSolver solver(callback_, options_, lp, solution_);
40744076
HighsMipSolverInfo mip_solver_info;
40754077
if (run_mip_race) {
@@ -4084,7 +4086,7 @@ HighsStatus Highs::callSolveMip() {
40844086
worker_callback.clear();
40854087
// Race the MIP solver!
40864088
highsLogUser(options_.log_options, HighsLogType::kInfo,
4087-
"Starting MIP race with %d instances: behaviour is "
4089+
"\nStarting MIP race with %d instances: behaviour is "
40884090
"non-deterministic!\n",
40894091
int(mip_race_concurrency));
40904092
// Define the HighsMipSolverInfo record for each worker
@@ -4133,9 +4135,9 @@ HighsStatus Highs::callSolveMip() {
41334135
}
41344136
});
41354137
// Determine the winner and report on the solution
4136-
HighsStatus call_status = this->mipRaceResults(use_mip_race_single_presolve,
4137-
mip_solver_info, worker_info,
4138-
mip_time, mip_race_time);
4138+
HighsStatus call_status =
4139+
this->mipRaceResults(use_mip_race_single_presolve, mip_solver_info,
4140+
worker_info, mip_time, mip_race_time);
41394141
// Restore the presolve option - that will have been set to
41404142
// kHighsOffString for a single presolve MIP race
41414143
this->options_.presolve = presolve;
@@ -4238,9 +4240,10 @@ HighsStatus Highs::callSolveMip() {
42384240
return return_status;
42394241
}
42404242

4241-
// Only called from Highs::postsolve
4242-
HighsStatus Highs::callRunPostsolve(const HighsSolution& solution,
4243-
const HighsBasis& basis) {
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) {
42444247
HighsStatus return_status = HighsStatus::kOk;
42454248
HighsStatus call_status;
42464249
const HighsLp& presolved_lp = presolve_.getReducedProblem();
@@ -4305,9 +4308,12 @@ HighsStatus Highs::callRunPostsolve(const HighsSolution& solution,
43054308
max_integrality_violation);
43064309
}
43074310
}
4308-
highsLogUser(
4309-
options_.log_options, HighsLogType::kWarning,
4310-
"Postsolve performed for MIP, but model status cannot be known\n");
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");
43114317
} else {
43124318
highsLogUser(options_.log_options, HighsLogType::kError,
43134319
"Postsolve return status is %d\n", (int)postsolve_status);

highs/lp_data/HighsInterface.cpp

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

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) {
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) {
42694268
const HighsInt mip_race_concurrency = this->options_.mip_race_concurrency;
42704269
HighsInt winning_instance = -1;
42714270
HighsModelStatus winning_model_status = HighsModelStatus::kNotset;
@@ -4310,22 +4309,34 @@ HighsStatus Highs::mipRaceResults(bool use_mip_race_single_presolve,
43104309
solution.col_value = mip_solver_info.solution;
43114310
// Perform postsolve after the MIP race
43124311
//
4313-
// NB Highs::postsolve() is normally called externally, so calls
4314-
// returnFromHighs(). This will stop the run clock, and check that
4315-
// called_return_from_optimize_model is true - when it isn't. So,
4316-
// add a hack to set called_return_from_optimize_model true before
4317-
// the call to postsolve...
4318-
assert(!this->called_return_from_optimize_model);
4319-
this->called_return_from_optimize_model = true;
4320-
4321-
this->postsolve(solution);
4322-
// ... then set it back to false and restart the run clock
4323-
this->called_return_from_optimize_model = false;
4324-
this->timer_.start();
4325-
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;
43264326
// Now update the MipSolverInfo with the postsolved solution
4327-
mip_solver_info.solution = this->getSolution().col_value;
4327+
mip_solver_info.solution = this->solution_.col_value;
43284328
}
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+
43294340
mip_race_time += this->timer_.read();
43304341

43314342
std::array<char, 128> gapString = getGapString(

highs/lp_data/HighsOptions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ struct HighsOptionsStruct {
580580
mip_allow_restart(false),
581581
mip_race_concurrency(0),
582582
mip_race_read_solutions(false),
583-
mip_race_single_presolve(false),
583+
mip_race_single_presolve(false),
584584
mip_max_nodes(0),
585585
mip_max_stall_nodes(0),
586586
mip_max_start_nodes(0),

highs/mip/HighsMipSolverData.cpp

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "mip/HighsMipSolverData.h"
99

1010
#include <random>
11+
#include <sstream>
1112

1213
// #include "lp_data/HighsLpUtils.h"
1314
#include "../extern/pdqsort/pdqsort.h"
@@ -1400,19 +1401,24 @@ bool HighsMipSolverData::addIncumbent(const std::vector<double>& sol,
14001401
get_transformed_solution ? transformNewIntegerFeasibleSolution(
14011402
sol, possibly_store_as_new_incumbent)
14021403
: 0;
1403-
const bool highs_solution_report = true;
1404-
if (solution_source == kSolutionSourceHighsSolution
1405-
&& highs_solution_report
1404+
const bool highs_solution_report = false;
1405+
if (solution_source == kSolutionSourceHighsSolution && highs_solution_report
14061406
//&& possibly_store_as_new_incumbent
1407-
) {
1407+
) {
1408+
std::stringstream ss;
1409+
ss.str(std::string());
1410+
ss << highsFormatToString(
1411+
"HighsMipSolverData::addIncumbent HiGHS solution Obj "
1412+
"= %15.8g; UB = %15.8g; Obj-UB = %11.4g; PossAdd = %s",
1413+
solobj, upper_bound, solobj - upper_bound,
1414+
possibly_store_as_new_incumbent ? "T" : "F");
1415+
if (possibly_store_as_new_incumbent)
1416+
ss << highsFormatToString(
1417+
"; TransObj = %15.8g; TransObj-UB = %11.4g; TransSolobj < UB %s",
1418+
transformed_solobj, transformed_solobj - upper_bound,
1419+
transformed_solobj < upper_bound ? "T" : "F");
14081420
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kInfo,
1409-
"HighsMipSolverData::addIncumbent HiGHS solution Obj "
1410-
"= %15.8g; UB = %15.8g; Obj-UB = %11.4g; PossAdd = %s; TransObj = %15.8g; TransObj-UB = %11.4g; TransSolobj < UB %s \n",
1411-
solobj, upper_bound,
1412-
solobj-upper_bound,
1413-
possibly_store_as_new_incumbent ? "T" : "F", transformed_solobj,
1414-
transformed_solobj - upper_bound,
1415-
transformed_solobj < upper_bound ? "T" : "F");
1421+
"%s\n", ss.str().c_str());
14161422
fflush(stdout);
14171423
}
14181424
if (possibly_store_as_new_incumbent) {
@@ -2731,17 +2737,19 @@ void HighsMipSolverData::queryExternalSolution(
27312737
if (!checkSolution(reduced_instance_solution)) {
27322738
const bool feasibility_warning = true;
27332739
if (feasibility_warning) {
2734-
highsLogUser(mipsolver.options_mip_->log_options, HighsLogType::kWarning,
2735-
"Solution from instance %2d is not feasible for instance %2d\n",
2736-
int(instance), int(mip_race.my_instance));
2740+
highsLogUser(
2741+
mipsolver.options_mip_->log_options, HighsLogType::kWarning,
2742+
"Solution from instance %2d is not feasible for instance %2d\n",
2743+
int(instance), int(mip_race.my_instance));
27372744
}
27382745
continue;
27392746
}
27402747
HighsCDouble reduced_instance_quad_objective_value = 0;
27412748
for (HighsInt iCol = 0; iCol < mipsolver.model_->num_col_; iCol++)
27422749
reduced_instance_quad_objective_value +=
2743-
mipsolver.colCost(iCol) * reduced_instance_solution[iCol];
2744-
double reduced_instance_objective_value = double(reduced_instance_quad_objective_value);
2750+
mipsolver.colCost(iCol) * reduced_instance_solution[iCol];
2751+
double reduced_instance_objective_value =
2752+
double(reduced_instance_quad_objective_value);
27452753
addIncumbent(reduced_instance_solution, reduced_instance_objective_value,
27462754
kSolutionSourceHighsSolution);
27472755
}

0 commit comments

Comments
 (0)