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"
108 nauty_kill_request = 1;
124 for (
int j = 0; j < permlen; ++j)
126 if ( (
int) p[j] != j )
186 "symmetry computation terminated early, because number of cells %d in Nauty exceeds limit of %d\n",
189 "for running full symmetry detection, increase value of parameter propagating/symmetry/nautymaxncells\n");
195 "symmetry computation terminated early, because number of"
198 "for running full symmetry detection, increase value of"
199 " parameter propagating/symmetry/nautymaxnnodes\n");
205 nauty_kill_request = 1;
231 nauty_kill_request = 1;
247 for (j = 0; j < permlen; ++j)
249 if ( (
int) p[j] != j )
310 if ( first < 0 && second < 0 )
316 if ( first < 0 || second < 0 )
322 if ( first >= 0 && second >= 0 )
330 else if ( first >= 0 )
379 assert( *internodeid >= 0 );
382 assert( *maxdegrees > 0 );
389 assert( commonnodeidx <= *internodeid );
398 curcolor = colors[0];
400 for (e = 1; e < nneighbors; ++e)
403 if ( colors[e] != curcolor )
409 (*degrees)[*internodeid] = 1;
410 ++(*degrees)[commonnodeidx];
411 (*colorstostore)[*internodeid] = curcolor;
413 for (f = curstart; f < e; ++f)
415 assert( neighbors[f] <= *internodeid );
416 ++(*degrees)[*internodeid];
417 ++(*degrees)[neighbors[f]];
422 SG->e[edgestartpos[commonnodeidx]++] = *internodeid;
423 SG->e[edgestartpos[*internodeid]++] = commonnodeidx;
425 for (f = curstart; f < e; ++f)
427 SG->e[edgestartpos[neighbors[f]]++] = *internodeid;
428 SG->e[edgestartpos[*internodeid]++] = neighbors[f];
432 *naddededges += e - curstart + 1;
435 curcolor = colors[e];
446 (*degrees)[*internodeid] = 1;
447 ++(*degrees)[commonnodeidx];
448 (*colorstostore)[*internodeid] = curcolor;
450 for (f = curstart; f < nneighbors; ++f)
452 assert( neighbors[f] <= *internodeid );
453 ++(*degrees)[*internodeid];
454 ++(*degrees)[neighbors[f]];
459 SG->e[edgestartpos[commonnodeidx]++] = *internodeid;
460 SG->e[edgestartpos[*internodeid]++] = commonnodeidx;
462 for (f = curstart; f < nneighbors; ++f)
464 SG->e[edgestartpos[*internodeid]++] = neighbors[f];
465 SG->e[edgestartpos[neighbors[f]]++] = *internodeid;
469 *naddededges += nneighbors - curstart + 1;
494 int* groupfirsts =
NULL;
495 int* groupseconds =
NULL;
496 int* groupcolors =
NULL;
498 int edgebegincnt = 0;
528 nvarnodestoadd = nsymvars;
532 nvarnodestoadd = 2 * nsymvars;
548 for (j = 0; j < *
nnodes; ++j)
555 for (j = 0; j < nvarnodestoadd; ++j)
565 for (j = 0; j < *
nnodes; ++j)
567 SG->d[j] = (*degrees)[j];
568 SG->v[j] = (size_t) (
unsigned) edgebegincnt;
569 pos[j] = edgebegincnt;
570 edgebegincnt += (*degrees)[j];
594 first += nvarnodestoadd;
596 second = -second - 1;
598 second += nvarnodestoadd;
610 groupfirsts[ngroupedges] = first;
611 groupseconds[ngroupedges] = second;
615 groupfirsts[ngroupedges] = second;
616 groupseconds[ngroupedges] = first;
634 ++(*degrees)[second];
635 (*degrees)[internodeid] = 2;
646 SG->e[pos[first]++] = internodeid;
647 SG->e[pos[internodeid]++] = first;
648 SG->e[pos[second]++] = internodeid;
649 SG->e[pos[internodeid]++] = second;
651 assert( first == *
nnodes - 1 || pos[first] <= (
int) SG->v[first+1] );
652 assert( second == *
nnodes - 1 || pos[second] <= (
int) SG->v[second+1] );
653 assert( internodeid == *
nnodes - 1 || pos[internodeid] <= (
int) SG->v[internodeid+1] );
663 ++(*degrees)[second];
669 SG->e[pos[first]++] = second;
670 SG->e[pos[second]++] = first;
672 assert( first == *
nnodes - 1 || pos[first] <= (
int) SG->v[first+1] );
673 assert( second == *
nnodes - 1 || pos[second] <= (
int) SG->v[second+1] );
680 if ( ngroupedges > 0 )
689 firstnodeidx = groupfirsts[0];
691 for (j = 1; j < ngroupedges; ++j)
694 if ( groupfirsts[j] != firstnodeidx )
697 degrees, maxdegrees, colors, ncolors,
nnodes, nedges, firstnodeidx, &groupseconds[firstidx],
698 &groupcolors[firstidx], j - firstidx, &naddednodes, &naddededges) );
701 firstnodeidx = groupfirsts[j];
706 *nedges += naddededges;
713 degrees, maxdegrees, colors, ncolors,
nnodes, nedges, firstnodeidx, &groupseconds[firstidx],
714 &groupcolors[firstidx], ngroupedges - firstidx, &naddednodes, &naddededges) );
719 *nedges += naddededges;
733 for (j = 0; j < nvarnodestoadd; ++j)
739 for (j = 0; j < nsymvars; ++j)
741 SG->e[pos[j]++] = j + nsymvars;
742 SG->e[pos[j + nsymvars]++] = j;
744 assert( pos[j] <= (
int) SG->v[j+1] );
745 assert( j + nsymvars == *
nnodes - 1 || pos[j+nsymvars] <= (
int) SG->v[j+nsymvars+1] );
789 int* nnodesfromgraph1,
797 int* nvarused1 =
NULL;
798 int* nvarused2 =
NULL;
799 int* varlabel =
NULL;
800 int* groupfirsts =
NULL;
801 int* groupseconds =
NULL;
802 int* groupcolors =
NULL;
805 int edgebegincnt = 0;
831 assert( ! determinesize || nnodesfromgraph1 !=
NULL );
855 nvarnodestoadd = nsymvars;
859 nvarnodestoadd = 2 * nsymvars;
867 for (e = 0; e < nsymedges; ++e)
872 nvarused1[-first - 1] += 1;
874 nvarused1[-second - 1] += 1;
879 nvarused2[-first - 1] += 1;
881 nvarused2[-second - 1] += 1;
884 for (j = 0; j < nvarnodestoadd; ++j)
887 if ( nvarused1[j] != nvarused2[j] )
898 varlabel[j] = nusdvars++;
919 for (j = 0; j < *
nnodes; ++j)
921 SG->d[j] = (*degrees)[j];
922 SG->v[j] = (size_t) (
unsigned) edgebegincnt;
923 pos[j] = edgebegincnt;
924 edgebegincnt += (*degrees)[j];
938 for (
i = 0;
i < 2; ++
i)
941 symgraph =
i == 0 ? graph1 : graph2;
948 for (j = 0; j < nvarnodestoadd; ++j)
950 if ( varlabel[j] >= 0 )
953 (*degrees)[nodeshift + varlabel[j]] = 0;
964 (*degrees)[nodeshift + nusdvars + j] = 0;
973 for (j = 0; j < nvarnodestoadd; ++j)
975 if ( varlabel[j] >= 0 )
982 internodeid = nodeshift + curnnodes;
983 for (e = 0; e < nsymedges; ++e)
990 first = varlabel[-first - 1];
992 first = nusdvars + first;
994 second = varlabel[-second - 1];
996 second = nusdvars + second;
1006 groupfirsts[ngroupedges] = nodeshift + first;
1007 groupseconds[ngroupedges] = nodeshift + second;
1011 groupfirsts[ngroupedges] = nodeshift + second;
1012 groupseconds[ngroupedges] = nodeshift + first;
1025 if ( determinesize )
1030 ++(*degrees)[nodeshift + first];
1031 ++(*degrees)[nodeshift + second];
1032 (*degrees)[internodeid] = 2;
1035 (*colors)[internodeid] = nusdvars + color;
1044 SG->e[pos[internodeid]++] = nodeshift + first;
1045 SG->e[pos[internodeid]++] = nodeshift + second;
1046 SG->e[pos[nodeshift + first]++] = internodeid;
1047 SG->e[pos[nodeshift + second]++] = internodeid;
1050 || pos[internodeid] <= (
int) SG->v[internodeid+1] );
1052 || pos[nodeshift + first] <= (
int) SG->v[nodeshift+first+1] );
1054 pos[nodeshift + second] <= (
int) SG->v[nodeshift+second+1] );
1061 if ( determinesize )
1063 ++(*degrees)[nodeshift + first];
1064 ++(*degrees)[nodeshift + second];
1069 SG->e[pos[nodeshift + first]++] = nodeshift + second;
1070 SG->e[pos[nodeshift + second]++] = nodeshift + first;
1072 assert( nodeshift+first == *
nnodes - 1 || pos[nodeshift+first] <= (
int) SG->v[nodeshift+first+1] );
1073 assert( nodeshift+second == *
nnodes - 1 || pos[nodeshift+second] <= (
int) SG->v[nodeshift+second+1] );
1080 if ( ngroupedges > 0 )
1089 firstnodeidx = groupfirsts[0];
1091 for (j = 1; j < ngroupedges; ++j)
1094 if ( groupfirsts[j] != firstnodeidx )
1097 degrees, maxdegrees, colors, ncolors,
nnodes, nedges, firstnodeidx,
1098 &groupseconds[firstidx], &groupcolors[firstidx], j - firstidx, &naddednodes, &naddededges) );
1101 firstnodeidx = groupfirsts[j];
1103 if ( determinesize )
1106 *nedges += naddededges;
1108 curnnodes += naddednodes;
1114 degrees, maxdegrees, colors, ncolors,
nnodes, nedges, firstnodeidx,
1115 &groupseconds[firstidx], &groupcolors[firstidx], ngroupedges - firstidx, &naddednodes, &naddededges) );
1117 if ( determinesize )
1120 *nedges += naddededges;
1122 curnnodes += naddednodes;
1128 if ( determinesize )
1130 for (j = 0; j < nusdvars; ++j)
1131 ++(*degrees)[nodeshift + j];
1132 (*nedges) += nusdvars / 2;
1136 for (j = 0; j < nusdvars/2; ++j)
1138 SG->e[pos[nodeshift+j]++] = nodeshift + j + nusdvars/2;
1139 SG->e[pos[nodeshift + j + nusdvars/2]++] = nodeshift + j;
1141 assert( pos[nodeshift+j] <= (
int) SG->v[nodeshift+j+1] );
1143 || pos[nodeshift+j+nusdvars/2] <= (
int) SG->v[nodeshift+j+nusdvars/2+1] );
1147 nodeshift = curnnodes;
1150 if ( determinesize &&
i == 0 )
1151 *nnodesfromgraph1 = *
nnodes;
1155 if ( determinesize )
1161 for (j = 0; j < *
nnodes - 1; ++j)
1164 (*nedges) += *
nnodes - 1;
1165 (*colors)[*
nnodes - 1] = 8;
1169 for (j = 0; j < *
nnodes - 1; ++j)
1171 SG->e[pos[j]++] = *
nnodes - 1;
1172 SG->e[pos[*
nnodes-1]++] = j;
1186 if ( determinesize )
1187 *nusedvars = nusdvars;
1206 (void)
SCIPsnprintf(
nautyname, (
int)
sizeof(
nautyname),
"Nauty %d.%d.%d", NAUTYVERSIONID/10000, (NAUTYVERSIONID%10000)/1000, (NAUTYVERSIONID%1000)/10);
1208 (void)
SCIPsnprintf(
nautyname, (
int)
sizeof(
nautyname),
"Traces %d.%d.%d", NAUTYVERSIONID/10000, (NAUTYVERSIONID%10000)/1000, (NAUTYVERSIONID%1000)/10);
1217 return "Computing Graph Automorphism Groups by Brendan D. McKay (https://users.cecs.anu.edu.au/~bdm/nauty/)";
1219 return "Computing Graph Automorphism Groups by Adolfo Piperno (https://pallini.di.uniroma1.it/)";
1264 DEFAULTOPTIONS_SPARSEGRAPH(options);
1267 static DEFAULTOPTIONS_TRACES(options);
1275 *log10groupsize = 0;
1281 options.writeautoms =
FALSE;
1283 options.defaultptn =
FALSE;
1287 options.writeautoms =
FALSE;
1288 options.userautomproc = traceshook;
1289 options.defaultptn =
FALSE;
1296 °rees, &maxdegrees, &colors, &ncolors, &success) );
1301 "Stopped symmetry computation: Symmetry graph would become too large.\n");
1308 SG_ALLOC(SG, (
size_t)
nnodes, 2 * (
size_t)(
unsigned) nedges,
"malloc");
1311 SG.nde = (size_t) (
unsigned) (2 * nedges);
1315 °rees, &maxdegrees, &colors, &ncolors, &success) );
1325 for (v = 0; v <
nnodes; ++v)
1332 for (v = 0; v <
nnodes; ++v)
1334 if ( v <
nnodes-1 && colors[v] == colors[v+1] )
1356 sparsenauty(&SG, lab, ptn, orbits, &options, &stats,
NULL);
1358 Traces(&SG, lab, ptn, orbits, &options, &stats,
NULL);
1388 *log10groupsize = (
SCIP_Real) stats.grpsize2;
1422 &colors, &ncolors, &nusedvars, &nnodesfromG1, &success) );
1439 DEFAULTOPTIONS_SPARSEGRAPH(options);
1442 static DEFAULTOPTIONS_TRACES(options);
1449 options.writeautoms =
FALSE;
1451 options.defaultptn =
FALSE;
1454 options.writeautoms =
FALSE;
1455 options.userautomproc = traceshook;
1456 options.defaultptn =
FALSE;
1462 SG_ALLOC(SG, (
size_t)
nnodes, 2 * (
size_t)(
unsigned) nedges,
"malloc");
1465 SG.nde = (size_t) (
unsigned) (2 * nedges);
1469 &colors, &ncolors, &nusedvars,
NULL, &success) );
1474#ifdef SCIP_DISABLED_CODE
1479 for (v = 0; v < SG.nv; ++v)
1484 for (v = 0; v < SG.nv; ++v)
1489 for (v = 0; v < SG.nv; ++v)
1491 for (
int w = 0;
w < SG.d[v]; ++
w)
1504 for (v = 0; v <
nnodes; ++v)
1511 for (v = 0; v <
nnodes; ++v)
1513 if ( v <
nnodes-1 && colors[v] == colors[v+1] )
1519#ifdef SCIP_DISABLED_CODE
1522 for (v = 0; v < SG.nv; ++v)
1543 sparsenauty(&SG, lab, ptn, orbits, &options, &stats,
NULL);
1545 Traces(&SG, lab, ptn, orbits, &options, &stats,
NULL);
1563 for (
int i = 0;
i < nnodesfromG1; ++
i)
interface for symmetry computations
SCIP_Bool SYMcheckGraphsAreIdentical(SCIP *scip, SYM_SYMTYPE symtype, SYM_GRAPH *G1, SYM_GRAPH *G2)
const char * SYMsymmetryGetName(void)
static void nautyhook(int count, int *p, int *orbits, int numorbits, int stabvertex, int n)
const char * SYMsymmetryGetAddName(void)
static struct NAUTY_Data data_
SCIP_Bool SYMcanComputeSymmetry(void)
const char * SYMsymmetryGetDesc(void)
static TLS_ATTR char nautyname[20]
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)
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)
int SCIPsnprintf(char *t, int len, const char *s,...)
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
enum SCIP_Retcode SCIP_RETCODE
enum SYM_Symtype SYM_SYMTYPE
enum SYM_Nodetype SYM_NODETYPE