Skip to content

Commit 7fb7a11

Browse files
committed
Fixed 2635, with new unit test in testIis.cpp and TestCAPI.c
1 parent 211253d commit 7fb7a11

File tree

3 files changed

+141
-44
lines changed

3 files changed

+141
-44
lines changed

check/TestCAPI.c

Lines changed: 66 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2239,8 +2239,7 @@ void testIis() {
22392239
}
22402240

22412241
// Re #2635 check with feasible LP
2242-
/*
2243-
Highs_clear(highs);
2242+
Highs_clearModel(highs);
22442243

22452244
ret = Highs_addCol(highs, 0.0, 0.0, inf, 0, NULL, NULL);
22462245
assert(ret == 0);
@@ -2272,6 +2271,9 @@ void testIis() {
22722271
HighsInt* col_status = (HighsInt*)malloc(sizeof(HighsInt) * num_col);
22732272
HighsInt* row_status = (HighsInt*)malloc(sizeof(HighsInt) * num_row);
22742273

2274+
// First try with kIisStrategyLight
2275+
Highs_setIntOptionValue(highs, "iis_strategy", kHighsIisStrategyLight);
2276+
22752277
for (int k = 0 ; k < 2; k++) {
22762278
HighsInt iis_num_col;
22772279
HighsInt iis_num_row;
@@ -2289,25 +2291,53 @@ void testIis() {
22892291
col_index, row_index,
22902292
col_bound, row_bound,
22912293
col_status, row_status);
2294+
assert(ret == 0);
22922295
if (k == 0) {
2293-
assert(ret == 0);
2294-
2296+
// Before running HiGHS, model status is unknown
2297+
assert(col_status[0] == kHighsIisStatusMaybeInConflict);
2298+
assert(col_status[1] == kHighsIisStatusMaybeInConflict);
2299+
assert(row_status[0] == kHighsIisStatusMaybeInConflict);
2300+
assert(row_status[1] == kHighsIisStatusMaybeInConflict);
2301+
} else {
2302+
// After running HiGHS, model status is known to be optimal
22952303
assert(col_status[0] == kHighsIisStatusNotInConflict);
22962304
assert(col_status[1] == kHighsIisStatusNotInConflict);
2297-
22982305
assert(row_status[0] == kHighsIisStatusNotInConflict);
22992306
assert(row_status[1] == kHighsIisStatusNotInConflict);
2300-
} else {
2301-
assert(ret == -1);
23022307
}
2308+
Highs_run(highs);
23032309
}
2304-
free(col_index);
2305-
free(row_index);
2306-
free(col_bound);
2307-
free(row_bound);
2310+
2311+
// Now try with kHighsIisStrategyFromLpRowPriority
2312+
Highs_clearSolver(highs);
2313+
Highs_setIntOptionValue(highs, "iis_strategy",
2314+
kHighsIisStrategyFromLpRowPriority);
2315+
HighsInt iis_num_col;
2316+
HighsInt iis_num_row;
2317+
ret = Highs_getIis(highs,
2318+
&iis_num_col, &iis_num_row,
2319+
NULL, NULL,
2320+
NULL, NULL,
2321+
NULL, NULL);
2322+
assert(ret == 0);
2323+
2324+
assert(iis_num_col == 0);
2325+
assert(iis_num_row == 0);
2326+
ret = Highs_getIis(highs,
2327+
&iis_num_col, &iis_num_row,
2328+
col_index, row_index,
2329+
col_bound, row_bound,
2330+
col_status, row_status);
2331+
assert(ret == 0);
2332+
// With kHighsIisStrategyFromLpRowPriority, model status is found to
2333+
// be feasible
2334+
assert(col_status[0] == kHighsIisStatusNotInConflict);
2335+
assert(col_status[1] == kHighsIisStatusNotInConflict);
2336+
assert(row_status[0] == kHighsIisStatusNotInConflict);
2337+
assert(row_status[1] == kHighsIisStatusNotInConflict);
2338+
23082339
free(col_status);
23092340
free(row_status);
2310-
*/
23112341

23122342
Highs_destroy(highs);
23132343
}
@@ -2422,30 +2452,30 @@ void testFixedLp() {
24222452
}
24232453

24242454
int main() {
2425-
// minimalApiIllegalLp();
2426-
// testCallback();
2427-
// versionApi();
2428-
// fullApi();
2429-
// minimalApiLp();
2430-
// minimalApiMip();
2431-
// minimalApiQp();
2432-
// fullApiOptions();
2433-
// fullApiLp();
2434-
// fullApiMip();
2435-
// fullApiQp();
2436-
// passPresolveGetLp();
2437-
// options();
2438-
// testGetColsByRange();
2439-
// testPassHessian();
2440-
// testRanging();
2441-
// testFeasibilityRelaxation();
2442-
// testGetModel();
2443-
// testMultiObjective();
2444-
// testQpIndefiniteFailure();
2445-
// testDualRayTwice();
2446-
// testDeleteRowResolveWithBasis();
2447-
testIis();
2448-
// testFixedLp();
2455+
minimalApiIllegalLp();
2456+
testCallback();
2457+
versionApi();
2458+
fullApi();
2459+
minimalApiLp();
2460+
minimalApiMip();
2461+
minimalApiQp();
2462+
fullApiOptions();
2463+
fullApiLp();
2464+
fullApiMip();
2465+
fullApiQp();
2466+
passPresolveGetLp();
2467+
options();
2468+
testGetColsByRange();
2469+
testPassHessian();
2470+
testRanging();
2471+
testFeasibilityRelaxation();
2472+
testGetModel();
2473+
testMultiObjective();
2474+
testQpIndefiniteFailure();
2475+
testDualRayTwice();
2476+
testDeleteRowResolveWithBasis();
2477+
testIis();
2478+
testFixedLp();
24492479
return 0;
24502480
}
24512481
// testSetSolution();

check/TestIis.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,3 +442,59 @@ void testFeasibilityRelaxation(
442442
REQUIRE(h.getInfo().objective_function_value ==
443443
require_feasibility_objective_function_value);
444444
}
445+
446+
TEST_CASE("feasible-lp-iis", "[iis]") {
447+
HighsLp lp;
448+
lp.model_name_ = "chip";
449+
lp.sense_ = ObjSense::kMaximize;
450+
lp.num_col_ = 2;
451+
lp.num_row_ = 2;
452+
lp.col_cost_ = {10, 25};
453+
lp.col_lower_ = {0, 0};
454+
lp.col_upper_ = {inf, inf};
455+
lp.col_names_ = {"Tables", "SetsOfChairs"};
456+
lp.row_lower_ = {-inf, -inf};
457+
lp.row_upper_ = {80, 120};
458+
lp.row_names_ = {"Assembly", "Finishng"};
459+
lp.a_matrix_.start_ = {0, 2, 4};
460+
lp.a_matrix_.index_ = {0, 1, 0, 1};
461+
lp.a_matrix_.value_ = {1, 1, 2, 4};
462+
Highs h;
463+
h.setOptionValue("output_flag", dev_run);
464+
h.passModel(lp);
465+
HighsIis iis;
466+
// With kIisStrategyLight, feasibility of the LP is not determined
467+
// until it's been solved
468+
h.getIis(iis);
469+
REQUIRE(iis.col_index_.size() == 0);
470+
REQUIRE(iis.row_index_.size() == 0);
471+
REQUIRE(iis.col_status_[0] == kIisStatusMaybeInConflict);
472+
REQUIRE(iis.col_status_[1] == kIisStatusMaybeInConflict);
473+
REQUIRE(iis.row_status_[0] == kIisStatusMaybeInConflict);
474+
REQUIRE(iis.row_status_[1] == kIisStatusMaybeInConflict);
475+
476+
h.run();
477+
478+
h.getIis(iis);
479+
REQUIRE(iis.col_index_.size() == 0);
480+
REQUIRE(iis.row_index_.size() == 0);
481+
REQUIRE(iis.col_status_[0] == kIisStatusNotInConflict);
482+
REQUIRE(iis.col_status_[1] == kIisStatusNotInConflict);
483+
REQUIRE(iis.row_status_[0] == kIisStatusNotInConflict);
484+
REQUIRE(iis.row_status_[1] == kIisStatusNotInConflict);
485+
486+
h.passModel(lp);
487+
// With kIisStrategyFromLpRowPriority, feasibility of the LP is
488+
// determined
489+
h.setOptionValue("iis_strategy", kIisStrategyFromLpRowPriority);
490+
491+
h.getIis(iis);
492+
REQUIRE(iis.col_index_.size() == 0);
493+
REQUIRE(iis.row_index_.size() == 0);
494+
REQUIRE(iis.col_status_[0] == kIisStatusNotInConflict);
495+
REQUIRE(iis.col_status_[1] == kIisStatusNotInConflict);
496+
REQUIRE(iis.row_status_[0] == kIisStatusNotInConflict);
497+
REQUIRE(iis.row_status_[1] == kIisStatusNotInConflict);
498+
499+
h.resetGlobalScheduler(true);
500+
}

highs/lp_data/HighsInterface.cpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1831,32 +1831,37 @@ HighsStatus Highs::getIisInterfaceReturn(const HighsStatus return_status) {
18311831
// A valid IIS is one for which the IIS information is known to be
18321832
// correct. In the case of a system that's feasible this will give
18331833
// empty HighsIis::col_index_ and HighsIis::col_index_.
1834+
HighsLp& lp = this->model_.lp_;
1835+
HighsLp& iis_lp = this->iis_.model_.lp_;
18341836
const bool has_iis =
18351837
this->iis_.col_index_.size() || this->iis_.row_index_.size();
18361838
if (has_iis) {
18371839
assert(this->iis_.valid_);
18381840
// Construct the ISS LP
1839-
this->iis_.getLp(this->model_.lp_);
1841+
this->iis_.getLp(lp);
18401842
// Check that the IIS LP data are OK (correspond to original model
18411843
// reduced to IIS col/row and bound data).
1842-
if (!this->iis_.lpDataOk(this->model_.lp_, this->options_))
1843-
return HighsStatus::kError;
1844+
if (!this->iis_.lpDataOk(lp, this->options_)) return HighsStatus::kError;
18441845
// Check that the IIS LP is OK (infeasible and optimal/unbounded
18451846
// is any bound is relaxed)
18461847
if (!this->iis_.lpOk(this->options_)) return HighsStatus::kError;
18471848
// Construct the ISS status vectors for cols and rows of original
18481849
// model
1849-
this->iis_.getStatus(model_.lp_);
1850+
this->iis_.getStatus(lp);
18501851
} else {
18511852
// No IIS, so check that the IIS LP is empty
1852-
assert(this->iis_.model_.lp_.num_col_ == 0);
1853-
assert(this->iis_.model_.lp_.num_row_ == 0);
1853+
assert(iis_lp.num_col_ == 0);
1854+
assert(iis_lp.num_row_ == 0);
1855+
// Make sure that col_status_ and row_status_ have been assigned
1856+
assert(this->iis_.col_status_.size() == static_cast<size_t>(lp.num_col_));
1857+
assert(this->iis_.row_status_.size() == static_cast<size_t>(lp.num_row_));
18541858
}
18551859
}
18561860
return return_status;
18571861
}
18581862

18591863
HighsStatus Highs::getIisInterface() {
1864+
const HighsLp& lp = model_.lp_;
18601865
if (this->model_status_ == HighsModelStatus::kOptimal ||
18611866
this->model_status_ == HighsModelStatus::kUnbounded) {
18621867
// Strange to call getIis for a model that's known to be feasible
@@ -1866,6 +1871,8 @@ HighsStatus Highs::getIisInterface() {
18661871
this->iis_.invalidate();
18671872
// No IIS exists, so validate the empty HighsIis instance
18681873
this->iis_.valid_ = true;
1874+
this->iis_.col_status_.assign(lp.num_col_, kIisStatusNotInConflict);
1875+
this->iis_.row_status_.assign(lp.num_row_, kIisStatusNotInConflict);
18691876
return this->getIisInterfaceReturn(HighsStatus::kOk);
18701877
}
18711878
HighsStatus return_status = HighsStatus::kOk;
@@ -1878,7 +1885,6 @@ HighsStatus Highs::getIisInterface() {
18781885
}
18791886
if (this->iis_.valid_) return this->getIisInterfaceReturn(HighsStatus::kOk);
18801887
this->iis_.invalidate();
1881-
const HighsLp& lp = model_.lp_;
18821888
// Check for trivial IIS: empty infeasible row or inconsistent bounds
18831889
if (this->iis_.trivial(lp, options_)) {
18841890
this->model_status_ = HighsModelStatus::kInfeasible;
@@ -1899,8 +1905,11 @@ HighsStatus Highs::getIisInterface() {
18991905
}
19001906
// Don't continue with more expensive techniques if using the IIS
19011907
// light strategy
1902-
if (options_.iis_strategy == kIisStrategyLight)
1908+
if (options_.iis_strategy == kIisStrategyLight) {
1909+
this->iis_.col_status_.assign(lp.num_col_, kIisStatusMaybeInConflict);
1910+
this->iis_.row_status_.assign(lp.num_row_, kIisStatusMaybeInConflict);
19031911
return this->getIisInterfaceReturn(HighsStatus::kOk);
1912+
}
19041913
const bool ray_option = false;
19051914
// options_.iis_strategy == kIisStrategyFromRayRowPriority ||
19061915
// options_.iis_strategy == kIisStrategyFromRayColPriority;
@@ -1974,6 +1983,8 @@ HighsStatus Highs::getIisInterface() {
19741983
if (infeasible_row_subset.size() == 0) {
19751984
// No subset of infeasible rows, so model is feasible
19761985
this->iis_.valid_ = true;
1986+
this->iis_.col_status_.assign(lp.num_col_, kIisStatusNotInConflict);
1987+
this->iis_.row_status_.assign(lp.num_row_, kIisStatusNotInConflict);
19771988
} else {
19781989
return_status =
19791990
this->iis_.getData(lp, options_, basis_, infeasible_row_subset);

0 commit comments

Comments
 (0)