Skip to content

Commit 13a5068

Browse files
authored
Merge pull request #2474 from ERGO-Code/mip-race
Mip race
2 parents b3fee7c + 6b4a6ee commit 13a5068

18 files changed

+454
-184
lines changed

check/TestCallbacks.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ struct MipData {
3636
struct UserMipSolution {
3737
double optimal_objective_value;
3838
std::vector<double> optimal_solution;
39-
HighsInt require_user_solution_callback_origin;
39+
HighsInt require_external_solution_query_origin;
4040
};
4141

4242
// Callback that saves message for comparison
@@ -193,8 +193,8 @@ HighsCallbackFunctionType userkMipUserSolution =
193193
void* user_callback_data) {
194194
UserMipSolution callback_data =
195195
*(static_cast<UserMipSolution*>(user_callback_data));
196-
if (data_out->user_solution_callback_origin ==
197-
callback_data.require_user_solution_callback_origin) {
196+
if (data_out->external_solution_query_origin ==
197+
callback_data.require_external_solution_query_origin) {
198198
if (data_out->mip_primal_bound >
199199
callback_data.optimal_objective_value) {
200200
// If current objective value is not optimal, pass the
@@ -203,7 +203,7 @@ HighsCallbackFunctionType userkMipUserSolution =
203203
printf(
204204
"userkMipUserSolution: origin = %d; %g = mip_primal_bound > "
205205
"optimal_objective_value = %g\n",
206-
int(data_out->user_solution_callback_origin),
206+
int(data_out->external_solution_query_origin),
207207
data_out->mip_primal_bound,
208208
callback_data.optimal_objective_value);
209209
data_in->user_has_solution = true;
@@ -218,13 +218,13 @@ HighsCallbackFunctionType userkMipUserSetSolution =
218218
void* user_callback_data) {
219219
const auto& callback_data =
220220
*(static_cast<UserMipSolution*>(user_callback_data));
221-
if (data_out->user_solution_callback_origin ==
222-
callback_data.require_user_solution_callback_origin) {
221+
if (data_out->external_solution_query_origin ==
222+
callback_data.require_external_solution_query_origin) {
223223
if (dev_run)
224224
printf(
225225
"userkMipUserSetSolution: origin = %d; %g = mip_primal_bound > "
226226
"optimal_objective_value = %g\n",
227-
int(data_out->user_solution_callback_origin),
227+
int(data_out->external_solution_query_origin),
228228
data_out->mip_primal_bound,
229229
callback_data.optimal_objective_value);
230230

@@ -239,14 +239,14 @@ HighsCallbackFunctionType userkMipUserSetPartialSolution =
239239
void* user_callback_data) {
240240
const auto& callback_data =
241241
*(static_cast<UserMipSolution*>(user_callback_data));
242-
if (data_out->user_solution_callback_origin ==
243-
callback_data.require_user_solution_callback_origin) {
242+
if (data_out->external_solution_query_origin ==
243+
callback_data.require_external_solution_query_origin) {
244244
if (dev_run)
245245
printf(
246246
"userkMipUserSetPartialSolution: origin = %d; %g = "
247247
"mip_primal_bound > "
248248
"optimal_objective_value = %g\n",
249-
int(data_out->user_solution_callback_origin),
249+
int(data_out->external_solution_query_origin),
250250
data_out->mip_primal_bound,
251251
callback_data.optimal_objective_value);
252252

@@ -511,7 +511,7 @@ static void runMipUserSolutionTest(
511511
UserMipSolution user_callback_data;
512512
user_callback_data.optimal_objective_value = objective_function_value0;
513513
user_callback_data.optimal_solution = optimal_solution;
514-
user_callback_data.require_user_solution_callback_origin =
514+
user_callback_data.require_external_solution_query_origin =
515515
require_origin[iModel];
516516
void* p_user_callback_data = (void*)(&user_callback_data);
517517

@@ -597,4 +597,4 @@ TEST_CASE("highs-callback-mip-user-solution-c", "[highs-callback]") {
597597

598598
highs.run();
599599
highs.resetGlobalScheduler(true);
600-
}
600+
}

check/TestMipSolver.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,16 @@ TEST_CASE("MIP-rowless-1", "[highs_test_mip_solver]") {
4040
Highs highs;
4141
if (!dev_run) highs.setOptionValue("output_flag", false);
4242
rowlessMIP1(highs);
43+
44+
highs.resetGlobalScheduler(true);
4345
}
4446

4547
TEST_CASE("MIP-rowless-2", "[highs_test_mip_solver]") {
4648
Highs highs;
4749
if (!dev_run) highs.setOptionValue("output_flag", false);
4850
rowlessMIP2(highs);
51+
52+
highs.resetGlobalScheduler(true);
4953
}
5054

5155
TEST_CASE("MIP-solution-limit", "[highs_test_mip_solver]") {
@@ -79,6 +83,8 @@ TEST_CASE("MIP-solution-limit", "[highs_test_mip_solver]") {
7983
REQUIRE(highs.getModelStatus() == HighsModelStatus::kSolutionLimit);
8084
highs.setOptionValue("mip_max_improving_sols", kHighsIInf);
8185
highs.clearSolver();
86+
87+
highs.resetGlobalScheduler(true);
8288
}
8389

8490
TEST_CASE("MIP-integrality", "[highs_test_mip_solver]") {
@@ -173,6 +179,8 @@ TEST_CASE("MIP-integrality", "[highs_test_mip_solver]") {
173179
REQUIRE(info.mip_node_count == 1);
174180
REQUIRE(fabs(info.mip_dual_bound + 6) < double_equal_tolerance);
175181
REQUIRE(std::fabs(info.mip_gap) < 1e-12);
182+
183+
highs.resetGlobalScheduler(true);
176184
}
177185

178186
TEST_CASE("MIP-clear-integrality", "[highs_test_mip_solver]") {
@@ -215,6 +223,8 @@ TEST_CASE("MIP-nmck", "[highs_test_mip_solver]") {
215223
REQUIRE(info.num_primal_infeasibilities == 0);
216224
REQUIRE(info.max_primal_infeasibility == 0);
217225
REQUIRE(info.sum_primal_infeasibilities == 0);
226+
227+
highs.resetGlobalScheduler(true);
218228
}
219229

220230
TEST_CASE("MIP-maximize", "[highs_test_mip_solver]") {
@@ -295,6 +305,8 @@ TEST_CASE("MIP-maximize", "[highs_test_mip_solver]") {
295305
REQUIRE(std::abs(info.objective_function_value - info.mip_dual_bound) <=
296306
options.mip_abs_gap);
297307
REQUIRE(std::abs(info.mip_gap) <= options.mip_rel_gap);
308+
309+
highs.resetGlobalScheduler(true);
298310
}
299311

300312
TEST_CASE("MIP-unbounded", "[highs_test_mip_solver]") {
@@ -403,6 +415,8 @@ TEST_CASE("MIP-unbounded", "[highs_test_mip_solver]") {
403415

404416
model_status = highs.getModelStatus();
405417
REQUIRE(model_status == HighsModelStatus::kInfeasible);
418+
419+
highs.resetGlobalScheduler(true);
406420
}
407421

408422
TEST_CASE("MIP-od", "[highs_test_mip_solver]") {
@@ -470,6 +484,8 @@ TEST_CASE("MIP-od", "[highs_test_mip_solver]") {
470484
double_equal_tolerance);
471485
REQUIRE(fabs(solution.col_value[0] - required_x0_value) <
472486
double_equal_tolerance);
487+
488+
highs.resetGlobalScheduler(true);
473489
}
474490

475491
TEST_CASE("MIP-infeasible-start", "[highs_test_mip_solver]") {
@@ -513,6 +529,8 @@ TEST_CASE("MIP-infeasible-start", "[highs_test_mip_solver]") {
513529
HighsStatus::kOk);
514530
highs.run();
515531
REQUIRE(model_status == HighsModelStatus::kInfeasible);
532+
533+
highs.resetGlobalScheduler(true);
516534
}
517535

518536
TEST_CASE("get-integrality", "[highs_test_mip_solver]") {}
@@ -556,6 +574,8 @@ TEST_CASE("MIP-bounds", "[highs_test_mip_solver]") {
556574
obj1);
557575
REQUIRE(obj0 == obj1);
558576
std::remove(test_mps.c_str());
577+
578+
highs.resetGlobalScheduler(true);
559579
}
560580

561581
TEST_CASE("MIP-get-saved-solutions", "[highs_test_mip_solver]") {
@@ -583,6 +603,8 @@ TEST_CASE("MIP-get-saved-solutions", "[highs_test_mip_solver]") {
583603
REQUIRE(saved_objective_and_solution[last_saved_solution].col_value[iCol] ==
584604
highs.getSolution().col_value[iCol]);
585605
std::remove(solution_file.c_str());
606+
607+
highs.resetGlobalScheduler(true);
586608
}
587609

588610
TEST_CASE("MIP-objective-target", "[highs_test_mip_solver]") {
@@ -597,6 +619,8 @@ TEST_CASE("MIP-objective-target", "[highs_test_mip_solver]") {
597619
highs.run();
598620
REQUIRE(highs.getModelStatus() == HighsModelStatus::kObjectiveTarget);
599621
REQUIRE(highs.getInfo().objective_function_value > egout_optimal_objective);
622+
623+
highs.resetGlobalScheduler(true);
600624
}
601625

602626
TEST_CASE("MIP-max-offset-test", "[highs_test_mip_solver]") {
@@ -625,6 +649,8 @@ TEST_CASE("MIP-max-offset-test", "[highs_test_mip_solver]") {
625649
highs.getInfo().objective_function_value;
626650
REQUIRE(objectiveOk(max_offset_optimal_objective, -offset_optimal_objective,
627651
dev_run));
652+
653+
highs.resetGlobalScheduler(true);
628654
}
629655

630656
TEST_CASE("MIP-get-saved-solutions-presolve", "[highs_test_mip_solver]") {
@@ -663,6 +689,8 @@ TEST_CASE("MIP-get-saved-solutions-presolve", "[highs_test_mip_solver]") {
663689
REQUIRE(saved_objective_and_solution[last_saved_solution].col_value[iCol] ==
664690
highs.getSolution().col_value[iCol]);
665691
std::remove(solution_file.c_str());
692+
693+
highs.resetGlobalScheduler(true);
666694
}
667695

668696
TEST_CASE("IP-infeasible-unbounded", "[highs_test_mip_solver]") {
@@ -720,6 +748,8 @@ TEST_CASE("IP-infeasible-unbounded", "[highs_test_mip_solver]") {
720748
}
721749
highs.setOptionValue("presolve", kHighsOnString);
722750
}
751+
752+
highs.resetGlobalScheduler(true);
723753
}
724754

725755
TEST_CASE("IP-with-fract-bounds-no-presolve", "[highs_test_mip_solver]") {
@@ -755,6 +785,8 @@ TEST_CASE("IP-with-fract-bounds-no-presolve", "[highs_test_mip_solver]") {
755785

756786
// Infeasible
757787
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
788+
789+
highs.resetGlobalScheduler(true);
758790
}
759791

760792
bool objectiveOk(const double optimal_objective,
@@ -787,6 +819,8 @@ void solve(Highs& highs, std::string presolve,
787819
require_optimal_objective, dev_run));
788820
}
789821
REQUIRE(highs.resetOptions() == HighsStatus::kOk);
822+
823+
highs.resetGlobalScheduler(true);
790824
}
791825

792826
void distillationMIP(Highs& highs) {

highs/highs_bindings.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,8 @@ PYBIND11_MODULE(_core, m, py::mod_gil_not_used()) {
975975
.value("kUnknown", HighsModelStatus::kUnknown)
976976
.value("kSolutionLimit", HighsModelStatus::kSolutionLimit)
977977
.value("kInterrupt", HighsModelStatus::kInterrupt)
978-
.value("kMemoryLimit", HighsModelStatus::kMemoryLimit);
978+
.value("kMemoryLimit", HighsModelStatus::kMemoryLimit)
979+
.value("kHighsInterrupt", HighsModelStatus::kHighsInterrupt);
979980
py::enum_<HighsPresolveStatus>(m, "HighsPresolveStatus", py::module_local())
980981
.value("kNotPresolved", HighsPresolveStatus::kNotPresolved)
981982
.value("kNotReduced", HighsPresolveStatus::kNotReduced)

highs/interfaces/highs_csharp_api.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ public enum HighsModelStatus
6161
kUnknown,
6262
kSolutionLimit,
6363
kInterrupt,
64-
kMemoryLimit
64+
kMemoryLimit,
65+
kHighsInterrupt
6566
}
6667

6768
public enum HighsIntegrality

highs/io/HighsIO.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#include <iostream>
1616

1717
#include "lp_data/HighsCallback.h"
18-
// #include "util/HighsInt.h"
1918

2019
class HighsOptions;
2120

highs/lp_data/HConst.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const double kExcessivelyLargeCostValue = 1e10;
3939
const double kExcessivelySmallBoundValue = 1e-4;
4040
const double kExcessivelySmallCostValue = 1e-4;
4141

42+
const HighsInt kNoThreadInstance = -1;
4243
const bool kAllowDeveloperAssert = false;
4344
const bool kExtendInvertWhenAddingRows = false;
4445

@@ -218,8 +219,9 @@ enum class HighsModelStatus {
218219
kSolutionLimit,
219220
kInterrupt,
220221
kMemoryLimit,
222+
kHighsInterrupt,
221223
kMin = kNotset,
222-
kMax = kMemoryLimit
224+
kMax = kHighsInterrupt
223225
};
224226

225227
enum HighsCallbackType : int {

highs/lp_data/Highs.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4033,14 +4033,13 @@ HighsStatus Highs::callSolveMip() {
40334033
// Extract the solution
40344034
if (solver.solution_objective_ != kHighsInf) {
40354035
// There is a primal solution
4036-
HighsInt solver_solution_size = solver.solution_.size();
4037-
assert(solver_solution_size >= lp.num_col_);
4036+
//
40384037
// If the original model has semi-variables, its solution is
40394038
// (still) given by the first model_.lp_.num_col_ entries of the
40404039
// solution from the MIP solver
40414040
solution_.col_value.resize(model_.lp_.num_col_);
40424041
solution_.col_value = solver.solution_;
4043-
saved_objective_and_solution_ = solver.saved_objective_and_solution_;
4042+
this->saved_objective_and_solution_ = solver.saved_objective_and_solution_;
40444043
model_.lp_.a_matrix_.productQuad(solution_.row_value, solution_.col_value);
40454044
solution_.value_valid = true;
40464045
} else {
@@ -4509,6 +4508,7 @@ HighsStatus Highs::returnFromOptimizeModel(const HighsStatus run_return_status,
45094508
case HighsModelStatus::kIterationLimit:
45104509
case HighsModelStatus::kSolutionLimit:
45114510
case HighsModelStatus::kInterrupt:
4511+
case HighsModelStatus::kHighsInterrupt:
45124512
case HighsModelStatus::kUnknown:
45134513
assert(return_status == HighsStatus::kWarning);
45144514
break;
@@ -4549,6 +4549,7 @@ HighsStatus Highs::returnFromOptimizeModel(const HighsStatus run_return_status,
45494549
case HighsModelStatus::kIterationLimit:
45504550
case HighsModelStatus::kSolutionLimit:
45514551
case HighsModelStatus::kInterrupt:
4552+
case HighsModelStatus::kHighsInterrupt:
45524553
case HighsModelStatus::kUnknown:
45534554
// Have info and primal solution (unless infeasible). No primal solution
45544555
// in some other case, too!

highs/lp_data/HighsCallback.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ void HighsCallback::clearHighsCallbackOutput() {
3535
this->data_out.cutpool_value.clear();
3636
this->data_out.cutpool_lower.clear();
3737
this->data_out.cutpool_upper.clear();
38-
this->data_out.user_solution_callback_origin =
39-
userMipSolutionCallbackOrigin::kUserMipSolutionCallbackOriginAfterSetup;
38+
this->data_out.external_solution_query_origin =
39+
ExternalMipSolutionQueryOrigin::kExternalMipSolutionQueryOriginAfterSetup;
4040
}
4141

4242
void HighsCallback::clearHighsCallbackInput() {
@@ -134,8 +134,8 @@ HighsCallbackOutput::operator HighsCallbackDataOut() const {
134134
? nullptr
135135
: const_cast<double*>(cutpool_upper.data());
136136

137-
data.user_solution_callback_origin =
138-
static_cast<HighsInt>(user_solution_callback_origin);
137+
data.external_solution_query_origin =
138+
static_cast<HighsInt>(external_solution_query_origin);
139139
return data;
140140
}
141141

@@ -320,4 +320,4 @@ HighsStatus HighsCallbackInput::repairSolution() {
320320
return HighsStatus::kError;
321321
}
322322
}
323-
}
323+
}

highs/lp_data/HighsCallback.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ class Highs;
2020
#include "lp_data/HStruct.h"
2121
#include "lp_data/HighsCallbackStruct.h"
2222

23-
enum userMipSolutionCallbackOrigin {
24-
kUserMipSolutionCallbackOriginAfterSetup = 0,
25-
kUserMipSolutionCallbackOriginBeforeDive,
26-
kUserMipSolutionCallbackOriginEvaluateRootNode0,
27-
kUserMipSolutionCallbackOriginEvaluateRootNode1,
28-
kUserMipSolutionCallbackOriginEvaluateRootNode2,
29-
kUserMipSolutionCallbackOriginEvaluateRootNode3,
30-
kUserMipSolutionCallbackOriginEvaluateRootNode4
23+
enum ExternalMipSolutionQueryOrigin {
24+
kExternalMipSolutionQueryOriginAfterSetup = 0,
25+
kExternalMipSolutionQueryOriginBeforeDive,
26+
kExternalMipSolutionQueryOriginEvaluateRootNode0,
27+
kExternalMipSolutionQueryOriginEvaluateRootNode1,
28+
kExternalMipSolutionQueryOriginEvaluateRootNode2,
29+
kExternalMipSolutionQueryOriginEvaluateRootNode3,
30+
kExternalMipSolutionQueryOriginEvaluateRootNode4
3131
};
3232

3333
/**
@@ -54,7 +54,7 @@ struct HighsCallbackOutput {
5454
std::vector<double> cutpool_value;
5555
std::vector<double> cutpool_lower;
5656
std::vector<double> cutpool_upper;
57-
userMipSolutionCallbackOrigin user_solution_callback_origin;
57+
ExternalMipSolutionQueryOrigin external_solution_query_origin;
5858

5959
operator HighsCallbackDataOut() const;
6060
};

highs/lp_data/HighsCallbackStruct.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ typedef struct {
4444
double* cutpool_value;
4545
double* cutpool_lower;
4646
double* cutpool_upper;
47-
HighsInt user_solution_callback_origin;
47+
HighsInt external_solution_query_origin;
4848
} HighsCallbackDataOut;
4949

5050
// Some external packages (e.g., jump) currently assume that the first 2 fields

0 commit comments

Comments
 (0)