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

Path: gap4r8 / pkg / ace-5.2 / src / enum.c
Views: 418346
1
2
/**************************************************************************
3
4
enum.c
5
Colin Ramsay ([email protected])
6
20 Dec 00
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 main enumeration stuff for the core coset enumerator.
18
19
Note: many of the functions `borrow' the scanning code (R-style or C-style)
20
& the deduction processing code from one another. We do this for speed
21
(wrapping things up in a function can carry a significant penalty, and
22
generality `costs') or because the code in not _exactly_ the same (be
23
warned!). I sometimes don't bother commenting such copies as fully as I
24
might; check all copies for the full details. (This is a form of
25
distributed documentation!)
26
27
**************************************************************************/
28
29
#include "al0.h"
30
31
/******************************************************************
32
This macro readies a new coset for use, and gathers some
33
statistics.
34
******************************************************************/
35
36
#define NEXTC(kk) \
37
kk = nextdf; \
38
for (col = 1; col <= ncol; col++) \
39
{ CT(kk, col) = 0; } \
40
nextdf++; \
41
totcos++; \
42
if (++nalive > maxcos) \
43
{ maxcos = nalive; } \
44
45
/******************************************************************
46
This is all the stuff declared in al0.h
47
******************************************************************/
48
49
FILE *fop, *fip;
50
double begintime, endtime, deltatime, totaltime;
51
Logic msgctrl, msghol;
52
int msgincr, msgnext;
53
Logic mendel, rfill, pcomp;
54
int maxrow, rfactor, cfactor, comppc, nrinsgp, lahead;
55
int tlimit, hlimit, llimit, lcount;
56
int nalive, maxcos, totcos;
57
int chead, ctail;
58
int pdefn;
59
float ffactor;
60
int pdsiz, *pdqcol, *pdqrow, toppd, botpd;
61
int dedsiz, *dedrow, *dedcol, topded, dedmode;
62
Logic disded;
63
int *edp, *edpbeg, *edpend;
64
int ncol, **colptr, *col1ptr, *col2ptr, *invcol;
65
int ndrel, *relind, *relexp, *rellen, *relators;
66
int nsgpg, *subggen, *subgindex, *subglength;
67
Logic sgdone;
68
int knr, knh, nextdf;
69
70
#ifdef AL0_STAT
71
int cdcoinc; /* primary D-coincidences in _cdefn()/_rpefn() */
72
int rdcoinc; /* primary R-coincidences in _rdefn()/_rpefn() */
73
int apcoinc; /* primary coincidences in _apply() */
74
int rlcoinc; /* primary coincidences in _rl() */
75
int clcoinc; /* primary coincidences in _cl() */
76
int xcoinc; /* calls to _coinc() */
77
int xcols12; /* calls to _cols12() */
78
int qcoinc; /* number of actual coincs queued */
79
80
int xsave12; /* calls to SAVE12() */
81
int s12dup; /* number of duplicates */
82
int s12new; /* number of new ones */
83
84
/* The number of column 1 table accesses for CREP is xcrep+crepred+crepwrk.
85
For COMPRESS, the number is xcomp+2*compwrk. */
86
87
int xcrep; /* calls to CREP() */
88
int crepred; /* number involving redundant cosets */
89
int crepwrk; /* number of `links' followed */
90
int xcomp; /* calls to COMPRESS() */
91
int compwrk; /* number of `links' altered */
92
93
int xsaved; /* calls to SAVED() */
94
int sdmax; /* max (used) size of dedn stack */
95
int sdoflow; /* number of dedn stack overflows */
96
97
int xapply; /* calls to _apply() */
98
int apdedn; /* number of dedn in _apply() */
99
int apdefn; /* number of defn in _apply() */
100
101
int rldedn; /* number of dedn in _rl() */
102
int cldedn; /* number of dedn in _cl() */
103
104
int xrdefn; /* calls to _rdefn()/_rpefn() */
105
int rddedn; /* number of R-dedn in _rdefn()/_rpefn() */
106
int rddefn; /* number of defn in _rdefn()/_rpefn() */
107
int rdfill; /* number of fill in _rdefn()/_rpefn() */
108
109
int xcdefn; /* calls to _cdefn() */
110
int cddproc; /* number of dedn processed (ie, unstacked) */
111
int cdddedn; /* number of coinc dedn (ie, dead) */
112
int cddedn; /* number of dedn (in dedn processing) */
113
int cdgap; /* number of gap of len 1 */
114
int cdidefn; /* number of immediate defn */
115
int cdidedn; /* number of immediate dedn */
116
int cdpdl; /* number of pd listed */
117
int cdpof; /* number of pdl overflows */
118
int cdpdead; /* number of dead pd */
119
int cdpdefn; /* number of pref defn */
120
int cddefn; /* number of defn */
121
#endif
122
123
/******************************************************************
124
int al0_apply(int cos, int *beg, int *end, Logic defn, Logic save)
125
126
Apply coset cos to the word stored in beg...end. If defn is true
127
then definitions are made to complete the trace, and if save is
128
true any definitions are saved on the deduction stack. This
129
routine is intended for `general' use during R-style scans, so it
130
does _not_ worry about fill-factors or short gaps, nor is there any
131
limit on the number of definitions made. It's main use is in the
132
subgroup generator & relators as generators phases (when defn
133
will be true, and save may be true or false).
134
135
If a finite `index' is obtained, this is the return value. If an
136
overflow occurs, 0 is returned. Otherwise -1 is returned.
137
138
Warning: cos _must_ be a valid (1...nextdf-1) & non-coincident
139
coset. This routine must _never_ be called if the coincidence
140
queue is non-empty (i.e., all coincidences must have been fully
141
processed).
142
******************************************************************/
143
144
int al0_apply(int cos, int *beg, int *end, Logic defn, Logic save)
145
{
146
int i,j,k;
147
int *fwd, *bwd;
148
int col, ifront, iback, ji;
149
150
INCR(xapply);
151
ifront = iback = cos;
152
153
/* Forward scan, leaving ifront set to coset at left of leftmost hole in
154
relator or to the last coset in the relator if no hole. */
155
156
for (fwd = beg; fwd <= end; fwd++)
157
{
158
if ((i = CT(ifront, *fwd)) > 0)
159
{ ifront = i; }
160
else
161
{ break; }
162
}
163
164
/* If the scan completed, then i = ifront & iback = cos, and we'll fall
165
right through and check for a coincidence (i.e., has ifront cycled back
166
to cos or not?). Else, there's a hole & a backward scan is required. */
167
168
if (i == 0)
169
{
170
for (bwd = end; bwd >= fwd; bwd--)
171
{
172
j = *bwd;
173
ji = invcol[j];
174
175
if ((i = CT(iback, ji)) > 0)
176
{ iback = i; }
177
else /* Scan stalled */
178
{
179
if (bwd == fwd)
180
{
181
/* The backward scan has only one gap, so note the deduction to
182
complete the cycle. */
183
184
CT(iback, ji) = ifront;
185
if (save)
186
{ SAVED(iback, ji); }
187
188
/* Since bwd == fwd and there was a hole, then either
189
CT(ifront,j) is still 0, or it has been set by a `backward'
190
definition (particularly if j's an involution). If it has been
191
set (on-the-fly, so to speak), we need to setup correctly for a
192
possible coincidence. */
193
194
if (CT(ifront,j) > 0)
195
{ ifront = CT(ifront,j); } /* May be a coincidence here */
196
else
197
{
198
CT(ifront,j) = iback;
199
ifront = iback; /* Prevent false coincidence */
200
}
201
202
INCR(apdedn);
203
}
204
else if (defn) /* Define a new coset */
205
{
206
/* Note that, if j is an involution, and occurs next to itself,
207
then after the first defn, the remainder of the string of j's
208
will close. Note that if j^2 = 1 & j is _not_ being treated as
209
an involution, then `removing' it is a Tietze transformation, not
210
a free reduction! */
211
212
if (nextdf > maxrow) /* Overflow */
213
{ return(0); }
214
NEXTC(k);
215
CT(iback,ji) = k;
216
CT(k,j) = iback;
217
if (save)
218
{ SAVED(iback,ji); }
219
220
iback = k;
221
INCR(apdefn);
222
223
if (msgctrl && --msgnext == 0)
224
{
225
msgnext = msgincr;
226
ETINT;
227
fprintf(fop, "AD: a=%d r=%d h=%d n=%d;",
228
nalive, knr, knh, nextdf);
229
MSGMID;
230
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
231
BTINT;
232
}
233
}
234
else
235
{ return(-1); } /* New coset definition disabled */
236
}
237
}
238
}
239
240
/* If we get here, the scan has been completed. Check to see if we've
241
found a pair of coincident cosets. */
242
243
if (ifront != iback)
244
{
245
INCR(apcoinc);
246
if ((i = al0_coinc(ifront,iback,save)) > 0)
247
{ return(i); }
248
}
249
250
return(-1);
251
}
252
253
/******************************************************************
254
static int al0_rl(int first, int last, Logic saved)
255
256
Do an R-style lookahead from coset #first up to #last. We return
257
-1 if nothing exciting happens and >=1 if we get a finite `index'
258
(ie, collapse to 1). `Approx.' complexity is rl or rl^2. Note
259
that this (incl. its call to _coinc) does _not_ alter knr/knh,
260
although in may `invalidate' them. Lookahead _never_ makes _new_
261
definitions (so, it never overflows), but it may stack deductions,
262
if requested.
263
******************************************************************/
264
265
static int al0_rl(int first, int last, Logic saved)
266
{
267
int row,rel,i,ii,j,k,l;
268
int *pj, *pk, *fwd, *bwd;
269
int ifront, iback;
270
271
for (row = first; row <= last; row++)
272
{
273
if (COL1(row) >= 0)
274
{
275
for (rel = 1; rel <= ndrel; rel++)
276
{
277
j = (mendel ? rellen[rel]/relexp[rel] : 1);
278
for (k = 0; k < j; k++)
279
{
280
pj = &(relators[relind[rel]+k]);
281
pk = pj + rellen[rel]-1;
282
283
/* <-- cancel indent; the code here is essentially al0_apply(). */
284
285
ifront = iback = row;
286
287
for (fwd = pj; fwd <= pk; fwd++)
288
{
289
if ((l = CT(ifront, *fwd)) > 0)
290
{ ifront = l; }
291
else
292
{ break; }
293
}
294
295
if (l == 0)
296
{
297
for (bwd = pk; bwd >= fwd; bwd--)
298
{
299
i = *bwd;
300
ii = invcol[i];
301
302
if ((l = CT(iback, ii)) > 0)
303
{ iback = l; }
304
else if (bwd == fwd)
305
{
306
CT(iback, ii) = ifront;
307
if (saved)
308
{ SAVED(iback, ii); }
309
310
/* Since we're _not_ making definitions, there is no need to check
311
if CT(ifront,i) is still undefined. The _only_ case where it's
312
not is if ifront=iback & i=ii; ie, i's an involution & we've just
313
deduced that ifront.i=ifront. So, we may set CT(ifront,i) twice,
314
but that's rare & does no damage, and is cheaper than checking. */
315
316
CT(ifront, i) = iback;
317
318
INCR(rldedn);
319
goto next_k;
320
}
321
else
322
{ goto next_k; }
323
}
324
}
325
326
if (ifront != iback)
327
{
328
INCR(rlcoinc);
329
if ((l = al0_coinc(ifront,iback,saved)) > 0)
330
{ return(l); }
331
}
332
333
/* --> restore indent */
334
335
if (COL1(row) < 0) /* We've become redundant */
336
{ goto next_row; }
337
338
next_k:
339
;
340
}
341
}
342
}
343
next_row:
344
; /* Prevent non-ANSI warning */
345
}
346
347
return(-1);
348
}
349
350
/******************************************************************
351
static int al0_cl(int first, int last, Logic saved)
352
353
Do a C-style `lookahead' over all the entries in the table from
354
row #first to row #last inclusive; ie, treat it as a deduction
355
stack. We may, or may not, save deductions, depending as we're in
356
R-style or C-style. Returned value & comments as for al0_rl().
357
`Approx.' complexity is rcl.
358
******************************************************************/
359
360
static int al0_cl(int first, int last, Logic saved)
361
{
362
int row,col,beg,end,i,j,ji,k;
363
int *pj, *pk, *fwd, *bwd;
364
int ifront, iback;
365
366
for (row = first; row <= last; row++)
367
{
368
if (COL1(row) >= 0)
369
{
370
for (col = 1; col <= ncol; col++)
371
{
372
if (CT(row,col) > 0)
373
{
374
if ((beg = edpbeg[col]) >= 0)
375
{
376
end = edpend[col];
377
for (i = beg; i <= end; i += 2)
378
{
379
pj = &(relators[edp[i]]);
380
pk = pj + edp[i+1]-1;
381
382
/* <-- cancel indent; the code here is essentially al0_apply(). */
383
384
ifront = iback = row;
385
386
for (fwd = pj; fwd <= pk; fwd++)
387
{
388
if ((k = CT(ifront, *fwd)) > 0)
389
{ ifront = k; }
390
else
391
{ break; }
392
}
393
394
if (k == 0)
395
{
396
for (bwd = pk; bwd >= fwd; bwd--)
397
{
398
j = *bwd;
399
ji = invcol[j];
400
401
if ((k = CT(iback, ji)) > 0)
402
{ iback = k; }
403
else if (bwd == fwd)
404
{
405
CT(iback, ji) = ifront;
406
if (saved)
407
{ SAVED(iback, ji); }
408
409
CT(ifront, j) = iback;
410
411
INCR(cldedn);
412
goto next_i;
413
}
414
else
415
{ goto next_i; }
416
}
417
}
418
419
if (ifront != iback)
420
{
421
INCR(clcoinc);
422
if ((k = al0_coinc(ifront,iback,saved)) > 0)
423
{ return(k); }
424
}
425
426
/* --> restore indent */
427
428
if (COL1(row) < 0) /* We've become redundant */
429
{ goto next_row; }
430
431
next_i:
432
;
433
}
434
}
435
}
436
}
437
}
438
next_row:
439
; /* Prevent non-ANSI warning */
440
}
441
442
return(-1);
443
}
444
445
/******************************************************************
446
static int al0_rdefn(int cnt, Logic fillr, Logic saved)
447
448
Start scanning through the relators at coset knr, making
449
definitions as necessary to close the scans. If coset knr closes
450
against all relators, we fill any empty slots in its row (if fillr
451
is set), bump knr up, and loop round to process the next row. On
452
overflow we return 0 (leaving knr unchanged & the row only
453
partially scanned) and on a finite index we return nalive. Up to
454
cnt rows will be scanned (either completely or partially). If
455
nothing `exciting' happens, we return -1. Deductions are stacked
456
if saved is true. If cnt <0 then an infinite number of rows will
457
be scanned (so we'll get an index or overflow). We try as far as
458
possible to exit with complete rows scanned, so we do not continue
459
scanning after we've processed cnt rows (although the next active
460
row could close without any definitions required, or, in fact, we
461
could have finished without knowing it).
462
463
Note that a finite index is only correct if the table has no holes.
464
If we get knr = nextdf & there are holes, then one option open to
465
the control logic is to set knr to 1, and then rerun _rdefn() with
466
fillr set to fill the holes. (Of course, this _isn't_ what we
467
actually do in this situation, since a holy-table is precisely
468
what we'd expect if some of the generators don't appear in any of
469
the relators!)
470
******************************************************************/
471
472
static int al0_rdefn(int cnt, Logic fillr, Logic saved)
473
{
474
int i, j, k, l, m, mi, n;
475
int *beg, *end, *fwd, *bwd;
476
int col, ifront, iback;
477
478
INCR(xrdefn);
479
480
/* Count current knr up if it's redundant and/or get an index. Note, we
481
check nextdf _first_ so that COL1(knr) (ie, CT(knr,1)) is defined. */
482
483
while (knr < nextdf && COL1(knr) < 0)
484
{ knr++; }
485
if (knr == nextdf)
486
{ return(nalive); }
487
488
while (cnt != 0)
489
{
490
/* Scan through all relators for this coset. The code here is
491
essentially the same as that in al0_apply. We inline for speed (and
492
flexibility; the code's not _exactly_ the same). */
493
494
for (i = 1; i <= ndrel; i++)
495
{
496
j = (mendel ? rellen[i]/relexp[i] : 1);
497
for (k = 0; k < j; k++)
498
{
499
500
/* <-- cancel indent */
501
502
/* Setup start & stop positions for scan, and the coset at the current
503
scan positions. */
504
505
beg = &(relators[relind[i]+k]);
506
end = beg-1 + rellen[i];
507
ifront = iback = knr;
508
509
/* Forward scan, leaving ifront set to coset at left of leftmost hole in
510
relator or to the last coset in the relator if no hole. */
511
512
for (fwd = beg; fwd <= end; fwd++)
513
{
514
if ((l = CT(ifront, *fwd)) > 0)
515
{ ifront = l; }
516
else
517
{ break; }
518
}
519
520
/* If the scan completed, then l = ifront & iback = cos, and we'll fall
521
right through and check for a coincidence (i.e., has ifront cycled back
522
to cos or not?). Else, there's a hole & a backward scan is required. */
523
524
if (l == 0)
525
{
526
for (bwd = end; bwd >= fwd; bwd--)
527
{
528
m = *bwd;
529
mi = invcol[m];
530
531
if ((l = CT(iback, mi)) > 0)
532
{ iback = l; }
533
else /* Scan stalled */
534
{
535
if (bwd == fwd)
536
{
537
/* The backward scan has only one gap, so note the deduction to
538
complete the cycle & prime for coincidence check. */
539
540
CT(iback, mi) = ifront;
541
if (saved)
542
{ SAVED(iback, mi); }
543
544
if (CT(ifront, m) > 0)
545
{ ifront = CT(ifront, m); }
546
else
547
{
548
CT(ifront, m) = iback;
549
ifront = iback;
550
}
551
552
INCR(rddedn);
553
}
554
else /* Need to define a new coset */
555
{
556
/* Note that, if m is an involution, and occurs next to itself,
557
then after the first defn, the remainder of the string of m's
558
will close. Note that if m^2 = 1 & m is _not_ being treated as
559
an involution, then `removing' it is a Tietze transformation, not
560
a free reduction! */
561
562
if (nextdf > maxrow) /* Overflow */
563
{ return(0); }
564
565
NEXTC(n); /* Making a definition ... */
566
567
CT(iback,mi) = n;
568
CT(n,m) = iback;
569
if (saved)
570
{ SAVED(iback,mi); }
571
572
iback = n; /* Advance to next spot */
573
574
INCR(rddefn);
575
576
if (msgctrl && --msgnext == 0)
577
{
578
msgnext = msgincr;
579
ETINT;
580
fprintf(fop, "RD: a=%d r=%d h=%d n=%d;",
581
nalive, knr, knh, nextdf);
582
MSGMID;
583
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
584
BTINT;
585
}
586
}
587
}
588
}
589
}
590
591
/* If we get here, the scan has been completed. Check to see if we've
592
found a pair of coincident cosets. Recall that _coinc (if it does not
593
return >0) is guaranteed _not_ to change knc/knh, although it may render
594
them redundant. */
595
596
if (ifront != iback)
597
{
598
INCR(rdcoinc);
599
if ((l = al0_coinc(ifront,iback,saved)) > 0)
600
{ return(l); }
601
if (COL1(knr) < 0)
602
{ goto do_next; } /* knr now redundant */
603
}
604
605
/* --> restore indent */
606
607
}
608
}
609
610
/* All relators close at this coset, any row-filling to do? Only
611
(formally) necessary if some g/G does _not_ appear in any relator,
612
but it's usually a good thing to do. */
613
614
if (fillr)
615
{
616
for (i = 1; i <= ncol; i++)
617
{
618
if (CT(knr,i) == 0)
619
{
620
if (nextdf > maxrow) /* Overflow */
621
{ return(0); }
622
623
NEXTC(k); /* Make definition */
624
CT(knr,i) = k;
625
CT(k,invcol[i]) = knr;
626
if (saved)
627
{ SAVED(knr,i); }
628
629
INCR(rdfill);
630
631
if (msgctrl && --msgnext == 0)
632
{
633
msgnext = msgincr;
634
ETINT;
635
fprintf(fop, "RF: a=%d r=%d h=%d n=%d;",
636
nalive, knr, knh, nextdf);
637
MSGMID;
638
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
639
BTINT;
640
}
641
}
642
}
643
}
644
645
/* Row knr is fully scanned (or redundant), so we adjust knr up,
646
jumping over any redundancies & checking to see if we've finished. We
647
have also used up one of our allowed rows, if there's a limit. */
648
649
do_next: /* from al0_coinc(): knr redundant */
650
651
do
652
{ knr++; }
653
while (knr < nextdf && COL1(knr) < 0);
654
655
if (knr == nextdf)
656
{ return(nalive); }
657
658
if (cnt > 0)
659
{ cnt--; }
660
}
661
662
return(-1); /* `normal' termination */
663
}
664
665
/******************************************************************
666
static int al0_cdefn(int cnt)
667
668
Repeatedly process any outstanding deductions and make definitions
669
until: we get a finite result (return > 0), we get an overflow
670
(return 0), or we've defined cnt new cosets (return -1). If cnt
671
is zero then we make no definitions, simply clearing the deduction
672
stack. If cnt < 0 there's no limit on the number of definitions.
673
******************************************************************/
674
675
static int al0_cdefn(int cnt)
676
{
677
int icol, rcol, irow, ires, k, col, pdqr, pdqc;
678
int first, last, i, ifront, iback, l, m, mi;
679
int *beg, *end, *fwd, *bwd;
680
Logic fi;
681
682
INCR(xcdefn);
683
684
while(TRUE)
685
{
686
/* Process all outstanding deductions on the stack */
687
688
while (topded >= 0)
689
{
690
INCR(cddproc);
691
692
irow = dedrow[topded];
693
icol = dedcol[topded--];
694
if (COL1(irow) < 0)
695
{
696
INCR(cdddedn);
697
continue; /* coset has become redundant */
698
}
699
else
700
{
701
ires = CT(irow,icol);
702
rcol = invcol[icol];
703
}
704
705
fi = TRUE; /* first pass through */
706
707
proc_ded: /* entry point for second pass through */
708
709
if ((first = edpbeg[icol]) >= 0)
710
{
711
last = edpend[icol];
712
for (i = first; i <= last; i += 2)
713
{
714
beg = &(relators[edp[i]]);
715
end = beg + edp[i+1]-1;
716
717
/* <-- cancel indent */
718
719
/* We scan this e.d.p. against irow. We don't need to scan the first
720
position, since we _know_ it must be ok. We have to set l, in case the
721
relator has length precisely one! */
722
723
ifront = l = ires;
724
iback = irow;
725
726
/* Forward scan, leaving ifront set to coset at left of leftmost hole in
727
relator or to the last coset in the relator if no hole. */
728
729
for (fwd = beg+1; fwd <= end; fwd++)
730
{
731
if ((l = CT(ifront, *fwd)) > 0)
732
{ ifront = l; }
733
else
734
{ break; }
735
}
736
737
/* If the scan completed, ifront = l > 0 & iback = irow, and we'll fall
738
right through and check for a coincidence (i.e., has ifront cycled back
739
to irow or not?). Else, there's a hole & a backward scan is required. */
740
741
if (l == 0)
742
{
743
for (bwd = end; bwd >= fwd; bwd--)
744
{
745
m = *bwd;
746
mi = invcol[m];
747
748
if ((l = CT(iback, mi)) > 0)
749
{ iback = l; }
750
else /* Scan stalled */
751
{
752
if (bwd == fwd)
753
{
754
/* The backward scan has only one gap, so note the deduction to
755
complete the cycle. */
756
757
CT(iback, mi) = ifront;
758
CT(ifront, m) = iback;
759
SAVED(iback, mi);
760
761
INCR(cddedn);
762
}
763
else if (bwd == fwd + 1) /* gap of length = 1 */
764
{
765
INCR(cdgap);
766
767
/* In pdefn = 1 or 2 mode make definition immediately, if fill-
768
factor permits, there's space & it's allowed. If not, do
769
nothing. Note that we can handle the deduction from this
770
definition at this stage, or not (it'll come out in a later pass
771
through the loop), depending as pdefn = 1 or 2. In general,
772
these strategies blow out the count of total cosets, although
773
making definitions immediately is quicker than storing them on
774
the pdq & making them later, so pdefn=1/2 has a higher
775
`throughput'; whether this compensates for the larger totcos
776
figure is moot! */
777
778
switch(pdefn)
779
{
780
case 1:
781
if (cnt != 0 && nextdf <= maxrow &&
782
(float)(knh-1)*ffactor >= (float)(nextdf-1) )
783
{
784
NEXTC(k);
785
CT(iback, mi) = k;
786
CT(k, m) = iback;
787
SAVED(iback, mi);
788
789
if (cnt > 0)
790
{ cnt--; } /* used an `allowed' definition */
791
INCR(cdidefn);
792
793
if (msgctrl && --msgnext == 0)
794
{
795
msgnext = msgincr;
796
ETINT;
797
fprintf(fop, "CG: a=%d r=%d h=%d n=%d;",
798
nalive, knr, knh, nextdf);
799
MSGMID;
800
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
801
BTINT;
802
}
803
}
804
break;
805
806
case 2:
807
if (cnt != 0 && nextdf <= maxrow &&
808
(float)(knh-1)*ffactor >= (float)(nextdf-1) )
809
{
810
NEXTC(k);
811
CT(iback, mi) = k;
812
CT(k, m) = iback;
813
SAVED(iback, mi);
814
815
if (cnt > 0)
816
{ cnt--; } /* used an `allowed' definition */
817
INCR(cdidefn);
818
819
CT(ifront,*fwd) = k;
820
CT(k,invcol[*fwd]) = ifront;
821
SAVED(ifront,*fwd);
822
823
INCR(cdidedn);
824
825
if (msgctrl && --msgnext == 0)
826
{
827
msgnext = msgincr;
828
ETINT;
829
fprintf(fop, "CG: a=%d r=%d h=%d n=%d;",
830
nalive, knr, knh, nextdf);
831
MSGMID;
832
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
833
BTINT;
834
}
835
}
836
break;
837
838
case 3: /* store definition on pdq */
839
pdqrow[botpd] = iback;
840
pdqcol[botpd] = mi;
841
INCR(cdpdl);
842
if ((botpd = NEXTPD(botpd)) == toppd)
843
{
844
toppd = NEXTPD(toppd);
845
INCR(cdpof);
846
}
847
break;
848
}
849
}
850
851
iback = ifront; /* prevents a false coincidence */
852
break;
853
}
854
}
855
}
856
857
/* At this stage, if ifront != iback, then either the initial forward
858
scan did not cycle back to irow, or a backward scan produced a mismatch;
859
in either case, we have found a coincidence. In all other cases ifront =
860
iback has been enforced, to prevent problems. */
861
862
if (iback != ifront)
863
{
864
/* We do _not_ return an index at this stage if _coinc() returns a +ve
865
value, since there may still be deductions to process (which might
866
_decrease_ nalive). We do, however, detect if the current rows have
867
become redundant. Currently, the only finite value returned by
868
_coinc() is 1, on a total collapse. This clears the dedn stack, so
869
we'll drop out of the while(topded>=1) loop immediately & then drop
870
out of this function with an index of 1. */
871
872
INCR(cdcoinc);
873
al0_coinc(ifront,iback,TRUE);
874
if (COL1(irow) < 0 || COL1(ires) < 0)
875
{ goto next_ded; }
876
}
877
878
/* --> restore indent */
879
880
}
881
}
882
883
/* Do we have to do a second pass? */
884
885
if (fi && (irow != ires || icol != rcol))
886
{
887
SWAP(irow,ires);
888
SWAP(icol,rcol);
889
fi = FALSE;
890
goto proc_ded;
891
}
892
893
/* End of processing this deduction, loop back to next deduction. We
894
also jump here if current deduction becomes redundant. */
895
896
next_ded:
897
;
898
899
#ifdef AL0_DD
900
if (msgctrl && --msgnext == 0)
901
{
902
msgnext = msgincr;
903
ETINT;
904
fprintf(fop, "DD: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);
905
MSGMID;
906
fprintf(fop, " d=%d\n", topded+1);
907
BTINT;
908
}
909
#endif
910
}
911
912
/* Find next empty position (& maybe finish). */
913
914
for ( ; knh < nextdf; knh++)
915
{
916
if (COL1(knh) >= 0)
917
{
918
for (icol = 1; icol <= ncol; icol++)
919
{
920
if (CT(knh, icol) == 0)
921
{ goto hfill; }
922
}
923
}
924
}
925
return(nalive); /* coset table is complete */
926
927
/* Try to fill the next hole in the table */
928
929
hfill:
930
931
if (cnt == 0) /* `normal' termination, since */
932
{ return(-1); } /* done all requested definitions */
933
else
934
{
935
/* Do we have space to make a definition? If not, return overflow.
936
If yes, prime the next sequential position & get its row number. */
937
938
if (nextdf > maxrow)
939
{ return(0); } /* unable to make definition */
940
NEXTC(k); /* ready for definition ... */
941
942
/* We try to make a preferred definition, if possible. If we do,
943
fi is set TRUE. */
944
945
fi = FALSE;
946
if ( pdefn == 3 && toppd != botpd
947
&& (float)(knh-1)*ffactor >= (float)(nextdf-1) )
948
{
949
pdqr = pdqrow[toppd];
950
pdqc = pdqcol[toppd];
951
while (COL1(pdqr) < 0 || CT(pdqr,pdqc) != 0)
952
{
953
INCR(cdpdead);
954
if ((toppd = NEXTPD(toppd)) == botpd)
955
{ break; }
956
pdqr = pdqrow[toppd];
957
pdqc = pdqcol[toppd];
958
}
959
960
if (toppd != botpd)
961
{
962
toppd = NEXTPD(toppd);
963
CT(pdqr,pdqc) = k;
964
CT(k,invcol[pdqc]) = pdqr;
965
SAVED(pdqr,pdqc);
966
967
fi = TRUE;
968
INCR(cdpdefn);
969
970
if (msgctrl && --msgnext == 0)
971
{
972
msgnext = msgincr;
973
ETINT;
974
fprintf(fop, "CP: a=%d r=%d h=%d n=%d;",
975
nalive, knr, knh, nextdf);
976
MSGMID;
977
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
978
BTINT;
979
}
980
}
981
}
982
983
/* If no preferred definition made, fill next hole. */
984
985
if (!fi)
986
{
987
CT(knh,icol) = k;
988
CT(k,invcol[icol]) = knh;
989
SAVED(knh,icol);
990
991
INCR(cddefn);
992
993
if (msgctrl && --msgnext == 0)
994
{
995
msgnext = msgincr;
996
ETINT;
997
fprintf(fop, "CD: a=%d r=%d h=%d n=%d;",
998
nalive, knr, knh, nextdf);
999
MSGMID;
1000
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
1001
BTINT;
1002
}
1003
}
1004
1005
if (cnt > 0) /* keep track, if there's a limit */
1006
{ cnt--; }
1007
}
1008
}
1009
}
1010
1011
/******************************************************************
1012
static int al0_rpefn(int cnt, Logic fill)
1013
******************************************************************/
1014
1015
#include "enum01.c"
1016
1017
/******************************************************************
1018
Pull in the state machine.
1019
******************************************************************/
1020
1021
#include "enum00.c"
1022
1023
/******************************************************************
1024
int al0_enum(int mode, int style)
1025
1026
mode 0 : start enumeration (from row 1 of zeroed table)
1027
1 : continue enumeration (from current row of current table)
1028
2 : redo enumeration (from row 1 of current table)
1029
1030
style 0 : R/C HLT until overflow, then CR-style
1031
1 : R* R-style + dedn stacking/processing
1032
2 : Cr 1 pass Felsch, 1 pass HLT, then C-style
1033
3 : reserved Level 1: C* (?!)
1034
4 : reserved Level 1: defaulted R/C
1035
5 : C Felsch strategy
1036
6 : Rc 1 pass HLT, 1 pass Felsch, then R-style
1037
7 : R HLT strategy
1038
8 : CR alternate Felsch & HLT passes
1039
1040
We can `start' at any time. We can `redo' at any time provided
1041
that any changes to the presentation are confined to _adding_
1042
group relators or subgroup generators. We can `continue' only if
1043
we have made _no_ changes to the presentation (& even if we already
1044
have a finite index). The rfactor/cfactor parameters must be set
1045
correctly (ie, >0) for the `style' of this call; they can be 0 (or
1046
even <0), but this may cause weirdness (although some intriguing
1047
things become possible).
1048
1049
return >1 : non-trivial finite index
1050
1 : index of 1 (? collapse in coincidence processing)
1051
0 : overflow
1052
-256 : incomplete table (ie, unfilled positions)
1053
-257 : hole limit exceeded
1054
-258 : time limit exceeded
1055
-259 : iteration (loops) limit exceeded
1056
-260 : overflow during SG phase
1057
-512 : disallowed mode
1058
-513 : disallowed style
1059
-514 : disallowed mode/style combination (not used yet))
1060
-4096 : invalid machine state (aka reality failure)
1061
-4097 : invalid finite result (aka reality failure)
1062
******************************************************************/
1063
1064
int al0_enum(int mode, int style)
1065
{
1066
int state, action, result; /* The current state, action & result. */
1067
Logic isave; /* Save definitions/deductions on stack? */
1068
static Logic rhfree; /* Table guaranteed hole-free (R-style)? */
1069
static Logic cdapp; /* All definitions applied (C-style)? */
1070
int i,j,k; /* temp ints / indices */
1071
int *pj, *pk; /* temp pointers */
1072
Logic li; /* temp booleans */
1073
1074
/* Start up the timing for this call. Prime the message counter (if
1075
required), initialise the stats package (if macro is defined), and zero
1076
the loop count. */
1077
1078
totaltime = 0.0;
1079
begintime = al0_clock();
1080
if (msgctrl)
1081
{ msgnext = msgincr; }
1082
STATINIT;
1083
lcount = 0;
1084
1085
/* Check mode, style, and their combination. */
1086
1087
if (mode < 0 || mode > 2)
1088
{
1089
result = -512;
1090
goto tail_tail;
1091
}
1092
if (style < 0 || style > 8 || style == 3 || style == 4)
1093
{
1094
result = -513;
1095
goto tail_tail;
1096
}
1097
1098
/* Do the appropriate setup for the requested mode. Note that we _never_
1099
preserve pd's between calls, and there are _never_ outstanding coincs
1100
at a call's exit (so we don't actually need to zero chead/ctail, but we
1101
do anyway!). We may, or may not, preserve deduction stack, entries in
1102
the table and the various `progress' counters. */
1103
1104
toppd = botpd = 0;
1105
chead = ctail = 0;
1106
1107
switch(mode)
1108
{
1109
case 0: /* start; ie, a new run */
1110
1111
topded = -1;
1112
disded = FALSE;
1113
1114
for (i = 1; i <= ncol; i++)
1115
{ CT(1, i) = 0; }
1116
1117
nalive = maxcos = totcos = 1;
1118
knr = knh = 1;
1119
nextdf = 2;
1120
1121
sgdone = FALSE; /* SG not (successfully) run yet */
1122
rhfree = cdapp = TRUE; /* prime for this new run */
1123
1124
break;
1125
1126
case 1: /* continue */
1127
1128
;
1129
1130
break;
1131
1132
case 2: /* redo */
1133
1134
topded = -1;
1135
disded = FALSE;
1136
1137
knr = knh = 1;
1138
1139
sgdone = FALSE;
1140
1141
break;
1142
}
1143
1144
/* The static variable rhfree is primed to true at the start of every run
1145
(ie, start mode), and retains its value across a sequence of continue &
1146
redo commands until the next start. Any time we could _potentially_ do
1147
any R-style applying without filling rows, we toggle it to false. This
1148
indicates that the table _may_ contain holes, and that the al0_upknh()
1149
routine may need to be called before a finite index (due to knr = nextdf)
1150
is returned. Any code anywhere which could cause empty table slots
1151
should take care to ensure that rhfree is false. Since rhfree is only
1152
invoked when checking a finite result due to knr = nextdf, its value if
1153
we get a result due to knh=nextdf is of no concern (here, the table is
1154
hole-free, since that's what knh means!).
1155
1156
Instead of trying to be clever, and keeping a close watch on what the
1157
value of this should be at each point, we simply reset it at the start of
1158
any call(s) where the rfill control parameter is false. The cost of
1159
running _upknh() is no more than that of row-filling (although it's
1160
concentrated in one `lump'), since all table positions are checked in
1161
both cases. In fact, it will usually be less, since we can start the
1162
check at knh, we need not check rows that have become redundant, and we
1163
make no definitions. Note that, even if row-filling is not needed (to
1164
obtain a finite index), it may still be beneficial to turn it on, since
1165
it may alter the definition sequence. */
1166
1167
if (!rfill)
1168
{ rhfree = FALSE; }
1169
1170
/* Do the appropriate setup for the requested style. Our main concern
1171
is whether or not to stack defns/dedns (isave flag) so that these can be
1172
tested against all edp, for C-style enumerations. We also have to track
1173
whether or not we have done this over the course of an entire run; we use
1174
the cdapp flag for this. This flag is similar in concept to the rhfree
1175
one, but is more difficult to manage, since it is `more expensive' to get
1176
it `wrong'. Furthermore, saving & applying dedns is a 3-stage process,
1177
and cdapp only tracks the first step.
1178
1179
cdapp is static, and is primed to true. Any time we _may_ make any table
1180
entries _without_ stacking them, we toggle it to false. Whether or not
1181
the stacking (call to SAVED()) was successful is monitored by the global
1182
disded flag. Whether or not all the stacked dedns have been processed is
1183
determined by the stack size (the global topded). If knh=nextdf and all
1184
three stages were successful (ie, cdapp=TRUE & disded=FALSE & topded==-1)
1185
then the result is valid. If not, then the actual index may be smaller
1186
than the `current' one (ie, nalive). Since our table is guaranteed hole-
1187
free at this stage, the quickest check is to run an R-style scan (with
1188
definitions & deduction stacking both off!) to move knr up to nextdf,
1189
perhaps finding some coincs along the way; this RA phase is the default
1190
action.
1191
1192
The settings below prime isave & cdapp for the styles. However, finer
1193
control is needed since, for example, a (successful) CL phase forces
1194
cdapp back to true (provided further dedns _will_ be stacked (ie, isave
1195
is true)). We use the switch at the end of the state machine's main
1196
loop to do this. Note that we must be careful, since we can exit at any
1197
time and we must ensure that the status is valid for any continues or
1198
redos. We err on the side of caution, so the RA phase may be done when
1199
it is not (formally) required.
1200
1201
Note that in some styles we don't save deductions initially, since we do
1202
a C-style table lookahead at the point where we switch from R-style to
1203
C-style (which effectively forces cdapp to true). (We could also insist
1204
that _all_ dedns _are_ applied, and do a C-style lookahead at any point
1205
where we detect `missed' dedns.) Of course, if the dedn stack is large
1206
enough, then we'll never lose dedn's; but we could end up having to
1207
process _very_ large dedn stacks, which can be expensive. */
1208
1209
switch(style)
1210
{
1211
case 0:
1212
isave = FALSE;
1213
cdapp = FALSE;
1214
break;
1215
1216
case 1:
1217
isave = TRUE;
1218
break;
1219
1220
case 2:
1221
isave = TRUE;
1222
break;
1223
1224
case 5:
1225
isave = TRUE;
1226
break;
1227
1228
case 6:
1229
isave = FALSE;
1230
cdapp = FALSE;
1231
break;
1232
1233
case 7:
1234
isave = FALSE;
1235
cdapp = FALSE;
1236
break;
1237
1238
case 8:
1239
isave = TRUE;
1240
break;
1241
}
1242
1243
/* Combine the style with the mode into the machine's starting state.
1244
Prime machine with `dummy'/`null' action & `success' result. */
1245
1246
state = 1 + 9*mode + style;
1247
1248
action = 0;
1249
result = -1;
1250
1251
/* THE MACHINE ... */
1252
1253
while (TRUE)
1254
{
1255
/* lcount tracks which pass through the machine's loop this is. Then
1256
use result of last action to get next state & action. */
1257
1258
lcount++;
1259
1260
/* DEBUG/TEST/TRACE (DTT) code. Monitors the state machine. */
1261
/*
1262
fprintf(fop, "DTT: lcount=%d; state=%d action=%d result=%d",
1263
lcount, state, action, result);
1264
*/
1265
1266
action = al0_act[state][-result];
1267
state = al0_st[state][-result];
1268
1269
/* Warning: DTT code (see above) */
1270
/*
1271
fprintf(fop, " --> state=%d action=%d\n", state, action);
1272
*/
1273
1274
switch(action)
1275
{
1276
1277
/* <-- cancel indent */
1278
1279
/* The null action; allows timing tests, progress messages, etc. */
1280
1281
case 0:
1282
result = -1;
1283
break;
1284
1285
/* Make some R-style definitions. al0_rdefn() can return -1 (`nothing'
1286
happened), 0 (unable to make definition), or >0 (finite result). Note
1287
that _all_ finite `index' return values are `filtered' through the check
1288
phase (action #6), to prevent `problems'. */
1289
1290
case 1:
1291
1292
if ((result = al0_rdefn(rfactor, rfill, isave)) > 0)
1293
{ result = -2; }
1294
1295
break;
1296
1297
/* Perform lookahead, in R-style _only_, if enabled. This lookahead is
1298
used when we run out of table space, and it could allow us to continue
1299
_without_ running a compaction. However, we elect not to detect this
1300
state of affairs in the current version. Instead, we'll _always_ try to
1301
compact, and we'll check after doing that whether or not there's any
1302
space available in the table (however it was obtained!). Note that
1303
lookahead (& any coincidence processing) does _not_ alter nextdf or knr/
1304
knh (except in the collapse to 1 case, of course), although it may render
1305
them redundant. Since this is a _lookahead_ only, there is never any
1306
need to stack deductions. We don't try to trap an invalid lahead value.
1307
If we don't recognise it, we just quietly do nothing.
1308
1309
Note that we can be as `sloppy' as we wish, in the sense that all we
1310
require is one or more coincs to free up some table space. The current
1311
options all look only for immediate consequences of the current table,
1312
and don't worry about consequent consequences. There are a great variety
1313
of other ways to do lookahead. For example: we could repeatedly run
1314
_rl() until there's no further improvement; or we could bail out early,
1315
after a burst of `significant' progress or if we're achieving
1316
`nothing'. */
1317
1318
case 2:
1319
1320
switch(lahead)
1321
{
1322
case 1:
1323
result = al0_rl(knr, nextdf-1, FALSE);
1324
if (msgctrl)
1325
{
1326
msgnext = msgincr; /* start new count */
1327
ETINT;
1328
fprintf(fop, "L1: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);
1329
MSGMID;
1330
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
1331
BTINT;
1332
}
1333
break;
1334
case 2:
1335
result = al0_cl(1, nextdf-1, FALSE);
1336
if (msgctrl)
1337
{
1338
msgnext = msgincr;
1339
ETINT;
1340
fprintf(fop, "L2: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);
1341
MSGMID;
1342
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
1343
BTINT;
1344
}
1345
break;
1346
case 3:
1347
result = al0_rl(1, nextdf-1, FALSE);
1348
if (msgctrl)
1349
{
1350
msgnext = msgincr;
1351
ETINT;
1352
fprintf(fop, "L3: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);
1353
MSGMID;
1354
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
1355
BTINT;
1356
}
1357
break;
1358
case 4:
1359
result = al0_cl(knr, nextdf-1, FALSE);
1360
if (msgctrl)
1361
{
1362
msgnext = msgincr;
1363
ETINT;
1364
fprintf(fop, "L4: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);
1365
MSGMID;
1366
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
1367
BTINT;
1368
}
1369
break;
1370
default:
1371
result = -1;
1372
break;
1373
}
1374
1375
if (result > 0)
1376
{ result = -2; }
1377
1378
break;
1379
1380
/* Perform compaction (any style) if it's allowed & then check whether
1381
the table has any space left. If so, then continue, else return
1382
overflow. Note that compaction does _not_ alter nalive, but may change
1383
(reduce) knr/knh/nextdf. It makes `free' space _available_, but it does
1384
not _create_ it; coincidences (normal, or in lookahead) do that. */
1385
1386
case 3:
1387
1388
if (nalive >= maxrow)
1389
{
1390
result = 0;
1391
goto tail_tail;
1392
}
1393
else if ( (double)(nextdf-1 - nalive)/(double)(nextdf-1)
1394
>= (double)comppc/100.0 )
1395
{
1396
/* DTT: how expensive is compaction? */
1397
/*
1398
if (msgctrl)
1399
{
1400
msgnext = msgincr;
1401
ETINT;
1402
fprintf(fop, "co: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);
1403
MSGMID;
1404
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
1405
BTINT;
1406
}
1407
*/
1408
al0_compact();
1409
if (msgctrl)
1410
{
1411
msgnext = msgincr;
1412
ETINT;
1413
fprintf(fop, "CO: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);
1414
MSGMID;
1415
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
1416
BTINT;
1417
}
1418
}
1419
1420
if (nextdf <= maxrow)
1421
{ result = -1; }
1422
else
1423
{
1424
result = 0;
1425
goto tail_tail;
1426
}
1427
1428
break;
1429
1430
/* Do some C-style definitions / deduction processing. al0_cdefn() can
1431
return -1 (`nothing' happened), 0 (unable to make definition), or >0
1432
(finite result - potential index, needs checking). */
1433
1434
case 4:
1435
1436
if ((result = al0_cdefn(cfactor)) > 0)
1437
{ result = -2; }
1438
1439
break;
1440
1441
/* Do a C-style complete table lookahead. This is run when we're
1442
switching styles from R- to C-style, or when we're `starting' C-style
1443
with an already existing table. Since we maybe haven't being processing
1444
definitions, we need to run through the entire table. We treat each
1445
table entry as a deduction and stack any new deductions. A subsequent
1446
C-style defn/dedn pass will clear the stack, as usual; we can now enter
1447
C-style, and be confident of any C-style result.
1448
1449
Actually, calling this lookahead is a misnomer. It more correctly might
1450
be thought of as either a `check' (when we have a finite result but
1451
cannot guarantee that all definitions have been processed, or when we
1452
call the enumerator in the redo mode) or a `prime' (when we're switching
1453
to C-style) phase. */
1454
1455
case 5:
1456
1457
if ((result = al0_cl(1, nextdf-1, TRUE)) > 0)
1458
{ result = -2; }
1459
if (msgctrl)
1460
{
1461
msgnext = msgincr;
1462
ETINT;
1463
fprintf(fop, "CL: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);
1464
MSGMID;
1465
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
1466
BTINT;
1467
}
1468
1469
break;
1470
1471
/* We have a finite result; triggered by knr=nextdf, knh=nextdf, or a
1472
collapse to 1 in coinc processing. Check that it's a valid index; it may
1473
be a multiple, or the table may have holes. If knr=nextdf, then all
1474
relators close against all cosets, so we need only check whether or not
1475
the table has any holes. If knh=nextdf, then the table is hole-free, so
1476
we need to check that all table entries have been scanned in all edp.
1477
Note that we have to check for a `clean' C-style termination _before_ we
1478
may bump knh; this is an artifact of the overloading of knh's meaning. */
1479
1480
case 6:
1481
1482
if (knr == nextdf && rhfree)
1483
{ ; } /* ok, fall through */
1484
else if (knh == nextdf && cdapp && !disded && topded < 0)
1485
{ ; } /* ok, fall through */
1486
else if (knr == nextdf)
1487
{
1488
al0_upknh(); /* check for holes ... */
1489
if (msgctrl)
1490
{
1491
msgnext = msgincr;
1492
ETINT;
1493
fprintf(fop, "UH: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);
1494
MSGMID;
1495
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
1496
BTINT;
1497
}
1498
if (knh < nextdf) /* ... table is incomplete */
1499
{
1500
result = -256;
1501
goto tail_tail;
1502
}
1503
}
1504
else if (knh == nextdf)
1505
{
1506
/* Apply all remaining cosets. Note that knh=nextdf, so there are no
1507
holes & no defns will (can!) be made. Since we are only interested in
1508
moving knr up to nextdf (perhaps finding coincs), we turn mendel off;
1509
if it's on (& left on), it can cause a dramatic slow-down. */
1510
1511
li = mendel;
1512
mendel = FALSE;
1513
al0_rdefn(-1,FALSE,FALSE);
1514
mendel = li;
1515
1516
if (msgctrl)
1517
{
1518
msgnext = msgincr;
1519
ETINT;
1520
fprintf(fop, "RA: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);
1521
MSGMID;
1522
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
1523
BTINT;
1524
}
1525
}
1526
else
1527
{ /* fatal error (ie, can't happen!) */
1528
result = -4097;
1529
goto tail_tail;
1530
}
1531
1532
result = nalive;
1533
goto tail_tail;
1534
1535
break; /* not really needed! */
1536
1537
/* If start or redo, scan & close the subgroup generators on coset #1.
1538
Note that we can get coincidences, or collapses, or overflows here. We
1539
treat an overflow as fatal, and return a special value (-260) to alert
1540
the caller to the fact that the subgroup generators have not been fully
1541
processed (so we _must_ (re)start, we can't continue). Note that knr =
1542
knh = 1 here, and they are _not_ changed (we do no scanning against the
1543
relators, so they can't go up, and coset 1 is never redundant). Thus the
1544
only finite index we can get is a collapse to 1, and this is a valid
1545
result.
1546
1547
Note that closing subgroup generators against coset 1 is done R-style, in
1548
that we (maybe) stack up definitions/deductions for later action, and
1549
make as many definitions as required to (immediately) fill any empty
1550
relator table positions. If the enumeration is a (pure) C-style one, we
1551
should process each definition (ie, stacked deduction) _immediately_,
1552
since we should only make definitions if there's nothing else we can do.
1553
For the moment, we don't worry about his `complication'.
1554
1555
As this phase _must_ be successfully completed before a continue is
1556
allowed, and it need not be the 1st phase (it can be the 2nd in redo), a
1557
time/hole/loop limit could cause an early return. So we make sure the
1558
sgdone flag is correctly (re)set at all times. */
1559
1560
case 7:
1561
1562
if (nsgpg > 0)
1563
{
1564
for (i = 1; i <= nsgpg; i++)
1565
{
1566
pj = &(subggen[subgindex[i]]);
1567
pk = pj-1 + subglength[i];
1568
1569
if ((result = al0_apply(1,pj,pk,TRUE,isave)) >= 0)
1570
{ break; }
1571
}
1572
1573
if (msgctrl)
1574
{
1575
msgnext = msgincr;
1576
ETINT;
1577
fprintf(fop, "SG: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);
1578
MSGMID;
1579
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
1580
BTINT;
1581
}
1582
1583
sgdone = TRUE;
1584
if (result == 0)
1585
{
1586
result = -260;
1587
sgdone = FALSE;
1588
goto tail_tail;
1589
}
1590
else if (result > 0)
1591
{ result = -2; }
1592
}
1593
else
1594
{
1595
result = -1; /* `default' result */
1596
sgdone = TRUE; /* ok, since nothing to do! */
1597
}
1598
1599
break;
1600
1601
/* If start or redo (modes 0/2) and in an appropriate style (ie, 1st step
1602
will be a C-style scan), and requested (nrinsgp > 0), then scan & close
1603
the first nrinsgp group relators against coset 1. Similar comments to
1604
those for the subgroup generators apply here, although an overflow does
1605
_not_ force a restart here. */
1606
1607
case 8:
1608
1609
if (nrinsgp > 0)
1610
{
1611
for (i = 1; i <= nrinsgp; i++)
1612
{
1613
j = (mendel ? rellen[i]/relexp[i] : 1);
1614
for (k = 0; k < j; k++)
1615
{
1616
pj = &(relators[relind[i]+k]);
1617
pk = pj-1 + rellen[i];
1618
1619
if ((result = al0_apply(1,pj,pk,TRUE,isave)) >= 0)
1620
{ break; }
1621
}
1622
1623
if (result >= 0)
1624
{ break; }
1625
}
1626
1627
if (msgctrl)
1628
{
1629
msgnext = msgincr;
1630
ETINT;
1631
fprintf(fop, "RS: a=%d r=%d h=%d n=%d;", nalive, knr, knh, nextdf);
1632
MSGMID;
1633
fprintf(fop, " m=%d t=%d\n", maxcos, totcos);
1634
BTINT;
1635
}
1636
1637
if (result > 0)
1638
{ result = -2; }
1639
}
1640
else
1641
{ result = -1; } /* `default' result */
1642
1643
break;
1644
1645
/* Do some R*-style definitions / deduction processing. al0_rpefn() can
1646
return -1 (`nothing' happened), 0 (unable to make definition), or >0
1647
(finite result - potential index, needs checking). Note the row-filling
1648
argument and the fact that we don't use (need?) isave, since dedn
1649
stacking is mandatory here. */
1650
1651
case 9:
1652
1653
if ((result = al0_rpefn(rfactor, rfill)) > 0)
1654
{ result = -2; }
1655
1656
break;
1657
1658
/* If we get here, something's a touch awry. */
1659
1660
default:
1661
result = -4096;
1662
goto tail_tail;
1663
1664
/* --> restore indent */
1665
1666
} /* end of "switch(action)" */
1667
1668
/* At this point, we have just completed action in state, and are about
1669
to `leave' state via one of its exit paths (selected by the (state,
1670
result) pair). Now is the time to perform any action specific to this
1671
point. Note that the checks for the various limits (times, holes, ...)
1672
are done _after_ this, so we're guaranteed that the (updated) status
1673
will be correct on any `early' exit. */
1674
1675
switch(state)
1676
{
1677
case 32:
1678
if (result == -1)
1679
{ cdapp = TRUE; }
1680
break;
1681
case 38:
1682
if (result == -1)
1683
{ cdapp = TRUE; }
1684
break;
1685
case 45:
1686
if (result == 0)
1687
{ isave = TRUE; }
1688
break;
1689
case 46:
1690
if (result == -1)
1691
{ cdapp = TRUE; }
1692
break;
1693
case 47:
1694
if (result == -1)
1695
{ cdapp = TRUE; }
1696
break;
1697
case 55:
1698
if (result == -1)
1699
{ cdapp = TRUE; }
1700
break;
1701
case 56:
1702
if (result == -1)
1703
{ cdapp = TRUE; }
1704
break;
1705
case 58:
1706
if (result == -1 || result == 0)
1707
{ cdapp = FALSE; }
1708
case 59:
1709
if (result == -1)
1710
{ cdapp = TRUE; }
1711
break;
1712
}
1713
1714
/* Only calculate % holes if requested, since it's expensive! We only
1715
treat the value as significant if we've actually defined some cosets
1716
other than #1! We ignore the case where nalive=1 and not all #1's row
1717
entries are 0 (ie, some, but not necessarily all, are 1 instead). */
1718
1719
if (hlimit >= 0 && nalive > 1)
1720
{
1721
if (al0_nholes() >= (double)hlimit)
1722
{
1723
result = -257;
1724
break;
1725
}
1726
}
1727
1728
/* We have to correctly find the total accumulated time, without
1729
disturbing any messaging (which must always print the elapsed time
1730
since the last message). So we _can't_ use the ETINT/BTINT macros. */
1731
1732
if (tlimit >= 0)
1733
{
1734
if ((totaltime + al0_diff(begintime,al0_clock())) >= (double)tlimit)
1735
{
1736
result = -258;
1737
break;
1738
}
1739
}
1740
1741
/* Any loop limit in force? */
1742
1743
if (llimit > 0 && lcount >= llimit)
1744
{
1745
result = -259;
1746
break;
1747
}
1748
1749
} /* end of "while(TRUE)" */
1750
1751
/* We've either jumped here (finite result, overflow, error), or we've
1752
broken out the main loop (time / holes / iterations limit). We simply
1753
update the total time for this call & return the `status'. */
1754
1755
tail_tail:
1756
1757
endtime = al0_clock();
1758
totaltime += al0_diff(begintime,endtime);
1759
1760
return(result);
1761
}
1762
1763
1764