@@ -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 }
0 commit comments