Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
237 commits
Select commit Hold shift + click to select a range
8db6a3d
WIP
fwesselm Apr 28, 2026
98183bc
Fix format
fwesselm Apr 28, 2026
8b05196
Simplify
fwesselm Apr 28, 2026
4b880d5
Add comments
fwesselm Apr 28, 2026
1cb0450
Use okResize
fwesselm Apr 28, 2026
60a80ff
More WIP
fwesselm Apr 29, 2026
ee737b5
Return Result::kOk
fwesselm Apr 29, 2026
6aa8fd5
WIP
fwesselm Apr 29, 2026
58378c6
Re-set pointers for bound vectors
fwesselm Apr 30, 2026
1774ba2
Skip deleted rows
fwesselm Apr 30, 2026
e1065df
WIP
fwesselm May 5, 2026
5c1bcb6
WIP
fwesselm May 6, 2026
f4ff79e
More WIP
fwesselm May 6, 2026
8e609db
More WIP
fwesselm May 6, 2026
001e7aa
WIP
fwesselm May 6, 2026
60dd349
Restarts still not working
fwesselm May 7, 2026
2f5e5a1
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into pres…
fwesselm May 8, 2026
a6249a5
WIP
fwesselm May 8, 2026
7fb4241
Still WIP
fwesselm May 8, 2026
dd7ba14
WIP
fwesselm May 8, 2026
d240363
Pass reference to postsolve stack to undo
fwesselm May 8, 2026
4917aee
Still WIP
fwesselm May 8, 2026
f501b74
Undo change
fwesselm May 8, 2026
b4b501c
WIP
fwesselm May 11, 2026
cf3fb69
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into pres…
fwesselm May 11, 2026
8c33b10
Argh, still WIP
fwesselm May 12, 2026
8638241
WIP
fwesselm May 12, 2026
67377ce
WIP
fwesselm May 13, 2026
f6d3ab9
WIP
fwesselm May 13, 2026
fc5da65
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into pres…
fwesselm May 13, 2026
7708fc1
And WIP again
fwesselm May 13, 2026
6a23105
Fix issue in unsed code
fwesselm May 13, 2026
3ac0def
Add indicator for row type
fwesselm May 13, 2026
37e91ef
WIP
fwesselm May 13, 2026
8e673c3
WIP
fwesselm May 13, 2026
dc9565c
Add utility methods
fwesselm May 13, 2026
ac29c0b
Rename
fwesselm May 18, 2026
4e9e51e
WIP
fwesselm May 18, 2026
3fec169
Format
fwesselm May 18, 2026
965b66a
WIP
fwesselm May 18, 2026
96fe562
WIP
fwesselm May 18, 2026
07e3051
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into pres…
fwesselm May 18, 2026
9569e1e
WIP
fwesselm May 18, 2026
c1f8489
Merge branch 'presolveAddRowsDebugging7' of https://github.com/fwesse…
fwesselm May 18, 2026
9017acb
WIP
fwesselm May 18, 2026
195305c
Remove extra variable
fwesselm May 18, 2026
a577431
Remove debugging code
fwesselm May 18, 2026
08b3adc
WIP
fwesselm May 19, 2026
8a772c5
Merge branch 'latest' of https://github.com/fwesselm/HiGHS into preso…
fwesselm May 26, 2026
ca383bd
Cannot use shrinkProblem
fwesselm May 26, 2026
ed1d357
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into pres…
fwesselm May 26, 2026
ce57eea
Remove debugging code
fwesselm May 26, 2026
39f5853
Merge branch 'presolveAddRows7' of https://github.com/fwesselm/HiGHS …
fwesselm May 28, 2026
52ee49a
WIP
fwesselm May 28, 2026
6fac31c
Clean up
fwesselm May 28, 2026
678b29e
Simplify
fwesselm May 28, 2026
f3dbeb5
Heap
fwesselm May 28, 2026
6b4922d
Resize singleEquationChecked
fwesselm May 28, 2026
6149f99
Simplify again
fwesselm May 28, 2026
1f74f9f
Add flag
fwesselm May 28, 2026
032d80f
Merge branch 'fourierMotzkin2' of https://github.com/fwesselm/HiGHS i…
fwesselm May 28, 2026
46bfd28
Add message
fwesselm May 28, 2026
de74be1
Rename
fwesselm May 28, 2026
6a1fbdd
Merge branch 'fourierMotzkin2' of https://github.com/fwesselm/HiGHS i…
fwesselm May 28, 2026
60fcf05
Bound handling
fwesselm May 28, 2026
12a096d
Initialise
fwesselm May 29, 2026
2e6786f
Add another lambda to check if column is a candidate
fwesselm May 29, 2026
824434a
Merge branch 'fourierMotzkin2' of https://github.com/fwesselm/HiGHS i…
fwesselm May 29, 2026
0045191
Format
fwesselm May 29, 2026
59e3a73
Remove check
fwesselm May 29, 2026
7e624e8
Clean up
fwesselm May 29, 2026
394455b
Postolve
fwesselm May 29, 2026
badcf5f
WIP
fwesselm May 29, 2026
e2a84b4
WIP
fwesselm May 29, 2026
f7d8ab0
WIP
fwesselm Jun 1, 2026
56c00af
WIP
fwesselm Jun 1, 2026
d57cbf6
WIP
fwesselm Jun 1, 2026
c4083f0
WIP
fwesselm Jun 1, 2026
a86bdff
WIP
fwesselm Jun 2, 2026
d025edf
WIP
fwesselm Jun 2, 2026
77bf8b0
WIP
fwesselm Jun 3, 2026
a833703
WIP
fwesselm Jun 3, 2026
e16f90c
WIP
fwesselm Jun 3, 2026
80d6a77
WIP
fwesselm Jun 3, 2026
fe3ec59
WIP
fwesselm Jun 3, 2026
7973649
Remove debugging code
fwesselm Jun 3, 2026
56881a6
Apply only once
fwesselm Jun 3, 2026
3825291
Revert change for debugging
fwesselm Jun 3, 2026
dcd8dd6
Use implied bounds and remove debug print
fwesselm Jun 5, 2026
21ef5a3
Fix build error
fwesselm Jun 5, 2026
abaa8c8
Skip cols with non-zero objective coefficient
fwesselm Jun 5, 2026
9945207
Add artificial variable for objective
fwesselm Jun 5, 2026
8edc1c3
WIP
fwesselm Jun 8, 2026
6eb1cb2
Resize
fwesselm Jun 8, 2026
00fc8f0
Fix reformulation
fwesselm Jun 8, 2026
2dab50a
Fix pseudo cost
fwesselm Jun 8, 2026
f071113
Fix basis
fwesselm Jun 8, 2026
9875e49
WIP
fwesselm Jun 8, 2026
bc1e474
WIP
fwesselm Jun 8, 2026
5dafacd
More postsolve changes
fwesselm Jun 8, 2026
34d4b29
Fix postsolve
fwesselm Jun 8, 2026
5bda1d1
New lambda
fwesselm Jun 8, 2026
c46f1de
Simplify
fwesselm Jun 8, 2026
973eb73
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Jun 8, 2026
cea2bfe
Reformulate only if needed
fwesselm Jun 8, 2026
d4d40ed
Fix output alignment
fwesselm Jun 8, 2026
a6afedb
Remove extra check
fwesselm Jun 8, 2026
4c32837
Enable on LPs
fwesselm Jun 9, 2026
734ff6a
Clean up
fwesselm Jun 9, 2026
bb2faca
Use static_cast
fwesselm Jun 9, 2026
58ec85c
Allow multiple rounds of FM presolve
fwesselm Jun 9, 2026
4234afa
Minor changes
fwesselm Jun 9, 2026
a842f24
Still issues with basis postsolve
fwesselm Jun 9, 2026
be60813
Rework postsolve
fwesselm Jun 10, 2026
39c9d79
Formatted
fwesselm Jun 10, 2026
e532146
Simplify
fwesselm Jun 10, 2026
6a27df1
Simplify again
fwesselm Jun 10, 2026
f42e203
Comments
fwesselm Jun 10, 2026
9533f1d
Simplify some more
fwesselm Jun 10, 2026
6b1e790
Fix merge
fwesselm Jun 10, 2026
52516a1
Try on LPs again
fwesselm Jun 10, 2026
7064915
Fix test
fwesselm Jun 10, 2026
741af63
Clean up postsolve
fwesselm Jun 10, 2026
2f5bd41
Comments
fwesselm Jun 10, 2026
c89ad9f
Simplify postsolve and use HighsCDouble if needed
fwesselm Jun 10, 2026
b2afd70
Merge
fwesselm Jun 10, 2026
39e7cdd
Store correct scaling
fwesselm Jun 10, 2026
e7f9686
Primal postsolve
fwesselm Jun 11, 2026
6e1baee
Clean up some more
fwesselm Jun 11, 2026
bb1d471
Fix comment
fwesselm Jun 11, 2026
a35437b
Clean up
fwesselm Jun 11, 2026
d89b6ac
Comment
fwesselm Jun 11, 2026
1668343
Clean up
fwesselm Jun 11, 2026
a5fffb9
Clean up
fwesselm Jun 11, 2026
80bca3f
Primal postsolve as in paper
fwesselm Jun 11, 2026
6b7ebd8
Dual postsolve fix for ranged rows
fwesselm Jun 11, 2026
e9cc2a4
Fix col dual
fwesselm Jun 11, 2026
324c0b8
Basis postsolve again
fwesselm Jun 11, 2026
242c989
Basis postsolve again
fwesselm Jun 11, 2026
f34c37c
Primal postsolve and FME column index changes
fwesselm Jun 11, 2026
7bf2792
Modified reformulation logic
fwesselm Jun 11, 2026
ec5d2b1
Clean up
fwesselm Jun 11, 2026
66d5f9b
Move lambda
fwesselm Jun 11, 2026
f8a6fa4
Basis postsolve still not working
fwesselm Jun 12, 2026
cb8e864
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Jun 12, 2026
35568f8
Minor change
fwesselm Jun 12, 2026
335f9d2
Resize vector
fwesselm Jun 12, 2026
06cb5ec
Simplify some more
fwesselm Jun 12, 2026
390c8fb
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Jun 22, 2026
5bbd61c
Move logic to postsolve
fwesselm Jun 22, 2026
5a71bfc
Comment
fwesselm Jun 22, 2026
65c046b
Try to simplify a little more
fwesselm Jun 22, 2026
fc0aec0
Remove unused code
fwesselm Jun 22, 2026
e6f2874
Use checkLimits() correctly
fwesselm Jun 22, 2026
ee118a4
Use tolerance in primal postsolve
fwesselm Jun 22, 2026
745e4b4
Merge branch 'FMPresolve3' of https://github.com/fwesselm/HiGHS into …
fwesselm Jun 22, 2026
b2da68c
Clean up
fwesselm Jun 22, 2026
47159d8
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Jun 22, 2026
26570ae
Merge branch 'FMPresolve3' of https://github.com/fwesselm/HiGHS into …
fwesselm Jun 22, 2026
bdcc554
Reset stale values
fwesselm Jun 22, 2026
3f0aa9b
Fix sc50b
fwesselm Jun 23, 2026
3a5163b
Use global bounds
fwesselm Jun 23, 2026
a35484a
Add postsolve handling for rows that were converted to equations
fwesselm Jun 23, 2026
6b9c3ac
Cost should be zero
fwesselm Jun 24, 2026
6545812
Working on basis postsolve again
fwesselm Jun 24, 2026
c1e721c
Basis postsolve
fwesselm Jun 24, 2026
bf438ad
Fix handling of ranged rows
fwesselm Jun 24, 2026
ac18a6b
Add an assertion
fwesselm Jun 24, 2026
4a16200
Comment out assertion about numbers of rows/columns in TestCAPI
fwesselm Jun 24, 2026
251d4e0
Remove unused code
fwesselm Jun 24, 2026
9f2ffc7
Switch off FM for distillation LP
fwesselm Jun 24, 2026
c21cae6
Fix test
fwesselm Jun 24, 2026
42d3c52
Mark col as deleted before removing rows
fwesselm Jun 24, 2026
7cbb4de
Merge latest
fwesselm Jun 25, 2026
c09a170
Fix test after merge
fwesselm Jun 25, 2026
6fb1ce5
Add lambda for logging
fwesselm Jun 26, 2026
0bee908
Use HighsHashTable
fwesselm Jun 26, 2026
77965b7
Fix log message
fwesselm Jun 26, 2026
fbd05e2
Switch back to unordered_map
fwesselm Jun 26, 2026
60e00c6
Redundancy checks
fwesselm Jun 26, 2026
b3463e0
Added specific FM test to TestPresolveRules.cpp and reworded FM reduc…
Jun 26, 2026
c26aa4d
Merge branch 'latest' into FMPresolve4-jh
Jun 26, 2026
a042db8
Merged latest into this branch
Jun 26, 2026
a212fe3
Constructed simple example giving simplex iteration after postsolve
Jun 26, 2026
329f0ee
Derived failing FM postsolve test
Jun 26, 2026
76d3278
Cleaned up; formatted
Jun 26, 2026
91bdc7b
Fix check
fwesselm Jun 26, 2026
0c04422
Fix basis postsolve
fwesselm Jun 29, 2026
3065941
Remove debug printfs
fwesselm Jun 29, 2026
a626d6f
Don't run failing test
fwesselm Jun 29, 2026
ba41411
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Jun 29, 2026
faa25be
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Jun 29, 2026
38e37b5
Merge branch 'FMPresolve4-jh' of https://github.com/fwesselm/HiGHS in…
fwesselm Jun 29, 2026
cb347de
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Jun 29, 2026
5cb87dc
Merge branch 'FMPresolve4-jh' of https://github.com/fwesselm/HiGHS in…
fwesselm Jun 29, 2026
6424320
Clean up
fwesselm Jun 29, 2026
32924a4
Enable test but skip PDLP
fwesselm Jun 29, 2026
5b68226
Simplify
fwesselm Jun 29, 2026
dbe5c45
Clean up postsolve a little
fwesselm Jun 30, 2026
9930679
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Jun 30, 2026
04bca58
Some more postsolve cleanup
fwesselm Jun 30, 2026
fcb8ee3
Merge branch 'FMPresolve5' of https://github.com/fwesselm/HiGHS into …
fwesselm Jun 30, 2026
e865591
Fix build error
fwesselm Jun 30, 2026
73dd258
Sort candidates
fwesselm Jul 2, 2026
25db949
Add heap struct
fwesselm Jul 2, 2026
605a097
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Jul 2, 2026
a4e16ef
Move some code around
fwesselm Jul 3, 2026
67a8109
Stop early
fwesselm Jul 3, 2026
d8fc938
Add tryFourierMotzkin flag
fwesselm Jul 3, 2026
3f54fd1
Fix flag
fwesselm Jul 3, 2026
90049fc
Simplify
fwesselm Jul 3, 2026
aefaca0
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Jul 6, 2026
ca7294a
Tidy up HPresolve::dominatedColumns
fwesselm Jul 6, 2026
ddc8274
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Jul 15, 2026
48f5384
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Jul 15, 2026
f51842f
Merge with latest
fwesselm Aug 3, 2026
90960f9
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Aug 5, 2026
a37c797
Add option to control FM objective reformulation
fwesselm Aug 5, 2026
020b59b
Add overload for getOrigColIndex and getOrigRowIndex
fwesselm Aug 5, 2026
3baff29
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Aug 6, 2026
6633cf7
Don't build vector of non-zero objective coefficients if it is not used
fwesselm Aug 7, 2026
484a8a7
Merge branch 'FMPresolve5' of https://github.com/ERGO-Code/HiGHS into…
fwesselm Aug 7, 2026
3c926e9
Clear original row index
fwesselm Aug 7, 2026
94e1287
Merge branch 'FMPresolve5' of https://github.com/fwesselm/HiGHS into …
fwesselm Aug 7, 2026
daadc06
Fix commented out line
fwesselm Aug 7, 2026
06b577d
Fix tolerance
fwesselm Aug 7, 2026
fa3140e
Merge
fwesselm Aug 10, 2026
4b8bf3d
Merge chaser
fwesselm Aug 10, 2026
b98ebc4
Disable FM in presolve light mode
fwesselm Aug 10, 2026
cca4f83
Merge branch 'latest' of https://github.com/fwesselm/HiGHS into FMPre…
fwesselm Aug 10, 2026
bf3a382
Minor change; use size_t
fwesselm Aug 10, 2026
2bd1e5c
Fix usage of allow_rule_
fwesselm Aug 10, 2026
85e8a5f
Fix merge issue
fwesselm Aug 11, 2026
d939366
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Aug 11, 2026
cb5d1e1
Fix another merge issues
fwesselm Aug 11, 2026
a6b908c
Merge branch 'FMPresolve6' of https://github.com/fwesselm/HiGHS into …
fwesselm Aug 11, 2026
915b51d
Merge branch 'latest' of https://github.com/ERGO-Code/HiGHS into FMPr…
fwesselm Aug 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions check/TestCAPI.c
Original file line number Diff line number Diff line change
Expand Up @@ -726,17 +726,17 @@ void testNames() {
printf("Row %" HIGHSINT_FORMAT " has name %s\n", iRow, name);
}

// Check extraction of names for the presolved LP, in which the
// first row is removed
// Check extraction of names for the presolved LP
Highs_presolve(highs);
if (dev_run) Highs_writePresolvedModel(highs, "");

HighsInt presolved_num_col = Highs_getPresolvedNumCol(highs);
HighsInt presolved_num_row = Highs_getPresolvedNumRow(highs);
assert(presolved_num_col == num_col);
assert(presolved_num_row == num_row - 1);
// Fourier-Motzkin presolve reduction may add columns/rows
//assert(presolved_num_col == num_col);
//assert(presolved_num_row == num_row-1);

char presolved_name[5];
char presolved_name[512];

return_status = Highs_getPresolvedColName(highs, -1, presolved_name);
assert(return_status == kHighsStatusError);
Expand Down Expand Up @@ -1511,7 +1511,10 @@ void passPresolveGetLp() {
double* presolved_row_upper =
(double*)malloc(sizeof(double) * presolved_num_row);
HighsInt* presolved_a_start =
(HighsInt*)malloc(sizeof(HighsInt) * (presolved_num_col + 1));
(HighsInt*)malloc(sizeof(HighsInt) *
(presolved_a_format == kHighsMatrixFormatColwise
? presolved_num_col + 1
: presolved_num_row + 1));
HighsInt* presolved_a_index =
(HighsInt*)malloc(sizeof(HighsInt) * presolved_num_nz);
double* presolved_a_value =
Expand All @@ -1538,9 +1541,9 @@ void passPresolveGetLp() {
assert(return_status == kHighsStatusOk);
return_status = Highs_run(local_highs);

double* col_value = (double*)malloc(sizeof(double) * num_col);
double* col_dual = (double*)malloc(sizeof(double) * num_col);
double* row_dual = (double*)malloc(sizeof(double) * num_row);
double* col_value = (double*)malloc(sizeof(double) * presolved_num_col);
double* col_dual = (double*)malloc(sizeof(double) * presolved_num_col);
double* row_dual = (double*)malloc(sizeof(double) * presolved_num_row);

return_status =
Highs_getSolution(local_highs, col_value, col_dual, NULL, row_dual);
Expand Down
5 changes: 5 additions & 0 deletions check/TestPresolve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ TEST_CASE("postsolve-no-basis", "[highs_test_presolve]") {
"Col Primal Col Primal\n");
for (HighsInt iCol = 0; iCol < presolved_lp.num_col_; iCol++) {
HighsInt original_iCol = original_col_indices[iCol];
// Skip columns added by presolve (e.g. FME objective reformulation)
if (original_iCol >= highs.getNumCol()) continue;
if (dev_run)
printf("%3d %11.5g %3d %11.5g\n", int(iCol), solution.col_value[iCol],
int(original_iCol), postsolve_solution.col_value[original_iCol]);
Expand Down Expand Up @@ -136,11 +138,14 @@ TEST_CASE("presolve", "[highs_test_presolve]") {
// Have to set matrix dimensions to match presolved_model.lp_
lp.setMatrixDimensions();
highs.passModel(lp);
// Disable Fourier-Motzkin so this LP is not reduced
highs.setOptionValue("presolve_rule_off", 1 << kPresolveRuleFourierMotzkin);
REQUIRE(highs.presolve() == HighsStatus::kOk);
REQUIRE(lp.equalButForNames(presolved_model.lp_));
REQUIRE(highs.getModelPresolveStatus() == HighsPresolveStatus::kNotReduced);
REQUIRE(highs.getModelStatus() == HighsModelStatus::kNotset);
REQUIRE(!presolved_model.isEmpty());
highs.setOptionValue("presolve_rule_off", 0);

special_lps.primalDualInfeasible1Lp(lp, require_model_status);
highs.passModel(lp);
Expand Down
70 changes: 64 additions & 6 deletions check/TestPresolveRules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include "Highs.h"
#include "catch.hpp"

const bool dev_run = false;
const bool dev_run = true;

void presolveOffOn(const std::string& message, const HighsLp& lp, Highs& h,
const HighsInt require_presolved_model_num_col = 0,
Expand Down Expand Up @@ -79,6 +79,67 @@ TEST_CASE("test-col-stuffing", "[highs_test_presolve_rules]") {
h.resetGlobalScheduler(true);
}

TEST_CASE("test-fourier-motzkin", "[highs_test_presolve_rules]") {
Highs h;
h.setOptionValue("output_flag", dev_run);
h.setOptionValue("presolve_rule_test", kPresolveRuleFourierMotzkin);
h.setOptionValue("presolve_rule_logging", true);
Comment thread
Opt-Mucca marked this conversation as resolved.
h.setOptionValue("log_dev_level", 1);

const bool lp0 = true;
const bool lp1 = true; // Makes eliminations marginal, and leaves x2=0
const bool lp2 = true;

// From "A novel linear optimization presolve technique based on
// Fourier-Motzkin elimination", Zhang, Ploskas and Sahinidis,
// Mathematical Programming Computation (2026) 18:345–378
HighsLp lp;

lp.num_col_ = 4;
lp.num_row_ = 3;

lp.col_cost_.assign(lp.num_col_, 0);
lp.col_lower_.assign(lp.num_col_, 0);
lp.col_upper_.assign(lp.num_col_, kHighsInf);
lp.col_upper_[0] = 40.0;

lp.row_lower_.assign(lp.num_row_, -kHighsInf);
lp.row_upper_ = {-30, 50, 40};
lp.a_matrix_.format_ = MatrixFormat::kRowwise;
lp.a_matrix_.start_ = {0, 3, 6, 9};
lp.a_matrix_.index_ = {0, 1, 3, 1, 2, 3, 1, 2, 3};
lp.a_matrix_.value_ = {-1, 1, -1, 2, 1, 2, 3, -1, 3};

if (lp0) {
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
presolveOffOn("FM example from paper", lp, h);
}

lp.col_upper_[0] = 5.0;
lp.row_upper_ = {-30, 75, 50};

if (lp1) {
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
presolveOffOn("FM example from paper - tightened", lp, h);
}

lp.col_cost_ = {1, 2, 3, 4};

REQUIRE(h.passModel(lp) == HighsStatus::kOk);

if (lp2) {
HighsInt require_presolved_model_num_col = 1;
HighsInt require_presolved_model_num_row = 6;
HighsInt require_presolved_model_num_nz = 6;
presolveOffOn("FM example from paper - tightened and with costs", lp, h,
require_presolved_model_num_col,
require_presolved_model_num_row,
require_presolved_model_num_nz);
}

h.resetGlobalScheduler(true);
}

void presolveOffOn(const std::string& message, const HighsLp& lp, Highs& h,
const HighsInt require_presolved_model_num_col,
const HighsInt require_presolved_model_num_row,
Expand All @@ -89,7 +150,7 @@ void presolveOffOn(const std::string& message, const HighsLp& lp, Highs& h,
// solvers cannot be tested
const bool reduce_to_empty = require_presolved_model_num_col == 0 &&
require_presolved_model_num_row == 0;
const HighsInt to_k = reduce_to_empty ? 2 : 5;
const HighsInt to_k = reduce_to_empty ? 2 : 4;
for (int k = 0; k < to_k; k++) {
std::string solver = kSimplexString;
std::string run_crossover = kHighsOnString;
Expand All @@ -108,9 +169,6 @@ void presolveOffOn(const std::string& message, const HighsLp& lp, Highs& h,
solver = kIpmString;
run_crossover = kHighsOffString;
basis_postsolve = false;
} else {
solver = kHiPdlpString;
basis_postsolve = false;
}
}
std::string presolve = presolve_on ? kHighsOnString : kHighsOffString;
Expand Down Expand Up @@ -138,7 +196,7 @@ void presolveOffOn(const std::string& message, const HighsLp& lp, Highs& h,
REQUIRE(h.getModelStatus() == HighsModelStatus::kOptimal);
REQUIRE(h.getInfo().num_primal_infeasibilities == 0);
REQUIRE(h.getInfo().num_dual_infeasibilities == 0);
REQUIRE(h.getInfo().simplex_iteration_count == 0);
if (reduce_to_empty) REQUIRE(h.getInfo().simplex_iteration_count == 0);
// Ensure that any basis postsolve is correct
if (basis_postsolve)
REQUIRE(run_data.num_simplex_iterations_after_postsolve == 0);
Expand Down
3 changes: 3 additions & 0 deletions check/TestSemiVariables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,9 @@ TEST_CASE("3015", "[highs_test_semi_variables]") {
double optimal_objective_value = -1407973.679417;
Highs highs;
highs.setOptionValue("output_flag", dev_run);
// Disable Fourier-Motzkin presolve so that the semi-variable
// infeasibility is still triggered with default mip_feasibility_tolerance
highs.setOptionValue("presolve_rule_off", 1 << kPresolveRuleFourierMotzkin);
highs.readModel(filename);
HighsStatus status = highs.run();
REQUIRE(status == HighsStatus::kError);
Expand Down
4 changes: 2 additions & 2 deletions highs/Highs.h
Original file line number Diff line number Diff line change
Expand Up @@ -535,15 +535,15 @@ class Highs {
* the presolved model
*/
const HighsInt* getPresolveOrigColsIndex() const {
return presolve_.data_.postSolveStack.getOrigColsIndex();
return presolve_.data_.postSolveStack.getOrigColIndex().data();
}

/**
* @brief Return a const pointer to the original row indices for the
* presolved model
*/
const HighsInt* getPresolveOrigRowsIndex() const {
return presolve_.data_.postSolveStack.getOrigRowsIndex();
return presolve_.data_.postSolveStack.getOrigRowIndex().data();
}

/**
Expand Down
3 changes: 2 additions & 1 deletion highs/lp_data/HConst.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ enum PresolveRuleType : int {
kPresolveRuleDualFixing,
kPresolveRuleColStuffing,
kPresolveRuleInitialSweep,
kPresolveRuleMax = kPresolveRuleInitialSweep,
kPresolveRuleFourierMotzkin,
kPresolveRuleMax = kPresolveRuleFourierMotzkin,
kPresolveRuleLastAllowOff = kPresolveRuleMax,
kPresolveRuleCount
};
Expand Down
3 changes: 0 additions & 3 deletions highs/lp_data/HStruct.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ struct HighsSolution {
void clear();
void print(const std::string& prefix = "",
const std::string& message = "") const;
bool isModelRow(HighsInt row) const {
return static_cast<size_t>(row) < row_value.size();
}
};

struct HighsObjectiveSolution {
Expand Down
2 changes: 1 addition & 1 deletion highs/lp_data/Highs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4002,7 +4002,7 @@ HighsPostsolveStatus Highs::runPostsolve() {
const HighsInt report_3040_col = -21792;
presolve_.data_.postSolveStack.undo(
options_, presolve_.data_.recovered_solution_,
presolve_.data_.recovered_basis_, report_3040_col);
presolve_.data_.recovered_basis_, 0, report_3040_col);
// Compute the row activities
assert(model_.lp_.a_matrix_.isColwise());
calculateRowValuesQuad(model_.lp_, presolve_.data_.recovered_solution_);
Expand Down
1 change: 1 addition & 0 deletions highs/lp_data/HighsLp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ void HighsLp::clear() {
this->is_moved_ = false;
this->cost_row_location_ = -1;
this->has_infinite_cost_ = false;
this->fme_obj_col_ = -1;
this->mods_.clear();
}

Expand Down
1 change: 1 addition & 0 deletions highs/lp_data/HighsLp.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class HighsLp {
bool is_moved_;
HighsInt cost_row_location_;
bool has_infinite_cost_;
HighsInt fme_obj_col_ = -1;
HighsLpMods mods_;

bool operator==(const HighsLp& lp) const;
Expand Down
2 changes: 2 additions & 0 deletions highs/lp_data/HighsModelUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1521,6 +1521,8 @@ std::string utilPresolveRuleTypeToString(const HighsInt rule_type) {
return "Col stuffing";
} else if (rule_type == kPresolveRuleInitialSweep) {
return "Initial sweep";
} else if (rule_type == kPresolveRuleFourierMotzkin) {
return "Fourier-Motzkin";
}
assert(1 == 0);
return "????";
Expand Down
7 changes: 7 additions & 0 deletions highs/lp_data/HighsOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ struct HighsOptionsStruct {
HighsInt presolve_substitution_maxfillin;
HighsInt presolve_rule_off;
HighsInt presolve_rule_test;
HighsInt presolve_fm_level;
bool presolve_rule_logging;
bool presolve_remove_slacks;
bool no_unnecessary_rebuild_refactor;
Expand Down Expand Up @@ -636,6 +637,7 @@ struct HighsOptionsStruct {
presolve_substitution_maxfillin(0),
presolve_rule_off(0),
presolve_rule_test(0),
presolve_fm_level(0),
presolve_rule_logging(false),
presolve_remove_slacks(false),
no_unnecessary_rebuild_refactor(false),
Expand Down Expand Up @@ -1684,6 +1686,11 @@ class HighsOptions : public HighsOptionsStruct {
&presolve_rule_test, 0, 0, kPresolveRuleMax);
records.push_back(record_int);

record_int = new OptionRecordInt("presolve_fm_level",
"Fourier-Motzkin elimination level",
advanced, &presolve_fm_level, 0, 1, 1);
records.push_back(record_int);

record_bool = new OptionRecordBool(
"presolve_rule_logging", "Log effectiveness of presolve rules for LP",
advanced, &presolve_rule_logging, false);
Expand Down
7 changes: 4 additions & 3 deletions highs/mip/HighsCliqueTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1283,9 +1283,10 @@ void HighsCliqueTable::extractCliques(HighsMipSolver& mipsolver,
HighsInt start = mipsolver.mipdata_->ARstart_[i];
HighsInt end = mipsolver.mipdata_->ARstart_[i + 1];

if (mipsolver.mipdata_->postSolveStack.getOrigRowIndex(i) >=
mipsolver.orig_model_->num_row_)
break;
if (mipsolver.mipdata_->postSolveStack.isCutRow(i)) {
if (!mipsolver.mipdata_->postSolveStack.hasAppendedRows()) break;
continue;
}

// catch set packing and partitioning constraints that already have the form
// of a clique without transformations and add those cliques with the rows
Expand Down
14 changes: 9 additions & 5 deletions highs/mip/HighsCliqueTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,7 @@ class HighsCliqueTable {
int64_t numNeighbourhoodQueries;

HighsCliqueTable(HighsInt ncols) {
invertedHashList.resize(2 * static_cast<size_t>(ncols));
invertedHashListSizeTwo.resize(2 * static_cast<size_t>(ncols));
numcliquesvar.resize(2 * static_cast<size_t>(ncols), 0);
colsubstituted.resize(ncols);
colDeleted.resize(ncols, false);
resize(static_cast<size_t>(ncols));
nfixings = 0;
numNeighbourhoodQueries = 0;
numEntries = 0;
Expand All @@ -178,6 +174,14 @@ class HighsCliqueTable {
allowParallel = true;
}

void resize(size_t ncols) {
invertedHashList.resize(2 * ncols);
invertedHashListSizeTwo.resize(2 * ncols);
numcliquesvar.resize(2 * ncols, 0);
colsubstituted.resize(ncols);
colDeleted.resize(ncols, false);
}

void setPresolveFlag(bool inPresolve) { this->inPresolve = inPresolve; }

bool getPresolveFlag() const { return inPresolve; }
Expand Down
23 changes: 10 additions & 13 deletions highs/mip/HighsImplications.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,10 @@ class HighsImplications {
std::vector<HighsSubstitution> substitutions;
std::vector<HighsBool> colsubstituted;
HighsImplications(const HighsMipSolver& mipsolver) : mipsolver(mipsolver) {
HighsInt numcol = mipsolver.numCol();
implications.resize(2 * static_cast<size_t>(numcol));
colsubstituted.resize(numcol);
vubs.resize(numcol);
vlbs.resize(numcol);
nextCleanupCall = mipsolver.numNonzero();
numImplications = 0;
numVarBounds = 0;
maxVarBounds = calcMaxVarBounds(numcol);
resize(mipsolver.numCol());
}

std::function<void(HighsInt, HighsInt, HighsInt, double)>
Expand All @@ -78,22 +73,24 @@ class HighsImplications {
implications.clear();
implications.shrink_to_fit();

HighsInt numcol = mipsolver.numCol();
implications.resize(2 * static_cast<size_t>(numcol));
colsubstituted.resize(numcol);
numImplications = 0;
vubs.clear();
vubs.shrink_to_fit();
vubs.resize(numcol);
vlbs.clear();
vlbs.shrink_to_fit();
vlbs.resize(numcol);
resize(mipsolver.numCol());
numVarBounds = 0;
maxVarBounds = calcMaxVarBounds(numcol);

nextCleanupCall = mipsolver.numNonzero();
}

void resize(HighsInt ncols) {
implications.resize(2 * static_cast<size_t>(ncols));
colsubstituted.resize(ncols);
vubs.resize(ncols);
vlbs.resize(ncols);
maxVarBounds = calcMaxVarBounds(ncols);
}

constexpr static int64_t calcMaxVarBounds(HighsInt numcol) {
return int64_t{5000000} + 10 * static_cast<int64_t>(numcol);
};
Expand Down
Loading
Loading