/* This is dretodot.c version 1.0 (Feb 2016), which is included in * * nauty distribution (version 2.6). * * See the file COPYRIGHT for the details of the software license. * * * * gcc -03 -o dretodot dretodot.c nauty.a * * nauty.a is produced by: make all */ #define USAGE "dretodot [-S#:#ixF#o#m#n#r#:#[r#]d#g] [infile.dre [outfile.dot [outfile.dre]]]" #define HELPTEXT \ " Read graphs and initial coloring in dreadnaut format.\n\ Write graphs in dot format to outfile.dot.\n\ If outfile.dre is given, write the input graph and the partition,\n\ as modified by the -F and -i options, to outfile.dre. outfile.dre\n\ is allowed to be the same file as infile.dre.\n\ -V Set max number of vertices (default 1000).\n\ -E Set max number of edges (default 5000).\n\ -v Set verbose mode (default NO).\n\ -S#:# Set maximum width and height of the drawing, in inches\n\ (default 10 x 6.18).\n\ -i Refine the partition before drawing (default NO).\n\ -x Draw the orbit partition, computed by Traces. (default NO).\n\ -F# Individualize vertex # (and refine the partition).\n\ -o# Label vertices starting at # (default 0). This can be\n\ overridden in the input.\n\ -m# Set the drawing model (see http://www.graphviz.org): \n\ 0 (or any value different from 1,...,5)=dot (default 0),\n\ 1=neato, 2=fdp, 3=sfdp, 4=twopi, 5=circo.\n\ -n# Scale the size of vertices in the drawing (#=0,1,2; default 1).\n\ -r#:# (-r#) Set the vertices to be drawn at the topmost level\n\ in a hierarchical (dot model) drawing (default none).\n\ Any sequence of -r#:# (r#) options is allowed.\n\ -d# Draw the graph induced by vertices at topmost level\n\ and by vertices at distance # from them; example:\n\ ./dretodot -n2 -r1 -r12:17 -d2 MyGraph.dre Outfile.dot.\n\ -g Highlight the induced subgraph into the whole graph.\n\ \n\ Only dreadnaut commands $,$$,g,n,f,\",! are recognised; no digraphs.\n" /*************************************************************************/ #include #include "gtools.h" /* which includes nauty.h and stdio.h */ #include "traces.h" #define SORT_OF_SORT 2 #define SORT_TYPE1 int #define SORT_TYPE2 int #define SORT_NAME sort2ints #include "sorttemplates.c" #define WRITEDREFILE if (argnum == 3) { \ fprintf(drefile, "n=%d $=%d g\n", n, labelorg); \ putgraph_sg(drefile, &g, 0); \ if (numcells > 1) { \ fprintf(drefile, "f = "); \ putptn(drefile,lab,ptn,0,0,n); }} extern int labelorg; /**************************************************************************/ typedef struct NodeShape { char color[6]; int labcol; } NodeShape; typedef struct list { int vtx; struct list *next; } list; struct list *NewListelem(int el) { struct list *L; L = malloc(sizeof(list)); if (L == NULL) { fprintf(ERRFILE, "\nError, memory not allocated.\n"); exit(1); } L->vtx = el; L->next = NULL; return L; } #define FONT_NAME "Arial Narrow" #if MAXN int lab[MAXN]; int invlab[MAXN]; int ptn[MAXN]; NodeShape NShape[MAXN]; int CurrVertices[MAXN]; int DistStack[MAXN]; int Ranks[MAXN]; int orbits[MAXN]; #else DYNALLSTAT(int, lab, lab_sz); DYNALLSTAT(int, invlab, invlab_sz); DYNALLSTAT(int, ptn, ptn_sz); DYNALLSTAT(NodeShape, NShape, NShape_sz); DYNALLSTAT(int, CurrVertices, CurrVertices_sz); DYNALLSTAT(int, DistStack, DistStack_sz); DYNALLSTAT(int, Ranks, Ranks_sz); DYNALLSTAT(int, orbits, orbits_sz); #endif DEFAULTOPTIONS_TRACES(traces_opts); TracesStats traces_stats; void CreateRandColors(int n) { int i=0, ind0, ind1, ind2; char aux[6]; ran_init(n); for (i = 0; iE dretodot -V") else SWINT('E', Eswitch, MaxE, ">E dretodot -E") else SWINT('d', dswitch, distance, ">E dretodot -d") else SWINT('F', fswitch, indivtx, ">E dretodot -F") else SWINT('m', mswitch, modcode, ">E dretodot -m") else SWINT('n', nswitch, nodescale, ">E dretodot -n") else SWINT('o', oswitch, initorg, ">E dretodot -o") else SWRANGE('r',":-",rswitch,minil,maxil,">E dretodot -r") else SWREALRANGE('S',":-",Sswitch,hsize,vsize,">E dretodot -S") else badargs = TRUE; } if (rswitch) { rswitch1 = TRUE; rswitch = FALSE; for (i=minil; i<=maxil; i++) { if (liststart == NULL) { liststart = NewListelem(i); listend = liststart; } else { listend->next = NewListelem(i); listend = listend->next; } } } } else { ++argnum; if (argnum == 1) infilename = arg; else if (argnum == 2) outfilename = arg; else if (argnum == 3) drefilename = arg; else badargs = TRUE; } } if (labelorg < 0) gt_abort(">E dretodot: negative origin forbidden\n"); if (badargs || argnum > 3) { fprintf(stderr, ">E Usage: %s\n", USAGE); GETHELP; exit(1); } if (!infilename || infilename[0] == '-') { infilename = "stdin"; infile = stdin; } else if ((infile = fopen(infilename, "r")) == NULL) { fprintf(stderr, "Can't open input file %s\n", infilename); gt_abort(NULL); } if (!outfilename || outfilename[0] == '-') { outfilename = "stdout"; outfile = stdout; } else if ((outfile = fopen(outfilename, "w")) == NULL) { fprintf(stderr, "Can't open output file %s\n", outfilename); gt_abort(NULL); } labelorg = initorg; nin = 0; while (fscanf(infile, "%1s", s) == 1) { if (s[0] == 'n') { if (fscanf(infile, "%1s", s) == 1 && s[0] != '=') ungetc(s[0], infile); if (fscanf(infile, "%d", &n) != 1) { fprintf(stderr, ">E dretodot: invalid n=# command\n"); gt_abort(NULL); } if (n <= 0) gt_abort(">E dretodot: n can't be <= 0\n"); } else if (s[0] == '"') { while ((c = getc(infile)) != '"' && c != EOF) {} } else if (s[0] == '!') { while ((c = getc(infile)) != '\n' && c != EOF) {} } else if (s[0] == '$') { if ((s[0] = getc(infile)) == '$') labelorg = initorg; else { if (s[0] != '=') ungetc(s[0], infile); if (fscanf(infile, "%d", &labelorg) != 1) gt_abort(">E dretodot: invalid $=# command\n"); if (labelorg < 0) gt_abort(">E dretodot: must have labelorg >= 0\n"); } } else if (s[0] == 'g' || (s[0] >= '0' && s[0] <= '9') || s[0] == ';') { if (n < 0) gt_abort(">E dretodot: g command before n is defined\n"); if (s[0] != 'g') ungetc(s[0], infile); m = (n + WORDSIZE - 1) / WORDSIZE; #if MAXN if (n > MAXN || m > MAXM) gt_abort(">E n or m too big\n"); #else DYNALLOC2(int, lab, lab_sz, n, m, "dretodot"); DYNALLOC2(int, invlab, invlab_sz, n, m, "dretodot"); DYNALLOC2(int, ptn, ptn_sz, n, m, "dretodot"); DYNALLOC2(NodeShape, NShape, NShape_sz, n, m, "dretodot"); DYNALLOC2(int, orbits, orbits_sz, n, m, "dretodot"); #endif for (i=0; i 1) { traces_opts.defaultptn = FALSE; } } else { fprintf(stderr, ">E dretodot: invalid command \"%c\"\n", s[0]); gt_abort(NULL); } } fclose(infile); if ((nodescale != 0) && (nodescale != 1) && (nodescale != 2)) { nodescale = 1; } if (!drefilename || drefilename[0] == '-') { drefilename = "stdout"; drefile = stdout; } else if ((drefile = fopen(drefilename, "w")) == NULL) { fprintf(stderr, "Can't open output file %s\n", drefilename); gt_abort(NULL); } if (!dswitch) distance = n; if (iswitch && !xswitch && !fswitch) { if (vswitch) fprintf(stderr, ">Z partition refinement..."); refine_tr(&g,lab,ptn,&numcells,&refcode,&traces_opts); if (vswitch) fprintf(stderr, "done.\n"); WRITEDREFILE } if (fswitch) { indivtx -= labelorg; refine_tr(&g,lab,ptn,&numcells,&refcode,&traces_opts); cell = 0; for (i=0; iZ running Traces..."); Traces(&g,lab,ptn,orbits,&traces_opts,&traces_stats,&g1); if (vswitch) fprintf(stderr, "done.\n"); WRITEDREFILE for (i=0; iZ selected drawing model \"%s\".\n",model); #if !MAXN DYNALLOC2(int, CurrVertices, CurrVertices_sz, n, m, "dretodot"); DYNALLOC2(int, DistStack, DistStack_sz, n, m, "dretodot"); DYNALLOC2(int, Ranks, Ranks_sz, n, m, "dretodot"); #endif if (vswitch) fprintf(stderr, ">Z analyzing graph: step 1"); if (!liststart) { for (i=0; ivtx-labelorg < 0 || listend->vtx-labelorg >= n) { fprintf(stderr, ">W dretodot: invalid vertex %d\n", listend->vtx); } else { DistStack[StInd++] = listend->vtx-labelorg; CurrVertices[listend->vtx-labelorg] = 1; } listend = listend->next; } } if (vswitch) fprintf(stderr, ", 2"); cell = 0; for (i=0; i MaxV) { fprintf(stderr, ">E Too many vertices (%d, max: %d; use -V# (at your own risk))\n", n_count, MaxV); too_big = TRUE; } if (e_count > MaxE) { fprintf(stderr, ">E Too many edges (%lu, max: %d; use -E# (at your own risk))\n", e_count, MaxE); too_big = TRUE; } if (too_big) { exit(1); } if (vswitch) fprintf(stderr, ", 4"); if (Sswitch) { if (gswitch) { hsize *= log10(n); vsize *= log10(n); } else { if (StIndDist) { hsize *= log10(StIndDist); vsize *= log10(StIndDist); } } } if (vswitch) fprintf(stderr, ".\n"); if (vswitch) fprintf(stderr, ">Z creating colors..."); CreateRandColors(n); if (vswitch) fprintf(stderr, "done\n"); if (vswitch) fprintf(stderr, ">Z drawing size %.2f x %.2f\n", hsize, vsize); /* Preamble */ fprintf(outfile, "graph [center=\"true\", size=\"%.2f, %.2f\", ratio=\"fill\", ranksep=\"0.25\", nodesep=\"0.40\",\n", hsize, vsize); fprintf(outfile, " outputorder=\"edgesfirst\", overlap=\"scale\", layout=\"%s\"];\n",model); fprintf(outfile, "node [shape=\"circle\", width=\"%.2f\", height=\"%.2f\", fixedsize=\"true\",\n", 0.5*nodescale, 0.5*nodescale); fprintf(outfile, " style=\"filled\", color=\"black\",\n"); fprintf(outfile, " fontsize=\"13\", fontname=\"%s\"];\n", FONT_NAME); /* Nodes */ if (vswitch) fprintf(stderr, ">Z drawing vertices..."); fprintf(outfile, "node [color=\"black\", fontcolor=\"black\"]\n"); a = 1; if (dswitch) end = StIndDist; else end = StInd; make_ranks = ((modcode == 0) || (modcode > 5)) && rswitch1; if (make_ranks) fprintf(outfile, "{ rank=\"source\";\n"); for (i=0; iZ drawing edges..."); if (gswitch) { fprintf(outfile, "edge [penwidth=\"0.4\", color=\"gray\", weight=\"10\"];\n"); for (vtx = 0; vtx < n; vtx++) { for (j1 = g.v[vtx]; j1 < g.v[vtx] + g.d[vtx]; ++j1) { if (CurrVertices[vtx] != 1 || CurrVertices[g.e[j1]] != 1) { if (g.e[j1] > vtx) fprintf(outfile, "%d -- %d;\n", vtx + labelorg, g.e[j1] + labelorg); } } } } fprintf(outfile, "edge [penwidth=\"0.8\", color=\"black\", weight=\"10\"];\n"); for (i = 0; i < StIndDist; ++i) { vtx = DistStack[i]; for (j1 = g.v[vtx]; j1 < g.v[vtx] + g.d[vtx]; ++j1) { if (CurrVertices[g.e[j1]] == 1) { if (g.e[j1] > vtx) fprintf(outfile, "%d -- %d;\n", vtx + labelorg, g.e[j1] + labelorg); } } } if (gswitch) { RnkIndDist = RnkInd; } if (RnkIndDist>1) { fprintf(outfile, "%d ", DistStack[0] + labelorg); for (i=1; iZ " COUNTER_FMT " graph drawn from %s to %s\n", nin, infilename, outfilename); exit(0); }