Skip to content

Commit d00326f

Browse files
committed
merge latest
2 parents 35a1ffc + b3fee7c commit d00326f

26 files changed

+1127
-207
lines changed

.github/workflows/valgrind.yml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,82 @@ jobs:
9393
--output-on-failure \
9494
2>&1 | tee logfile2
9595
96+
- name: Check log for Errors
97+
working-directory: ${{runner.workspace}}/build
98+
shell: bash
99+
run: |
100+
cat logfile2
101+
OUTPUT='ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)'
102+
if grep -q "$OUTPUT" logfile2; then
103+
exit 0
104+
fi
105+
exit 1
106+
107+
examples:
108+
runs-on: ${{ matrix.os }}
109+
strategy:
110+
matrix:
111+
os: [ubuntu-latest]
112+
113+
steps:
114+
- uses: actions/checkout@v4
115+
116+
- name: Install Valgrind
117+
run: sudo apt-get update && sudo apt-get install valgrind
118+
119+
- name: Create Build Environment
120+
run: cmake -E make_directory ${{runner.workspace}}/build
121+
122+
- name: Configure CMake All
123+
shell: bash
124+
working-directory: ${{runner.workspace}}/build
125+
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=Debug
126+
127+
- name: Build All
128+
working-directory: ${{runner.workspace}}/build
129+
shell: bash
130+
run: |
131+
cmake --build . --parallel
132+
133+
- name: Test cpp example
134+
working-directory: ${{runner.workspace}}/build
135+
shell: bash
136+
run: |
137+
valgrind \
138+
--leak-check=full \
139+
--show-leak-kinds=all \
140+
--track-origins=yes \
141+
-s \
142+
./bin/call_highs_from_cpp \
143+
--timeout 1000 \
144+
--output-on-failure \
145+
2>&1 | tee logfile2
146+
147+
- name: Check log for Errors
148+
working-directory: ${{runner.workspace}}/build
149+
shell: bash
150+
run: |
151+
cat logfile2
152+
OUTPUT='ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)'
153+
if grep -q "$OUTPUT" logfile2; then
154+
exit 0
155+
fi
156+
exit 1
157+
158+
- name: Test C example
159+
working-directory: ${{runner.workspace}}/build
160+
shell: bash
161+
run: |
162+
valgrind \
163+
--leak-check=full \
164+
--show-leak-kinds=all \
165+
--track-origins=yes \
166+
-s \
167+
./bin/call_highs_from_c_minimal \
168+
--timeout 1000 \
169+
--output-on-failure \
170+
2>&1 | tee logfile2
171+
96172
- name: Check log for Errors
97173
working-directory: ${{runner.workspace}}/build
98174
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
@@ -735,3 +735,107 @@ TEST_CASE("presolve-issue-2446", "[highs_test_presolve]") {
735735
REQUIRE(highs.presolve() == HighsStatus::kOk);
736736
REQUIRE(highs.getModelPresolveStatus() == HighsPresolveStatus::kReduced);
737737
}
738+
739+
TEST_CASE("presolve-solve-postsolve-no-col-dual", "[highs_test_presolve]") {
740+
Highs highs;
741+
highs.setOptionValue("output_flag", dev_run);
742+
std::string model_file =
743+
std::string(HIGHS_DIR) + "/check/instances/afiro.mps";
744+
highs.readModel(model_file);
745+
highs.presolve();
746+
HighsLp presolved_lp = highs.getPresolvedLp();
747+
Highs highs1;
748+
highs1.setOptionValue("output_flag", dev_run);
749+
highs1.setOptionValue("presolve", kHighsOffString);
750+
highs1.passModel(presolved_lp);
751+
highs1.run();
752+
HighsSolution solution = highs1.getSolution();
753+
754+
// Perform postsolve using the optimal solution and basis for the
755+
// presolved model
756+
REQUIRE(highs.postsolve(solution) == HighsStatus::kOk);
757+
758+
// If row duals are supplied, then column duals must also be suppplied
759+
solution.col_dual.clear();
760+
REQUIRE(highs.postsolve(solution) == HighsStatus::kError);
761+
762+
highs.resetGlobalScheduler(true);
763+
}
764+
765+
TEST_CASE("presolve-egout-ac", "[highs_test_presolve]") {
766+
// Tests the case where, for this model when run_crossover is off,
767+
// sparsify is used to reduce the LP to empty. However, when
768+
// starting from an empty LP, basis postsolve is always used
769+
std::string model_file =
770+
std::string(HIGHS_DIR) + "/check/instances/egout-ac.mps";
771+
Highs h;
772+
h.setOptionValue("output_flag", dev_run);
773+
REQUIRE(h.setOptionValue("presolve_rule_logging", true) == HighsStatus::kOk);
774+
if (dev_run)
775+
REQUIRE(h.setOptionValue("log_dev_level", 1) == HighsStatus::kOk);
776+
REQUIRE(h.readModel(model_file) == HighsStatus::kOk);
777+
// Firstly check that pure presolve reduces the LP to empty
778+
REQUIRE(h.presolve() == HighsStatus::kOk);
779+
// Ensure that sparsify isn't called
780+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
781+
782+
const HighsLp& presolved_lp = h.getPresolvedLp();
783+
REQUIRE(presolved_lp.num_col_ == 0);
784+
REQUIRE(presolved_lp.num_row_ == 0);
785+
786+
HighsSolution solution;
787+
HighsBasis basis;
788+
basis.useful = true;
789+
solution.value_valid = true;
790+
solution.dual_valid = true;
791+
// Check that postsolve with the empty solution and basis runs OK -
792+
// ie doesn't trigger assert due to sparsify having been used
793+
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
794+
795+
// Check that using IPM with crossover runs OK without using
796+
// sparsify
797+
REQUIRE(h.setOptionValue("solver", kIpmString) == HighsStatus::kOk);
798+
REQUIRE(h.run() == HighsStatus::kOk);
799+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
800+
801+
// Check that pure presolve reduces the LP to empty without using
802+
// sparsify
803+
REQUIRE(h.presolve() == HighsStatus::kOk);
804+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
805+
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
806+
807+
// Check that pure presolve reduces the LP to empty using sparsify
808+
// when lp_presolve_requires_basis_postsolve is false
809+
bool lp_presolve_requires_basis_postsolve = false;
810+
REQUIRE(h.setOptionValue("lp_presolve_requires_basis_postsolve",
811+
lp_presolve_requires_basis_postsolve) ==
812+
HighsStatus::kOk);
813+
REQUIRE(h.presolve() == HighsStatus::kOk);
814+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call > 0);
815+
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
816+
REQUIRE(h.getOptions().lp_presolve_requires_basis_postsolve ==
817+
lp_presolve_requires_basis_postsolve);
818+
819+
// Now, with crossover off
820+
REQUIRE(h.setOptionValue("run_crossover", kHighsOffString) ==
821+
HighsStatus::kOk);
822+
823+
// Now reset lp_presolve_requires_basis_postsolve default to true,
824+
// to test whether it's set false due to running IPM without
825+
// crossover
826+
lp_presolve_requires_basis_postsolve = true;
827+
REQUIRE(h.setOptionValue("lp_presolve_requires_basis_postsolve",
828+
lp_presolve_requires_basis_postsolve) ==
829+
HighsStatus::kOk);
830+
831+
REQUIRE(h.clearSolver() == HighsStatus::kOk);
832+
REQUIRE(h.run() == HighsStatus::kOk);
833+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call > 0);
834+
// Ensure that lp_presolve_requires_basis_postsolve has been reset
835+
// to true, after being set false before presolve when using IPM
836+
// without crossover
837+
REQUIRE(h.getOptions().lp_presolve_requires_basis_postsolve ==
838+
lp_presolve_requires_basis_postsolve);
839+
840+
h.resetGlobalScheduler(true);
841+
}

0 commit comments

Comments
 (0)