diff options
| author | Andrew Guschin <guschin@altlinux.org> | 2024-03-31 18:36:27 +0500 |
|---|---|---|
| committer | Andrew Guschin <guschin@altlinux.org> | 2024-03-31 18:36:27 +0500 |
| commit | f7aa97e10a2fbddb76e1893b7deb193ad56e7192 (patch) | |
| tree | dab29cd1166edee5c096bdfc45d1c6ab509107f8 /graph-checker/nauty/naugroup.c | |
| parent | b294692a8251eb9c4ea8f3e78651d88fc6efd792 (diff) | |
latest version
Diffstat (limited to 'graph-checker/nauty/naugroup.c')
| -rw-r--r-- | graph-checker/nauty/naugroup.c | 527 |
1 files changed, 527 insertions, 0 deletions
diff --git a/graph-checker/nauty/naugroup.c b/graph-checker/nauty/naugroup.c new file mode 100644 index 0000000..9ec2610 --- /dev/null +++ b/graph-checker/nauty/naugroup.c @@ -0,0 +1,527 @@ +/* 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(int,allp,allp_sz); +DYNALLSTAT(int,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(int)); + + 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. */ +{ + permrec *q; + + if (p == NULL) return; + + if (freelist_n != n) + { + while (freelist) + { + q = freelist; + freelist = freelist->ptr; + free(q); + } + 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, int *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; + int *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(int *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)(int*,int), + int *before, int *after, int *id) +/* Recursive routine used by allgroup. */ +{ + int i,j,orbsize; + int *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)(int*,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(int,id,id_sz,n,"malloc"); + for (i = 0; i < n; ++i) id[i] = i; + + if (depth == 0) + { + (*action)(id,n); + return; + } + + DYNALLOC1(int,allp,allp_sz,n*depth,"malloc"); + + groupelts(grp->levelinfo,n,depth-1,action,NULL,allp,id); +} + +/**************************************************************************/ + +static void +groupelts2(levelrec *lr, int n, int level, + void (*action)(int*,int,int*), int *before, + int *after, int *id, int *abort) +/* Recursive routine used by allgroup2. */ +{ + int i,j,orbsize; + int *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)(int*,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(int,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(int,allp,allp_sz,n*depth,"malloc"); + + groupelts2(grp->levelinfo,n,depth-1,action,NULL,allp,id,&abort); + + return abort; +} + +/**************************************************************************/ + +static void +groupelts3(levelrec *lr, int n, int level, + void (*action)(int*,int,int*,void*), int *before, + int *after, int *id, int *abort, void *userptr) +/* Recursive routine used by allgroup3. */ +{ + int i,j,orbsize; + int *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,userptr); + else + groupelts3(lr,n,level-1,action,p,after+n,id,abort,userptr); + if (*abort) return; + } +} + +/**************************************************************************/ + +int +allgroup3(grouprec *grp, void (*action)(int*,int,int*,void*), void *userptr) +/* Call action(p,n,&abort,userptr) 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. The pointer userptr is not interpretted and + is passed to action() to use as it likes. */ +{ + int i,depth,n,abort; + + depth = grp->depth; + n = grp->n; + + DYNALLOC1(int,id,id_sz,n,"malloc"); + for (i = 0; i < n; ++i) id[i] = i; + + abort = 0; + if (depth == 0) + { + (*action)(id,n,&abort,userptr); + return abort; + } + + DYNALLOC1(int,allp,allp_sz,n*depth,"malloc"); + + groupelts3(grp->levelinfo,n,depth-1,action,NULL,allp,id,&abort,userptr); + + return abort; +} |