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); } }
static void makecanon(graph *g, graph *gcan, int n1, int n2) /* gcan := canonise(g) */ { int lab[MAXN],ptn[MAXN],orbits[MAXN]; setword active[1]; int i; statsblk stats; static DEFAULTOPTIONS_GRAPH(options); setword workspace[50]; options.writemarkers = FALSE; options.writeautoms = FALSE; options.getcanon = TRUE; options.defaultptn = FALSE; for (i = 0; i < n1+n2; ++i) { lab[i] = i; ptn[i] = 1; } ptn[n1-1] = ptn[n1+n2-1] = 0; EMPTYSET(active,1); ADDELEMENT(active,0); ADDELEMENT(active,n1); nauty(g,lab,ptn,active,orbits,&options,&stats, workspace,50,1,n1+n2,gcan); }
static boolean ismax(int *p, int n) /* test if x^p <= x */ { int i,j,k; set px[MAXME]; EMPTYSET(px,me); for (j = 0; j < nix; ++j) { i = ix[j]; k = i >> 1; if (i & 1) ADDELEMENT(px,edgeno[p[v1[k]]][p[v0[k]]]); else ADDELEMENT(px,edgeno[p[v0[k]]][p[v1[k]]]); if (px[0] > x[0]) { rejectlevel = k; return FALSE; } } rejectlevel = MAXNE+1; if (px[0] < x[0]) return TRUE; for (i = 1; i < me; ++i) if (px[i] > x[i]) return FALSE; else if (px[i] < x[i]) return TRUE; ++newgroupsize; ntgroup = TRUE; return TRUE; }
void targetcell(graph *g, int *lab, int *ptn, int level, int numcells, set *tcell, int *tcellsize, int *cellpos, int tc_level, int hint, int (*goodcell)(graph*,int*,int*,int,int,int,int), int m, int n) { register int i,j,k; if (hint >= 0 && ptn[hint] > level && (hint == 0 || ptn[hint-1] <= level)) i = hint; else if (level <= tc_level && goodcell != NULL) i = (*goodcell)(g,lab,ptn,level,tc_level,m,n); else for (i = 0; i < n && ptn[i] <= level; ++i) {} if (i == n) i = j = 0; else for (j = i + 1; ptn[j] > level; ++j) {} *tcellsize = j - i + 1; EMPTYSET(tcell,m); for (k = i; k <= j; ++k) ADDELEMENT(tcell,lab[k]); *cellpos = i; }
void permset(set *set1, set *set2, int m, permutation *perm) { register setword setw; register int pos,w,b; EMPTYSET(set2,m); #if MAXM==1 setw = set1[0]; while (setw != 0) { TAKEBIT(b,setw); pos = perm[b]; ADDELEMENT(set2,pos); } #else for (w = 0; w < m; ++w) { setw = set1[w]; while (setw != 0) { TAKEBIT(b,setw); pos = perm[TIMESWORDSIZE(w)+b]; ADDELEMENT(set2,pos); } } #endif }
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; } }
static void newedge(graph *g1, int m1, int n1, int v1, int v2, int w1, int w2, graph *g2, int m2) /* Make g2 by subdividing edges v1-v2 and w1-w2 in g1 and adding an edge between them. Must have m2 >= m1. */ { int i,j; setword *s1,*s2; s1 = g1; s2 = g2; for (i = 0; i < n1; ++i) { for (j = 0; j < m1; ++j) *(s2++) = *(s1++); for (; j < m2; ++j) *(s2++) = 0; } s2 = GRAPHROW(g2,v1,m2); DELELEMENT(s2,v2); ADDELEMENT(s2,n1); s2 = GRAPHROW(g2,v2,m2); DELELEMENT(s2,v1); ADDELEMENT(s2,n1); s2 = GRAPHROW(g2,w1,m2); DELELEMENT(s2,w2); ADDELEMENT(s2,n1+1); s2 = GRAPHROW(g2,w2,m2); DELELEMENT(s2,w1); ADDELEMENT(s2,n1+1); s2 = GRAPHROW(g2,n1,m2); EMPTYSET(s2,m2); ADDELEMENT(s2,v1); ADDELEMENT(s2,v2); ADDELEMENT(s2,n1+1); s2 = GRAPHROW(g2,n1+1,m2); EMPTYSET(s2,m2); ADDELEMENT(s2,w1); ADDELEMENT(s2,w2); ADDELEMENT(s2,n1); }
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 fmptn(int *lab, int *ptn, int level, set *fix, set *mcr, int m, int n) { register int i,lmin; EMPTYSET(fix,m); EMPTYSET(mcr,m); for (i = 0; i < n; ++i) if (ptn[i] <= level) { ADDELEMENT(fix,lab[i]); ADDELEMENT(mcr,lab[i]); } else { lmin = lab[i]; do if (lab[++i] < lmin) lmin = lab[i]; while (ptn[i] > level); ADDELEMENT(mcr,lmin); } }
void maketargetcell(graphnau *g, int *lab, int *ptn, int level, set *tcell, int *tcellsize, int *cellpos, int tc_level, boolean digraph, int hint, int (*targetcell)(graphnau*,int*,int*,int,int,boolean,int,int,int), int m, int n) { int i,j,k; i = (*targetcell)(g,lab,ptn,level,tc_level,digraph,hint,m,n); for (j = i + 1; ptn[j] > level; ++j) {} *tcellsize = j - i + 1; EMPTYSET(tcell,m); for (k = i; k <= j; ++k) ADDELEMENT(tcell,lab[k]); *cellpos = i; }
void breakout(int *lab, int *ptn, int level, int tc, int tv, set *active, int m) { register int i,prev,next; EMPTYSET(active,m); ADDELEMENT(active,tc); i = tc; prev = tv; do { next = lab[i]; lab[i++] = prev; prev = next; } while (prev != tv); ptn[tc] = level; }
static int trythisone(grouprec *group, int ne, int n) { int i,k; boolean accept; #ifdef PROCESS graph g[WORDSIZE]; #endif first = TRUE; ++gd_ngen; nix = ne; newgroupsize = 1; ntgroup = FALSE; if (!group || groupsize == 1) accept = TRUE; else if (lastrejok && !ismax(lastreject,n)) accept = FALSE; else if (lastrejok && groupsize == 2) accept = TRUE; else { newgroupsize = 1; ntgroup = FALSE; if (allgroup2(group,testmax) == 0) accept = TRUE; else accept = FALSE; } if (accept) { #ifdef GROUPTEST if (groupsize % newgroupsize != 0) gt_abort("group size error\n"); totallab += groupsize/newgroupsize; #endif if (Vswitch && !ntisol && !ntgroup) return MAXNE+1; ++dg_nout; #ifdef PROCESS EMPTYSET(g,n); for (i = -1; (i = nextelement(x,me,i)) >= 0; ) { k = i >> 1; if (i & 1) g[v1[k]] |= bit[v0[k]]; else g[v0[k]] |= bit[v1[k]]; } PROCESS(outfile,g,n); #endif if (outfile) { fprintf(outfile,"%d %d",n,ne); if (Gswitch) fprintf(outfile," %lu",newgroupsize); for (i = -1; (i = nextelement(x,me,i)) >= 0; ) { k = i >> 1; if (i & 1) fprintf(outfile," %d %d",v1[k],v0[k]); else fprintf(outfile," %d %d",v0[k],v1[k]); } fprintf(outfile,"\n"); } return MAXNE+1; } else return rejectlevel;
static void multi(graph *g, int nfixed, long minedges, long maxedges, long maxmult, int maxdeg, boolean lswitch, int m, int n) { static DEFAULTOPTIONS_GRAPH(options); statsblk stats; setword workspace[100]; grouprec *group; int ne; int i,j,k,j0,j1,thisdeg,maxd,x0,x1; set *gi; int lab[MAXNV],ptn[MAXNV],orbits[MAXNV],deg[MAXNV]; int delta[MAXNV],def[MAXNV]; set active[(MAXNV+WORDSIZE-1)/WORDSIZE]; boolean isreg; #ifdef PATHCOUNTS ++count0; #endif j0 = -1; /* last vertex with degree 0 */ j1 = n; /* first vertex with degree > 0 */ ne = 0; maxd = 0; for (i = 0, gi = g; i < n; ++i, gi += m) { thisdeg = 0; for (j = 0; j < m; ++j) thisdeg += POPCOUNT(gi[j]); deg[i] = thisdeg; if (thisdeg > maxd) maxd = thisdeg; if (thisdeg == 0) lab[++j0] = i; else lab[--j1] = i; ne += thisdeg; } ne /= 2; if (maxdeg >= 0 && maxd > maxdeg) return; #ifdef PATHCOUNTS ++count1; #endif if (Aswitch || Bswitch) for (i = 0; i < n; ++i) for (j = 0; j < n; ++j) edgeno[i][j] = -1; if (ne == 0 && minedges <= 0 && (!lswitch || (lswitch && (maxdeg&1) == 0))) { trythisone(NULL,lswitch,deg,maxdeg,0,n); return; } #ifdef PATHCOUNTS ++count2; #endif k = 0; for (i = 0, gi = g; i < n; ++i, gi += m) { for (j = i; (j = nextelement(gi,m,j)) >= 0; ) { v0[k] = i; v1[k] = j; edgeno[i][j] = edgeno[j][i] = k; lastlev[i] = lastlev[j] = k; ++k; } } isreg = !lswitch && (maxdeg >= 0 && 2*minedges == n*(long)maxdeg); /* Case of regular multigraphs */ if (isreg) /* regular case */ /* Condition: def(v) <= total def of neighbours */ { for (i = 0; i < n; ++i) { def[i] = maxdeg - deg[i]; delta[i] = -def[i]; } for (i = 0; i < k; ++i) { x0 = v0[i]; x1 = v1[i]; delta[x0] += def[x1]; delta[x1] += def[x0]; } for (i = 0; i < n; ++i) if (delta[i] < 0) return; } if ((isreg || lswitch) && (maxdeg & n & 1) == 1) return; if (isreg && j0 >= 0 && maxdeg > 0) return; if (lswitch && j0 >= 0 && (maxdeg&1) == 1) return; #ifdef PATHCOUNTS ++count3; #endif if (maxedges == NOLIMIT) { if (maxmult == NOLIMIT) maxedges = maxdeg*n/2; else maxedges = ne*maxmult; } if (maxmult == NOLIMIT) maxmult = maxedges - ne + 1; if (maxdeg >= 0 && maxmult > maxdeg) maxmult = maxdeg; if (maxedges < ne || ne*maxmult < minedges) return; #ifdef PATHCOUNTS ++count4; #endif if (n > MAXNV || ne > MAXNE) { fprintf(stderr,">E multig: MAXNV or MAXNE exceeded\n"); exit(1); } nauty_check(WORDSIZE,m,n,NAUTYVERSIONID); for (i = 0; i < n; ++i) ptn[i] = 1; ptn[n-1] = 0; EMPTYSET(active,m); if (j0 != n-1) ADDELEMENT(active,j0+1); for (i = 0; i <= j0; ++i) ptn[i] = 0; for (i = j0+1; i < n; ++i) if (lab[i] < nfixed) break; if (i != j0+1 && i != n) { ptn[i-1] = 0; ADDELEMENT(active,i); } options.defaultptn = FALSE; options.userautomproc = groupautomproc; options.userlevelproc = grouplevelproc; nauty(g,lab,ptn,active,orbits,&options,&stats,workspace,100,m,n,NULL); if (stats.grpsize2 == 0) groupsize = stats.grpsize1 + 0.1; else groupsize = 0; group = groupptr(FALSE); makecosetreps(group); lastrejok = FALSE; if (isreg) scan_reg(0,ne,minedges,maxedges,0,maxmult,group,n,delta,def,maxdeg); else if (lswitch) scan_lp(0,ne,minedges,maxedges,0,maxmult,group,n,deg,maxdeg); else if (maxdeg >= 0) scan_md(0,ne,minedges,maxedges,0,maxmult,group,n,deg,maxdeg); else scan(0,ne,minedges,maxedges,0,maxmult,group,n); }
Nauty::Nauty(int vertices) { n_ = vertices; m_ = (n_ + WORDSIZE - 1)/WORDSIZE; //printf ("size of long = %d (%d)\nwordsize = %d\nn,m = %d,%d\n", // SIZEOF_LONG, sizeof (long), WORDSIZE, n_, m_); nauty_check (WORDSIZE, m_, n_, NAUTYVERSIONID); /// Apparently sizes are skewed on 64bit machines #define MULTIPLIER 2 G_ = (graph *) malloc(MULTIPLIER * m_ * n_ * sizeof(int)); lab_ = (int *) malloc(MULTIPLIER * n_ * sizeof(int)); ptn_ = (int *) malloc(MULTIPLIER * n_ * sizeof(int)); active_ = NULL; orbits_ = (int *) malloc(MULTIPLIER * n_ * sizeof(int)); options_ = (optionblk *) malloc(MULTIPLIER * sizeof(optionblk)); stats_ = (statsblk *) malloc(MULTIPLIER * sizeof(statsblk)); worksize_ = 100*m_; workspace_ = (setword *) malloc(MULTIPLIER * worksize_*sizeof(setword)); canonG_ = NULL; if (G_ == 0 || lab_ == 0 || ptn_ == 0 || orbits_ == 0 || options_ == 0 || stats_ == 0 || workspace_ == 0) assert(0); // Zero allocated memory memset(G_, 0, m_*n_*sizeof(int)); memset(lab_, 0, n_*sizeof(int)); memset(ptn_, 0, n_*sizeof(int)); memset(orbits_, 0, n_*sizeof(int)); memset(workspace_, 0, worksize_*sizeof(setword)); // Set the options you want options_->getcanon = FALSE; options_->digraph = FALSE; options_->writeautoms = FALSE; options_->writemarkers = FALSE; options_->defaultptn = TRUE; options_->cartesian = FALSE; options_->linelength = 78; options_->outfile = NULL; options_->userrefproc = NULL; options_->userautomproc = NULL; options_->userlevelproc = NULL; options_->usernodeproc = NULL; // options_->usertcellproc = NULL; options_->invarproc = NULL; options_->tc_level = 100; options_->mininvarlevel = 0; options_->maxinvarlevel = 1; options_->invararg = 0; options_->dispatch = &dispatch_graph; // Make an empty graph for (int j = 0; j < n_; j++) { set *gv = GRAPHROW(G_, j, m_); EMPTYSET(gv, m_); } vstat_ = new int[n_]; clearPartitions(); afp_ = NULL; }
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; }
/* Cette fonction génère les structures qui vont bien pour les appels à Nauty */ void Carquois::genGraph() { int i,j,m,nbSommetsNauty; int lab1[MAXN],ptn[MAXN],orbits[MAXN]; static DEFAULTOPTIONS_GRAPH(options); statsblk stats; setword workspace[5*MAXM]; if(!this->graphAJour) { nbSommetsNauty = 2 * this->getN(); m=(nbSommetsNauty + WORDSIZE - 1)/WORDSIZE; /* Si on trouve une valeur strictement positive dans la matrice d'incidence, alors on ajoute une arrête dans notre graphe */ for(i=0;i<this->getN();i++) { gv=GRAPHROW(nautyG,i+this->getN(),m); EMPTYSET(gv,m); gv=GRAPHROW(nautyG,i,m); EMPTYSET(gv,m); /* On ajoute les fausses arrêtes entre le layer 0 et le layer 1 */ ADDELEMENT(gv,i+this->getN()); for(j=0;j<this->getN();j++) { /* multiplicité de 1 */ if(this->getM(i,j)==1) { gv=GRAPHROW(nautyG,i,m); ADDELEMENT(gv,j); } else { if(this->getM(i,j)==2) { gv=GRAPHROW(nautyG,i+this->getN(),m); ADDELEMENT(gv,j+this->getN()); } } } } options.getcanon = TRUE; options.digraph = TRUE; options.defaultptn = FALSE; nauty_check(WORDSIZE,m,nbSommetsNauty,NAUTYVERSIONID); for(i=0;i<2*n;i++) { lab1[i]=i; ptn[i]=1; } ptn[n-1]=0; ptn[2*n-1]=0; nauty(nautyG,lab1,ptn,NULL,orbits,&options,&stats, workspace,5*MAXM,m,nbSommetsNauty,nautyGC); this->graphAJour=1; } }