Skip to content

Commit 34f0899

Browse files
committed
Now deducing IS data after elasticity filter, when kIisStrategyIrreducible not set. Added unit tests that are failing
1 parent b1ffe17 commit 34f0899

File tree

6 files changed

+283
-148
lines changed

6 files changed

+283
-148
lines changed

check/TestIis.cpp

Lines changed: 79 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ const bool write_model = false;
1010

1111
const double inf = kHighsInf;
1212

13-
const HighsInt kIisStrategyFromRayRowPriority = kIisStrategyFromRay;
14-
const HighsInt kIisStrategyFromRayColPriority = kIisStrategyFromRay + kIisStrategyColPriority;
15-
const HighsInt kIisStrategyFromLpRowPriority = kIisStrategyFromLp;
16-
const HighsInt kIisStrategyFromLpColPriority = kIisStrategyFromLp + kIisStrategyColPriority;
13+
const HighsInt kIisStrategyFromRayColPriority =
14+
kIisStrategyFromRay + kIisStrategyColPriority;
15+
const HighsInt kIisStrategyFromLpColPriority =
16+
kIisStrategyFromLp + kIisStrategyColPriority;
1717

1818
void testMps(std::string& model, const HighsInt iis_strategy,
1919
const HighsModelStatus require_model_status =
@@ -58,7 +58,7 @@ TEST_CASE("lp-incompatible-bounds", "[iis]") {
5858
REQUIRE(highs.run() == HighsStatus::kOk);
5959
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
6060

61-
highs.setOptionValue("iis_strategy", kIisStrategyFromLpRowPriority);
61+
highs.setOptionValue("iis_strategy", kIisStrategyFromLp);
6262
REQUIRE(highs.getIis(iis) == HighsStatus::kOk);
6363
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
6464
REQUIRE(iis.valid_ == true);
@@ -100,13 +100,15 @@ TEST_CASE("lp-incompatible-bounds", "[iis]") {
100100
// that just one of each (the first encountered) is found
101101
lp.col_upper_[0] = -1;
102102
lp.row_upper_[1] = -1;
103-
const bool two_inconsistent_rows = lp.row_upper_[0] < lp.row_lower_[0] && lp.row_upper_[1] < lp.row_lower_[1];
104-
const bool two_inconsistent_cols = lp.col_upper_[0] < lp.col_lower_[0] && lp.col_upper_[2] < lp.col_lower_[2];
103+
const bool two_inconsistent_rows = lp.row_upper_[0] < lp.row_lower_[0] &&
104+
lp.row_upper_[1] < lp.row_lower_[1];
105+
const bool two_inconsistent_cols = lp.col_upper_[0] < lp.col_lower_[0] &&
106+
lp.col_upper_[2] < lp.col_lower_[2];
105107
REQUIRE(two_inconsistent_cols);
106108
REQUIRE(two_inconsistent_rows);
107-
109+
108110
highs.passModel(lp);
109-
highs.setOptionValue("iis_strategy", kIisStrategyFromLpRowPriority);
111+
highs.setOptionValue("iis_strategy", kIisStrategyFromLp);
110112
REQUIRE(highs.getIis(iis) == HighsStatus::kOk);
111113
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
112114
REQUIRE(iis.valid_ == true);
@@ -243,7 +245,7 @@ TEST_CASE("lp-get-iis-light", "[iis]") {
243245
//
244246
// -10 <= 4w - 2x + y + 2z <= 15
245247
//
246-
// -34 <= - 2x -1.5y - z
248+
// -34 <= - 2x -1.5y - z
247249
//
248250
Highs highs;
249251
highs.setOptionValue("output_flag", dev_run);
@@ -259,26 +261,28 @@ TEST_CASE("lp-get-iis-light", "[iis]") {
259261
REQUIRE(iis.row_index_.size() == 1);
260262
HighsInt iis_row = iis.row_index_[0];
261263
if (lp.a_matrix_.isColwise()) {
262-
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
263-
for (HighsInt iEl = lp.a_matrix_.start_[iCol]; iEl < lp.a_matrix_.start_[iCol+1]; iEl++) {
264-
if (lp.a_matrix_.index_[iEl] == iis_row) {
265-
REQUIRE(iis.col_status_[iCol] == kIisStatusInConflict);
266-
break;
267-
}
268-
}
269-
}
264+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
265+
for (HighsInt iEl = lp.a_matrix_.start_[iCol];
266+
iEl < lp.a_matrix_.start_[iCol + 1]; iEl++) {
267+
if (lp.a_matrix_.index_[iEl] == iis_row) {
268+
REQUIRE(iis.col_status_[iCol] == kIisStatusInConflict);
269+
break;
270+
}
271+
}
272+
}
270273
} else {
271-
for (HighsInt iEl = lp.a_matrix_.start_[iis_row]; iEl < lp.a_matrix_.start_[iis_row+1]; iEl++) {
272-
HighsInt iCol = lp.a_matrix_.index_[iEl];
273-
REQUIRE(iis.col_status_[iCol] == kIisStatusInConflict);
274-
}
274+
for (HighsInt iEl = lp.a_matrix_.start_[iis_row];
275+
iEl < lp.a_matrix_.start_[iis_row + 1]; iEl++) {
276+
HighsInt iCol = lp.a_matrix_.index_[iEl];
277+
REQUIRE(iis.col_status_[iCol] == kIisStatusInConflict);
278+
}
275279
}
276280
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
277-
if (iRow == iis.row_index_[0]) {
278-
REQUIRE(iis.row_status_[iRow] == kIisStatusInConflict);
279-
} else {
280-
REQUIRE(iis.row_status_[iRow] == kIisStatusNotInConflict);
281-
}
281+
if (iRow == iis.row_index_[0]) {
282+
REQUIRE(iis.row_status_[iRow] == kIisStatusInConflict);
283+
} else {
284+
REQUIRE(iis.row_status_[iRow] == kIisStatusNotInConflict);
285+
}
282286
}
283287
if (dev_run && write_model) {
284288
highs.writeModel("");
@@ -353,24 +357,26 @@ TEST_CASE("lp-get-iis", "[iis]") {
353357
HighsInt iis_row = iis.row_index_[0];
354358
if (lp.a_matrix_.isColwise()) {
355359
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
356-
for (HighsInt iEl = lp.a_matrix_.start_[iCol]; iEl < lp.a_matrix_.start_[iCol+1]; iEl++) {
357-
if (lp.a_matrix_.index_[iEl] == iis_row) {
358-
REQUIRE(iis.col_status_[iCol] == kIisStatusInConflict);
359-
break;
360-
}
361-
}
360+
for (HighsInt iEl = lp.a_matrix_.start_[iCol];
361+
iEl < lp.a_matrix_.start_[iCol + 1]; iEl++) {
362+
if (lp.a_matrix_.index_[iEl] == iis_row) {
363+
REQUIRE(iis.col_status_[iCol] == kIisStatusInConflict);
364+
break;
365+
}
366+
}
362367
}
363368
} else {
364-
for (HighsInt iEl = lp.a_matrix_.start_[iis_row]; iEl < lp.a_matrix_.start_[iis_row+1]; iEl++) {
365-
HighsInt iCol = lp.a_matrix_.index_[iEl];
366-
REQUIRE(iis.col_status_[iCol] == kIisStatusInConflict);
369+
for (HighsInt iEl = lp.a_matrix_.start_[iis_row];
370+
iEl < lp.a_matrix_.start_[iis_row + 1]; iEl++) {
371+
HighsInt iCol = lp.a_matrix_.index_[iEl];
372+
REQUIRE(iis.col_status_[iCol] == kIisStatusInConflict);
367373
}
368374
}
369375
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
370376
if (iRow == iis.row_index_[0]) {
371-
REQUIRE(iis.row_status_[iRow] == kIisStatusInConflict);
377+
REQUIRE(iis.row_status_[iRow] == kIisStatusInConflict);
372378
} else {
373-
REQUIRE(iis.row_status_[iRow] == kIisStatusNotInConflict);
379+
REQUIRE(iis.row_status_[iRow] == kIisStatusNotInConflict);
374380
}
375381
}
376382
highs.clearSolver();
@@ -382,8 +388,12 @@ TEST_CASE("lp-get-iis", "[iis]") {
382388

383389
TEST_CASE("lp-get-iis-woodinfe", "[iis]") {
384390
std::string model = "woodinfe";
385-
testMps(model, kIisStrategyFromLpRowPriority);
386-
// testMps(model, kIisStrategyFromRayRowPriority);
391+
testMps(model, kIisStrategyLight);
392+
testMps(model, kIisStrategyFromLp);
393+
// testMps(model, kIisStrategyFromRay);
394+
//
395+
// No need for a +kIisStrategyIrreducible test, since kIisStrategyFromLp
396+
// yields IIS
387397
}
388398

389399
TEST_CASE("lp-get-iis-galenet", "[iis]") {
@@ -407,7 +417,7 @@ TEST_CASE("lp-get-iis-galenet", "[iis]") {
407417
//
408418
// 0 <= c4 <= 30
409419
//
410-
// This is infeasible since c4 >= 30 and c4 <= 30 fices c4 = 30,
420+
// This is infeasible since c4 >= 30 and c4 <= 30 fixes c4 = 30,
411421
// then c0 + c1 >= c3 + c4 >= 30 cannot be satisfied due to the
412422
// upper bounds of 10 on these variables
413423
//
@@ -427,19 +437,36 @@ TEST_CASE("lp-get-iis-galenet", "[iis]") {
427437
// r2 that makes r0 infeasible
428438
//
429439
// Hence only empty columns can be removed
440+
//
441+
// If the elasticity filter is used, then it identifies the
442+
// following infeasibility system
443+
//
444+
// r4: 0 <= c2 + c3 - c6 - c7
445+
//
446+
// r6: 20 <= c5 + c6
447+
//
448+
// r7: 30 <= c7
449+
//
450+
// This is infeasible since c7 >= 30 gives 30 <= c2 + c3, but c2 and
451+
// c3 have upper bounds of 10
452+
//
453+
// Hence the IIS does not require r6 or c5, and consists of r4 and r7
454+
// (>=0) with c2 <= 10; c3 <= 10; c6 free; c7 free
455+
430456
std::string model = "galenet";
431-
testMps(model, kIisStrategyFromLpRowPriority);
432-
// testMps(model, kIisStrategyFromLpRowPriority + kIisStrategyIrreducible);
457+
testMps(model, kIisStrategyLight, HighsModelStatus::kNotset);
458+
testMps(model, kIisStrategyFromLp);
459+
testMps(model, kIisStrategyFromLp + kIisStrategyIrreducible);
433460
}
434461

435462
TEST_CASE("lp-get-iis-avgas", "[iis]") {
436463
std::string model = "avgas";
437464
// For the whole LP calculation the elasticity filter only
438465
// identified feasibility, so the model status is not set
439-
testMps(model, kIisStrategyFromLpRowPriority, HighsModelStatus::kNotset);
466+
testMps(model, kIisStrategyFromLp, HighsModelStatus::kNotset);
440467
// For the ray calculation the model is solved, so its status is
441468
// known
442-
// testMps(model, kIisStrategyFromRayRowPriority,
469+
// testMps(model, kIisStrategyFromRay,
443470
// HighsModelStatus::kOptimal);
444471
}
445472

@@ -562,7 +589,7 @@ void testMps(std::string& model, const HighsInt iis_strategy,
562589
// highs.setOptionValue("output_flag", dev_run);
563590

564591
REQUIRE(highs.readModel(model_file) == HighsStatus::kOk);
565-
// if (iis_strategy == kIisStrategyFromRayRowPriority ||
592+
// if (iis_strategy == kIisStrategyFromRay ||
566593
// iis_strategy == kIisStrategyFromRayColPriority) {
567594
// // For a ray strategy, solve the LP first
568595
// REQUIRE(highs.run() == HighsStatus::kOk);
@@ -586,11 +613,12 @@ void testMps(std::string& model, const HighsInt iis_strategy,
586613
int(num_iis_col), int(num_iis_row));
587614
REQUIRE(iis.valid_ == true);
588615
const bool find_irreducible = kIisStrategyIrreducible & iis_strategy;
589-
const HighsInt iis_status = find_irreducible ? kIisStatusInConflict : kIisStatusMaybeInConflict;
590-
REQUIRE(iis.irreducible_ == find_irreducible);
591-
for(HighsInt iX = 0; iX < num_iis_col; iX++)
616+
if (find_irreducible) REQUIRE(iis.irreducible_);
617+
const HighsInt iis_status =
618+
iis.irreducible_ ? kIisStatusInConflict : kIisStatusMaybeInConflict;
619+
for (HighsInt iX = 0; iX < num_iis_col; iX++)
592620
REQUIRE(iis.col_status_[iis.col_index_[iX]] == iis_status);
593-
for(HighsInt iX = 0; iX < num_iis_row; iX++)
621+
for (HighsInt iX = 0; iX < num_iis_row; iX++)
594622
REQUIRE(iis.row_status_[iis.row_index_[iX]] == iis_status);
595623
} else {
596624
REQUIRE(num_iis_col == 0);
@@ -656,7 +684,7 @@ TEST_CASE("feasible-lp-iis", "[iis]") {
656684

657685
h.passModel(lp);
658686
// With kIisStrategyFromLp, feasibility of the LP is determined
659-
h.setOptionValue("iis_strategy", kIisStrategyFromLpRowPriority);
687+
h.setOptionValue("iis_strategy", kIisStrategyFromLp);
660688

661689
h.getIis(iis);
662690
REQUIRE(iis.col_index_.size() == 0);

highs/lp_data/HConst.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -282,13 +282,15 @@ enum PresolveRuleType : int {
282282
enum IisStrategy : int {
283283
kIisStrategyMin = 0,
284284
kIisStrategyLight = kIisStrategyMin, // 0
285-
kIisStrategyFromRay = 1,
286-
kIisStrategyFromLp = 2,
285+
kIisStrategyFromRay = 1,
286+
kIisStrategyFromLp = 2,
287287
kIisStrategyColPriority = 4,
288288
kIisStrategyIrreducible = 8,
289289
kIisStrategyRelaxation = 16,
290290
kIisStrategyDefault = kIisStrategyLight,
291-
kIisStrategyMax = kIisStrategyFromRay + kIisStrategyFromLp + kIisStrategyColPriority + kIisStrategyIrreducible + kIisStrategyRelaxation
291+
kIisStrategyMax = kIisStrategyFromRay + kIisStrategyFromLp +
292+
kIisStrategyColPriority + kIisStrategyIrreducible +
293+
kIisStrategyRelaxation
292294
};
293295

294296
enum IisStatus {

highs/lp_data/HighsIis.cpp

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,13 @@ bool HighsIis::rowValueBounds(const HighsLp& lp, const HighsOptions& options) {
224224
break;
225225
}
226226
}
227-
if (this->row_index_.size() == 0) return false;
227+
if (this->row_index_.size() == 0) {
228+
// Nothing found, but IIS data still valid
229+
this->clear();
230+
this->valid_ = true;
231+
this->strategy_ = options.iis_strategy;
232+
return false;
233+
}
228234
assert(below_lower || above_upper);
229235
assert(!(below_lower && above_upper));
230236
// Found an infeasible row
@@ -291,11 +297,11 @@ bool HighsIis::rowValueBounds(const HighsLp& lp, const HighsOptions& options) {
291297
this->valid_ = true;
292298
this->irreducible_ = true;
293299
this->strategy_ = options.iis_strategy;
294-
return this->valid_;
300+
return true;
295301
}
296302

297303
HighsStatus HighsIis::deduce(const HighsLp& lp, const HighsOptions& options,
298-
const HighsBasis& basis) {
304+
const HighsBasis& basis) {
299305
// The number of infeasible rows must be positive
300306
assert(this->row_index_.size() > 0);
301307
// Identify the LP corresponding to the set of infeasible rows
@@ -307,6 +313,9 @@ HighsStatus HighsIis::deduce(const HighsLp& lp, const HighsOptions& options,
307313
assert(!this->trivial(lp, options));
308314
// Only uses this->row_index_ to initialise from_row, so can clear
309315
this->clear();
316+
// ToDo Exploit the known col_index_ and row_bound_ HighsIis
317+
// information
318+
//
310319
// To get the IIS data needs the matrix to be column-wise
311320
assert(lp.a_matrix_.isColwise());
312321
// Determine how to detect whether a row is in from_row and (then)
@@ -467,13 +476,11 @@ void HighsIis::setStatus(const HighsLp& lp) {
467476
HighsInt iis_num_col = this->col_index_.size();
468477
HighsInt iis_num_row = this->row_index_.size();
469478
for (HighsInt iisCol = 0; iisCol < iis_num_col; iisCol++)
470-
this->col_status_[this->col_index_[iisCol]] = this->irreducible_ ?
471-
kIisStatusInConflict :
472-
kIisStatusMaybeInConflict;
479+
this->col_status_[this->col_index_[iisCol]] =
480+
this->irreducible_ ? kIisStatusInConflict : kIisStatusMaybeInConflict;
473481
for (HighsInt iisRow = 0; iisRow < iis_num_row; iisRow++)
474-
this->row_status_[this->row_index_[iisRow]] = this->irreducible_ ?
475-
kIisStatusInConflict :
476-
kIisStatusMaybeInConflict;
482+
this->row_status_[this->row_index_[iisRow]] =
483+
this->irreducible_ ? kIisStatusInConflict : kIisStatusMaybeInConflict;
477484
}
478485

479486
HighsStatus HighsIis::compute(const HighsLp& lp, const HighsOptions& options,
@@ -795,6 +802,7 @@ HighsStatus HighsIis::compute(const HighsLp& lp, const HighsOptions& options,
795802
this->row_index_.resize(iss_num_row);
796803
this->row_bound_.resize(iss_num_row);
797804
this->valid_ = true;
805+
this->irreducible_ = true;
798806
this->strategy_ = options.iis_strategy;
799807
return HighsStatus::kOk;
800808
}
@@ -804,8 +812,10 @@ bool indexStatusOkReturn(const bool return_value) { return return_value; }
804812
bool HighsIis::indexStatusOk(const HighsLp& lp) const {
805813
HighsInt num_col = lp.num_col_;
806814
HighsInt num_row = lp.num_row_;
807-
bool col_status_size_ok = this->col_status_.size() == static_cast<size_t>(num_col);
808-
bool row_status_size_ok = this->row_status_.size() == static_cast<size_t>(num_row);
815+
bool col_status_size_ok =
816+
this->col_status_.size() == static_cast<size_t>(num_col);
817+
bool row_status_size_ok =
818+
this->row_status_.size() == static_cast<size_t>(num_row);
809819
assert(col_status_size_ok);
810820
assert(row_status_size_ok);
811821
if (!col_status_size_ok) return indexStatusOkReturn(false);
@@ -823,8 +833,8 @@ bool HighsIis::indexStatusOk(const HighsLp& lp) const {
823833
if (!true_iis) {
824834
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
825835
if (this->row_status_[iRow] == kIisStatusInConflict) {
826-
true_iis = true;
827-
break;
836+
true_iis = true;
837+
break;
828838
}
829839
}
830840
}
@@ -835,26 +845,24 @@ bool HighsIis::indexStatusOk(const HighsLp& lp) const {
835845
std::vector<HighsInt> row_status = row_status_;
836846
for (HighsInt iX = 0; iX < num_iis_col; iX++) {
837847
HighsInt iCol = this->col_index_[iX];
838-
if (col_status_[iCol] != true_iis ?
839-
kIisStatusInConflict :
840-
kIisStatusMaybeInConflict) return indexStatusOkReturn(false);
848+
if (col_status_[iCol] != true_iis ? kIisStatusInConflict
849+
: kIisStatusMaybeInConflict)
850+
return indexStatusOkReturn(false);
841851
col_status[iCol] = -1;
842852
}
843853
for (HighsInt iX = 0; iX < num_iis_row; iX++) {
844854
HighsInt iRow = this->row_index_[iX];
845-
if (row_status_[iRow] != true_iis ?
846-
kIisStatusInConflict :
847-
kIisStatusMaybeInConflict) return indexStatusOkReturn(false);
855+
if (row_status_[iRow] != true_iis ? kIisStatusInConflict
856+
: kIisStatusMaybeInConflict)
857+
return indexStatusOkReturn(false);
848858
row_status[iRow] = -1;
849859
}
850860
for (HighsInt iCol = 0; iCol < num_col; iCol++) {
851-
if (col_status[iCol] >= 0 &&
852-
col_status[iCol] != kIisStatusNotInConflict)
861+
if (col_status[iCol] >= 0 && col_status[iCol] != kIisStatusNotInConflict)
853862
return indexStatusOkReturn(false);
854863
}
855864
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
856-
if (row_status[iRow] >= 0 &&
857-
row_status[iRow] != kIisStatusNotInConflict)
865+
if (row_status[iRow] >= 0 && row_status[iRow] != kIisStatusNotInConflict)
858866
return indexStatusOkReturn(false);
859867
}
860868
return indexStatusOkReturn(true);
@@ -1024,7 +1032,7 @@ bool lpOkReturn(const bool return_value) { return return_value; }
10241032
bool HighsIis::lpOk(const HighsOptions& options) const {
10251033
// Check that the IIS LP is OK (infeasible and optimal if
10261034
// any bound is relaxed)
1027-
if (!this->valid_) return true;
1035+
if (!this->valid_) return lpOkReturn(true);
10281036
HighsInt num_iis_col = this->col_index_.size();
10291037
HighsInt num_iis_row = this->row_index_.size();
10301038
// If an LP has a row with inconsistent bounds, or an empty row with
@@ -1046,6 +1054,7 @@ bool HighsIis::lpOk(const HighsOptions& options) const {
10461054
"HighsIis: IIS LP is not infeasible\n");
10471055
return lpOkReturn(false);
10481056
}
1057+
if (!this->irreducible_) return lpOkReturn(true);
10491058
auto optimal = [&]() -> bool {
10501059
if (options.log_dev_level > 0) h.writeModel("");
10511060
h.run();

0 commit comments

Comments
 (0)