Skip to content

Commit a4d00eb

Browse files
committed
Don't pass test2 of AMPL infeasible MIP
1 parent 8bb529c commit a4d00eb

File tree

3 files changed

+41
-25
lines changed

3 files changed

+41
-25
lines changed

check/TestIis.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,8 @@ TEST_CASE("lp-get-iis-avgas", "[iis]") {
472472

473473
TEST_CASE("lp-feasibility-relaxation", "[iis]") {
474474
// Using infeasible LP from AMPL documentation
475+
//
476+
// https://mp.ampl.com/features-guide.html#feasibility-relaxation
475477
HighsLp lp;
476478
lp.model_name_ = "ampl_infeas";
477479
lp.num_col_ = 2;
@@ -488,14 +490,14 @@ TEST_CASE("lp-feasibility-relaxation", "[iis]") {
488490
lp.a_matrix_.value_ = {-1, -3, 20, 21, 2, 1};
489491
lp.integrality_ = {HighsVarType::kInteger, HighsVarType::kInteger};
490492
Highs h;
491-
h.setOptionValue("output_flag", dev_run);
493+
//h.setOptionValue("output_flag", dev_run);
492494
const HighsSolution& solution = h.getSolution();
493495
h.passModel(lp);
494496

495-
const bool all_tests = false;
497+
const bool all_tests = false;//true;
496498
const bool test0 = false || all_tests;
497499
const bool test1 = false || all_tests;
498-
const bool test2 = false || all_tests;
500+
const bool test2 = true || all_tests;
499501
const bool test3 = false || all_tests;
500502
if (test0) {
501503
// Vanilla feasibility relaxation
@@ -531,7 +533,8 @@ TEST_CASE("lp-feasibility-relaxation", "[iis]") {
531533
"===============================\n"
532534
"Local penalties RHS {1, -1, 10}\n"
533535
"===============================\n");
534-
// Now test local penalties
536+
// Now test local penalties, allowing lower bounds to be violated,
537+
// but not upper bounds
535538
//
536539
// constraint 0: normal weight
537540
//
@@ -544,7 +547,7 @@ TEST_CASE("lp-feasibility-relaxation", "[iis]") {
544547
local_rhs_penalty.data());
545548
// Should get slacks (-3, 4, 0)
546549
h.writeSolution("", 1);
547-
REQUIRE(solution.row_value[0] == lp.row_lower_[0] - 3);
550+
REQUIRE(solution.row_value[0] == lp.row_lower_[0] + 3);
548551
REQUIRE(solution.row_value[1] == lp.row_upper_[1] - 4);
549552
REQUIRE(solution.row_value[2] == lp.row_upper_[2]);
550553
}
@@ -566,6 +569,7 @@ TEST_CASE("lp-feasibility-relaxation", "[iis]") {
566569
h.feasibilityRelaxation(1, 1, 0, nullptr, nullptr,
567570
local_rhs_penalty.data());
568571
// Should get slacks (18, 2, -1)
572+
h.writeSolution("", 1);
569573
REQUIRE(solution.row_value[0] == lp.row_lower_[0] + 18);
570574
REQUIRE(solution.row_value[1] == lp.row_upper_[1] - 2);
571575
REQUIRE(solution.row_value[2] == lp.row_upper_[2] + 1);

highs/Highs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1728,7 +1728,7 @@ class Highs {
17281728
HighsStatus getIisInterfaceReturn(const HighsStatus return_status);
17291729

17301730
HighsStatus elasticityFilterReturn(
1731-
const HighsStatus return_status, const bool feasible_model,
1731+
const HighsStatus return_status,
17321732
const std::string& original_model_name, const HighsInt original_num_col,
17331733
const HighsInt original_num_row,
17341734
const std::vector<double>& original_col_cost,

highs/lp_data/HighsInterface.cpp

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,7 +2047,7 @@ HighsStatus Highs::getIisInterface() {
20472047
}
20482048

20492049
HighsStatus Highs::elasticityFilterReturn(
2050-
const HighsStatus return_status, const bool feasible_model,
2050+
const HighsStatus return_status,
20512051
const std::string& original_model_name, const HighsInt original_num_col,
20522052
const HighsInt original_num_row,
20532053
const std::vector<double>& original_col_cost,
@@ -2059,7 +2059,11 @@ HighsStatus Highs::elasticityFilterReturn(
20592059
// LP, so save them
20602060
const bool iis_valid = this->iis_.valid_;
20612061
HighsIis iis;
2062-
if (iis_valid) iis = this->iis_;
2062+
if (iis_valid) {
2063+
iis = this->iis_;
2064+
} else {
2065+
assert(return_status != HighsStatus::kOk);
2066+
}
20632067
double objective_function_value = info_.objective_function_value;
20642068
// Delete any additional rows and columns, and restore the original
20652069
// column costs and bounds
@@ -2108,10 +2112,17 @@ HighsStatus Highs::elasticityFilterReturn(
21082112
getKktFailures(options_, model_, solution_, basis_, info_);
21092113
info_.valid = true;
21102114
}
2111-
// If the model is feasible, then the status of model is not known
2112-
if (feasible_model) this->model_status_ = HighsModelStatus::kNotset;
21132115
// If there was valid HighsIis data, then restore it
2114-
if (iis_valid) this->iis_ = iis;
2116+
if (iis_valid) {
2117+
// If the model is feasible, then the status of model is not known
2118+
if (iis.status_ == kIisModelStatusFeasible)
2119+
this->model_status_ = HighsModelStatus::kNotset;
2120+
this->iis_ = iis;
2121+
} else {
2122+
// No valid HighsIis should imply a runtime error, so ensure that
2123+
// no misleading model status is set
2124+
this->model_status_ = HighsModelStatus::kNotset;
2125+
}
21152126
return return_status;
21162127
}
21172128

@@ -2434,20 +2445,24 @@ HighsStatus Highs::elasticityFilter(const double global_lower_penalty,
24342445
return run_status;
24352446
};
24362447

2448+
// Solve the elastic LP
24372449
run_status = solveLp();
24382450

24392451
if (run_status != HighsStatus::kOk)
2440-
return elasticityFilterReturn(run_status, false, original_model_name,
2452+
return elasticityFilterReturn(run_status, original_model_name,
24412453
original_num_col, original_num_row,
24422454
original_col_cost, original_col_lower,
24432455
original_col_upper, original_integrality);
24442456
if (kIisDevReport) this->writeSolution("", kSolutionStylePretty);
24452457
// Model status should be optimal, unless model is unbounded
24462458
assert(this->model_status_ == HighsModelStatus::kOptimal ||
24472459
this->model_status_ == HighsModelStatus::kUnbounded);
2448-
2449-
if (!get_iis)
2450-
return elasticityFilterReturn(HighsStatus::kOk, false, original_model_name,
2460+
this->iis_.valid_ = true;
2461+
this->iis_.status_ = this->info_.objective_function_value > 0 ?
2462+
kIisModelStatusInfeasible :
2463+
kIisModelStatusFeasible;
2464+
if (!get_iis)
2465+
return elasticityFilterReturn(HighsStatus::kOk, original_model_name,
24512466
original_num_col, original_num_row,
24522467
original_col_cost, original_col_lower,
24532468
original_col_upper, original_integrality);
@@ -2458,7 +2473,6 @@ HighsStatus Highs::elasticityFilter(const double global_lower_penalty,
24582473
const HighsSolution& solution = this->getSolution();
24592474
// Now fix e-variables that are positive and re-solve until e-LP is infeasible
24602475
HighsInt loop_k = 0;
2461-
bool feasible_model = false;
24622476
for (;;) {
24632477
if (kIisDevReport)
24642478
printf("\nElasticity filter pass %d\n==============\n", int(loop_k));
@@ -2501,13 +2515,13 @@ HighsStatus Highs::elasticityFilter(const double global_lower_penalty,
25012515
}
25022516
if (num_fixed == 0) {
25032517
// No elastic variables were positive, so problem is feasible
2504-
feasible_model = true;
2518+
this->iis_.status_ = kIisModelStatusFeasible;
25052519
break;
25062520
}
25072521
HighsStatus run_status = solveLp();
25082522
if (run_status != HighsStatus::kOk)
25092523
return elasticityFilterReturn(
2510-
run_status, feasible_model, original_model_name, original_num_col,
2524+
run_status, original_model_name, original_num_col,
25112525
original_num_row, original_col_cost, original_col_lower,
25122526
original_col_upper, original_integrality);
25132527
if (kIisDevReport) this->writeSolution("", kSolutionStylePretty);
@@ -2553,7 +2567,7 @@ HighsStatus Highs::elasticityFilter(const double global_lower_penalty,
25532567
}
25542568
}
25552569
HighsInt num_iis_row = iis.row_index_.size();
2556-
if (feasible_model) {
2570+
if (iis.status_ == kIisModelStatusFeasible) {
25572571
assert(num_enforced_col_ecol == 0 && num_enforced_row_ecol == 0);
25582572
assert(num_iis_row == 0);
25592573
}
@@ -2571,17 +2585,15 @@ HighsStatus Highs::elasticityFilter(const double global_lower_penalty,
25712585

25722586
iis.valid_ = true;
25732587
iis.strategy_ = this->options_.iis_strategy;
2574-
if (feasible_model) {
2575-
iis.status_ = kIisModelStatusFeasible;
2588+
if (iis.status_ == kIisModelStatusFeasible)
25762589
return elasticityFilterReturn(
2577-
HighsStatus::kOk, feasible_model, original_model_name, original_num_col,
2590+
HighsStatus::kOk, original_model_name, original_num_col,
25782591
original_num_row, original_col_cost, original_col_lower,
25792592
original_col_upper, original_integrality);
2580-
}
2581-
assert(!feasible_model);
25822593
// Model is infeasible because there are (at least) a positive
25832594
// number of rows in the infeasibility set. Hence the IIS status is
25842595
// reducible
2596+
assert(this->iis_.status_ > kIisModelStatusFeasible);
25852597
assert(num_iis_row > 0);
25862598
iis.status_ = kIisModelStatusReducible;
25872599

@@ -2652,7 +2664,7 @@ HighsStatus Highs::elasticityFilter(const double global_lower_penalty,
26522664
assert(iis.row_bound_.size() == iis.row_index_.size());
26532665
for (HighsInt iX = 0; iX < num_iis_row; iX++) assert(iis.row_bound_[iX] >= 0);
26542666
return elasticityFilterReturn(
2655-
HighsStatus::kOk, feasible_model, original_model_name, original_num_col,
2667+
HighsStatus::kOk, original_model_name, original_num_col,
26562668
original_num_row, original_col_cost, original_col_lower,
26572669
original_col_upper, original_integrality);
26582670
}

0 commit comments

Comments
 (0)