Skip to content

Commit 50a0824

Browse files
authored
Merge pull request #2886 from ERGO-Code/hmw-mt
MIP Worker Refactor
2 parents 586c324 + 767079a commit 50a0824

60 files changed

Lines changed: 4627 additions & 2466 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 65 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,35 @@
11
name: action-sanitizers-bazel
22

33
on:
4+
pull_request:
45
workflow_dispatch:
56

67
jobs:
7-
# asan:
8-
# runs-on: ${{ matrix.os }}
9-
# strategy:
10-
# matrix:
11-
# os: [ubuntu-latest]
8+
asan:
9+
runs-on: ${{ matrix.os }}
10+
strategy:
11+
matrix:
12+
os: [ubuntu-latest]
1213

13-
# steps:
14-
# - uses: actions/checkout@v6
14+
steps:
15+
- uses: actions/checkout@v6
1516

16-
# - uses: bazelbuild/setup-bazelisk@v3
17+
- uses: bazelbuild/setup-bazelisk@v3
1718

18-
# - name: Bazel clean
19-
# run: bazel clean
19+
- name: Bazel clean
20+
run: bazel clean
2021

21-
# - name: Bazel build
22-
# run: bazel build -c dbg --config=asan //...
22+
- name: Bazel build
23+
run: bazel build -c dbg --config=asan //...
2324

24-
# - name: Bazel test
25-
# run: bazel test -c dbg --config=asan --runs_per_test 3 //...
25+
- name: Bazel test
26+
run: bazel test -c dbg --config=asan --runs_per_test 5 //...
2627

27-
# # - name: Upload bazel-testlogs
28-
# # uses: actions/upload-artifact@v7
29-
# # with:
30-
# # name: bazel-testlogs-asan
31-
# # path: bazel-testlogs/
28+
# - name: Upload bazel-testlogs
29+
# uses: actions/upload-artifact@v7
30+
# with:
31+
# name: bazel-testlogs-asan
32+
# path: bazel-testlogs/
3233

3334
tsan:
3435
runs-on: ${{ matrix.os }}
@@ -47,66 +48,69 @@ jobs:
4748
- name: Bazel build
4849
run: bazel build -c dbg --config=tsan //...
4950

50-
- name: Bazel test
51-
run: bazel test -c dbg --config=tsan --runs_per_test 3 //:TestMipSolver
51+
- name: Test Mip Solver
52+
run: bazel test -c dbg --config=tsan --runs_per_test 100 //:TestMipSolver
53+
54+
- name: Test Highs Parallel
55+
run: bazel test -c dbg --config=tsan --runs_per_test 100 //:TestHighsParallel
5256

53-
- name: Bazel test 2
54-
run: bazel test -c dbg --config=tsan --runs_per_test 3 //:TestHighsParallel
57+
- name: All Tests
58+
run: bazel test -c dbg --config=tsan --runs_per_test 5 //...
5559

5660
# - name: Upload bazel-testlogs
5761
# uses: actions/upload-artifact@v7
5862
# with:
5963
# name: bazel-testlogs-tsan
6064
# path: bazel-testlogs/
6165

62-
# lsan:
63-
# runs-on: ${{ matrix.os }}
64-
# strategy:
65-
# matrix:
66-
# os: [ubuntu-latest]
66+
lsan:
67+
runs-on: ${{ matrix.os }}
68+
strategy:
69+
matrix:
70+
os: [ubuntu-latest]
6771

68-
# steps:
69-
# - uses: actions/checkout@v6
72+
steps:
73+
- uses: actions/checkout@v6
7074

71-
# - uses: bazelbuild/setup-bazelisk@v3
75+
- uses: bazelbuild/setup-bazelisk@v3
7276

73-
# - name: Bazel clean
74-
# run: bazel clean
77+
- name: Bazel clean
78+
run: bazel clean
7579

76-
# - name: Bazel build
77-
# run: bazel build -c dbg --config=lsan //...
80+
- name: Bazel build
81+
run: bazel build -c dbg --config=lsan //...
7882

79-
# - name: Bazel test
80-
# run: bazel test -c dbg --config=lsan --runs_per_test 3 //...
83+
- name: Bazel test
84+
run: bazel test -c dbg --config=lsan --runs_per_test 5 //...
8185

82-
# # - name: Upload bazel-testlogs
83-
# # uses: actions/upload-artifact@v7
84-
# # with:
85-
# # name: bazel-testlogs-lsan
86-
# # path: bazel-testlogs/
86+
# - name: Upload bazel-testlogs
87+
# uses: actions/upload-artifact@v7
88+
# with:
89+
# name: bazel-testlogs-lsan
90+
# path: bazel-testlogs/
8791

88-
# ubsan:
89-
# runs-on: ${{ matrix.os }}
90-
# strategy:
91-
# matrix:
92-
# os: [ubuntu-latest]
92+
ubsan:
93+
runs-on: ${{ matrix.os }}
94+
strategy:
95+
matrix:
96+
os: [ubuntu-latest]
9397

94-
# steps:
95-
# - uses: actions/checkout@v6
98+
steps:
99+
- uses: actions/checkout@v6
96100

97-
# - uses: bazelbuild/setup-bazelisk@v3
101+
- uses: bazelbuild/setup-bazelisk@v3
98102

99-
# - name: Bazel clean
100-
# run: bazel clean
103+
- name: bazel clean
104+
run: bazel clean
101105

102-
# - name: Bazel build
103-
# run: bazel build -c dbg --config=ubsan //...
106+
- name: bazel build
107+
run: bazel build -c dbg --config=ubsan //...
104108

105-
# - name: Bazel test
106-
# run: bazel test -c dbg --config=ubsan --runs_per_test 3000 //...
109+
- name: bazel test
110+
run: bazel test -c dbg --config=ubsan --runs_per_test 5 //...
107111

108-
# # - name: Upload bazel-testlogs
109-
# # uses: actions/upload-artifact@v7
110-
# # with:
111-
# # name: bazel-testlogs-ubsan
112-
# # path: bazel-testlogs/
112+
# - name: upload bazel-testlogs
113+
# uses: actions/upload-artifact@v7
114+
# with:
115+
# name: bazel-testlogs-ubsan
116+
# path: bazel-testlogs/

check/TestBasisSolves.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ TEST_CASE("Basis-solves", "[highs_basis_solves]") {
449449
// filename = std::string(HIGHS_DIR) + "/check/instances/25fv47.mps";
450450

451451
Highs highs;
452-
if (!dev_run) highs.setOptionValue("output_flag", false);
452+
highs.setOptionValue("output_flag", dev_run);
453453

454454
vector<HighsInt> basic_variables;
455455
vector<double> rhs, solution_row, solution_col;

check/TestCheckSolution.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {
8787
HighsSolution optimal_solution = highs.getSolution();
8888

8989
HighsInt scratch_num_nodes = info.mip_node_count;
90+
HighsInt scratch_num_simplex = info.simplex_iteration_count;
9091
if (dev_run) printf("Num nodes = %d\n", int(scratch_num_nodes));
9192

9293
std::string solution_file = test_name + model + ".sol";
@@ -113,7 +114,10 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {
113114

114115
highs.run();
115116
if (dev_run) printf("Num nodes = %d\n", int(info.mip_node_count));
116-
REQUIRE(info.mip_node_count != scratch_num_nodes);
117+
const bool different_search =
118+
info.mip_node_count != scratch_num_nodes ||
119+
info.simplex_iteration_count != scratch_num_simplex;
120+
REQUIRE(different_search);
117121
highs.clear();
118122
}
119123

@@ -132,7 +136,10 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {
132136

133137
highs.run();
134138
if (dev_run) printf("Num nodes = %d\n", int(info.mip_node_count));
135-
REQUIRE(info.mip_node_count != scratch_num_nodes);
139+
const bool different_search =
140+
info.mip_node_count != scratch_num_nodes ||
141+
info.simplex_iteration_count != scratch_num_simplex;
142+
REQUIRE(different_search);
136143
highs.clear();
137144
}
138145

@@ -162,7 +169,10 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {
162169

163170
highs.run();
164171
if (dev_run) printf("Num nodes = %d\n", int(info.mip_node_count));
165-
REQUIRE(info.mip_node_count != scratch_num_nodes);
172+
const bool different_search =
173+
info.mip_node_count != scratch_num_nodes ||
174+
info.simplex_iteration_count != scratch_num_simplex;
175+
REQUIRE(different_search);
166176
highs.clear();
167177
}
168178

@@ -185,7 +195,10 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {
185195

186196
highs.run();
187197
if (dev_run) printf("Num nodes = %d\n", int(info.mip_node_count));
188-
REQUIRE(info.mip_node_count != scratch_num_nodes);
198+
const bool different_search =
199+
info.mip_node_count != scratch_num_nodes ||
200+
info.simplex_iteration_count != scratch_num_simplex;
201+
REQUIRE(different_search);
189202
highs.clear();
190203
}
191204

@@ -232,7 +245,10 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {
232245
return_status = highs.setSolution(starting_solution);
233246
REQUIRE(return_status == HighsStatus::kOk);
234247
highs.run();
235-
REQUIRE(info.mip_node_count != scratch_num_nodes);
248+
const bool different_search =
249+
info.mip_node_count != scratch_num_nodes ||
250+
info.simplex_iteration_count != scratch_num_simplex;
251+
REQUIRE(different_search);
236252
highs.clear();
237253
}
238254

@@ -283,7 +299,10 @@ TEST_CASE("check-set-mip-solution", "[highs_check_solution]") {
283299
return_status = highs.setSolution(num_entries, index.data(), value.data());
284300
REQUIRE(return_status == HighsStatus::kOk);
285301
highs.run();
286-
REQUIRE(info.mip_node_count != scratch_num_nodes);
302+
const bool different_search =
303+
info.mip_node_count != scratch_num_nodes ||
304+
info.simplex_iteration_count != scratch_num_simplex;
305+
REQUIRE(different_search);
287306
highs.clear();
288307
}
289308
assert(other_tests);

check/TestMipSolver.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,6 +1162,7 @@ TEST_CASE("mip-lp-solver", "[highs_test_mip_solver]") {
11621162
#endif
11631163
}
11641164

1165+
/*
11651166
TEST_CASE("mip-sub-solver-time", "[highs_test_mip_solver]") {
11661167
const std::string model = "flugpl"; //"rgn"; //
11671168
std::string model_file =
@@ -1174,6 +1175,7 @@ TEST_CASE("mip-sub-solver-time", "[highs_test_mip_solver]") {
11741175
REQUIRE(h.run() == HighsStatus::kOk);
11751176
REQUIRE(h.getModelStatus() == HighsModelStatus::kOptimal);
11761177
}
1178+
*/
11771179

11781180
TEST_CASE("get-fixed-lp", "[highs_test_mip_solver]") {
11791181
std::string model = "avgas";
@@ -1405,6 +1407,28 @@ TEST_CASE("issue-2173", "[highs_test_mip_solver]") {
14051407
solve(highs, kHighsOnString, require_model_status, optimal_objective);
14061408
}
14071409

1410+
TEST_CASE("parallel-mip-determinism", "[highs_test_mip_solver]") {
1411+
std::string filename = std::string(HIGHS_DIR) + "/check/instances/bell5.mps";
1412+
HighsInt num_runs = 6;
1413+
std::vector<HighsInt> lp_iters(num_runs);
1414+
for (HighsInt i = 0; i < num_runs; i++) {
1415+
Highs highs;
1416+
highs.setOptionValue("output_flag", dev_run);
1417+
highs.setOptionValue("mip_rel_gap", 0);
1418+
highs.setOptionValue("threads", 2);
1419+
highs.setOptionValue("parallel", kHighsOnString);
1420+
if (i % 2 == 0) highs.setOptionValue("mip_search_simulate_concurrency", 1);
1421+
highs.readModel(filename);
1422+
const HighsModelStatus require_model_status = HighsModelStatus::kOptimal;
1423+
const double optimal_objective = 8966406.491519;
1424+
solve(highs, kHighsOffString, require_model_status, optimal_objective);
1425+
lp_iters[i] = highs.getInfo().simplex_iteration_count;
1426+
if (i > 0) {
1427+
REQUIRE(lp_iters[i] == lp_iters[0]);
1428+
}
1429+
}
1430+
}
1431+
14081432
TEST_CASE("issue-2957", "[highs_test_mip_solver]") {
14091433
HighsLp lp;
14101434
lp.num_col_ = 2;

check/TestSemiVariables.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ TEST_CASE("semi-variable-model", "[highs_test_semi_variables]") {
2626
const double semi_col_lower = lp.col_lower_[semi_col];
2727
const double semi_col_upper = lp.col_upper_[semi_col];
2828
lp.col_cost_[semi_col] = semi_col_cost;
29+
lp.model_name_ = "semi-variable-model";
2930
optimal_objective_function_value = 6.83333;
3031
// Legal to have infinte upper bounds on semi-variables
3132
lp.col_upper_[semi_col] = inf;

cmake/sources.cmake

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,9 +380,9 @@ set(highs_sources
380380
mip/HighsImplications.cpp
381381
mip/HighsLpAggregator.cpp
382382
mip/HighsLpRelaxation.cpp
383-
mip/HighsMipAnalysis.cpp
384383
mip/HighsMipSolver.cpp
385384
mip/HighsMipSolverData.cpp
385+
mip/HighsMipWorker.cpp
386386
mip/HighsModkSeparator.cpp
387387
mip/HighsNodeQueue.cpp
388388
mip/HighsObjectiveFunction.cpp
@@ -510,9 +510,9 @@ set(highs_headers
510510
mip/HighsImplications.h
511511
mip/HighsLpAggregator.h
512512
mip/HighsLpRelaxation.h
513-
mip/HighsMipAnalysis.h
514513
mip/HighsMipSolver.h
515514
mip/HighsMipSolverData.h
515+
mip/HighsMipWorker.h
516516
mip/HighsModkSeparator.h
517517
mip/HighsNodeQueue.h
518518
mip/HighsObjectiveFunction.h

0 commit comments

Comments
 (0)