Skip to content

Commit 9356ff2

Browse files
author
hbagheri
committed
Added test point for iis_time_limit
1 parent 65e4e51 commit 9356ff2

File tree

4 files changed

+90
-26
lines changed

4 files changed

+90
-26
lines changed

check/TestIis.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,50 @@ TEST_CASE("lp-get-iis-avgas", "[iis]") {
470470
// HighsModelStatus::kOptimal);
471471
}
472472

473+
TEST_CASE("lp-get-iis-time-limit", "[iis]") {
474+
// Test that setting time limit to zero causes getIis() to return
475+
// an error with an invalid and empty IIS
476+
//
477+
// Using forest6 model which is known to be infeasible, but with
478+
// time_limit = 0, the IIS computation should fail immediately
479+
//
480+
// Expected behavior:
481+
// - getIis() returns HighsStatus::kError
482+
// - IIS is marked as invalid (valid_ = false)
483+
// - IIS contains no rows or columns
484+
485+
std::string model_file =
486+
std::string(HIGHS_DIR) + "/check/instances/forest6.mps";
487+
488+
Highs highs;
489+
highs.setOptionValue("output_flag", dev_run);
490+
491+
REQUIRE(highs.readModel(model_file) == HighsStatus::kOk);
492+
493+
// Set iis time limit to zero to force immediate timeout
494+
highs.setOptionValue("iis_time_limit", 0.0);
495+
496+
// Use kIisStrategyFromLp strategy - this requires solving the LP
497+
// which should fail due to time limit
498+
highs.setOptionValue("iis_strategy", kIisStrategyFromLp);
499+
500+
HighsIis iis;
501+
// Should return error due to time limit being reached
502+
REQUIRE(highs.getIis(iis) == HighsStatus::kError);
503+
504+
// IIS should be invalid since computation could not complete
505+
REQUIRE(iis.valid_ == false);
506+
507+
// IIS status should be kIisModelStatusTimeLimit
508+
REQUIRE(iis.status_ == kIisModelStatusTimeLimit);
509+
510+
// IIS should be empty - no rows or columns identified
511+
REQUIRE(iis.col_index_.size() == 0);
512+
REQUIRE(iis.row_index_.size() == 0);
513+
514+
highs.resetGlobalScheduler(true);
515+
}
516+
473517
TEST_CASE("lp-feasibility-relaxation", "[iis]") {
474518
// Using infeasible MIP from AMPL documentation
475519
//

highs/lp_data/HighsIis.cpp

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -502,14 +502,45 @@ void HighsIis::setStatus(const HighsLp& lp) {
502502
this->row_status_[this->row_index_[iisRow]] = in_is_status;
503503
}
504504

505+
HighsInt HighsIis::determineBoundStatus(const double lower, const double upper,
506+
const bool is_row) const {
507+
HighsInt iss_bound_status = kIisBoundStatusNull;
508+
if (lower <= -kHighsInf) {
509+
if (upper >= kHighsInf) {
510+
if (is_row) {
511+
// Free rows can be dropped
512+
iss_bound_status = kIisBoundStatusDropped;
513+
} else {
514+
// Free columns can only be dropped if they are empty
515+
iss_bound_status = kIisBoundStatusFree;
516+
}
517+
} else {
518+
iss_bound_status = kIisBoundStatusUpper;
519+
}
520+
} else {
521+
if (upper >= kHighsInf) {
522+
iss_bound_status = kIisBoundStatusLower;
523+
} else {
524+
// FX or BX
525+
iss_bound_status = kIisBoundStatusBoxed;
526+
}
527+
}
528+
assert(iss_bound_status != kIisBoundStatusNull);
529+
return iss_bound_status;
530+
}
531+
505532
HighsStatus HighsIis::compute(const HighsLp& lp, const HighsOptions& options,
506533
const HighsBasis* basis) {
507534
const HighsLogOptions& log_options = options.log_options;
508535
const bool col_priority = kIisStrategyColPriority & options.iis_strategy;
509536
const bool row_priority = !col_priority;
510537
// Initially all columns and rows are candidates for the IIS
511-
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++) this->addCol(iCol);
512-
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++) this->addRow(iRow);
538+
for (HighsInt iCol = 0; iCol < lp.num_col_; iCol++)
539+
this->addCol(iCol, this->determineBoundStatus(lp.col_lower_[iCol],
540+
lp.col_upper_[iCol], false));
541+
for (HighsInt iRow = 0; iRow < lp.num_row_; iRow++)
542+
this->addRow(iRow, this->determineBoundStatus(lp.row_lower_[iRow],
543+
lp.row_upper_[iRow], true));
513544
Highs highs;
514545
const HighsInfo& info = highs.getInfo();
515546
highs.passOptions(options);
@@ -644,8 +675,12 @@ HighsStatus HighsIis::compute(const HighsLp& lp, const HighsOptions& options,
644675
run_status = solveLp();
645676
// If we fail to establish infeasibility, return the initial subset
646677
if (run_status != HighsStatus::kOk) {
678+
this->valid_ = true;
679+
this->strategy_ = options.iis_strategy;
647680
if (highs.getModelStatus() == HighsModelStatus::kTimeLimit) {
648681
this->status_ = IisModelStatus::kIisModelStatusTimeLimit;
682+
} else {
683+
this->status_ = IisModelStatus::kIisModelStatusReducible;
649684
}
650685
return HighsStatus::kWarning;
651686
}
@@ -669,8 +704,8 @@ HighsStatus HighsIis::compute(const HighsLp& lp, const HighsOptions& options,
669704
continue;
670705
double lower = row_deletion ? lp.row_lower_[iX] : lp.col_lower_[iX];
671706
double upper = row_deletion ? lp.row_upper_[iX] : lp.col_upper_[iX];
672-
// Record whether the upper bound has been dropped due to the lower bound
673-
// being kept
707+
// Record whether the upper bound has been dropped due to the lower
708+
// bound being kept
674709
if (lower > -kHighsInf && iis_status != kIisModelStatusTimeLimit) {
675710
// Drop the lower bound temporarily
676711
bool drop_lower = true;
@@ -713,28 +748,8 @@ HighsStatus HighsIis::compute(const HighsLp& lp, const HighsOptions& options,
713748
assert(check_lower == lower);
714749
assert(check_upper == upper);
715750
}
716-
HighsInt iss_bound_status = kIisBoundStatusNull;
717-
if (lower <= -kHighsInf) {
718-
if (upper >= kHighsInf) {
719-
if (row_deletion) {
720-
// Free rows can be dropped
721-
iss_bound_status = kIisBoundStatusDropped;
722-
} else {
723-
// Free columns can only be dropped if they are empty
724-
iss_bound_status = kIisBoundStatusFree;
725-
}
726-
} else {
727-
iss_bound_status = kIisBoundStatusUpper;
728-
}
729-
} else {
730-
if (upper >= kHighsInf) {
731-
iss_bound_status = kIisBoundStatusLower;
732-
} else {
733-
// FX or BX
734-
iss_bound_status = kIisBoundStatusBoxed;
735-
}
736-
}
737-
assert(iss_bound_status != kIisBoundStatusNull);
751+
HighsInt iss_bound_status =
752+
this->determineBoundStatus(lower, upper, row_deletion);
738753
if (row_deletion) {
739754
this->row_bound_[iX] = iss_bound_status;
740755
} else {

highs/lp_data/HighsIis.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ class HighsIis {
8282
void setLp(const HighsLp& lp);
8383
HighsInt nonIsStatus() const;
8484
void setStatus(const HighsLp& lp);
85+
HighsInt determineBoundStatus(const double lower, const double upper,
86+
const bool is_row) const;
8587

8688
HighsStatus compute(const HighsLp& lp, const HighsOptions& options,
8789
const HighsBasis* basis = nullptr);

highs/lp_data/HighsInterface.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1976,11 +1976,13 @@ HighsStatus Highs::getIisInterface() {
19761976
// No IIS exists, so validate the empty HighsIis instance
19771977
this->iis_.valid_ = true;
19781978
this->iis_.status_ = kIisModelStatusFeasible;
1979+
this->iis_.strategy_ = options_.iis_strategy;
19791980
return this->getIisInterfaceReturn(HighsStatus::kOk, original_options,
19801981
original_callback);
19811982
} else if (this->model_status_ == HighsModelStatus::kTimeLimit) {
19821983
// Time limit reached
19831984
this->iis_.status_ = kIisModelStatusTimeLimit;
1985+
this->iis_.strategy_ = options_.iis_strategy;
19841986
return this->getIisInterfaceReturn(HighsStatus::kError, original_options,
19851987
original_callback);
19861988
} else if (this->model_status_ != HighsModelStatus::kInfeasible) {
@@ -1989,6 +1991,7 @@ HighsStatus Highs::getIisInterface() {
19891991
highsLogUser(options_.log_options, HighsLogType::kError,
19901992
"Can not compute IIS for a model with status %s\n",
19911993
this->modelStatusToString(this->model_status_).c_str());
1994+
this->iis_.strategy_ = options_.iis_strategy;
19921995
return this->getIisInterfaceReturn(HighsStatus::kError, original_options,
19931996
original_callback);
19941997
}

0 commit comments

Comments
 (0)