1 /* genspecialg.c  version 1.3; B D McKay, Mar 19, 2018 */
2 
3 #define USAGE "genspecialg [-s|-g|-z|-d|-v] [-q]\n\
4      [-p#|-c#|-e#|-k#|-b#,#[,#]|-Q#|-f#|-J#,#\n\
5          |-P#,#|C#,#...|G#,#...|T#,#...]* [outfile]"
6 
7 #define HELPTEXT \
8 " Generate special graphs.\n\
9      #  : size parameter called n in the descriptions\n\
10 \n\
11     -s : Write in sparse6 format (default)\n\
12     -g : Write in graph6 format\n\
13     -z : Make digraph versions and write in digraph6 format\n\
14     -d : Write in dreadnaut format (can be used with -z)\n\
15     -v : For each graph, report the size to stderr\n\
16     -q : Suppress summary\n\
17 \n\
18     If defined, the digraph version is shown in parentheses:\n\
19     -p#   : path (directed path) on n vertices.\n\
20     -c#   : cycle (directed cycle) on n vertices.\n\
21     -e#   : empty graph (digraph with loops only) on n vertices.\n\
22     -k#   : complete graph (with loops) on n vertices\n\
23     -b#,#[,#] : complete bipartite graph (directed l->r) on n vertices\n\
24 	           minus a matching of given size if present\n\
25     -f#   : flower snark on 4*# vertices\n\
26     -P#,# : generalized Petersen graph; usual one is -P5,2\n\
27     -Q#   : hypercube on 2^n vertices and degree n.\n\
28     -J#,# : Johnson graph J(n,k), args are n and k.\n\
29     -C#,#... : circulant (di)graph.\n\
30     -T#,#... : theta (di)graph Theta(#,#,...), give path lengths.\n\
31     -G#,#... : (directed) grid, use negative values for open directions\n\
32 \n\
33     Any number of graphs can be generated at once.\n"
34 
35 /* Ideas: multipartite, knesser, full trees, antiregular, individual */
36 
37 #include "gtools.h"
38 
39 #define MAXARGS 10000  /* Maximum argument list for multi-argument parameters */
40 #define SWAP(x,y) {int w = x; x = y; y = w;}
41 
42 static long args[MAXARGS];
43 
44 static short vmark_val = 32000;
45 DYNALLSTAT(short,vmark,vmark_sz);
46 #define MARK(i) vmark[i] = vmark_val
47 #define UNMARK(i) vmark[i] = 0
48 #define ISMARKED(i) (vmark[i] == vmark_val)
49 #define ISNOTMARKED(i) (vmark[i] != vmark_val)
50 #define RESETMARKS {if (vmark_val++ >= 32000) \
51     {size_t ij; for (ij=0;ij<vmark_sz;++ij) vmark[ij]=0; vmark_val=1;}}
52 
53 static void
preparemarks(size_t nn)54 preparemarks(size_t nn)
55 {
56     size_t oldsize;
57     short *oldpos;
58 
59     oldsize = vmark_sz;
60     oldpos = vmark;
61     DYNALLOC1(short,vmark,vmark_sz,nn,"preparemarks");
62     if (vmark_sz != oldsize || vmark != oldpos) vmark_val = 32000;
63 }
64 
65 /**************************************************************************/
66 
67 static void
writedread(FILE * f,sparsegraph * sg,boolean digraph)68 writedread(FILE *f, sparsegraph *sg, boolean digraph)
69 /* Write in dreadnaut format */
70 {
71     size_t *v;
72     int *d,*e,n,i,j,k;
73 
74     SG_VDE(sg,v,d,e);
75     n = sg->nv;
76 
77     if (digraph) fprintf(f,"n=%d $=0 dg\n",n);
78     else         fprintf(f,"n=%d $=0 g\n",n);
79 
80     for (i = 0; i < n; ++i)
81     {
82 	for (j = 0; j < d[i]; ++j)
83         {
84 	    k = e[v[i]+j];
85 	    if (k >= i || digraph) fprintf(f," %d",k);
86 	}
87 	if (i == n-1) fprintf(f,".\n$$\n");
88 	else          fprintf(f,";\n");
89     }
90 }
91 
92 /**************************************************************************/
93 
94 static int binom[32][16];   /* Cached binomial coefficients */
95 
96 static int
binomial(int n,int k)97 binomial(int n, int k)
98 /* Value of binomial(n,k), error if too big for int */
99 {
100     int i,nki,ans;
101     nauty_counter work;
102 
103     if (k > n/2) k = n - k;
104     if (k < 0) return 0;
105 
106     if (n < 32  && binom[n][k] > 0) return binom[n][k];
107 
108     work = 1;
109     for (i = 1; i <= k; ++i)
110     {
111         nki = n-k+i;
112         work = (work/i) * nki + (work%i) * nki / i;
113         if ((int)work != work) { fprintf(stderr,"Overflow\n"); exit(1); }
114     }
115 
116     ans = (int)work;
117     if (n < 32) binom[n][k] = ans;
118 
119     return ans;
120 }
121 
122 /**************************************************************************/
123 
124 static void
unrank(int r,int k,int * a)125 unrank(int r, int k, int *a)
126 /* r-th k-set in colex order (r=0,1,...) */
127 {
128     int i,p;
129 
130     for (i = k; i > 0; --i)
131     {
132         p = i - 1;
133         do ++p; while (binomial(p,i) <= r);
134         r -= binomial(p-1,i);
135         a[i-1] = p-1;
136     }
137 }
138 
139 static int
rank(int k,int * a)140 rank(int k, int *a)
141 /* Rank of a[0..k-1] in colex order */
142 {
143     int i,r;
144 
145     r = 0;
146     for (i = 0; i < k; ++i)
147         r += binomial(a[i],i+1);
148 
149     return r;
150 }
151 
152 /**************************************************************************/
153 
154 static int
vnumber(long * dimen,int * index,int ndimen)155 vnumber(long *dimen, int *index, int ndimen)
156 {
157     int i,v;
158 
159     v = 0;
160     for (i = 0; i < ndimen; ++i)
161         v = v*dimen[i] + index[i];
162 
163     return v;
164 }
165 
166 /**************************************************************************/
167 
168 static void
makepath(long n,boolean digraph,sparsegraph * sg)169 makepath(long n, boolean digraph, sparsegraph *sg)
170 {
171     int *d,*e,i;
172     size_t *v,k;
173 
174     if (n < 1 || n > NAUTY_INFINITY-2)
175         gt_abort(">E genspecialg: bad argument for -p\n");
176 
177     if (digraph) SG_ALLOC(*sg,n,n-1,"genspecialg");
178     else         SG_ALLOC(*sg,n,2UL*n-2,"genspecialg");
179 
180     SG_VDE(sg,v,d,e);
181 
182     if (digraph || n == 1)
183     {
184 	sg->nv = n;
185 	sg->nde = n-1;
186 
187 	for (i = 0; i < n-1; ++i)
188         {
189 	    d[i] = 1;
190 	    v[i] = i;
191 	    e[i] = i+1;
192         }
193 	d[n-1] = 0;
194 	v[n-1] = 0;
195     }
196     else
197     {
198 	sg->nv = n;
199 	sg->nde = 2*n-2;
200 
201 	d[0] = 1;
202 	v[0] = 0;
203 	e[0] = 1;
204 	for (i = 1, k = 1; i < n-1; ++i, k += 2)
205 	{
206 	    d[i] = 2;
207 	    v[i] = k;
208 	    e[k] = i-1;
209 	    e[k+1] = i+1;
210 	}
211 	d[n-1] = 1;
212 	v[n-1] = k;
213 	e[k] = n-2;
214     }
215 }
216 
217 /**************************************************************************/
218 
219 static void
makecycle(long n,boolean digraph,sparsegraph * sg)220 makecycle(long n, boolean digraph, sparsegraph *sg)
221 {
222     int *d,*e,i;
223     size_t *v;
224 
225     if (!digraph && (n < 1 || n == 2 || n > NAUTY_INFINITY-2))
226         gt_abort(">E genspecialg: bad argument for -c\n");
227     if (digraph && (n < 1 || n > NAUTY_INFINITY-2))
228         gt_abort(">E genspecialg: bad argument for -zc\n");
229 
230     if (digraph) SG_ALLOC(*sg,n,n,"genspecialg");
231     else         SG_ALLOC(*sg,n,2UL*n,"genspecialg");
232 
233     SG_VDE(sg,v,d,e);
234 
235     if (digraph || n == 1)
236     {
237 	sg->nv = n;
238 	sg->nde = n;
239 
240 	for (i = 0; i < n-1; ++i)
241         {
242 	    d[i] = 1;
243 	    v[i] = i;
244 	    e[i] = i+1;
245         }
246 	d[n-1] = 1;
247 	v[n-1] = n-1;
248 	e[n-1] = 0;
249     }
250     else
251     {
252 	sg->nv = n;
253 	sg->nde = 2UL*n;
254 
255 	d[0] = 2;
256 	v[0] = 0;
257 	e[0] = 1;
258 	e[1] = n-1;
259 
260 	for (i = 1; i < n-1; ++i)
261         {
262 	    d[i] = 2;
263 	    v[i] = 2UL*i;
264 	    e[2UL*i] = i-1;
265 	    e[2UL*i+1] = i+1;
266         }
267 	d[n-1] = 2;
268 	v[n-1] = 2UL*n-2;
269 	e[2UL*n-2] = 0;
270 	e[2UL*n-1] = n-2;
271     }
272 }
273 
274 /**************************************************************************/
275 
276 static void
makeflowersnark(long k,boolean digraph,sparsegraph * sg)277 makeflowersnark(long k, boolean digraph, sparsegraph *sg)
278 /* Flower snark on 4*k vertices, no digraph variant
279 *
280  * The flower snark Jn can be constructed with the following process :
281  * Build n copies of the star graph on 4 vertices. Denote the
282  * central vertex of each star Ai and the outer vertices Bi, Ci and
283  * Di. This results in a disconnected graph on 4n vertices with 3n
284  * edges (Ai-Bi, Ai-Ci and Ai-Di for 1?i?n). Construct the n-cycle
285  * (B1... Bn). This adds n edges. Finally construct the 2n-cycle
286  * (C1... CnD1... Dn). This adds 2n edges. By construction, the
287  * Flower snark Jn is a cubic graph with 4n vertices and 6n edges.
288 */
289 
290 #define FSA(i) (4*(i))
291 #define FSB(i) (4*(i)+1)
292 #define FSC(i) (4*(i)+2)
293 #define FSD(i) (4*(i)+3)
294 
295 {
296     int n,*d,*e,i,j;
297     size_t *v,nde;
298 
299     if (k < 3 || k > (NAUTY_INFINITY-2)/4)
300         gt_abort(">E genspecialg: bad argument for -f\n");
301 
302     n = 4*k;
303     nde = 12*(size_t)k;
304 
305     SG_ALLOC(*sg,n,nde,"genspecialg");
306 
307     SG_VDE(sg,v,d,e);
308     sg->nv = n;
309     sg->nde = nde;
310 
311     for (i = 0; i < n; ++i)
312     {
313 	d[i] = 0;
314         v[i] = 3*(size_t)i;
315     }
316 
317     for (i = 0; i < k; ++i)
318     {
319         e[v[FSA(i)]+d[FSA(i)]++] = FSB(i);
320         e[v[FSB(i)]+d[FSB(i)]++] = FSA(i);
321         e[v[FSA(i)]+d[FSA(i)]++] = FSC(i);
322         e[v[FSC(i)]+d[FSC(i)]++] = FSA(i);
323         e[v[FSA(i)]+d[FSA(i)]++] = FSD(i);
324         e[v[FSD(i)]+d[FSD(i)]++] = FSA(i);
325     }
326 
327     for (i = 0; i < k; ++i)
328     {
329         j = FSB((i+1)%k);
330 	e[v[FSB(i)]+d[FSB(i)]++] = j;
331 	e[v[j]+d[j]++] = FSB(i);
332     }
333 
334     for (i = 0; i < k-1; ++i)
335     {
336 	e[v[FSC(i)]+d[FSC(i)]++] = FSC(i+1);
337 	e[v[FSC(i+1)]+d[FSC(i+1)]++] = FSC(i);
338     }
339 
340     for (i = 0; i < k-1; ++i)
341     {
342 	e[v[FSD(i)]+d[FSD(i)]++] = FSD(i+1);
343 	e[v[FSD(i+1)]+d[FSD(i+1)]++] = FSD(i);
344     }
345 
346     e[v[FSD(0)]+d[FSD(0)]++] = FSC(k-1);
347     e[v[FSC(k-1)]+d[FSC(k-1)]++] = FSD(0);
348     e[v[FSC(0)]+d[FSC(0)]++] = FSD(k-1);
349     e[v[FSD(k-1)]+d[FSD(k-1)]++] = FSC(0);
350 }
351 
352 /**************************************************************************/
353 
354 static void
makeJohnson(long n,long k,boolean digraph,sparsegraph * sg)355 makeJohnson(long n, long k, boolean digraph, sparsegraph *sg)
356 {
357     size_t *v;
358     int *d,*e,*ep,nv,deg,i,j,s,t,u;
359     DYNALLSTAT(int,a,a_sz);
360     DYNALLSTAT(int,b,b_sz);
361 
362     if (k > n/2) k = n - k;
363     if (k < 0) gt_abort(">E genspecialg: bad parameters for -J\n");
364 
365     nv = binomial(n,k);
366     if (nv > NAUTY_INFINITY-2) gt_abort(">E genspecialg: too big -J\n");
367     deg = k*(n-k);
368 
369     SG_ALLOC(*sg,nv,nv*(size_t)deg,"genspecialg");
370     sg->nv = nv;
371     sg->nde = nv*(size_t)deg;
372     SG_VDE(sg,v,d,e);
373 
374     DYNALLOC1(int,a,a_sz,k,"genspecialg");
375     DYNALLOC1(int,b,b_sz,k,"genspecialg");
376     preparemarks(n);
377 
378     for (i = 0; i < nv; ++i)
379     {
380 	v[i] = i*(size_t)deg;
381 	d[i] = deg;
382 	ep = e + v[i];
383 	unrank(i,k,a);
384 //{int x;for(x=0;x<k;++x)printf(" %d",a[x]);printf("\n");}
385 	RESETMARKS;
386 	for (j = 0; j < k; ++j) MARK(a[j]);
387 
388 	for (j = 0; j < n; ++j)
389 	if (ISNOTMARKED(j))
390 	{
391 	    for (s = 0; s < k; ++s)
392 	    {
393 		for (t = 0; t < k; ++t) b[t] = a[t];
394 		u = s;
395 		while (u > 0 && b[u-1] > j)
396 		{
397 		    b[u] = b[u-1];
398 		    --u;
399 		}
400 		while (u < k-1 && b[u+1] < j)
401 		{
402 		    b[u] = b[u+1];
403 		    ++u;
404 		}
405 		b[u] = j;
406 //{int x;printf("-");for(x=0;x<k;++x)printf(" %d",b[x]);printf(" (%d)\n",rank(k,b));}
407 		*(ep++) = rank(k,b);
408 	    }
409 	}
410     }
411 }
412 
413 /**************************************************************************/
414 
415 static void
makecomplete(long n,boolean digraph,sparsegraph * sg)416 makecomplete(long n, boolean digraph, sparsegraph *sg)
417 {
418     int *d,*e,i,j;
419     size_t *v,k;
420 
421     if (n < 1 || n > NAUTY_INFINITY-2)
422         gt_abort(">E genspecialg: bad argument for -k\n");
423 
424     if (digraph) SG_ALLOC(*sg,n,n*(size_t)n,"genspecialg");
425     else         SG_ALLOC(*sg,n,n*(size_t)(n-1),"genspecialg");
426 
427     SG_VDE(sg,v,d,e);
428 
429     if (digraph)
430     {
431         sg->nv = n;
432 	sg->nde = n*(size_t)n;
433 
434 	for (i = 0, k = 0; i < n; ++i, k += n)
435 	{
436 	    d[i] = n;
437 	    v[i] = k;
438 	    for (j = 0; j < n; ++j) e[k+j] = j;
439         }
440     }
441     else
442     {
443         sg->nv = n;
444 	sg->nde = n*(size_t)(n-1);
445 
446 	for (i = 0, k = 0; i < n; ++i)
447 	{
448 	    d[i] = n-1;
449 	    v[i] = k;
450 	    for (j = 0; j < n; ++j)
451                if (j != i) e[k++] = j;
452         }
453     }
454 }
455 
456 /**************************************************************************/
457 
458 static void
makeempty(long n,boolean digraph,sparsegraph * sg)459 makeempty(long n, boolean digraph, sparsegraph *sg)
460 {
461     int *d,*e,i;
462     size_t *v;
463 
464     if (n < 1 || n > NAUTY_INFINITY-2)
465         gt_abort(">E genspecialg: bad argument for -e\n");
466 
467     if (digraph) SG_ALLOC(*sg,n,n,"genspecialg");
468     else         SG_ALLOC(*sg,n,0,"genspecialg");
469 
470     SG_VDE(sg,v,d,e);
471 
472     if (digraph)
473     {
474         sg->nv = n;
475 	sg->nde = n;
476 
477 	for (i = 0; i < n; ++i)
478 	{
479 	    d[i] = 1;
480 	    v[i] = i;
481 	    e[i] = i;
482         }
483     }
484     else
485     {
486         sg->nv = n;
487 	sg->nde = 0;
488 
489 	for (i = 0; i < n; ++i)
490 	{
491 	    d[i] = 0;
492 	    v[i] = 0;
493         }
494     }
495 }
496 
497 /**************************************************************************/
498 
499 static void
makehypercube(long deg,boolean digraph,sparsegraph * sg)500 makehypercube(long deg, boolean digraph, sparsegraph *sg)
501 {
502     int *d,*e,i,j;
503     size_t *v,k,nv;
504 
505     if (deg < 0 || deg > 30)
506         gt_abort(">E genspecialg: bad argument for -q\n");
507     if (digraph)
508         gt_abort(">E genspecialg: -zq is not implemented\n");
509 
510     nv = 1UL << deg;
511     SG_ALLOC(*sg,nv,deg*nv,"genspecialg");
512 
513     SG_VDE(sg,v,d,e);
514 
515     sg->nv = nv;
516     sg->nde = deg*nv;
517 
518     for (i = 0, k = 0; i < nv; ++i, k += deg)
519     {
520 	d[i] = deg;
521 	v[i] = k;
522 	for (j = 0; j < deg; ++j) e[k+j] = i ^ (1<<j);
523     }
524 }
525 
526 /**************************************************************************/
527 
528 static void
maketheta(long * len,int npaths,boolean digraph,sparsegraph * sg)529 maketheta(long *len, int npaths, boolean digraph, sparsegraph *sg)
530 {
531     int i,j,k,n,ntemp,*d,*e;
532     size_t *v,ne,etemp;
533     boolean hasone;
534 
535     hasone = FALSE;
536     n = 2;
537     ne = 0;
538     for (i = 0; i < npaths; ++i)
539     {
540 	if (len[i] < 1)
541 	    gt_abort(">E genspecialg: -T paths must be at least length 1\n");
542 	if (len[i] == 1)
543 	{
544 	    if (hasone) gt_abort(
545                   ">E genspecialg: -T only one path of length 1 allowed\n");
546 	    hasone = TRUE;
547 	}
548 	ntemp = n;
549 	n += len[i]-1;
550 	if (n < ntemp)
551 	    gt_abort(">E genspecialg: -T too many vertices\n");
552 	etemp = ne;
553 	ne += len[i];
554 	if (ne < etemp) gt_abort(">E genspecialg: -T too many edges\n");
555     }
556 
557     if (n > NAUTY_INFINITY-2)
558         gt_abort(">E genspecialg: -T size is too big\n");
559 
560     if (!digraph)
561     {
562 	etemp = ne;
563 	ne *= 2;
564 	if (ne < etemp) gt_abort(">E genspecialg: -T too many edges\n");
565     }
566 
567     SG_ALLOC(*sg,n,ne,"genspecialg");
568     SG_VDE(sg,v,d,e);
569     sg->nv = n;
570     sg->nde = ne;
571 
572     v[0] = 0;
573     v[1] = npaths;
574     if (digraph)
575     {
576 	v[2] = v[1];
577 	for (i = 3; i < n; ++i) v[i] = v[i-1] + 1;
578     }
579     else
580     {
581 	v[2] = v[1] + npaths;
582 	for (i = 3; i < n; ++i) v[i] = v[i-1] + 2;
583     }
584 
585     for (i = 0; i < n; ++i) d[i] = 0;
586 
587     if (hasone)
588     {
589 	e[v[0]+(d[0]++)] = 1;
590 	if (!digraph) e[v[1]+(d[1]++)] = 0;
591     }
592 
593     k = 2;
594     for (i = 0; i < npaths; ++i)
595     {
596 	if (len[i] == 1) continue;
597 
598 	e[v[0]+(d[0]++)] = k;
599 	if (!digraph) e[v[k]+(d[k]++)] = 0;
600 
601 	for (j = 0; j < len[i]-2; ++j)
602 	{
603 	    e[v[k]+(d[k]++)] = k+1;
604 	    if (!digraph) e[v[k+1]+(d[k+1]++)] = k;
605 	    ++k;
606 	}
607 	e[v[k]+(d[k]++)] = 1;
608 	if (!digraph) e[v[1]+(d[1]++)] = k;
609         ++k;
610     }
611 }
612 
613 /**************************************************************************/
614 
615 static void
makegrid(long * dim,int ndim,boolean digraph,sparsegraph * sg)616 makegrid(long *dim, int ndim, boolean digraph, sparsegraph *sg)
617 {
618     int *d,*e,i,j,deg,n,oldn;
619     size_t *v,k;
620     boolean closed[30];
621     int index[30];
622 
623     n = 1;
624     deg = 0;
625     for (i = 0; i < ndim; ++i)
626     {
627         if (dim[i] >= -1 && dim[i] <= 1)
628             gt_abort(">E genspecialg: -G dimensions must be at least 2\n");
629 	if (dim[i] == 2 && !digraph)
630             gt_abort(">E genspecialg: -G dimen 2 is only ok for digraphs\n");
631 
632 	closed[i] = (dim[i] > 0);
633 	if (dim[i] < 0) dim[i] = -dim[i];
634 
635 	oldn = n;
636         n *= dim[i];
637 	if (n < 0 || n / dim[i] != oldn)
638 	    gt_abort(">E genspecialg: -G size is too big\n");
639 
640 	if (digraph || dim[i] == 2) ++deg;
641         else                        deg += 2;
642 
643         index[i] = 0;
644     }
645 
646     if (n > NAUTY_INFINITY-2)
647         gt_abort(">E genspecialg: -G size is too big\n");
648 
649     SG_ALLOC(*sg,n,deg*(size_t)n,"genspecialg");
650 
651     SG_VDE(sg,v,d,e);
652 
653     sg->nv = n;
654     sg->nde = deg*(size_t)n;
655 
656     k = 0;
657     for (i = 0; i < n; ++i)
658     {
659 	v[i] = k;
660 	for (j = 0; j < ndim; ++j)
661 	{
662 	    if (index[j] < dim[j]-1)
663 	    {
664 		++index[j];
665 		e[k++] = vnumber(dim,index,ndim);
666 		--index[j];
667 	    }
668 	    if (!digraph && index[j] > 0)
669 	    {
670 		--index[j];
671 		e[k++] = vnumber(dim,index,ndim);
672 		++index[j];
673 	    }
674 	    if (closed[j] && index[j] == dim[j]-1)
675 	    {
676 		index[j] = 0;
677 		e[k++] = vnumber(dim,index,ndim);
678 		index[j] = dim[j]-1;
679 	    }
680 	    if (closed[j] && !digraph && index[j] == 0)
681 	    {
682 		index[j] = dim[j]-1;
683 		e[k++] = vnumber(dim,index,ndim);
684 		index[j] = 0;
685 	    }
686 	}
687 
688         d[i] = k - v[i];
689 
690 	for (j = ndim; --j >= 0;)
691 	{
692 	    if (index[j] != dim[j]-1)
693 	    {
694 		++index[j];
695 		break;
696 	    }
697 	    else
698 		index[j] = 0;
699 	}
700     }
701 }
702 
703 /**************************************************************************/
704 
705 static void
makecirculant(long n,long * conn,int nconn,boolean digraph,sparsegraph * sg)706 makecirculant(long n, long *conn, int nconn, boolean digraph, sparsegraph *sg)
707 {
708     int *d,*e,i,j,deg;
709     size_t *v,k;
710 
711     if (nconn > 0 && conn[0] <= 0)
712         gt_abort(">E genspecialg: -C connections must be nonzero\n");
713 
714     for (i = 1; i < nconn; ++i)
715 	if (conn[i] <= conn[i-1])
716 	    gt_abort(">E genspecialg: -C connections must be increasing\n");
717 
718     if (nconn == 0)
719 	deg = 0;
720     else
721     {
722         if (digraph)
723 	{
724 	    if (conn[nconn-1] >= n) gt_abort(
725                  ">E genspecialg: -C connections must be 1..n-1\n");
726 	    deg = nconn;
727 	}
728 	else
729         {
730             if (conn[nconn-1] > n/2) gt_abort(
731                  ">E genspecialg: -C connections must be 1..n/2\n");
732 	    deg = 2*nconn - (2*conn[nconn-1]==n);
733 	}
734     }
735 
736     SG_ALLOC(*sg,n,deg*n,"genspecialg");
737 
738     SG_VDE(sg,v,d,e);
739     sg->nv = n;
740     sg->nde = deg*n;
741 
742     for (i = 0; i < n; ++i)
743     {
744         d[i] = deg;
745 	v[i] = deg*(size_t)i;
746     }
747 
748     for (i = 0; i < n; ++i)
749     {
750 	k = v[i];
751 	for (j = 0; j < nconn; ++j)
752 	{
753 	    e[k++] = (i + conn[j]) % n;
754 	    if (!digraph && 2*conn[j] != n)
755 		e[k++] = (i - conn[j] + n) % n;
756 	}
757     }
758 }
759 
760 /**************************************************************************/
761 
762 static void
makegenpetersen(long n1,long n2,boolean digraph,sparsegraph * sg)763 makegenpetersen(long n1, long n2, boolean digraph, sparsegraph *sg)
764 {
765     int *d,*e,i,n;
766     size_t *v,k;
767 
768     if (digraph) gt_abort(">E no digraph version of -P is implemented\n");
769 
770     n = 2*n1;
771     if (n < 1 || n1 > NAUTY_INFINITY/2-1 || n2 < 1 || 2*n2 >= n1)
772 	gt_abort(">E -Pm,k needs m>0,0<k<m/2; or m too large\n");
773 
774     SG_ALLOC(*sg,n,3UL*n,"genspecialg");
775 
776     SG_VDE(sg,v,d,e);
777     sg->nv = n;
778     sg->nde = 3UL*n;
779 
780     for (i = 0; i < n; ++i)
781     {
782         d[i] = 3;
783 	v[i] = 3UL*i;
784     }
785 
786     for (i = 0; i < n1; ++i)
787     {
788 	k = v[i];
789 	e[k] = (i + 1) % n1;
790 	e[k+1] = (i + n1 - 1) % n1;
791 	e[k+2] = i + n1;
792     }
793 
794     for (i = 0; i < n1; ++i)
795     {
796 	k = v[n1+i];
797 	e[k] = n1 + (i + n2) % n1;
798         e[k+1] = n1 + (i - n2 + n1) % n1;
799 	e[k+2] = i;
800     }
801 }
802 
803 /**************************************************************************/
804 
805 static void
makecompletebipartite(long n1,long n2,long matching,boolean digraph,sparsegraph * sg)806 makecompletebipartite(long n1, long n2,
807                       long matching, boolean digraph, sparsegraph *sg)
808 {
809     int *d,*e,i,j,jmissing,n;
810     size_t *v,k;
811 
812     n = n1 + n2;
813     if (matching > n1 || matching > n2)
814 	gt_abort(">E genspecialg: matching too large\n");
815 
816     if (n1 < 1 || n2 < 1 || n > NAUTY_INFINITY-2)
817         gt_abort(">E genspecialg: bad argument for -b\n");
818 
819     if (digraph) SG_ALLOC(*sg,n,n1*n2,"genspecialg");
820     else         SG_ALLOC(*sg,n,2*n1*n2,"genspecialg");
821 
822     SG_VDE(sg,v,d,e);
823 
824     if (digraph)
825     {
826 	sg->nv = n;
827 	sg->nde = n1*n2 - matching;
828 
829 	for (i = 0, k = 0; i < n1; ++i)
830 	{
831 	    v[i] = k;
832 	    jmissing = (i < matching ? n1+i : -1);
833 	    for (j = n1; j < n; ++j) if (j != jmissing) e[k++] = j;
834 	    d[i] = k - v[i];
835 	}
836 	for (i = n1; i < n; ++i)
837 	{
838 	    d[i] = 0;
839 	    v[i] = k;
840         }
841     }
842     else
843     {
844 	sg->nv = n;
845 	sg->nde = 2*(n1*n2 - matching);
846 
847 	for (i = 0, k = 0; i < n1; ++i)
848 	{
849 	    v[i] = k;
850             jmissing = (i < matching ? n1+i : -1);
851 	    for (j = n1; j < n; ++j) if (j != jmissing) e[k++] = j;
852 	    d[i] = k - v[i];
853 	}
854 	for (i = n1; i < n; ++i)
855 	{
856 	    v[i] = k;
857 	    jmissing = (i < n1+matching ? i-n1 : -1);
858 	    for (j = 0; j < n1; ++j) if (j != jmissing) e[k++] = j;
859 	    d[i] = k - v[i];
860         }
861     }
862 }
863 
864 /**************************************************************************/
865 
866 int
main(int argc,char * argv[])867 main(int argc, char *argv[])
868 {
869     int codetype;
870     int argnum,j;
871     char *arg,sw;
872     boolean badargs,quiet;
873     boolean Cswitch,Pswitch,gswitch,sswitch,zswitch,Jswitch,dswitch;
874     boolean pswitch,cswitch,eswitch,kswitch,bswitch,Qswitch,Gswitch;
875     boolean fswitch,Tswitch,verbose,havegraph,dreadnaut;
876     long size;
877     static FILE *outfile;
878     char *outfilename;
879     sparsegraph sg;
880     long Pargs[2],bargs[3],Jargs[2];
881     int nPargs,nbargs,nCargs,nGargs,nJargs,nTargs;
882     int numgraphs;
883     HELP; PUTVERSION;
884 
885     numgraphs = 0;
886 
887     gswitch = sswitch = zswitch = Pswitch = FALSE;
888     pswitch = cswitch = eswitch = kswitch = FALSE;
889     Gswitch = Cswitch = bswitch = Qswitch = verbose = FALSE;
890     dswitch = Jswitch = fswitch = Tswitch = quiet = FALSE;
891 
892     outfilename = NULL;
893 
894     argnum = 0;
895     badargs = FALSE;
896     for (j = 1; !badargs && j < argc; ++j)
897     {
898         arg = argv[j];
899         if (arg[0] == '-' && arg[1] != '\0')
900         {
901             ++arg;
902             while (*arg != '\0')
903             {
904                 sw = *arg++;
905                      SWBOOLEAN('g',gswitch)
906                 else SWBOOLEAN('s',sswitch)
907                 else SWBOOLEAN('z',zswitch)
908                 else SWBOOLEAN('d',dswitch)
909                 else SWBOOLEAN('q',quiet)
910                 else SWBOOLEAN('v',verbose)
911                 else SWLONG('p',pswitch,size,"genspecialg -p")
912 		else SWLONG('c',cswitch,size,"genspecialg -c")
913                 else SWLONG('e',eswitch,size,"genspecialg -e")
914                 else SWLONG('k',kswitch,size,"genspecialg -k")
915                 else SWLONG('f',fswitch,size,"genspecialg -f")
916 		else SWLONG('Q',Qswitch,size,"genspecialg -Q")
917 		else SWSEQUENCEMIN('b',",",bswitch,bargs,2,3,nbargs,"genspecialg -b")
918                 else SWSEQUENCEMIN('J',",",Jswitch,Jargs,2,2,nJargs,"genspecialg -J")
919                 else SWSEQUENCEMIN('P',",",Pswitch,Pargs,2,2,nPargs,"genspecialg -P")
920                 else SWSEQUENCEMIN('C',",",Cswitch,args,
921                                         1,MAXARGS,nCargs,"genspecialg -C")
922                 else SWSEQUENCE('G',",",Gswitch,args,30,nGargs,"genspecialg -G")
923                 else SWSEQUENCE('T',",",Tswitch,args,MAXARGS,
924                                 nTargs,"genspecialg -T")
925                 else badargs = TRUE;
926             }
927         }
928         else
929         {
930             ++argnum;
931             if (argnum == 1) outfilename = arg;
932             else             badargs = TRUE;
933         }
934     }
935 
936     if ((gswitch!=0) + (sswitch!=0) + (zswitch!=0) > 1)
937         gt_abort(">E genspecialg: -gsz are incompatible\n");
938 
939     if ((gswitch!=0) + (sswitch!=0) + (dswitch!=0) > 1)
940         gt_abort(">E genspecialg: -gsd are incompatible\n");
941 
942     if (badargs)
943     {
944         fprintf(stderr,">E Usage: %s\n",USAGE);
945         GETHELP;
946         exit(1);
947     }
948 
949     if (gswitch)      codetype = GRAPH6;
950     else if (zswitch) codetype = DIGRAPH6;
951     else              codetype = SPARSE6;
952     dreadnaut = dswitch;
953 
954     if (!outfilename || outfilename[0] == '-')
955     {
956         outfilename = "stdout";
957         outfile = stdout;
958     }
959     else if ((outfile = fopen(outfilename,"w")) == NULL)
960     {
961         fprintf(stderr,"Can't open output file %s\n",outfilename);
962         gt_abort(NULL);
963     }
964 
965     SG_INIT(sg);
966 
967     argnum = 0;
968     badargs = havegraph = FALSE;
969     for (j = 1; !badargs && j < argc; ++j)
970     {
971         arg = argv[j];
972         if (arg[0] == '-' && arg[1] != '\0')
973         {
974             ++arg;
975             while (*arg != '\0')
976             {
977                 sw = *arg++;
978                      SWBOOLEAN('g',gswitch)
979                 else SWBOOLEAN('s',sswitch)
980                 else SWBOOLEAN('z',zswitch)
981                 else SWBOOLEAN('d',dswitch)
982                 else SWBOOLEAN('q',quiet)
983 		else SWBOOLEAN('v',verbose)
984                 else if (sw == 'p')
985 		{
986 		    SWLONG('p',pswitch,size,"genspecialg -p")
987             	    makepath(size,zswitch,&sg);
988 		    havegraph = TRUE;
989 		}
990                 else if (sw == 'c')
991 		{
992 		    SWLONG('c',cswitch,size,"genspecialg -c")
993             	    makecycle(size,zswitch,&sg);
994 		    havegraph = TRUE;
995 		}
996                 else if (sw == 'e')
997 		{
998 		    SWLONG('e',eswitch,size,"genspecialg -e")
999             	    makeempty(size,zswitch,&sg);
1000 		    havegraph = TRUE;
1001 		}
1002                 else if (sw == 'k')
1003 		{
1004 		    SWLONG('k',kswitch,size,"genspecialg -k")
1005             	    makecomplete(size,zswitch,&sg);
1006 		    havegraph = TRUE;
1007 		}
1008                 else if (sw == 'f')
1009 		{
1010 		    SWLONG('f',fswitch,size,"genspecialg -f")
1011     	            makeflowersnark(size,zswitch,&sg);
1012 		    havegraph = TRUE;
1013 		}
1014                 else if (sw == 'Q')
1015 		{
1016 		    SWLONG('Q',Qswitch,size,"genspecialg -Q")
1017                     makehypercube(size,zswitch,&sg);
1018 		    havegraph = TRUE;
1019 		}
1020                 else if (sw == 'b')
1021 		{
1022 		    SWSEQUENCEMIN('b',",",bswitch,bargs,2,3,nbargs,"genspecialg -b")
1023                     makecompletebipartite(bargs[0],bargs[1],
1024                            (nbargs==2?0:bargs[2]),zswitch,&sg);
1025 		    havegraph = TRUE;
1026 		}
1027                 else if (sw == 'J')
1028 		{
1029 		    SWSEQUENCEMIN('J',",",Jswitch,Jargs,2,2,nJargs,"genspecialg -J")
1030                     makeJohnson(Jargs[0],Jargs[1],zswitch,&sg);
1031 		    havegraph = TRUE;
1032 		}
1033                 else if (sw == 'P')
1034 		{
1035 		    SWSEQUENCEMIN('P',",",Pswitch,Pargs,2,2,nPargs,"genspecialg -P")
1036             	    makegenpetersen(Pargs[0],Pargs[1],zswitch,&sg);
1037 		    havegraph = TRUE;
1038 		}
1039                 else if (sw == 'C')
1040 		{
1041 		    SWSEQUENCEMIN('C',",",Cswitch,args,
1042                                         1,MAXARGS,nCargs,"genspecialg -C")
1043             	    makecirculant(args[0],args+1,nCargs-1,zswitch,&sg);
1044 		    havegraph = TRUE;
1045 		}
1046                 else if (sw == 'G')
1047 		{
1048 		    SWSEQUENCEMIN('G',",",Gswitch,args,2,30,nGargs,"genspecialg -G")
1049                     makegrid(args,nGargs,zswitch,&sg);
1050 		    havegraph = TRUE;
1051 		}
1052                 else if (sw == 'T')
1053 		{
1054 		    SWSEQUENCEMIN('T',",",Tswitch,args,MAXARGS,
1055                                 1,nTargs,"genspecialg -T")
1056             	    maketheta(args,nTargs,zswitch,&sg);
1057 		    havegraph = TRUE;
1058 		}
1059 
1060 	 	if (havegraph)
1061 		{
1062         	    sortlists_sg(&sg);
1063         	    if (dreadnaut)                 writedread(outfile,&sg,zswitch);
1064         	    else if (codetype == GRAPH6)   writeg6_sg(outfile,&sg);
1065         	    else if (codetype == DIGRAPH6) writed6_sg(outfile,&sg);
1066         	    else                           writes6_sg(outfile,&sg);
1067 		    ++numgraphs;
1068 		    havegraph = FALSE;
1069 
1070 		    if (verbose)
1071         	        fprintf(stderr,"Graph %d: %d vertices %lu edges\n",numgraphs,
1072 		           sg.nv,(unsigned long)(zswitch ? sg.nde : sg.nde/2));
1073 		}
1074             }
1075         }
1076         else
1077         {
1078             ++argnum;
1079         }
1080     }
1081 
1082     if (!quiet)
1083         fprintf(stderr,">Z %d graphs written to %s\n",numgraphs,outfilename);
1084 
1085     exit(0);
1086 }
1087