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