@@ -549,6 +549,7 @@ bool HighsCutGeneration::cmirCutGenerationHeuristic(double minEfficacy,
549549 // Positive coefficient values later set to 0 so have no contribution
550550 updateViolationAndNorm (i, vals[i], continuouscontribution,
551551 continuoussqrnorm);
552+ // StrongCG cannot be computed when negative coefficients for cont exist
552553 strongcg = false ;
553554 }
554555 }
@@ -704,11 +705,10 @@ bool HighsCutGeneration::cmirCutGenerationHeuristic(double minEfficacy,
704705 double f0 = scalrhs - downrhs;
705706 double oneoveroneminusf0 = 1.0 / (1.0 - f0);
706707 // Skip numerically troublesome cuts
707- double oneoverf0 = 1 / f0;
708- double k = fast_ceil (oneoverf0) - 1 ;
709- if (oneoverf0 - k < 1e-3 || oneoverf0 - k > 1 - 1e-3 ) {
708+ if (fractionality (1 / f0) < 1e-3 ) {
710709 strongcg = false ;
711710 } else {
711+ double k = fast_ceil (1 / f0) - 1 ;
712712 // All coefficients of continuous variables are 0 in strong CG cut
713713 double sqrnorm = 0 ;
714714 double viol = -downrhs;
@@ -717,20 +717,18 @@ bool HighsCutGeneration::cmirCutGenerationHeuristic(double minEfficacy,
717717 double scalaj = vals[j] * scale;
718718 double downaj = fast_floor (scalaj + kHighsTiny );
719719 double fj = scalaj - downaj;
720- if (fj <= f0 + feastol) {
721- double aj = downaj;
722- updateViolationAndNorm (j, aj, viol, sqrnorm);
723- } else {
720+ double aj = downaj;
721+ if (fj >= f0 + 10 * feastol) {
724722 double pj = fast_ceil (k * (fj - f0) * oneoveroneminusf0 - 1e-4 );
725- double aj = downaj + (pj / (k + 1 ));
726- updateViolationAndNorm (j, aj, viol, sqrnorm);
723+ aj += pj / (k + 1 );
727724 }
725+ updateViolationAndNorm (j, aj, viol, sqrnorm);
728726 }
729727 if (sqrnorm <= kHighsTiny ) {
730728 strongcg = false ;
731729 } else {
732730 double efficacy = viol / sqrt (sqrnorm);
733- // Use the strong CG cut instead of the CMIR if efficacy is larger
731+ // Use the strongCG cut instead of the CMIR if efficacy is larger
734732 if (efficacy < bestefficacy + epsilon) {
735733 strongcg = false ;
736734 } else {
@@ -740,6 +738,62 @@ bool HighsCutGeneration::cmirCutGenerationHeuristic(double minEfficacy,
740738 }
741739 }
742740
741+ if (strongcg) {
742+ // try to flip complementation of integers to increase efficacy
743+ double delta = bestdelta;
744+ double scale = 1.0 / delta;
745+ for (HighsInt i : integerinds) {
746+ if (upper[i] == kHighsInf ) continue ;
747+ if (solval[i] <= feastol) continue ;
748+
749+ flipComplementation (i);
750+
751+ double scalrhs = double (rhs) * scale;
752+ double downrhs = fast_floor (scalrhs);
753+
754+ double f0 = scalrhs - downrhs;
755+ if (f0 < f0min || f0 > f0max) {
756+ flipComplementation (i);
757+ continue ;
758+ }
759+
760+ double oneoveroneminusf0 = 1.0 / (1.0 - f0);
761+ if (oneoveroneminusf0 > maxCMirScale) {
762+ flipComplementation (i);
763+ continue ;
764+ }
765+
766+ if (fractionality (1 / f0) < 1e-3 ) {
767+ flipComplementation (i);
768+ continue ;
769+ }
770+
771+ double k = fast_ceil (1 / f0) - 1 ;
772+
773+ double sqrnorm = 0 ;
774+ double viol = -downrhs;
775+
776+ for (HighsInt j : integerinds) {
777+ double scalaj = vals[j] * scale;
778+ double downaj = fast_floor (scalaj + kHighsTiny );
779+ double fj = scalaj - downaj;
780+ double aj = downaj;
781+ if (fj - f0 >= 10 * feastol) {
782+ double pj = fast_ceil (k * (fj - f0) * oneoveroneminusf0 - 1e-4 );
783+ aj += (pj / (k + 1 ));
784+ }
785+ updateViolationAndNorm (j, aj, viol, sqrnorm);
786+ }
787+
788+ double efficacy = viol / sqrt (sqrnorm);
789+ if (efficacy > bestefficacy) {
790+ bestefficacy = efficacy;
791+ } else {
792+ flipComplementation (i);
793+ }
794+ }
795+ }
796+
743797 HighsCDouble scale = 1.0 / HighsCDouble (bestdelta);
744798 HighsCDouble scalrhs = rhs * scale;
745799 double downrhs = floor (double (scalrhs));
0 commit comments