Skip to content

Commit 23f3d80

Browse files
committed
Merge branch 'latest' into metis-workflow
2 parents 148172a + b3fee7c commit 23f3d80

26 files changed

+1094
-210
lines changed

.github/workflows/valgrind.yml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,82 @@ jobs:
9292
--output-on-failure \
9393
2>&1 | tee logfile2
9494
95+
- name: Check log for Errors
96+
working-directory: ${{runner.workspace}}/build
97+
shell: bash
98+
run: |
99+
cat logfile2
100+
OUTPUT='ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)'
101+
if grep -q "$OUTPUT" logfile2; then
102+
exit 0
103+
fi
104+
exit 1
105+
106+
examples:
107+
runs-on: ${{ matrix.os }}
108+
strategy:
109+
matrix:
110+
os: [ubuntu-latest]
111+
112+
steps:
113+
- uses: actions/checkout@v4
114+
115+
- name: Install Valgrind
116+
run: sudo apt-get update && sudo apt-get install valgrind
117+
118+
- name: Create Build Environment
119+
run: cmake -E make_directory ${{runner.workspace}}/build
120+
121+
- name: Configure CMake All
122+
shell: bash
123+
working-directory: ${{runner.workspace}}/build
124+
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=Debug
125+
126+
- name: Build All
127+
working-directory: ${{runner.workspace}}/build
128+
shell: bash
129+
run: |
130+
cmake --build . --parallel
131+
132+
- name: Test cpp example
133+
working-directory: ${{runner.workspace}}/build
134+
shell: bash
135+
run: |
136+
valgrind \
137+
--leak-check=full \
138+
--show-leak-kinds=all \
139+
--track-origins=yes \
140+
-s \
141+
./bin/call_highs_from_cpp \
142+
--timeout 1000 \
143+
--output-on-failure \
144+
2>&1 | tee logfile2
145+
146+
- name: Check log for Errors
147+
working-directory: ${{runner.workspace}}/build
148+
shell: bash
149+
run: |
150+
cat logfile2
151+
OUTPUT='ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)'
152+
if grep -q "$OUTPUT" logfile2; then
153+
exit 0
154+
fi
155+
exit 1
156+
157+
- name: Test C example
158+
working-directory: ${{runner.workspace}}/build
159+
shell: bash
160+
run: |
161+
valgrind \
162+
--leak-check=full \
163+
--show-leak-kinds=all \
164+
--track-origins=yes \
165+
-s \
166+
./bin/call_highs_from_c_minimal \
167+
--timeout 1000 \
168+
--output-on-failure \
169+
2>&1 | tee logfile2
170+
95171
- name: Check log for Errors
96172
working-directory: ${{runner.workspace}}/build
97173
shell: bash

BUILD.bazel

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
load("@bazel_skylib//rules:copy_file.bzl", "copy_file")
2-
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_binary", "cc_test")
2+
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
33

44
copy_file(
55
name = "highs-config",
@@ -16,9 +16,8 @@ cc_library(
1616

1717
cc_library(
1818
name = "highs",
19-
srcs = glob([
19+
srcs = ["highs/interfaces/highs_c_api.cpp"] + glob([
2020
"extern/filereaderlp/*.cpp",
21-
"highs/interfaces/highs_c_api.cpp",
2221
"highs/io/*.cpp",
2322
"highs/ipm/*.cpp",
2423
"highs/ipm/ipx/*.cc",
@@ -35,18 +34,21 @@ cc_library(
3534
"highs/test_kkt/*.cpp",
3635
"highs/util/*.cpp",
3736
]),
38-
hdrs = glob([
39-
"**/*.h",
37+
hdrs = [
4038
"highs/mip/feasibilityjump.hh",
39+
] + glob([
40+
"**/*.h",
4141
"highs/qpsolver/*.hpp",
42-
"highs/Highs.h",
4342
"extern/filereaderlp/*.hpp",
4443
"extern/zstr/*.hpp",
4544
]),
46-
copts = [
47-
"-Wno-unused-variable",
48-
"-Wno-unused-but-set-variable",
49-
],
45+
copts = select({
46+
"@rules_cc//cc/compiler:msvc-cl": [],
47+
"//conditions:default": [
48+
"-Wno-unused-variable",
49+
"-Wno-unused-but-set-variable",
50+
],
51+
}),
5052
includes = [
5153
"extern",
5254
# "extern/filereaderlp",
@@ -66,7 +68,10 @@ cc_library(
6668
# "highs/util",
6769
"bazel-bin",
6870
],
69-
linkopts = ["-lpthread"],
71+
linkopts = select({
72+
"@rules_cc//cc/compiler:msvc-cl": ["-DEFAULTLIB:shell32.lib"],
73+
"//conditions:default": ["-lpthread"],
74+
}),
7075
visibility = ["//visibility:public"],
7176
deps = [
7277
"//:config",
@@ -76,8 +81,10 @@ cc_library(
7681

7782
cc_library(
7883
name = "highs-runtime-opts",
79-
hdrs = ["app/HighsRuntimeOptions.h",
80-
"app/CLI11.hpp"],
84+
hdrs = [
85+
"app/CLI11.hpp",
86+
"app/HighsRuntimeOptions.h",
87+
],
8188
visibility = ["//visibility:public"],
8289
deps = [
8390
"//:highs",
@@ -180,11 +187,13 @@ TEST_NAMES = [
180187
[cc_test(
181188
name = name,
182189
srcs = ["check/%s.cpp" % name],
183-
copts = [
184-
"-Iextern",
185-
"-Wno-unused-variable",
186-
"-Wno-unused-but-set-variable",
187-
],
190+
copts = ["-Iextern"] + select({
191+
"@rules_cc//cc/compiler:msvc-cl": [],
192+
"//conditions:default": [
193+
"-Wno-unused-variable",
194+
"-Wno-unused-but-set-variable",
195+
],
196+
}),
188197
deps = [
189198
":highs",
190199
":test_lib",

MODULE.bazel

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ module(
77

88
bazel_dep(
99
name = "bazel_skylib",
10-
version = "1.7.1",
10+
version = "1.8.1",
1111
)
1212

1313
bazel_dep(
1414
name = "rules_cc",
15-
version = "0.0.16",
15+
version = "0.1.2",
1616
)
1717

1818
bazel_dep(
1919
name = "zlib",
20-
version = "1.3.1.bcr.3",
20+
version = "1.3.1.bcr.5",
2121
)

check/TestPresolve.cpp

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,3 +734,107 @@ TEST_CASE("presolve-issue-2446", "[highs_test_presolve]") {
734734
REQUIRE(highs.presolve() == HighsStatus::kOk);
735735
REQUIRE(highs.getModelPresolveStatus() == HighsPresolveStatus::kReduced);
736736
}
737+
738+
TEST_CASE("presolve-solve-postsolve-no-col-dual", "[highs_test_presolve]") {
739+
Highs highs;
740+
highs.setOptionValue("output_flag", dev_run);
741+
std::string model_file =
742+
std::string(HIGHS_DIR) + "/check/instances/afiro.mps";
743+
highs.readModel(model_file);
744+
highs.presolve();
745+
HighsLp presolved_lp = highs.getPresolvedLp();
746+
Highs highs1;
747+
highs1.setOptionValue("output_flag", dev_run);
748+
highs1.setOptionValue("presolve", kHighsOffString);
749+
highs1.passModel(presolved_lp);
750+
highs1.run();
751+
HighsSolution solution = highs1.getSolution();
752+
753+
// Perform postsolve using the optimal solution and basis for the
754+
// presolved model
755+
REQUIRE(highs.postsolve(solution) == HighsStatus::kOk);
756+
757+
// If row duals are supplied, then column duals must also be suppplied
758+
solution.col_dual.clear();
759+
REQUIRE(highs.postsolve(solution) == HighsStatus::kError);
760+
761+
highs.resetGlobalScheduler(true);
762+
}
763+
764+
TEST_CASE("presolve-egout-ac", "[highs_test_presolve]") {
765+
// Tests the case where, for this model when run_crossover is off,
766+
// sparsify is used to reduce the LP to empty. However, when
767+
// starting from an empty LP, basis postsolve is always used
768+
std::string model_file =
769+
std::string(HIGHS_DIR) + "/check/instances/egout-ac.mps";
770+
Highs h;
771+
h.setOptionValue("output_flag", dev_run);
772+
REQUIRE(h.setOptionValue("presolve_rule_logging", true) == HighsStatus::kOk);
773+
if (dev_run)
774+
REQUIRE(h.setOptionValue("log_dev_level", 1) == HighsStatus::kOk);
775+
REQUIRE(h.readModel(model_file) == HighsStatus::kOk);
776+
// Firstly check that pure presolve reduces the LP to empty
777+
REQUIRE(h.presolve() == HighsStatus::kOk);
778+
// Ensure that sparsify isn't called
779+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
780+
781+
const HighsLp& presolved_lp = h.getPresolvedLp();
782+
REQUIRE(presolved_lp.num_col_ == 0);
783+
REQUIRE(presolved_lp.num_row_ == 0);
784+
785+
HighsSolution solution;
786+
HighsBasis basis;
787+
basis.useful = true;
788+
solution.value_valid = true;
789+
solution.dual_valid = true;
790+
// Check that postsolve with the empty solution and basis runs OK -
791+
// ie doesn't trigger assert due to sparsify having been used
792+
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
793+
794+
// Check that using IPM with crossover runs OK without using
795+
// sparsify
796+
REQUIRE(h.setOptionValue("solver", kIpmString) == HighsStatus::kOk);
797+
REQUIRE(h.run() == HighsStatus::kOk);
798+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
799+
800+
// Check that pure presolve reduces the LP to empty without using
801+
// sparsify
802+
REQUIRE(h.presolve() == HighsStatus::kOk);
803+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
804+
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
805+
806+
// Check that pure presolve reduces the LP to empty using sparsify
807+
// when lp_presolve_requires_basis_postsolve is false
808+
bool lp_presolve_requires_basis_postsolve = false;
809+
REQUIRE(h.setOptionValue("lp_presolve_requires_basis_postsolve",
810+
lp_presolve_requires_basis_postsolve) ==
811+
HighsStatus::kOk);
812+
REQUIRE(h.presolve() == HighsStatus::kOk);
813+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call > 0);
814+
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
815+
REQUIRE(h.getOptions().lp_presolve_requires_basis_postsolve ==
816+
lp_presolve_requires_basis_postsolve);
817+
818+
// Now, with crossover off
819+
REQUIRE(h.setOptionValue("run_crossover", kHighsOffString) ==
820+
HighsStatus::kOk);
821+
822+
// Now reset lp_presolve_requires_basis_postsolve default to true,
823+
// to test whether it's set false due to running IPM without
824+
// crossover
825+
lp_presolve_requires_basis_postsolve = true;
826+
REQUIRE(h.setOptionValue("lp_presolve_requires_basis_postsolve",
827+
lp_presolve_requires_basis_postsolve) ==
828+
HighsStatus::kOk);
829+
830+
REQUIRE(h.clearSolver() == HighsStatus::kOk);
831+
REQUIRE(h.run() == HighsStatus::kOk);
832+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call > 0);
833+
// Ensure that lp_presolve_requires_basis_postsolve has been reset
834+
// to true, after being set false before presolve when using IPM
835+
// without crossover
836+
REQUIRE(h.getOptions().lp_presolve_requires_basis_postsolve ==
837+
lp_presolve_requires_basis_postsolve);
838+
839+
h.resetGlobalScheduler(true);
840+
}

0 commit comments

Comments
 (0)