@@ -625,7 +625,8 @@ bool HighsTransformedLp::transformSNFRelaxation(
625625
626626 auto checkValidityVB = [&](HighsInt bincol, HighsImplications::VarBound vb,
627627 double coef, double origbincoef, double lb,
628- double ub, bool isVub) {
628+ double ub, bool isVub, bool & complement,
629+ bool & inclbincoef) {
629630 // a_j coefficient of y_j in row. c_j coefficient of x_j in row.
630631 // u_j, l_j, closest simple bounds imposed on y_j.
631632 // y_j <= u'_j x_j + d_j || y_j >= l'_j x_j + d_j
@@ -648,41 +649,99 @@ bool HighsTransformedLp::transformSNFRelaxation(
648649 // Note: c_j may change during transform if two columns use same bin col
649650 if (bincol == -1 ) return false ;
650651 if (abs (vb.coef ) >= 1e+6 ) return false ;
651- if (isVub && lb < vb.constant ) return false ;
652- if (!isVub && ub > vb.constant ) return false ;
652+ complement = false ;
653+ inclbincoef = true ;
654+ if (isVub && lb < vb.constant ) {
655+ if (lb >= vb.constant + vb.coef ) {
656+ complement = true ;
657+ } else {
658+ return false ;
659+ }
660+ }
661+ if (!isVub && ub > vb.constant ) {
662+ if (ub <= vb.constant + vb.coef ) {
663+ complement = true ;
664+ } else {
665+ return false ;
666+ }
667+ }
653668 const double sign = coef >= 0 ? 1 : -1 ;
654669 if (isVub) {
655- double val = sign * ((coef * vb.coef ) + origbincoef);
656- if (val < 0 || val > kHighsInf ) return false ;
657- val = sign * ((coef * (lb - vb.constant )) + origbincoef);
658- if (val < 0 ) return false ;
670+ double val = complement ? sign * (coef * -vb.coef + origbincoef)
671+ : sign * (coef * vb.coef + origbincoef);
672+ if (val > kHighsInf ) return false ;
673+ if (val < 0 ) {
674+ val = complement ? sign * (coef * -vb.coef ) : sign * (coef * vb.coef );
675+ if (val < 0 ) return false ;
676+ inclbincoef = false ;
677+ }
678+ if (inclbincoef) {
679+ val = complement
680+ ? sign * (coef * (lb - (vb.constant + vb.coef )) + origbincoef)
681+ : sign * (coef * (lb - vb.constant ) + origbincoef);
682+ if (val < 0 ) {
683+ val = complement ? sign * (coef * (lb - (vb.constant + vb.coef )))
684+ : sign * (coef * (lb - vb.constant ));
685+ if (val < 0 ) return false ;
686+ inclbincoef = false ;
687+ val = complement ? sign * (coef * -vb.coef ) : sign * (coef * vb.coef );
688+ if (val < 0 ) return false ;
689+ }
690+ } else {
691+ val = complement ? sign * (coef * (lb - (vb.constant + vb.coef )))
692+ : sign * (coef * (lb - vb.constant ));
693+ if (val < 0 ) return false ;
694+ }
659695 } else {
660- double val = sign * ((coef * vb.coef ) + origbincoef);
661- if (val > 0 || -val > kHighsInf ) return false ;
662- val = sign * ((coef * (ub - vb.constant )) + origbincoef);
663- if (val > 0 ) return false ;
696+ double val = complement ? sign * ((coef * -vb.coef ) + origbincoef)
697+ : sign * ((coef * vb.coef ) + origbincoef);
698+ if (-val > kHighsInf ) return false ;
699+ if (val > 0 ) {
700+ val = complement ? sign * (coef * -vb.coef ) : sign * (coef * vb.coef );
701+ if (val > 0 ) return false ;
702+ inclbincoef = false ;
703+ }
704+ if (inclbincoef) {
705+ val =
706+ complement
707+ ? sign * ((coef * (ub - (vb.constant + vb.coef ))) + origbincoef)
708+ : sign * ((coef * (ub - vb.constant )) + origbincoef);
709+ if (val > 0 ) {
710+ val = complement ? sign * (coef * (ub - (vb.constant + vb.coef )))
711+ : sign * (coef * (ub - vb.constant ));
712+ if (val > 0 ) return false ;
713+ inclbincoef = false ;
714+ val = complement ? sign * (coef * -vb.coef ) : sign * (coef * vb.coef );
715+ if (val > 0 ) return false ;
716+ }
717+ } else {
718+ val = complement ? sign * (coef * (ub - (vb.constant + vb.coef )))
719+ : sign * (coef * (ub - vb.constant ));
720+ if (val > 0 ) return false ;
721+ }
664722 }
665723 return true ;
666724 };
667725
668- auto addSNFRentry = [&](HighsInt origbincol, HighsInt origcontcol,
669- double binsolval, double contsolval, HighsInt coef,
670- double vubcoef, double aggrconstant,
671- double aggrbincoef, double aggrcontcoef) {
672- assert (binsolval >= -lprelaxation.getMipSolver ().mipdata_ ->feastol &&
673- binsolval <= 1 + lprelaxation.getMipSolver ().mipdata_ ->feastol );
674- assert (vubcoef >= -1e-10 );
675- snfr.origBinCols [snfr.numNnzs ] = origbincol;
676- snfr.origContCols [snfr.numNnzs ] = origcontcol;
677- snfr.binSolval [snfr.numNnzs ] = binsolval;
678- snfr.contSolval [snfr.numNnzs ] = contsolval;
679- snfr.coef [snfr.numNnzs ] = coef;
680- snfr.vubCoef [snfr.numNnzs ] = std::max (vubcoef, 0.0 );
681- snfr.aggrConstant [snfr.numNnzs ] = aggrconstant;
682- snfr.aggrBinCoef [snfr.numNnzs ] = aggrbincoef;
683- snfr.aggrContCoef [snfr.numNnzs ] = aggrcontcoef;
684- snfr.numNnzs ++;
685- };
726+ auto addSNFRentry =
727+ [&](HighsInt origbincol, HighsInt origcontcol, double binsolval,
728+ double contsolval, HighsInt coef, double vubcoef, double aggrconstant,
729+ double aggrbincoef, double aggrcontcoef, bool complement) {
730+ assert (binsolval >= -lprelaxation.getMipSolver ().mipdata_ ->feastol &&
731+ binsolval <= 1 + lprelaxation.getMipSolver ().mipdata_ ->feastol );
732+ assert (vubcoef >= -1e-10 );
733+ snfr.origBinCols [snfr.numNnzs ] = origbincol;
734+ snfr.origContCols [snfr.numNnzs ] = origcontcol;
735+ snfr.binSolval [snfr.numNnzs ] = binsolval;
736+ snfr.contSolval [snfr.numNnzs ] = contsolval;
737+ snfr.coef [snfr.numNnzs ] = coef;
738+ snfr.vubCoef [snfr.numNnzs ] = std::max (vubcoef, 0.0 );
739+ snfr.aggrConstant [snfr.numNnzs ] = aggrconstant;
740+ snfr.aggrBinCoef [snfr.numNnzs ] = aggrbincoef;
741+ snfr.aggrContCoef [snfr.numNnzs ] = aggrcontcoef;
742+ snfr.complementation [snfr.numNnzs ] = complement;
743+ snfr.numNnzs ++;
744+ };
686745
687746 // Place the non-binary columns to the front (all general ints relaxed)
688747 // Use vectorsum to track original row coefficients of binary columns.
@@ -761,36 +820,39 @@ bool HighsTransformedLp::transformSNFRelaxation(
761820 // Binary columns can be added directly to the SNFR
762821 if (vals[i] >= 0 ) {
763822 addSNFRentry (col, -1 , getLpSolution (col), getLpSolution (col) * vals[i],
764- 1 , vals[i], 0 , vals[i] , 0 );
823+ 1 , vals[i], 0 , vectorsum. getValue (col) , 0 , false );
765824 } else {
766825 addSNFRentry (col, -1 , getLpSolution (col), -getLpSolution (col) * vals[i],
767- -1 , -vals[i], 0 , -vals[i] , 0 );
826+ -1 , -vals[i], 0 , -vectorsum. getValue (col) , 0 , false );
768827 }
769828 } else {
770829 // Decide whether to use {simple, variable} {lower, upper} bound
771- bool vlbValid = checkValidityVB (bestVlb[col].first , bestVlb[col].second , vals[i],
772- bestVlb[col].first == -1
773- ? 0
774- : vectorsum.getValue (bestVlb[col].first ),
775- lb, ub, false );
776- bool vubValid = checkValidityVB (bestVub[col].first , bestVub[col].second , vals[i],
777- bestVub[col].first == -1
778- ? 0
779- : vectorsum.getValue (bestVub[col].first ),
780- lb, ub, true );
781- BoundType boundType = BoundType::kSimpleLb ;
830+ bool complementvlb = false ;
831+ bool inclbincolvlb = true ;
832+ bool vlbValid = checkValidityVB (
833+ bestVlb[col].first , bestVlb[col].second , vals[i],
834+ bestVlb[col].first == -1 ? 0 : vectorsum.getValue (bestVlb[col].first ),
835+ lb, ub, false , complementvlb, inclbincolvlb);
836+ bool complementvub = false ;
837+ bool inclbincolvub = true ;
838+ bool vubValid = checkValidityVB (
839+ bestVub[col].first , bestVub[col].second , vals[i],
840+ bestVub[col].first == -1 ? 0 : vectorsum.getValue (bestVub[col].first ),
841+ lb, ub, true , complementvub, inclbincolvub);
842+ auto boundType = BoundType::kSimpleLb ;
782843 if (lbDist[col] < ubDist[col] - mip.mipdata_ ->feastol && vlbValid) {
783844 boundType = BoundType::kVariableLb ;
784- } else if (ubDist[col] < lbDist[col] - mip.mipdata_ ->feastol && vubValid) {
845+ } else if (ubDist[col] < lbDist[col] - mip.mipdata_ ->feastol &&
846+ vubValid) {
785847 boundType = BoundType::kVariableUb ;
786848 } else if (vals[i] > 0 && vlbValid) {
787849 boundType = BoundType::kVariableLb ;
788850 } else if (vals[i] < 0 && vubValid) {
789851 boundType = BoundType::kVariableUb ;
790852 } else if (vlbValid) {
791- boundType = BoundType::kVariableLb ;
853+ boundType = BoundType::kVariableLb ;
792854 } else if (vubValid) {
793- boundType = BoundType::kVariableUb ;
855+ boundType = BoundType::kVariableUb ;
794856 } else if (lbDist[col] < ubDist[col] - mip.mipdata_ ->feastol ) {
795857 boundType = BoundType::kSimpleLb ;
796858 } else if (ubDist[col] < lbDist[col] - mip.mipdata_ ->feastol ) {
@@ -817,10 +879,10 @@ bool HighsTransformedLp::transformSNFRelaxation(
817879 aggrconstant = static_cast <double >(HighsCDouble (vals[i]) * ub);
818880 if (vals[i] >= 0 ) {
819881 addSNFRentry (-1 , col, 1.0 , -substsolval, -1 , vbcoef, aggrconstant,
820- 0 , -vals[i]);
882+ 0 , -vals[i], false );
821883 } else {
822884 addSNFRentry (-1 , col, 1 , substsolval, 1 , -vbcoef, -aggrconstant, 0 ,
823- vals[i]);
885+ vals[i], false );
824886 }
825887 tmpSnfrRhs -= aggrconstant;
826888 break ;
@@ -836,10 +898,10 @@ bool HighsTransformedLp::transformSNFRelaxation(
836898 aggrconstant = static_cast <double >(HighsCDouble (vals[i]) * lb);
837899 if (vals[i] >= 0 ) {
838900 addSNFRentry (-1 , col, 1 , substsolval, 1 , vbcoef, -aggrconstant, 0 ,
839- vals[i]);
901+ vals[i], false );
840902 } else {
841903 addSNFRentry (-1 , col, 1 , -substsolval, -1 , -vbcoef, aggrconstant, 0 ,
842- -vals[i]);
904+ -vals[i], false );
843905 }
844906 tmpSnfrRhs -= aggrconstant;
845907 break ;
@@ -857,21 +919,32 @@ bool HighsTransformedLp::transformSNFRelaxation(
857919 bestVlb[col].second .constant ) +
858920 (HighsCDouble (lpSolution.col_value [vbcol]) *
859921 vectorsum.getValue (vbcol)));
860- vbcoef = static_cast <double >(HighsCDouble (vals[i]) *
861- bestVlb[col].second .coef +
862- vectorsum.getValue (vbcol));
863- aggrconstant = static_cast <double >(HighsCDouble (vals[i]) *
864- bestVlb[col].second .constant );
922+ vbcoef = static_cast <double >(
923+ HighsCDouble (vals[i]) * (complementvlb
924+ ? -bestVlb[col].second .coef
925+ : bestVlb[col].second .coef ) +
926+ (inclbincolvlb ? vectorsum.getValue (vbcol) : 0 ));
927+ aggrconstant = static_cast <double >(
928+ HighsCDouble (vals[i]) *
929+ (complementvlb
930+ ? bestVlb[col].second .constant + bestVlb[col].second .coef
931+ : bestVlb[col].second .constant ));
865932 if (vals[i] >= 0 ) {
866- addSNFRentry (vbcol, col, lpSolution.col_value [vbcol], -substsolval,
867- -1 , -vbcoef, aggrconstant, -vectorsum.getValue (vbcol),
868- -vals[i]);
933+ addSNFRentry (vbcol, col,
934+ complementvlb ? 1 - lpSolution.col_value [vbcol]
935+ : lpSolution.col_value [vbcol],
936+ -substsolval, -1 , -vbcoef, aggrconstant,
937+ inclbincolvlb ? -vectorsum.getValue (vbcol) : 0 ,
938+ -vals[i], complementvlb);
869939 } else {
870- addSNFRentry (vbcol, col, lpSolution.col_value [vbcol], substsolval,
871- 1 , vbcoef, -aggrconstant, vectorsum.getValue (vbcol),
872- vals[i]);
940+ addSNFRentry (vbcol, col,
941+ complementvlb ? 1 - lpSolution.col_value [vbcol]
942+ : lpSolution.col_value [vbcol],
943+ substsolval, 1 , vbcoef, -aggrconstant,
944+ inclbincolvlb ? vectorsum.getValue (vbcol) : 0 , vals[i],
945+ complementvlb);
873946 }
874- vectorsum.values [vbcol] = 0 ;
947+ if (inclbincolvlb) vectorsum.values [vbcol] = 0 ;
875948 tmpSnfrRhs -= aggrconstant;
876949 break ;
877950 case BoundType::kVariableUb :
@@ -888,21 +961,32 @@ bool HighsTransformedLp::transformSNFRelaxation(
888961 bestVub[col].second .constant ) +
889962 (HighsCDouble (lpSolution.col_value [vbcol]) *
890963 vectorsum.getValue (vbcol)));
891- vbcoef = static_cast <double >(HighsCDouble (vals[i]) *
892- bestVub[col].second .coef +
893- vectorsum.getValue (vbcol));
894- aggrconstant = static_cast <double >(HighsCDouble (vals[i]) *
895- bestVub[col].second .constant );
964+ vbcoef = static_cast <double >(
965+ HighsCDouble (vals[i]) * (complementvub
966+ ? -bestVub[col].second .coef
967+ : bestVub[col].second .coef ) +
968+ (inclbincolvub ? vectorsum.getValue (vbcol) : 0 ));
969+ aggrconstant = static_cast <double >(
970+ HighsCDouble (vals[i]) *
971+ (complementvub
972+ ? bestVub[col].second .constant + bestVub[col].second .coef
973+ : bestVub[col].second .constant ));
896974 if (vals[i] >= 0 ) {
897- addSNFRentry (vbcol, col, lpSolution.col_value [vbcol], substsolval,
898- 1 , vbcoef, -aggrconstant, vectorsum.getValue (vbcol),
899- vals[i]);
975+ addSNFRentry (vbcol, col,
976+ complementvub ? 1 - lpSolution.col_value [vbcol]
977+ : lpSolution.col_value [vbcol],
978+ substsolval, 1 , vbcoef, -aggrconstant,
979+ inclbincolvub ? vectorsum.getValue (vbcol) : 0 , vals[i],
980+ complementvub);
900981 } else {
901- addSNFRentry (vbcol, col, lpSolution.col_value [vbcol], -substsolval,
902- -1 , -vbcoef, aggrconstant, -vectorsum.getValue (vbcol),
903- -vals[i]);
982+ addSNFRentry (vbcol, col,
983+ complementvub ? 1 - lpSolution.col_value [vbcol]
984+ : lpSolution.col_value [vbcol],
985+ -substsolval, -1 , -vbcoef, aggrconstant,
986+ inclbincolvub ? -vectorsum.getValue (vbcol) : 0 ,
987+ -vals[i], complementvub);
904988 }
905- vectorsum.values [vbcol] = 0 ;
989+ if (inclbincolvub) vectorsum.values [vbcol] = 0 ;
906990 tmpSnfrRhs -= aggrconstant;
907991 break ;
908992 }
0 commit comments