int main(int argc, char *argv[]) { DYNALLSTAT(graph,g,g_sz); DYNALLSTAT(int,lab,lab_sz); DYNALLSTAT(int,ptn,ptn_sz); DYNALLSTAT(int,orbits,orbits_sz); static DEFAULTOPTIONS_GRAPH(options); statsblk stats; int n,m,v; grouprec *group; /* The following cause nauty to call two procedures which store the group information as nauty runs. */ options.userautomproc = groupautomproc; options.userlevelproc = grouplevelproc; while (1) { printf("\nenter n : "); if (scanf("%d",&n) == 1 && n > 0) { m = SETWORDSNEEDED(n); nauty_check(WORDSIZE,m,n,NAUTYVERSIONID); DYNALLOC2(graph,g,g_sz,m,n,"malloc"); DYNALLOC1(int,lab,lab_sz,n,"malloc"); DYNALLOC1(int,ptn,ptn_sz,n,"malloc"); DYNALLOC1(int,orbits,orbits_sz,n,"malloc"); EMPTYGRAPH(g,m,n); for (v = 0; v < n; ++v) ADDONEEDGE(g,v,(v+1)%n,m); printf("Automorphisms of C[%d]:\n",n); densenauty(g,lab,ptn,orbits,&options,&stats,m,n,NULL); /* Get a pointer to the structure in which the group information has been stored. If you use TRUE as an argument, the structure will be "cut loose" so that it won't be used again the next time nauty() is called. Otherwise, as here, the same structure is used repeatedly. */ group = groupptr(FALSE); /* Expand the group structure to include a full set of coset representatives at every level. This step is necessary if allgroup() is to be called. */ makecosetreps(group); /* Call the procedure writeautom() for every element of the group. The first call is always for the identity. */ allgroup(group,writeautom); } else break;
int static main(int argc, char *argv[]) { DYNALLSTAT(int,lab,lab_sz); DYNALLSTAT(int,ptn,ptn_sz); DYNALLSTAT(int,orbits,orbits_sz); static DEFAULTOPTIONS_SPARSEGRAPH(options); statsblk stats; sparsegraph sg; /* Declare sparse graph structure */ int n,m,i; options.writeautoms = TRUE; /* Initialise sparse graph structure. */ SG_INIT(sg); while (1) { printf("\nenter n : "); if (scanf("%d",&n) == 1 && n > 0) { m = SETWORDSNEEDED(n); nauty_check(WORDSIZE,m,n,NAUTYVERSIONID); DYNALLOC1(int,lab,lab_sz,n,"malloc"); DYNALLOC1(int,ptn,ptn_sz,n,"malloc"); DYNALLOC1(int,orbits,orbits_sz,n,"malloc"); /* SG_ALLOC makes sure that the v,d,e fields of a sparse graph structure point to arrays that are large enough. This only works if the structure has been initialised. */ SG_ALLOC(sg,n,2*n,"malloc"); sg.nv = n; /* Number of vertices */ sg.nde = 2*n; /* Number of directed edges */ for (i = 0; i < n; ++i) { sg.v[i] = 2*i; sg.d[i] = 2; sg.e[2*i] = (i+n-1)%n; /* edge i->i-1 */ sg.e[2*i+1] = (i+n+1)%n; /* edge i->i+1 */ } printf("Generators for Aut(C[%d]):\n",n); sparsenauty(&sg,lab,ptn,orbits,&options,&stats,NULL); printf("Automorphism group size = "); writegroupsize(stdout,stats.grpsize1,stats.grpsize2); printf("\n"); } else break;
/* This method translates the internal data structure to nauty's dense graph * data structure, so the graph can be passed to nauty. */ static inline void translateGraphToNautyDenseGraph(GRAPH graph, ADJACENCY adj){ int n, i, j; n = graph[0][0]; if(n > MAXN){ fprintf(stderr, "We only support graphs with up to %d vertices - exiting!\n", MAXN); exit(EXIT_FAILURE); } m = SETWORDSNEEDED(n); nauty_check(WORDSIZE,m,n,NAUTYVERSIONID); EMPTYGRAPH(ng,m,n); for(i = 1; i <= graph[0][0]; i++){ for(j = 0; j < adj[i]; j++){ if(i < graph[i][j]){ ADDONEEDGE(ng, i - 1, graph[i][j] - 1, m); } } } }
int static main(int argc, char *argv[]) { DYNALLSTAT(int,lab1,lab1_sz); DYNALLSTAT(int,lab2,lab2_sz); DYNALLSTAT(int,ptn,ptn_sz); DYNALLSTAT(int,orbits,orbits_sz); DYNALLSTAT(int,map,map_sz); static DEFAULTOPTIONS_TRACES(options); TracesStats stats; /* Declare and initialize sparse graph structures */ SG_DECL(sg1); SG_DECL(sg2); SG_DECL(cg1); SG_DECL(cg2); int n,m,i; /* Select option for canonical labelling */ options.getcanon = TRUE; /* Read a number of vertices and process */ while (1) { printf("\nenter n : "); if (scanf("%d",&n) == 1 && n > 0) { if (n%2 != 0) { fprintf(stderr,"Sorry, n must be even\n"); continue; } m = SETWORDSNEEDED(n); nauty_check(WORDSIZE,m,n,NAUTYVERSIONID); DYNALLOC1(int,lab1,lab1_sz,n,"malloc"); DYNALLOC1(int,lab2,lab2_sz,n,"malloc"); DYNALLOC1(int,ptn,ptn_sz,n,"malloc"); DYNALLOC1(int,orbits,orbits_sz,n,"malloc"); DYNALLOC1(int,map,map_sz,n,"malloc"); /* Now make the first graph */ SG_ALLOC(sg1,n,3*n,"malloc"); sg1.nv = n; /* Number of vertices */ sg1.nde = 3*n; /* Number of directed edges */ for (i = 0; i < n; ++i) { sg1.v[i] = 3*i; /* Position of vertex i in v array */ sg1.d[i] = 3; /* Degree of vertex i */ } for (i = 0; i < n; i += 2) /* Spokes */ { sg1.e[sg1.v[i]] = i+1; sg1.e[sg1.v[i+1]] = i; } for (i = 0; i < n-2; ++i) /* Clockwise edges */ sg1.e[sg1.v[i]+1] = i+2; sg1.e[sg1.v[n-2]+1] = 1; sg1.e[sg1.v[n-1]+1] = 0; for (i = 2; i < n; ++i) /* Anticlockwise edges */ sg1.e[sg1.v[i]+2] = i-2; sg1.e[sg1.v[1]+2] = n-2; sg1.e[sg1.v[0]+2] = n-1; /* Now make the second graph */ SG_ALLOC(sg2,n,3*n,"malloc"); sg2.nv = n; /* Number of vertices */ sg2.nde = 3*n; /* Number of directed edges */ for (i = 0; i < n; ++i) { sg2.v[i] = 3*i; sg2.d[i] = 3; } for (i = 0; i < n; ++i) { sg2.v[i] = 3*i; sg2.d[i] = 3; sg2.e[sg2.v[i]] = (i+1) % n; /* Clockwise */ sg2.e[sg2.v[i]+1] = (i+n-1) % n; /* Anti-clockwise */ sg2.e[sg2.v[i]+2] = (i+n/2) % n; /* Diagonals */ } /* Label sg1, result in cg1 and labelling in lab1; similarly sg2. It is not necessary to pre-allocate space in cg1 and cg2, but they have to be initialised as we did above. */ Traces(&sg1,lab1,ptn,orbits,&options,&stats,&cg1); Traces(&sg2,lab2,ptn,orbits,&options,&stats,&cg2); /* Compare canonically labelled graphs */ if (aresame_sg(&cg1,&cg2)) { printf("Isomorphic.\n"); if (n <= 1000) { /* Write the isomorphism. For each i, vertex lab1[i] of sg1 maps onto vertex lab2[i] of sg2. We compute the map in order of labelling because it looks better. */ for (i = 0; i < n; ++i) map[lab1[i]] = lab2[i]; for (i = 0; i < n; ++i) printf(" %d-%d",i,map[i]); printf("\n"); } } else printf("Not isomorphic.\n"); } else break; }
int main(int argc, char *argv[]) { DYNALLSTAT(int,p,p_sz); DYNALLSTAT(boolean,issquare,issquare_sz); DYNALLSTAT(int,lab,lab_sz); DYNALLSTAT(int,ptn,ptn_sz); DYNALLSTAT(int,orbits,orbits_sz); static DEFAULTOPTIONS_TRACES(options); TracesStats stats; /* Declare and initialize sparse graph structures */ SG_DECL(sg); int deg,n,m,i,j; size_t k; permnode *gens; /* Select option for passing generators to Traces */ options.generators = &gens; /* Read a number of vertices and process it */ while (1) { printf("\nenter n : "); if (scanf("%d",&n) == 1 && n > 2) { m = SETWORDSNEEDED(n); nauty_check(WORDSIZE,m,n,NAUTYVERSIONID); DYNALLOC1(int,lab,lab_sz,n,"malloc"); DYNALLOC1(int,ptn,ptn_sz,n,"malloc"); DYNALLOC1(int,orbits,orbits_sz,n,"malloc"); DYNALLOC1(int,p,p_sz,n,"malloc"); DYNALLOC1(boolean,issquare,issquare_sz,n,"malloc"); /* Initialise list of automorphisms */ gens = NULL; /* Find the squares and the degree */ for (i = 0; i < n; ++i) issquare[i] = FALSE; for (i = 0; i < n; ++i) issquare[(i*i)%n] = TRUE; if (!issquare[n-1]) { printf("-1 must be a square mod n; try again\n"); continue; } deg = 0; for (i = 1; i < n; ++i) if (issquare[i]) ++deg; /* Now make the graph */ SG_ALLOC(sg,n,n*deg,"malloc"); sg.nv = n; /* Number of vertices */ sg.nde = n*deg; /* Number of directed edges */ for (i = 0; i < n; ++i) { sg.v[i] = i*deg; /* Position of vertex i in v array */ sg.d[i] = deg; /* Degree of vertex i */ } for (i = 0; i < n; ++i) /* Edges */ { k = sg.v[i]; for (j = 1; j < n; ++j) if (issquare[j]) sg.e[k++] = (i + j) % n; } /* Add known automorphisms */ /* We wouldn't need freeschreier() if we were only processing one graph, but it doesn't hurt. This is how to properly dispose of previous generators. */ freeschreier(NULL,&gens); /* Cyclic rotation */ for (i = 0; i < n; ++i) p[i] = (i + 1) % n; addpermutation(&gens,p,n); /* Reflection about 0 */ for (i = 0; i < n; ++i) p[i] = (n - i) % n; addpermutation(&gens,p,n); /* Call Traces */ Traces(&sg,lab,ptn,orbits,&options,&stats,NULL); printf("Automorphism group size = "); writegroupsize(stdout,stats.grpsize1,stats.grpsize2); printf("\n"); /* Traces left the automorphims we gave it, augmented by any extra automorphims it found, in a circular list pointed to by gens. See schreier.txt for documentation. */ } else break;
int main(int argc, char *argv[]) { DYNALLSTAT(int,lab1,lab1_sz); DYNALLSTAT(int,lab2,lab2_sz); DYNALLSTAT(int,ptn,ptn_sz); DYNALLSTAT(int,orbits,orbits_sz); DYNALLSTAT(int,map,map_sz); DYNALLSTAT(graph,g1,g1_sz); DYNALLSTAT(graph,g2,g2_sz); DYNALLSTAT(graph,cg1,cg1_sz); DYNALLSTAT(graph,cg2,cg2_sz); static DEFAULTOPTIONS_GRAPH(options); statsblk stats; int n,m,i; size_t k; /* Select option for canonical labelling */ options.getcanon = TRUE; while (1) { printf("\nenter n : "); if (scanf("%d",&n) == 1 && n > 0) { if (n%2 != 0) { fprintf(stderr,"Sorry, n must be even\n"); continue; } m = SETWORDSNEEDED(n); nauty_check(WORDSIZE,m,n,NAUTYVERSIONID); DYNALLOC1(int,lab1,lab1_sz,n,"malloc"); DYNALLOC1(int,lab2,lab2_sz,n,"malloc"); DYNALLOC1(int,ptn,ptn_sz,n,"malloc"); DYNALLOC1(int,orbits,orbits_sz,n,"malloc"); DYNALLOC1(int,map,map_sz,n,"malloc"); /* Now make the first graph */ DYNALLOC2(graph,g1,g1_sz,n,m,"malloc"); EMPTYGRAPH(g1,m,n); for (i = 0; i < n; i += 2) /* Spokes */ ADDONEEDGE(g1,i,i+1,m); for (i = 0; i < n-2; ++i) /* Cycle */ ADDONEEDGE(g1,i,i+2,m); ADDONEEDGE(g1,1,n-2,m); ADDONEEDGE(g1,0,n-1,m); /* Now make the second graph */ DYNALLOC2(graph,g2,g2_sz,n,m,"malloc"); EMPTYGRAPH(g2,m,n); for (i = 0; i < n; ++i) { ADDONEEDGE(g2,i,(i+1)%n,m); /* Rim */ ADDONEEDGE(g2,i,(i+n/2)%n,m); /* Diagonals */ } /* Create canonical graphs */ DYNALLOC2(graph,cg1,cg1_sz,n,m,"malloc"); DYNALLOC2(graph,cg2,cg2_sz,n,m,"malloc"); densenauty(g1,lab1,ptn,orbits,&options,&stats,m,n,cg1); densenauty(g2,lab2,ptn,orbits,&options,&stats,m,n,cg2); /* Compare canonically labelled graphs */ for (k = 0; k < m*(size_t)n; ++k) if (cg1[k] != cg2[k]) break; if (k == m*(size_t)n) { printf("Isomorphic.\n"); if (n <= 1000) { /* Write the isomorphism. For each i, vertex lab1[i] of sg1 maps onto vertex lab2[i] of sg2. We compute the map in order of labelling because it looks better. */ for (i = 0; i < n; ++i) map[lab1[i]] = lab2[i]; for (i = 0; i < n; ++i) printf(" %d-%d",i,map[i]); printf("\n"); } } else printf("Not isomorphic.\n"); } else break; }
static void* runit(void * threadarg) /* Main routine for one thread */ { DYNALLSTAT(int,lab,lab_sz); DYNALLSTAT(int,ptn,ptn_sz); DYNALLSTAT(int,orbits,orbits_sz); DEFAULTOPTIONS_SPARSEGRAPH(options); statsblk stats; sparsegraph sg; /* Declare sparse graph structure */ int n,m,i; n = ((params*)threadarg)->n; options.writeautoms = ((params*)threadarg)->writeautoms; /* Initialise sparse graph structure. */ SG_INIT(sg); m = SETWORDSNEEDED(n); nauty_check(WORDSIZE,m,n,NAUTYVERSIONID); DYNALLOC1(int,lab,lab_sz,n,"malloc"); DYNALLOC1(int,ptn,ptn_sz,n,"malloc"); DYNALLOC1(int,orbits,orbits_sz,n,"malloc"); /* SG_ALLOC makes sure that the v,d,e fields of a sparse graph structure point to arrays that are large enough. This only works if the structure has been initialised. */ SG_ALLOC(sg,n,2*n,"malloc"); sg.nv = n; /* Number of vertices */ sg.nde = 2*n; /* Number of directed edges */ for (i = 0; i < n; ++i) { sg.v[i] = 2*i; sg.d[i] = 2; sg.e[2*i] = (i+n-1)%n; /* edge i->i-1 */ sg.e[2*i+1] = (i+n+1)%n; /* edge i->i+1 */ } if (options.writeautoms) printf("Generators for Aut(C[%d]):\n",n); sparsenauty(&sg,lab,ptn,orbits,&options,&stats,NULL); if (options.writeautoms) { printf("Automorphism group size = "); writegroupsize(stdout,stats.grpsize1,stats.grpsize2); printf("\n"); } if (stats.numorbits != 1 || stats.grpsize1 != 2*n) fprintf(stderr,">E group error\n"); /* If we are using multiple threads, we need to free all the dynamic memory we have allocated. We don't have to do this after each call to nauty, just once before the thread finishes. */ SG_FREE(sg); DYNFREE(lab,lab_sz); DYNFREE(ptn,ptn_sz); DYNFREE(orbits,orbits_sz); nauty_freedyn(); nautil_freedyn(); nausparse_freedyn(); /* Use naugraph_freedyn() instead if dense format is being used. */ return NULL; }
int main(int argc, char *argv[]) { graph g[MAXN*MAXM]; int lab[MAXN],ptn[MAXN],orbits[MAXN]; static DEFAULTOPTIONS_GRAPH(options); statsblk stats; int n,m,v; /* Default options are set by the DEFAULTOPTIONS_GRAPH macro above. Here we change those options that we want to be different from the defaults. writeautoms=TRUE causes automorphisms to be written. */ options.writeautoms = TRUE; while (1) { printf("\nenter n : "); if (scanf("%d",&n) != 1 || n <= 0) /* Exit if EOF or bad number */ break; if (n > MAXN) { printf("n must be in the range 1..%d\n",MAXN); exit(1); } /* The nauty parameter m is a value such that an array of m setwords is sufficient to hold n bits. The type setword is defined in nauty.h. The number of bits in a setword is WORDSIZE, which is 16, 32 or 64. Here we calculate m = ceiling(n/WORDSIZE). */ m = SETWORDSNEEDED(n); /* The following optional call verifies that we are linking to compatible versions of the nauty routines. */ nauty_check(WORDSIZE,m,n,NAUTYVERSIONID); /* Now we create the cycle. First we zero the graph, than for each v, we add the edge (v,v+1), where values are mod n. */ EMPTYGRAPH(g,m,n); for (v = 0; v < n; ++v) ADDONEEDGE(g,v,(v+1)%n,m); printf("Generators for Aut(C[%d]):\n",n); /* Since we are not requiring a canonical labelling, the last parameter to densenauty() is not required and can be NULL. */ densenauty(g,lab,ptn,orbits,&options,&stats,m,n,NULL); /* The size of the group is returned in stats.grpsize1 and stats.grpsize2. */ printf("Automorphism group size = "); writegroupsize(stdout,stats.grpsize1,stats.grpsize2); printf("\n"); } exit(0); }
void main(int argc, char** argv) { boost::program_options::options_description options("Usage"); options.add_options() ("graphFile", boost::program_options::value<std::string>(), "(path) The path to a graph file, in graphml format. ") ("help", "Display this message"); boost::program_options::variables_map variableMap; try { boost::program_options::store(boost::program_options::parse_command_line(argc, argv, options), variableMap); } catch (boost::program_options::error& ee) { std::cerr << "Error parsing command line arguments: " << ee.what() << std::endl << std::endl; std::cerr << options << std::endl; return; } if (variableMap.count("help") > 0) { std::cout << "Compute the size of the automorphism group" << std::endl; std::cout << options << std::endl; return; } std::ifstream graphStream(variableMap["graphFile"].as<std::string>()); typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS> graphType; graphType boostGraph; boost::dynamic_properties properties; try { boost::read_graphml(graphStream, boostGraph, properties, 0); } catch(std::exception& exp) { std::cout << "Error calling boost::read_graphml: " << exp.what() << std::endl; return; } std::size_t nVertices = boost::num_vertices(boostGraph); std::vector<int> lab; std::vector<int> ptn; std::vector<int> orbits; std::vector<graph> nautyGraph; std::vector<graph> cannonicalNautyGraph; static DEFAULTOPTIONS_GRAPH(nautyOptions); statsblk stats; //nautyOptions.getcanon = true; nautyOptions.userlevelproc = userlevelproc; int n = nVertices; int m = SETWORDSNEEDED(n); nauty_check(WORDSIZE, m, n, NAUTYVERSIONID); lab.resize(n); ptn.resize(n); orbits.resize(n); nautyGraph.resize(n * m); EMPTYGRAPH(&(nautyGraph[0]), m, n); graphType::edge_iterator current, end; boost::tie(current, end) = boost::edges(boostGraph); for(; current != end; current++) { ADDONEEDGE(&(nautyGraph[0]), (int)boost::source(*current, boostGraph), (int)boost::target(*current, boostGraph), m); } //cannonicalNautyGraph.resize(n * m); densenauty(&(nautyGraph[0]), &(lab[0]), &(ptn[0]), &(orbits[0]), &nautyOptions, &stats, m, n, &(cannonicalNautyGraph[0])); std::cout << product << std::endl; }
JNIEXPORT jobjectArray JNICALL Java_org_tmu_core_Nauty_canonize (JNIEnv * env, jobject thisobj, jobjectArray arr, jint k){ int subgraph_size=0; graph g[MAXN*MAXM]; graph canong[MAXN*MAXM]; int lab[MAXN],ptn[MAXN],orbits[MAXN]; static DEFAULTOPTIONS_DIGRAPH(options); statsblk stats; subgraph_size=k; if (subgraph_size > MAXN) { printf("size of graph must be in the range 1..%d\n",MAXN); return NULL; } options.defaultptn = TRUE; options.getcanon = TRUE; char bin_adj[BUFSIZE]; char zeroed_adj[BUFSIZE]; char str[BUFSIZE]; int n=subgraph_size; int m=SETWORDSNEEDED(n); nauty_check(WORDSIZE,m,n,NAUTYVERSIONID); int stringCount = GetArrayLength(env, arr); jobjectArray ret; ret= (jobjectArray)env->NewObjectArray(stringCount, env->FindClass("java/lang/String"), env->NewStringUTF("")); for (int i=0; i<stringCount; i++) { jstring string = (jstring) GetObjectArrayElement(env, arr, i); const char *rawString = GetStringUTFChars(env, string, 0); strcpy(bin_adj,rawString); ReleaseStringUTFChars(rawString); int bin_len=strlen(bin_adj); if(bin_len<subgraph_size*subgraph_size){ memset(zeroed_adj,'0',subgraph_size*subgraph_size-bin_len); } strcpy(zeroed_adj+subgraph_size*subgraph_size-bin_len,bin_adj); EMPTYGRAPH(g,m,n); for (int i = 0; i < subgraph_size; i++) for (int j = 0; j < subgraph_size; j++) if (i!=j&&zeroed_adj[i * subgraph_size + j] == '1') ADDONEARC(g,i,j,m); densenauty(g,lab,ptn,orbits,&options,&stats,m,n,canong); memset(str,'0',subgraph_size*subgraph_size); for (int i = 0; i < subgraph_size; i++) { for(int j = 0; j < subgraph_size; j++) { if(i!=j&&zeroed_adj[lab[i]*subgraph_size+lab[j]]=='1') str[i*subgraph_size+j]='1'; } } str[subgraph_size*subgraph_size]=0; env->SetObjectArrayElement(ret,i,env->NewStringUTF(str)); } return ret; }
static void* runit(void * threadarg) /* Main routine for one thread */ { DYNALLSTAT(graph,g,g_sz); DYNALLSTAT(int,lab,lab_sz); DYNALLSTAT(int,ptn,ptn_sz); DYNALLSTAT(int,orbits,orbits_sz); DEFAULTOPTIONS_GRAPH(options); statsblk stats; set *gv; int n,m,v; n = ((params*)threadarg)->n; /* Default options are set by the DEFAULTOPTIONS_GRAPH macro above. Here we change those options that we want to be different from the defaults. writeautoms=TRUE causes automorphisms to be written. */ options.writeautoms = ((params*)threadarg)->writeautoms; m = SETWORDSNEEDED(n); /* The following optional call verifies that we are linking to compatible versions of the nauty routines. */ nauty_check(WORDSIZE,m,n,NAUTYVERSIONID); DYNALLOC2(graph,g,g_sz,m,n,"malloc"); DYNALLOC1(int,lab,lab_sz,n,"malloc"); DYNALLOC1(int,ptn,ptn_sz,n,"malloc"); DYNALLOC1(int,orbits,orbits_sz,n,"malloc"); /* Now we will make a polygon of n vertices */ EMPTYGRAPH(g,m,n); for (v = 0; v < n; ++v) ADDONEEDGE(g,v,(v+1)%n,m); if (options.writeautoms) printf("Generators for Aut(C[%d]):\n",n); densenauty(g,lab,ptn,orbits,&options,&stats,m,n,NULL); if (options.writeautoms) { printf("order = "); writegroupsize(stdout,stats.grpsize1,stats.grpsize2); printf("\n"); } if (stats.numorbits != 1 || stats.grpsize1 != 2*n) fprintf(stderr,">E group error\n"); /* If we are using multiple threads, we need to free all the dynamic memory we have allocated. We don't have to do this after each call to nauty, just once before the thread finishes. */ DYNFREE(g,g_sz); DYNFREE(lab,lab_sz); DYNFREE(ptn,ptn_sz); DYNFREE(orbits,orbits_sz); nauty_freedyn(); nautil_freedyn(); naugraph_freedyn(); /* Use nausparse_freedyn() instead if sparse format is being used. */ return NULL; }
int main(int argc, char *argv[]) { DYNALLSTAT(int,lab1,lab1_sz); DYNALLSTAT(int,lab2,lab2_sz); DYNALLSTAT(int,ptn,ptn_sz); DYNALLSTAT(int,orbits,orbits_sz); DYNALLSTAT(int,map,map_sz); DYNALLSTAT(graph,g1,g1_sz); DYNALLSTAT(graph,g2,g2_sz); DYNALLSTAT(graph,cg1,cg1_sz); DYNALLSTAT(graph,cg2,cg2_sz); static DEFAULTOPTIONS_GRAPH(options); statsblk stats; int n,m,i; /* Select option for canonical labelling */ options.getcanon = TRUE; while (1) { printf("\nenter n : "); if (scanf("%d",&n) == 1 && n > 0) { if (n%2 != 0) { fprintf(stderr,"Sorry, n must be even\n"); continue; } m = SETWORDSNEEDED(n); nauty_check(WORDSIZE,m,n,NAUTYVERSIONID); DYNALLOC1(int,lab1,lab1_sz,n,"malloc"); DYNALLOC1(int,lab2,lab2_sz,n,"malloc"); DYNALLOC1(int,ptn,ptn_sz,n,"malloc"); DYNALLOC1(int,orbits,orbits_sz,n,"malloc"); DYNALLOC1(int,map,map_sz,n,"malloc"); DYNALLOC2(graph,g1,g1_sz,n,m,"malloc"); DYNALLOC2(graph,g2,g2_sz,n,m,"malloc"); DYNALLOC2(graph,cg1,cg1_sz,n,m,"malloc"); DYNALLOC2(graph,cg2,cg2_sz,n,m,"malloc"); /* Now make the first graph */ /* ADDEDGE() is defined above */ EMPTYGRAPH(g1,m,n); /* start with no edges */ for (i = 0; i < n-2; ++i) ADDONEEDGE(g1,i,i+2,m); ADDONEEDGE(g1,n-2,1,m); ADDONEEDGE(g1,n-1,0,m); for (i = 0; i < n; i += 2) ADDONEEDGE(g1,i,i+1,m); /* Now make the second graph */ EMPTYGRAPH(g2,m,n); /* start with no edges */ for (i = 0; i < n-1; ++i) ADDONEEDGE(g2,i,i+1,m); ADDONEEDGE(g2,n-1,0,m); for (i = 0; i < n/2; ++i) ADDONEEDGE(g2,i,i+n/2,m); /* Label g1, result in cg1 and labelling in lab1; similarly g2. It is not necessary to pre-allocate space in cg1 and cg2, but they have to be initialised as we did above. */ densenauty(g1,lab1,ptn,orbits,&options,&stats,m,n,cg1); densenauty(g2,lab2,ptn,orbits,&options,&stats,m,n,cg2); /* Compare canonically labelled graphs */ if (memcmp(cg1,cg2,m*sizeof(graph)*n) == 0) { printf("Isomorphic.\n"); if (n <= 1000) { /* Write the isomorphism. For each i, vertex lab1[i] of sg1 maps onto vertex lab2[i] of sg2. We compute the map in order of labelling because it looks better. */ for (i = 0; i < n; ++i) map[lab1[i]] = lab2[i]; for (i = 0; i < n; ++i) printf(" %d-%d",i,map[i]); printf("\n"); } } else printf("Not isomorphic.\n"); } else break; }