CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

| Download

GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it

Views: 418346
1
2
/**************************************************************************
3
4
postproc.c
5
Colin Ramsay ([email protected])
6
2 Mar 01
7
8
ADVANCED COSET ENUMERATOR, Version 3.001
9
10
Copyright 2000
11
Centre for Discrete Mathematics and Computing,
12
Department of Mathematics and
13
Department of Computer Science & Electrical Engineering,
14
The University of Queensland, QLD 4072.
15
(http://staff.itee.uq.edu.au/havas)
16
17
This is the post (enumeration) processing stuff for stand-alone ACE. Note
18
that many of the routines here could be considered as Level 0 or Level 1
19
functions, since they perform general-purpose table manipulations; however,
20
some of them use Level 2's error-handler, so they couldn't be moved as they
21
stand to a lower level. They have been written to be as versatile and as
22
`robust' as possible, although Level 2 may not take full advantage of this.
23
24
**************************************************************************/
25
26
#include "al2.h"
27
28
#include <ctype.h>
29
30
/******************************************************************
31
void al2_oo(int arg)
32
33
Find cosets with order a multiple of |arg|, modulo the subgroup.
34
If arg=0, print all orders. Otherwise, print the first (arg>0) or
35
all (arg<0) coset numbers with order a multiple of |arg|, along
36
with their reps.
37
******************************************************************/
38
39
void al2_oo(int arg)
40
{
41
int i,j,k, aarg, ord;
42
Logic found;
43
44
if (arg < 0)
45
{ aarg = -arg; }
46
else
47
{ aarg = arg; }
48
49
found = FALSE;
50
for (i = 2; i < nextdf; i++)
51
{
52
if (COL1(i) >= 0)
53
{
54
if (al1_bldrep(i))
55
{
56
if ((ord = al1_ordrep()) == 0)
57
{ continue; }
58
if ((arg == 0) || (ord%aarg == 0))
59
{
60
if (!found)
61
{
62
found = TRUE;
63
fprintf(fop, " coset | order rep\n");
64
fprintf(fop, "--------+------------\n");
65
}
66
67
fprintf(fop, "%7d | %6d ", i, ord);
68
for (j = 0; j < repsiz; j++)
69
{
70
k = colgen[currrep[j]]; /* generator number */
71
if (!galpha)
72
{ fprintf(fop, "%d ", k); }
73
else
74
{ fprintf(fop, "%c",
75
(k > 0) ? algen[k] : toupper(algen[-k])); }
76
}
77
fprintf(fop, "\n");
78
79
if ((arg > 0) && (ord%aarg == 0))
80
{ break; }
81
}
82
}
83
else
84
{ al2_continue("unable to build coset rep've"); }
85
}
86
}
87
88
if (!found)
89
{ fprintf(fop, "* Nothing found\n"); }
90
}
91
92
/******************************************************************
93
Logic al2_normal(int cos)
94
95
Coset cos is normalising if for the subgroup H = <w_1,...,w_s>,
96
then cos*w_j = cos (for all j=1...s). Return T if this is the
97
case, else F (incl. out-of-range/redundant).
98
99
Warning: this routine traces thro the subgrp gens, using the
100
enumerator's data structure. Thus, it can only be used if the
101
al1_start() routine has been called & nsgpg has *not* been altered.
102
Similar remarks apply to al2_normcl().
103
******************************************************************/
104
105
Logic al2_normal(int cos)
106
{
107
int s, *beg, *end, *pi, next;
108
109
if (cos < 1 || cos >= nextdf || COL1(cos) < 0)
110
{ return(FALSE); }
111
112
for (s = 1; s <= nsgpg; s++)
113
{
114
beg = &(subggen[subgindex[s]]);
115
end = beg-1 + subglength[s];
116
117
next = cos;
118
for (pi = beg; pi <= end; pi++)
119
{
120
if ((next = CT(next,*pi)) == 0 || COL1(next) < 0)
121
{ return(FALSE); }
122
}
123
if (next != cos)
124
{ return(FALSE); }
125
}
126
127
return(TRUE);
128
}
129
130
/******************************************************************
131
void al2_sc(int arg)
132
133
Print the stabilising cosets of the subgrp. arg>0 prints the first
134
arg of them, arg<0 prints the first |arg| + reps, and arg=0 prints
135
all of them + reps.
136
******************************************************************/
137
138
void al2_sc(int arg)
139
{
140
int i,j,k, aarg;
141
Logic found;
142
143
if (arg < 0)
144
{ aarg = -arg; }
145
else
146
{ aarg = arg; }
147
148
found = FALSE;
149
for (i = 2; i < nextdf; i++)
150
{
151
if (COL1(i) >= 0)
152
{
153
if (al2_normal(i))
154
{
155
if (!found)
156
{
157
found = TRUE;
158
if (arg <= 0)
159
{ fprintf(fop, "Stabilising cosets (+ reps):\n"); }
160
else
161
{ fprintf(fop, "Stabilising cosets:\n"); }
162
}
163
164
fprintf(fop, "%7d", i);
165
if (arg <= 0)
166
{
167
if (!al1_bldrep(i))
168
{ al2_continue("unable to build coset rep've"); }
169
fprintf(fop, " ");
170
for (j = 0; j < repsiz; j++)
171
{
172
k = colgen[currrep[j]];
173
if (!galpha)
174
{ fprintf(fop, "%d ", k); }
175
else
176
{ fprintf(fop, "%c",
177
(k > 0) ? algen[k] : toupper(algen[-k])); }
178
}
179
}
180
fprintf(fop, "\n");
181
182
if ((aarg != 0) && (--aarg == 0))
183
{ break; }
184
}
185
}
186
}
187
188
if (!found)
189
{ fprintf(fop, "* Nothing found\n"); }
190
}
191
192
/******************************************************************
193
void al2_cycles(void)
194
195
Print out the coset table in cycles (permutation representation).
196
This *must* only be called when a completed *and* compacted coset
197
table is present; ie, when a finite index has been computed & a
198
(final) CO phase has been run. The dispatcher code in parser.c
199
enforces this. Note the use of the sign bit to track processed
200
cosets for each generator.
201
202
ToDo: what about faithfulness?!
203
******************************************************************/
204
205
void al2_cycles(void)
206
{
207
int i, j, k, kn, t, length;
208
Logic id;
209
210
for (j = 1; j <= ndgen; j++)
211
{
212
k = gencol[ndgen+j]; /* find the column k for generator j */
213
id = TRUE; /* assume action is the identity */
214
215
if (!galpha) /* print lhs & record its length */
216
{
217
fprintf(fop, "%d = ", j);
218
length = al2_outlen(j) + 3;
219
}
220
else
221
{
222
fprintf(fop, "%c = ", algen[j]);
223
length = 4;
224
}
225
226
for (i = 1; i <= nalive; i++)
227
{
228
if (CT(i, k) == i) /* skip if i is a one-cycle */
229
{
230
CT(i, k) = -i;
231
continue;
232
}
233
234
/* have we used coset i in previous cycle? */
235
236
if (CT((kn = i), k) < 0)
237
{ continue; }
238
239
id = FALSE; /* action of generator not identity */
240
241
/* no, trace out this cycle */
242
243
length += al2_outlen(kn) + 1;
244
if (length < LLL)
245
{ fprintf(fop, "(%d", kn); }
246
else
247
{
248
fprintf(fop, "\n (%d", kn);
249
length = al2_outlen(kn) + 3;
250
}
251
252
t = CT(kn, k);
253
CT(kn, k) = -t; /* mark this coset as used */
254
kn = t;
255
256
while (CT(kn,k) > 0)
257
{
258
length += al2_outlen(kn) + 1;
259
if (length < LLL)
260
{ fprintf(fop, ",%d", kn); }
261
else
262
{
263
fprintf(fop, ",\n %d", kn);
264
length = al2_outlen(kn) + 2;
265
}
266
267
t = CT(kn, k);
268
CT(kn, k) = -t;
269
kn = t;
270
}
271
272
/* we have reached the end of the cycle */
273
274
fprintf(fop, ")");
275
length++;
276
}
277
278
if (id)
279
{ fprintf(fop, "identity\n"); }
280
else
281
{ fprintf(fop, "\n"); }
282
283
/* change all the (negative) values in this column back to positive */
284
285
for (i = 1; i <= nalive; i++)
286
{ CT(i, k) = -CT(i, k); }
287
}
288
}
289
290
/******************************************************************
291
void al2_normcl(Logic build)
292
293
Check normal closure. Trace g^-1 * w * g and g * w * g^-1 for all
294
group generators g and all subgroup generator words w, noting
295
whether we get back to coset 1 or not. Note that 1.w^g = 1 iff
296
1.Gwg = 1 iff 1.Gw = 1.G (hence the apparent switch in the sense of
297
first when we set it). If build is T, then the conjugates of subgroup
298
generators by group generators that cannot be traced to the subgroup
299
are added to the list of subgroup generators; the *user* has to rerun
300
the enumeration. Note that coset #1 is never redundant; however,
301
others may be, and the table may be incomplete.
302
303
Note: if g has a finite order, say n, then G=g^{n-1}. So either
304
both or neither of gwG and Gwg are in the subgroup (ie, we need
305
check only one). However, g may have infinite/unknown order so,
306
in general, we have to check both.
307
308
Remark: we choose to ignore those g/w pairs where the trace does
309
not complete. It could be argued that we should include them in
310
the list of added conjugates (as ACE2 did). If we did, this would
311
require definitions to be made during the rerun of the SG phase.
312
By including only those pairs which do trace, but not to 1, we
313
effectively introduce coincidences.
314
******************************************************************/
315
316
void al2_normcl(Logic build)
317
{
318
int col, first, next, s, *beg, *end, *pi, j,k,l;
319
Logic found;
320
Wlist *list;
321
Wlelt *lelt;
322
323
found = FALSE;
324
list = NULL;
325
326
for (col = 1; col <= ncol; col++) /* all `significant' gen'rs */
327
{
328
if ((first = CT(1,invcol[col])) == 0 || COL1(first) < 0)
329
{ continue; } /* trace incomplete, next col */
330
331
for (s = 1; s <= nsgpg; s++) /* all (original) subgrp gens */
332
{
333
beg = &subggen[subgindex[s]];
334
end = beg-1 + subglength[s];
335
336
next = first;
337
for (pi = beg; pi <= end; pi++)
338
{
339
if ((next = CT(next,*pi)) == 0 || COL1(next) < 0)
340
{ goto next_s; } /* trace incomplete, next gen */
341
}
342
if (next == first)
343
{ continue; } /* closes, next gen */
344
345
/* At this point, we know that the trace of s^col completes but does
346
not get back to 1. So we have a conjugate that's not in the subgrp. */
347
348
found = TRUE; /* at least 1 conjugate not in sgp */
349
350
k = colgen[col]; /* (signed) generator number */
351
if (!galpha)
352
{
353
fprintf(fop, "Conjugate by grp gen'r \"%d\" of", k);
354
fprintf(fop, " subgrp gen'r \"");
355
for (pi = beg; pi <= end; pi++)
356
{ fprintf(fop, " %d", colgen[*pi]); }
357
}
358
else
359
{
360
fprintf(fop, "Conjugate by grp gen'r \"%c\" of",
361
(k > 0) ? algen[k] : toupper(algen[-k]));
362
fprintf(fop, " subgrp gen'r \"");
363
for (pi = beg; pi <= end; pi++)
364
{
365
if ((l = colgen[*pi]) > 0)
366
{ fprintf(fop, "%c", algen[l]); }
367
else
368
{ fprintf(fop, "%c", toupper(algen[-l])); }
369
}
370
}
371
fprintf(fop, "\" not in subgrp\n");
372
373
if (build)
374
{
375
if (list == NULL)
376
{
377
if ((list = al1_newwl()) == NULL)
378
{ al2_continue("unable to create new subgrp gen'r list"); }
379
}
380
381
if ((lelt = al1_newelt()) == NULL)
382
{
383
al1_emptywl(list);
384
free(list);
385
al2_continue("unable to create subgrp gen'r list elt");
386
}
387
388
lelt->len = subglength[s] + 2; /* gen'r + col/col^-1 */
389
if ((lelt->word = (int*)malloc((lelt->len+1)*sizeof(int))) == NULL)
390
{
391
al1_emptywl(list);
392
free(list);
393
free(lelt);
394
al2_continue("unable to create subgrp gen'r list elt word");
395
}
396
lelt->exp = 1;
397
398
lelt->word[1] = -k;
399
for (pi = beg, j = 2; pi <= end; pi++, j++)
400
{ lelt->word[j] = colgen[*pi]; }
401
lelt->word[lelt->len] = k;
402
403
al1_addwl(list,lelt);
404
}
405
406
next_s:
407
;
408
}
409
}
410
411
if (!found)
412
{ fprintf(fop, "* All (traceable) conjugates in subgroup\n"); }
413
414
/* If list != NULL then we must have created a list with at least one new
415
subgrp gen'r; so found is T & genlst is non-NULL/non-empty! Append the
416
list of new gen'rs & update the enumeration status. */
417
418
if (list != NULL)
419
{
420
al1_concatwl(genlst,list);
421
422
nsgpg = genlst->len;
423
424
okcont = FALSE;
425
tabinfo = tabindex = FALSE;
426
427
fprintf(fop, "* Subgroup generators have been augmented\n");
428
}
429
}
430
431
/******************************************************************
432
void al2_cc(int cos)
433
434
cos is guaranteed (by the caller) to be a non-redundant coset in
435
the range 2..nextdf-1. Get its rep & add it to the subgroup gens.
436
******************************************************************/
437
438
void al2_cc(int cos)
439
{
440
int i,j;
441
Wlelt *lelt;
442
443
/* Build & printout the representative */
444
445
if (!al1_bldrep(cos))
446
{ al2_continue("unable to build rep've"); }
447
448
fprintf(fop, "Coset #%d: ", cos);
449
for (i = 0; i < repsiz; i++)
450
{
451
j = colgen[currrep[i]];
452
if (!galpha)
453
{ fprintf(fop, "%d ", j); }
454
else
455
{ fprintf(fop, "%c", (j > 0) ? algen[j] : toupper(algen[-j])); }
456
}
457
fprintf(fop, "\n");
458
459
/* Add the rep to the subgroup generators */
460
461
if ((lelt = al1_newelt()) == NULL)
462
{ al2_continue("unable to create new subgrp gen'r"); }
463
464
lelt->len = repsiz;
465
if ((lelt->word = (int*)malloc((lelt->len+1)*sizeof(int))) == NULL)
466
{
467
free(lelt);
468
al2_continue("unable to create subgrp gen'r word");
469
}
470
lelt->exp = 1;
471
472
for (i = 0; i < repsiz; i++)
473
{ lelt->word[i+1] = colgen[currrep[i]]; }
474
475
/* Add the new element to the (possibly non-existent) gen list */
476
477
if (genlst == NULL)
478
{
479
if ((genlst = al1_newwl()) == NULL)
480
{
481
free(lelt->word);
482
free(lelt);
483
al2_continue("unable to create subgrp gen'r list");
484
}
485
}
486
al1_addwl(genlst,lelt);
487
nsgpg++;
488
489
/* Reset enumeration status & `remind' the user */
490
491
okcont = FALSE;
492
tabinfo = tabindex = FALSE;
493
494
fprintf(fop, "* Subgroup generators have been augmented\n");
495
}
496
497
/******************************************************************
498
void al2_rc(int desire, int count)
499
500
Try to find a nontrival subgroup with index a multiple of a desired
501
index `desire' by repeatedly putting randomly chosen cosets
502
coincident with coset 1 and seeing what happens. The special value
503
desire=0 accepts *any* non-trivial finite index, while desire=1
504
accepts *any* finite index. We use the (not very good, but ok for
505
our purposes) random number generator rand(), which returns numbers
506
in the range 0..32767 (ie, lower 15 bits). We take care to ensure
507
that we generate a `valid' coset to set coincident with #1. If an
508
attempt fails, we restore the original subgrp gens, rerun the
509
original enumeration, and try again (making up to count attempts in
510
all). We use the asis flag to prevent subgroup generator
511
reordering, so that we can easily blow away the added generators.
512
513
Notes:
514
(i) This routine presupposes that an enumeration has already been
515
performed (this may or may not have yielded a finite index). The
516
presentation and all the control parameters (apart from asis) are
517
frozen at their current values during this call; only the subgroup
518
generator list is altered. Any redo (or start) calls to the
519
enumerator use the current settings, including any messaging.
520
(ii) This routine can take a *long* time.
521
(iii) On success, the presentation/table reflects the discovered
522
subgroup. On failure, it reflects the original status.
523
(iv) We try hard to ensure that the system is always left in a
524
consistent state, and that all errors are picked up. However, it
525
is *strongly* recommended that a positive result is checked (by
526
doing a complete enumeration), and that nothing is assumed about
527
the presentation/table on a negative result or on an error (note
528
that the call to al2_cc() could cause an error return).
529
(v) Note that the value of cos, before it is reduced modulo nextdf,
530
is limited to 30 bits (ie, 0..1073741823).
531
******************************************************************/
532
533
void al2_rc(int desire, int count)
534
{
535
int r1, r2, cos, old, i, cnt;
536
Logic tmp;
537
Wlelt *p, *q;
538
539
/* Record current status; asis flag & subgrp gen list */
540
541
tmp = asis;
542
asis = TRUE;
543
old = nsgpg;
544
545
for (cnt = 1; cnt <= count; cnt++) /* Try up to count times */
546
{
547
fprintf(fop, "* Attempt %d ...\n", cnt);
548
549
while (TRUE) /* Try until success / too small */
550
{
551
do
552
{
553
r1 = rand();
554
r2 = rand();
555
cos = ((r1 << 15) + r2)%nextdf;
556
}
557
while (cos < 2 || COL1(cos) < 0);
558
559
al2_cc(cos);
560
561
/* This chunk of code, for redo, is pinched from the parser */
562
563
al1_rslt(lresult = al1_start(2));
564
565
if (lresult > 0 && sgdone)
566
{
567
okcont = TRUE;
568
tabinfo = tabindex = TRUE;
569
}
570
else if (lresult >= -259 && sgdone)
571
{
572
okcont = TRUE;
573
tabinfo = TRUE;
574
tabindex = FALSE;
575
}
576
else
577
{
578
okcont = FALSE;
579
tabinfo = tabindex = FALSE;
580
}
581
if (lresult < -260)
582
{ okredo = FALSE; }
583
584
/* Try and sort out what happened! */
585
586
if (!(okcont && okredo && tabinfo))
587
{
588
asis = tmp;
589
al2_restart("* An unknown problem has occurred");
590
}
591
592
if (desire == 0)
593
{
594
if (tabindex && lresult > 1)
595
{
596
fprintf(fop, "* An appropriate subgroup has been found\n");
597
asis = tmp;
598
return;
599
}
600
if (tabindex && lresult == 1)
601
{ goto restore; }
602
}
603
else
604
{
605
if (tabindex && lresult%desire == 0)
606
{
607
fprintf(fop, "* An appropriate subgroup has been found\n");
608
asis = tmp;
609
return;
610
}
611
if (tabindex && lresult < desire)
612
{ goto restore; }
613
}
614
};
615
616
/* Setup for another attempt */
617
618
restore:
619
620
fprintf(fop, "* Recalculating original table\n");
621
622
/* Remove added subgroup generators (of which there is at least 1) */
623
624
if (old == 0)
625
{
626
al1_emptywl(genlst);
627
nsgpg = 0;
628
}
629
else
630
{
631
for (i = 1, p = genlst->first; i < old; i++, p = p->next)
632
{ ; }
633
634
q = p->next; /* Points to first added generator */
635
636
genlst->last = p;
637
genlst->last->next = NULL;
638
genlst->len = nsgpg = old;
639
640
for (p = q; p != NULL; )
641
{
642
q = p->next;
643
644
if (p->word != NULL)
645
{ free(p->word); }
646
free(p);
647
648
p = q;
649
}
650
}
651
652
/* Rerun the (original) enumeration (using code pinched from the
653
parser), and then try to sort out what happened. */
654
655
al1_rslt(lresult = al1_start(0));
656
657
if (lresult > 0 && sgdone)
658
{
659
okcont = okredo = TRUE;
660
tabinfo = tabindex = TRUE;
661
}
662
else if (lresult >= -259 && sgdone)
663
{
664
okcont = okredo = TRUE;
665
tabinfo = TRUE;
666
tabindex = FALSE;
667
}
668
else
669
{
670
okcont = okredo = FALSE;
671
tabinfo = tabindex = FALSE;
672
}
673
674
if (!(okcont && okredo && tabinfo))
675
{
676
asis = tmp;
677
al2_restart("* An unknown problem has occurred");
678
}
679
680
if (desire == 0)
681
{
682
if (tabindex && lresult > 1)
683
{
684
fprintf(fop, "* The original subgroup is appropriate!\n");
685
asis = tmp;
686
return;
687
}
688
}
689
else
690
{
691
if (tabindex && lresult%desire == 0)
692
{
693
fprintf(fop, "* The original subgroup is appropriate!\n");
694
asis = tmp;
695
return;
696
}
697
}
698
699
if (tabindex && lresult == 1)
700
{
701
asis = tmp;
702
al2_restart("* Unable to restore original status");
703
}
704
if (desire >= nalive)
705
{
706
asis = tmp;
707
al2_restart("* Unable to restore original status");
708
}
709
};
710
711
/* Our efforts failed. The last time through the outer loop restored the
712
original subgrp gens & table, so just restore asis & print a message. */
713
714
fprintf(fop, "* No success; original status restored\n");
715
asis = tmp;
716
}
717
718
/******************************************************************
719
void al2_dw(Wlist *p)
720
721
Delete the list of words given by intarr[] from the word list p.
722
Both intarr[] & *p are guaranteed to be non-empty.
723
******************************************************************/
724
725
void al2_dw(Wlist *p)
726
{
727
int i,j;
728
Wlelt *old, *tmp;
729
730
/* Check the 1st value, and then ensure that (any) others are strictly
731
increasing and don't exceed the list length. */
732
733
if (intarr[0] < 1 || intarr[0] > p->len)
734
{ al2_continue("first argument out of range"); }
735
for (i = 1; i < intcnt; i++)
736
{
737
if (intarr[i] <= intarr[i-1] || intarr[i] > p->len)
738
{ al2_continue("bad argument list"); }
739
}
740
741
/* Trace through the list, `moving' the required words & dropping those
742
not required (freeing their space). */
743
744
old = p->first; /* Start at front of old list ... */
745
i = 0;
746
747
j = 0; /* First deletion is position intarr[0] */
748
749
p->first = p->last = NULL; /* Clear `new' list ... */
750
p->len = 0;
751
752
while (old != NULL)
753
{
754
tmp = old; /* `Chop' head of old list off */
755
old = old->next;
756
i++; /* Current position */
757
758
if (i == intarr[j]) /* Delete this one */
759
{
760
if (tmp->word != NULL)
761
{ free(tmp->word); }
762
free(tmp);
763
764
j++;
765
}
766
else /* Keep this one */
767
{
768
if (p->first == NULL)
769
{ p->first = tmp; }
770
else
771
{ p->last->next = tmp; }
772
tmp->next = NULL;
773
p->last = tmp;
774
p->len++;
775
}
776
}
777
}
778
779
/**************************************************************************
780
The stuff under here is all concerned with testing various equivalent
781
presentations; either doing a random selection thereof, or all of them. It
782
is guaranteed that the (top-level) routines are only called if the relator
783
list is non-empty. The code here is all very naive, but there is little
784
point in trying to be clever/efficient. Note that, no matter how we
785
cycle/invert/permute the relators, the data attached to each word (ie, its
786
length & exponent, and how it was entered) remains valid.
787
**************************************************************************/
788
789
/******************************************************************
790
void al2_inv_rel(Wlelt *p)
791
792
Formally invert the word pointed to by p.
793
******************************************************************/
794
795
void al2_inv_rel(Wlelt *p)
796
{
797
int j,k, len;
798
799
len = p->len;
800
801
for (j = 1; j <= len/2; j++)
802
{
803
k = p->word[j];
804
p->word[j] = -p->word[len+1-j];
805
p->word[len+1-j] = -k;
806
}
807
if (len%2 == 1)
808
{ p->word[1 + len/2] = -p->word[1 + len/2]; }
809
}
810
811
/******************************************************************
812
void al2_cyc_rel(Wlelt *p)
813
814
Cycle the word pointed to by p by 1 position.
815
******************************************************************/
816
817
void al2_cyc_rel(Wlelt *p)
818
{
819
int j,k;
820
821
k = p->word[1];
822
for (j = 1; j <= p->len-1; j++)
823
{ p->word[j] = p->word[j+1]; }
824
p->word[p->len] = k;
825
}
826
827
/******************************************************************
828
void al2_per_rel(void)
829
830
Randomly pick a position in the relator list, and move it to the
831
front of the list. The list is guaranteed to contain at least 2
832
elements.
833
******************************************************************/
834
835
void al2_per_rel(void)
836
{
837
Wlelt *p, *pp;
838
int c,i;
839
840
c = 1 + rand()%rellst->len; /* 1 <= c <= rellst->len */
841
if (c == 1)
842
{ return; } /* do nothing */
843
844
pp = rellst->first;
845
p = pp->next;
846
i = 2;
847
for ( ; i < c; i++)
848
{ pp = p; p = p->next; }
849
850
if (rellst->last == p)
851
{
852
pp->next = NULL;
853
rellst->last = pp;
854
}
855
else
856
{ pp->next = p->next; }
857
858
p->next = rellst->first;
859
rellst->first = p;
860
}
861
862
/******************************************************************
863
void al2_munge_cyc(void)
864
void al2_munge_inv(void)
865
void al2_munge_per(void)
866
867
These 3 routines implement random cyclings, inversions &
868
permutations of the relators respectively. Note that we have to
869
take a `guess' as to how many relator list element moves are needed
870
to `randomly' reorder the relators. The permutation becomes
871
progressively `better' the more runs we do.
872
******************************************************************/
873
874
void al2_munge_cyc(void)
875
{
876
Wlelt *p;
877
int c;
878
879
for (p = rellst->first; p != NULL; p = p->next)
880
{
881
if ((c = rand()%p->len) > 0)
882
{
883
while (c-- > 0)
884
{ al2_cyc_rel(p); }
885
}
886
}
887
}
888
889
void al2_munge_inv(void)
890
{
891
Wlelt *p;
892
893
for (p = rellst->first; p != NULL; p = p->next)
894
{
895
if (rand()%2 == 1)
896
{ al2_inv_rel(p); }
897
}
898
}
899
900
void al2_munge_per(void)
901
{
902
int len = rellst->len;
903
904
while ((len /= 2) >= 1)
905
{ al2_per_rel(); }
906
}
907
908
/******************************************************************
909
void al2_rep(int cntrl, int cnt)
910
911
Do cnt enumerations using random equivalent presentations. The 3
912
lsbs of cntrl control cycling, inverting & permuting respectively.
913
We turn messaging off, dump the relators *after* each run (ie,
914
after al1_start() processes them, so that we see what they actually
915
were for the run), and use asis to prevent al1_start() from
916
messing up the relator ordering.
917
******************************************************************/
918
919
void al2_rep(int cntrl, int cnt)
920
{
921
Logic tmpa, tmpm;
922
923
tmpa = asis;
924
asis = TRUE;
925
tmpm = msgctrl;
926
msgctrl = FALSE;
927
928
while (cnt-- > 0)
929
{
930
if ((cntrl & 0x1) != 0)
931
{ al2_munge_cyc(); }
932
if ((cntrl & 0x2) != 0)
933
{ al2_munge_inv(); }
934
if ((cntrl & 0x4) != 0)
935
{ al2_munge_per(); }
936
937
/* (Re)run the enumeration, and then try to sort out what happened. */
938
939
lresult = al1_start(0);
940
fprintf(fop, "Group Relators: ");
941
al1_prtwl(rellst, 16);
942
fprintf(fop, ";\n");
943
al1_rslt(lresult);
944
945
if (lresult > 0 && sgdone)
946
{
947
okcont = okredo = TRUE;
948
tabinfo = tabindex = TRUE;
949
}
950
else if (lresult >= -259 && sgdone)
951
{
952
okcont = okredo = TRUE;
953
tabinfo = TRUE;
954
tabindex = FALSE;
955
}
956
else
957
{
958
okcont = okredo = FALSE;
959
tabinfo = tabindex = FALSE;
960
}
961
962
if (!(okcont && okredo && tabinfo))
963
{
964
asis = tmpa;
965
msgctrl = tmpm;
966
al2_restart("* An unknown problem has occurred");
967
}
968
}
969
970
asis = tmpa;
971
msgctrl = tmpm;
972
}
973
974
/******************************************************************
975
void al2_aep2(Wlelt *p, int *d)
976
977
For this permutation, recursively do all cycles/inversions.
978
******************************************************************/
979
980
void al2_aep2(Wlelt *p, int *d)
981
{
982
Logic flg;
983
int i,blen;
984
985
if (p == NULL) /* End of list, run enumerator */
986
{
987
/* Run the enumeration, and then try to sort out what happened. */
988
989
d[2]++;
990
lresult = al1_start(0);
991
992
if (lresult > 0 && sgdone)
993
{
994
okcont = okredo = TRUE;
995
tabinfo = tabindex = TRUE;
996
}
997
else if (lresult >= -259 && sgdone)
998
{
999
okcont = okredo = TRUE;
1000
tabinfo = TRUE;
1001
tabindex = FALSE;
1002
}
1003
else
1004
{
1005
okcont = okredo = FALSE;
1006
tabinfo = tabindex = FALSE;
1007
}
1008
1009
if (!(okcont && okredo && tabinfo))
1010
{
1011
asis = (Logic)d[0];
1012
msgctrl = (Logic)d[1];
1013
al2_restart("* An unknown problem has occurred");
1014
}
1015
1016
/* Did we get an index? Any new best/worst values? */
1017
1018
if (tabindex)
1019
{
1020
d[8]++;
1021
1022
flg = FALSE;
1023
if (maxcos < d[3])
1024
{
1025
d[3] = maxcos;
1026
flg = TRUE;
1027
}
1028
if (maxcos > d[4])
1029
{
1030
d[4] = maxcos;
1031
flg = TRUE;
1032
}
1033
if (totcos < d[5])
1034
{
1035
d[5] = totcos;
1036
flg = TRUE;
1037
}
1038
if (totcos > d[6])
1039
{
1040
d[6] = totcos;
1041
flg = TRUE;
1042
}
1043
if (flg)
1044
{
1045
fprintf(fop, "Group Relators: ");
1046
al1_prtwl(rellst, 16);
1047
fprintf(fop, ";\n");
1048
al1_rslt(lresult);
1049
}
1050
1051
/* DTT code: dump *all* totcos values */
1052
/*
1053
fprintf(fop, "DTT: totcos=%d\n", totcos);
1054
*/
1055
}
1056
}
1057
1058
/* Cycle and/or invert this word, and then recurse. Note the care to
1059
ensure that we always do just what is required; in particular, we must
1060
ensure we restore a word to its original form. Note that we correctly
1061
cope with cycling in the presence of non-1 exponents. We *cannot*
1062
suppress inverting (x)^n, if x is an involution, since the geninv[]
1063
array is recalculated by al1_start() & may change since we're
1064
manipulating asis. To implement this, we'd need to duplicate the code in
1065
the al1_chkinvol() function. In fact, there's no end to this, since
1066
inverting (ab)^n, if a & b are involutions, is equivalent to cycling it,
1067
and doing *both* is wasteful! */
1068
1069
else
1070
{
1071
blen = p->len/p->exp; /* Baselength of word */
1072
1073
if ((d[7] & 0x3) == 0) /* Do nothing */
1074
{ al2_aep2(p->next, d); }
1075
else if ((d[7] & 0x3) == 1) /* Cycle only */
1076
{
1077
for (i = 0; i < blen; i++)
1078
{
1079
al2_cyc_rel(p);
1080
al2_aep2(p->next, d);
1081
}
1082
}
1083
else if ((d[7] & 0x3) == 2) /* Invert only */
1084
{
1085
al2_aep2(p->next, d);
1086
al2_inv_rel(p);
1087
al2_aep2(p->next, d);
1088
al2_inv_rel(p);
1089
}
1090
else /* Cycle & invert */
1091
{
1092
for (i = 0; i < blen; i++)
1093
{
1094
al2_cyc_rel(p);
1095
al2_aep2(p->next, d);
1096
}
1097
al2_inv_rel(p);
1098
for (i = 0; i < blen; i++)
1099
{
1100
al2_cyc_rel(p);
1101
al2_aep2(p->next, d);
1102
}
1103
al2_inv_rel(p);
1104
}
1105
}
1106
}
1107
1108
/******************************************************************
1109
void al2_aep1(int *d, Wlelt *p)
1110
1111
Recursively generate the permutations, calling al2_aep2() for each
1112
one. p is a pointer to parent node of the unprocessed `tail' of
1113
rellst. rellst contains >1 elts & p is (initially) the 1st elt.
1114
The node pointed to by the parent node is put in all positions, and
1115
then we recurse. So 123 yields 321, 231, 213, 312, 132, 123.
1116
******************************************************************/
1117
1118
void al2_aep1(int *d, Wlelt *p)
1119
{
1120
Wlelt *t0, *t1;
1121
1122
if (p->next == NULL)
1123
{ al2_aep2(rellst->first, d); }
1124
else
1125
{
1126
/* Move the head of the unprocessed tail to all possible positions. */
1127
1128
t0 = p->next; /* Node being moved */
1129
p->next = t0->next; /* Slice it out ... */
1130
if (rellst->last == t0)
1131
{ rellst->last = p; }
1132
1133
/* The head ... */
1134
1135
t0->next = rellst->first;
1136
rellst->first = t0;
1137
1138
al2_aep1(d, p);
1139
1140
rellst->first = t0->next;
1141
1142
/* The middle ... */
1143
1144
for (t1 = rellst->first; t1 != p; t1 = t1->next)
1145
{
1146
t0->next = t1->next;
1147
t1->next = t0;
1148
1149
al2_aep1(d, p);
1150
1151
t1->next = t0->next;
1152
}
1153
1154
/* The tail (where it started) ... */
1155
1156
t0->next = p->next;
1157
p->next = t0;
1158
if (rellst->last == p)
1159
{ rellst->last = t0; }
1160
1161
al2_aep1(d, p->next);
1162
}
1163
}
1164
1165
/******************************************************************
1166
void al2_aep(int cntrl)
1167
1168
Do all enumerations using equivalent presentations; see comments
1169
for al2_rep(). To prevent having lots of global data floating
1170
around, we pass a pointer to the datum array, which contains:
1171
[0] original asis
1172
[1] original msgctrl
1173
[2] number of runs
1174
[3] min maxcos
1175
[4] max maxcos
1176
[5] min totcos
1177
[6] max totcos
1178
[7] cntrl
1179
[8] number of successes
1180
******************************************************************/
1181
1182
void al2_aep(int cntrl)
1183
{
1184
int datum[9];
1185
1186
/* Temporary code, until we split al1_start() and do the presentation
1187
altering in the middle. We need to ensure that the current presentation
1188
has been processed so that the word exponents are correctly set. We do
1189
this run using whatever the current setup is, *before* we set asis &
1190
turn messaging off. After this run, the exponents will be fixed.
1191
However, setting asis may screw up involutions (ie, whether or not we'd
1192
need to invert some relators, if requested). Note that this also sets
1193
maxrow to a valid U.B. for maxcos/totcos. */
1194
1195
fprintf(fop, "* Priming run ...\n");
1196
al1_rslt(lresult = al1_start(0));
1197
1198
if (lresult > 0 && sgdone)
1199
{
1200
okcont = okredo = TRUE;
1201
tabinfo = tabindex = TRUE;
1202
}
1203
else if (lresult >= -259 && sgdone)
1204
{
1205
okcont = okredo = TRUE;
1206
tabinfo = TRUE;
1207
tabindex = FALSE;
1208
}
1209
else
1210
{
1211
okcont = okredo = FALSE;
1212
tabinfo = tabindex = FALSE;
1213
}
1214
1215
if (!(okcont && okredo && tabinfo))
1216
{ al2_restart("* An unknown problem has occurred"); }
1217
1218
/* Start of the `proper' code. */
1219
1220
datum[0] = (int)asis;
1221
asis = TRUE;
1222
datum[1] = (int)msgctrl;
1223
msgctrl = FALSE;
1224
datum[2] = 0;
1225
datum[3] = maxrow+1;
1226
datum[4] = 0;
1227
datum[5] = maxrow+1;
1228
datum[6] = 0;
1229
datum[7] = cntrl;
1230
datum[8] = 0;
1231
1232
fprintf(fop, "* Equivalent runs ...\n");
1233
if ((cntrl & 0x4) == 0 || rellst->len < 2) /* No permutations */
1234
{ al2_aep2(rellst->first, datum); }
1235
else
1236
{ al2_aep1(datum, rellst->first); }
1237
1238
if (datum[8] == 0)
1239
{ fprintf(fop, "* There were no successes in %d runs\n", datum[2]); }
1240
else
1241
{
1242
fprintf(fop, "* There were %d successes in %d runs:\n",
1243
datum[8], datum[2]);
1244
fprintf(fop, "* maxcos=%d..%d, totcos=%d..%d\n",
1245
datum[3], datum[4], datum[5], datum[6]);
1246
}
1247
1248
asis = (Logic)datum[0];
1249
msgctrl = (Logic)datum[1];
1250
}
1251
1252
1253