Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 36 additions & 21 deletions highs/mip/HighsRedcostFixing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -225,34 +225,45 @@ void HighsRedcostFixing::addRootRedcost(const HighsMipSolver& mipsolver,
}
HighsInt maxNumSteps = static_cast<HighsInt>(1ULL << maxNumStepsExp);

auto fitsInt64 = [](double val) {
return val > std::numeric_limits<int64_t>::min() &&
val < std::numeric_limits<int64_t>::max();
};

// lambda for finding lurking bounds
auto findLurkingBounds =
[&](HighsInt col, HighsInt direction, HighsInt bound, HighsInt otherBound,
[&](HighsInt col, HighsInt direction, int64_t bound, int64_t otherBound,
bool isOtherBoundFinite, double lpObjective, double redCost,
HighsInt maxNumSteps, HighsInt maxNumStepsExp,
std::multimap<double, HighsInt>& lurkingBounds,
std::multimap<double, HighsInt>& otherLurkingBounds) {
std::multimap<double, int64_t>& lurkingBounds,
std::multimap<double, int64_t>& otherLurkingBounds) {
if (direction * redCost == kHighsInf) {
lurkingBounds.clear();
otherLurkingBounds.clear();
lurkingBounds.emplace(-kHighsInf, bound);
return;
}

HighsInt lastBound;
int64_t lastBound;
if (!isOtherBoundFinite)
lastBound = bound + direction * maxNumSteps;
else
lastBound = otherBound - direction;

HighsInt step = 1;
HighsInt range = direction * (lastBound - bound);
if (range > maxNumSteps)
step = (range + maxNumSteps - 1) >> maxNumStepsExp;
int64_t step = 1;
uint64_t range = direction > 0 ? static_cast<uint64_t>(lastBound) -
static_cast<uint64_t>(bound)
: static_cast<uint64_t>(bound) -
static_cast<uint64_t>(lastBound);

if (range > static_cast<uint64_t>(maxNumSteps))
step = static_cast<int64_t>(
(range >> maxNumStepsExp) +
((range & (static_cast<uint64_t>(maxNumSteps) - 1)) != 0));
double shift = direction * (1 - 10 * mipsolver.mipdata_->feastol);
step *= direction;

for (HighsInt lurkingBound = bound;
for (int64_t lurkingBound = bound;
direction * lurkingBound <= direction * lastBound;
lurkingBound += step) {
double fracBound = lurkingBound - bound + shift;
Expand Down Expand Up @@ -289,35 +300,39 @@ void HighsRedcostFixing::addRootRedcost(const HighsMipSolver& mipsolver,
};

for (HighsInt col : mipsolver.mipdata_->integral_cols) {
bool lowerFinite =
fitsInt64(mipsolver.mipdata_->getDomain().col_lower_[col]);
bool upperFinite =
fitsInt64(mipsolver.mipdata_->getDomain().col_upper_[col]);
if (lpredcost[col] > mipsolver.mipdata_->feastol) {
// col <= (cutoffbound - lpobj)/redcost + lb
// so for lurkub = lb to ub - 1 we can compute the necessary cutoff
// bound to reach this bound which is:
// lurkub = (cutoffbound - lpobj)/redcost + lb
// cutoffbound = (lurkub - lb) * redcost + lpobj
if (!lowerFinite) continue;
findLurkingBounds(
col, HighsInt{1},
static_cast<HighsInt>(
mipsolver.mipdata_->getDomain().col_lower_[col]),
static_cast<HighsInt>(
mipsolver.mipdata_->getDomain().col_upper_[col]),
mipsolver.mipdata_->getDomain().col_upper_[col] != kHighsInf,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we just replace this line by:

mipsolver.mipdata_->getDomain().col_upper_[col] < kHighsIInf

lpobjective, lpredcost[col], maxNumSteps, maxNumStepsExp,
static_cast<int64_t>(mipsolver.mipdata_->getDomain().col_lower_[col]),
upperFinite ? static_cast<int64_t>(
mipsolver.mipdata_->getDomain().col_upper_[col])
: int64_t{0},
upperFinite, lpobjective, lpredcost[col], maxNumSteps, maxNumStepsExp,
lurkingColUpper[col], lurkingColLower[col]);
} else if (lpredcost[col] < -mipsolver.mipdata_->feastol) {
if (!upperFinite) continue;
// col >= (cutoffbound - lpobj)/redcost + ub
// so for lurklb = lb + 1 to ub we can compute the necessary cutoff
// bound to reach this bound which is:
// lurklb = (cutoffbound - lpobj)/redcost + ub
// cutoffbound = (lurklb - ub) * redcost + lpobj
findLurkingBounds(
col, HighsInt{-1},
static_cast<HighsInt>(
mipsolver.mipdata_->getDomain().col_upper_[col]),
static_cast<HighsInt>(
mipsolver.mipdata_->getDomain().col_lower_[col]),
mipsolver.mipdata_->getDomain().col_lower_[col] != -kHighsInf,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mipsolver.mipdata_->getDomain().col_lower_[col] > -kHighsIInf?

lpobjective, lpredcost[col], maxNumSteps, maxNumStepsExp,
static_cast<int64_t>(mipsolver.mipdata_->getDomain().col_upper_[col]),
lowerFinite ? static_cast<int64_t>(
mipsolver.mipdata_->getDomain().col_lower_[col])
: int64_t{0},
lowerFinite, lpobjective, lpredcost[col], maxNumSteps, maxNumStepsExp,
lurkingColLower[col], lurkingColUpper[col]);
}
}
Expand Down
5 changes: 3 additions & 2 deletions highs/mip/HighsRedcostFixing.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#ifndef HIGHS_REDCOST_FIXING_H_
#define HIGHS_REDCOST_FIXING_H_

#include <cstdint>
#include <map>
#include <vector>

Expand All @@ -23,8 +24,8 @@ class HighsMipSolver;
class HighsLpRelaxation;

class HighsRedcostFixing {
std::vector<std::multimap<double, HighsInt>> lurkingColUpper;
std::vector<std::multimap<double, HighsInt>> lurkingColLower;
std::vector<std::multimap<double, int64_t>> lurkingColUpper;
std::vector<std::multimap<double, int64_t>> lurkingColLower;

public:
std::vector<std::pair<double, HighsDomainChange>> getLurkingBounds(
Expand Down
Loading