Skip to content

Commit 14e2a97

Browse files
committed
HiGHS solution has been read
1 parent 5a5b30a commit 14e2a97

File tree

5 files changed

+61
-30
lines changed

5 files changed

+61
-30
lines changed

check/TestMipSolver.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,12 +1003,13 @@ TEST_CASE("issue-2432", "[highs_test_mip_solver]") {
10031003
}
10041004

10051005
TEST_CASE("mip-race", "[highs_test_mip_solver]") {
1006-
const std::string model = "flugpl";
1006+
const std::string model = "bell5";//"flugpl";
10071007
const std::string model_file =
10081008
std::string(HIGHS_DIR) + "/check/instances/" + model + ".mps";
10091009
Highs h;
10101010
// h.setOptionValue("output_flag", dev_run);
1011-
h.setOptionValue("mip_race_concurrency", 4);
1011+
h.setOptionValue("mip_race_concurrency", 2);
1012+
// h.setOptionValue("mip_race_read_solutions", false);
10121013
REQUIRE(h.readModel(model_file) == HighsStatus::kOk);
10131014
REQUIRE(h.run() == HighsStatus::kOk);
10141015
}

highs/lp_data/HighsOptions.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ struct HighsOptionsStruct {
425425
bool mip_detect_symmetry;
426426
bool mip_allow_restart;
427427
HighsInt mip_race_concurrency;
428+
bool mip_race_read_solutions;
428429
HighsInt mip_max_nodes;
429430
HighsInt mip_max_stall_nodes;
430431
HighsInt mip_max_start_nodes;
@@ -577,6 +578,7 @@ struct HighsOptionsStruct {
577578
mip_detect_symmetry(false),
578579
mip_allow_restart(false),
579580
mip_race_concurrency(0),
581+
mip_race_read_solutions(false),
580582
mip_max_nodes(0),
581583
mip_max_stall_nodes(0),
582584
mip_max_start_nodes(0),
@@ -1024,6 +1026,11 @@ class HighsOptions : public HighsOptionsStruct {
10241026
advanced, &mip_race_concurrency, 0, 0, kHighsIInf);
10251027
records.push_back(record_int);
10261028

1029+
record_bool = new OptionRecordBool("mip_race_read_solutions",
1030+
"Whether the MIP races should read other racers' solutions",
1031+
advanced, &mip_race_read_solutions, true);
1032+
records.push_back(record_bool);
1033+
10271034
record_int = new OptionRecordInt("mip_max_nodes",
10281035
"MIP solver max number of nodes", advanced,
10291036
&mip_max_nodes, 0, kHighsIInf, kHighsIInf);

highs/mip/HighsMipSolver.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,17 @@ struct HighsPseudocostInitialization;
1919
class HighsCliqueTable;
2020
class HighsImplications;
2121

22+
const HighsInt kMipRaceNoSolution = -1;
23+
2224
struct MipRaceIncumbent {
23-
HighsInt start_write_incumbent = -1;
24-
HighsInt finish_write_incumbent = -1;
25+
HighsInt start_write_incumbent = kMipRaceNoSolution;
26+
HighsInt finish_write_incumbent = kMipRaceNoSolution;
2527
double objective = -kHighsInf;
2628
std::vector<double> solution;
2729
void clear();
2830
void initialise(const HighsInt num_col);
2931
void update(const double objective, const std::vector<double>& solution);
30-
bool readOk(double& objective_, std::vector<double>& solution_) const;
32+
HighsInt read(double& objective_, std::vector<double>& solution_) const;
3133
};
3234

3335
struct MipRaceRecord {
@@ -52,7 +54,7 @@ struct MipRace {
5254
const HighsLogOptions log_options_);
5355
HighsInt concurrency() const;
5456
void update(const double objective, const std::vector<double>& solution);
55-
bool newSolution(double objective, std::vector<double>& solution) const;
57+
HighsInt newSolution(const HighsInt instance, double objective, std::vector<double>& solution) const;
5658
void terminate();
5759
bool terminated() const;
5860
void report() const;

highs/mip/HighsMipSolverData.cpp

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2621,6 +2621,7 @@ bool HighsMipSolverData::interruptFromCallbackWithData(
26212621
void HighsMipSolverData::queryExternalSolution(
26222622
const double mipsolver_objective_value,
26232623
const ExternalMipSolutionQueryOrigin external_solution_query_origin) {
2624+
assert(!mipsolver.submip);
26242625
HighsCallback* callback = mipsolver.callback_;
26252626
const bool use_callback =
26262627
callback->user_callback && callback->active[kCallbackMipUserSolution];
@@ -2664,11 +2665,29 @@ void HighsMipSolverData::queryExternalSolution(
26642665
is_user_solution);
26652666
}
26662667
}
2668+
if (!mipsolver.options_mip_->mip_race_read_solutions) return;
2669+
MipRace& mip_race = mipsolver.mip_race_;
2670+
if (!mip_race.record) return;
2671+
double instance_solution_objective_value;
2672+
std::vector<double> instance_solution;
2673+
for (HighsInt instance = 0; instance < mip_race.concurrency(); instance++) {
2674+
if (instance == mip_race.my_instance) continue;
2675+
HighsInt read_incumbent = mip_race.newSolution(instance, instance_solution_objective_value, instance_solution);
2676+
if (read_incumbent < 0) continue;
2677+
if (read_incumbent <= mip_race.last_incumbent_read[instance]) continue;
2678+
// Have read a new incumbent
2679+
std::vector<double> reduced_instance_solution;
2680+
reduced_instance_solution =
2681+
postSolveStack.getReducedPrimalSolution(instance_solution);
2682+
addIncumbent(reduced_instance_solution, instance_solution_objective_value,
2683+
kSolutionSourceHighsSolution);
2684+
2685+
}
26672686
}
26682687

26692688
HighsInt HighsMipSolverData::mipRaceConcurrency() const {
2670-
if (!mipsolver.mip_race_.record) return;
26712689
assert(!mipsolver.submip);
2690+
if (!mipsolver.mip_race_.record) return;
26722691
return mipsolver.mip_race_.concurrency();
26732692
}
26742693

@@ -2679,22 +2698,23 @@ void HighsMipSolverData::mipRaceUpdate() {
26792698
mipsolver.solution_);
26802699
}
26812700

2682-
bool HighsMipSolverData::mipRaceNewSolution(double& objective_value,
2683-
std::vector<double>& solution) {
2684-
if (!mipsolver.mip_race_.record) return false;
2701+
HighsInt HighsMipSolverData::mipRaceNewSolution(const HighsInt instance,
2702+
double& objective_value,
2703+
std::vector<double>& solution) {
26852704
assert(!mipsolver.submip);
2686-
return false;
2705+
if (!mipsolver.mip_race_.record) return kMipRaceNoSolution;
2706+
return mipsolver.mip_race_.newSolution(instance, objective_value, solution);
26872707
}
26882708

26892709
void HighsMipSolverData::mipRaceTerminate() {
2690-
if (!mipsolver.mip_race_.record) return;
26912710
assert(!mipsolver.submip);
2711+
if (!mipsolver.mip_race_.record) return;
26922712
mipsolver.mip_race_.terminate();
26932713
}
26942714

26952715
bool HighsMipSolverData::mipRaceTerminated() const {
2696-
if (!mipsolver.mip_race_.record) return false;
26972716
assert(!mipsolver.submip);
2717+
if (!mipsolver.mip_race_.record) return false;
26982718
return mipsolver.mip_race_.terminated();
26992719
}
27002720

@@ -2840,8 +2860,8 @@ void HighsMipSolverData::updatePrimalDualIntegral(const double from_lower_bound,
28402860
void HighsPrimaDualIntegral::initialise() { this->value = -kHighsInf; }
28412861

28422862
void MipRaceIncumbent::clear() {
2843-
this->start_write_incumbent = -1;
2844-
this->finish_write_incumbent = -1;
2863+
this->start_write_incumbent = kMipRaceNoSolution;
2864+
this->finish_write_incumbent = kMipRaceNoSolution;
28452865
this->objective = -kHighsInf;
28462866
this->solution.clear();
28472867
}
@@ -2861,17 +2881,17 @@ void MipRaceIncumbent::update(const double objective_,
28612881
assert(this->start_write_incumbent == this->finish_write_incumbent);
28622882
}
28632883

2864-
bool MipRaceIncumbent::readOk(double& objective_,
2865-
std::vector<double>& solution_) const {
2884+
HighsInt MipRaceIncumbent::read(double& objective_,
2885+
std::vector<double>& solution_) const {
28662886
const HighsInt start_write_incumbent = this->start_write_incumbent;
28672887
assert(this->finish_write_incumbent <= start_write_incumbent);
28682888
// If a write call has not completed, return failure
2869-
if (this->finish_write_incumbent < start_write_incumbent) return false;
2889+
if (this->finish_write_incumbent < start_write_incumbent) return kMipRaceNoSolution;
28702890
// finish_write_incumbent = start_write_incumbent so start reading
28712891
objective_ = this->objective;
28722892
solution_ = this->solution;
28732893
// Read is OK if no new write has started
2874-
return this->start_write_incumbent == start_write_incumbent;
2894+
return this->start_write_incumbent == start_write_incumbent ? start_write_incumbent : kMipRaceNoSolution;
28752895
}
28762896

28772897
void MipRaceRecord::clear() {
@@ -2902,22 +2922,22 @@ void MipRaceRecord::report(const HighsLogOptions log_options) const {
29022922
HighsInt mip_race_concurrency = this->concurrency();
29032923
highsLogUser(log_options, HighsLogType::kInfo, "\nMipRaceRecord: ");
29042924
for (HighsInt instance = 0; instance < mip_race_concurrency; instance++)
2905-
highsLogUser(log_options, HighsLogType::kInfo, " %11d", int(instance));
2925+
highsLogUser(log_options, HighsLogType::kInfo, " %16d", int(instance));
29062926
highsLogUser(log_options, HighsLogType::kInfo, "\nTerminated: ");
29072927
for (HighsInt instance = 0; instance < mip_race_concurrency; instance++)
2908-
highsLogUser(log_options, HighsLogType::kInfo, " %11s",
2928+
highsLogUser(log_options, HighsLogType::kInfo, " %16s",
29092929
this->terminated[instance] ? "T" : "F");
29102930
highsLogUser(log_options, HighsLogType::kInfo, "\nStartWrite: ");
29112931
for (HighsInt instance = 0; instance < mip_race_concurrency; instance++)
2912-
highsLogUser(log_options, HighsLogType::kInfo, " %11d",
2932+
highsLogUser(log_options, HighsLogType::kInfo, " %16d",
29132933
this->incumbent[instance].start_write_incumbent);
29142934
highsLogUser(log_options, HighsLogType::kInfo, "\nObjective: ");
29152935
for (HighsInt instance = 0; instance < mip_race_concurrency; instance++)
2916-
highsLogUser(log_options, HighsLogType::kInfo, " %11.4g",
2936+
highsLogUser(log_options, HighsLogType::kInfo, " %16.8g",
29172937
this->incumbent[instance].objective);
29182938
highsLogUser(log_options, HighsLogType::kInfo, "\nFinishWrite: ");
29192939
for (HighsInt instance = 0; instance < mip_race_concurrency; instance++)
2920-
highsLogUser(log_options, HighsLogType::kInfo, " %11d",
2940+
highsLogUser(log_options, HighsLogType::kInfo, " %16d",
29212941
this->incumbent[instance].finish_write_incumbent);
29222942
highsLogUser(log_options, HighsLogType::kInfo, "\n");
29232943
}
@@ -2936,7 +2956,7 @@ void MipRace::initialise(const HighsInt mip_race_concurrency,
29362956
this->my_instance = my_instance_;
29372957
this->record = record_;
29382958
this->log_options = log_options_;
2939-
this->last_incumbent_read.assign(mip_race_concurrency, -1);
2959+
this->last_incumbent_read.assign(mip_race_concurrency, kMipRaceNoSolution);
29402960
}
29412961

29422962
HighsInt MipRace::concurrency() const {
@@ -2951,10 +2971,10 @@ void MipRace::update(const double objective,
29512971
this->report();
29522972
}
29532973

2954-
bool MipRace::newSolution(double objective,
2974+
HighsInt MipRace::newSolution(const HighsInt instance, double objective,
29552975
std::vector<double>& solution) const {
29562976
assert(this->record);
2957-
return false;
2977+
return this->record->incumbent[instance].read(objective, solution);
29582978
}
29592979

29602980
void MipRace::terminate() {
@@ -2974,7 +2994,7 @@ void MipRace::report() const {
29742994
this->record->report(this->log_options);
29752995
highsLogUser(this->log_options, HighsLogType::kInfo, "LastIncumbentRead: ");
29762996
for (HighsInt instance = 0; instance < this->concurrency(); instance++)
2977-
highsLogUser(this->log_options, HighsLogType::kInfo, " %11d",
2997+
highsLogUser(this->log_options, HighsLogType::kInfo, " %16d",
29782998
this->last_incumbent_read[instance]);
29792999
highsLogUser(this->log_options, HighsLogType::kInfo, "\n\n");
29803000
}

highs/mip/HighsMipSolverData.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,9 @@ struct HighsMipSolverData {
303303

304304
HighsInt mipRaceConcurrency() const;
305305
void mipRaceUpdate();
306-
bool mipRaceNewSolution(double& objective_value,
307-
std::vector<double>& solution);
306+
HighsInt mipRaceNewSolution(const HighsInt instance,
307+
double& objective_value,
308+
std::vector<double>& solution);
308309
void mipRaceTerminate();
309310
bool mipRaceTerminated() const;
310311
void mipRaceReport() const;

0 commit comments

Comments
 (0)