Skip to content

Commit ea08dee

Browse files
committed
Merge remote-tracking branch 'origin/v10-minor'
2 parents 8832503 + b9f6213 commit ea08dee

File tree

16 files changed

+3171
-193
lines changed

16 files changed

+3171
-193
lines changed

CHANGELOG

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Performance improvements
5050
- disable dualsol and dualray conflict upgrades to maintain conflict store
5151
- apply general conflict upgrades in conflict store
5252
- inline SCIPgetStatus() to reduce computational overhead
53+
- allow multi-aggregation of unbounded slack variables, which may enable more bound tightening due to a reduction in the number of unbounded variables
5354

5455
Examples and applications
5556
-------------------------
@@ -194,6 +195,8 @@ Interface changes
194195
- SCIPnlpiOracleGetJacobianColSparsity() to get the columnwise sparsity pattern of the Jacobian from the NLP oracle
195196
- SCIPnlpiOracleGetObjGradientNnz() to get indices of nonzeroes in the objective gradient
196197
- SCIPhashmapInsertLong() and SCIPhashmapGetImageLong()
198+
- SCIPvarGetMinAggrCoef() and SCIPvarGetMaxAggrCoef() to get bounds on absolute aggregation coefficients for a loose variable;
199+
SCIPisVarAggrCoefAcceptable() to check whether bounds on aggregation coefficients would exceed thresholds when using a loose variable in another aggregation
197200

198201
### Changes in preprocessor macros
199202

@@ -338,6 +341,8 @@ Fixed bugs
338341
- allow negative update in SCIPconsAddUpgradeLocks() to unlock constraint upgrade
339342
- fixed memory leaks when LP, MPS and OPB/WBO readers abort unsuccessfully
340343
- removed erroneous catching of objective-changed events in intobj separator, instead the separator no longer executes within probing with changed objective function
344+
- propagator dualfix no longer fixes variables to infinity to avoid issues when transferring the solution to the original problem
345+
- track and check bounds on the coefficients that is used for a variable in aggregations of other variables to improve numerical stability
341346

342347
Miscellaneous
343348
-------------

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_DEBUG} ${CMAKE_CXX_FLAGS_R
2626
set(SCIP_VERSION_MAJOR 11)
2727
set(SCIP_VERSION_MINOR 0)
2828
set(SCIP_VERSION_PATCH 0)
29-
set(SCIP_VERSION_API 153)
29+
set(SCIP_VERSION_API 154)
3030

3131
project(SCIP
3232
VERSION ${SCIP_VERSION_MAJOR}.${SCIP_VERSION_MINOR}.${SCIP_VERSION_PATCH}

check/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,7 @@ set(pairs_Issue
538538
"instances/Issue/3662_2.cip\;0\;default"
539539
"instances/Issue/3675_1.cip\;0\;default"
540540
"instances/Issue/3675_2.cip\;0\;presolving_heuristics_off"
541+
"instances/Issue/3675_3.cip\;21589416.4938212\;default"
541542
"instances/Issue/3681.cip\;0\;default"
542543
"instances/Issue/3688.cip\;131882\;reduced_presolving"
543544
"instances/Issue/3691.cip\;1.862908\;presolvingnolinear"
@@ -674,6 +675,7 @@ macro(add_instancetests instances settings prefix)
674675
if(NOT ((${setting} STREQUAL "default") AND (${basename} STREQUAL "pltexpA4_6.smps") AND (${LPS} STREQUAL "xprs")))
675676
if(NOT ((${setting} STREQUAL "lns_epsgreedy_vanilla") AND (${basename} STREQUAL "enigma.mps") AND (${LPS} STREQUAL "xprs")))
676677
if(NOT ((${setting} STREQUAL "lns_epsgreedy_vanilla") AND (${basename} STREQUAL "blend2.mps") AND (${LPS} STREQUAL "grb")))
678+
if(NOT ((${setting} STREQUAL "cgmipdirect") AND (${basename} STREQUAL "bell5.mps")))
677679
add_test(NAME ${prefix}-${setting}-${basename}
678680
COMMAND $<TARGET_FILE:scip> -f ${PROJECT_SOURCE_DIR}/check/${path} -s ${PROJECT_SOURCE_DIR}/check/coverage/settings/${setting}.set -o ${optval} ${optval}
679681
)
@@ -683,6 +685,7 @@ macro(add_instancetests instances settings prefix)
683685
FAIL_REGULAR_EXPRESSION "ERROR|user parameter file <${PROJECT_SOURCE_DIR}/check/coverage/settings/${setting}.set> not found"
684686
DEPENDS scip-build
685687
)
688+
endif() # solution not feasible in original problem due to cons_linear presolve, #3819 (https://git.zib.de/integer/scip/-/merge_requests/3881#note_295336)
686689
endif() # Gurobi gets stuck in LP solve, #2833
687690
endif() # Xpress returns 11 while solving a strong branching LP, #3724
688691
endif() # LP Error: Xpress returned 120, #3724 (LPS=xprs, Stochastic-default-pltexpA4_6.smps)

check/instances/Issue/3675_3.cip

Lines changed: 2886 additions & 0 deletions
Large diffs are not rendered by default.

make/make.project

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ SPLINT ?= splint
172172
SCIP_VERSION_MAJOR = 11
173173
SCIP_VERSION_MINOR = 0
174174
SCIP_VERSION_PATCH = 0
175-
SCIP_VERSION_API = 153
175+
SCIP_VERSION_API = 154
176176
SCIP_VERSION = $(SCIP_VERSION_MAJOR).$(SCIP_VERSION_MINOR).$(SCIP_VERSION_PATCH)
177177

178178
#-----------------------------------------------------------------------------

src/scip/cons_linear.c

Lines changed: 57 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -9614,13 +9614,6 @@ SCIP_RETCODE convertLongEquality(
96149614
SCIP_Bool coefsintegral;
96159615
SCIP_Bool varsintegral;
96169616
SCIP_Bool infeasible;
9617-
SCIP_Bool samevar;
9618-
int supinf; /* counter for infinite contributions to the supremum of a possible
9619-
* multi-aggregation
9620-
*/
9621-
int infinf; /* counter for infinite contributions to the infimum of a possible
9622-
* multi-aggregation
9623-
*/
96249617
int maxnlocksstay;
96259618
int maxnlocksremove;
96269619
int bestslackpos;
@@ -9851,17 +9844,19 @@ SCIP_RETCODE convertLongEquality(
98519844
if( conshdlrdata->multaggrremove && !removescons )
98529845
continue;
98539846

9854-
/* prefer variables that make the constraints redundant */
9855-
if( bestremovescons && !removescons )
9856-
continue;
9857-
98589847
/* if the constraint does not become redundant, only accept the variable if it does not appear in
98599848
* other constraints
98609849
*/
98619850
if( !removescons && nlocks > maxnlocksstay )
98629851
continue;
98639852

9864-
better = better || (!bestremovescons && removescons);
9853+
/* prefer variables that make the constraints redundant
9854+
* unless there is a continuous better slack
9855+
*/
9856+
if( !bestremovescons && removescons )
9857+
better = TRUE;
9858+
else if( bestremovescons && !removescons && (bestslacktype > SCIP_VARTYPE_INTEGER || slacktype <= SCIP_VARTYPE_INTEGER) )
9859+
better = FALSE;
98659860
if( better )
98669861
{
98679862
bestslackpos = v;
@@ -9883,56 +9878,6 @@ SCIP_RETCODE convertLongEquality(
98839878
return SCIP_OKAY;
98849879
}
98859880

9886-
supinf = 0;
9887-
infinf = 0;
9888-
samevar = FALSE;
9889-
9890-
/* check whether the the infimum and the supremum of the multi-aggregation can be get infinite */
9891-
for( v = 0; v < consdata->nvars; ++v )
9892-
{
9893-
if( v != bestslackpos )
9894-
{
9895-
if( SCIPisPositive(scip, consdata->vals[v]) )
9896-
{
9897-
if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->vars[v])) )
9898-
{
9899-
++supinf;
9900-
if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->vars[v])) )
9901-
{
9902-
++infinf;
9903-
samevar = TRUE;
9904-
}
9905-
}
9906-
else if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->vars[v])) )
9907-
++infinf;
9908-
}
9909-
else if( SCIPisNegative(scip, consdata->vals[v]) )
9910-
{
9911-
if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->vars[v])) )
9912-
{
9913-
++supinf;
9914-
if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->vars[v])) )
9915-
{
9916-
++infinf;
9917-
samevar = TRUE;
9918-
}
9919-
}
9920-
else if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->vars[v])) )
9921-
++infinf;
9922-
}
9923-
}
9924-
}
9925-
assert(!samevar || (supinf > 0 && infinf > 0));
9926-
9927-
/** @todo Do not exit here, but continue if we may still detect implied integrality. */
9928-
/* If the infimum and the supremum of a multi-aggregation are both infinite, then the multi-aggregation might not be resolvable.
9929-
* E.g., consider the equality z = x-y. If x and y are both fixed to +infinity, the value for z is not determined */
9930-
if( (samevar && (supinf > 1 || infinf > 1)) || (!samevar && supinf > 0 && infinf > 0) )
9931-
{
9932-
SCIPdebugMsg(scip, "do not perform multi-aggregation: infimum and supremum are both infinite\n");
9933-
return SCIP_OKAY;
9934-
}
9935-
99369881
/* if the slack variable is of integer type, and the constraint itself may take fractional values,
99379882
* we cannot aggregate the variable, because the integrality condition would get lost
99389883
* Similarly, if there are implied integral variables, we cannot aggregate since we might
@@ -9942,6 +9887,7 @@ SCIP_RETCODE convertLongEquality(
99429887
&& (bestslacktype == SCIP_VARTYPE_CONTINUOUS || bestslacktype == SCIP_DEPRECATED_VARTYPE_IMPLINT
99439888
|| (coefsintegral && varsintegral && nimplvars == 0)) )
99449889
{
9890+
SCIP_VAR** aggrvars;
99459891
SCIP_VAR* slackvar;
99469892
SCIP_Real* scalars;
99479893
SCIP_Real slackcoef;
@@ -9967,33 +9913,37 @@ SCIP_RETCODE convertLongEquality(
99679913
assert(!SCIPisZero(scip, slackcoef));
99689914
aggrconst = consdata->rhs/slackcoef;
99699915

9970-
getNewSidesAfterAggregation(scip, consdata, slackvar, slackcoef, &newlhs, &newrhs);
9971-
assert(SCIPisLE(scip, newlhs, newrhs));
9972-
SCIP_CALL( chgLhs(scip, cons, newlhs) );
9973-
SCIP_CALL( chgRhs(scip, cons, newrhs) );
9974-
SCIP_CALL( delCoefPos(scip, cons, bestslackpos) );
9975-
99769916
/* allocate temporary memory */
9977-
SCIP_CALL( SCIPallocBufferArray(scip, &scalars, consdata->nvars) );
9917+
SCIP_CALL( SCIPallocBufferArray(scip, &aggrvars, consdata->nvars - 1) );
9918+
SCIP_CALL( SCIPallocBufferArray(scip, &scalars, consdata->nvars - 1) );
99789919

99799920
/* set up the multi-aggregation */
99809921
SCIPdebugMsg(scip, "linear constraint <%s>: multi-aggregate <%s> ==", SCIPconsGetName(cons), SCIPvarGetName(slackvar));
9981-
for( v = 0; v < consdata->nvars; ++v )
9922+
for( v = 0; v < consdata->nvars - 1; ++v )
99829923
{
9983-
scalars[v] = -consdata->vals[v]/slackcoef;
9984-
SCIPdebugMsgPrint(scip, " %+.15g<%s>", scalars[v], SCIPvarGetName(vars[v]));
9924+
if( v == bestslackpos )
9925+
{
9926+
aggrvars[v] = vars[consdata->nvars - 1];
9927+
scalars[v] = -consdata->vals[consdata->nvars - 1] / slackcoef;
9928+
}
9929+
else
9930+
{
9931+
aggrvars[v] = vars[v];
9932+
scalars[v] = -consdata->vals[v] / slackcoef;
9933+
}
9934+
SCIPdebugMsgPrint(scip, " %+.15g<%s>", scalars[v], SCIPvarGetName(aggrvars[v]));
99859935
}
99869936
SCIPdebugMsgPrint(scip, " %+.15g, bounds of <%s>: [%.15g,%.15g], nlocks=%d, maxnlocks=%d, removescons=%u\n",
99879937
aggrconst, SCIPvarGetName(slackvar), SCIPvarGetLbGlobal(slackvar), SCIPvarGetUbGlobal(slackvar),
99889938
bestnlocks, bestremovescons ? maxnlocksremove : maxnlocksstay, bestremovescons);
99899939

99909940
/* perform the multi-aggregation */
9991-
SCIP_CALL( SCIPmultiaggregateVar(scip, slackvar, consdata->nvars, vars, scalars, aggrconst,
9941+
SCIP_CALL( SCIPmultiaggregateVar(scip, slackvar, consdata->nvars - 1, aggrvars, scalars, aggrconst,
99929942
&infeasible, &aggregated) );
9993-
assert(aggregated);
99949943

99959944
/* free temporary memory */
99969945
SCIPfreeBufferArray(scip, &scalars);
9946+
SCIPfreeBufferArray(scip, &aggrvars);
99979947

99989948
/* check for infeasible aggregation */
99999949
if( infeasible )
@@ -10003,7 +9953,20 @@ SCIP_RETCODE convertLongEquality(
100039953
return SCIP_OKAY;
100049954
}
100059955

10006-
(*naggrvars)++;
9956+
/* check for applied aggregation */
9957+
if( !aggregated )
9958+
{
9959+
SCIPdebugMsg(scip, "linear constraint <%s>: multi-aggregation not applicable\n", SCIPconsGetName(cons));
9960+
return SCIP_OKAY;
9961+
}
9962+
9963+
++(*naggrvars);
9964+
9965+
getNewSidesAfterAggregation(scip, consdata, slackvar, slackcoef, &newlhs, &newrhs);
9966+
assert(SCIPisLE(scip, newlhs, newrhs));
9967+
SCIP_CALL( chgLhs(scip, cons, newlhs) );
9968+
SCIP_CALL( chgRhs(scip, cons, newrhs) );
9969+
SCIP_CALL( delCoefPos(scip, cons, bestslackpos) );
100079970

100089971
/* delete the constraint if it became redundant */
100099972
if( bestremovescons )
@@ -10897,13 +10860,6 @@ SCIP_RETCODE dualPresolve(
1089710860
int j;
1089810861
SCIP_Bool infeasible;
1089910862
SCIP_Bool aggregated;
10900-
SCIP_Bool samevar;
10901-
int supinf; /* counter for infinite contributions to the supremum of a possible
10902-
* multi-aggregation
10903-
*/
10904-
int infinf; /* counter for infinite contributions to the infimum of a possible
10905-
* multi-aggregation
10906-
*/
1090710863

1090810864
assert(!bestislhs || lhsexists);
1090910865
assert(bestislhs || rhsexists);
@@ -10920,9 +10876,6 @@ SCIP_RETCODE dualPresolve(
1092010876
SCIPdebugPrintCons(scip, cons, NULL);
1092110877
SCIPdebugMsg(scip, "linear constraint <%s> (dual): multi-aggregate <%s> ==", SCIPconsGetName(cons), SCIPvarGetName(bestvar));
1092210878
naggrs = 0;
10923-
supinf = 0;
10924-
infinf = 0;
10925-
samevar = FALSE;
1092610879

1092710880
for( j = 0; j < consdata->nvars; ++j )
1092810881
{
@@ -10952,39 +10905,9 @@ SCIP_RETCODE dualPresolve(
1095210905
aggrcoefs[naggrs] = SCIPfloor(scip, aggrcoefs[naggrs]+0.5);
1095310906
}
1095410907

10955-
if( SCIPisPositive(scip, aggrcoefs[naggrs]) )
10956-
{
10957-
if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->vars[j])) )
10958-
{
10959-
++supinf;
10960-
if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->vars[j])) )
10961-
{
10962-
++infinf;
10963-
samevar = TRUE;
10964-
}
10965-
}
10966-
else if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->vars[j])) )
10967-
++infinf;
10968-
}
10969-
else if( SCIPisNegative(scip, aggrcoefs[naggrs]) )
10970-
{
10971-
if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->vars[j])) )
10972-
{
10973-
++supinf;
10974-
if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->vars[j])) )
10975-
{
10976-
++infinf;
10977-
samevar = TRUE;
10978-
}
10979-
}
10980-
else if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->vars[j])) )
10981-
++infinf;
10982-
}
10983-
1098410908
naggrs++;
1098510909
}
1098610910
}
10987-
assert(!samevar || (supinf > 0 && infinf > 0));
1098810911

1098910912
aggrconst = (bestislhs ? consdata->lhs/bestval : consdata->rhs/bestval);
1099010913
SCIPdebugMsgPrint(scip, " %+.15g, bounds of <%s>: [%.15g,%.15g]\n", aggrconst, SCIPvarGetName(bestvar),
@@ -11002,43 +10925,35 @@ SCIP_RETCODE dualPresolve(
1100210925
infeasible = FALSE;
1100310926

1100410927
/* perform the multi-aggregation */
11005-
if( (samevar && supinf == 1 && infinf == 1) || (!samevar && (supinf == 0 || infinf == 0)) )
10928+
SCIP_CALL( SCIPmultiaggregateVar(scip, bestvar, naggrs, aggrvars, aggrcoefs, aggrconst, &infeasible, &aggregated) );
10929+
10930+
/** @todo handle this case properly with weak and strong implied integrality */
10931+
/* if the multi-aggregated bestvar is enforced but not strongly implied integral, we need to convert implied
10932+
* integral to integer variables because integrality of the multi-aggregated variable must hold
10933+
*/
10934+
if( !infeasible && aggregated && SCIPvarGetType(bestvar) != SCIP_VARTYPE_CONTINUOUS && SCIPvarGetImplType(bestvar) != SCIP_IMPLINTTYPE_STRONG )
1100610935
{
11007-
SCIP_CALL( SCIPmultiaggregateVar(scip, bestvar, naggrs, aggrvars, aggrcoefs, aggrconst, &infeasible, &aggregated) );
10936+
SCIP_Bool infeasiblevartypechg = FALSE;
1100810937

11009-
/** @todo handle this case properly with weak and strong implied integrality */
11010-
/* if the multi-aggregated bestvar is enforced but not strongly implied integral, we need to convert implied
11011-
* integral to integer variables because integrality of the multi-aggregated variable must hold
11012-
*/
11013-
if( !infeasible && aggregated && SCIPvarGetType(bestvar) != SCIP_VARTYPE_CONTINUOUS && SCIPvarGetImplType(bestvar) != SCIP_IMPLINTTYPE_STRONG )
10938+
for( j = 0; j < naggrs; ++j )
1101410939
{
11015-
SCIP_Bool infeasiblevartypechg = FALSE;
11016-
11017-
for( j = 0; j < naggrs; ++j)
10940+
/* if the multi-aggregation was not infeasible, then setting implied integral to integer should not
10941+
* lead to infeasibility
10942+
*/
10943+
if( SCIPvarGetType(aggrvars[j]) == SCIP_VARTYPE_CONTINUOUS || SCIPvarGetImplType(aggrvars[j]) != SCIP_IMPLINTTYPE_NONE )
1101810944
{
11019-
/* if the multi-aggregation was not infeasible, then setting implied integral to integer should not
11020-
* lead to infeasibility
11021-
*/
11022-
if( SCIPvarGetType(aggrvars[j]) == SCIP_VARTYPE_CONTINUOUS || SCIPvarGetImplType(aggrvars[j]) != SCIP_IMPLINTTYPE_NONE )
10945+
if( SCIPvarGetType(aggrvars[j]) == SCIP_VARTYPE_CONTINUOUS )
1102310946
{
11024-
if( SCIPvarGetType(aggrvars[j]) == SCIP_VARTYPE_CONTINUOUS )
11025-
{
11026-
SCIP_CALL( SCIPchgVarType(scip, aggrvars[j], SCIP_VARTYPE_INTEGER, &infeasiblevartypechg) );
11027-
assert(!infeasiblevartypechg);
11028-
}
11029-
SCIP_CALL( SCIPchgVarImplType(scip, aggrvars[j], SCIP_IMPLINTTYPE_NONE, &infeasiblevartypechg) );
10947+
SCIP_CALL( SCIPchgVarType(scip, aggrvars[j], SCIP_VARTYPE_INTEGER, &infeasiblevartypechg) );
1103010948
assert(!infeasiblevartypechg);
11031-
(*nchgvartypes)++;
1103210949
}
10950+
SCIP_CALL( SCIPchgVarImplType(scip, aggrvars[j], SCIP_IMPLINTTYPE_NONE, &infeasiblevartypechg) );
10951+
assert(!infeasiblevartypechg);
10952+
(*nchgvartypes)++;
1103310953
}
1103410954
}
1103510955
}
11036-
else
11037-
{
11038-
/* If the infimum and the supremum of a multi-aggregation are both infinite, then the multi-aggregation might not be resolvable.
11039-
* E.g., consider the equality z = x-y. If x and y are both fixed to +infinity, the value for z is not determined */
11040-
SCIPdebugMsg(scip, "do not perform multi-aggregation: infimum and supremum are both infinite\n");
11041-
}
10956+
1104210957
/* free temporary memory */
1104310958
SCIPfreeBufferArray(scip, &aggrcoefs);
1104410959
SCIPfreeBufferArray(scip, &aggrvars);

0 commit comments

Comments
 (0)