Skip to content

Commit a030aad

Browse files
author
Julian Hall
committed
Removed removeSlacks presolve reduction as, without costs, it is a duplication of zeroCostSingleton reduction
1 parent 28b4ebc commit a030aad

7 files changed

Lines changed: 7 additions & 192 deletions

File tree

check/TestPresolve.cpp

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -638,46 +638,6 @@ TEST_CASE("write-presolved-model", "[highs_test_presolve]") {
638638
highs1.resetGlobalScheduler(true);
639639
}
640640

641-
TEST_CASE("presolve-slacks", "[highs_test_presolve]") {
642-
// This LP reduces to empty, because the equation is a doubleton
643-
HighsLp lp;
644-
lp.num_col_ = 2;
645-
lp.num_row_ = 1;
646-
lp.col_cost_ = {1, 0};
647-
lp.col_lower_ = {0, 0};
648-
lp.col_upper_ = {kHighsInf, kHighsInf};
649-
lp.row_lower_ = {1};
650-
lp.row_upper_ = {1};
651-
lp.a_matrix_.start_ = {0, 1, 2};
652-
lp.a_matrix_.index_ = {0, 0};
653-
lp.a_matrix_.value_ = {1, 1};
654-
Highs h;
655-
h.setOptionValue("output_flag", dev_run);
656-
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
657-
REQUIRE(h.presolve() == HighsStatus::kOk);
658-
REQUIRE(h.getPresolvedLp().num_col_ == 0);
659-
REQUIRE(h.getPresolvedLp().num_row_ == 0);
660-
661-
lp.num_col_ = 4;
662-
lp.num_row_ = 2;
663-
lp.col_cost_ = {-10, -25, 0, 0};
664-
lp.col_lower_ = {0, 0, 0, 0};
665-
lp.col_upper_ = {kHighsInf, kHighsInf, kHighsInf, kHighsInf};
666-
lp.row_lower_ = {80, 120};
667-
lp.row_upper_ = {80, 120};
668-
lp.a_matrix_.start_ = {0, 2, 4, 5, 6};
669-
lp.a_matrix_.index_ = {0, 1, 0, 1, 0, 1};
670-
lp.a_matrix_.value_ = {1, 1, 2, 4, 1, 1};
671-
REQUIRE(h.setOptionValue("presolve_remove_slacks", true) == HighsStatus::kOk);
672-
REQUIRE(h.passModel(lp) == HighsStatus::kOk);
673-
REQUIRE(h.run() == HighsStatus::kOk);
674-
REQUIRE(h.presolve() == HighsStatus::kOk);
675-
REQUIRE(h.getPresolvedLp().num_col_ == 2);
676-
REQUIRE(h.getPresolvedLp().num_row_ == 2);
677-
678-
h.resetGlobalScheduler(true);
679-
}
680-
681641
TEST_CASE("presolve-issue-2095", "[highs_test_presolve]") {
682642
std::string model_file =
683643
std::string(HIGHS_DIR) + "/check/instances/issue-2095.mps";

highs/lp_data/HighsOptions.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,9 +1691,10 @@ class HighsOptions : public HighsOptionsStruct {
16911691
advanced, &presolve_rule_logging, false);
16921692
records.push_back(record_bool);
16931693

1694-
record_bool = new OptionRecordBool("presolve_remove_slacks",
1695-
"Remove slacks after presolve", advanced,
1696-
&presolve_remove_slacks, false);
1694+
record_bool =
1695+
new OptionRecordBool("presolve_remove_slacks",
1696+
"Remove slacks after presolve: redundant option!",
1697+
advanced, &presolve_remove_slacks, false);
16971698
records.push_back(record_bool);
16981699

16991700
record_bool =

highs/presolve/HPresolve.cpp

Lines changed: 1 addition & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6547,13 +6547,7 @@ HPresolve::Result HPresolve::presolve(HighsPostsolveStack& postsolve_stack) {
65476547
break;
65486548
}
65496549

6550-
if (!reducedToEmpty()) {
6551-
// Now consider removing slacks
6552-
if (options->presolve_remove_slacks)
6553-
HPRESOLVE_CHECKED_CALL(removeSlacks(postsolve_stack));
6554-
6555-
report();
6556-
}
6550+
if (!reducedToEmpty()) report();
65576551
} else {
65586552
highsLogUser(options->log_options, HighsLogType::kInfo,
65596553
"\nPresolve is switched off\n");
@@ -6562,49 +6556,6 @@ HPresolve::Result HPresolve::presolve(HighsPostsolveStack& postsolve_stack) {
65626556
return presolveReturn();
65636557
}
65646558

6565-
HPresolve::Result HPresolve::removeSlacks(
6566-
HighsPostsolveStack& postsolve_stack) {
6567-
// SingletonColumns data structure appears not to be retained
6568-
// throughout presolve
6569-
for (HighsInt iCol = 0; iCol != model->num_col_; ++iCol) {
6570-
if (colDeleted[iCol]) continue;
6571-
if (colsize[iCol] != 1) continue;
6572-
// Only do this for pure slacks as cost coefficient changes lead
6573-
// to dual postsolve errors since the basic costs may well change,
6574-
// leading to changes in the row duals that cannot be determined
6575-
if (model->col_cost_[iCol]) continue;
6576-
if (model->integrality_[iCol] == HighsVarType::kInteger) continue;
6577-
HighsInt coliter = colhead[iCol];
6578-
HighsInt iRow = Arow[coliter];
6579-
assert(Acol[coliter] == iCol);
6580-
assert(!rowDeleted[iRow]);
6581-
if (!isEquation(iRow)) continue;
6582-
double lower = model->col_lower_[iCol];
6583-
double upper = model->col_upper_[iCol];
6584-
double rhs = model->row_lower_[iRow];
6585-
double coeff = Avalue[coliter];
6586-
assert(coeff);
6587-
// Slack is s = (rhs - a^Tx)/coeff
6588-
//
6589-
// Constraint bounds become:
6590-
//
6591-
// For coeff > 0 [rhs - coeff * upper, rhs - coeff * lower]
6592-
//
6593-
// For coeff < 0 [rhs - coeff * lower, rhs - coeff * upper]
6594-
model->row_lower_[iRow] =
6595-
coeff > 0 ? rhs - coeff * upper : rhs - coeff * lower;
6596-
model->row_upper_[iRow] =
6597-
coeff > 0 ? rhs - coeff * lower : rhs - coeff * upper;
6598-
//
6599-
postsolve_stack.slackColSubstitution(iRow, iCol, rhs, getRowVector(iRow));
6600-
6601-
markColDeleted(iCol);
6602-
6603-
unlink(coliter);
6604-
}
6605-
return Result::kOk;
6606-
}
6607-
66086559
HPresolve::Result HPresolve::checkTimeLimit() {
66096560
assert(timer);
66106561
if (options->time_limit < kHighsInf && timer->read() >= options->time_limit)

highs/presolve/HPresolve.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -352,8 +352,6 @@ class HPresolve {
352352

353353
Result presolve(HighsPostsolveStack& postsolve_stack);
354354

355-
Result removeSlacks(HighsPostsolveStack& postsolve_stack);
356-
357355
Result checkTimeLimit();
358356

359357
Result checkLimits(HighsPostsolveStack& postsolve_stack);

highs/presolve/HPresolveAnalysis.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,8 @@ void HPresolveAnalysis::setup(const HighsLp* model_,
3232
presolve_clocks_ = clock;
3333
}
3434

35-
// Allow logging if option is set and presolve_remove_slacks option
36-
// is not set (since it's not and official pesolve rule with an
37-
// entry in PresolveRuleType) and LP presolve is being used
38-
allow_logging_ = options_->presolve_rule_logging &&
39-
!options->presolve_remove_slacks && lp_presolve;
35+
// Allow logging if option is set and LP presolve is being used
36+
allow_logging_ = options_->presolve_rule_logging && lp_presolve;
4037
// NB logging_on_ is also used to determine whether logging has
4138
// started to prevent double-accounting. Specifically,
4239
//

highs/presolve/HighsPostsolveStack.cpp

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,64 +1294,6 @@ void HighsPostsolveStack::DuplicateColumn::transformToPresolvedSpace(
12941294
primalSol[col] = primalSol[col] + colScale * primalSol[duplicateCol];
12951295
}
12961296

1297-
void HighsPostsolveStack::SlackColSubstitution::undo(
1298-
const HighsOptions& options, const std::vector<Nonzero>& rowValues,
1299-
HighsSolution& solution, HighsBasis& basis) {
1300-
bool debug_print = false;
1301-
1302-
// compute primal values
1303-
double colCoef = 0;
1304-
HighsCDouble rowValue = 0;
1305-
for (const auto& rowVal : rowValues) {
1306-
if (rowVal.index == col)
1307-
colCoef = rowVal.value;
1308-
else
1309-
rowValue += rowVal.value * solution.col_value[rowVal.index];
1310-
}
1311-
1312-
assert(colCoef != 0);
1313-
// Row values aren't fully postsolved, so why do this?
1314-
solution.row_value[row] =
1315-
static_cast<double>(rowValue + colCoef * solution.col_value[col]);
1316-
1317-
solution.col_value[col] = static_cast<double>((rhs - rowValue) / colCoef);
1318-
1319-
// If no dual values requested, return here
1320-
if (!solution.dual_valid) return;
1321-
1322-
// Row retains its dual value, and column has this dual value
1323-
solution.col_dual[col] = -solution.row_dual[row] * colCoef;
1324-
1325-
// Set basis status if necessary
1326-
if (!basis.valid) return;
1327-
1328-
// If row is basic, then slack is basic, otherwise row retains its status
1329-
HighsBasisStatus save_row_basis_status = basis.row_status[row];
1330-
if (basis.row_status[row] == HighsBasisStatus::kBasic) {
1331-
basis.col_status[col] = HighsBasisStatus::kBasic;
1332-
basis.row_status[row] =
1333-
computeRowStatus(solution.row_dual[row], RowType::kEq);
1334-
} else if (basis.row_status[row] == HighsBasisStatus::kLower) {
1335-
basis.col_status[col] =
1336-
colCoef > 0 ? HighsBasisStatus::kUpper : HighsBasisStatus::kLower;
1337-
} else {
1338-
basis.col_status[col] =
1339-
colCoef > 0 ? HighsBasisStatus::kLower : HighsBasisStatus::kUpper;
1340-
}
1341-
if (debug_print)
1342-
printf(
1343-
"HighsPostsolveStack::SlackColSubstitution::undo OgRowStatus = %s; "
1344-
"RowStatus = %s; ColStatus = %s\n",
1345-
utilBasisStatusToString(save_row_basis_status).full_.c_str(),
1346-
utilBasisStatusToString(basis.row_status[row]).full_.c_str(),
1347-
utilBasisStatusToString(basis.col_status[col]).full_.c_str());
1348-
if (basis.col_status[col] == HighsBasisStatus::kLower) {
1349-
assert(solution.col_dual[col] > -options.dual_feasibility_tolerance);
1350-
} else if (basis.col_status[col] == HighsBasisStatus::kUpper) {
1351-
assert(solution.col_dual[col] < options.dual_feasibility_tolerance);
1352-
}
1353-
}
1354-
13551297
void HighsPostsolveStack::FourierMotzkinObjCol::transformToPresolvedSpace(
13561298
const std::vector<Nonzero>& costEntries,
13571299
std::vector<double>& primalSol) const {

highs/presolve/HighsPostsolveStack.h

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -283,16 +283,6 @@ class HighsPostsolveStack {
283283
void transformToPresolvedSpace(std::vector<double>& primalSol) const;
284284
};
285285

286-
struct SlackColSubstitution {
287-
double rhs;
288-
HighsInt row;
289-
HighsInt col;
290-
291-
void undo(const HighsOptions& options,
292-
const std::vector<Nonzero>& rowValues, HighsSolution& solution,
293-
HighsBasis& basis);
294-
};
295-
296286
struct ZeroObjSingletonContinuousCol {
297287
double origRowLower;
298288
double origRowUpper;
@@ -325,7 +315,6 @@ class HighsPostsolveStack {
325315
kForcingColumnRemovedRow,
326316
kDuplicateRow,
327317
kDuplicateColumn,
328-
kSlackColSubstitution,
329318
kZeroObjSingletonContinuousCol,
330319
kFourierMotzkinBlock,
331320
kFourierMotzkinObjCol,
@@ -412,9 +401,6 @@ class HighsPostsolveStack {
412401
case ReductionType::kDuplicateColumn: {
413402
return "Duplicate column";
414403
}
415-
case ReductionType::kSlackColSubstitution: {
416-
return "Slack col substitution";
417-
}
418404
case ReductionType::kImpliedEquation: {
419405
return "Implied equation";
420406
}
@@ -607,19 +593,6 @@ class HighsPostsolveStack {
607593
reductionAdded(ReductionType::kFreeColSubstitution);
608594
}
609595

610-
template <typename RowStorageFormat>
611-
void slackColSubstitution(HighsInt row, HighsInt col, double rhs,
612-
const HighsMatrixSlice<RowStorageFormat>& rowVec) {
613-
rowValues.clear();
614-
for (const HighsSliceNonzero& rowVal : rowVec)
615-
rowValues.emplace_back(origColIndex[rowVal.index()], rowVal.value());
616-
617-
reductionValues.push(
618-
SlackColSubstitution{rhs, origRowIndex[row], origColIndex[col]});
619-
reductionValues.push(rowValues);
620-
reductionAdded(ReductionType::kSlackColSubstitution);
621-
}
622-
623596
template <typename RowStorageFormat>
624597
void zeroCostSingleton(HighsInt row, HighsInt col, double origRowLower,
625598
double origRowUpper, double new_row_lb,
@@ -1284,13 +1257,6 @@ class HighsPostsolveStack {
12841257
reduction.undo(options, solution, basis);
12851258
break;
12861259
}
1287-
case ReductionType::kSlackColSubstitution: {
1288-
SlackColSubstitution reduction;
1289-
reductionValues_.pop(rowValues_);
1290-
reductionValues_.pop(reduction);
1291-
reduction.undo(options, rowValues_, solution, basis);
1292-
break;
1293-
}
12941260
case ReductionType::kZeroObjSingletonContinuousCol: {
12951261
ZeroObjSingletonContinuousCol reduction;
12961262
reductionValues.pop(rowValues);

0 commit comments

Comments
 (0)