From d46bcf0e2c21c106e2a793601a53910c9a97210a Mon Sep 17 00:00:00 2001 From: Alexander Hoen Date: Mon, 1 Apr 2024 20:25:07 +0200 Subject: [PATCH] 3681 use percentage in applyFixings in cons_linear.c --- CHANGELOG | 1 + check/CMakeLists.txt | 1 + check/instances/Issue/3681.cip | 12 +++ src/scip/cons_linear.c | 144 ++++++++++++++++++++------------- 4 files changed, 102 insertions(+), 56 deletions(-) create mode 100644 check/instances/Issue/3681.cip diff --git a/CHANGELOG b/CHANGELOG index 9a7627246c..32be2eb8c7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,7 @@ Fixed bugs - set probing LP to be a relaxation only when objective has not been changed - declare contradicting infinities in getMinActivity() and getMaxActivity() as non-tight - reject farkas solution with large values to bound magnification of errors in SCIPgetFarkasProof() +- if all variables are fixed, apply relative feasibility tolerance to avoid invalid infeasibility in applyFixings() of cons_linear.c Miscellaneous ------------- diff --git a/check/CMakeLists.txt b/check/CMakeLists.txt index 1a47111e1d..ee438b3143 100644 --- a/check/CMakeLists.txt +++ b/check/CMakeLists.txt @@ -482,6 +482,7 @@ set(pairs_Issue "instances/Issue/3633.lp\;0\;default" "instances/Issue/3662_1.cip\;0\;default" "instances/Issue/3662_2.cip\;0\;default" + "instances/Issue/3681.cip\;0\;default" ) # diff --git a/check/instances/Issue/3681.cip b/check/instances/Issue/3681.cip new file mode 100644 index 0000000000..f51612ae3a --- /dev/null +++ b/check/instances/Issue/3681.cip @@ -0,0 +1,12 @@ +STATISTICS + Problem name : PyomoModel + Variables : 1 (0 binary, 0 integer, 0 implicit integer, 1 continuous) + Constraints : 0 initial, 2 maximal +OBJECTIVE + Sense : maximize +VARIABLES + [continuous] : obj=0, original bounds=[-inf,+inf] +CONSTRAINTS + [linear] : +3.68[C] == 1334.96018242414; + [linear] : -50000000[C] == -18138045956.8497; +END diff --git a/src/scip/cons_linear.c b/src/scip/cons_linear.c index 51186e4a87..0e9d33db63 100644 --- a/src/scip/cons_linear.c +++ b/src/scip/cons_linear.c @@ -3472,21 +3472,23 @@ SCIP_RETCODE chgLhs( assert(scip != NULL); assert(cons != NULL); - assert(!SCIPisInfinity(scip, lhs)); - /* adjust value to not be smaller than -inf */ - if ( SCIPisInfinity(scip, -lhs) ) + /* adjust value to be not beyond infinity */ + if( SCIPisInfinity(scip, -lhs) ) lhs = -SCIPinfinity(scip); + else if( SCIPisInfinity(scip, lhs) ) + lhs = SCIPinfinity(scip); consdata = SCIPconsGetData(cons); assert(consdata != NULL); assert(consdata->nvars == 0 || (consdata->vars != NULL && consdata->vals != NULL)); - assert(!SCIPisInfinity(scip, consdata->lhs)); /* check whether the side is not changed */ if( SCIPisEQ(scip, consdata->lhs, lhs) ) return SCIP_OKAY; + assert(!SCIPisInfinity(scip, ABS(consdata->lhs)) || !SCIPisInfinity(scip, ABS(lhs))); + /* ensure that rhs >= lhs is satisfied without numerical tolerance */ if( SCIPisEQ(scip, lhs, consdata->rhs) ) { @@ -3554,7 +3556,7 @@ SCIP_RETCODE chgLhs( } /* check whether the left hand side is increased, if and only if that's the case we maybe can propagate, tighten and add more cliques */ - if( !SCIPisInfinity(scip, -lhs) && SCIPisGT(scip, lhs, consdata->lhs) ) + if( !SCIPisInfinity(scip, ABS(lhs)) && SCIPisGT(scip, lhs, consdata->lhs) ) { consdata->boundstightened = 0; consdata->presolved = FALSE; @@ -3598,21 +3600,23 @@ SCIP_RETCODE chgRhs( assert(scip != NULL); assert(cons != NULL); - assert(!SCIPisInfinity(scip, -rhs)); - /* adjust value to not be larger than inf */ - if ( SCIPisInfinity(scip, rhs) ) + /* adjust value to be not beyond infinity */ + if( SCIPisInfinity(scip, rhs) ) rhs = SCIPinfinity(scip); + else if( SCIPisInfinity(scip, -rhs) ) + rhs = -SCIPinfinity(scip); consdata = SCIPconsGetData(cons); assert(consdata != NULL); assert(consdata->nvars == 0 || (consdata->vars != NULL && consdata->vals != NULL)); - assert(!SCIPisInfinity(scip, -consdata->rhs)); /* check whether the side is not changed */ if( SCIPisEQ(scip, consdata->rhs, rhs) ) return SCIP_OKAY; + assert(!SCIPisInfinity(scip, ABS(consdata->rhs)) || !SCIPisInfinity(scip, ABS(rhs))); + /* ensure that rhs >= lhs is satisfied without numerical tolerance */ if( SCIPisEQ(scip, rhs, consdata->lhs) ) { @@ -3682,7 +3686,7 @@ SCIP_RETCODE chgRhs( } /* check whether the right hand side is decreased, if and only if that's the case we maybe can propagate, tighten and add more cliques */ - if( !SCIPisInfinity(scip, rhs) && SCIPisLT(scip, rhs, consdata->rhs) ) + if( !SCIPisInfinity(scip, ABS(rhs)) && SCIPisLT(scip, rhs, consdata->rhs) ) { consdata->boundstightened = 0; consdata->presolved = FALSE; @@ -4707,22 +4711,20 @@ SCIP_RETCODE applyFixings( { if( SCIPisInfinity(scip, ABS(fixedval)) ) { - if( val * fixedval > 0.0 ) - { - SCIP_CALL( chgLhs(scip, cons, -SCIPinfinity(scip)) ); - } - else + /* if lhs gets infinity it means that the problem is infeasible */ + if( ( val > 0.0 ) != ( fixedval > 0.0 ) ) { + SCIP_CALL( chgLhs(scip, cons, SCIPinfinity(scip)) ); + if( infeasible != NULL ) { - /* if lhs gets infinity it means that the problem is infeasible */ *infeasible = TRUE; return SCIP_OKAY; } - else - { - SCIP_CALL( chgLhs(scip, cons, SCIPinfinity(scip)) ); - } + } + else + { + SCIP_CALL( chgLhs(scip, cons, -SCIPinfinity(scip)) ); } } else @@ -4732,18 +4734,16 @@ SCIP_RETCODE applyFixings( { if( SCIPisInfinity(scip, ABS(fixedval)) ) { - if( val * fixedval > 0.0 ) + /* if rhs gets -infinity it means that the problem is infeasible */ + if( ( val > 0.0 ) == ( fixedval > 0.0 ) ) { + SCIP_CALL( chgRhs(scip, cons, -SCIPinfinity(scip)) ); + if( infeasible != NULL ) { - /* if rhs gets -infinity it means that the problem is infeasible */ *infeasible = TRUE; return SCIP_OKAY; } - else - { - SCIP_CALL( chgRhs(scip, cons, -SCIPinfinity(scip)) ); - } } else { @@ -4757,31 +4757,31 @@ SCIP_RETCODE applyFixings( break; case SCIP_VARSTATUS_AGGREGATED: - { - SCIP_VAR* activevar = SCIPvarGetAggrVar(var); - SCIP_Real activescalar = val * SCIPvarGetAggrScalar(var); - SCIP_Real activeconstant = val * SCIPvarGetAggrConstant(var); + { + SCIP_VAR* activevar = SCIPvarGetAggrVar(var); + SCIP_Real activescalar = val * SCIPvarGetAggrScalar(var); + SCIP_Real activeconstant = val * SCIPvarGetAggrConstant(var); - assert(activevar != NULL); - SCIP_CALL( SCIPgetProbvarSum(scip, &activevar, &activescalar, &activeconstant) ); - assert(activevar != NULL); + assert(activevar != NULL); + SCIP_CALL( SCIPgetProbvarSum(scip, &activevar, &activescalar, &activeconstant) ); + assert(activevar != NULL); - if( !SCIPisZero(scip, activescalar) ) - { - SCIP_CALL( addCoef(scip, cons, activevar, activescalar) ); - } + if( !SCIPisZero(scip, activescalar) ) + { + SCIP_CALL( addCoef(scip, cons, activevar, activescalar) ); + } - if( !SCIPisZero(scip, activeconstant) ) - { - if( !SCIPisInfinity(scip, -consdata->lhs) ) - lhssubtrahend += activeconstant; - if( !SCIPisInfinity(scip, consdata->rhs) ) - rhssubtrahend += activeconstant; - } + if( !SCIPisZero(scip, activeconstant) ) + { + if( !SCIPisInfinity(scip, -consdata->lhs) ) + lhssubtrahend += activeconstant; + if( !SCIPisInfinity(scip, consdata->rhs) ) + rhssubtrahend += activeconstant; + } SCIP_CALL( delCoefPos(scip, cons, v) ); break; - } + } case SCIP_VARSTATUS_MULTAGGR: SCIP_CALL( SCIPflattenVarAggregationGraph(scip, var) ); naggrvars = SCIPvarGetMultaggrNVars(var); @@ -4822,12 +4822,28 @@ SCIP_RETCODE applyFixings( if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->lhs) ) { - /* for large numbers that are relatively equal, substraction can lead to cancellation, - * causing wrong fixings of other variables --> better use a real zero here; - * for small numbers, polishing the difference might lead to wrong results --> - * better use the exact difference in this case + /* check left hand side of unmodifiable empty constraint with former feasibility tolerance */ + if( !SCIPconsIsModifiable(cons) && consdata->nvars == 0 ) + { + if( SCIPisFeasLT(scip, lhssubtrahend, consdata->lhs) ) + { + SCIP_CALL( chgLhs(scip, cons, SCIPinfinity(scip)) ); + + if( infeasible != NULL ) + { + *infeasible = TRUE; + return SCIP_OKAY; + } + } + else + { + SCIP_CALL( chgLhs(scip, cons, -SCIPinfinity(scip)) ); + } + } + /* for large numbers that are relatively equal, subtraction can lead to cancellation, + * causing wrong fixings of other variables --> better use a real zero here */ - if( SCIPisEQ(scip, lhssubtrahend, consdata->lhs) && SCIPisFeasGE(scip, REALABS(lhssubtrahend), 1.0) ) + else if( SCIPisEQ(scip, lhssubtrahend, consdata->lhs) ) { SCIP_CALL( chgLhs(scip, cons, 0.0) ); } @@ -4836,14 +4852,30 @@ SCIP_RETCODE applyFixings( SCIP_CALL( chgLhs(scip, cons, consdata->lhs - lhssubtrahend) ); } } - if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->rhs)) + if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->rhs) ) { + /* check right hand side of unmodifiable empty constraint with former feasibility tolerance */ + if( !SCIPconsIsModifiable(cons) && consdata->nvars == 0 ) + { + if( SCIPisFeasGT(scip, rhssubtrahend, consdata->rhs) ) + { + SCIP_CALL( chgRhs(scip, cons, -SCIPinfinity(scip)) ); + + if( infeasible != NULL ) + { + *infeasible = TRUE; + return SCIP_OKAY; + } + } + else + { + SCIP_CALL( chgRhs(scip, cons, SCIPinfinity(scip)) ); + } + } /* for large numbers that are relatively equal, substraction can lead to cancellation, - * causing wrong fixings of other variables --> better use a real zero here; - * for small numbers, polishing the difference might lead to wrong results --> - * better use the exact difference in this case + * causing wrong fixings of other variables --> better use a real zero here */ - if( SCIPisEQ(scip, rhssubtrahend, consdata->rhs ) && SCIPisFeasGE(scip, REALABS(rhssubtrahend), 1.0) ) + else if( SCIPisEQ(scip, rhssubtrahend, consdata->rhs) ) { SCIP_CALL( chgRhs(scip, cons, 0.0) ); } @@ -11347,7 +11379,7 @@ SCIP_RETCODE aggregateVariables( } } } - while( success ); + while( success && consdata->nvars >= 1 ); return SCIP_OKAY; }