/* showg.c version 2.1; B D McKay, August 2017. Formerly called readg.c. This is a stand-alone edition of listg.c that does not need nauty or any other files. Use listg in preference
if you have installed it. */
#define HELPTEXT \ " Write graphs in human-readable format.\n\
\n\
infile is the input file in graph6, sparse6 or digraph6 format\n\ This program does not support incremental sparse6 files; use listg.\n\
outfile is the output file\n\
Defaults are standard input and standard output.\n\
\n\
-p#, -p#:#, -p#-# : only display one graph or a sequence of\n\
graphs. The first graph is number 1. A second number\n\
which is empty or zero means infinity.\n\
\n\
-a : write the adjacency matrix\n\
-A : same as -a with a space between entries\n\
-d : write output to satisfy dreadnaut\n\
-c : write compact dreadnaut form with minimal line-breaks\n\
-e : write a list of edges, preceded by the order and the\n\
number of edges\n\
\n\
-o# : specify number of first vertex (default is 0)\n\
-t : write upper triangle only (affects -a, -A, -d anddefault)\n\
-F : write a form-feed after each graph except the last\n\
-l# : specify screen width limit (default 78, 0 means no limit)\n\ This is not currently implemented with -a or -A.\n\
-q : suppress auxiliary output\n\
\n\
-a, -A, -c, -d and -e are incompatible.\n"
/* Version 1.1: Fixed sparse6 input for powers of 2. May 9, 1998. Version 1.3: Declared errno according to ISO C. August 22, 1998. Version 1.4: Change name of getline() so that broken compilers which define the GNU function without being asked don't cause a conflict. June 16, 2006. Version 1.5: Use function prototypes. Avoid errno. Sep 19, 2007. Version 1.6: Very minor tweaks. Hope you all have string.h. Sep 6, 2009. Version 1.7: Make it work for n=0. Sep 18, 2013. Version 2.0: Support digraph6 format. Version 2.1: Fix digraph6 format and remove limit of 200K or so vertices.
*/
#define SIZELEN(n) ((n)<=SMALLN?1:((n)<=SMALLISHN?4:8)) /* length of size code in bytes */ #define G6BODYLEN(n) \
(((size_t)(n)/12)*((size_t)(n)-1) + (((size_t)(n)%12)*((size_t)(n)-1)+11)/12) #define G6LEN(n) (SIZELEN(n) + G6BODYLEN(n)) /* exact graph6 string length excluding \n\0 This twisted expression works up to n=227023 in 32-bit arithmetic
and for larger n if size_t has 64 bits. */ #define D6BODYLEN(n) \
((n)*(size_t)((n)/6) + (((n)*(size_t)((n)%6)+5)/6)) #define D6LEN(n) (1 + SIZELEN(n) + D6BODYLEN(n)) /* exact digraph6 string length excluding \n\0 This twisted expression works up to n=160529 in 32-bit arithmetic
and for larger n if size_t has 64 bits. */
staticvoid
gt_abort(char *msg) /* Write message and halt. */
{ if (msg) fprintf(stderr,"%s",msg); exit(1);
}
/***************************************************************************** * * * itos(i,s) converts the int i to a nul-terminated decimal character * * string s. The value returned is the number of characters excluding * * the nul. * * * * GLOBALS ACCESSED: NONE * * *
*****************************************************************************/
staticint
itos(int i, char *s)
{ int digit,j,k; char c; int ans;
if (i < 0)
{
k = 0;
i = -i;
j = 1;
s[0] = '-';
} else
{
k = -1;
j = 0;
}
do
{
digit = i % 10;
i = i / 10;
s[++k] = digit + '0';
} while (i);
s[k+1] = '\0';
ans = k + 1;
for (;j < k; ++j, --k)
{
c = s[j];
s[j] = s[k];
s[k] = c;
}
return(ans);
}
/***************************************************************************** * * * nextelement(set1,m,pos) = the position of the first element in set set1 * * which occupies a position greater than pos. If no such element exists, * * the value is -1. pos can have any value less than n, including negative * * values. * * * * GLOBALS ACCESSED: none * * *
*****************************************************************************/
staticint
nextelement(set *set1, int m, int pos)
{
setword setwd; int w;
if (pos < 0)
{
w = 0;
setwd = set1[0];
} else
{
w = SETWD(pos);
setwd = set1[w] & BITMASK(SETBT(pos));
}
for (;;)
{ if (setwd != 0) return(TIMESWORDSIZE(w) + FIRSTBIT(setwd)); if (++w == m) return -1;
setwd = set1[w];
}
}
/********************************************************************* opengraphfile(filename,codetype,assumefixed,position) opens and positions a file for reading graphs.
filename = the name of the file to open (NULL means stdin, assumed already open) codetype = returns a code for the format. This is a combination of SPARSE6, GRAPH6, UNKNOWN_TYPE and HAS_HEADER. If a header is present, that overrides the data. If there is no header, the first graph is examined. assumefixed = nonzero if files other than stdin should be assumed to be seekable and have equal record sizes. Ignored if there is a sparse6 header or the first graph has sparse6 format. position = the number of the record to position to (the first is number 1; 0 and -NOLIMIT also mean to position at start)
If the file starts with ">", there must be a header, either GRAPH6_HEADER, SPARSE6_HEADER or DIGRAPH6_HEADER. Otherwise opengraphfile() fails.
The value returned is a file pointer or NULL. If assumedfixed is not zero and position > 1, the global variable ogf_linelen is set to the length (including \n) of the length of the first record.
static FILE*
opengraphfile(char *filename, int *codetype, int assumefixed, long position)
{
FILE *f; int c,firstc; long i,l,pos,pos1,pos2;
boolean bad_header;
if (filename == NULL)
f = stdin; else
{
f = fopen(filename,"r"); if (f == NULL)
{
fprintf(stderr,">E opengraphfile: can't open %s\n",filename); return NULL;
}
}
firstc = c = getc(f); if (c == EOF)
{
*codetype = GRAPH6; return f;
}
if (c != '>')
{
*codetype = firstc == ':' ? SPARSE6 : firstc == '&' ? DIGRAPH6 : GRAPH6;
ungetc(c,f);
} else
{
bad_header = FALSE; if ((c = getc(f)) == EOF || c != '>')
bad_header = TRUE; if (!bad_header &&
((c = getc(f)) == EOF || (c != 'g' && c != 's')))
bad_header = TRUE; if (!bad_header && c == 'g')
{ if ((c = getc(f)) == EOF || c != 'r' ||
(c = getc(f)) == EOF || c != 'a' ||
(c = getc(f)) == EOF || c != 'p' ||
(c = getc(f)) == EOF || c != 'h' ||
(c = getc(f)) == EOF || c != '6' ||
(c = getc(f)) == EOF || c != '<' ||
(c = getc(f)) == EOF || c != '<')
bad_header = TRUE; else
*codetype = GRAPH6 | HAS_HEADER;
} elseif (!bad_header && c == 'd')
{ if ((c = getc(f)) == EOF || c != 'i' ||
(c = getc(f)) == EOF || c != 'g' ||
(c = getc(f)) == EOF || c != 'r' ||
(c = getc(f)) == EOF || c != 'a' ||
(c = getc(f)) == EOF || c != 'p' ||
(c = getc(f)) == EOF || c != 'h' ||
(c = getc(f)) == EOF || c != '6' ||
(c = getc(f)) == EOF || c != '<' ||
(c = getc(f)) == EOF || c != '<')
bad_header = TRUE; else
*codetype = DIGRAPH6 | HAS_HEADER;
} elseif (!bad_header && c == 's')
{ if ((c = getc(f)) == EOF || c != 'p' ||
(c = getc(f)) == EOF || c != 'a' ||
(c = getc(f)) == EOF || c != 'r' ||
(c = getc(f)) == EOF || c != 's' ||
(c = getc(f)) == EOF || c != 'e' ||
(c = getc(f)) == EOF || c != '6' ||
(c = getc(f)) == EOF || c != '<' ||
(c = getc(f)) == EOF || c != '<')
bad_header = TRUE; else
*codetype = SPARSE6 | HAS_HEADER;
} if (bad_header)
{
fprintf(stderr,">E opengraphfile: illegal header in %s\n",
filename == NULL ? "stdin" : filename);
*codetype = UNKNOWN_TYPE | HAS_HEADER; return NULL;
}
}
if (position <= 1) return f;
if (filename == NULL || !assumefixed || (*codetype&SPARSE6)
|| firstc == ':')
{
l = 1; while ((c = getc(f)) != EOF)
{ if (c == '\n')
{
++l; if (l == position) break;
}
} if (l == position) return f;
fprintf(stderr, ">E opengraphfile: can't find line %ld in %s\n",position,
filename == NULL ? "stdin" : filename); return NULL;
} else
{
pos1 = ftell(f); if (pos1 < 0)
{
fprintf(stderr,">E opengraphfile: error on first ftell\n"); return NULL;
}
for (i = 1; (c = getc(f)) != EOF && c != '\n'; ++i) {}
ogf_linelen = i;
if (c == EOF)
{
fprintf(stderr, ">E opengraphfile: required record no present\n"); return NULL;
}
pos2 = ftell(f); if (pos2 < 0)
{
fprintf(stderr,">E opengraphfile: error on second ftell\n"); return NULL;
}
staticchar*
showg_getline(FILE *f) /* read a line with error checking */ /* includes \n (if present) and \0.
Immediate EOF causes NULL return. */
{
DYNALLSTAT(char,s,s_sz); int c; long i;
DYNALLOC1(char,s,s_sz,500,"showg_getline");
i = 0; while ((c = getc(f)) != EOF && c != '\n')
{ if (i == s_sz-2) DYNREALLOC(char,s,s_sz,s_sz+1000,"showg_getline");
s[i++] = c;
}
staticvoid
stringtograph(char *s, graph *g, int m) /* Convert string (graph6, digraph6 or sparse6 format) to graph. */ /* Assumes g is big enough to hold it. */
{ char *p; int n,i,j,k,v,x,nb,need;
size_t ii;
set *gi,*gj;
boolean done;
n = graphsize(s); if (n == 0) return;
p = s + (s[0] == ':' || s[0] == '&') + SIZELEN(n);
if (TIMESWORDSIZE(m) < n)
gt_abort(">E stringtograph: impossible m value\n");
if (s[0] != ':' && s[0] != '&') /* graph6 format */
{
k = 1; for (j = 1; j < n; ++j)
{
gj = GRAPHROW(g,j,m);
for (i = 0; i < j; ++i)
{ if (--k == 0)
{
k = 6;
x = *(p++) - BIAS6;
}
if ((x & TOPBIT6))
{
gi = GRAPHROW(g,i,m);
ADDELEMENT(gi,j);
ADDELEMENT(gj,i);
}
x <<= 1;
}
}
} elseif (s[0] == '&')
{
k = 1; for (i = 0; i < n; ++i)
{
gi = GRAPHROW(g,i,m);
for (j = 0; j < n; ++j)
{ if (--k == 0)
{
k = 6;
x = *(p++) - BIAS6;
}
if ((x & TOPBIT6))
{
ADDELEMENT(gi,j);
}
x <<= 1;
}
}
} else/* sparse6 format */
{ for (i = n-1, nb = 0; i != 0 ; i >>= 1, ++nb) {}
k = 0;
v = 0;
done = FALSE; while (!done)
{ if (k == 0)
{
x = *(p++); if (x == '\n' || x == '\0')
{
done = TRUE; continue;
} else
{
x -= BIAS6; k = 6;
}
} if ((x & B(k))) ++v;
--k;
need = nb;
j = 0; while (need > 0 && !done)
{ if (k == 0)
{
x = *(p++); if (x == '\n' || x == '\0')
{
done = TRUE; continue;
} else
{
x -= BIAS6; k = 6;
}
} if (need >= k)
{
j = (j << k) | (x & M(k));
need -= k; k = 0;
} else
{
k -= need;
j = (j << need) | ((x >> k) & M(need));
need = 0;
}
} if (done) continue;
if (j > v)
v = j; elseif (v < n)
{
ADDELEMENT(GRAPHROW(g,v,m),j);
ADDELEMENT(GRAPHROW(g,j,m),v);
}
}
}
}
graph* /* read graph into nauty format */
readgg(FILE *f, graph *g, int reqm, int *pm, int *pn, boolean *digraph) /* graph6, digraph6 and sparse6 formats are supported f = an open file g = place to put the answer (NULL for dynamic allocation) reqm = the requested value of m (0 => compute from n) *pm = the actual value of m *pn = the value of n *digraph = whether the input is a digraph
*/
{ char *s,*p; int m,n; int readg_code;
if ((s = showg_getline(f)) == NULL) return NULL;
if (s[0] == ':')
{
*digraph = FALSE;
p = s + 1;
} elseif (s[0] == '&')
{
readg_code = DIGRAPH6;
*digraph = TRUE;
p = s + 1;
} else
{
readg_code = GRAPH6;
*digraph = FALSE;
p = s;
}
n = graphsize(s); if (readg_code == GRAPH6 && p - s != G6LEN(n))
gt_abort(">E readgg: truncated graph6 line\n"); if (readg_code == DIGRAPH6 && p - s != D6LEN(n))
gt_abort(">E readgg: truncated digraph6 line\n");
if (reqm > 0 && TIMESWORDSIZE(reqm) < n)
gt_abort(">E readgg: reqm too small\n"); elseif (reqm > 0)
m = reqm; else
m = (n + WORDSIZE - 1) / WORDSIZE;
if (g == NULL)
{ if ((g = (graph*)ALLOCS(n,m*sizeof(graph))) == NULL)
gt_abort(">E readgg: malloc failed\n");
}
#define LABELORG 0 /* number of first vertex (any integer >= 0) */ #define LINELEN 78 /* max characters per line (0 = no limit) */
static FILE *infile,*outfile; staticlong nin;
/***************************************************************************** * * * putsetx(f,set1,curlenp,linelength,m,compress,start) writes the set * * set1 to file f using at most linelength characters per line (excluding * * '\n'). Set elements less than or equal to start are ignored. * * *curlenp is the number of characters on the line so far; it is updated. * * A range j1,j1+1,...,j2 for j2-j1>=2 is written as "j1:j2" if compress * * is nonzero (eg. TRUE); otherwise each element is written separately. * * No final '\n' is written. labelorg is used. * * * * FUNCTIONS CALLED: nextelement(),itos() * * *
*****************************************************************************/
staticvoid
putsetx(FILE *f, set *set1, int *curlenp, int linelength, int m,
boolean compress, int start)
{ int slen,j1,j2; char s[40];
boolean first;
first = TRUE;
j1 = start; while ((j1 = nextelement(set1,m,j1)) >= 0)
{
j2 = j1; if (compress)
{ while (nextelement(set1,m,j2) == j2 + 1)
++j2; if (j2 == j1+1)
j2 = j1;
}
slen = itos(j1 + labelorg,s); if (j2 >= j1 + 2)
{
s[slen] = ':';
slen += 1 + itos(j2 + labelorg,&s[slen+1]);
}
/***************************************************************************** * * * STOLEN FROM naututil.c * * putgraphx(f,g,linelength,m,n) writes a list of the edges of g to f * * using at most linelength characters per line (excluding '\n'). * * If triang, only write the upper triangle. * * labelorg is used. * * *
*****************************************************************************/
staticvoid
putgraphx(FILE *f, graph *g, int linelength, boolean triang, int m, int n)
{ int i,curlen;
set *pg;
for (i = 0, pg = g; i < n; ++i, pg += m)
{
fprintf(f,"%3d : ",i + labelorg);
curlen = 7;
putsetx(f,pg,&curlen,linelength,m,FALSE,triang ? i-1 : -1);
fprintf(f,";\n");
}
}
staticvoid
putedges(FILE *f, graph *g, int linelength,
boolean digraph, int m, int n) /* Write list of edges, preceded by the numbers of vertices and
edges. Use labelorg */
{ int i,j,curlen,ne; char s[20];
set *pg;
ne = 0; for (i = 0, pg = g; i < n; ++i, pg += m)
{ for (j = (digraph?-1:i-1); (j = nextelement(pg,m,j)) >= 0;)
++ne;
}
staticvoid
putcgraph(FILE *f, graph *g, int linelength, boolean digraph, int m, int n) /* write compressed form, using labelorg */
{ int i,curlen,j0; int semicolons; char s[20];
set *pg;
staticvoid
putam(FILE *f, graph *g, int linelength, boolean space, boolean triang, int m, int n) /* write adjacency matrix */
{
set *gi; int i,j;
boolean first;
for (i = 0, gi = (set*)g; i < n - (triang!=0); ++i, gi += m)
{
first = TRUE; for (j = triang ? i+1 : 0; j < n; ++j)
{ if (!first && space) putc(' ',f); else first = FALSE; if (ISELEMENT(gi,j)) putc('1',f); else putc('0',f);
}
putc('\n',f);
}
}
if (sizeof(setword) < 4)
{
fprintf(stderr,">E showg: setword too small\n");
fprintf(stderr," Please report this to brendan.mckay@anu.edu.au\n"); exit(1);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.