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
*A extra_relations.c ANUPQ source Eamonn O'Brien
4
**
5
*Y Copyright 1995-2001, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany
6
*Y Copyright 1995-2001, School of Mathematical Sciences, ANU, Australia
7
**
8
*/
9
10
#include "pq_defs.h"
11
#include "pcp_vars.h"
12
#include "constants.h"
13
#include "pq_functions.h"
14
#include "exp_vars.h"
15
16
#if defined(GROUP)
17
18
/* this procedure collect extra relations which hold in the group;
19
20
it may be used as an exponent check routine for certain
21
Burnside computations;
22
23
if pcp->extra_relations = 0 there are no extra relations;
24
25
if pcp->extra_relations > 0, the extra relations specify that
26
certain pcp words have exponent pcp->extra_relations -- those
27
normal pcp words with weights from pcp->start_wt to end_class;
28
29
if pcp->end_wt > 0, end_class is set to the minimum of pcp->cc and
30
this value;
31
32
if both pcp->end_wt and pcp->start_wt are 0, this ensures that the
33
group has exponent pcp->extra_relations;
34
35
if ALL_WORDS is chosen, then the routine generates a complete
36
list of the normal words needed in exponent checking whose
37
weights lie within the chosen bounds;
38
39
if REDUCED_LIST is chosen, it is assumed that all redundant
40
relations in the queue are later closed under supplied
41
automorphisms which must contain a generating set for the
42
appropriate general linear group;
43
44
if INITIAL_SEGMENT is chosen, the routine will read in a word
45
and only generate all those words needed for exponent checking
46
which have this word as a proper initial segment;
47
48
any redundancies obtained by echelonising the members of this
49
list are added to the supplied queue;
50
51
there are a number of options in this code which are selected
52
according to the value of the following variables:
53
54
if exp_flag->process is FALSE, generate the list of words but do
55
not process the elements; if diagnostic output, then print out
56
all words which will be collected;
57
58
if exp_flag->complete is TRUE and diagnostic output is chosen,
59
then print out all of the words of the appropriate weight
60
generated and not just those which survive the conjugacy and
61
other tests;
62
63
hence, if you want a listing of all of the words generated using the
64
back-track search, you should set both flags TRUE;
65
66
if exp_flag->partitions is TRUE, print the weight partitions
67
of the generated words; */
68
69
70
#define MCLASS 10000
71
72
int initial_length; /* length of initial segment */
73
int least_weight; /* lower bound on weight of remaining letters */
74
int max_weight; /* upper bound on weight of remaining letters */
75
int initial_weight; /* weight of initial segment */
76
int first_entry; /* lower bound on new letters in word */
77
int least_entry; /* lower bound on remaining new letters in word */
78
int max_entry; /* upper bound on new letters in word */
79
80
/* read in the initial segment to be used in generating the words */
81
82
static void
83
read_initial_segment(int *initial, int *initial_coeff, struct pcp_vars *pcp)
84
{
85
register int *y = y_address;
86
87
register int i;
88
int lower_bound; /* lower bound on next letter in word */
89
int lower_bound_weight; /* lower bound on weight of next letter */
90
91
#include "access.h"
92
93
/* read in details of the initial segment of the words to be processed */
94
read_value(
95
TRUE, "Input length of initial segment of words: ", &initial_length, 0);
96
97
lower_bound = 0;
98
if (initial_length != 0) {
99
printf("Input initial segment of words as a generator exponent list: ");
100
for (i = 1; i < initial_length; ++i) {
101
read_value(FALSE, "", &initial[i], lower_bound + 1);
102
read_value(FALSE, "", &initial_coeff[i], 1);
103
lower_bound = initial[i];
104
}
105
read_value(FALSE, "", &initial[i], lower_bound + 1);
106
read_value(TRUE, "", &initial_coeff[i], 1);
107
lower_bound = initial[i];
108
}
109
110
/* find initial weight */
111
initial_weight = 0;
112
for (i = 1; i <= initial_length; ++i)
113
initial_weight += initial_coeff[i] * WT(y[pcp->structure + initial[i]]);
114
115
/* all other entries in this word must have weight as least
116
as great as the last letter of the initial segment */
117
if (lower_bound == 0)
118
lower_bound_weight = 1;
119
else
120
lower_bound_weight = MAX(1, WT(y[pcp->structure + lower_bound]));
121
122
read_value(TRUE,
123
"Input lower bound for weight of remaining letters: ",
124
&least_weight,
125
lower_bound_weight);
126
127
/* first entry in the remainder of word */
128
first_entry = y[pcp->clend + MIN(least_weight - 1, pcp->cc)];
129
130
/* the first new letter must be larger than the last letter
131
of the initial segment */
132
first_entry = MAX(lower_bound, first_entry);
133
134
/* if using automorphisms and initial segment has length 0,
135
we skip all but first of those pcp generators of weight 1 */
136
least_entry =
137
(pcp->m != 0 && initial_length == 0) ? y[pcp->clend + 1] : first_entry;
138
139
read_value(TRUE,
140
"Input upper bound for weight of remaining letters: ",
141
&max_weight,
142
least_weight);
143
144
max_entry = pcp->ccbeg;
145
if (max_weight < pcp->cc)
146
max_entry = y[pcp->clend + max_weight] + 1;
147
}
148
149
void extra_relations(struct exp_vars *exp_flag, struct pcp_vars *pcp)
150
{
151
register int *y = y_address;
152
153
register int nmr_words; /* number of normal words powered in class */
154
register int length; /* number of generators in normal word */
155
register int exp_length; /* sum of exponents in normal word */
156
register int nextg; /* next generator added to normal word */
157
register int w; /* weight of generator in normal word */
158
register int weight; /* weight of normal word */
159
register int wt_gen1; /* weight of first generator in normal word */
160
register int gen_i; /* ith generator in normal word */
161
register Logical exit; /* exit from loop? */
162
163
int gen[MCLASS + 1]; /* generators of normal word */
164
int coeff[MCLASS + 1]; /* exponents of these generators */
165
int initial[MCLASS + 1]; /* generators of initial normal word */
166
int initial_coeff[MCLASS + 1]; /* exponents of these generators */
167
168
register int extra_relations = pcp->extra_relations;
169
register int structure = pcp->structure;
170
register int lastg = pcp->lastg;
171
register int prime = pcp->p;
172
register int pm1 = pcp->pm1;
173
174
register int end_class; /* end class for check */
175
register int class;
176
register int entry;
177
register int i, j;
178
int *queue;
179
char *s;
180
181
FILE *RelationList;
182
183
#include "access.h"
184
185
if (extra_relations == 0)
186
return;
187
188
/* relation file */
189
if (exp_flag->word_list)
190
RelationList = OpenFile("Relation_list", "w");
191
192
/* determine whether the supplied exponent is
193
valid and what classes must be checked */
194
i = 0;
195
j = extra_relations;
196
while (j > 1) {
197
if (MOD(j, prime) != 0) {
198
text(14, extra_relations, 0, 0, 0);
199
pcp->valid = FALSE;
200
return;
201
}
202
++i;
203
j /= prime;
204
}
205
206
if (pcp->cc <= i)
207
return;
208
end_class = pcp->cc;
209
if (pcp->end_wt != 0)
210
end_class = MIN(end_class, pcp->end_wt);
211
212
if (exp_flag->list == ALL_WORDS || exp_flag->list == REDUCED_LIST) {
213
initial_length = 0;
214
initial_weight = 0;
215
first_entry = 0;
216
least_entry = (exp_flag->list == REDUCED_LIST) ? y[pcp->clend + 1] : 0;
217
max_entry = pcp->ccbeg;
218
} else {
219
read_initial_segment(initial, initial_coeff, pcp);
220
}
221
queue = exp_flag->queue;
222
223
/* process each relevant class in turn --
224
using a backtrack process, build up normal words in the pcp
225
generators of the group which have weight equal to class;
226
each word has the general form
227
228
gen[1]^coeff[1] * gen[2]^coeff[2] * ... * gen[length]^coeff[length]
229
230
where gen[1], ..., gen[length] are pcp generators with
231
gen[1] < gen[2] < ... < gen[length], coeff[1] = 1,
232
and 0 < coeff[i] < prime for i = 2,...,length;
233
234
we generate only all words with weight equal to class and
235
coeff[1] = 1; normal words with coeff[1] > 1 are powers
236
of normal words with coeff[1] = 1, and so they have the
237
same orders as those with coeff[1] = 1;
238
239
if REDUCED_LIST is chosen, we enforce the additional
240
requirement that gen[i] has weight at least 2 for
241
all i >= 2, and gen[1] = 1 or gen[1] has weight at least 2;
242
243
if INITIAL_SEGMENT is chosen, we enforce the additional
244
requirement that each word has the supplied proper
245
initial segment;
246
247
we apply some commutator calculus to eliminate some of
248
the words; those not eliminated are raised to the power
249
extra_relations and then the result is echelonised */
250
251
for (class = MAX(1, pcp->start_wt); class <= end_class; ++class) {
252
253
nmr_words = 0;
254
length = initial_length;
255
weight = initial_weight;
256
257
/* set up the initial-segment of the word */
258
for (i = 1; i <= initial_length; ++i) {
259
gen[i] = initial[i];
260
coeff[i] = initial_coeff[i];
261
}
262
263
nextg = first_entry + 1;
264
w = WT(y[structure + nextg]);
265
266
do {
267
/* backtrack process -- start to construct the next normal word */
268
exit = FALSE;
269
while (weight + w > class || nextg >= max_entry) {
270
271
/* if length = 0, we have finished this class */
272
exit = (length == initial_length);
273
if (exit)
274
break;
275
276
/* strip off last generator from the normal word and
277
decrease the weight of the word accordingly */
278
nextg = gen[length];
279
if (--coeff[length] == 0)
280
--length;
281
weight -= WT(y[structure + nextg]);
282
283
if (nextg >= 1 && nextg < least_entry)
284
/* nextg should now start with first generator of next weight */
285
nextg = least_entry + 1;
286
else
287
++nextg;
288
289
w = WT(y[structure + nextg]);
290
}
291
if (exit)
292
break;
293
294
/* add in nextg as last pcp generator with exponent
295
one of normal word; increase weight accordingly */
296
coeff[++length] = 1;
297
if (nextg > 1 && nextg <= least_entry) {
298
/* nextg should now start with first generator of weight 2 */
299
nextg = least_entry + 1;
300
w = WT(y[structure + nextg]);
301
}
302
gen[length] = nextg;
303
weight += w;
304
305
/* keep extending normal word as long as its weight is < class */
306
while (weight < class) {
307
if (coeff[length] == pm1 || length == 1) {
308
/* add in a new pcp generator with exponent 1 */
309
coeff[++length] = 1;
310
++nextg;
311
if (nextg > 1 && nextg <= least_entry)
312
/* nextg now starts with first generator of next weight */
313
nextg = least_entry + 1;
314
gen[length] = nextg;
315
w = WT(y[structure + nextg]);
316
} else
317
/* add in another copy of nextg */
318
++coeff[length];
319
320
/* update weight for new word */
321
weight += w;
322
}
323
324
/* if weight > class, we have extended the normal
325
word too far, and we need to backtrack */
326
if (weight > class)
327
continue;
328
329
/* if appropriate, print out weight partitions */
330
331
if (exp_flag->partitions) {
332
printf("seq (");
333
for (i = 1; i < length; ++i)
334
for (j = 1; j <= coeff[i]; ++j)
335
printf("%d, ", WT(y[structure + gen[i]]));
336
337
for (j = 1; j < coeff[length]; ++j)
338
printf("%d, ", WT(y[structure + gen[length]]));
339
printf("%d),\n", WT(y[structure + gen[length]]));
340
}
341
342
if (exp_flag->complete) {
343
printf("Seek to collect power %d of the following word: ",
344
extra_relations);
345
for (i = 1; i <= length; ++i)
346
printf("%d^%d ", gen[i], coeff[i]);
347
printf("\n");
348
}
349
350
/* we now have a normal word of weight class; run a number of
351
checks to establish if it is necessary to exponentiate it;
352
first, use commutator identities to possibly eliminate it;
353
354
if the conditions in the if clause below are satisfied,
355
then the normal closure of nextg has prime exponent;
356
357
if this is the case, we can express the normal word in
358
the form u * nextg, where u is a normal word of lower weight;
359
we assume by induction that u^extra_relations = 1,
360
and this, together with the fact that the normal
361
closure of nextg has exponent prime, implies that
362
(u * nextg)^extra_relations is a product of commutators
363
which have length at least extra_relations and which have
364
entries gen[1],..., gen[length]; we may also assume that
365
gen[i] occurs at least coeff[i] times for i = 1, ..., length
366
in each of these commutators;
367
368
let exp_length = sum of coeff[i] for i = 1, ..., length;
369
if extra_relations > exp_length then these commutators
370
have extra entries of weight at least wt_gen1; check whether
371
the extra entries make the total weight of the commutators
372
exceed the current class; if so, the power of this word
373
is trivial */
374
375
wt_gen1 = WT(y[structure + gen[1]]);
376
377
if (prime * w >= pcp->cc && y[pcp->ppower + nextg] == 0) {
378
/* find the sum of the coefficients */
379
for (i = 1, exp_length = 0; i <= length; ++i)
380
exp_length += coeff[i];
381
if (weight + (extra_relations - exp_length) * wt_gen1 > pcp->cc) {
382
if (exp_flag->filter) {
383
printf("Filtered from list using normal closure\n");
384
}
385
continue;
386
}
387
}
388
389
/* seek to eliminate conjugates and powers of words
390
which are tested at other times;
391
392
the Felsch-Neubueser conjugacy class algorithm provides
393
a list of class representatives for a group described
394
by a pcp; these representatives have the property that
395
if a word occurs in the list, then any of its subwords
396
also occurs as a representative; the calculations listed
397
below allow us to recognise that certain words would
398
not occur in the list; if we can deduce that our
399
normal word, w, would not occur, we do not power w;
400
401
in the iteration listed below, if gen_i = PART2(entry) or
402
PART3(entry) then gen[j] is a commutator or power of gen_i;
403
this means that our normal word, w, is a conjugate or a power
404
of another normal word which starts off with the same first
405
i generator-exponent pairs as w, but which does not have
406
gen[j] anywhere in it;
407
408
note that this reduction is critically sensitive to
409
the way in which generators are numbered, and to the
410
way eliminations are carried out in this program;
411
412
Michael Vaughan-Lee provided this refinement */
413
414
/* first, find last generator in normal word with weight = wt_gen1 */
415
for (i = length; WT(y[structure + gen[i]]) > wt_gen1; --i)
416
;
417
418
if (i != length) {
419
exit = FALSE;
420
gen_i = gen[i];
421
for (j = i + 1; j <= length && !exit; ++j) {
422
entry = y[structure + gen[j]];
423
exit = (gen_i == PART2(entry) || gen_i == PART3(entry));
424
}
425
if (exit) {
426
if (exp_flag->filter == TRUE)
427
printf("Filtered from list using conjugacy checks\n");
428
continue;
429
}
430
}
431
432
/* we have a word to exponentiate */
433
++nmr_words;
434
435
/* we may want to save all test words generated to
436
a relation file for later processing */
437
if (exp_flag->word_list) {
438
fprintf(RelationList, "%d ", extra_relations);
439
for (i = 1; i <= length; ++i)
440
for (j = 1; j <= coeff[i]; ++j)
441
fprintf(RelationList, "%d ", gen[i]);
442
fprintf(RelationList, ";\n");
443
}
444
445
/* space is required for three collected parts set up in power */
446
if (is_space_exhausted(6 * lastg + 6, pcp))
447
return;
448
449
structure = pcp->structure;
450
451
/* put one copy of word into collected part in exponent-vector form */
452
for (i = 1; i <= lastg; ++i)
453
y[pcp->lused + i] = 0;
454
455
for (i = 1; i <= length; ++i) {
456
nextg = gen[i];
457
y[pcp->lused + nextg] = coeff[i];
458
}
459
460
/* if process flag is true, and the number of the word is higher
461
than supplied value, power the word and echelonise the result */
462
463
if (exp_flag->process && nmr_words >= exp_flag->start_process) {
464
465
power(extra_relations, pcp->lused, pcp);
466
467
/* is the result trivial? if not, group has larger exponent */
468
if (exp_flag->check_exponent == TRUE) {
469
i = 1;
470
while (i <= lastg && exp_flag->all_trivial) {
471
exp_flag->all_trivial = (y[pcp->lused + i] == 0);
472
++i;
473
}
474
if (exp_flag->all_trivial == FALSE)
475
return;
476
}
477
478
/* set second collected part trivial for echelonisation */
479
for (i = 1; i <= lastg; ++i)
480
y[pcp->lused + lastg + i] = 0;
481
482
echelon(pcp);
483
}
484
485
/* if appropriate, print out the normal word */
486
if (((pcp->fullop && pcp->eliminate_flag) ||
487
(pcp->diagn && exp_flag->process) ||
488
(pcp->diagn && !exp_flag->process && !exp_flag->filter)) &&
489
nmr_words >= exp_flag->start_process) {
490
s = exp_flag->process ? "Collected" : "Will collect";
491
printf("%s power %d of the following word: ", s, extra_relations);
492
for (i = 1; i <= length; ++i)
493
printf("%d^%d ", gen[i], coeff[i]);
494
printf("\n");
495
}
496
497
if (pcp->redgen != 0 && pcp->m != 0)
498
queue[++exp_flag->queue_length] = pcp->redgen;
499
500
/* report intermediate statistics */
501
if (exp_flag->report_unit && nmr_words % exp_flag->report_unit == 0) {
502
s = nmr_words == 1 ? "" : "s";
503
printf(
504
"%d relation%s of class %d collected\n", nmr_words, s, class);
505
}
506
507
if (pcp->overflow || pcp->complete != 0 || pcp->newgen == 0)
508
return;
509
510
} while (length != 0);
511
512
/* if appropriate, report the number of words raised to power */
513
if (!exp_flag->process || exp_flag->report_unit || pcp->fullop ||
514
pcp->diagn)
515
text(13, nmr_words, class, exp_flag->process, 0);
516
}
517
518
if (exp_flag->word_list)
519
CloseFile(RelationList);
520
}
521
522
#endif
523
524