/***************************************************************************** * * * Graph-specific auxiliary source file for version 2.8 of nauty. * * * * Copyright (1984-2019) Brendan McKay. All rights reserved. * * Subject to waivers and disclaimers in nauty.h. * * * * CHANGE HISTORY * * 16-Nov-00 : initial creation out of nautil.c * * 22-Apr-01 : added aproto line for Magma * * EXTDEFS is no longer required * * removed dynamic allocation from refine1() * * 21-Nov-01 : use NAUTYREQUIRED in naugraph_check() * * 23-Nov-06 : add targetcell(); make bestcell() local * * 10-Dec-06 : remove BIGNAUTY * * 10-Nov-09 : remove shortish and permutation types * * 23-May-10 : add densenauty() * * 15-Jan-12 : add TLS_ATTR attributes * * 23-Jan-13 : add some parens to make icc happy * * 15-Oct-19 : fix default size of dnwork[] to match densenauty() * * 6-Apr-21 : increase work space in densenauty() * * *
*****************************************************************************/
#define ONE_WORD_SETS #include"nauty.h"
/* macros for hash-codes: */ #define MASH(l,i) ((((l) ^ 065435) + (i)) & 077777) /* : expression whose long value depends only on long l and int/long i.
Anything goes, preferably non-commutative. */
#define CLEANUP(l) ((int)((l) % 077777)) /* : expression whose value depends on long l and is less than 077777
when converted to int then short. Anything goes. */
#if !MAXN
DYNALLSTAT(set,workset,workset_sz);
DYNALLSTAT(int,workperm,workperm_sz);
DYNALLSTAT(int,bucket,bucket_sz);
DYNALLSTAT(set,dnwork,dnwork_sz); #else static TLS_ATTR set workset[MAXM]; /* used for scratch work */ static TLS_ATTR int workperm[MAXN]; static TLS_ATTR int bucket[MAXN+2]; static TLS_ATTR set dnwork[2*500*MAXM]; #endif
/***************************************************************************** * * * isautom(g,perm,digraph,m,n) = TRUE iff perm is an automorphism of g * * (i.e., g^perm = g). Symmetry is assumed unless digraph = TRUE. * * *
*****************************************************************************/
boolean
isautom(graph *g, int *perm, boolean digraph, int m, int n)
{
set *pg; int pos;
set *pgp; int posp,i;
for (pg = g, i = 0; i < n; pg += M, ++i)
{
pgp = GRAPHROW(g,perm[i],M);
pos = (digraph ? -1 : i);
while ((pos = nextelement(pg,M,pos)) >= 0)
{
posp = perm[pos]; if (!ISELEMENT(pgp,posp)) returnFALSE;
}
} returnTRUE;
}
/***************************************************************************** * * * testcanlab(g,canong,lab,samerows,m,n) compares g^lab to canong, * * using an ordering which is immaterial since it's only used here. The * * value returned is -1,0,1 if g^lab <,=,> canong. *samerows is set to * * the number of rows (0..n) of canong which are the same as those of g^lab. * * * * GLOBALS ACCESSED: workset<rw>,permset(),workperm<rw> * * *
*****************************************************************************/
int
testcanlab(graph *g, graph *canong, int *lab, int *samerows, int m, int n)
{ int i,j;
set *ph;
for (i = samerows, ph = GRAPHROW(canong,samerows,M);
i < n; ++i, ph += M)
permset(GRAPHROW(g,lab[i],M),ph,M,workperm);
}
/***************************************************************************** * * * refine(g,lab,ptn,level,numcells,count,active,code,m,n) performs a * * refinement operation on the partition at the specified level of the * * partition nest (lab,ptn). *numcells is assumed to contain the number of * * cells on input, and is updated. The initial set of active cells (alpha * * in the paper) is specified in the set active. Precisely, x is in active * * iff the cell starting at index x in lab is active. * * The resulting partition is equitable if active is correct (see the paper * * and the Guide). * * *code is set to a value which depends on the fine detail of the * * algorithm, but which is independent of the labelling of the graph. * * count is used for work space. * * * * GLOBALS ACCESSED: workset<w>,bit<r>,nextelement(),bucket<w>,workperm<w> * * *
*****************************************************************************/
void
refine(graph *g, int *lab, int *ptn, int level, int *numcells, int *count, set *active, int *code, int m, int n)
{
while (bmin > cnt) bucket[--bmin] = 0; while (bmax < cnt) bucket[++bmax] = 0;
++bucket[cnt];
count[i] = cnt;
} if (bmin == bmax)
{
longcode = MASH(longcode,bmin+cell1); continue;
}
c1 = cell1;
maxcell = -1; for (i = bmin; i <= bmax; ++i) if (bucket[i])
{
c2 = c1 + bucket[i];
bucket[i] = c1;
longcode = MASH(longcode,i+c1); if (c2-c1 > maxcell)
{
maxcell = c2-c1;
maxpos = c1;
} if (c1 != cell1)
{
ADDELEMENT(active,c1); if (c2-c1 == 1) hint = c1;
++*numcells;
} if (c2 <= cell2) ptn[c2-1] = level;
c1 = c2;
} for (i = cell1; i <= cell2; ++i)
workperm[bucket[count[i]]++] = lab[i]; for (i = cell1; i <= cell2; ++i) lab[i] = workperm[i]; if (!ISELEMENT(active,cell1))
{
ADDELEMENT(active,cell1);
DELELEMENT(active,maxpos);
}
}
}
}
longcode = MASH(longcode,*numcells);
*code = CLEANUP(longcode);
} #endif/* else case of MAXM==1 */
/***************************************************************************** * * * refine1(g,lab,ptn,level,numcells,count,active,code,m,n) is the same as * * refine(g,lab,ptn,level,numcells,count,active,code,m,n), except that * * m==1 is assumed for greater efficiency. The results are identical in all * * respects. See refine (above) for the specs. * * *
*****************************************************************************/
void
refine1(graph *g, int *lab, int *ptn, int level, int *numcells, int *count, set *active, int *code, int m, int n)
{ int i,c1,c2,labc1;
setword x; int split1,split2,cell1,cell2; int cnt,bmin,bmax; long longcode;
set *gptr,workset0; int maxcell,maxpos,hint;
/***************************************************************************** * * * cheapautom(ptn,level,digraph,n) returns TRUE if the partition at the * * specified level in the partition nest (lab,ptn) {lab is not needed here} * * satisfies a simple sufficient condition for its cells to be the orbits of * * some subgroup of the automorphism group. Otherwise it returns FALSE. * * It always returns FALSE if digraph!=FALSE. * * * * nauty assumes that this function will always return TRUE for any * * partition finer than one for which it returns TRUE. * * *
*****************************************************************************/
boolean
cheapautom(int *ptn, int level, boolean digraph, int n)
{ int i,k,nnt;
if (digraph) returnFALSE;
k = n;
nnt = 0; for (i = 0; i < n; ++i)
{
--k; if (ptn[i] > level)
{
++nnt; while (ptn[++i] > level) {}
}
}
return (k <= nnt + 1 || k <= 4);
}
/***************************************************************************** * * * bestcell(g,lab,ptn,level,tc_level,m,n) returns the index in lab of the * * start of the "best non-singleton cell" for fixing. If there is no * * non-singleton cell it returns n. * * This implementation finds the first cell which is non-trivially joined * * to the greatest number of other cells. * * * * GLOBALS ACCESSED: bit<r>,workperm<rw>,workset<rw>,bucket<rw> * * *
*****************************************************************************/
staticint
bestcell(const graph *g, constint *lab, constint *ptn, int level, int tc_level, int m, int n)
{ int i;
set *gp;
setword setword1,setword2; int v1,v2,nnt;
/* find non-singleton cells: put starts in workperm[0..nnt-1] */
i = nnt = 0;
while (i < n)
{ if (ptn[i] > level)
{
workperm[nnt++] = i; while (ptn[i] > level) ++i;
}
++i;
}
if (nnt == 0) return n;
/* set bucket[i] to # non-trivial neighbours of n.s. cell i */
for (i = nnt; --i >= 0;) bucket[i] = 0;
for (v2 = 1; v2 < nnt; ++v2)
{
EMPTYSET(workset,m);
i = workperm[v2] - 1; do
{
++i;
ADDELEMENT(workset,lab[i]);
} while (ptn[i] > level); for (v1 = 0; v1 < v2; ++v1)
{
gp = GRAPHROW(g,lab[workperm[v1]],m); #if MAXM==1
setword1 = *workset & *gp;
setword2 = *workset & ~*gp; #else
setword1 = setword2 = 0; for (i = m; --i >= 0;)
{
setword1 |= workset[i] & gp[i];
setword2 |= workset[i] & ~gp[i];
} #endif if (setword1 != 0 && setword2 != 0)
{
++bucket[v1];
++bucket[v2];
}
}
}
/* find first greatest bucket value */
v1 = 0;
v2 = bucket[0]; for (i = 1; i < nnt; ++i) if (bucket[i] > v2)
{
v1 = i;
v2 = bucket[i];
}
return (int)workperm[v1];
}
/***************************************************************************** * * * targetcell(g,lab,ptn,level,tc_level,digraph,hint,m,n) returns the index * * in lab of the next cell to split. * * hint is a suggestion for the answer, which is obeyed if it is valid. * * Otherwise we use bestcell() up to tc_level and the first non-trivial * * cell after that. * * *
*****************************************************************************/
int
targetcell(graph *g, int *lab, int *ptn, int level, int tc_level, boolean digraph, int hint, int m, int n)
{ int i;
if (hint >= 0 && ptn[hint] > level &&
(hint == 0 || ptn[hint-1] <= level)) return hint; elseif (level <= tc_level) return bestcell(g,lab,ptn,level,tc_level,m,n); else
{ for (i = 0; i < n && ptn[i] <= level; ++i) {} return (i == n ? 0 : i);
}
}
/***************************************************************************** * * * densenauty(g,lab,ptn,orbits,&options,&stats,m,n,h) * * is a slightly simplified interface to nauty(). It allocates enough * * workspace for 500 automorphisms and checks that the densegraph dispatch * * vector is in use. * * *
*****************************************************************************/
void
densenauty(graph *g, int *lab, int *ptn, int *orbits,
optionblk *options, statsblk *stats, int m, int n, graph *h)
{ if (options->dispatch != &dispatch_graph)
{
fprintf(ERRFILE,"Error: densenauty() needs standard options block\n"); exit(1);
}
#if !MAXN /* Don't increase 2*500*m in the next line unless you also increase
the default declaration of dnwork[] earlier. */
DYNALLOC1(set,dnwork,dnwork_sz,2*500*m,"densenauty malloc"); #endif
/***************************************************************************** * * * naugraph_check() checks that this file is compiled compatibly with the * * given parameters. If not, call exit(1). * * *
*****************************************************************************/
void
naugraph_check(int wordsize, int m, int n, int version)
{ if (wordsize != WORDSIZE)
{
fprintf(ERRFILE,"Error: WORDSIZE mismatch in naugraph.c\n"); exit(1);
}
#if MAXN if (m > MAXM)
{
fprintf(ERRFILE,"Error: MAXM inadequate in naugraph.c\n"); exit(1);
}
if (n > MAXN)
{
fprintf(ERRFILE,"Error: MAXN inadequate in naugraph.c\n"); exit(1);
} #endif
if (version < NAUTYREQUIRED)
{
fprintf(ERRFILE,"Error: naugraph.c version mismatch\n"); exit(1);
}
}
/***************************************************************************** * * * naugraph_freedyn() - free the dynamic memory in this module * * *
*****************************************************************************/
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.