Skip to content

Commit 1c2ed37

Browse files
committed
Surely free columns can be dropped from the ISS
1 parent c3341d5 commit 1c2ed37

File tree

7 files changed

+92
-62
lines changed

7 files changed

+92
-62
lines changed

check/TestCAPI.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2128,7 +2128,7 @@ void testDeleteRowResolveWithBasis() {
21282128

21292129
void testIis() {
21302130
void* highs = Highs_create();
2131-
Highs_setBoolOptionValue(highs, "output_flag", dev_run);
2131+
//Highs_setBoolOptionValue(highs, "output_flag", dev_run);
21322132
HighsInt ret;
21332133
double inf = Highs_getInfinity(highs);
21342134
// For the constraints
@@ -2190,7 +2190,7 @@ void testIis() {
21902190
assert(iis_num_col == 0);
21912191
assert(iis_num_row == 0);
21922192
Highs_setIntOptionValue(highs, "iis_strategy",
2193-
kHighsIisStrategyFromLpRowPriority);
2193+
kHighsIisStrategyFromLpRowPriorityIrreducible);
21942194
} else {
21952195
assert(iis_num_col == 3);
21962196
assert(iis_num_row == 2);

check/TestIis.cpp

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,31 @@ TEST_CASE("lp-feasibility-relaxation", "[iis]") {
474474
// Using infeasible MIP from AMPL documentation
475475
//
476476
// https://mp.ampl.com/features-guide.html#feasibility-relaxation
477+
//
478+
// min x-2y
479+
//
480+
// 2 <= -x + 21y
481+
//
482+
// -3x + 2y <= 1
483+
//
484+
// 20x + y <= 20
485+
//
486+
// 5 <= x; y free
487+
//
488+
// Vanilla feasibility relaxation
489+
//
490+
// min e0 + e1 + e2 + e3
491+
//
492+
// 2 <= e1 - x + 21y
493+
//
494+
// -3x + 2y - e2 <= 1
495+
//
496+
// 20x + y - e3 <= 20
497+
//
498+
// 5 <= e0 + x
499+
//
500+
// x, y free
501+
//
477502
HighsLp lp;
478503
lp.model_name_ = "ampl_infeas";
479504
lp.num_col_ = 2;
@@ -490,15 +515,15 @@ TEST_CASE("lp-feasibility-relaxation", "[iis]") {
490515
lp.a_matrix_.value_ = {-1, -3, 20, 21, 2, 1};
491516
lp.integrality_ = {HighsVarType::kInteger, HighsVarType::kInteger};
492517
Highs h;
493-
//h.setOptionValue("output_flag", dev_run);
518+
h.setOptionValue("output_flag", dev_run);
494519
const HighsSolution& solution = h.getSolution();
495520
h.passModel(lp);
496521

497-
const bool all_tests = false;//true;
498-
const bool test0 = false || all_tests;
499-
const bool test1 = false || all_tests;
522+
const bool all_tests = true;
523+
const bool test0 = true || all_tests;
524+
const bool test1 = true || all_tests;
500525
const bool test2 = true || all_tests;
501-
const bool test3 = false || all_tests;
526+
const bool test3 = true || all_tests;
502527
if (test0) {
503528
// Vanilla feasibility relaxation
504529
if (dev_run)
@@ -545,11 +570,19 @@ TEST_CASE("lp-feasibility-relaxation", "[iis]") {
545570
std::vector<double> local_rhs_penalty = {1, -1, 10};
546571
h.feasibilityRelaxation(1, 1, 0, nullptr, nullptr,
547572
local_rhs_penalty.data());
548-
// Should get slacks (-3, 4, 0)
573+
// AMPL says: Should get slacks (-3, 4, 0) corresponding to x = 1;
574+
// y = 0, giving objective = 4 + 3 = 7
575+
//
576+
// However, x = 0; y = 0, gives slacks (-2, 1, 20) and also
577+
// objective = 5 + 2 = 7
578+
//
579+
double r0_slack = -2; // -3;
580+
double r1_slack = 1; // 4;
581+
double r2_slack = 20; // 0;
549582
h.writeSolution("", 1);
550-
REQUIRE(solution.row_value[0] == lp.row_lower_[0] + 3);
551-
REQUIRE(solution.row_value[1] == lp.row_upper_[1] - 4);
552-
REQUIRE(solution.row_value[2] == lp.row_upper_[2]);
583+
REQUIRE(solution.row_value[0] == lp.row_lower_[0] + r0_slack);
584+
REQUIRE(solution.row_value[1] == lp.row_upper_[1] - r1_slack);
585+
REQUIRE(solution.row_value[2] == lp.row_upper_[2] - r2_slack);
553586
}
554587

555588
if (test3) {
@@ -617,10 +650,9 @@ void testMps(std::string& model, const HighsInt iis_strategy,
617650
REQUIRE(iis.valid_ == true);
618651
const bool find_irreducible = kIisStrategyIrreducible & iis_strategy;
619652
if (find_irreducible) REQUIRE(iis.status_ == kIisModelStatusIrreducible);
620-
const HighsInt in_iis_status =
621-
iis.status_ == kIisModelStatusIrreducible ?
622-
kIisStatusInConflict :
623-
kIisStatusMaybeInConflict;
653+
const HighsInt in_iis_status = iis.status_ == kIisModelStatusIrreducible
654+
? kIisStatusInConflict
655+
: kIisStatusMaybeInConflict;
624656
for (HighsInt iX = 0; iX < num_iis_col; iX++)
625657
REQUIRE(iis.col_status_[iis.col_index_[iX]] == in_iis_status);
626658
for (HighsInt iX = 0; iX < num_iis_row; iX++)

highs/Highs.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,9 +1728,8 @@ class Highs {
17281728
HighsStatus getIisInterfaceReturn(const HighsStatus return_status);
17291729

17301730
HighsStatus elasticityFilterReturn(
1731-
const HighsStatus return_status,
1732-
const std::string& original_model_name, const HighsInt original_num_col,
1733-
const HighsInt original_num_row,
1731+
const HighsStatus return_status, const std::string& original_model_name,
1732+
const HighsInt original_num_col, const HighsInt original_num_row,
17341733
const std::vector<double>& original_col_cost,
17351734
const std::vector<double>& original_col_lower,
17361735
const std::vector<double> original_col_upper,

highs/interfaces/highs_c_api.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,17 +145,19 @@ static const char* const kHighsCallbackDataOutCutpoolUpperName =
145145
"cutpool_upper";
146146

147147
const HighsInt kHighsIisStrategyLight = 0;
148-
const HighsInt kHighsIisStrategyFromLpRowPriority = 1; // WIP
149-
const HighsInt kHighsIisStrategyFromLpColPriority = 2; // WIP
148+
const HighsInt kHighsIisStrategyFromLpRowPriority = 2;
149+
const HighsInt kHighsIisStrategyFromLpColPriority = 6;
150+
const HighsInt kHighsIisStrategyFromLpRowPriorityIrreducible = 10;
151+
const HighsInt kHighsIisStrategyFromLpColPriorityIrreducible = 14;
150152

151153
const HighsInt kHighsIisBoundFree = 1;
152154
const HighsInt kHighsIisBoundLower = 2;
153155
const HighsInt kHighsIisBoundUpper = 3;
154156
const HighsInt kHighsIisBoundBoxed = 4;
155157

156-
const HighsInt kHighsIisStatusInConflict = 0;
157-
const HighsInt kHighsIisStatusNotInConflict = 1;
158-
const HighsInt kHighsIisStatusMaybeInConflict = 2;
158+
const HighsInt kHighsIisStatusNotInConflict = -1;
159+
const HighsInt kHighsIisStatusMaybeInConflict = 0;
160+
const HighsInt kHighsIisStatusInConflict = 1;
159161

160162
#ifdef __cplusplus
161163
extern "C" {

highs/lp_data/HighsIis.cpp

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -479,19 +479,18 @@ HighsInt HighsIis::nonIsStatus() const {
479479
if (has_is) assert(this->status_ >= kIisModelStatusReducible);
480480
// If there is an IS, then all columns and rows not in the IS are
481481
// kIisStatusNotInConflict
482-
const HighsInt default_iis_status = is_feasible || has_is ?
483-
kIisStatusNotInConflict :
484-
kIisStatusMaybeInConflict;
482+
const HighsInt default_iis_status = is_feasible || has_is
483+
? kIisStatusNotInConflict
484+
: kIisStatusMaybeInConflict;
485485
return default_iis_status;
486486
}
487-
487+
488488
void HighsIis::setStatus(const HighsLp& lp) {
489489
if (!this->valid_) return;
490490
const HighsInt non_is_status = nonIsStatus();
491-
const HighsInt in_is_status =
492-
this->status_ == kIisModelStatusIrreducible ?
493-
kIisStatusInConflict :
494-
kIisStatusMaybeInConflict;
491+
const HighsInt in_is_status = this->status_ == kIisModelStatusIrreducible
492+
? kIisStatusInConflict
493+
: kIisStatusMaybeInConflict;
495494
this->col_status_.assign(lp.num_col_, non_is_status);
496495
this->row_status_.assign(lp.num_row_, non_is_status);
497496
const HighsInt iis_num_col = this->col_index_.size();
@@ -879,13 +878,11 @@ bool HighsIis::indexStatusOk(const HighsLp& lp) const {
879878
}
880879
const HighsInt non_is_status = nonIsStatus();
881880
for (HighsInt iCol = 0; iCol < num_col; iCol++) {
882-
if (col_status[iCol] > illegal_status &&
883-
col_status[iCol] != non_is_status)
881+
if (col_status[iCol] > illegal_status && col_status[iCol] != non_is_status)
884882
return indexStatusOkReturn(false);
885883
}
886884
for (HighsInt iRow = 0; iRow < num_row; iRow++) {
887-
if (row_status[iRow] > illegal_status &&
888-
row_status[iRow] != non_is_status)
885+
if (row_status[iRow] > illegal_status && row_status[iRow] != non_is_status)
889886
return indexStatusOkReturn(false);
890887
}
891888
return indexStatusOkReturn(true);

highs/lp_data/HighsIis.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ enum IisBoundStatus {
2626

2727
enum IisModelStatus {
2828
kIisModelStatusFeasible = -1,
29-
kIisModelStatusUnknown, // 0
30-
kIisModelStatusInfeasible, // 1
31-
kIisModelStatusReducible, // 2
32-
kIisModelStatusIrreducible // 3
29+
kIisModelStatusUnknown, // 0
30+
kIisModelStatusInfeasible, // 1
31+
kIisModelStatusReducible, // 2
32+
kIisModelStatusIrreducible // 3
3333
};
3434

3535
struct HighsIisInfo {

highs/lp_data/HighsInterface.cpp

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,7 +1844,7 @@ HighsStatus Highs::getIisInterfaceReturn(const HighsStatus return_status) {
18441844
// HighsIis::row_index_ have HighsIis::col_bound_ and
18451845
// HighsIis::row_bound_ values set to kIisStatusNotInConflict
18461846
assert(this->iis_.valid_);
1847-
// If the IIS process has identified infeasibility, then set
1847+
// If the IIS process has identified infeasibility, then set
18481848
if (this->iis_.status_ >= kIisModelStatusInfeasible)
18491849
this->model_status_ = HighsModelStatus::kInfeasible;
18501850

@@ -1908,7 +1908,7 @@ HighsStatus Highs::getIisInterface() {
19081908
if (this->iis_.valid_) return this->getIisInterfaceReturn(HighsStatus::kOk);
19091909
this->iis_.clear();
19101910
// Check for trivial IIS: empty infeasible row or inconsistent bounds
1911-
if (this->iis_.trivial(lp, options_))
1911+
if (this->iis_.trivial(lp, options_))
19121912
return this->getIisInterfaceReturn(HighsStatus::kOk);
19131913
HighsInt num_row = lp.num_row_;
19141914
if (num_row == 0) {
@@ -2008,7 +2008,7 @@ HighsStatus Highs::getIisInterface() {
20082008
// A subset of infeasible rows, so at least have a reducible
20092009
// infeasibility set
20102010
this->iis_.status_ = kIisModelStatusReducible;
2011-
if (!(kIisStrategyIrreducible & this->options_.iis_strategy))
2011+
if (!(kIisStrategyIrreducible & this->options_.iis_strategy))
20122012
return this->getIisInterfaceReturn(return_status);
20132013
// Attempt to compute a true IIS
20142014
//
@@ -2047,9 +2047,8 @@ HighsStatus Highs::getIisInterface() {
20472047
}
20482048

20492049
HighsStatus Highs::elasticityFilterReturn(
2050-
const HighsStatus return_status,
2051-
const std::string& original_model_name, const HighsInt original_num_col,
2052-
const HighsInt original_num_row,
2050+
const HighsStatus return_status, const std::string& original_model_name,
2051+
const HighsInt original_num_col, const HighsInt original_num_row,
20532052
const std::vector<double>& original_col_cost,
20542053
const std::vector<double>& original_col_lower,
20552054
const std::vector<double> original_col_upper,
@@ -2447,6 +2446,7 @@ HighsStatus Highs::elasticityFilter(const double global_lower_penalty,
24472446

24482447
// Solve the elastic LP
24492448
run_status = solveLp();
2449+
this->writeSolution("", 1);
24502450

24512451
if (run_status != HighsStatus::kOk)
24522452
return elasticityFilterReturn(run_status, original_model_name,
@@ -2458,10 +2458,10 @@ HighsStatus Highs::elasticityFilter(const double global_lower_penalty,
24582458
assert(this->model_status_ == HighsModelStatus::kOptimal ||
24592459
this->model_status_ == HighsModelStatus::kUnbounded);
24602460
this->iis_.valid_ = true;
2461-
this->iis_.status_ = this->info_.objective_function_value > 0 ?
2462-
kIisModelStatusInfeasible :
2463-
kIisModelStatusFeasible;
2464-
if (!get_iis)
2461+
this->iis_.status_ = this->info_.objective_function_value > 0
2462+
? kIisModelStatusInfeasible
2463+
: kIisModelStatusFeasible;
2464+
if (!get_iis)
24652465
return elasticityFilterReturn(HighsStatus::kOk, original_model_name,
24662466
original_num_col, original_num_row,
24672467
original_col_cost, original_col_lower,
@@ -2520,10 +2520,10 @@ HighsStatus Highs::elasticityFilter(const double global_lower_penalty,
25202520
}
25212521
HighsStatus run_status = solveLp();
25222522
if (run_status != HighsStatus::kOk)
2523-
return elasticityFilterReturn(
2524-
run_status, original_model_name, original_num_col,
2525-
original_num_row, original_col_cost, original_col_lower,
2526-
original_col_upper, original_integrality);
2523+
return elasticityFilterReturn(run_status, original_model_name,
2524+
original_num_col, original_num_row,
2525+
original_col_cost, original_col_lower,
2526+
original_col_upper, original_integrality);
25272527
if (kIisDevReport) this->writeSolution("", kSolutionStylePretty);
25282528
HighsModelStatus model_status = this->getModelStatus();
25292529
if (model_status == HighsModelStatus::kInfeasible) break;
@@ -2585,11 +2585,11 @@ HighsStatus Highs::elasticityFilter(const double global_lower_penalty,
25852585

25862586
iis.valid_ = true;
25872587
iis.strategy_ = this->options_.iis_strategy;
2588-
if (iis.status_ == kIisModelStatusFeasible)
2589-
return elasticityFilterReturn(
2590-
HighsStatus::kOk, original_model_name, original_num_col,
2591-
original_num_row, original_col_cost, original_col_lower,
2592-
original_col_upper, original_integrality);
2588+
if (iis.status_ == kIisModelStatusFeasible)
2589+
return elasticityFilterReturn(HighsStatus::kOk, original_model_name,
2590+
original_num_col, original_num_row,
2591+
original_col_cost, original_col_lower,
2592+
original_col_upper, original_integrality);
25932593
// Model is infeasible because there are (at least) a positive
25942594
// number of rows in the infeasibility set. Hence the IIS status is
25952595
// reducible
@@ -2663,10 +2663,10 @@ HighsStatus Highs::elasticityFilter(const double global_lower_penalty,
26632663
}
26642664
assert(iis.row_bound_.size() == iis.row_index_.size());
26652665
for (HighsInt iX = 0; iX < num_iis_row; iX++) assert(iis.row_bound_[iX] >= 0);
2666-
return elasticityFilterReturn(
2667-
HighsStatus::kOk, original_model_name, original_num_col,
2668-
original_num_row, original_col_cost, original_col_lower,
2669-
original_col_upper, original_integrality);
2666+
return elasticityFilterReturn(HighsStatus::kOk, original_model_name,
2667+
original_num_col, original_num_row,
2668+
original_col_cost, original_col_lower,
2669+
original_col_upper, original_integrality);
26702670
}
26712671

26722672
HighsStatus Highs::extractIis(HighsInt& num_iis_col, HighsInt& num_iis_row,

0 commit comments

Comments
 (0)