/*****************************************************************************
* *
* 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 MAXM==1
#define M 1
#else
#define M m
#endif
/* aproto: header new_nauty_protos.h */
dispatchvec dispatch_graph =
{isautom,testcanlab,updatecan,refine,refine1,cheapautom,targetcell,
naugraph_freedyn,naugraph_check,NULL,NULL};
#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)) return FALSE ;
}
}
return TRUE ;
}
/*****************************************************************************
* *
* 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;
#if !MAXN
DYNALLOC1(int ,workperm,workperm_sz,n,"testcanlab" );
DYNALLOC1(set,workset,workset_sz,m,"testcanlab" );
#endif
for (i = 0 ; i < n; ++i) workperm[lab[i]] = i;
for (i = 0 , ph = canong; i < n; ++i, ph += M)
{
permset(GRAPHROW(g,lab[i],M),workset,M,workperm);
for (j = 0 ; j < M; ++j)
if (workset[j] < ph[j])
{
*samerows = i;
return -1 ;
}
else if (workset[j] > ph[j])
{
*samerows = i;
return 1 ;
}
}
*samerows = n;
return 0 ;
}
/*****************************************************************************
* *
* updatecan ( g , canong , lab , samerows , m , n ) sets canong = g ^ lab , assuming *
* the first samerows of canong are ok already . *
* *
* GLOBALS ACCESSED : permset ( ) , workperm < rw > *
* *
*****************************************************************************/
void
updatecan(graph *g, graph *canong, int *lab, int samerows, int m, int n)
{
int i;
set *ph;
#if !MAXN
DYNALLOC1(int ,workperm,workperm_sz,n,"updatecan" );
#endif
for (i = 0 ; i < n; ++i) workperm[lab[i]] = i;
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)
{
#if MAXM==1
refine1(g,lab,ptn,level,numcells,count,active,code,m,n);
}
#else
int i,c1,c2,labc1;
setword x;
set *set1,*set2;
int split1,split2,cell1,cell2;
int cnt,bmin,bmax;
long longcode;
set *gptr;
int maxcell,maxpos,hint;
#if !MAXN
DYNALLOC1(int ,workperm,workperm_sz,n,"refine" );
DYNALLOC1(set,workset,workset_sz,m,"refine" );
DYNALLOC1(int ,bucket,bucket_sz,n+2 ,"refine" );
#endif
longcode = *numcells;
split1 = -1 ;
hint = 0 ;
while (*numcells < n && ((split1 = hint, ISELEMENT(active,split1))
|| (split1 = nextelement(active,M,split1)) >= 0
|| (split1 = nextelement(active,M,-1 )) >= 0 ))
{
DELELEMENT(active,split1);
for (split2 = split1; ptn[split2] > level; ++split2) {}
longcode = MASH(longcode,split1+split2);
if (split1 == split2) /* trivial splitting cell */
{
gptr = GRAPHROW(g,lab[split1],M);
for (cell1 = 0 ; cell1 < n; cell1 = cell2 + 1 )
{
for (cell2 = cell1; ptn[cell2] > level; ++cell2) {}
if (cell1 == cell2) continue ;
c1 = cell1;
c2 = cell2;
while (c1 <= c2)
{
labc1 = lab[c1];
if (ISELEMENT(gptr,labc1))
++c1;
else
{
lab[c1] = lab[c2];
lab[c2] = labc1;
--c2;
}
}
if (c2 >= cell1 && c1 <= cell2)
{
ptn[c2] = level;
longcode = MASH(longcode,c2);
++*numcells;
if (ISELEMENT(active,cell1) || c2-cell1 >= cell2-c1)
{
ADDELEMENT(active,c1);
if (c1 == cell2) hint = c1;
}
else
{
ADDELEMENT(active,cell1);
if (c2 == cell1) hint = cell1;
}
}
}
}
else /* nontrivial splitting cell */
{
EMPTYSET(workset,m);
for (i = split1; i <= split2; ++i)
ADDELEMENT(workset,lab[i]);
longcode = MASH(longcode,split2-split1+1 );
for (cell1 = 0 ; cell1 < n; cell1 = cell2 + 1 )
{
for (cell2 = cell1; ptn[cell2] > level; ++cell2) {}
if (cell1 == cell2) continue ;
i = cell1;
set1 = workset;
set2 = GRAPHROW(g,lab[i],m);
cnt = 0 ;
for (c1 = m; --c1 >= 0 ;)
if ((x = ((*set1++) & (*set2++))) != 0 )
cnt += POPCOUNT(x);
count[i] = bmin = bmax = cnt;
bucket[cnt] = 1 ;
while (++i <= cell2)
{
set1 = workset;
set2 = GRAPHROW(g,lab[i],m);
cnt = 0 ;
for (c1 = m; --c1 >= 0 ;)
if ((x = ((*set1++) & (*set2++))) != 0 )
cnt += POPCOUNT(x);
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;
#if !MAXN
DYNALLOC1(int ,workperm,workperm_sz,n,"refine1" );
DYNALLOC1(int ,bucket,bucket_sz,n+2 ,"refine1" );
#endif
longcode = *numcells;
split1 = -1 ;
hint = 0 ;
while (*numcells < n && ((split1 = hint, ISELEMENT1(active,split1))
|| (split1 = nextelement(active,1 ,split1)) >= 0
|| (split1 = nextelement(active,1 ,-1 )) >= 0 ))
{
DELELEMENT1(active,split1);
for (split2 = split1; ptn[split2] > level; ++split2) {}
longcode = MASH(longcode,split1+split2);
if (split1 == split2) /* trivial splitting cell */
{
gptr = GRAPHROW(g,lab[split1],1 );
for (cell1 = 0 ; cell1 < n; cell1 = cell2 + 1 )
{
for (cell2 = cell1; ptn[cell2] > level; ++cell2) {}
if (cell1 == cell2) continue ;
c1 = cell1;
c2 = cell2;
while (c1 <= c2)
{
labc1 = lab[c1];
if (ISELEMENT1(gptr,labc1))
++c1;
else
{
lab[c1] = lab[c2];
lab[c2] = labc1;
--c2;
}
}
if (c2 >= cell1 && c1 <= cell2)
{
ptn[c2] = level;
longcode = MASH(longcode,c2);
++*numcells;
if (ISELEMENT1(active,cell1) || c2-cell1 >= cell2-c1)
{
ADDELEMENT1(active,c1);
if (c1 == cell2) hint = c1;
}
else
{
ADDELEMENT1(active,cell1);
if (c2 == cell1) hint = cell1;
}
}
}
}
else /* nontrivial splitting cell */
{
workset0 = 0 ;
for (i = split1; i <= split2; ++i)
ADDELEMENT1(&workset0,lab[i]);
longcode = MASH(longcode,split2-split1+1 );
for (cell1 = 0 ; cell1 < n; cell1 = cell2 + 1 )
{
for (cell2 = cell1; ptn[cell2] > level; ++cell2) {}
if (cell1 == cell2) continue ;
i = cell1;
if ((x = workset0 & g[lab[i]]) != 0 )
cnt = POPCOUNT(x);
else
cnt = 0 ;
count[i] = bmin = bmax = cnt;
bucket[cnt] = 1 ;
while (++i <= cell2)
{
if ((x = workset0 & g[lab[i]]) != 0 )
cnt = POPCOUNT(x);
else
cnt = 0 ;
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)
{
ADDELEMENT1(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 (!ISELEMENT1(active,cell1))
{
ADDELEMENT1(active,cell1);
DELELEMENT1(active,maxpos);
}
}
}
}
longcode = MASH(longcode,*numcells);
*code = CLEANUP(longcode);
}
/*****************************************************************************
* *
* 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) return FALSE ;
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 > *
* *
*****************************************************************************/
static int
bestcell(const graph *g, const int *lab, const int *ptn, int level,
int tc_level, int m, int n)
{
int i;
set *gp;
setword setword1,setword2;
int v1,v2,nnt;
#if !MAXN
DYNALLOC1(int ,workperm,workperm_sz,n,"bestcell" );
DYNALLOC1(set,workset,workset_sz,m,"bestcell" );
DYNALLOC1(int ,bucket,bucket_sz,n+2 ,"bestcell" );
#endif
/* 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;
else if (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
nauty(g,lab,ptn,NULL,orbits,options,stats,dnwork,2 *500 *m,m,n,h);
}
/*****************************************************************************
* *
* 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 *
* *
*****************************************************************************/
void
naugraph_freedyn(void )
{
#if !MAXN
DYNFREE(workset,workset_sz);
DYNFREE(workperm,workperm_sz);
DYNFREE(bucket,bucket_sz);
DYNFREE(dnwork,dnwork_sz);
#endif
}
Messung V0.5 in Prozent C=97 H=59 G=80
¤ Dauer der Verarbeitung: 0.19 Sekunden
(vorverarbeitet am 2026-06-15)
¤
*© Formatika GbR, Deutschland