Skip to content

Commit 771d015

Browse files
authored
Merge pull request #2636 from ERGO-Code/fix-2635
Fix 2635
2 parents bd96e11 + defb773 commit 771d015

File tree

3 files changed

+218
-38
lines changed

3 files changed

+218
-38
lines changed

check/TestCAPI.c

Lines changed: 125 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2238,6 +2238,107 @@ void testIis() {
22382238
}
22392239
}
22402240

2241+
// Re #2635 check with feasible LP
2242+
Highs_clearModel(highs);
2243+
2244+
ret = Highs_addCol(highs, 0.0, 0.0, inf, 0, NULL, NULL);
2245+
assert(ret == 0);
2246+
ret = Highs_addCol(highs, 0.0, 0.0, inf, 0, NULL, NULL);
2247+
assert(ret == 0);
2248+
index[0] = 0;
2249+
index[1] = 1;
2250+
value_1[0] = 1;
2251+
value_1[1] = 2;
2252+
value_2[0] = 1;
2253+
value_2[1] = 4;
2254+
ret = Highs_addRow(highs, -inf, 80, 2, index, value_1);
2255+
assert(ret == 0);
2256+
ret = Highs_addRow(highs, -inf, 120, 2, index, value_2);
2257+
assert(ret == 0);
2258+
2259+
ret = Highs_getLp(highs, kHighsMatrixFormatRowwise,
2260+
&num_col, &num_row, &num_nz,
2261+
&sense, &offset,
2262+
NULL, NULL, NULL,
2263+
NULL, NULL,
2264+
NULL, NULL, NULL,
2265+
NULL);
2266+
2267+
HighsInt* col_index = NULL;
2268+
HighsInt* row_index = NULL;
2269+
HighsInt* col_bound = NULL;
2270+
HighsInt* row_bound = NULL;
2271+
HighsInt* col_status = (HighsInt*)malloc(sizeof(HighsInt) * num_col);
2272+
HighsInt* row_status = (HighsInt*)malloc(sizeof(HighsInt) * num_row);
2273+
2274+
// First try with kIisStrategyLight
2275+
Highs_setIntOptionValue(highs, "iis_strategy", kHighsIisStrategyLight);
2276+
2277+
for (int k = 0 ; k < 2; k++) {
2278+
HighsInt iis_num_col;
2279+
HighsInt iis_num_row;
2280+
ret = Highs_getIis(highs,
2281+
&iis_num_col, &iis_num_row,
2282+
NULL, NULL,
2283+
NULL, NULL,
2284+
NULL, NULL);
2285+
assert(ret == 0);
2286+
2287+
assert(iis_num_col == 0);
2288+
assert(iis_num_row == 0);
2289+
ret = Highs_getIis(highs,
2290+
&iis_num_col, &iis_num_row,
2291+
col_index, row_index,
2292+
col_bound, row_bound,
2293+
col_status, row_status);
2294+
assert(ret == 0);
2295+
if (k == 0) {
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
2303+
assert(col_status[0] == kHighsIisStatusNotInConflict);
2304+
assert(col_status[1] == kHighsIisStatusNotInConflict);
2305+
assert(row_status[0] == kHighsIisStatusNotInConflict);
2306+
assert(row_status[1] == kHighsIisStatusNotInConflict);
2307+
}
2308+
Highs_run(highs);
2309+
}
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+
2339+
free(col_status);
2340+
free(row_status);
2341+
22412342
Highs_destroy(highs);
22422343
}
22432344

@@ -2351,30 +2452,30 @@ void testFixedLp() {
23512452
}
23522453

23532454
int main() {
2354-
minimalApiIllegalLp();
2355-
testCallback();
2356-
versionApi();
2357-
fullApi();
2358-
minimalApiLp();
2359-
minimalApiMip();
2360-
minimalApiQp();
2361-
fullApiOptions();
2362-
fullApiLp();
2363-
fullApiMip();
2364-
fullApiQp();
2365-
passPresolveGetLp();
2366-
options();
2367-
testGetColsByRange();
2368-
testPassHessian();
2369-
testRanging();
2370-
testFeasibilityRelaxation();
2371-
testGetModel();
2372-
testMultiObjective();
2373-
testQpIndefiniteFailure();
2374-
testDualRayTwice();
2375-
testDeleteRowResolveWithBasis();
2376-
testIis();
2377-
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();
23782479
return 0;
23792480
}
23802481
// 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: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,23 +1828,40 @@ HighsStatus Highs::getRangingInterface() {
18281828

18291829
HighsStatus Highs::getIisInterfaceReturn(const HighsStatus return_status) {
18301830
if (return_status != HighsStatus::kError) {
1831-
// Construct the ISS LP
1832-
this->iis_.getLp(this->model_.lp_);
1833-
// Check that the IIS LP data are OK (correspond to original model
1834-
// reduced to IIS col/row and bound data).
1835-
if (!this->iis_.lpDataOk(this->model_.lp_, this->options_))
1836-
return HighsStatus::kError;
1837-
// Check that the IIS LP is OK (infeasible and optimal/unbounded
1838-
// is any bound is relaxed)
1839-
if (!this->iis_.lpOk(this->options_)) return HighsStatus::kError;
1840-
// Construct the ISS status vectors for cols and rows of original
1841-
// model
1842-
this->iis_.getStatus(model_.lp_);
1831+
// A valid IIS is one for which the IIS information is known to be
1832+
// correct. In the case of a system that's feasible this will give
1833+
// empty HighsIis::col_index_ and HighsIis::col_index_.
1834+
HighsLp& lp = this->model_.lp_;
1835+
HighsLp& iis_lp = this->iis_.model_.lp_;
1836+
const bool has_iis =
1837+
this->iis_.col_index_.size() || this->iis_.row_index_.size();
1838+
if (has_iis) {
1839+
assert(this->iis_.valid_);
1840+
// Construct the ISS LP
1841+
this->iis_.getLp(lp);
1842+
// Check that the IIS LP data are OK (correspond to original model
1843+
// reduced to IIS col/row and bound data).
1844+
if (!this->iis_.lpDataOk(lp, this->options_)) return HighsStatus::kError;
1845+
// Check that the IIS LP is OK (infeasible and optimal/unbounded
1846+
// is any bound is relaxed)
1847+
if (!this->iis_.lpOk(this->options_)) return HighsStatus::kError;
1848+
// Construct the ISS status vectors for cols and rows of original
1849+
// model
1850+
this->iis_.getStatus(lp);
1851+
} else {
1852+
// No IIS, so check that the IIS LP is empty
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_));
1858+
}
18431859
}
18441860
return return_status;
18451861
}
18461862

18471863
HighsStatus Highs::getIisInterface() {
1864+
const HighsLp& lp = model_.lp_;
18481865
if (this->model_status_ == HighsModelStatus::kOptimal ||
18491866
this->model_status_ == HighsModelStatus::kUnbounded) {
18501867
// Strange to call getIis for a model that's known to be feasible
@@ -1854,6 +1871,8 @@ HighsStatus Highs::getIisInterface() {
18541871
this->iis_.invalidate();
18551872
// No IIS exists, so validate the empty HighsIis instance
18561873
this->iis_.valid_ = true;
1874+
this->iis_.col_status_.assign(lp.num_col_, kIisStatusNotInConflict);
1875+
this->iis_.row_status_.assign(lp.num_row_, kIisStatusNotInConflict);
18571876
return this->getIisInterfaceReturn(HighsStatus::kOk);
18581877
}
18591878
HighsStatus return_status = HighsStatus::kOk;
@@ -1866,7 +1885,6 @@ HighsStatus Highs::getIisInterface() {
18661885
}
18671886
if (this->iis_.valid_) return this->getIisInterfaceReturn(HighsStatus::kOk);
18681887
this->iis_.invalidate();
1869-
const HighsLp& lp = model_.lp_;
18701888
// Check for trivial IIS: empty infeasible row or inconsistent bounds
18711889
if (this->iis_.trivial(lp, options_)) {
18721890
this->model_status_ = HighsModelStatus::kInfeasible;
@@ -1887,8 +1905,11 @@ HighsStatus Highs::getIisInterface() {
18871905
}
18881906
// Don't continue with more expensive techniques if using the IIS
18891907
// light strategy
1890-
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);
18911911
return this->getIisInterfaceReturn(HighsStatus::kOk);
1912+
}
18921913
const bool ray_option = false;
18931914
// options_.iis_strategy == kIisStrategyFromRayRowPriority ||
18941915
// options_.iis_strategy == kIisStrategyFromRayColPriority;
@@ -1962,6 +1983,8 @@ HighsStatus Highs::getIisInterface() {
19621983
if (infeasible_row_subset.size() == 0) {
19631984
// No subset of infeasible rows, so model is feasible
19641985
this->iis_.valid_ = true;
1986+
this->iis_.col_status_.assign(lp.num_col_, kIisStatusNotInConflict);
1987+
this->iis_.row_status_.assign(lp.num_row_, kIisStatusNotInConflict);
19651988
} else {
19661989
return_status =
19671990
this->iis_.getData(lp, options_, basis_, infeasible_row_subset);

0 commit comments

Comments
 (0)