int testcanlab(graphnau *g, graphnau *canong, int *lab, int *samerows, int m, int n) { int i,j; set *ph; #if !MAXN DYNALLOC1(permutation,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; }
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; }
void fmperm(permutation *perm, set *fix, set *mcr, int m, int n) { register int i,k,l; #if !MAXN DYNALLOC1(permutation,workperm,workperm_sz,n,"writeperm"); #endif EMPTYSET(fix,m); EMPTYSET(mcr,m); for (i = n; --i >= 0;) workperm[i] = 0; for (i = 0; i < n; ++i) if (perm[i] == i) { ADDELEMENT(fix,i); ADDELEMENT(mcr,i); } else if (workperm[i] == 0) { l = i; do { k = l; l = perm[l]; workperm[k] = 1; } while (l != i); ADDELEMENT(mcr,i); } }
void compl(graph *g, int m, int n, graph *h) /* h := complement of g */ { int i,j; setword *gi,*hi; #if MAXN set all[MAXM]; #else DYNALLSTAT(set,all,all_sz); DYNALLOC1(set,all,all_sz,m,"complg"); #endif EMPTYSET(all,m); for (i = 0; i < n; ++i) ADDELEMENT(all,i); gi = (setword*) g; hi = (setword*) h; for (i = 0; i < n; ++i) { for (j = 0; j < m; ++j) hi[j] = gi[j] ^ all[j]; DELELEMENT(hi,i); gi += m; hi += m; } }
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; }
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); }
void updatecan(graphnau *g, graphnau *canong, permutation *lab, int samerows, int m, int n) { int i; set *ph; #if !MAXN DYNALLOC1(permutation,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); }
static int p4decomposition(sparsegraph sg, int vertex, boolean vertical) /* Test which non-triangular P4s extend to a decomposition. Return -2: timeout -1: not decomposable at all >=0: number of P4s missed If 0 <= vertex < n, only P4s starting at that vertex are considered. If vertical (only for prisms), the central edge must be vertical. The paths missed can be found in p4list[]. */ { int i,j,k,l,n,c; int ans,status; int imin,imax,nump4; int v1,v2,v3,v4,e1,e2,e3,j1,j2,j3; n = sg.nv; if (vertex >= n) gt_abort(">E vertex given to -t is too large"); status = isdecomposable(sg,FALSE,FALSE); if (status == NO) return -1; else if (status == TIMEOUT) return -2; if (vertex >= 0) { imin = imax = vertex; DYNALLOC1(p4,p4list,p4list_sz,36,"malloc"); } else { imin = 0; imax = n-1; DYNALLOC1(p4,p4list,p4list_sz,18*n,"malloc"); } nump4 = 0; for (v1 = imin; v1 <= imax; ++v1) for (j1 = 0; j1 < 4; ++j1) { v2 = sg.e[4*v1+j1]; e1 = eno[4*v1+j1]; for (j2 = 0; j2 < 4; ++j2) { v3 = sg.e[4*v2+j2]; if (v3 == v1) continue; if (vertical && (v2|1) != (v3|1)) continue; e2 = eno[4*v2+j2]; for (j3 = 0; j3 < 4; ++j3) { v4 = sg.e[4*v3+j3]; if (v4 == v1 || v4 == v2) continue; e3 = eno[4*v3+j3]; if (vertex >= 0 || v1 < v4) { p4list[nump4].v1 = v1; p4list[nump4].v2 = v2; p4list[nump4].v3 = v3; p4list[nump4].v4 = v4; p4list[nump4].e1 = e1; p4list[nump4].e2 = e2; p4list[nump4].e3 = e3; p4list[nump4].ok = FALSE; ++nump4; } } } } for (i = 0; i < nump4; ++i) if (colour[p4list[i].e1] == colour[p4list[i].e2] && colour[p4list[i].e1] == colour[p4list[i].e3]) p4list[i].ok = TRUE; for (i = 0; i < nump4; ++i) if (!p4list[i].ok) { initialise_colouring(n); if (makeblue(p4list[i].e1,FALSE) && makeblue(p4list[i].e2,n==2) && makeblue(p4list[i].e3,n==3)) { status = dispatchsearch(n,sg.e,3,0); if (status == TIMEOUT) return -2; if (status == YES) { for (k = 0; k < nump4; ++k) { if (p4list[k].ok) continue; if (colour[p4list[k].e1] == colour[p4list[k].e2] && colour[p4list[k].e1] == colour[p4list[k].e3]) p4list[k].ok = TRUE; } } } } ans = 0; for (i = 0; i < nump4; ++i) if (!p4list[i].ok) ++ans; return ans; }
static void initialise_g(int n, int *e) /* Allocate all and initialise eno[],v1[],v2[] e is a vector like sg.e */ { int ne,i,j,k,l; DYNALLOC1(addrval,valstack,valstack_sz,10*n,"malloc"); DYNALLOC1(int,bluefarend,bluefarend_sz,n,"malloc"); DYNALLOC1(int,redfarend,redfarend_sz,n,"malloc"); DYNALLOC1(int,eno,eno_sz,4*n,"malloc"); DYNALLOC1(int,v1,v1_sz,2*n,"malloc"); DYNALLOC1(int,v2,v2_sz,2*n,"malloc"); DYNALLOC1(int,colour,colour_sz,2*n,"malloc"); DYNALLOC1(int,bluedeg,bluedeg_sz,n,"malloc"); DYNALLOC1(int,reddeg,reddeg_sz,n,"malloc"); DYNALLOC1(int,vstack,vstack_sz,n,"malloc"); DYNALLOC1(boolean,onstack,onstack_sz,n,"malloc"); DYNALLOC1(int,beste,beste_sz,2*n,"malloc"); /* Randomize e; seems to be no purpose for this any more. */ for (i = 0; i < n; ++i) { j = KRAN(4); k = e[4*i+j]; e[4*i+j] = e[4*i+3]; e[4*i+3] = k; j = KRAN(3); k = e[4*i+j]; e[4*i+j] = e[4*i+2]; e[4*i+2] = k; j = KRAN(2); k = e[4*i+j]; e[4*i+j] = e[4*i+1]; e[4*i+1] = k; } ne = 0; for (i = 0; i < n; ++i) { for (j = 0; j < 4; ++j) { k = e[4*i+j]; if (k > i) { v1[ne] = i; v2[ne] = k; eno[4*i+j] = ne++; } else /* Note: this code assumes a simple graph */ { for (l = 0; l < 4; ++l) if (e[4*k+l] == i) break; eno[4*i+j] = eno[4*k+l]; } } } if (ne != 2*n) gt_abort(">E ne is incorrect"); #if DEBUG { int ii; printf("===== n=%d === ne=%d ===================\n",n,ne); for (ii = 0; ii < n; ++ii) printf("%2d: %2d %2d %2d %2d %2d %2d %2d %2d\n", ii,e[4*ii],e[4*ii+1],e[4*ii+2],e[4*ii+3], eno[4*ii],eno[4*ii+1],eno[4*ii+2],eno[4*ii+3]); } #endif }
static boolean readblissgraph(FILE *f, sparsegraph *g) /* Reads a graph from Bliss format into a sparse graph */ { int n,c; unsigned long ne,j; int haven; int i,v,w; int haveptn; DYNALLSTAT(vpair,elist,elist_sz); haven = 0; j = 0; while ((c = nextchar(f)) >= 0) { switch (c) { case 'c': while ((c = getc(f)) != '\n' && c != EOF) {} break; case 'p': if (haven) { fprintf(stderr,"Duplicate p line\n"); exit(1); } if (fscanf(f," edge %d %lu",&n,&ne) != 2) { fprintf(stderr,"Bad p line\n"); return FALSE; } haven = 1; DYNALLOC1(vpair,elist,elist_sz,ne,"Alloc vpair"); break; case 'n': if (!haven) { fprintf(stderr,"Missing p line\n"); return FALSE; } if (fscanf(f,"%d%d",&w,&v) != 2 || w < 1 || w > n) { fprintf(stderr,"Bad n line\n"); return FALSE; } break; case 'e': if (!haven || j == ne) { fprintf(stderr,"Missing p line or too many e lines\n"); return FALSE; } if (fscanf(f,"%d%d",&v,&w) != 2 || v < 1 || w < 1 || v > n || w > n) { fprintf(stderr,"Bad e line\n"); return FALSE; } elist[j].v = v-1; elist[j].w = w-1; ++j; break; default: fprintf(stderr,"Unknown line %c\n",c); return FALSE; } } if (j != ne) { fprintf(stderr,"Wrong number of e lines\n"); exit(1); } SG_ALLOC(*g,n,2*ne,"SG_ALLOC"); g->nv = n; g->nde = 2*ne; for (i = 0; i < n; ++i) g->d[i] = 0; for (j = 0; j < ne; ++j) { ++(g->d[elist[j].v]); ++(g->d[elist[j].w]); } g->v[0] = 0; for (i = 1; i < n; ++i) g->v[i] = g->v[i-1] + g->d[i-1]; for (i = 0; i < n; ++i) g->d[i] = 0; for (j = 0; j < ne; ++j) { v = elist[j].v; w = elist[j].w; g->e[g->v[v]+(g->d[v])++] = w; g->e[g->v[w]+(g->d[w])++] = v; } return TRUE; }
void doref(graph *g, int *lab, int *ptn, int level, int *numcells, int *qinvar, permutation *invar, set *active, int *code, void (*refproc)(graph*,int*,int*,int,int*,permutation*,set*,int*,int,int), void (*invarproc)(graph*,int*,int*,int,int,int,permutation*, int,boolean,int,int), int mininvarlev, int maxinvarlev, int invararg, boolean digraph, int m, int n) { register int j,h; register permutation pw; int iw; int i,cell1,cell2,nc,tvpos,minlev,maxlev; long longcode; boolean same; #if !MAXN DYNALLOC1(permutation,workperm,workperm_sz,n,"doref"); #endif if ((tvpos = nextelement(active,M,-1)) < 0) tvpos = 0; (*refproc)(g,lab,ptn,level,numcells,invar,active,code,M,n); minlev = (mininvarlev < 0 ? -mininvarlev : mininvarlev); maxlev = (maxinvarlev < 0 ? -maxinvarlev : maxinvarlev); if (invarproc != NULL && *numcells < n && level >= minlev && level <= maxlev) { (*invarproc)(g,lab,ptn,level,*numcells,tvpos,invar,invararg, digraph,M,n); EMPTYSET(active,m); for (i = n; --i >= 0;) workperm[i] = invar[lab[i]]; nc = *numcells; for (cell1 = 0; cell1 < n; cell1 = cell2 + 1) { pw = workperm[cell1]; same = TRUE; for (cell2 = cell1; ptn[cell2] > level; ++cell2) if (workperm[cell2+1] != pw) same = FALSE; if (same) continue; j = (cell2 - cell1 + 1) / 3; h = 1; do h = 3 * h + 1; while (h < j); do /* shell sort */ { for (i = cell1 + h; i <= cell2; ++i) { iw = lab[i]; pw = workperm[i]; for (j = i; workperm[j-h] > pw; ) { workperm[j] = workperm[j-h]; lab[j] = lab[j-h]; if ((j -= h) < cell1 + h) break; } workperm[j] = pw; lab[j] = iw; } h /= 3; } while (h > 0); for (i = cell1 + 1; i <= cell2; ++i) if (workperm[i] != workperm[i-1]) { ptn[i-1] = level; ++*numcells; ADDELEMENT(active,i); } } if (*numcells > nc) { *qinvar = 2; longcode = *code; (*refproc)(g,lab,ptn,level,numcells,invar,active,code,M,n); longcode = MASH(longcode,*code); *code = CLEANUP(longcode); } else *qinvar = 1; } else *qinvar = 0; }
void writeperm(FILE *f, permutation *perm, boolean cartesian, int linelength, int n) { register int i,k,l,curlen,intlen; char s[30]; #if !MAXN DYNALLOC1(permutation,workperm,workperm_sz,n,"writeperm"); #endif /* CONDNL(x) writes end-of-line and 3 spaces if x characters won't fit on the current line. */ #define CONDNL(x) if (linelength>0 && curlen+(x)>linelength)\ {putstring(f,"\n ");curlen=3;} curlen = 0; if (cartesian) { for (i = 0; i < n; ++i) { intlen = itos(perm[i]+labelorg,s); CONDNL(intlen+1); PUTC(' ',f); putstring(f,s); curlen += intlen + 1; } PUTC('\n',f); } else { for (i = n; --i >= 0;) workperm[i] = 0; for (i = 0; i < n; ++i) { if (workperm[i] == 0 && perm[i] != i) { l = i; intlen = itos(l+labelorg,s); if (curlen > 3) CONDNL(2*intlen+4); PUTC('(',f); do { putstring(f,s); curlen += intlen + 1; k = l; l = perm[l]; workperm[k] = 1; if (l != i) { intlen = itos(l+labelorg,s); CONDNL(intlen+2); PUTC(' ',f); } } while (l != i); PUTC(')',f); ++curlen; } } if (curlen == 0) putstring(f,"(1)\n"); else PUTC('\n',f); } }
static void subdivisiongraph(sparsegraph *g, int k, sparsegraph *h) /* h := subdivision graph of g, k new vertices per edge */ { DYNALLSTAT(size_t,eno,eno_sz); /* edge number */ int *ge,*gd,*he,*hd; size_t *gv,*hv; int gnv,hnv; size_t i,j,l,gnde,hnde,num; size_t hi,lo,mid,w; if (k == 0) { copy_sg(g,h); return; } sortlists_sg(g); SG_VDE(g,gv,gd,ge); gnv = g->nv; gnde = g->nde; DYNALLOC1(size_t,eno,eno_sz,gnde,"subdivideg"); hnv = gnv + k*(gnde/2); if (hnv <= 0 || (gnde > 0 && ((size_t)(hnv-gnv))/(gnde/2) != k)) gt_abort(">E subdivideg: output graph too large\n"); hnde = gnde * (k+1); if (hnde/(k+1) != gnde) gt_abort(">E subdivideg: output graph too large\n"); num = 0; for (i = 0; i < gnv; ++i) { for (j = gv[i]; j < gv[i]+gd[i]; ++j) { if (ge[j] == i) gt_abort(">E subdivideg can't handle undirected loops\n"); else if (ge[j] > i) eno[j] = num++; else { lo = gv[ge[j]]; hi = lo + gd[ge[j]] - 1; while (lo <= hi) { mid = lo + (hi-lo)/2; if (ge[mid] == i) break; else if (ge[mid] < i) lo = mid+1; else hi = mid-1; } if (lo > hi) gt_abort(">E subdivideg : binary search failed\n"); eno[j] = eno[mid]; } } } SG_ALLOC(*h,hnv,hnde,"subdivideg"); h->nv = hnv; h->nde = hnde; SG_VDE(h,hv,hd,he); for (i = 0; i < gnv; ++i) { hd[i] = gd[i]; hv[i] = gv[i]; } for (i = gnv; i < hnv; ++i) { hd[i] = 2; hv[i] = gnde + 2*(i-gnv); } for (i = 0; i < gnv; ++i) { for (j = gv[i]; j < gv[i]+gd[i]; ++j) if (ge[j] > i) { w = gnv + k*eno[j]; he[j] = w; he[hv[w]] = i; for (l = 1; l < k; ++l) { he[hv[w]+1] = w+1; he[hv[w+1]] = w; ++w; } } else { w = gnv + k*eno[j] + k - 1; he[j] = w; he[hv[w]+1] = i; } } }
static void linegraph(sparsegraph *g, sparsegraph *h) /* h := linegraph of g */ { DYNALLSTAT(size_t,eno,eno_sz); /* edge number */ int *ge,*gd,*he,*hd; size_t *gv,*hv; int gnv,hnv; size_t i,j,k,gnde,hnde,xhnde,num; size_t hi,lo,mid,v,w; sortlists_sg(g); SG_VDE(g,gv,gd,ge); gnv = g->nv; gnde = g->nde; DYNALLOC1(size_t,eno,eno_sz,gnde,"linegraphg"); hnv = gnde/2; if (hnv != gnde/2) gt_abort(">E linegraphg: too many input edges\n"); hnde = 0; num = 0; for (i = 0; i < gnv; ++i) { xhnde = hnde; hnde += gd[i]*((size_t)gd[i]-1); if (hnde < xhnde) gt_abort(">E linegraphg: too many output edges\n"); for (j = gv[i]; j < gv[i]+gd[i]; ++j) { if (ge[j] == i) gt_abort(">E linegraphg can't handle loops\n"); else if (ge[j] > i) eno[j] = num++; else { lo = gv[ge[j]]; hi = lo + gd[ge[j]] - 1; while (lo <= hi) { mid = lo + (hi-lo)/2; if (ge[mid] == i) break; else if (ge[mid] < i) lo = mid+1; else hi = mid-1; } if (lo > hi) gt_abort(">E linegraphg : binary search failed\n"); eno[j] = eno[mid]; } } } SG_ALLOC(*h,hnv,hnde,"linegraphg"); h->nv = hnv; h->nde = hnde; SG_VDE(h,hv,hd,he); for (i = 0; i < hnv; ++i) hd[i] = 0; for (i = 0; i < gnv; ++i) { for (j = gv[i]; j < gv[i]+gd[i]; ++j) hd[eno[j]] += gd[i]-1; } hv[0] = 0; for (i = 1; i < hnv; ++i) hv[i] = hv[i-1] + hd[i-1]; for (i = 0; i < hnv; ++i) hd[i] = 0; for (i = 0; i < gnv; ++i) { for (j = gv[i]; j < gv[i]+gd[i]-1; ++j) for (k = j+1; k < gv[i]+gd[i]; ++k) { v = eno[j]; w = eno[k]; he[hv[v]+(hd[v]++)] = w; he[hv[w]+(hd[w]++)] = v; } } }