Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
9ed99dd
Created Highs::getIisLp and testing in lp-incompatible-bounds
jajhall Jul 4, 2025
cf3d5e9
lp-incompatible-bounds passes
jajhall Jul 4, 2025
a84beb7
Switching to markov
jajhall Jul 4, 2025
9fda01e
Now setting just the bounds given by col/row_bounds in the IIS; formated
jajhall Jul 4, 2025
b7fe821
lp-empty-infeasible-row passes
jajhall Jul 4, 2025
f287093
All IIS unit tests pass for IIS LP
jajhall Jul 5, 2025
81fcd9d
Need to be able to generate the IIS LP internally for checking IIS
jajhall Jul 6, 2025
eab8b22
Form IIS LP with IIS, and hold it as a member of HighsIis
jajhall Jul 6, 2025
df6321b
Added HighsLp member to HighsIis as IIS LP, and eliminated Highs::get…
jajhall Jul 6, 2025
ab329a0
Cleaned up and updated FEATURES.md
jajhall Jul 6, 2025
d175741
Added IisStrategy and IisStatus enums contents to highs_c_api.h
jajhall Jul 7, 2025
dda695d
Added variable/constraint IIS status
jajhall Jul 7, 2025
5babefd
Commented out code for HighsIisStatus in highs_bindings.cpp: leave it…
jajhall Jul 7, 2025
37fb045
ctest passes
jajhall Jul 9, 2025
a23df45
ctest passes silently
jajhall Jul 9, 2025
2d0bb19
Created C API methods for IIS
jajhall Jul 9, 2025
4c1099f
C API compiles
jajhall Jul 9, 2025
d04c148
Need to have HighsIis::getLp working for row-wise incumbent LP
jajhall Jul 9, 2025
d6b8feb
Test C API exploses IIS creation bug
jajhall Jul 9, 2025
1aafc1b
Added 3-variable 2-constraint IIS test to TestCAPI.c; formatted
jajhall Jul 10, 2025
9b702ca
Merged latest into this branch and fixed minor conflicts
jajhall Aug 6, 2025
c6a70c5
Added to FEATURES.md, and corrected IIS docstring in Highs.h
jajhall Aug 6, 2025
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
4 changes: 3 additions & 1 deletion FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ Forcing column reduction now checks the bound on the column dual rather than whe

Now handling correctly the case where an infeasible MIP has a feasible relaxation, so no ray is computed fixing [#2415](https://github.com/ERGO-Code/HiGHS/issues/2415)

Fixed minor bug exposed by [#2441](https://github.com/ERGO-Code/HiGHS/issues/2441) in Highs::setSolution() for a sparse user solution when the moidel is empty, and only clearing the dual data before solving with modified objective in Highs::multiobjectiveSolve() so that user-supplied solution is not cleared.
Fixed minor bug exposed by [#2441](https://github.com/ERGO-Code/HiGHS/issues/2441) in `Highs::setSolution()` for a sparse user solution when the moidel is empty, and only clearing the dual data before solving with modified objective in `Highs::multiobjectiveSolve()` so that user-supplied solution is not cleared.

The irreducible infeasibility system (IIS) facility now detects infeasibility due to bounds on constraint activity values (implied by variable bounds) being incompatible with constraint bounds. A `kIisStrategyLight mode` for the `iis_strategy` option has been introduced so that only infeasibility due to incompatible variable/constraint bounds and constraint activity values is checked for. The LP corresponding to any known IIS is now formed and held as a data member of the `HighsIis` class. It can be obtained as a const reference using `Highs::getIisLp()`, and written to a file using `Highs::writeIisModel(const std::string& filename = "")`

Prompted by [#2463](https://github.com/ERGO-Code/HiGHS/issues/2463), the HiGHS solution and basis files now match data to any column and row names in the model, only assuming that the data are aligned with column and row indices if there are no names in the model. This requires a new version (v2) of the HiGHS basis file. Basis files from v1 are still read, but deprecated. Now, when writing out a model, basis or solution, column and row names are added to the model - previously they were created temporarily and inconsistentyly on the fly. If the model has existing names, then distinctive names are created to replace any blank names, but names with spaces or duplicate names yield an error status return.
Copy link
Collaborator

@BenChampion BenChampion Aug 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happened to notice a typo here: inconsistentyly

EDIT: sorry, did not see you already merged this


181 changes: 148 additions & 33 deletions check/TestCAPI.c
Original file line number Diff line number Diff line change
Expand Up @@ -1989,7 +1989,7 @@ void testDualRayTwice() {
void* highs = Highs_create();
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
int ret;
double INF = Highs_getInfinity(highs);
double inf = Highs_getInfinity(highs);
ret = Highs_changeObjectiveOffset(highs, 0.0);
assert(ret == 0);
ret = Highs_setStringOptionValue(highs, "presolve", "off");
Expand All @@ -1998,9 +1998,9 @@ void testDualRayTwice() {
assert(ret == 0);
ret = Highs_addCol(highs, 0.0, 0.0, 0.0, 0, NULL, NULL);
assert(ret == 0);
ret = Highs_addCol(highs, -1.0, 0.0, INF, 0, NULL, NULL);
ret = Highs_addCol(highs, -1.0, 0.0, inf, 0, NULL, NULL);
assert(ret == 0);
ret = Highs_addCol(highs, -1.0, 0.0, INF, 0, NULL, NULL);
ret = Highs_addCol(highs, -1.0, 0.0, inf, 0, NULL, NULL);
assert(ret == 0);
HighsInt index[2] = {2, 3};
double value[2] = {1.0, -1.0};
Expand All @@ -2010,19 +2010,19 @@ void testDualRayTwice() {
index[1] = 3;
value[0] = 1.0;
value[1] = 1.0;
ret = Highs_addRow(highs, 1.0, INF, 2, index, value);
ret = Highs_addRow(highs, 1.0, inf, 2, index, value);
assert(ret == 0);
index[0] = 0;
index[1] = 2;
value[0] = -2.0;
value[1] = 1.0;
ret = Highs_addRow(highs, -INF, 0.0, 2, index, value);
ret = Highs_addRow(highs, -inf, 0.0, 2, index, value);
assert(ret == 0);
index[0] = 1;
index[1] = 3;
value[0] = -3.0;
value[1] = 1.0;
ret = Highs_addRow(highs, -INF, 0.0, 2, index, value);
ret = Highs_addRow(highs, -inf, 0.0, 2, index, value);
assert(ret == 0);
ret = Highs_run(highs);
assert(ret == 0);
Expand Down Expand Up @@ -2103,16 +2103,16 @@ void testDeleteRowResolveWithBasis() {
void* highs = Highs_create();
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
HighsInt ret;
double INF = Highs_getInfinity(highs);
double inf = Highs_getInfinity(highs);
ret = Highs_addCol(highs, 0.0, 2.0, 2.0, 0, NULL, NULL);
ret = Highs_addCol(highs, 0.0, -INF, INF, 0, NULL, NULL);
ret = Highs_addCol(highs, 0.0, -INF, INF, 0, NULL, NULL);
ret = Highs_addCol(highs, 0.0, -inf, inf, 0, NULL, NULL);
ret = Highs_addCol(highs, 0.0, -inf, inf, 0, NULL, NULL);
HighsInt index_1[2] = {0, 2};
double value_1[2] = {2.0, -1.0};
ret = Highs_addRow(highs, 0.0, 0.0, 2, index_1, value_1);
HighsInt index_2[1] = {1};
double value_2[1] = {6.0};
ret = Highs_addRow(highs, 10.0, INF, 1, index_2, value_2);
ret = Highs_addRow(highs, 10.0, inf, 1, index_2, value_2);
Highs_run(highs);
double col_value[3] = {0.0, 0.0, 0.0};
Highs_getSolution(highs, col_value, NULL, NULL, NULL);
Expand All @@ -2127,30 +2127,145 @@ void testDeleteRowResolveWithBasis() {
Highs_destroy(highs);
}

void testIis() {
void* highs = Highs_create();
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
HighsInt ret;
double inf = Highs_getInfinity(highs);
// For the constraints
//
// x + y - z = 2
//
// x + y + z <= 5
//
// x + 2y + z <= 1
//
// with variables in [0, 1], constraints 0 and 2 form an IIS with
//
// x free (so should be removed?); 0 <= y; 0 <= z
//
// x + y - z >= 2; x + 2y + z <= 1
//
ret = Highs_addCol(highs, 0.0, 0.0, 1.0, 0, NULL, NULL);
assert(ret == 0);
ret = Highs_addCol(highs, 0.0, 0.0, 1.0, 0, NULL, NULL);
assert(ret == 0);
ret = Highs_addCol(highs, 0.0, 0.0, 1.0, 0, NULL, NULL);
assert(ret == 0);
HighsInt index[3] = {0, 1, 2};
double value_1[3] = {1, 1, -1};
double value_2[3] = {1, 1, 1};
double value_3[3] = {1, 2, 1};
ret = Highs_addRow(highs, 2.0, 2.0, 3, index, value_1);
assert(ret == 0);
ret = Highs_addRow(highs, -inf, 5.0, 3, index, value_2);
assert(ret == 0);
ret = Highs_addRow(highs, -inf, 1.0, 3, index, value_3);
assert(ret == 0);

HighsInt num_col;
HighsInt num_row;
HighsInt num_nz;
HighsInt sense;
double offset;
ret = Highs_getLp(highs, kHighsMatrixFormatRowwise,
&num_col, &num_row, &num_nz,
&sense, &offset,
NULL, NULL, NULL,
NULL, NULL,
NULL, NULL, NULL,
NULL);

for (int k = 0 ; k < 2; k++) {
HighsInt iis_num_col;
HighsInt iis_num_row;
ret = Highs_getIis(highs,
&iis_num_col, &iis_num_row,
NULL, NULL,
NULL, NULL,
NULL, NULL);
assert(ret == 0);

if (k == 0) {
// No IIS from kHighsIisStrategyLight
assert(iis_num_col == 0);
assert(iis_num_row == 0);
Highs_setIntOptionValue(highs, "iis_strategy",
kHighsIisStrategyFromLpRowPriority);
} else {
assert(iis_num_col == 3);
assert(iis_num_row == 2);
HighsInt* col_index = (HighsInt*)malloc(sizeof(HighsInt) * iis_num_col);
HighsInt* row_index = (HighsInt*)malloc(sizeof(HighsInt) * iis_num_row);
HighsInt* col_bound = (HighsInt*)malloc(sizeof(HighsInt) * iis_num_col);
HighsInt* row_bound = (HighsInt*)malloc(sizeof(HighsInt) * iis_num_row);
HighsInt* col_status = (HighsInt*)malloc(sizeof(HighsInt) * num_col);
HighsInt* row_status = (HighsInt*)malloc(sizeof(HighsInt) * num_row);
ret = Highs_getIis(highs,
&iis_num_col, &iis_num_row,
col_index, row_index,
col_bound, row_bound,
col_status, row_status);
assert(ret == 0);

assert(col_index[0] == 0);
assert(col_index[1] == 1);
assert(col_index[2] == 2);

assert(row_index[0] == 0);
assert(row_index[1] == 2);

assert(col_bound[0] == kHighsIisBoundFree);
assert(col_bound[1] == kHighsIisBoundLower);
assert(col_bound[2] == kHighsIisBoundLower);

assert(row_bound[0] == kHighsIisBoundLower);
assert(row_bound[1] == kHighsIisBoundUpper);

assert(col_status[0] == kHighsIisStatusInConflict);
assert(col_status[1] == kHighsIisStatusInConflict);
assert(col_status[2] == kHighsIisStatusInConflict);

assert(row_status[0] == kHighsIisStatusInConflict);
assert(row_status[1] == kHighsIisStatusNotInConflict);
assert(row_status[2] == kHighsIisStatusInConflict);

free(col_index);
free(row_index);
free(col_bound);
free(row_bound);
free(col_status);
free(row_status);
}
}

Highs_destroy(highs);
}

int main() {
minimalApiIllegalLp();
testCallback();
versionApi();
fullApi();
minimalApiLp();
minimalApiMip();
minimalApiQp();
fullApiOptions();
fullApiLp();
fullApiMip();
fullApiQp();
passPresolveGetLp();
options();
testGetColsByRange();
testPassHessian();
testRanging();
testFeasibilityRelaxation();
testGetModel();
testMultiObjective();
testQpIndefiniteFailure();
testDualRayTwice();

testDeleteRowResolveWithBasis();
minimalApiIllegalLp();
testCallback();
versionApi();
fullApi();
minimalApiLp();
minimalApiMip();
minimalApiQp();
fullApiOptions();
fullApiLp();
fullApiMip();
fullApiQp();
passPresolveGetLp();
options();
testGetColsByRange();
testPassHessian();
testRanging();
testFeasibilityRelaxation();
testGetModel();
testMultiObjective();
testQpIndefiniteFailure();
testDualRayTwice();
testDeleteRowResolveWithBasis();
testIis();
return 0;
}
// testSetSolution();
Loading
Loading