Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/v9-minor'
Browse files Browse the repository at this point in the history
  • Loading branch information
scip-ci committed Oct 31, 2024
2 parents 19a9fcf + c31d129 commit edff984
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 4 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ Performance improvements
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
- use individual slack variables also for constraints indicated by a common binary variable to use tighter formulation by default
- when computing symmetries using Nauty, iteration limits are now available to terminate Nauty early

Fixed bugs
----------
Expand All @@ -142,13 +143,14 @@ Interface changes
### 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
- when compiled using the SYM=nauty or SYM=snauty option, parameters propagating/symmetry/nautymaxncells
and propagating/symmetry/nautymaxnnodes can be used to set iteration limits in the external software Nauty

### Changed parameters

Expand Down
20 changes: 20 additions & 0 deletions src/scip/prop_symmetry.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@
/* other defines */
#define MAXGENNUMERATOR 64000000 /**< determine maximal number of generators by dividing this number by the number of variables */
#define COMPRESSNVARSLB 25000 /**< lower bound on the number of variables above which compression could be performed */
#define DEFAULT_NAUTYMAXNCELLS 100000 /**< terminate symmetry detection using Nauty when number of cells in color refinment is at least this number
* (avoids segfaults due to Nauty for large graphs) */
#define DEFAULT_NAUTYMAXNNODES 10000000 /**< terminate symmetry detection using Nauty when its search tree has at least this number of nodes */
/*@todo investigate why the Nauty works well for some large instances (miplib2010/mspp16.mps) but not for PB instances (e.g., normalized-celar6-sub0_wcsp.wbo) */


/* macros for getting activeness of symmetry handling methods */
#define ISSYMRETOPESACTIVE(x) (((unsigned) x & SYM_HANDLETYPE_SYMBREAK) != 0)
Expand Down Expand Up @@ -8078,6 +8083,21 @@ SCIP_RETCODE SCIPincludePropSymmetry(
"timing of symmetry computation and handling (0 = before presolving, 1 = during presolving, 2 = after presolving)",
&propdata->symtiming, TRUE, DEFAULT_SYMCOMPTIMING, 0, 2, NULL, NULL) );

/* for symmetry detection tool Nauty, we add further parameters to terminate it early */
assert( strlen(SYMsymmetryGetName()) >= 5 );
if ( memcmp(SYMsymmetryGetName(), "Nauty", 5) == 0 ) /*lint !e747*/
{
SCIP_CALL( SCIPaddIntParam(scip,
"propagating/" PROP_NAME "/nautymaxncells",
"terminate symmetry detection using Nauty when number of cells in color refinment is at least this number",
NULL, TRUE, DEFAULT_NAUTYMAXNCELLS, 0, INT_MAX, NULL, NULL) );

SCIP_CALL( SCIPaddIntParam(scip,
"propagating/" PROP_NAME "/nautymaxnnodes",
"terminate symmetry detection using Nauty when its search tree has at least this number of nodes",
NULL, TRUE, DEFAULT_NAUTYMAXNNODES, 0, INT_MAX, NULL, NULL) );
}

/* possibly add description */
if ( SYMcanComputeSymmetry() )
{
Expand Down
56 changes: 56 additions & 0 deletions src/symmetry/compute_symmetry_nauty.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ struct NAUTY_Data
int nmaxperms; /**< maximal number of permutations */
int maxgenerators; /**< maximal number of generators to be constructed (= 0 if unlimited) */
SCIP_Bool restricttovars; /**< whether permutations shall be restricted to variables */
int ntreenodes; /**< number of nodes visited in nauty's search tree */
int maxncells; /**< maximum number of cells in nauty's search tree */
int maxnnodes; /**< maximum number of nodes in nauty's search tree */
};

/* static data for nauty callback */
Expand Down Expand Up @@ -158,6 +161,52 @@ void nautyhook(
data_.perms[data_.nperms++] = pp;
}

/** callback function for nauty to terminate early */ /*lint -e{715}*/
static
void nautyterminationhook(
graph* g, /**< sparse graph for nauty */
int* lab, /**< labels of node */
int* ptn, /**< array indicating change of set in node parition of graph */
int level, /**< level of current node in nauty's tree */
int numcells, /**< number of cells in current partition */
int tc, /**< index of target cells in lab if children need to be explored */
int code, /**< code produced by refinement and vertex-invariant procedures */
int m, /**< number of edges in the graph */
int n /**< number of nodes in the graph */
)
{ /* lint --e{715} */
SCIP_Bool terminate = FALSE;
data_.ntreenodes++;

/* add some iteration limit to avoid spending too much time in nauty */
if ( numcells >= data_.maxncells )
{
terminate = TRUE;
SCIPverbMessage(data_.scip, SCIP_VERBLEVEL_MINIMAL, NULL,
"symmetry computation terminated early, because number of cells %d in Nauty exceeds limit of %d\n",
numcells, data_.maxncells);
SCIPverbMessage(data_.scip, SCIP_VERBLEVEL_MINIMAL, NULL,
"for running full symmetry detection, increase value of parameter propagating/symmetry/nautymaxncells\n");
}
else if ( data_.ntreenodes >= data_.maxnnodes )
{
terminate = TRUE;
SCIPverbMessage(data_.scip, SCIP_VERBLEVEL_MINIMAL, NULL,
"symmetry computation terminated early, because number of"
" nodes %d in Nauty's search tree exceeds limit of %d\n", data_.ntreenodes, data_.maxnnodes);
SCIPverbMessage(data_.scip, SCIP_VERBLEVEL_MINIMAL, NULL,
"for running full symmetry detection, increase value of"
" parameter propagating/symmetry/nautymaxnnodes\n");
}

if ( terminate )
{
/* request a kill from nauty */
nauty_kill_request = 1;
return;
}
}

#else

/** callback function for traces */
Expand Down Expand Up @@ -1232,6 +1281,7 @@ SCIP_RETCODE SYMcomputeSymmetryGenerators(
options.writeautoms = FALSE;
options.userautomproc = nautyhook;
options.defaultptn = FALSE; /* use color classes */
options.usernodeproc = nautyterminationhook;
#else
/* init callback functions for traces (accumulate the group generators found by traces) */
options.writeautoms = FALSE;
Expand Down Expand Up @@ -1297,6 +1347,9 @@ SCIP_RETCODE SYMcomputeSymmetryGenerators(
data_.perms = NULL;
data_.symtype = SCIPgetSymgraphSymtype(symgraph);
data_.restricttovars = TRUE;
data_.ntreenodes = 0;
SCIP_CALL( SCIPgetIntParam(scip, "propagating/symmetry/nautymaxncells", &data_.maxncells) );
SCIP_CALL( SCIPgetIntParam(scip, "propagating/symmetry/nautymaxnnodes", &data_.maxnnodes) );

/* call nauty/traces */
#ifdef NAUTY
Expand Down Expand Up @@ -1481,6 +1534,9 @@ SCIP_Bool SYMcheckGraphsAreIdentical(
data_.perms = NULL;
data_.symtype = symtype;
data_.restricttovars = FALSE;
data_.ntreenodes = 0;
SCIP_CALL( SCIPgetIntParam(scip, "propagating/symmetry/nautymaxncells", &data_.maxncells) ); /*lint !e641*//*lint !e732*/
SCIP_CALL( SCIPgetIntParam(scip, "propagating/symmetry/nautymaxnnodes", &data_.maxnnodes) ); /*lint !e641*//*lint !e732*/

/* call nauty/traces */
#ifdef NAUTY
Expand Down
79 changes: 76 additions & 3 deletions src/symmetry/compute_symmetry_sassy_nauty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,19 @@ struct SYMMETRY_Data
SCIP_Bool restricttovars; /**< whether permutations shall be restricted to variables */
};

#ifdef NAUTY
/** struct for nauty callback */
struct NAUTY_Data
{
SCIP* scip; /**< SCIP pointer */
int ntreenodes; /**< number of nodes visitied in nauty's search tree */
int maxncells; /**< maximum number of cells in nauty's search tree */
int maxnnodes; /**< maximum number of nodes in nauty's search tree */
};

/** static data for nauty callback */
static struct NAUTY_Data nautydata_;
#endif

/* ------------------- hook functions ------------------- */

Expand Down Expand Up @@ -190,6 +203,55 @@ void sassyhook(
data->perms[data->nperms++] = p;
}

#ifdef NAUTY

/** callback function for nauty to terminate early */ /*lint -e{715}*/
static
void nautyterminationhook(
graph* g, /**< sparse graph for nauty */
int* lab, /**< labels of node */
int* ptn, /**< array indicating change of set in node parition of graph */
int level, /**< level of current node in nauty's tree */
int numcells, /**< number of cells in current partition */
int tc, /**< index of target cells in lab if children need to be explored */
int code, /**< code produced by refinement and vertex-invariant procedures */
int m, /**< number of edges in the graph */
int n /**< number of nodes in the graph */
)
{ /* lint --e{715} */
SCIP_Bool terminate = FALSE;
nautydata_.ntreenodes++;

/* add some iteration limit to avoid spending too much time in nauty */
if ( numcells >= nautydata_.maxncells )
{
terminate = TRUE;
SCIPverbMessage(nautydata_.scip, SCIP_VERBLEVEL_MINIMAL, NULL,
"symmetry computation terminated early, because number of cells %d in Nauty exceeds limit of %d\n",
numcells, nautydata_.maxncells);
SCIPverbMessage(nautydata_.scip, SCIP_VERBLEVEL_MINIMAL, NULL,
"for running full symmetry detection, increase value of parameter propagating/symmetry/nautymaxncells\n");
}
else if ( nautydata_.ntreenodes >= nautydata_.maxnnodes )
{
terminate = TRUE;
SCIPverbMessage(nautydata_.scip, SCIP_VERBLEVEL_MINIMAL, NULL,
"symmetry computation terminated early, because number of"
" nodes %d in Nauty's search tree exceeds limit of %d\n", nautydata_.ntreenodes, nautydata_.maxnnodes);
SCIPverbMessage(nautydata_.scip, SCIP_VERBLEVEL_MINIMAL, NULL,
"for running full symmetry detection, increase value of"
" parameter propagating/symmetry/nautymaxnnodes\n");
}

if ( terminate )
{
/* request a kill from nauty */
nauty_kill_request = 1;
return;
}
}

#endif

/** return whether symmetry can be computed */
SCIP_Bool SYMcanComputeSymmetry(void)
Expand Down Expand Up @@ -251,7 +313,9 @@ SCIP_RETCODE computeAutomorphisms(
* (needed for freeing storage) */
SCIP_Real* log10groupsize, /**< pointer to store log10 of size of group */
SCIP_Bool restricttovars, /**< whether permutations shall be restricted to variables */
SCIP_Real* symcodetime /**< pointer to store the time for symmetry code */
SCIP_Real* symcodetime, /**< pointer to store the time for symmetry code */
SCIP_Bool canterminateearly /**< whether we allow to interrupt symmetry detection early
* (e.g., because of iteration limits) */
)
{
SCIP_Real oldtime;
Expand Down Expand Up @@ -283,6 +347,13 @@ SCIP_RETCODE computeAutomorphisms(
data.perms = NULL;
data.restricttovars = restricttovars;

#ifdef NAUTY
nautydata_.scip = scip;
nautydata_.ntreenodes = 0;
SCIP_CALL( SCIPgetIntParam(scip, "propagating/symmetry/nautymaxncells", &nautydata_.maxncells) );
SCIP_CALL( SCIPgetIntParam(scip, "propagating/symmetry/nautymaxnnodes", &nautydata_.maxnnodes) );
#endif

oldtime = SCIPgetSolvingTime(scip);

/* set up sassy preprocessor */
Expand Down Expand Up @@ -316,6 +387,8 @@ SCIP_RETCODE computeAutomorphisms(
options.writeautoms = FALSE;
options.userautomproc = sassy::preprocessor::nauty_hook;
options.defaultptn = FALSE; /* use color classes */
if ( canterminateearly )
options.usernodeproc = nautyterminationhook;
*log10groupsize = 0.0;
if(sg.nv > 0) {
sparsenauty(&sg, lab, ptn, orbits, &options, &stats, NULL);
Expand Down Expand Up @@ -400,7 +473,7 @@ SCIP_RETCODE SYMcomputeSymmetryGenerators(

/* compute symmetries */
SCIP_CALL( computeAutomorphisms(scip, SCIPgetSymgraphSymtype(symgraph), &sassygraph, SCIPgetSymgraphNVars(symgraph),
maxgenerators, perms, nperms, nmaxperms, log10groupsize, TRUE, symcodetime) );
maxgenerators, perms, nperms, nmaxperms, log10groupsize, TRUE, symcodetime, TRUE) );

return SCIP_OKAY;
}
Expand Down Expand Up @@ -432,7 +505,7 @@ SCIP_Bool SYMcheckGraphsAreIdentical(

/* compute symmetries */
SCIP_CALL_ABORT( computeAutomorphisms(scip, SCIPgetSymgraphSymtype(G1), &sassygraph, nnodes, 0,
&perms, &nperms, &nmaxperms, &log10groupsize, FALSE, &symcodetime) );
&perms, &nperms, &nmaxperms, &log10groupsize, FALSE, &symcodetime, FALSE) );

/* since G1 and G2 are connected and disjoint, they are isomorphic iff there is a permutation
* mapping a node from G1 to a node of G2
Expand Down

0 comments on commit edff984

Please sign in to comment.