/* naugroup.c
Procedures for handling groups found by nauty.
*/
#include "naugroup.h"
static permrec *freelist = NULL;
static int freelist_n = 0;
static grouprec *group = NULL;
static int group_depth = 0;
DYNALLSTAT(cosetrec,coset,coset_sz);
static permrec *gens;
DYNALLSTAT(set,workset,workset_sz);
DYNALLSTAT(permutation,allp,allp_sz);
DYNALLSTAT(permutation,id,id_sz);
/**************************************************************************/
permrec
*newpermrec(int n)
/* Get a permrec of order n. This procedure and the next one are
designed to be efficient if lots of group ops are done with the
same value of n. */
{
permrec *p;
if (freelist_n != n)
{
while (freelist != NULL)
{
p = freelist;
freelist = freelist->ptr;
free(p);
}
freelist_n = n;
}
if (freelist != NULL)
{
p = freelist;
freelist = freelist->ptr;
return p;
}
p = (permrec*) malloc(sizeof(permrec)+(freelist_n-2)*sizeof(permutation));
if (p == NULL)
{
fprintf(ERRFILE,">E malloc failed in newpermrec()\n");
exit(1);
}
return p;
}
/**************************************************************************/
void
freepermrec(permrec *p, int n)
/* Free a permrec of given size. */
{
if (p == NULL) return;
if (freelist_n != n)
{
while (freelist)
{
p = freelist;
freelist = freelist->ptr;
free(p);
}
freelist_n = n;
}
p->ptr = freelist;
freelist = p;
}
/**************************************************************************/
grouprec *
groupptr(boolean cutloose)
/* Give the address of the group structure, cutting it loose
if requested. */
{
grouprec *p;
p = group;
if (cutloose)
{
group = NULL;
group_depth = 0;
coset = NULL;
coset_sz = 0;
}
return p;
}
/**************************************************************************/
void
freegroup(grouprec *grp)
/* Free (or pretend to free) group structure. */
{
int i,j;
cosetrec *p;
permrec *q,*qq;
for (i = 0; i < grp->depth; ++i)
{
p = grp->levelinfo[i].replist;
if (p != NULL)
for (j = grp->levelinfo[i].orbitsize; --j >= 0; )
{
freepermrec(p[j].rep,grp->n);
p[j].rep = NULL;
}
}
if (grp->depth > 0)
{
p = grp->levelinfo[0].replist;
if (p != NULL && p != coset)
{
free(p);
grp->levelinfo[0].replist = NULL;
}
q = grp->levelinfo[0].gens;
while (q != NULL)
{
qq = q;
q = q->ptr;
freepermrec(qq,grp->n);
}
grp->levelinfo[0].gens = NULL;
}
}
/**************************************************************************/
void
groupautomproc(int count, permutation *perm, int *orbits,
int numorbits, int stabvertex, int n)
{
permrec *p;
int i;
p = newpermrec(n);
for (i = 0; i < n; ++i) p->p[i] = perm[i];
p->ptr = gens;
gens = p;
}
/**************************************************************************/
void
grouplevelproc(int *lab, int *ptn, int level, int *orbits, statsblk *stats,
int tv, int index, int tcellsize, int numcells, int cc, int n)
{
int depth;
size_t sz;
if (numcells == n) /* first call */
{
depth = level - 1;
if (group) freegroup(group);
if (depth > group_depth || !group)
{
if (depth <= 1) sz = sizeof(grouprec);
else sz = sizeof(grouprec) + (depth-1)*sizeof(levelrec);
if (group) group = (grouprec*)realloc((void*)group,sz);
else group = (grouprec*)malloc(sz);
if (group == NULL)
{
fprintf(ERRFILE,">E malloc failed in grouplevelproc\n");
exit(1);
}
group_depth = depth;
}
group->n = n;
group->depth = depth;
gens = NULL;
return;
}
group->levelinfo[level-1].fixedpt = tv;
group->levelinfo[level-1].orbitsize = index;
group->levelinfo[level-1].gens = gens;
group->levelinfo[level-1].replist = NULL;
if (level == 1) group->numorbits = stats->numorbits;
}
/**************************************************************************/
void
makecosetreps(grouprec *grp)
/* Make all coset representatives for this group */
{
int i,j,k,n,depth;
int l,index;
permutation *p,*q;
permrec *gen,*g;
cosetrec *cr;
int head,tail;
DYNALLSTAT(int,queue,queue_sz);
DYNALLSTAT(int,lab,lab_sz);
n = grp->n;
depth = grp->depth;
DYNALLOC1(int,queue,queue_sz,n,"malloc");
DYNALLOC1(int,lab,lab_sz,n,"malloc");
j = 0;
for (i = 0; i < depth; ++i)
j += grp->levelinfo[i].orbitsize;
if (j > 0) DYNALLOC1(cosetrec,coset,coset_sz,j,"malloc");
cr = coset;
for (i = 0; i < depth; ++i)
{
grp->levelinfo[i].replist = cr;
cr += grp->levelinfo[i].orbitsize;
}
for (i = 0; i < depth; ++i)
{
cr = grp->levelinfo[i].replist;
gen = grp->levelinfo[i].gens;
for (j = 0; j < n; ++j) lab[j] = -1;
queue[0] = grp->levelinfo[i].fixedpt;
lab[queue[0]] = 0;
cr[0].image = queue[0];
cr[0].rep = NULL;
head = 0;
tail = 1;
index = 0;
while (head < tail)
{
j = queue[head++];
p = (cr[lab[j]].rep ? cr[lab[j]].rep->p : NULL);
for (g = gen; g != NULL; g = g->ptr)
{
k = g->p[j];
if (lab[k] < 0)
{
++index;
lab[k] = index;
queue[tail++] = k;
cr[index].image = k;
cr[index].rep = newpermrec(n);
q = cr[index].rep->p;
if (p == NULL)
for (l = 0; l < n; ++l) q[l] = g->p[l];
else
for (l = 0; l < n; ++l) q[l] = g->p[p[l]];
}
}
}
}
}
/**************************************************************************/
int
permcycles(permutation *p, int n, int *len, boolean sort)
/* Puts in len[0..] the cycle lengths of p. If sort, sort them.
Return the number of cycles. */
{
int m,i,j,k,h,nc,leni;
m = (n + WORDSIZE - 1) / WORDSIZE;
DYNALLOC1(set,workset,workset_sz,m,"malloc");
EMPTYSET(workset,m);
nc = 0;
for (i = 0; i < n; ++i)
if (!ISELEMENT(workset,i))
{
k = 1;
for (j = p[i]; j != i; j = p[j])
{
ADDELEMENT(workset,j);
++k;
}
len[nc++] = k;
}
if (sort && nc > 1)
{
j = nc / 3;
h = 1;
do
h = 3 * h + 1;
while (h < j);
do
{
for (i = h; i < nc; ++i)
{
leni = len[i];
for (j = i; len[j-h] > leni; )
{
len[j] = len[j-h];
if ((j -= h) < h) break;
}
len[j] = leni;
}
h /= 3;
}
while (h > 0);
}
return nc;
}
/**************************************************************************/
static void
groupelts(levelrec *lr, int n, int level, void (*action)(permutation*,int),
permutation *before, permutation *after, permutation *id)
/* Recursive routine used by allgroup. */
{
int i,j,orbsize;
permutation *p,*cr;
cosetrec *coset;
coset = lr[level].replist;
orbsize = lr[level].orbitsize;
for (j = 0; j < orbsize; ++j)
{
cr = (coset[j].rep == NULL ? NULL : coset[j].rep->p);
if (before == NULL)
p = cr;
else if (cr == NULL)
p = before;
else
{
p = after;
for (i = 0; i < n; ++i) p[i] = cr[before[i]];
}
if (level == 0)
(*action)((p == NULL ? id : p),n);
else
groupelts(lr,n,level-1,action,p,after+n,id);
}
}
/**************************************************************************/
void
allgroup(grouprec *grp, void (*action)(permutation*,int))
/* Call action(p,n) for every element of the group, including the identity.
The identity is always the first call. */
{
int i,depth,n;
depth = grp->depth;
n = grp->n;
DYNALLOC1(permutation,id,id_sz,n,"malloc");
for (i = 0; i < n; ++i) id[i] = i;
if (depth == 0)
{
(*action)(id,n);
return;
}
DYNALLOC1(permutation,allp,allp_sz,n*depth,"malloc");
groupelts(grp->levelinfo,n,depth-1,action,NULL,allp,id);
}
/**************************************************************************/
static int
groupelts2(levelrec *lr, int n, int level,
void (*action)(permutation*,int,int*), permutation *before,
permutation *after, permutation *id, int *abort)
/* Recursive routine used by allgroup2. */
{
int i,j,orbsize;
permutation *p,*cr;
cosetrec *coset;
coset = lr[level].replist;
orbsize = lr[level].orbitsize;
for (j = 0; j < orbsize; ++j)
{
cr = (coset[j].rep == NULL ? NULL : coset[j].rep->p);
if (before == NULL)
p = cr;
else if (cr == NULL)
p = before;
else
{
p = after;
for (i = 0; i < n; ++i) p[i] = cr[before[i]];
}
if (level == 0)
(*action)((p == NULL ? id : p),n,abort);
else
groupelts2(lr,n,level-1,action,p,after+n,id,abort);
if (*abort) return;
}
}
/**************************************************************************/
int
allgroup2(grouprec *grp, void (*action)(permutation*,int,int*))
/* Call action(p,n,&abort) for every element of the group, including
the identity. The identity is always the first call.
If action() stores a non-zero value in abort, group generation is
aborted and the abort value is returned by this procedure. If no
non-zero value is ever returned in abort by action(), this
procedure returns 0. */
{
int i,depth,n,abort;
depth = grp->depth;
n = grp->n;
DYNALLOC1(permutation,id,id_sz,n,"malloc");
for (i = 0; i < n; ++i) id[i] = i;
abort = 0;
if (depth == 0)
{
(*action)(id,n,&abort);
return abort;
}
DYNALLOC1(permutation,allp,allp_sz,n*depth,"malloc");
groupelts2(grp->levelinfo,n,depth-1,action,NULL,allp,id,&abort);
return abort;
}
syntax highlighted by Code2HTML, v. 0.9.1