Skip to content

Commit cd202e8

Browse files
authored
Merge pull request #2680 from ERGO-Code/col-integrality-helpers
Add col integrality helpers
2 parents 498eae1 + 9fa4d0c commit cd202e8

12 files changed

+52
-50
lines changed

highs/mip/HighsCliqueTable.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -869,7 +869,7 @@ void HighsCliqueTable::extractCliques(
869869
HighsCDouble colub =
870870
HighsCDouble(globaldom.col_upper_[col]) - globaldom.col_lower_[col];
871871
HighsCDouble implcolub = impliedub / vals[perm[j]];
872-
if (mipsolver.variableType(col) != HighsVarType::kContinuous)
872+
if (mipsolver.isColIntegral(col))
873873
implcolub =
874874
std::floor(double(implcolub) + mipsolver.mipdata_->feastol);
875875

@@ -1112,7 +1112,7 @@ void HighsCliqueTable::extractCliquesFromCut(const HighsMipSolver& mipsolver,
11121112
}
11131113

11141114
for (HighsInt i = 0; i != len; ++i) {
1115-
if (mipsolver.variableType(inds[i]) == HighsVarType::kContinuous) continue;
1115+
if (mipsolver.isColContinuous(inds[i])) continue;
11161116

11171117
double boundVal = double((rhs - minact) / vals[i]);
11181118
if (vals[i] > 0) {
@@ -1157,7 +1157,7 @@ void HighsCliqueTable::extractCliquesFromCut(const HighsMipSolver& mipsolver,
11571157
double implcolub = double(impliedActivity +
11581158
vals[perm[j]] * globaldom.col_lower_[col]) /
11591159
vals[perm[j]];
1160-
if (mipsolver.variableType(col) != HighsVarType::kContinuous)
1160+
if (mipsolver.isColIntegral(col))
11611161
implcolub = std::floor(implcolub + mipsolver.mipdata_->feastol);
11621162

11631163
if (implcolub < globaldom.col_upper_[col] - feastol) {
@@ -1182,7 +1182,7 @@ void HighsCliqueTable::extractCliquesFromCut(const HighsMipSolver& mipsolver,
11821182
double implcollb = double(impliedActivity +
11831183
vals[perm[j]] * globaldom.col_upper_[col]) /
11841184
vals[perm[j]];
1185-
if (mipsolver.variableType(col) != HighsVarType::kContinuous)
1185+
if (mipsolver.isColIntegral(col))
11861186
implcollb = std::ceil(implcollb - mipsolver.mipdata_->feastol);
11871187

11881188
if (implcollb > globaldom.col_lower_[col] + feastol) {

highs/mip/HighsDomain.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,7 +1333,7 @@ double HighsDomain::adjustedUb(HighsInt col, HighsCDouble boundVal,
13331333
bool& accept) const {
13341334
double bound;
13351335

1336-
if (mipsolver->variableType(col) != HighsVarType::kContinuous) {
1336+
if (mipsolver->isColIntegral(col)) {
13371337
bound = static_cast<double>(floor(boundVal + mipsolver->mipdata_->feastol));
13381338
accept = bound < col_upper_[col] &&
13391339
col_upper_[col] - bound >
@@ -1365,7 +1365,7 @@ double HighsDomain::adjustedLb(HighsInt col, HighsCDouble boundVal,
13651365
bool& accept) const {
13661366
double bound;
13671367

1368-
if (mipsolver->variableType(col) != HighsVarType::kContinuous) {
1368+
if (mipsolver->isColIntegral(col)) {
13691369
bound = static_cast<double>(ceil(boundVal - mipsolver->mipdata_->feastol));
13701370
accept = bound > col_lower_[col] &&
13711371
bound - col_lower_[col] >
@@ -2624,8 +2624,7 @@ void HighsDomain::tightenCoefficients(HighsInt* inds, double* vals,
26242624
HighsCDouble upper = rhs;
26252625
HighsInt tightened = 0;
26262626
for (HighsInt i = 0; i != len; ++i) {
2627-
if (mipsolver->variableType(inds[i]) == HighsVarType::kContinuous)
2628-
continue;
2627+
if (mipsolver->isColContinuous(inds[i])) continue;
26292628
if (vals[i] > maxabscoef) {
26302629
HighsCDouble delta = vals[i] - maxabscoef;
26312630
upper -= delta * col_upper_[inds[i]];
@@ -2677,13 +2676,13 @@ HighsDomainChange HighsDomain::flip(const HighsDomainChange& domchg) const {
26772676
if (domchg.boundtype == HighsBoundType::kLower) {
26782677
HighsDomainChange flipped{domchg.boundval - mipsolver->mipdata_->feastol,
26792678
domchg.column, HighsBoundType::kUpper};
2680-
if (mipsolver->variableType(domchg.column) != HighsVarType::kContinuous)
2679+
if (mipsolver->isColIntegral(domchg.column))
26812680
flipped.boundval = std::floor(flipped.boundval);
26822681
return flipped;
26832682
} else {
26842683
HighsDomainChange flipped{domchg.boundval + mipsolver->mipdata_->feastol,
26852684
domchg.column, HighsBoundType::kLower};
2686-
if (mipsolver->variableType(domchg.column) != HighsVarType::kContinuous)
2685+
if (mipsolver->isColIntegral(domchg.column))
26872686
flipped.boundval = std::ceil(flipped.boundval);
26882687
return flipped;
26892688
}

highs/mip/HighsDomain.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,7 @@ class HighsDomain {
440440

441441
void removeContinuousChangedCols() {
442442
for (HighsInt i : changedcols_)
443-
changedcolsflags_[i] =
444-
mipsolver->variableType(i) != HighsVarType::kContinuous;
443+
changedcolsflags_[i] = mipsolver->isColIntegral(i);
445444

446445
changedcols_.erase(
447446
std::remove_if(changedcols_.begin(), changedcols_.end(),
@@ -611,12 +610,12 @@ class HighsDomain {
611610
double getMinCutActivity(const HighsCutPool& cutpool, HighsInt cut) const;
612611

613612
bool isBinary(HighsInt col) const {
614-
return mipsolver->variableType(col) != HighsVarType::kContinuous &&
615-
col_lower_[col] == 0.0 && col_upper_[col] == 1.0;
613+
return mipsolver->isColIntegral(col) && col_lower_[col] == 0.0 &&
614+
col_upper_[col] == 1.0;
616615
}
617616

618617
bool isGlobalBinary(HighsInt col) const {
619-
return mipsolver->variableType(col) != HighsVarType::kContinuous &&
618+
return mipsolver->isColIntegral(col) &&
620619
mipsolver->model_->col_lower_[col] == 0.0 &&
621620
mipsolver->model_->col_upper_[col] == 1.0;
622621
}

highs/mip/HighsLpRelaxation.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,7 @@ bool HighsLpRelaxation::computeDualProof(const HighsDomain& globaldomain,
838838

839839
if (!removeValue &&
840840
(globaldomain.col_lower_[i] == globaldomain.col_upper_[i] ||
841-
mipsolver.variableType(i) == HighsVarType::kContinuous)) {
841+
mipsolver.isColContinuous(i))) {
842842
if (val > 0)
843843
removeValue =
844844
lpsolver.getSolution().col_value[i] - globaldomain.col_lower_[i] <=
@@ -948,7 +948,7 @@ void HighsLpRelaxation::storeDualInfProof() {
948948

949949
if (!removeValue &&
950950
(globaldomain.col_lower_[i] == globaldomain.col_upper_[i] ||
951-
mipsolver.variableType(i) == HighsVarType::kContinuous)) {
951+
mipsolver.isColContinuous(i))) {
952952
// remove continuous entries and globally fixed entries whenever the
953953
// local LP's bound is not tighter than the global bound
954954
if (val > 0)
@@ -1582,7 +1582,7 @@ HighsLpRelaxation::Status HighsLpRelaxation::resolveLp(HighsDomain* domain) {
15821582
fixSol[i] = lpsolver.getLp().col_lower_[i];
15831583
else if (fixSol[i] > lpsolver.getLp().col_upper_[i])
15841584
fixSol[i] = lpsolver.getLp().col_upper_[i];
1585-
else if (mipsolver.variableType(i) != HighsVarType::kContinuous)
1585+
else if (mipsolver.isColIntegral(i))
15861586
fixSol[i] = std::round(fixSol[i]);
15871587
}
15881588

highs/mip/HighsLpRelaxation.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ class HighsLpRelaxation {
211211

212212
bool isColIntegral(HighsInt col) const {
213213
return col < lpsolver.getLp().num_col_
214-
? mipsolver.variableType(col) != HighsVarType::kContinuous
214+
? mipsolver.isColIntegral(col)
215215
: isRowIntegral(col - lpsolver.getLp().num_col_);
216216
}
217217

highs/mip/HighsMipSolver.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,18 @@ class HighsMipSolver {
100100
return model_->integrality_[col];
101101
}
102102

103+
bool isColIntegral(const HighsInt col) const {
104+
return variableType(col) != HighsVarType::kContinuous;
105+
}
106+
107+
bool isColInteger(const HighsInt col) const {
108+
return variableType(col) == HighsVarType::kInteger;
109+
}
110+
111+
bool isColContinuous(const HighsInt col) const {
112+
return variableType(col) == HighsVarType::kContinuous;
113+
}
114+
103115
HighsMipSolver(HighsCallback& callback, const HighsOptions& options,
104116
const HighsLp& lp, const HighsSolution& solution,
105117
bool submip = false, HighsInt submip_level = 0);

highs/mip/HighsMipSolverData.cpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,7 @@ bool HighsMipSolverData::checkSolution(
101101
for (HighsInt i = 0; i != mipsolver.model_->num_col_; ++i) {
102102
if (solution[i] < mipsolver.model_->col_lower_[i] - feastol) return false;
103103
if (solution[i] > mipsolver.model_->col_upper_[i] + feastol) return false;
104-
if (mipsolver.variableType(i) == HighsVarType::kInteger &&
105-
fractionality(solution[i]) > feastol)
104+
if (mipsolver.isColInteger(i) && fractionality(solution[i]) > feastol)
106105
return false;
107106
}
108107

@@ -157,8 +156,7 @@ bool HighsMipSolverData::trySolution(const std::vector<double>& solution,
157156
for (HighsInt i = 0; i != mipsolver.model_->num_col_; ++i) {
158157
if (solution[i] < mipsolver.model_->col_lower_[i] - feastol) return false;
159158
if (solution[i] > mipsolver.model_->col_upper_[i] + feastol) return false;
160-
if (mipsolver.variableType(i) == HighsVarType::kInteger &&
161-
fractionality(solution[i]) > feastol)
159+
if (mipsolver.isColInteger(i) && fractionality(solution[i]) > feastol)
162160
return false;
163161

164162
obj += mipsolver.colCost(i) * solution[i];
@@ -465,15 +463,15 @@ void HighsMipSolverData::finishAnalyticCenterComputation(
465463
HighsDomain::Reason::unspecified());
466464
if (mipsolver.mipdata_->domain.infeasible()) return;
467465
++nfixed;
468-
if (mipsolver.variableType(i) == HighsVarType::kInteger) ++nintfixed;
466+
if (mipsolver.isColInteger(i)) ++nintfixed;
469467
} else if (analyticCenter[i] >=
470468
mipsolver.model_->col_upper_[i] - tolerance) {
471469
mipsolver.mipdata_->domain.changeBound(
472470
HighsBoundType::kLower, i, mipsolver.model_->col_upper_[i],
473471
HighsDomain::Reason::unspecified());
474472
if (mipsolver.mipdata_->domain.infeasible()) return;
475473
++nfixed;
476-
if (mipsolver.variableType(i) == HighsVarType::kInteger) ++nintfixed;
474+
if (mipsolver.isColInteger(i)) ++nintfixed;
477475
}
478476
}
479477
if (nfixed > 0)
@@ -900,10 +898,8 @@ void HighsMipSolverData::runSetup() {
900898
HighsInt end = ARstart_[i + 1];
901899
bool integral = true;
902900
for (HighsInt j = start; j != end; ++j) {
903-
integral =
904-
integral &&
905-
mipsolver.variableType(ARindex_[j]) != HighsVarType::kContinuous &&
906-
fractionality(ARvalue_[j]) <= epsilon;
901+
integral = integral && mipsolver.isColIntegral(ARindex_[j]) &&
902+
fractionality(ARvalue_[j]) <= epsilon;
907903

908904
maxabsval = std::max(maxabsval, std::abs(ARvalue_[j]));
909905
}

highs/mip/HighsModkSeparator.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,7 @@ void HighsModkSeparator::separateLpSolution(HighsLpRelaxation& lpRelaxation,
134134
HighsInt intRowLen = 0;
135135
for (HighsInt i = 0; i < rowlen; ++i) {
136136
if (solval[i] <= mipsolver.mipdata_->feastol) continue;
137-
if (mipsolver.variableType(inds[i]) == HighsVarType::kContinuous)
138-
continue;
137+
if (mipsolver.isColContinuous(inds[i])) continue;
139138
++intRowLen;
140139
}
141140

@@ -151,8 +150,7 @@ void HighsModkSeparator::separateLpSolution(HighsLpRelaxation& lpRelaxation,
151150
if (!lpRelaxation.isRowIntegral(row)) {
152151
scaleVals.clear();
153152
for (HighsInt i = 0; i != rowlen; ++i) {
154-
if (mipsolver.variableType(inds[i]) == HighsVarType::kContinuous)
155-
continue;
153+
if (mipsolver.isColContinuous(inds[i])) continue;
156154
if (solval[i] > mipsolver.mipdata_->feastol) {
157155
scaleVals.push_back(vals[i]);
158156
}
@@ -168,8 +166,7 @@ void HighsModkSeparator::separateLpSolution(HighsLpRelaxation& lpRelaxation,
168166
intrhs = HighsIntegers::nearestInteger(intscale * rhs);
169167

170168
for (HighsInt i = 0; i != rowlen; ++i) {
171-
if (mipsolver.variableType(inds[i]) == HighsVarType::kContinuous)
172-
continue;
169+
if (mipsolver.isColContinuous(inds[i])) continue;
173170
if (solval[i] > mipsolver.mipdata_->feastol) {
174171
intSystemIndex.push_back(inds[i]);
175172
intSystemValue.push_back(

highs/mip/HighsPathSeparator.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,15 @@ void HighsPathSeparator::separateLpSolution(HighsLpRelaxation& lpRelaxation,
8888
HighsInt col = -1;
8989
double val = 0.0;
9090
for (HighsInt j = 0; j != len; ++j) {
91-
if (mip.variableType(rowinds[j]) != HighsVarType::kContinuous) continue;
91+
if (mip.isColIntegral(rowinds[j])) continue;
9292
if (transLp.boundDistance(rowinds[j]) == 0.0) continue;
9393
col = rowinds[j];
9494
val = rowvals[j];
9595
break;
9696
}
9797

9898
assert(col != -1);
99-
assert(mip.variableType(col) == HighsVarType::kContinuous);
99+
assert(mip.isColContinuous(col));
100100
assert(transLp.boundDistance(col) > 0.0);
101101

102102
if (colSubstitutions[col].first != -1) continue;

highs/mip/HighsPrimalHeuristics.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,7 +1495,7 @@ void HighsPrimalHeuristics::feasibilityPump() {
14951495

14961496
auto localdom = mipsolver.mipdata_->domain;
14971497
for (HighsInt i : mipsolver.mipdata_->integer_cols) {
1498-
assert(mipsolver.variableType(i) == HighsVarType::kInteger);
1498+
assert(mipsolver.isColInteger(i));
14991499
double intval = std::floor(roundedsol[i] + randgen.real(0.4, 0.6));
15001500
intval = std::max(intval, localdom.col_lower_[i]);
15011501
intval = std::min(intval, localdom.col_upper_[i]);
@@ -1545,7 +1545,7 @@ void HighsPrimalHeuristics::feasibilityPump() {
15451545
break;
15461546

15471547
for (HighsInt i : mipsolver.mipdata_->integer_cols) {
1548-
assert(mipsolver.variableType(i) == HighsVarType::kInteger);
1548+
assert(mipsolver.isColInteger(i));
15491549

15501550
if (mipsolver.mipdata_->uplocks[i] == 0 ||
15511551
mipsolver.mipdata_->downlocks[i] == 0)

0 commit comments

Comments
 (0)