39#pragma GCC diagnostic ignored "-Wunused-variable"
40#pragma GCC diagnostic ignored "-Wredundant-decls"
41#pragma GCC diagnostic ignored "-Wpedantic"
44#include "nauty/nauty.h"
45#include "nauty/nausparse.h"
47#include "nauty/traces.h"
50#pragma GCC diagnostic warning "-Wunused-variable"
51#pragma GCC diagnostic warning "-Wredundant-decls"
52#pragma GCC diagnostic warning "-Wpedantic"
62#include "tinycthread/tinycthread.h"
80#if defined(_Thread_local)
111 nauty_kill_request = 1;
116 if (
data_.restricttovars )
119 permlen =
data_.npermvars;
121 permlen = 2 *
data_.npermvars;
127 for (
int j = 0; j < permlen; ++j)
129 if ( (
int) p[j] != j )
138 if (
data_.nmaxperms <= 0 )
140 if (
data_.maxgenerators == 0 )
141 data_.nmaxperms = 100;
159 data_.nmaxperms = newsize;
182 if ( level >
data_.maxlevel &&
data_.maxlevel >= 0 )
185 "symmetry computation terminated early because Nauty level limit %d is exceeded\n",
188 "for running full symmetry detection, increase value of parameter propagating/symmetry/nautymaxlevel\n");
189 nauty_kill_request = 1;
214 nauty_kill_request = 1;
219 if (
data_.restricttovars )
222 permlen =
data_.npermvars;
224 permlen = 2 *
data_.npermvars;
230 for (j = 0; j < permlen; ++j)
232 if ( (
int) p[j] != j )
241 if (
data_.nmaxperms <= 0 )
243 if (
data_.maxgenerators == 0 )
244 data_.nmaxperms = 100;
262 data_.nmaxperms = newsize;
293 if ( first < 0 && second < 0 )
299 if ( first < 0 || second < 0 )
305 if ( first >= 0 && second >= 0 )
313 else if ( first >= 0 )
362 assert( *internodeid >= 0 );
365 assert( *maxdegrees > 0 );
372 assert( commonnodeidx <= *internodeid );
381 curcolor = colors[0];
383 for (e = 1; e < nneighbors; ++e)
386 if ( colors[e] != curcolor )
392 (*degrees)[*internodeid] = 1;
393 ++(*degrees)[commonnodeidx];
394 (*colorstostore)[*internodeid] = curcolor;
396 for (f = curstart; f < e; ++f)
398 assert( neighbors[f] <= *internodeid );
399 ++(*degrees)[*internodeid];
400 ++(*degrees)[neighbors[f]];
405 SG->e[edgestartpos[commonnodeidx]++] = *internodeid;
406 SG->e[edgestartpos[*internodeid]++] = commonnodeidx;
408 for (f = curstart; f < e; ++f)
410 SG->e[edgestartpos[neighbors[f]]++] = *internodeid;
411 SG->e[edgestartpos[*internodeid]++] = neighbors[f];
415 *naddededges += e - curstart + 1;
418 curcolor = colors[e];
429 (*degrees)[*internodeid] = 1;
430 ++(*degrees)[commonnodeidx];
431 (*colorstostore)[*internodeid] = curcolor;
433 for (f = curstart; f < nneighbors; ++f)
435 assert( neighbors[f] <= *internodeid );
436 ++(*degrees)[*internodeid];
437 ++(*degrees)[neighbors[f]];
442 SG->e[edgestartpos[commonnodeidx]++] = *internodeid;
443 SG->e[edgestartpos[*internodeid]++] = commonnodeidx;
445 for (f = curstart; f < nneighbors; ++f)
447 SG->e[edgestartpos[*internodeid]++] = neighbors[f];
448 SG->e[edgestartpos[neighbors[f]]++] = *internodeid;
452 *naddededges += nneighbors - curstart + 1;
477 int* groupfirsts =
NULL;
478 int* groupseconds =
NULL;
479 int* groupcolors =
NULL;
481 int edgebegincnt = 0;
511 nvarnodestoadd = nsymvars;
515 nvarnodestoadd = 2 * nsymvars;
531 for (j = 0; j < *
nnodes; ++j)
538 for (j = 0; j < nvarnodestoadd; ++j)
548 for (j = 0; j < *
nnodes; ++j)
550 SG->d[j] = (*degrees)[j];
551 SG->v[j] = (size_t) (
unsigned) edgebegincnt;
552 pos[j] = edgebegincnt;
553 edgebegincnt += (*degrees)[j];
577 first += nvarnodestoadd;
579 second = -second - 1;
581 second += nvarnodestoadd;
593 groupfirsts[ngroupedges] = first;
594 groupseconds[ngroupedges] = second;
598 groupfirsts[ngroupedges] = second;
599 groupseconds[ngroupedges] = first;
617 ++(*degrees)[second];
618 (*degrees)[internodeid] = 2;
629 SG->e[pos[first]++] = internodeid;
630 SG->e[pos[internodeid]++] = first;
631 SG->e[pos[second]++] = internodeid;
632 SG->e[pos[internodeid]++] = second;
634 assert( first == *
nnodes - 1 || pos[first] <= (
int) SG->v[first+1] );
635 assert( second == *
nnodes - 1 || pos[second] <= (
int) SG->v[second+1] );
636 assert( internodeid == *
nnodes - 1 || pos[internodeid] <= (
int) SG->v[internodeid+1] );
646 ++(*degrees)[second];
652 SG->e[pos[first]++] = second;
653 SG->e[pos[second]++] = first;
655 assert( first == *
nnodes - 1 || pos[first] <= (
int) SG->v[first+1] );
656 assert( second == *
nnodes - 1 || pos[second] <= (
int) SG->v[second+1] );
663 if ( ngroupedges > 0 )
672 firstnodeidx = groupfirsts[0];
674 for (j = 1; j < ngroupedges; ++j)
677 if ( groupfirsts[j] != firstnodeidx )
680 degrees, maxdegrees, colors, ncolors,
nnodes, nedges, firstnodeidx, &groupseconds[firstidx],
681 &groupcolors[firstidx], j - firstidx, &naddednodes, &naddededges) );
684 firstnodeidx = groupfirsts[j];
689 *nedges += naddededges;
696 degrees, maxdegrees, colors, ncolors,
nnodes, nedges, firstnodeidx, &groupseconds[firstidx],
697 &groupcolors[firstidx], ngroupedges - firstidx, &naddednodes, &naddededges) );
702 *nedges += naddededges;
716 for (j = 0; j < nvarnodestoadd; ++j)
722 for (j = 0; j < nsymvars; ++j)
724 SG->e[pos[j]++] = j + nsymvars;
725 SG->e[pos[j + nsymvars]++] = j;
727 assert( pos[j] <= (
int) SG->v[j+1] );
728 assert( j + nsymvars == *
nnodes - 1 || pos[j+nsymvars] <= (
int) SG->v[j+nsymvars+1] );
772 int* nnodesfromgraph1,
780 int* nvarused1 =
NULL;
781 int* nvarused2 =
NULL;
782 int* varlabel =
NULL;
783 int* groupfirsts =
NULL;
784 int* groupseconds =
NULL;
785 int* groupcolors =
NULL;
788 int edgebegincnt = 0;
814 assert( ! determinesize || nnodesfromgraph1 !=
NULL );
838 nvarnodestoadd = nsymvars;
842 nvarnodestoadd = 2 * nsymvars;
850 for (e = 0; e < nsymedges; ++e)
855 nvarused1[-first - 1] += 1;
857 nvarused1[-second - 1] += 1;
862 nvarused2[-first - 1] += 1;
864 nvarused2[-second - 1] += 1;
867 for (j = 0; j < nvarnodestoadd; ++j)
870 if ( nvarused1[j] != nvarused2[j] )
881 varlabel[j] = nusdvars++;
902 for (j = 0; j < *
nnodes; ++j)
904 SG->d[j] = (*degrees)[j];
905 SG->v[j] = (size_t) (
unsigned) edgebegincnt;
906 pos[j] = edgebegincnt;
907 edgebegincnt += (*degrees)[j];
921 for (
i = 0;
i < 2; ++
i)
924 symgraph =
i == 0 ? graph1 : graph2;
931 for (j = 0; j < nvarnodestoadd; ++j)
933 if ( varlabel[j] >= 0 )
936 (*degrees)[nodeshift + varlabel[j]] = 0;
947 (*degrees)[nodeshift + nusdvars + j] = 0;
956 for (j = 0; j < nvarnodestoadd; ++j)
958 if ( varlabel[j] >= 0 )
965 internodeid = nodeshift + curnnodes;
966 for (e = 0; e < nsymedges; ++e)
973 first = varlabel[-first - 1];
975 first = nusdvars + first;
977 second = varlabel[-second - 1];
979 second = nusdvars + second;
989 groupfirsts[ngroupedges] = nodeshift + first;
990 groupseconds[ngroupedges] = nodeshift + second;
994 groupfirsts[ngroupedges] = nodeshift + second;
995 groupseconds[ngroupedges] = nodeshift + first;
1008 if ( determinesize )
1013 ++(*degrees)[nodeshift + first];
1014 ++(*degrees)[nodeshift + second];
1015 (*degrees)[internodeid] = 2;
1018 (*colors)[internodeid] = nusdvars + color;
1027 SG->e[pos[internodeid]++] = nodeshift + first;
1028 SG->e[pos[internodeid]++] = nodeshift + second;
1029 SG->e[pos[nodeshift + first]++] = internodeid;
1030 SG->e[pos[nodeshift + second]++] = internodeid;
1033 || pos[internodeid] <= (
int) SG->v[internodeid+1] );
1035 || pos[nodeshift + first] <= (
int) SG->v[nodeshift+first+1] );
1037 pos[nodeshift + second] <= (
int) SG->v[nodeshift+second+1] );
1044 if ( determinesize )
1046 ++(*degrees)[nodeshift + first];
1047 ++(*degrees)[nodeshift + second];
1052 SG->e[pos[nodeshift + first]++] = nodeshift + second;
1053 SG->e[pos[nodeshift + second]++] = nodeshift + first;
1055 assert( nodeshift+first == *
nnodes - 1 || pos[nodeshift+first] <= (
int) SG->v[nodeshift+first+1] );
1056 assert( nodeshift+second == *
nnodes - 1 || pos[nodeshift+second] <= (
int) SG->v[nodeshift+second+1] );
1063 if ( ngroupedges > 0 )
1072 firstnodeidx = groupfirsts[0];
1074 for (j = 1; j < ngroupedges; ++j)
1077 if ( groupfirsts[j] != firstnodeidx )
1080 degrees, maxdegrees, colors, ncolors,
nnodes, nedges, firstnodeidx,
1081 &groupseconds[firstidx], &groupcolors[firstidx], j - firstidx, &naddednodes, &naddededges) );
1084 firstnodeidx = groupfirsts[j];
1086 if ( determinesize )
1089 *nedges += naddededges;
1091 curnnodes += naddednodes;
1097 degrees, maxdegrees, colors, ncolors,
nnodes, nedges, firstnodeidx,
1098 &groupseconds[firstidx], &groupcolors[firstidx], ngroupedges - firstidx, &naddednodes, &naddededges) );
1100 if ( determinesize )
1103 *nedges += naddededges;
1105 curnnodes += naddednodes;
1111 if ( determinesize )
1113 for (j = 0; j < nusdvars; ++j)
1114 ++(*degrees)[nodeshift + j];
1115 (*nedges) += nusdvars / 2;
1119 for (j = 0; j < nusdvars/2; ++j)
1121 SG->e[pos[nodeshift+j]++] = nodeshift + j + nusdvars/2;
1122 SG->e[pos[nodeshift + j + nusdvars/2]++] = nodeshift + j;
1124 assert( pos[nodeshift+j] <= (
int) SG->v[nodeshift+j+1] );
1126 || pos[nodeshift+j+nusdvars/2] <= (
int) SG->v[nodeshift+j+nusdvars/2+1] );
1130 nodeshift = curnnodes;
1133 if ( determinesize &&
i == 0 )
1134 *nnodesfromgraph1 = *
nnodes;
1138 if ( determinesize )
1144 for (j = 0; j < *
nnodes - 1; ++j)
1147 (*nedges) += *
nnodes - 1;
1148 (*colors)[*
nnodes - 1] = 8;
1152 for (j = 0; j < *
nnodes - 1; ++j)
1154 SG->e[pos[j]++] = *
nnodes - 1;
1155 SG->e[pos[*
nnodes-1]++] = j;
1169 if ( determinesize )
1170 *nusedvars = nusdvars;
1183static const char nautyname[] = {
'N',
'a',
'u',
't',
'y',
' ', NAUTYVERSIONID/10000 +
'0',
'.', (NAUTYVERSIONID%10000)/1000 +
'0',
'.', (NAUTYVERSIONID%1000)/10 +
'0',
'\0'};
1185static const char nautyname[] = {
'T',
'r',
'a',
'c',
'e',
's',
' ', NAUTYVERSIONID/10000 +
'0',
'.', (NAUTYVERSIONID%10000)/1000 +
'0',
'.', (NAUTYVERSIONID%1000)/10 +
'0',
'\0'};
1198 return "Computing Graph Automorphism Groups by Brendan D. McKay (https://users.cecs.anu.edu.au/~bdm/nauty/)";
1200 return "Computing Graph Automorphism Groups by Adolfo Piperno (https://pallini.di.uniroma1.it/)";
1245 DEFAULTOPTIONS_SPARSEGRAPH(options);
1248 static DEFAULTOPTIONS_TRACES(options);
1256 *log10groupsize = 0;
1262 options.writeautoms =
FALSE;
1264 options.defaultptn =
FALSE;
1268 options.writeautoms =
FALSE;
1269 options.userautomproc = traceshook;
1270 options.defaultptn =
FALSE;
1277 °rees, &maxdegrees, &colors, &ncolors, &success) );
1282 "Stopped symmetry computation: Symmetry graph would become too large.\n");
1289 SG_ALLOC(SG, (
size_t)
nnodes, 2 * (
size_t)(
unsigned) nedges,
"malloc");
1292 SG.nde = (size_t) (
unsigned) (2 * nedges);
1296 °rees, &maxdegrees, &colors, &ncolors, &success) );
1306 for (v = 0; v <
nnodes; ++v)
1313 for (v = 0; v <
nnodes; ++v)
1315 if ( v <
nnodes-1 && colors[v] == colors[v+1] )
1326 data_.nmaxperms = 0;
1335 sparsenauty(&SG, lab, ptn, orbits, &options, &stats,
NULL);
1337 Traces(&SG, lab, ptn, orbits, &options, &stats,
NULL);
1350 if (
data_.nperms > 0 )
1367 *log10groupsize = log10(stats.grpsize1 * pow(10.0, (
SCIP_Real) stats.grpsize2));
1401 &colors, &ncolors, &nusedvars, &nnodesfromG1, &success) );
1418 DEFAULTOPTIONS_SPARSEGRAPH(options);
1421 static DEFAULTOPTIONS_TRACES(options);
1428 options.writeautoms =
FALSE;
1430 options.defaultptn =
FALSE;
1433 options.writeautoms =
FALSE;
1434 options.userautomproc = traceshook;
1435 options.defaultptn =
FALSE;
1441 SG_ALLOC(SG, (
size_t)
nnodes, 2 * (
size_t)(
unsigned) nedges,
"malloc");
1444 SG.nde = (size_t) (
unsigned) (2 * nedges);
1448 &colors, &ncolors, &nusedvars,
NULL, &success) );
1453#ifdef SCIP_DISABLED_CODE
1458 for (v = 0; v < SG.nv; ++v)
1463 for (v = 0; v < SG.nv; ++v)
1468 for (v = 0; v < SG.nv; ++v)
1470 for (
int w = 0;
w < SG.d[v]; ++
w)
1483 for (v = 0; v <
nnodes; ++v)
1490 for (v = 0; v <
nnodes; ++v)
1492 if ( v <
nnodes-1 && colors[v] == colors[v+1] )
1498#ifdef SCIP_DISABLED_CODE
1501 for (v = 0; v < SG.nv; ++v)
1511 data_.nmaxperms = 0;
1512 data_.maxgenerators = 0;
1520 sparsenauty(&SG, lab, ptn, orbits, &options, &stats,
NULL);
1522 Traces(&SG, lab, ptn, orbits, &options, &stats,
NULL);
1534 if (
data_.nperms == 0 )
1538 for (
int p = 0; p <
data_.nperms; ++p)
1540 for (
int i = 0;
i < nnodesfromG1; ++
i)
1542 if (
data_.perms[p][
i] >= nnodesfromG1 )
1551 for (
int p = 0; p <
data_.nperms; ++p)
interface for symmetry computations
static _Thread_local NAUTY_DATA data_
SCIP_Bool SYMcheckGraphsAreIdentical(SCIP *scip, SYM_SYMTYPE symtype, SYM_GRAPH *G1, SYM_GRAPH *G2)
const char * SYMsymmetryGetName(void)
static const char nautyname[]
static void nautyhook(int count, int *p, int *orbits, int numorbits, int stabvertex, int n)
const char * SYMsymmetryGetAddName(void)
SCIP_Bool SYMcanComputeSymmetry(void)
const char * SYMsymmetryGetDesc(void)
static SCIP_RETCODE createOrDetermineSizeGraphCheck(SCIP *scip, SYM_GRAPH *graph1, SYM_GRAPH *graph2, SCIP_Bool determinesize, sparsegraph *SG, int *nnodes, int *nedges, int **degrees, int *maxdegrees, int **colors, int *ncolors, int *nusedvars, int *nnodesfromgraph1, SCIP_Bool *success)
static void nautyterminationhook(graph *g, int *lab, int *ptn, int level, int numcells, int tc, int code, int m, int n)
static SCIP_RETCODE addOrDetermineEffectOfGroupedEdges(SCIP *scip, sparsegraph *SG, int *edgestartpos, SCIP_Bool determinesize, int *internodeid, int **degrees, int *maxdegrees, int **colorstostore, int *ncolorstostore, int *nnodes, int *nedges, int commonnodeidx, int *neighbors, int *colors, int nneighbors, int *naddednodes, int *naddededges)
struct NAUTY_Data NAUTY_DATA
static SCIP_RETCODE createOrDetermineSizeGraph(SCIP *scip, SYM_GRAPH *symgraph, SCIP_Bool determinesize, sparsegraph *SG, int *nnodes, int *nedges, int **degrees, int *maxdegrees, int **colors, int *ncolors, SCIP_Bool *success)
static SCIP_Bool isEdgeGroupable(SYM_GRAPH *symgraph, int edgeidx, SCIP_Bool groupbycons)
const char * SYMsymmetryGetAddDesc(void)
SCIP_RETCODE SYMcomputeSymmetryGenerators(SCIP *scip, int maxgenerators, SYM_GRAPH *symgraph, int *nperms, int *nmaxperms, int ***perms, SCIP_Real *log10groupsize, SCIP_Real *symcodetime)
Constraint handler for linear constraints in their most general form, .
constraint handler for nonlinear constraints specified by algebraic expressions
#define SCIP_CALL_ABORT(x)
private functions to work with algebraic expressions
power and signed power expression handlers
variable expression handler
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
SCIP_RETCODE SCIPgetIntParam(SCIP *scip, const char *name, int *value)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
#define SCIPensureBlockMemoryArray(scip, ptr, arraysizeptr, minsize)
#define SCIPallocClearBufferArray(scip, ptr, num)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
#define SCIPallocBufferArray(scip, ptr, num)
#define SCIPfreeBufferArray(scip, ptr)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
void SCIPsortIntIntInt(int *intarray1, int *intarray2, int *intarray3, int len)
SYM_NODETYPE SCIPgetSymgraphNodeType(SYM_GRAPH *graph, int nodeidx)
int SCIPgetSymgraphEdgeFirst(SYM_GRAPH *graph, int edgeidx)
SCIP_Bool SCIPhasGraphUniqueEdgetype(SYM_GRAPH *graph)
int SCIPgetSymgraphVarnodeColor(SYM_GRAPH *graph, int nodeidx)
int SCIPgetSymgraphNEdges(SYM_GRAPH *graph)
SYM_SYMTYPE SCIPgetSymgraphSymtype(SYM_GRAPH *graph)
int SCIPgetSymgraphEdgeSecond(SYM_GRAPH *graph, int edgeidx)
int SCIPgetSymgraphNConsnodes(SYM_GRAPH *graph)
int SCIPgetSymgraphNVars(SYM_GRAPH *graph)
SCIP_Bool SCIPisSymgraphEdgeColored(SYM_GRAPH *graph, int edgeidx)
int SCIPgetSymgraphNodeColor(SYM_GRAPH *graph, int nodeidx)
int SCIPgetSymgraphEdgeColor(SYM_GRAPH *graph, int edgeidx)
int SCIPgetSymgraphNNodes(SYM_GRAPH *graph)
assert(minobj< SCIPgetCutoffbound(scip))
public methods for memory management
methods for dealing with symmetry detection graphs
struct SYM_Graph SYM_GRAPH
enum SCIP_Retcode SCIP_RETCODE
enum SYM_Symtype SYM_SYMTYPE
enum SYM_Nodetype SYM_NODETYPE