1 /*****************************************************************************
2 *                                                                            *
3 * This is the main file for dreadnaut() version 2.2, which is a test-bed     *
4 *   for nauty() version 2.2.                                                 *
5 *                                                                            *
6 * ACTUALLY IT ISN'T.  This is a modified edition of dreadnaut that performs  *
7 * tests of conformity.  Instead of reporting the results of computations to  *
8 * the human, it compares them to values stored in the input and reports any  *
9 * differences.                                                               *
10 * It is assumed that "long int" has at least 32 bits.                        *
11 * In the following, # is a hex value (without 0x) that is compared to a      *
12 * hash certificate of the specified value.  An error message is given if     *
13 * they don't match exactly.                                                  *
14 * The following no longer have their old meanings:                           *
15 *    a #   - compare the generators                                          *
16 *    b #   - compare the canonical labelling and the labelled graph          *
17 *    o #   - compare the orbits                                              *
18 *    & #   - compare the partition                                           *
19 *    S #   - compare the statistics                                          *
20 *    C     - run tests on bits, sets, etc.                                   *
21 *                                                                            *
22 *   Copyright (1984-2002) Brendan McKay.  All rights reserved.               *
23 *   Subject to the waivers and disclaimers in nauty.h.                       *
24 *                                                                            *
25 *   CHANGE HISTORY                                                           *
26 *        1-Sep-02 - Initial write starting at dreadnaut.c                    *
27 *       17-Nov-03 - Change INFINITY to NAUTY_INFINITY                        *
28 *                                                                            *
29 *****************************************************************************/
30 
31 #include "naututil.h"    /* which includes nauty.h, which includes stdio.h */
32 #include "nautinv.h"    /* which includes nauty.h, which includes stdio.h */
33 
34 #define PM(x) ((x) ? '+' : '-')
35 #define SS(n,sing,plur)  (n),((n)==1?(sing):(plur))
36 #define WORKSIZE 60
37 
38 #define INFILE fileptr[curfile]
39 #define OUTFILE outfile
40 
41 #if !MAXN
42 DYNALLSTAT(graph,g,g_sz);
43 DYNALLSTAT(graph,canong,canong_sz);
44 DYNALLSTAT(graph,savedg,savedg_sz);
45 DYNALLSTAT(setword,workspace,workspace_sz);
46 DYNALLSTAT(int,lab,lab_sz);
47 DYNALLSTAT(int,ptn,ptn_sz);
48 DYNALLSTAT(int,orbits,orbits_sz);
49 DYNALLSTAT(int,savedlab,savedlab_sz);
50 DYNALLSTAT(permutation,perm,perm_sz);
51 DYNALLSTAT(set,active,active_sz);
52 #else
53 static graph g[MAXM*1L*MAXN];
54 static graph canong[MAXM*1L*MAXN];
55 static graph savedg[MAXM*1L*MAXN];
56 static setword workspace[MAXM*2L*WORKSIZE];
57 static int lab[MAXN];
58 static int ptn[MAXN];
59 static int orbits[MAXN];
60 static int savedlab[MAXN];
61 static permutation perm[MAXN];
62 static set active[MAXM];
63 #endif
64 
65 static DEFAULTOPTIONS_GRAPH(options);
66 static statsblk stats;
67 static int curfile;
68 static FILE *fileptr[MAXIFILES];
69 static FILE *outfile;
70 static char def_ext[] = DEFEXT;
71 static boolean firstpath;       /* used in usernode() */
72 
73 #define U_NODE  1               /* masks for u values */
74 #define U_AUTOM 2
75 #define U_LEVEL 4
76 #define U_TCELL 8
77 #define U_REF  16
78 
79 #ifndef  NODEPROC
80 #define NODEPROC usernode
81 #else
82 extern void NODEPROC(graph*,int*,int*,int,int,int,int,int,int);
83 #endif
84 
85 #ifndef  AUTOMPROC
86 #define AUTOMPROC userautom
87 #else
88 extern void AUTOMPROC(int,permutation*,int*,int,int,int);
89 #endif
90 
91 #ifndef  LEVELPROC
92 #define LEVELPROC userlevel
93 #else
94 extern void LEVELPROC(int*,int*,int,int*,statsblk*,int,int,int,int,int,int);
95 #endif
96 
97 #ifndef  TCELLPROC
98 #define TCELLPROC NULL
99 #else
100 extern void TCELLPROC(graph*,int*,int*,int,int,set*,int*,int*,int,int,
101               int(*)(graph*,int*,int*,int,int,int,int),int,int);
102 #endif
103 
104 #ifndef  REFPROC
105 #define REFPROC NULL
106 #else
107 extern void REFPROC(graph*,int*,int*,int,int*,permutation*,set*,int*,int,int);
108 #endif
109 
110 #ifndef  INVARPROC
111 #define INVARPROC NULL
112 #define INVARPROCNAME "none"
113 #else
114 extern void INVARPROC(graph*,int*,int*,int,int,int,permutation*,
115                       int,boolean,int,int);
116 #define INVARPROCNAME "user-defined"
117 #endif
118 
119 
120 static struct invarrec
121 {
122     void (*entrypoint)(graph*,int*,int*,int,int,int,permutation*,
123                       int,boolean,int,int);
124     char *name;
125 } invarproc[]
126     = {INVARPROC, INVARPROCNAME,
127        NULL, "none",
128        twopaths,    "twopaths",
129        adjtriang,   "adjtriang",
130        triples,     "triples",
131        quadruples,  "quadruples",
132        celltrips,   "celltrips",
133        cellquads,   "cellquads",
134        cellquins,   "cellquins",
135        distances,   "distances",
136        indsets,     "indsets",
137        cliques,     "cliques",
138        cellcliq,    "cellcliq",
139        cellind,     "cellind",
140        adjacencies, "adjacencies",
141        cellfano,    "cellfano",
142        cellfano2,   "cellfano2"};
143 #define NUMINVARS ((int)(sizeof(invarproc)/sizeof(struct invarrec)))
144 
145 #ifdef  NLMAP
146 #define GETNW(c,f) do c = getc(f); while (c==' '||c=='\t')
147 #define GETNWC(c,f) do c = getc(f); while (c==' '||c==','||c=='\t')
148 #define GETNWL(c,f) do c = getc(f); while (c==' '||c=='\n'||c=='\t')
149 #else
150 #define GETNW(c,f) do c = getc(f); while (c==' '||c=='\t'||c=='\r')
151 #define GETNWC(c,f) do c = getc(f); while (c==' '||c==','||c=='\t'||c=='\r')
152 #define GETNWL(c,f) do c = getc(f); while (c==' '||c=='\n'||c=='\t'||c=='\r')
153 #endif
154 
155 static void help(FILE*, int);
156 static void userautom(int,permutation*,int*,int,int,int);
157 static void usernode(graph*,int*,int*,int,int,int,int,int,int);
158 static void userlevel(int*,int*,int,int*,statsblk*,int,int,int,int,int,int);
159 
160 
161 #ifdef  EXTRADECLS
162 EXTRADECLS
163 #endif
164 
165 static long afound;
166 
167 /*****************************************************************************
168 *                                                                            *
169 *  gethex(f) reads a long hex integer from f, optionally preceded by '='     *
170 *  and white space.  -1 is returned if the attempt was unsuccessful.         *
171 *  Not much error checking.                                                  *
172 *                                                                            *
173 *****************************************************************************/
174 
175 static long
gethex(FILE * f)176 gethex(FILE *f)
177 {
178         int c;
179 	long i;
180 
181         GETNWL(c,f);
182         if (c != '=') ungetc((char)c,f);
183 
184         if (fscanf(f,"%lx",&i) == 1) return i;
185         else                         return -1;
186 }
187 
188 /*****************************************************************************
189 *                                                                            *
190 *  permhash(s,n,seed,key) is a function whose value depends only on the      *
191 *  permutation s, a long seed, and an integer key.  It is intended to be     *
192 *  independent of the machine and whether permutation has 16 or 32 bits.     *
193 *  n is the length.                                                          *
194 *  28 bits of seed and 15 bits of key are significant.                       *
195 *  The result is in the low 28 bits.                                         *
196 *                                                                            *
197 *****************************************************************************/
198 
199 static long
permhash(permutation * s,int n,long seed,int key)200 permhash(permutation *s, int n, long seed, int key)
201 {
202         int i,j,lsh,rsh;
203         long l,res,salt,lshmask;
204         long si;
205 
206         lsh = key & 0xF;
207         rsh = 28 - lsh;
208         salt = (key >> 4) & 0x7FFL;
209         res = seed & 0xFFFFFFFL;
210         lshmask = (1L << lsh) - 1;
211 
212         j = 0;
213         for (i = 0; i < n; ++i)
214         {
215             si = s[i];
216             l = si & 0xFFFFL;
217             res = (((res << lsh) ^ ((res >> rsh) & lshmask) ^ l) + salt)
218                                                                 & 0xFFFFFFFL;
219             l = si >> 16;
220             res = (((res << lsh) ^ ((res >> rsh) & lshmask) ^ l) + salt)
221                                                                 & 0xFFFFFFFL;
222 	}
223 
224 	return res;
225 }
226 
227 /*****************************************************************************
228 *                                                                            *
229 *  inthash(s,n,seed,key) is a function whose value depends only on the       *
230 *  int array p, a long seed, and an integer key.  It is intended to be       *
231 *  independent of the machine and whether int has 16 or 32 bits.             *
232 *  64 bits is also ok provided the values are not above 2^31-1.              *
233 *  n is the length.                                                          *
234 *  28 bits of seed and 15 bits of key are significant.                       *
235 *  The result is in the low 28 bits.                                         *
236 *                                                                            *
237 *****************************************************************************/
238 
239 static long
inthash(int * s,int n,long seed,int key)240 inthash(int *s, int n, long seed, int key)
241 {
242         int i,j,lsh,rsh;
243         long l,res,salt,lshmask;
244         long si;
245 
246         lsh = key & 0xF;
247         rsh = 28 - lsh;
248         salt = (key >> 4) & 0x7FFL;
249         res = seed & 0xFFFFFFFL;
250         lshmask = (1L << lsh) - 1;
251 
252         j = 0;
253         for (i = 0; i < n; ++i)
254         {
255             si = s[i];
256             l = si & 0xFFFFL;
257             res = (((res << lsh) ^ ((res >> rsh) & lshmask) ^ l) + salt)
258                                                                 & 0xFFFFFFFL;
259             l = si >> 16;
260             res = (((res << lsh) ^ ((res >> rsh) & lshmask) ^ l) + salt)
261                                                                 & 0xFFFFFFFL;
262         }
263 
264         return res;
265 }
266 
267 /*****************************************************************************
268 * bit_tests()   Run some configuration tests                                 *
269 *****************************************************************************/
270 
271 static int
bit_tests(void)272 bit_tests(void)
273 {
274 	int i,j,bad;
275 	setword w;
276 
277 	printf("NAUTYVERSION=%s NAUTYVERSIONID=%d NAUTYREQUIRED=%d\n",
278 		NAUTYVERSION,NAUTYVERSIONID,NAUTYREQUIRED);
279 	printf("MAXN=%d MAXM=%d WORDSIZE=%d NAUTY_INFINITY=%d",
280 		MAXN,MAXM,WORDSIZE,NAUTY_INFINITY);
281 #ifdef BIGNAUTY
282 	printf(" BIGNAUTY");
283 #endif
284 #ifdef SYS_UNIX
285 	printf(" SYS_UNIX");
286 #endif
287 #ifdef SYS_CRAY
288         printf(" SYS_CRAY");
289 #endif
290 
291 	printf("\n");
292 
293 
294 	bad = 0;
295 
296 	if (SIZEOF_INT != sizeof(int))
297 	{
298 	    printf(" ***** NOTE: sizeof problem (int) *****\n");
299 	    ++bad;
300 	}
301 	if (SIZEOF_LONG != sizeof(long))
302 	{
303 	    printf(" ***** NOTE: sizeof problem (long) *****\n");
304 	    ++bad;
305 	}
306 #if SIZEOF_LONGLONG > 0
307 	if (SIZEOF_LONGLONG != sizeof(long long))
308 	{
309 	    printf(" ***** NOTE: sizeof problem (long long) *****\n");
310 	    ++bad;
311 	}
312 #endif
313 
314 	if (8*sizeof(setword) < WORDSIZE)
315 	{
316 	    printf("\n ***** NOTE:  WORDSIZE mismatch *****\n");
317 	    ++bad;
318 	}
319 	if (8*sizeof(setword) > WORDSIZE)
320 	{
321 	    printf("\n WORDSIZE < 8*sizeof(setword)  [This is legal.]\n");
322 	}
323 
324 	for (i = 0; i < WORDSIZE; ++i)
325 	{
326 	    w = ALLMASK(i);
327 	    if (POPCOUNT(w) != i)
328 	    {
329 		printf("\n ***** POPCOUNT(ALLMASK) error %d *****\n\n",i);
330 		++bad;
331 	    }
332 	}
333 
334 	for (i = 0; i < WORDSIZE; ++i)
335         {
336             w = BITMASK(i);
337             if (POPCOUNT(w) != WORDSIZE-i-1)
338             {
339                 printf("\n ***** POPCOUNT(BITMASK) error %d *****\n\n",i);
340                 ++bad;
341             }
342         }
343 
344 	for (i = 0; i < WORDSIZE; ++i)
345 	    if (POPCOUNT(ALLMASK(i)) != i)
346 	    {
347 		printf("\n ***** POPCOUNT(ALLMASK) error %d *****\n\n",i);
348 		++bad;
349 	    }
350 
351 	for (i = 0; i < WORDSIZE; ++i)
352             if (FIRSTBIT(BITT[i]) != i)
353 	    {
354 		printf("\n ***** FIRSTBIT(BITT) error %d *****\n\n",i);
355 		++bad;
356 	    }
357 
358 	w = ALLBITS;
359 	for (i = 0; i < WORDSIZE; ++i)
360 	{
361 	    TAKEBIT(j,w);
362 	    if (j != i)
363             {
364                 printf("\n ***** TAKEBIT error %d *****\n\n",i);
365                 ++bad;
366             }
367 	}
368 
369 	for (i = 0; i < WORDSIZE; ++i)
370             if (POPCOUNT(BITT[i]) != 1)
371 	    {
372                 printf("\n ***** POPCOUNT(BITT) error %d *****\n\n",i);
373 		++bad;
374 	    }
375 
376 	for (i = 0; i < WORDSIZE; ++i)
377 	{
378 	    w = 0;
379 	    for (j = 1; j <= WORDSIZE; ++j)
380 	    {
381 		w |= BITT[(j*97+i)%WORDSIZE];
382 		if (POPCOUNT(w) != j)
383 		{
384 		    printf("\n ***** POPCOUNT(w) error %d %d *****\n\n",i,j);
385 		    ++bad;
386 		}
387 	    }
388 	}
389 
390 	if (bad) printf("\nXXXXXXX %d errors found XXXXXXX\n",bad);
391 
392 	return bad;
393 }
394 
395 /*****************************************************************************
396 *                                                                            *
397 *  This is a program which illustrates the use of nauty.                     *
398 *  Commands are read from stdin, and may be separated by white space,        *
399 *  commas or not separated.  Output is written to stdout.                    *
400 *  For a short description, see the nauty User's Guide.                      *
401 *                                                                            *
402 *****************************************************************************/
403 
404 int
main(int argc,char * argv[])405 main(int argc, char *argv[])
406 {
407         int m,n,newm,newn;
408         boolean gvalid,ovalid,cvalid,pvalid,minus,prompt,doquot;
409         int i,worksize,numcells,refcode,umask,qinvar;
410         int oldorg;
411         char *s1,*s2,*invarprocname;
412         int c,d;
413         register long li;
414         set *gp;
415         double timebefore,timeafter;
416         char filename[200];
417         int sgn,sgorg,nperm;
418 	int bad,multiplicity;
419 	boolean options_writeautoms,options_writemarkers;
420 	long zseed;
421 	long need,found;
422 
423         curfile = 0;
424         fileptr[curfile] = stdin;
425         prompt = FALSE;
426         outfile = stdout;
427 	options_writeautoms = options_writemarkers = TRUE;
428         n = m = 1;
429         worksize = 2*WORKSIZE;
430 
431 #if !MAXN
432 	n = WORDSIZE;
433         DYNALLOC2(graph,g,g_sz,n,m,"dreadnaut");
434         DYNALLOC1(int,lab,lab_sz,n,"dreadnaut");
435         DYNALLOC1(int,ptn,ptn_sz,n,"dreadnaut");
436         DYNALLOC1(setword,workspace,workspace_sz,
437                                             worksize,"dreadnaut");
438         DYNALLOC1(int,orbits,orbits_sz,n,"dreadnaut");
439         DYNALLOC1(permutation,perm,perm_sz,n,"dreadnaut");
440         DYNALLOC1(set,active,active_sz,m,"dreadnaut");
441 	n = 1;
442 #endif
443 
444 	ran_init(37);
445 
446 	bad = 0;
447 
448         umask = 0;
449         pvalid = FALSE;
450         gvalid = FALSE;
451         ovalid = FALSE;
452         cvalid = FALSE;
453         minus = FALSE;
454         labelorg = oldorg = 0;
455         multiplicity = 1;
456 	options.userautomproc = userautom;
457 
458 #ifdef  INITIALIZE
459         INITIALIZE;
460 #endif
461 
462         invarprocname = "none";
463         if (prompt)
464         {
465 #ifdef BIGNAUTY
466             fprintf(PROMPTFILE,"Dreadnaut version %s [BIG].\n",NAUTYVERSION);
467 #else
468             fprintf(PROMPTFILE,"Dreadnaut version %s.\n",NAUTYVERSION);
469 #endif
470             fprintf(PROMPTFILE,"> ");
471         }
472 
473         nauty_check(WORDSIZE,1,1,NAUTYVERSIONID);
474         nautinv_check(WORDSIZE,1,1,NAUTYVERSIONID);
475         nautil_check(WORDSIZE,1,1,NAUTYVERSIONID);
476         naututil_check(WORDSIZE,1,1,NAUTYVERSIONID);
477         naugraph_check(WORDSIZE,1,1,NAUTYVERSIONID);
478 
479         while (curfile >= 0)
480             if ((c = getc(INFILE)) == EOF || c == '\004')
481             {
482                 fclose(INFILE);
483                 --curfile;
484                 if (curfile >= 0)
485                     prompt = FALSE;
486             }
487             else switch (c)
488             {
489             case '\n':  /* possibly issue prompt */
490                 if (prompt)
491                     fprintf(PROMPTFILE,"> ");
492                 minus = FALSE;
493                 break;
494 
495             case ' ':   /* do nothing */
496             case '\t':
497 #ifndef  NLMAP
498             case '\r':
499 #endif
500             case '\f':
501                 break;
502 
503             case '-':   /* remember this for next time */
504                 minus = TRUE;
505                 break;
506 
507             case '+':   /* forget - */
508             case ',':
509             case ';':
510                 minus = FALSE;
511                 break;
512 
513             case '<':   /* new input file */
514                 minus = FALSE;
515                 if (curfile == MAXIFILES - 1)
516                     fprintf(ERRFILE,"exceeded maximum input nesting of %d\n\n",
517                             MAXIFILES);
518                 if (!readstring(INFILE,filename,200))
519                 {
520                     fprintf(ERRFILE,
521                             "missing file name on '>' command : ignored\n\n");
522                     break;
523                 }
524                 if ((fileptr[curfile+1] = fopen(filename,"r")) == NULL)
525                 {
526                     for (s1 = filename; *s1 != '\0'; ++s1) {}
527                     for (s2 = def_ext; (*s1 = *s2) != '\0'; ++s1, ++s2) {}
528                     fileptr[curfile+1] = fopen(filename,"r");
529                 }
530                 if (fileptr[curfile+1] != NULL)
531                 {
532                     ++curfile;
533                     prompt = FALSE;
534                     if (prompt)
535                         fprintf(PROMPTFILE,"> ");
536                 }
537                 else
538                     fprintf(ERRFILE,"can't open input file\n\n");
539                 break;
540 
541             case '>':   /* new output file */
542                 if ((d = getc(INFILE)) != '>')
543                     ungetc((char)d,INFILE);
544                 if (minus)
545                 {
546                     minus = FALSE;
547                     if (outfile != stdout)
548                     {
549                         fclose(outfile);
550                         outfile = stdout;
551                     }
552                 }
553                 else
554                 {
555                     if (!readstring(INFILE,filename,200))
556                     {
557                         fprintf(ERRFILE,
558                             "improper file name, reverting to stdout\n\n");
559                         outfile = stdout;
560                         break;
561                     }
562                     OPENOUT(outfile,filename,d=='>');
563                     if (outfile == NULL)
564                     {
565                         fprintf(ERRFILE,
566                             "can't open output file, reverting to stdout\n\n");
567                         outfile = stdout;
568                     }
569                 }
570                 break;
571 
572             case '!':   /* ignore rest of line */
573                 do
574                     c = getc(INFILE);
575                 while (c != '\n' && c != EOF);
576                 if (c == '\n')
577                     ungetc('\n',INFILE);
578                 break;
579 
580             case 'n':   /* read n value */
581                 minus = FALSE;
582                 i = getint(INFILE);
583                 if (i <= 0 || (MAXN && i > MAXN)
584 			   || (!MAXN && i > NAUTY_INFINITY-2))
585                     fprintf(ERRFILE,
586                          " n can't be less than 1 or more than %d\n\n",
587                            MAXN ? MAXN : NAUTY_INFINITY-2);
588                 else
589                 {
590                     gvalid = FALSE;
591                     ovalid = FALSE;
592                     cvalid = FALSE;
593                     pvalid = FALSE;
594                     n = i;
595                     m = (n + WORDSIZE - 1) / WORDSIZE;
596 #if !MAXN
597 		    worksize = 2 * m * WORKSIZE;
598 		    DYNALLOC2(graph,g,g_sz,n,m,"dreadnaut");
599 		    DYNALLOC1(int,lab,lab_sz,n,"dreadnaut");
600 		    DYNALLOC1(int,ptn,ptn_sz,n,"dreadnaut");
601                     DYNALLOC1(setword,workspace,workspace_sz,
602                                                         worksize,"dreadnaut");
603 		    DYNALLOC1(int,orbits,orbits_sz,n,"dreadnaut");
604 		    DYNALLOC1(permutation,perm,perm_sz,n,"dreadnaut");
605 		    DYNALLOC1(set,active,active_sz,m,"dreadnaut");
606 #endif
607                 }
608                 break;
609 
610             case 'g':   /* read graph */
611                 minus = FALSE;
612                 readgraph(INFILE,g,options.digraph,prompt,FALSE,
613                           options.linelength,m,n);
614                 gvalid = TRUE;
615                 cvalid = FALSE;
616                 ovalid = FALSE;
617                 break;
618 
619             case 'e':   /* edit graph */
620                 minus = FALSE;
621                 readgraph(INFILE,g,options.digraph,prompt,gvalid,
622                           options.linelength,m,n);
623                 gvalid = TRUE;
624                 cvalid = FALSE;
625                 ovalid = FALSE;
626                 break;
627 
628             case 'r':   /* relabel graph and current partition */
629                 minus = FALSE;
630                 if (gvalid)
631                 {
632 #if !MAXN
633 		    DYNALLOC2(graph,canong,canong_sz,n,m,"dreadnaut");
634 #endif
635                     readvperm(INFILE,perm,prompt,n,&nperm);
636                     relabel(g,(pvalid ? lab : NULL),perm,canong,m,n);
637                     cvalid = FALSE;
638                     ovalid = FALSE;
639                 }
640                 else
641                     fprintf(ERRFILE,"g is not defined\n\n");
642                 break;
643 
644             case 'R':   /* form subgraph */
645                 if (gvalid)
646                 {
647 #if !MAXN
648                     DYNALLOC2(graph,canong,canong_sz,n,m,"dreadnaut");
649 #endif
650                     readvperm(INFILE,perm,prompt,n,&nperm);
651 		    if (minus && nperm == n || !minus && nperm == 0)
652 			fprintf(ERRFILE,"can't form null graph\n\n");
653 		    else if (minus)
654 		    {
655                         sublabel(g,perm+nperm,n-nperm,canong,m,n);
656 			n = n - nperm;
657 		    }
658 		    else
659                     {
660                         sublabel(g,perm,nperm,canong,m,n);
661                         n = nperm;
662                     }
663                     cvalid = FALSE;
664 		    pvalid = FALSE;
665                     ovalid = FALSE;
666 		    m = (n + WORDSIZE - 1) / WORDSIZE;
667                 }
668                 else
669                     fprintf(ERRFILE,"g is not defined\n\n");
670                 minus = FALSE;
671                 break;
672 
673             case '_':   /* complement graph or converse digraph */
674                 minus = FALSE;
675                 if ((d = getc(INFILE)) != '_') ungetc((char)d,INFILE);
676 
677                 if (gvalid)
678                 {
679                     if (d == '_') converse(g,m,n);
680                     else          complement(g,m,n);
681                     cvalid = FALSE;
682                     ovalid = FALSE;
683                 }
684                 else
685                     fprintf(ERRFILE,"g is not defined\n\n");
686                 break;
687 
688             case '@':   /* copy canong into savedg */
689                 minus = FALSE;
690                 if (cvalid)
691                 {
692 #if !MAXN
693 		    DYNALLOC2(graph,savedg,savedg_sz,n,m,"dreadnaut");
694 		    DYNALLOC1(int,savedlab,savedlab_sz,n,"dreadnaut");
695 #endif
696                     sgn = n;
697                     for (li = (long)n * (long)m; --li >= 0;)
698                         savedg[li] = canong[li];
699                     for (i = n; --i >= 0;)
700                         savedlab[i] = lab[i];
701                     sgorg = labelorg;
702                 }
703                 else
704                     fprintf(ERRFILE,"h is not defined\n\n");
705                 break;
706 
707             case '#':   /* compare canong to savedg */
708                 if ((d = getc(INFILE)) != '#') ungetc((char)d,INFILE);
709 
710                 if (cvalid)
711                 {
712                     if (sgn > 0)
713                     {
714                         if (sgn != n)
715                             fprintf(OUTFILE,
716                                   "h and h' have different sizes.\n");
717                         else
718                         {
719                             for (li = (long)n * (long)m; --li >= 0;)
720                                 if (savedg[li] != canong[li]) break;
721                             if (li >= 0)
722                                 fprintf(OUTFILE,"h and h' are different.\n");
723                             else
724                             {
725                                 fprintf(OUTFILE,
726                                    "h and h' are identical.\n");
727                                 if (d == '#')
728                                     putmapping(OUTFILE,savedlab,sgorg,
729                                            lab,labelorg,options.linelength,n);
730                             }
731                         }
732                     }
733                     else
734                         fprintf(ERRFILE,"h' is not defined\n\n");
735                 }
736                 else
737                     fprintf(ERRFILE,"h is not defined\n\n");
738                 break;
739 
740             case 'j':   /* relabel graph randomly */
741                 minus = FALSE;
742                 if (gvalid)
743                 {
744 #if !MAXN
745 		    DYNALLOC2(graph,canong,canong_sz,n,m,"dreadnaut");
746 #endif
747                     ranperm(perm,n);
748                     relabel(g,(pvalid ? lab : NULL),perm,canong,m,n);
749                     cvalid = FALSE;
750                     ovalid = FALSE;
751                 }
752                 else
753                     fprintf(ERRFILE,"g is not defined\n\n");
754                 break;
755 
756             case 'v':   /* write vertex degrees */
757                 minus = FALSE;
758                 if (gvalid)
759                     putdegs(OUTFILE,g,options.linelength,m,n);
760                 else
761                     fprintf(ERRFILE,"g is not defined\n\n");
762                 break;
763 
764             case '%':   /* do Mathon doubling operation */
765                 minus = FALSE;
766                 if (gvalid)
767                 {
768 #if !MAXN
769 		    if (2L * ((long)n + 1L) > NAUTY_INFINITY-2)
770                     {
771                         fprintf(ERRFILE,
772 			     "n can't be more than %d\n\n",NAUTY_INFINITY-2);
773                         break;
774                     }
775 #else
776                     if (2L * ((long)n + 1L) > MAXN)
777                     {
778                         fprintf(ERRFILE,"n can't be more than %d\n\n",MAXN);
779                         break;
780                     }
781 #endif
782                     newn = 2 * (n + 1);
783                     newm = (newn + WORDSIZE - 1) / WORDSIZE;
784 #if !MAXN
785 		    DYNALLOC2(graph,canong,canong_sz,n,m,"dreadnaut");
786 #endif
787 
788                     for (li = (long)n * (long)m; --li >= 0;)
789                         canong[li] = g[li];
790 
791 #if !MAXN
792                     DYNALLOC2(graph,g,g_sz,newn,newm,"dreadnaut");
793                     DYNALLOC1(int,lab,lab_sz,newn,"dreadnaut");
794                     DYNALLOC1(int,ptn,ptn_sz,newn,"dreadnaut");
795 		    worksize = 2*WORKSIZE*newm;
796                     DYNALLOC1(setword,workspace,workspace_sz,
797                                                         worksize,"dreadnaut");
798                     DYNALLOC1(int,orbits,orbits_sz,newn,"dreadnaut");
799                     DYNALLOC1(permutation,perm,perm_sz,newn,"dreadnaut");
800                     DYNALLOC1(set,active,active_sz,newm,"dreadnaut");
801 #endif
802                     mathon(canong,m,n,g,newm,newn);
803                     m = newm;
804                     n = newn;
805                     cvalid = FALSE;
806                     ovalid = FALSE;
807                     pvalid = FALSE;
808                 }
809                 else
810                     fprintf(ERRFILE,"g is not defined\n\n");
811                 break;
812 
813             case 's':   /* generate random graph */
814                 minus = FALSE;
815                 i = getint(INFILE);
816                 if (i <= 0)
817                     i = 2;
818                 rangraph(g,options.digraph,i,m,n);
819                 gvalid = TRUE;
820                 cvalid = FALSE;
821                 ovalid = FALSE;
822                 break;
823 
824             case 'q':   /* quit */
825                 if (bad == 0) printf("OK");
826 		printf("\n");
827                 exit(bad);
828                 break;
829 
830             case '"':   /* copy comment to output */
831                 minus = FALSE;
832                 copycomment(INFILE,OUTFILE,'"');
833                 break;
834 
835             case 'I':   /* do refinement and invariants procedure */
836                 if (!pvalid)
837                     unitptn(lab,ptn,&numcells,n);
838                 cellstarts(ptn,0,active,m,n);
839                 doref(g,lab,ptn,0,&numcells,&qinvar,perm,active,&refcode,
840                         options.userrefproc ? options.userrefproc :
841 			(m == 1 ? refine1 : refine),
842                         options.invarproc,0,0,
843                         options.invararg,options.digraph,m,n);
844                 fprintf(OUTFILE," %d cell%s; code = %x",
845                         SS(numcells,"","s"),refcode);
846                 if (options.invarproc != NULL)
847                     fprintf(OUTFILE," (%s %s)",invarprocname,
848                         (qinvar == 2 ? "worked" : "failed"));
849                 fprintf(OUTFILE,"\n");
850                 if (numcells > 1)
851                     pvalid = TRUE;
852                 break;
853 
854             case 'i':   /* do refinement */
855                 if (!pvalid)
856                     unitptn(lab,ptn,&numcells,n);
857                 cellstarts(ptn,0,active,m,n);
858 		if (options.userrefproc)
859 		    (*options.userrefproc)
860                          (g,lab,ptn,0,&numcells,perm,active,&refcode,m,n);
861                 else if (m == 1)
862                     refine1(g,lab,ptn,0,&numcells,perm,active,&refcode,m,n);
863                 else
864                     refine(g,lab,ptn,0,&numcells,perm,active,&refcode,m,n);
865                 fprintf(OUTFILE," %d cell%s; code = %x\n",
866                         SS(numcells,"","s"),refcode);
867                 if (numcells > 1)
868                     pvalid = TRUE;
869                 break;
870 
871             case 'x':   /* execute nauty */
872                 minus = FALSE;
873                 ovalid = FALSE;
874                 cvalid = FALSE;
875                 if (!gvalid)
876                 {
877                     fprintf(ERRFILE,"g is not defined\n\n");
878                     break;
879                 }
880                 if (pvalid)
881                 {
882                     /* fprintf(OUTFILE,"[fixing partition]\n"); */
883                     options.defaultptn = FALSE;
884                 }
885                 else
886                     options.defaultptn = TRUE;
887                 options.outfile = outfile;
888 
889                 if (options.getcanon)
890                 {
891 #if !MAXN
892 		    DYNALLOC2(graph,canong,canong_sz,n,m,"dreadnaut");
893 #endif
894                 }
895 
896                 firstpath = TRUE;
897 		options.writeautoms = FALSE;
898 		options.writemarkers = FALSE;
899 		for (i = 0; i < multiplicity; ++i)
900 		{
901 		    afound = 1;
902                     nauty(g,lab,ptn,NULL,orbits,&options,&stats,workspace,
903                          worksize,m,n,canong);
904 		    options.writeautoms = FALSE;
905                     options.writemarkers = FALSE;
906 		}
907                 if (stats.errstatus != 0)
908                     fprintf(ERRFILE,
909                       "nauty returned error status %d [this can't happen]\n\n",
910                        stats.errstatus);
911                 else
912                 {
913                     if (options.getcanon) cvalid = TRUE;
914                     ovalid = TRUE;
915                  /* fprintf(OUTFILE,
916 			       "%d orbit%s",SS(stats.numorbits,"","s"));
917                     if (stats.grpsize2 == 0)
918                         fprintf(OUTFILE,"; grpsize=%.0f",stats.grpsize1+0.1);
919                     else
920                     {
921                         while (stats.grpsize1 >= 10.0)
922                         {
923                             stats.grpsize1 /= 10.0;
924                             ++stats.grpsize2;
925                         }
926                         fprintf(OUTFILE,"; grpsize=%12.10fe%d",
927                                    stats.grpsize1,stats.grpsize2);
928                     }
929                     fprintf(OUTFILE,"; %d gen%s",
930                             SS(stats.numgenerators,"","s"));
931                     fprintf(OUTFILE,"; %ld node%s",SS(stats.numnodes,"","s"));
932                     if (stats.numbadleaves)
933                         fprintf(OUTFILE," (%ld bad lea%s)",
934                                 SS(stats.numbadleaves,"f","ves"));
935                     fprintf(OUTFILE,"; maxlev=%d\n", stats.maxlevel);
936                     fprintf(OUTFILE,"tctotal=%ld",stats.tctotal);
937                     if (options.getcanon)
938                         fprintf(OUTFILE,"; canupdates=%ld",stats.canupdates);
939                     fprintf(OUTFILE,"\n");
940                     if (options.invarproc != NULL &&
941                                            options.maxinvarlevel != 0)
942                     {
943                         fprintf(OUTFILE,"invarproc \"%s\" succeeded %ld/%ld",
944                             invarprocname,stats.invsuccesses,stats.invapplics);
945                         if (stats.invarsuclevel > 0)
946                             fprintf(OUTFILE," beginning at level %d.\n",
947                                     stats.invarsuclevel);
948                         else
949                             fprintf(OUTFILE,".\n");
950                     }
951 		*/
952                 }
953                 break;
954 
955             case 'f':   /* read initial partition */
956                 if (minus)
957                 {
958                     pvalid = FALSE;
959                     minus = FALSE;
960                 }
961                 else
962                 {
963                     readptn(INFILE,lab,ptn,&numcells,prompt,n);
964                     pvalid = TRUE;
965                 }
966                 break;
967 
968             case 't':   /* type graph */
969                 minus = FALSE;
970                 if (!gvalid)
971                     fprintf(ERRFILE,"g is not defined\n\n");
972                 else
973                     putgraph(OUTFILE,g,options.linelength,m,n);
974                 break;
975 
976             case 'T':   /* type graph preceded by n, $ and g commands */
977                 minus = FALSE;
978                 if (!gvalid)
979                     fprintf(ERRFILE,"g is not defined\n\n");
980                 else
981                 {
982                     fprintf(OUTFILE,"n=%d $=%d g\n",n,labelorg);
983                     putgraph(OUTFILE,g,options.linelength,m,n);
984                     fprintf(OUTFILE,"$$\n");
985                 }
986                 break;
987 
988             case 'u':   /* call user procs */
989                 if (minus)
990                 {
991                     umask = 0;
992                     minus = FALSE;
993                 }
994                 else
995                 {
996                     umask = getint(INFILE);
997                     if (umask < 0)
998                         umask = ~0;
999                 }
1000                 if (umask & U_NODE)
1001                     options.usernodeproc = NODEPROC;
1002                 else
1003                     options.usernodeproc = NULL;
1004                 if (umask & U_AUTOM)
1005                     options.userautomproc = AUTOMPROC;
1006                 else
1007                     options.userautomproc = userautom;
1008                 if (umask & U_LEVEL)
1009                     options.userlevelproc = LEVELPROC;
1010                 else
1011                     options.userlevelproc = NULL;
1012                 if (umask & U_TCELL)
1013                     options.usertcellproc = TCELLPROC;
1014                 else
1015                     options.usertcellproc = NULL;
1016                 if (umask & U_REF)
1017                     options.userrefproc = REFPROC;
1018                 else
1019                     options.userrefproc = NULL;
1020                 break;
1021 
1022             case 'o':   /* type orbits */
1023                 minus = FALSE;
1024 		need = gethex(INFILE);
1025                 if (ovalid)
1026                 {
1027 		    found = inthash(orbits,n,761L,3);
1028 		    if (found != need)
1029 		    {
1030 			printf("\nERROR: need=%lx found=%lx\n",need,found);
1031 			++bad;
1032 		    }
1033 		    else
1034 			printf("+"); fflush(stdout);
1035 		}
1036                 else
1037                     fprintf(ERRFILE,"orbits are not defined\n\n");
1038                 break;
1039 
1040             case 'b':   /* type canonlab and canong */
1041                 minus = FALSE;
1042                 need = gethex(INFILE);
1043                 if (cvalid)
1044                 {
1045 		    zseed = n;
1046                     for (i = 0, gp = canong; i < n; ++i, gp += m)
1047                         zseed = sethash(gp,n,zseed,3109);
1048 		    found = inthash(lab,n,165,2) ^ zseed;
1049                     if (found != need)
1050 		    {
1051                         printf("\nERROR: need=%lx found=%lx\n",need,found);
1052 			++bad;
1053 		    }
1054                     else
1055                         printf("+"); fflush(stdout);
1056                 }
1057                 else
1058                     fprintf(ERRFILE,"automorphisms are not defined\n\n");
1059                 break;
1060 
1061             case 'z':   /* type hashcode for canong */
1062                 minus = FALSE;
1063                 if (cvalid)
1064 		{
1065 		    zseed = n;
1066 		    for (i = 0, gp = canong; i < n; ++i, gp += m)
1067 			zseed = sethash(gp,n,zseed,321);
1068                     fprintf(OUTFILE,"[%7lx",zseed);
1069 
1070                     for (i = 0, gp = canong; i < n; ++i, gp += m)
1071                         zseed = sethash(gp,n,zseed,3109);
1072                     fprintf(OUTFILE," %7lx",zseed);
1073 
1074                     for (i = 0, gp = canong; i < n; ++i, gp += m)
1075                         zseed = sethash(gp,n,zseed,4317);
1076                     fprintf(OUTFILE," %7lx]\n",zseed);
1077 		}
1078                 else
1079                     fprintf(ERRFILE,"h is not defined\n\n");
1080                 break;
1081 
1082             case 'c':   /* set getcanon option */
1083                 options.getcanon = !minus;
1084                 minus = FALSE;
1085                 break;
1086 
1087             case 'w':   /* read size of workspace */
1088                 minus = FALSE;
1089                 worksize = getint(INFILE);
1090 #if !MAXN
1091 		DYNALLOC1(setword,workspace,workspace_sz,worksize,"dreadnaut");
1092 #else
1093                 if (worksize > 2*MAXM*WORKSIZE)
1094                 {
1095                     fprintf(ERRFILE,
1096                        "too big - setting worksize = %d\n\n", 2*MAXM*WORKSIZE);
1097                     worksize = 2*MAXM*WORKSIZE;
1098                 }
1099 #endif
1100                 break;
1101 
1102             case 'l':   /* read linelength for output */
1103                 options.linelength = getint(INFILE);
1104                 minus = FALSE;
1105                 break;
1106 
1107             case 'y':   /* set tc_level field of options */
1108                 options.tc_level = getint(INFILE);
1109                 minus = FALSE;
1110                 break;
1111 
1112             case 'M':   /* set multiplicity */
1113                 multiplicity = getint(INFILE);
1114 		if (multiplicity <= 0) multiplicity = 1;
1115                 minus = FALSE;
1116                 break;
1117 
1118             case 'k':   /* set invarlev fields of options */
1119                 options.mininvarlevel = getint(INFILE);
1120                 options.maxinvarlevel = getint(INFILE);
1121                 minus = FALSE;
1122                 break;
1123 
1124             case 'K':   /* set invararg field of options */
1125                 options.invararg = getint(INFILE);
1126                 minus = FALSE;
1127                 break;
1128 
1129             case '*':   /* set invarproc field of options */
1130                 minus = FALSE;
1131                 d = getint(INFILE);
1132                 if (d >= -1 && d <= NUMINVARS-2)
1133                 {
1134                     options.invarproc = invarproc[d+1].entrypoint;
1135                     invarprocname = invarproc[d+1].name;
1136 		    if (options.invarproc != NULL)
1137 		    {
1138 			options.mininvarlevel = 0;
1139 			options.maxinvarlevel = 1;
1140 			if (options.invarproc == indsets ||
1141 			    options.invarproc == cliques ||
1142 			    options.invarproc == cellind ||
1143 			    options.invarproc == cellcliq)
1144 				options.invararg = 3;
1145 			else
1146 			    options.invararg = 0;
1147 		    }
1148                 }
1149                 else
1150                     fprintf(ERRFILE,"no such vertex-invariant\n\n");
1151                 break;
1152 
1153             case 'a':   /* set writeautoms option */
1154                 minus = FALSE;
1155                 need = gethex(INFILE);
1156                 if (ovalid)
1157                 {
1158                     if (afound != need)
1159 		    {
1160                         printf("\nERROR: need=%lx found=%lx\n",need,afound);
1161 			++bad;
1162 		    }
1163                     else
1164                         printf("+"); fflush(stdout);
1165                 }
1166                 else
1167                     fprintf(ERRFILE,"automorphisms are not defined\n\n");
1168                 break;
1169 
1170             case 'C':   /* check bit and set operations */
1171                 minus = FALSE;
1172 		bit_tests();
1173                 break;
1174 
1175             case 'm':   /* set writemarkers option */
1176                 options_writemarkers = !minus;
1177                 minus = FALSE;
1178                 break;
1179 
1180             case 'p':   /* set cartesian option */
1181                 options.cartesian = !minus;
1182                 minus = FALSE;
1183                 break;
1184 
1185             case 'd':   /* set digraph option */
1186                 if (options.digraph && minus)
1187                     gvalid = FALSE;
1188                 options.digraph = !minus;
1189                 minus = FALSE;
1190                 break;
1191 
1192             case '$':   /* set label origin */
1193                 if ((d = getc(INFILE)) == '$')
1194                     labelorg = oldorg;
1195                 else
1196                 {
1197                     ungetc((char)d,INFILE);
1198                     oldorg = labelorg;
1199                     i = getint(INFILE);
1200                     if (i < 0)
1201                         fprintf(ERRFILE,"labelorg must be >= 0\n\n");
1202                     else
1203                         labelorg = i;
1204                 }
1205                 break;
1206 
1207             case '?':   /* type options, etc. */
1208                 minus = FALSE;
1209                 fprintf(OUTFILE,"m=%d n=%d labelorg=%d",m,n,labelorg);
1210                 if (!gvalid)
1211                     fprintf(OUTFILE," g=undef");
1212                 else
1213                 {
1214                     li = 0;
1215                     for (i = 0, gp = g; i < n; ++i, gp += m)
1216                         li += setsize(gp,m);
1217                     if (options.digraph)
1218                         fprintf(OUTFILE," arcs=%ld",li);
1219                     else
1220                         fprintf(OUTFILE," edges=%ld",li/2);
1221                 }
1222                 fprintf(OUTFILE," options=(%cc%ca%cm%cp%cd",
1223                             PM(options.getcanon),PM(options_writeautoms),
1224                             PM(options_writemarkers),PM(options.cartesian),
1225                             PM(options.digraph));
1226                 if (umask & 31)
1227                     fprintf(OUTFILE," u=%d",umask&31);
1228                 if (options.tc_level > 0)
1229                     fprintf(OUTFILE," y=%d",options.tc_level);
1230                 if (options.mininvarlevel != 0 || options.maxinvarlevel != 0)
1231                     fprintf(OUTFILE," k=(%d,%d)",
1232                                   options.mininvarlevel,options.maxinvarlevel);
1233                 if (options.invararg > 0)
1234                     fprintf(OUTFILE," K=%d",options.invararg);
1235 		if (multiplicity > 1) fprintf(OUTFILE," M=%d",multiplicity);
1236                 fprintf(OUTFILE,")\n");
1237                 fprintf(OUTFILE,"linelen=%d worksize=%d input_depth=%d",
1238                                 options.linelength,worksize,curfile);
1239                 if (options.invarproc != NULL)
1240                     fprintf(OUTFILE," invarproc=%s",invarprocname);
1241                 if (pvalid)
1242                     fprintf(OUTFILE,"; %d cell%s",SS(numcells,"","s"));
1243                 else
1244                     fprintf(OUTFILE,"; 1 cell");
1245                 fprintf(OUTFILE,"\n");
1246                 if (OUTFILE != PROMPTFILE)
1247                     fprintf(PROMPTFILE,"m=%d n=%d depth=%d labelorg=%d\n",
1248                             m,n,curfile,labelorg);
1249                 break;
1250 
1251             case '&':   /* list the partition and possibly the quotient */
1252 		need = gethex(INFILE);
1253                 if ((d = getc(INFILE)) == '&')
1254                     doquot = TRUE;
1255                 else
1256                 {
1257                     ungetc((char)d,INFILE);
1258                     doquot = FALSE;
1259                 }
1260                 minus = FALSE;
1261                 if (pvalid)
1262 		{
1263 		    for (i = 0; i < n; ++i) if (ptn[i] > n) ptn[i] = n;
1264 		    found = inthash(lab,n,4123,12) ^ inthash(ptn,n,4123,12);
1265 		}
1266                 else
1267 		    found = 1001;
1268 
1269                 if (found != need)
1270 		{
1271                     printf("\nERROR: need=%lx found=%lx\n",need,found);
1272 		    ++bad;
1273 		}
1274                 else
1275                     printf("+"); fflush(stdout);
1276 
1277                 if (doquot)
1278                 {
1279 		 /*
1280                     if (!pvalid)
1281                         unitptn(lab,ptn,&numcells,n);
1282                     putquotient(OUTFILE,g,lab,ptn,0,options.linelength,m,n);
1283 		 */
1284                 }
1285                 break;
1286 
1287             case 'h':   /* type help information */
1288 	    case 'H':
1289                 minus = FALSE;
1290                 printf("a, o, & are reassigned and output is suppressed\n");
1291 		printf("Use dreadnaut for other functions\n");
1292                 break;
1293 
1294             default:    /* illegal command */
1295                 fprintf(ERRFILE,"'%c' is illegal - type 'h' for help\n\n",c);
1296                 flushline(INFILE);
1297                 if (prompt)
1298                     fprintf(PROMPTFILE,"> ");
1299                 break;
1300 
1301             }  /* end of switch */
1302 
1303 	return 0;
1304 }
1305 
1306 /*****************************************************************************
1307 *                                                                            *
1308 *  help(f,i) writes help information to file f (i = 0,1).                    *
1309 *                                                                            *
1310 *****************************************************************************/
1311 
1312 static void
help(FILE * f,int i)1313 help(FILE *f, int i)
1314 {
1315 #define H(ss) fprintf(f," %s\n",ss);
1316 
1317 if (i == 0)
1318 {
1319 H("+- a : write automs        v : write degrees    *=# : select invariant:")
1320 H("   b : write canong      w=# : set worksize")
1321 H("+- c : canonise            x : run nauty         -1 = user-defined")
1322 H("+- d : digraph or loops  y=# : set tc_level       0 = none")
1323 H("   e : edit graph          z : write hashcode     1 = twopaths")
1324 H("-f, f=#, f=[...] : set colours                    2 = adjtriang(K=0,1)")
1325 H("   g : read graph        $=# : set origin         3 = triples")
1326 H(" h,H : help               $$ : restore origin     4 = quadruples")
1327 H("   i : refine              ? : type options       5 = celltrips")
1328 H("   I : refine using invar  _ : compl  __ : conv   6 = cellquads")
1329 H("   j : relabel randomly    % : Mathon doubling    7 = cellquins")
1330 H("k=# # : set invar levels   & : type colouring     8 = distances(K)")
1331 H(" K=# : set invar param    && : + quotient matrix  9 = indsets(K)")
1332 H(" l=# : set line length   >ff : write to file     10 = cliques(K)")
1333 H("+- m : write markers    >>ff : append to file    11 = cellcliq(K)")
1334 H(" n=# : set order          -> : revert to stdout  12 = cellind(K)")
1335 H("   o : write orbits      <ff : read from file    13 = adjacencies")
1336 H("+- p : set autom format    @ : save canong       14 = cellfano")
1337 H("   q : quit                # : canong = savedg?  15 = cellfano2")
1338 H(" r,R : relabel/subgraph   ## : + write mapping")
1339 H(" s=# : random g (p=1/#)  \"...\" : copy comment")
1340 H(" t,T : type graph          ! : ignore line      Type H for more..")
1341 }
1342 
1343 if (i == 1)
1344 {
1345 H("Commands for g and e : ")
1346 H("   There is always a \"current vertex\" v, initially first vertex.")
1347 H("   # : add edge v=#       ; : increment v (exit if over limit)")
1348 H("  -# : delete edge v=#   #: : set v := #")
1349 H("   ? : list nbhs of v     . : exit")
1350 H("Syntax for f :  f=[2 3|4:9|10]  (rest in extra cell at right)")
1351 H("               -f same as f=[], f=# same as f=[#]")
1352 H("Syntax for r :  r 2:4 1 5;    (rest appended in order)")
1353 H("Syntax for R :  R 2:4 1 5;   or  -R 0 3 6:10;")
1354 H("Arguments for u : 1=node,2=autom,4=level,8=tcell,16=ref (add them)")
1355 H("Accurate times for easy graphs: M=# selects number of times to run.")
1356 }
1357 
1358 }
1359 
1360 /*****************************************************************************
1361 *                                                                            *
1362 *  usernode(g,lab,ptn,level,numcells,tc,code,m,n) is a simple version of the *
1363 *  procedure named by options.usernodeproc.                                  *
1364 *                                                                            *
1365 *****************************************************************************/
1366 
1367 static void
usernode(graph * g,int * lab,int * ptn,int level,int numcells,int tc,int code,int m,int n)1368 usernode(graph *g, int *lab, int *ptn, int level, int numcells,
1369          int tc, int code, int m, int n)
1370 {
1371 /*
1372         register int i;
1373 
1374         for (i = 0; i < level; ++i)
1375             PUTC('.',OUTFILE);
1376         if (numcells == n)
1377             fprintf(OUTFILE,"(n/%d)\n",code);
1378         else if (tc < 0)
1379             fprintf(OUTFILE,"(%d/%d)\n",numcells,code);
1380         else
1381             fprintf(OUTFILE,"(%d/%d/%d)\n",numcells,code,tc);
1382         if (firstpath)
1383             putptn(OUTFILE,lab,ptn,level,options.linelength,n);
1384         if (numcells == n)
1385             firstpath = FALSE;
1386 */
1387 }
1388 
1389 /*****************************************************************************
1390 *                                                                            *
1391 *  userautom(count,perm,orbits,numorbits,stabvertex,n) is a simple           *
1392 *  version of the procedure named by options.userautomproc.                  *
1393 *                                                                            *
1394 *****************************************************************************/
1395 
1396 static void
userautom(int count,permutation * perm,int * orbits,int numorbits,int stabvertex,int n)1397 userautom(int count, permutation *perm, int *orbits,
1398           int numorbits, int stabvertex, int n)
1399 {
1400 	afound ^= permhash(perm,n,107651L,count);
1401 }
1402 
1403 /*****************************************************************************
1404 *                                                                            *
1405 *  userlevel(lab,ptn,level,orbits,stats,tv,index,tcellsize,numcells,cc,n)    *
1406 *  is a simple version of the procedure named by options.userlevelproc.      *
1407 *                                                                            *
1408 *****************************************************************************/
1409 
1410 static void
userlevel(int * lab,int * ptn,int level,int * orbits,statsblk * stats,int tv,int index,int tcellsize,int numcells,int cc,int n)1411 userlevel(int *lab, int *ptn, int level, int *orbits, statsblk *stats,
1412           int tv, int index, int tcellsize, int numcells, int cc, int n)
1413 {
1414 /*
1415       fprintf(OUTFILE,
1416             "**userlevelproc:  level=%d tv=%d index=%d tcellsize=%d cc=%d\n",
1417             level,tv+labelorg,index,tcellsize,cc);
1418       fprintf(OUTFILE,"    nodes=%ld cells=%d orbits=%d generators=%d\n",
1419             stats->numnodes,numcells,stats->numorbits,stats->numgenerators);
1420 */
1421 }
1422