Skip to content

Commit

Permalink
Merge branch 'add_paramter_to_use_sameslackvar2' into 'v9-minor'
Browse files Browse the repository at this point in the history
allow to control whether slack var is reused for each binary variable

See merge request integer/scip!3526
  • Loading branch information
pfetsch committed Oct 25, 2024
2 parents 295f508 + 2969141 commit f8711d5
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 47 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ Performance improvements

- reoptimization now also stores propagations from propagators if reoptimization/saveconsprop is enabled;
the parameter will be renamed to reoptimization/saveprop in a next major release
- Imposed stricter limits on the size of disconnected components which may be solved separately during presolve by cons_components
- imposed stricter limits on the size of disconnected components which may be solved separately during presolve by cons_components
- use individual slack variables also for constraints indicated by a common binary variable to use tighter formulation by default

Fixed bugs
----------
Expand All @@ -40,13 +41,15 @@ Interface changes

### Command line interface
### Interfaces to external software

### New parameters

- presolving/milp/abortfacexhaustive to control the abort threshold for exhaustive presolving in PAPILO
- presolving/milp/abortfacmedium to control the abort threshold for medium presolving in PAPILO
- presolving/milp/abortfacfast to control the abort threshold for fast presolving in PAPILO
- constraints/components/maxcompweight to determine the maximum weight for a disconnected component that is solved during presolve
- constraints/components/contfactor counts the contributing factor of a single continuous variables with respect to the weight limit specified by constraints/components/maxcompweight
- constraints/indicator/usesameslackvar to decide whether the same slack variable should be used for indicators constraints with common binary variable

### Changed parameters

Expand Down
84 changes: 38 additions & 46 deletions src/scip/cons_indicator.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@
#define DEFAULT_CONFLICTSUPGRADE FALSE /**< Try to upgrade bounddisjunction conflicts by replacing slack variables? */
#define DEFAULT_FORCERESTART FALSE /**< Force restart if absolute gap is 1 or enough binary variables have been fixed? */
#define DEFAULT_RESTARTFRAC 0.9 /**< fraction of binary variables that need to be fixed before restart occurs (in forcerestart) */
#define DEFAULT_USESAMESLACKVAR FALSE /**< Use same slack variable for indicator constraints with common binary variable? */


/* other values */
Expand Down Expand Up @@ -415,6 +416,7 @@ struct SCIP_ConshdlrData
SCIP_Bool trysolfromcover; /**< Try to construct a feasible solution from a cover? */
SCIP_Bool upgradelinear; /**< Try to upgrade linear constraints to indicator constraints? */
char normtype; /**< norm type for cut computation */
SCIP_Bool usesameslackvar; /**< Use same slack variable for indicator constraints with common binary variable? */
/* parameters that should not be changed after problem stage: */
SCIP_Bool sepaalternativelp; /**< Separate using the alternative LP? */
SCIP_Bool sepaalternativelp_; /**< used to store the sepaalternativelp parameter */
Expand Down Expand Up @@ -3377,14 +3379,14 @@ SCIP_RETCODE consdataCreate(
assert( slackvar != NULL );
assert( eventhdlrrestart != NULL );

/* if active on 0, the binary variable is reversed */
if ( activeone )
/* if active on 0, a provided binary variable is reversed */
if ( activeone || binvar == NULL )
{
binvarinternal = binvar;
}
else
{
SCIP_CALL ( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
}

/* create constraint data */
Expand Down Expand Up @@ -7864,6 +7866,11 @@ SCIP_RETCODE SCIPincludeConshdlrIndicator(
"Try to upgrade linear constraints to indicator constraints?",
&conshdlrdata->upgradelinear, TRUE, DEFAULT_UPGRADELINEAR, NULL, NULL) );

SCIP_CALL( SCIPaddBoolParam(scip,
"constraints/indicator/usesameslackvar",
"Use same slack variable for indicator constraints with common binary variable?",
&conshdlrdata->usesameslackvar, TRUE, DEFAULT_USESAMESLACKVAR, NULL, NULL) );

/* parameters that should not be changed after problem stage: */
SCIP_CALL( SCIPaddBoolParam(scip,
"constraints/indicator/sepaalternativelp",
Expand Down Expand Up @@ -7968,6 +7975,7 @@ SCIP_RETCODE SCIPcreateConsIndicatorGeneric(
SCIP_CONSDATA* consdata = NULL;
SCIP_CONS* lincons;
SCIP_VAR* slackvar = NULL;
SCIP_VAR* binvarinternal;
SCIP_Bool modifiable = FALSE;
SCIP_Bool linconsactive = TRUE;
SCIP_VARTYPE slackvartype;
Expand Down Expand Up @@ -8032,32 +8040,29 @@ SCIP_RETCODE SCIPcreateConsIndicatorGeneric(
}
}

/* Check whether binary variable has been used for a different constraint; then use the same slack variable. */
if ( binvar != NULL )
/* if active on 0, a provided binary variable is reversed */
if ( activeone || binvar == NULL )
binvarinternal = binvar;
else
{
SCIP_VAR* binvarinternal;

/* if active on 0, the binary variable is reversed */
if ( activeone )
binvarinternal = binvar;
else
{
SCIP_CALL ( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
}
SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
}

/* make sure that the hashmap exists */
if ( conshdlrdata->binslackvarhash == NULL )
/* Check whether the same slack variable should be use for constraints with a common binary variable. This can
* reduce the size of the problem, because only one coupling constraint is needed. However, it is less tight. */
if ( binvarinternal != NULL )
{
/* make sure that the hashmap exists if we want to use the same slack variable */
if ( conshdlrdata->usesameslackvar && conshdlrdata->binslackvarhash == NULL )
{
SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binslackvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
}

assert( conshdlrdata->binslackvarhash != NULL );
if ( SCIPhashmapExists(conshdlrdata->binslackvarhash, (void*) binvarinternal) )
if ( conshdlrdata->binslackvarhash != NULL && SCIPhashmapExists(conshdlrdata->binslackvarhash, (void*) binvarinternal) )
{
SCIP_Bool infeasible;

slackvar = (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->binslackvarhash, (void*) binvarinternal);
assert( slackvar != NULL );

/* make sure that the type of the slackvariable is as general as possible */
if ( SCIPvarGetType(slackvar) == SCIP_VARTYPE_IMPLINT && slackvartype != SCIP_VARTYPE_IMPLINT )
Expand All @@ -8080,7 +8085,10 @@ SCIP_RETCODE SCIPcreateConsIndicatorGeneric(
/* mark slack variable not to be multi-aggregated */
SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, slackvar) );

SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binslackvarhash, (void*) binvarinternal, (void*) slackvar) );
if ( conshdlrdata->binslackvarhash != NULL )
{
SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binslackvarhash, (void*) binvarinternal, (void*) slackvar) );
}
}
}
else
Expand All @@ -8095,6 +8103,7 @@ SCIP_RETCODE SCIPcreateConsIndicatorGeneric(
/* mark slack variable not to be multi-aggregated */
SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, slackvar) );
}
assert( slackvar != NULL );

/* if the problem should be decomposed if only non-integer variables are present */
if ( conshdlrdata->nolinconscont )
Expand Down Expand Up @@ -8164,15 +8173,6 @@ SCIP_RETCODE SCIPcreateConsIndicatorGeneric(
if ( conshdlrdata->generatebilinear )
{
SCIP_Real val = 1.0;
SCIP_VAR* binvarinternal;

/* if active on 0, the binary variable is reversed */
if ( activeone )
binvarinternal = binvar;
else
{
SCIP_CALL ( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
}

/* create a quadratic constraint with a single bilinear term - note that cons is used */
SCIP_CALL( SCIPcreateConsQuadraticNonlinear(scip, cons, name, 0, NULL, NULL, 1, &binvarinternal, &slackvar, &val, 0.0, 0.0,
Expand Down Expand Up @@ -8202,21 +8202,11 @@ SCIP_RETCODE SCIPcreateConsIndicatorGeneric(
/* make sure that binary variable hash exists */
if ( conshdlrdata->sepaalternativelp )
{
SCIP_VAR* binvarinternal;

if ( conshdlrdata->binvarhash == NULL )
{
SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
}

/* if active on 0, the binary variable is reversed */
if ( activeone )
binvarinternal = binvar;
else
{
SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
}

/* check whether binary variable is present: note that a binary variable might appear several times, but this seldomly happens. */
assert( conshdlrdata->binvarhash != NULL );
if ( ! SCIPhashmapExists(conshdlrdata->binvarhash, (void*) binvarinternal) )
Expand Down Expand Up @@ -8608,21 +8598,20 @@ SCIP_RETCODE SCIPcreateConsIndicatorGenericLinConsPure(
binvarinternal = binvar;
else
{
SCIP_CALL ( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvarinternal) );
}

/* Check awhether binary variable has been used for a different constraint; then use the same slack variable. */
if ( conshdlrdata->binslackvarhash == NULL )
/* Check whether the same slack variable should be use for constraints with a common binary variable. This can
* reduce the size of the problem, because only one coupling constraint is needed. However, it is less tight. */
if ( conshdlrdata->usesameslackvar && conshdlrdata->binslackvarhash == NULL )
{
SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->binslackvarhash, SCIPblkmem(scip), SCIPgetNOrigVars(scip)) );
}

assert( conshdlrdata->binslackvarhash != NULL );
if ( SCIPhashmapExists(conshdlrdata->binslackvarhash, (void*) binvarinternal) )
if ( conshdlrdata->binslackvarhash != NULL && SCIPhashmapExists(conshdlrdata->binslackvarhash, (void*) binvarinternal) )
{
/* determine slack variable */
slackvar = (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->binslackvarhash, (void*) binvarinternal);
assert( slackvar != NULL );

/* make sure that the type of the slackvariable is as general as possible */
if ( SCIPvarGetType(slackvar) == SCIP_VARTYPE_IMPLINT && slackvartype != SCIP_VARTYPE_IMPLINT )
Expand All @@ -8646,7 +8635,10 @@ SCIP_RETCODE SCIPcreateConsIndicatorGenericLinConsPure(
/* mark slack variable not to be multi-aggregated */
SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, slackvar) );

SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binslackvarhash, (void*) binvarinternal, (void*) slackvar) );
if ( conshdlrdata->binslackvarhash != NULL )
{
SCIP_CALL( SCIPhashmapInsert(conshdlrdata->binslackvarhash, (void*) binvarinternal, (void*) slackvar) );
}
}
assert( slackvar != NULL );

Expand Down

0 comments on commit f8711d5

Please sign in to comment.