Skip to content

Commit 0fd46a0

Browse files
committed
Need to extract IS after elasticity filter
1 parent 2b86c1f commit 0fd46a0

File tree

7 files changed

+124
-49
lines changed

7 files changed

+124
-49
lines changed

check/TestIis.cpp

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,18 @@ TEST_CASE("lp-incompatible-bounds", "[iis]") {
5151
HighsIis iis;
5252
REQUIRE(highs.getIis(iis) == HighsStatus::kOk);
5353
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
54+
REQUIRE(iis.valid_ == true);
55+
REQUIRE(iis.irreducible_ == true);
5456

5557
// Perform full IIS
5658
REQUIRE(highs.run() == HighsStatus::kOk);
5759
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
5860

5961
highs.setOptionValue("iis_strategy", kIisStrategyFromLpRowPriority);
6062
REQUIRE(highs.getIis(iis) == HighsStatus::kOk);
63+
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
64+
REQUIRE(iis.valid_ == true);
65+
REQUIRE(iis.irreducible_ == true);
6166
REQUIRE(iis.col_index_.size() == 0);
6267
REQUIRE(iis.row_index_.size() == 1);
6368
REQUIRE(iis.row_index_[0] == 0);
@@ -74,6 +79,9 @@ TEST_CASE("lp-incompatible-bounds", "[iis]") {
7479

7580
highs.setOptionValue("iis_strategy", kIisStrategyFromLpColPriority);
7681
REQUIRE(highs.getIis(iis) == HighsStatus::kOk);
82+
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
83+
REQUIRE(iis.valid_ == true);
84+
REQUIRE(iis.irreducible_ == true);
7785
REQUIRE(iis.col_index_.size() == 1);
7886
REQUIRE(iis.row_index_.size() == 0);
7987
REQUIRE(iis.col_index_[0] == 2);
@@ -100,6 +108,9 @@ TEST_CASE("lp-incompatible-bounds", "[iis]") {
100108
highs.passModel(lp);
101109
highs.setOptionValue("iis_strategy", kIisStrategyFromLpRowPriority);
102110
REQUIRE(highs.getIis(iis) == HighsStatus::kOk);
111+
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
112+
REQUIRE(iis.valid_ == true);
113+
REQUIRE(iis.irreducible_ == true);
103114
REQUIRE(iis.col_index_.size() == 0);
104115
REQUIRE(iis.row_index_.size() == 1);
105116
REQUIRE(iis.row_index_[0] == 0);
@@ -115,7 +126,10 @@ TEST_CASE("lp-incompatible-bounds", "[iis]") {
115126
}
116127

117128
highs.setOptionValue("iis_strategy", kIisStrategyFromLpColPriority);
129+
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
118130
REQUIRE(highs.getIis(iis) == HighsStatus::kOk);
131+
REQUIRE(iis.valid_ == true);
132+
REQUIRE(iis.irreducible_ == true);
119133
REQUIRE(iis.col_index_.size() == 1);
120134
REQUIRE(iis.row_index_.size() == 0);
121135
REQUIRE(iis.col_index_[0] == 0);
@@ -156,6 +170,8 @@ TEST_CASE("lp-empty-infeasible-row", "[iis]") {
156170
// Get IIS for empty row with positive lower bound
157171
REQUIRE(highs.getIis(iis) == HighsStatus::kOk);
158172
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
173+
REQUIRE(iis.valid_ == true);
174+
REQUIRE(iis.irreducible_ == true);
159175
if (dev_run && write_model) {
160176
highs.writeModel("");
161177
highs.writeIisModel("");
@@ -184,6 +200,8 @@ TEST_CASE("lp-empty-infeasible-row", "[iis]") {
184200
lp.row_upper_[empty_row] = new_upper;
185201
REQUIRE(highs.getIis(iis) == HighsStatus::kOk);
186202
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
203+
REQUIRE(iis.valid_ == true);
204+
REQUIRE(iis.irreducible_ == true);
187205
REQUIRE(iis.col_index_.size() == 0);
188206
REQUIRE(iis.row_index_.size() == 1);
189207
REQUIRE(iis.row_index_[0] == empty_row);
@@ -236,20 +254,32 @@ TEST_CASE("lp-get-iis-light", "[iis]") {
236254
for (int k = 0; k < 2; k++) {
237255
REQUIRE(highs.getIis(iis) == HighsStatus::kOk);
238256
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
257+
REQUIRE(iis.valid_ == true);
258+
REQUIRE(iis.irreducible_ == true);
239259
REQUIRE(iis.row_index_.size() == 1);
240-
241-
printf("Pass k = %d; l = %d: iis.row_index_[0] = %d\n", k, l, int(iis.row_index_[0]));
242-
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
243-
// REQUIRE(iis.col_status_[iCol] == kIisStatusNotInConflict);
244-
printf("Pass k = %d; l = %d: iis.col_status_[%d] = %d\n", k, l, int(iCol), int(iis.col_status_[iCol]));
260+
HighsInt iis_row = iis.row_index_[0];
261+
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+
}
270+
} 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+
}
275+
}
245276
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
246277
if (iRow == iis.row_index_[0]) {
247278
REQUIRE(iis.row_status_[iRow] == kIisStatusInConflict);
248279
} else {
249280
REQUIRE(iis.row_status_[iRow] == kIisStatusNotInConflict);
250281
}
251282
}
252-
253283
if (dev_run && write_model) {
254284
highs.writeModel("");
255285
highs.writeIisModel("");
@@ -312,11 +342,37 @@ TEST_CASE("lp-get-iis", "[iis]") {
312342
for (HighsInt k = 0; k < 2; k++) {
313343
REQUIRE(highs.getIis(iis) == HighsStatus::kOk);
314344
REQUIRE(highs.getModelStatus() == HighsModelStatus::kInfeasible);
345+
REQUIRE(iis.valid_ == true);
346+
REQUIRE(iis.irreducible_ == true);
315347
REQUIRE(iis.col_index_.size() == 2);
316348
REQUIRE(iis.row_index_.size() == 1);
317349
REQUIRE(iis.col_index_[0] == 0);
318350
REQUIRE(iis.col_index_[1] == 1);
319351
REQUIRE(iis.row_index_[0] == 2);
352+
353+
HighsInt iis_row = iis.row_index_[0];
354+
if (lp.a_matrix_.isColwise()) {
355+
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+
}
362+
}
363+
} 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);
367+
}
368+
}
369+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) {
370+
if (iRow == iis.row_index_[0]) {
371+
REQUIRE(iis.row_status_[iRow] == kIisStatusInConflict);
372+
} else {
373+
REQUIRE(iis.row_status_[iRow] == kIisStatusNotInConflict);
374+
}
375+
}
320376
highs.clearSolver();
321377
highs.ensureRowwise();
322378
REQUIRE(highs_lp.a_matrix_.isRowwise());
@@ -372,10 +428,8 @@ TEST_CASE("lp-get-iis-galenet", "[iis]") {
372428
//
373429
// Hence only empty columns can be removed
374430
std::string model = "galenet";
375-
const HighsInt iis_strategy = kIisStrategyFromLpRowPriority
376-
+ kIisStrategyIrreducible;
377-
testMps(model, iis_strategy);
378-
// testMps(model, kIisStrategyFromRayRowPriority);
431+
testMps(model, kIisStrategyFromLpRowPriority);
432+
// testMps(model, kIisStrategyFromLpRowPriority + kIisStrategyIrreducible);
379433
}
380434

381435
TEST_CASE("lp-get-iis-avgas", "[iis]") {
@@ -530,6 +584,14 @@ void testMps(std::string& model, const HighsInt iis_strategy,
530584
if (dev_run)
531585
printf("Model %s has IIS with %d columns and %d rows\n", model.c_str(),
532586
int(num_iis_col), int(num_iis_row));
587+
REQUIRE(iis.valid_ == true);
588+
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++)
592+
REQUIRE(iis.col_status_[iis.col_index_[iX]] == iis_status);
593+
for(HighsInt iX = 0; iX < num_iis_row; iX++)
594+
REQUIRE(iis.row_status_[iis.row_index_[iX]] == iis_status);
533595
} else {
534596
REQUIRE(num_iis_col == 0);
535597
REQUIRE(num_iis_row == 0);
@@ -584,6 +646,7 @@ TEST_CASE("feasible-lp-iis", "[iis]") {
584646
h.run();
585647

586648
h.getIis(iis);
649+
REQUIRE(h.getModelStatus() == HighsModelStatus::kOptimal);
587650
REQUIRE(iis.col_index_.size() == 0);
588651
REQUIRE(iis.row_index_.size() == 0);
589652
REQUIRE(iis.col_status_[0] == kIisStatusNotInConflict);

highs/Highs.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1608,7 +1608,7 @@ class Highs {
16081608
// Invalidates all solver data in Highs class members by calling
16091609
// invalidateModelStatus(), invalidateSolution(), invalidateBasis(),
16101610
// invalidateRanging(), invalidateInfo(), invalidateEkk() and
1611-
// invalidateIis()
1611+
// clearIis()
16121612
void invalidateSolverData();
16131613

16141614
// Invalidates all solver dual data in Highs class members by calling
@@ -1641,8 +1641,8 @@ class Highs {
16411641
// Invalidates ekk_instance_
16421642
void invalidateEkk();
16431643

1644-
// Invalidates iis_
1645-
void invalidateIis();
1644+
// Clears iis_
1645+
void clearIis();
16461646

16471647
HighsStatus returnFromWriteSolution(FILE* file,
16481648
const HighsStatus return_status);

highs/lp_data/HConst.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -292,11 +292,11 @@ enum IisStrategy : int {
292292
};
293293

294294
enum IisStatus {
295-
kIisStatusMin = 0,
296-
kIisStatusInConflict = kIisStatusMin, // 0
297-
kIisStatusNotInConflict, // 1
298-
kIisStatusMaybeInConflict, // 2
299-
kIisStatusMax = kIisStatusMaybeInConflict
295+
kIisStatusMin = -1,
296+
kIisStatusNotInConflict = kIisStatusMin, // -1
297+
kIisStatusMaybeInConflict, // 0
298+
kIisStatusInConflict, // 1
299+
kIisStatusMax = kIisStatusInConflict
300300
};
301301

302302
enum SubSolverIndex : int {

highs/lp_data/Highs.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3772,7 +3772,7 @@ void Highs::invalidateSolverData() {
37723772
invalidateSolution();
37733773
invalidateBasis();
37743774
invalidateEkk();
3775-
invalidateIis();
3775+
clearIis();
37763776
}
37773777

37783778
void Highs::invalidateSolverDualData() {
@@ -3790,7 +3790,7 @@ void Highs::invalidateModelStatusAndInfo() {
37903790
invalidateModelStatus();
37913791
invalidateRanging();
37923792
invalidateInfo();
3793-
invalidateIis();
3793+
clearIis();
37943794
}
37953795

37963796
void Highs::invalidateModelStatus() {
@@ -3820,7 +3820,7 @@ void Highs::invalidateRanging() { ranging_.invalidate(); }
38203820

38213821
void Highs::invalidateEkk() { ekk_instance_.invalidate(); }
38223822

3823-
void Highs::invalidateIis() { iis_.invalidate(); }
3823+
void Highs::clearIis() { iis_.clear(); }
38243824

38253825
HighsStatus Highs::completeSolutionFromDiscreteAssignment() {
38263826
// Determine whether the current solution of a MIP is feasible and,

highs/lp_data/HighsIis.cpp

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
#include "Highs.h"
1313

14-
void HighsIis::invalidate() {
14+
void HighsIis::clear() {
1515
this->valid_ = false;
1616
this->irreducible_ = false;
1717
this->strategy_ = kIisStrategyMin;
@@ -25,6 +25,12 @@ void HighsIis::invalidate() {
2525
this->model_.clear();
2626
}
2727

28+
void HighsIis::invalid(const HighsLp& lp) {
29+
this->clear();
30+
this->col_status_.assign(lp.num_col_, kIisStatusMaybeInConflict);
31+
this->row_status_.assign(lp.num_row_, kIisStatusMaybeInConflict);
32+
}
33+
2834
std::string HighsIis::iisBoundStatusToString(HighsInt bound_status) const {
2935
if (bound_status == kIisBoundStatusDropped) return "Dropped";
3036
if (bound_status == kIisBoundStatusNull) return " Null";
@@ -85,7 +91,7 @@ void HighsIis::removeRow(const HighsInt row) {
8591
}
8692

8793
bool HighsIis::trivial(const HighsLp& lp, const HighsOptions& options) {
88-
this->invalidate();
94+
this->clear();
8995
const bool col_priority = kIisStrategyColPriority & options.iis_strategy;
9096
for (HighsInt k = 0; k < 2; k++) {
9197
if ((col_priority && k == 0) || (!col_priority && k == 1)) {
@@ -112,12 +118,12 @@ bool HighsIis::trivial(const HighsLp& lp, const HighsOptions& options) {
112118
}
113119
HighsInt num_iis_col = this->col_index_.size();
114120
HighsInt num_iis_row = this->row_index_.size();
115-
// If one is found then we're done
121+
// If one is found then we've found an IIS
116122
if (num_iis_col + num_iis_row > 0) {
117123
// Should have found exactly 1
118-
assert((num_iis_col == 1 || num_iis_row == 1) &&
119-
num_iis_col + num_iis_row < 2);
124+
assert(num_iis_col + num_iis_row == 1);
120125
this->valid_ = true;
126+
this->irreducible_ = true;
121127
this->strategy_ = options.iis_strategy;
122128
return true;
123129
}
@@ -145,7 +151,9 @@ bool HighsIis::trivial(const HighsLp& lp, const HighsOptions& options) {
145151
this->addRow(iRow, kIisBoundStatusUpper);
146152
}
147153
if (this->row_index_.size() > 0) {
154+
// If one is found then we've found an IIS
148155
this->valid_ = true;
156+
this->irreducible_ = true;
149157
this->strategy_ = options.iis_strategy;
150158
return true;
151159
}
@@ -155,7 +163,7 @@ bool HighsIis::trivial(const HighsLp& lp, const HighsOptions& options) {
155163

156164
bool HighsIis::rowValueBounds(const HighsLp& lp, const HighsOptions& options) {
157165
// Look for infeasible rows based on row value bounds
158-
this->invalidate();
166+
this->clear();
159167
std::vector<double> lower_value;
160168
std::vector<double> upper_value;
161169
if (lp.a_matrix_.isColwise()) {
@@ -219,24 +227,8 @@ bool HighsIis::rowValueBounds(const HighsLp& lp, const HighsOptions& options) {
219227
if (this->row_index_.size() == 0) return false;
220228
assert(below_lower || above_upper);
221229
assert(!(below_lower && above_upper));
222-
double value;
223-
auto setColBound = [&]() {
224-
if (below_lower) {
225-
if (value > 0) {
226-
this->col_bound_.push_back(kIisBoundStatusUpper);
227-
} else {
228-
this->col_bound_.push_back(kIisBoundStatusLower);
229-
}
230-
} else {
231-
if (value > 0) {
232-
this->col_bound_.push_back(kIisBoundStatusLower);
233-
} else {
234-
this->col_bound_.push_back(kIisBoundStatusUpper);
235-
}
236-
}
237-
};
238230
// Found an infeasible row
239-
HighsInt iRow = this->row_index_[0];
231+
const HighsInt iRow = this->row_index_[0];
240232
const std::string row_name_string =
241233
lp.row_names_.size() > 0 ? "(" + lp.row_names_[iRow] + ")" : "";
242234
if (below_lower) {
@@ -252,6 +244,23 @@ bool HighsIis::rowValueBounds(const HighsLp& lp, const HighsOptions& options) {
252244
int(iRow), row_name_string.c_str(), lower_value[iRow],
253245
lp.row_upper_[iRow]);
254246
}
247+
double value;
248+
auto setColBound = [&]() {
249+
if (below_lower) {
250+
if (value > 0) {
251+
this->col_bound_.push_back(kIisBoundStatusUpper);
252+
} else {
253+
this->col_bound_.push_back(kIisBoundStatusLower);
254+
}
255+
} else {
256+
if (value > 0) {
257+
this->col_bound_.push_back(kIisBoundStatusLower);
258+
} else {
259+
this->col_bound_.push_back(kIisBoundStatusUpper);
260+
}
261+
}
262+
};
263+
255264
if (lp.a_matrix_.isColwise()) {
256265
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) {
257266
for (HighsInt iEl = lp.a_matrix_.start_[iCol];
@@ -274,12 +283,14 @@ bool HighsIis::rowValueBounds(const HighsLp& lp, const HighsOptions& options) {
274283
}
275284
}
276285
}
286+
277287
// There must be at least one column in the IIS
278288
assert(this->col_index_.size() > 0);
279289
assert(this->col_index_.size() == this->col_bound_.size());
280290
assert(this->row_index_.size() == this->row_bound_.size());
281-
this->strategy_ = options.iis_strategy;
282291
this->valid_ = true;
292+
this->irreducible_ = true;
293+
this->strategy_ = options.iis_strategy;
283294
return this->valid_;
284295
}
285296

highs/lp_data/HighsIis.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ class HighsIis {
3333
public:
3434
HighsIis() {}
3535

36-
void invalidate();
36+
void clear();
37+
void invalid(const HighsLp& lp);
3738
std::string iisBoundStatusToString(HighsInt bound_status) const;
3839
void report(const std::string message, const HighsLp& lp) const;
3940
void addCol(const HighsInt col, const HighsInt status = kIisBoundStatusNull);

0 commit comments

Comments
 (0)