Skip to content

Commit 1b97c0c

Browse files
committed
Minor performance improvements. More comments
1 parent e2069d7 commit 1b97c0c

File tree

2 files changed

+35
-15
lines changed

2 files changed

+35
-15
lines changed

highs/mip/HighsCutGeneration.cpp

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ bool HighsCutGeneration::separateLiftedFlowCover() {
558558
ld.d1 = sumC2 + snfr.rhs;
559559

560560
pdqsort_branchless(
561-
ld.m.begin(), ld.m.end(),
561+
ld.m.begin(), ld.m.begin() + ld.r,
562562
[&](const HighsCDouble a, const HighsCDouble b) { return a > b; });
563563

564564
for (HighsInt i = 0; i != ld.r + 1; ++i) {
@@ -1366,7 +1366,7 @@ bool HighsCutGeneration::generateCut(HighsTransformedLp& transLp,
13661366
std::vector<HighsInt> flowCoverInds;
13671367
double flowCoverRhs = rhs_;
13681368
double flowCoverEfficacy = 0;
1369-
if (genFlowCover) {
1369+
if (genFlowCover && !lpRelaxation.getMipSolver().submip) {
13701370
flowCoverVals = vals_;
13711371
flowCoverInds = inds_;
13721372
flowCoverSuccess = tryGenerateFlowCoverCut(
@@ -1610,8 +1610,10 @@ bool HighsCutGeneration::preprocessSNFRelaxation() {
16101610
// reject base inequalities where that is not possible due to unbounded
16111611
// variables
16121612
// 4. Don't consider any inequality with too many non-zeros
1613+
// 5. Don't consider any inequality with too few continuous cols
16131614

16141615
HighsInt numZeros = 0;
1616+
HighsInt numCont = 0;
16151617
double maxact = -feastol;
16161618
double maxAbsVal = 0;
16171619
HighsInt slackOffset = lpRelaxation.getMipSolver().numCol();
@@ -1628,40 +1630,47 @@ bool HighsCutGeneration::preprocessSNFRelaxation() {
16281630
};
16291631

16301632
for (HighsInt i = 0; i < rowlen; ++i) {
1633+
HighsInt col = inds[i];
1634+
double lb = getLb(col);
1635+
double ub = getUb(col);
16311636
maxAbsVal = std::max(std::abs(vals[i]), maxAbsVal);
1632-
if (getLb(inds[i]) == -kHighsInf || getUb(inds[i]) == kHighsInf) {
1637+
if (lb == -kHighsInf || ub == kHighsInf) {
16331638
return false;
16341639
}
1640+
if (!lpRelaxation.isColIntegral(col)) numCont++;
16351641
}
16361642

1643+
if (numCont <= 1) return false;
16371644
scale(maxAbsVal);
16381645

16391646
for (HighsInt i = 0; i != rowlen; ++i) {
16401647
HighsInt col = inds[i];
1648+
double lb = getLb(col);
1649+
double ub = getUb(col);
16411650

16421651
// relax variables with small contributions if possible
1643-
if (std::abs(vals[i]) * (getUb(col) - getLb(col)) <= 10 * feastol) {
1652+
if (std::abs(vals[i]) * (ub - lb) <= 10 * feastol) {
16441653
if (vals[i] < 0) {
1645-
if (getUb(col) == kHighsInf) return false;
1646-
rhs -= vals[i] * getUb(col);
1654+
if (ub == kHighsInf) return false;
1655+
rhs -= vals[i] * ub;
16471656
++numZeros;
16481657
vals[i] = 0.0;
16491658
} else if (vals[i] > 0) {
1650-
if (getLb(col) == -kHighsInf) return false;
1651-
rhs -= vals[i] * getLb(col);
1659+
if (lb == -kHighsInf) return false;
1660+
rhs -= vals[i] * lb;
16521661
++numZeros;
16531662
vals[i] = 0.0;
16541663
}
16551664
}
16561665

16571666
if (vals[i] > 0) {
1658-
maxact += vals[i] * getUb(col);
1667+
maxact += vals[i] * ub;
16591668
} else if (vals[i] < 0) {
1660-
maxact += vals[i] * getLb(col);
1669+
maxact += vals[i] * lb;
16611670
}
16621671
}
16631672

1664-
HighsInt maxLen = 100 + 0.15 * (lpRelaxation.numCols());
1673+
HighsInt maxLen = 0.15 * (lpRelaxation.numCols());
16651674
if (rowlen - numZeros > maxLen) return false;
16661675

16671676
if (numZeros != 0) {
@@ -1737,22 +1746,27 @@ bool HighsCutGeneration::computeFlowCover() {
17371746
if (capacity < feastol) return false;
17381747

17391748
// Solve a knapsack greedily to assign items to C+, C-, N+\C+, N-\C-
1749+
// z_j is a binary variable deciding whether the item goes into the knapsack
1750+
// max sum_{j in N+} ( x_j - 1 ) z_j + sum_{j in N-} x_j
1751+
// sum_{j in N+} u'_j z_j + sum_{j in N-} u'_j z_j < -b + sum_{j in N+} u'_j
1752+
// z_j in {0,1} for all j in N+ & N-
1753+
17401754
double knapsackWeight = 0;
17411755
std::vector<double> weights(nitems);
1742-
std::vector<double> profits(nitems);
1756+
std::vector<double> profitweightratios(nitems);
17431757
std::vector<HighsInt> perm(nitems);
17441758
std::iota(perm.begin(), perm.end(), 0);
17451759
for (HighsInt i = 0; i < nitems; ++i) {
17461760
weights[i] = snfr.vubCoef[items[i]];
17471761
if (snfr.coef[items[i]] == 1) {
1748-
profits[i] = 1 - snfr.binSolval[items[i]];
1762+
profitweightratios[i] = (1 - snfr.binSolval[items[i]]) / weights[i];
17491763
} else {
1750-
profits[i] = snfr.binSolval[items[i]];
1764+
profitweightratios[i] = snfr.binSolval[items[i]] / weights[i];
17511765
}
17521766
}
17531767
pdqsort_branchless(perm.begin(), perm.end(),
17541768
[&](const HighsInt a, const HighsInt b) {
1755-
return profits[a] / weights[a] > profits[b] / weights[b];
1769+
return profitweightratios[a] > profitweightratios[b];
17561770
});
17571771
// Greedily add items to knapsack
17581772
for (HighsInt i = 0; i < nitems; ++i) {
@@ -1761,19 +1775,23 @@ bool HighsCutGeneration::computeFlowCover() {
17611775
if (knapsackWeight + weights[j] < capacity) {
17621776
knapsackWeight += weights[j];
17631777
if (snfr.coef[k] == 1) {
1778+
// j in N+ with z_j = 1 => j in N+ \ C+
17641779
snfr.flowCoverStatus[k] = -1;
17651780
nNonFlowCover++;
17661781
} else {
1782+
// j in N- with z_j = 1 => j in C-
17671783
snfr.flowCoverStatus[k] = 1;
17681784
nFlowCover++;
17691785
flowCoverWeight -= snfr.vubCoef[k];
17701786
}
17711787
} else {
17721788
if (snfr.coef[k] == 1) {
1789+
// j in N+ with z_j = 0 => j in C+
17731790
snfr.flowCoverStatus[k] = 1;
17741791
nFlowCover++;
17751792
flowCoverWeight += snfr.vubCoef[k];
17761793
} else {
1794+
// j in N- with z_j = 0 => j in N- \ C-
17771795
snfr.flowCoverStatus[k] = -1;
17781796
nNonFlowCover++;
17791797
}

highs/mip/HighsTransformedLp.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,8 @@ bool HighsTransformedLp::transformSNFRelaxation(
647647
// (2) a_j (l_j - d_j) + c_j <= 0
648648
// (3) a_j u'_j + c_j <= 0
649649
// Note: c_j may change during transform if two columns use same bin col
650+
// complement: Should x_j be replaced by x'_j = (1 - x_j)
651+
// inclbincoef: Should c_j be used and included in the aggregation
650652
if (bincol == -1) return false;
651653
if (abs(vb.coef) >= 1e+6) return false;
652654
complement = false;

0 commit comments

Comments
 (0)