Skip to content

Commit 752afca

Browse files
committed
Merge branch 'latest' into warnings-gcc
2 parents 6904857 + 3d36291 commit 752afca

File tree

10 files changed

+736
-13
lines changed

10 files changed

+736
-13
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

check/TestPresolve.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,3 +734,81 @@ 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-egout-ac", "[highs_test_presolve]") {
739+
// Tests the case where, for this model when run_crossover is off,
740+
// sparsify is used to reduce the LP to empty. However, when
741+
// starting from an empty LP, basis postsolve is always used
742+
std::string model_file =
743+
std::string(HIGHS_DIR) + "/check/instances/egout-ac.mps";
744+
Highs h;
745+
h.setOptionValue("output_flag", dev_run);
746+
REQUIRE(h.setOptionValue("presolve_rule_logging", true) == HighsStatus::kOk);
747+
if (dev_run)
748+
REQUIRE(h.setOptionValue("log_dev_level", 1) == HighsStatus::kOk);
749+
REQUIRE(h.readModel(model_file) == HighsStatus::kOk);
750+
// Firstly check that pure presolve reduces the LP to empty
751+
REQUIRE(h.presolve() == HighsStatus::kOk);
752+
// Ensure that sparsify isn't called
753+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
754+
755+
const HighsLp& presolved_lp = h.getPresolvedLp();
756+
REQUIRE(presolved_lp.num_col_ == 0);
757+
REQUIRE(presolved_lp.num_row_ == 0);
758+
759+
HighsSolution solution;
760+
HighsBasis basis;
761+
basis.useful = true;
762+
solution.value_valid = true;
763+
solution.dual_valid = true;
764+
// Check that postsolve with the empty solution and basis runs OK -
765+
// ie doesn't trigger assert due to sparsify having been used
766+
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
767+
768+
// Check that using IPM with crossover runs OK without using
769+
// sparsify
770+
REQUIRE(h.setOptionValue("solver", kIpmString) == HighsStatus::kOk);
771+
REQUIRE(h.run() == HighsStatus::kOk);
772+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
773+
774+
// Check that pure presolve reduces the LP to empty without using
775+
// sparsify
776+
REQUIRE(h.presolve() == HighsStatus::kOk);
777+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call == 0);
778+
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
779+
780+
// Check that pure presolve reduces the LP to empty using sparsify
781+
// when lp_presolve_requires_basis_postsolve is false
782+
bool lp_presolve_requires_basis_postsolve = false;
783+
REQUIRE(h.setOptionValue("lp_presolve_requires_basis_postsolve",
784+
lp_presolve_requires_basis_postsolve) ==
785+
HighsStatus::kOk);
786+
REQUIRE(h.presolve() == HighsStatus::kOk);
787+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call > 0);
788+
REQUIRE(h.postsolve(solution, basis) == HighsStatus::kOk);
789+
REQUIRE(h.getOptions().lp_presolve_requires_basis_postsolve ==
790+
lp_presolve_requires_basis_postsolve);
791+
792+
// Now, with crossover off
793+
REQUIRE(h.setOptionValue("run_crossover", kHighsOffString) ==
794+
HighsStatus::kOk);
795+
796+
// Now reset lp_presolve_requires_basis_postsolve default to true,
797+
// to test whether it's set false due to running IPM without
798+
// crossover
799+
lp_presolve_requires_basis_postsolve = true;
800+
REQUIRE(h.setOptionValue("lp_presolve_requires_basis_postsolve",
801+
lp_presolve_requires_basis_postsolve) ==
802+
HighsStatus::kOk);
803+
804+
REQUIRE(h.clearSolver() == HighsStatus::kOk);
805+
REQUIRE(h.run() == HighsStatus::kOk);
806+
REQUIRE(h.getPresolveLog().rule[kPresolveRuleSparsify].call > 0);
807+
// Ensure that lp_presolve_requires_basis_postsolve has been reset
808+
// to true, after being set false before presolve when using IPM
809+
// without crossover
810+
REQUIRE(h.getOptions().lp_presolve_requires_basis_postsolve ==
811+
lp_presolve_requires_basis_postsolve);
812+
813+
h.resetGlobalScheduler(true);
814+
}

0 commit comments

Comments
 (0)